About the Add a traversal result to the map Sample
[C#]
AddTraversalResultsToMap.cs
//*************************************************************************************
// ArcGIS Network Analyst extension - Add Traversal Results to Map Sample
//
// This simple code is an ArcGIS Add-In that shows how to take the traversal results
// from a solved network analysis layer and add them to the map as feature layers.
// The user can then step through the traversal results layers to see the
// individual features that make up the results.
//
//************************************************************************************
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.CartoUI;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.NetworkAnalyst;
using ESRI.ArcGIS.NetworkAnalystUI;
namespace NAAddTraversalResultToMap
{
public class AddTraversalResultsToMap : ESRI.ArcGIS.Desktop.AddIns.Button
{
public AddTraversalResultsToMap()
{
}
/// <summary>
/// OnClick is the main function for the add-in. When the button is clicked in ArcMap,
/// this code will execute. Note that if you re-solve the analysis layer associated with
/// the traversal result, any open attribute tables associated with the traversal result
/// will disconnect and need to be reopened.
/// </summary>
protected override void OnClick()
{
try
{
var networkAnalystExtension = ArcMap.Application.FindExtensionByName("Network Analyst") as INetworkAnalystExtension;
if (networkAnalystExtension == null)
throw new System.Exception("Network Analyst Extension is not available.");
INALayer naLayer = networkAnalystExtension.NAWindow.ActiveAnalysis;
if (naLayer == null)
throw new System.Exception("Cannot add a traversal result. There is no active network analysis layer.");
var result = naLayer.Context.Result;
if (result == null || !result.HasValidResult)
throw new System.Exception("Cannot add a traversal result. The active analysis layer either does not have a valid result or does not support traversal results.");
// In the case of Vehicle Routing Problem (VRP) layers, get the traversal result from the internal route context, if available
var vrpResult = result as INAVRPResult;
if (vrpResult != null)
{
if (vrpResult.InternalRouteContext == null || vrpResult.InternalRouteContext.Result == null || !vrpResult.InternalRouteContext.Result.HasValidResult)
throw new System.Exception("Cannot add a traversal result. VRP layers cannot have a shape type of none.");
result = vrpResult.InternalRouteContext.Result;
}
var naTraversalResultEdit = result as INATraversalResultEdit;
if (naTraversalResultEdit == null)
throw new System.Exception("Cannot add a traversal result. The active analysis layer does not support traversal results.");
// Geometry needs to be inferred for traversal edges in cases where the route geometry is not already generated.
// It doesn't hurt to make this call, though, even when a geometry is already present.
naTraversalResultEdit.InferGeometry(string.Empty, null, new CancelTrackerClass());
// Load the junction, edge and turn traversal results to the map
// also add the internal route and internal NAContext if available
IGroupLayer groupLayer = new GroupLayerClass();
groupLayer.Name = "NAResults - " + ((ILayer)naLayer).Name;
AddNATraversalResultLayersToGroup(groupLayer, result);
// The newly added layer references in-memory features of the NALayer.
// Therefore, in order for the new layer to persist properly, it has to be
// placed below the layer it references.
var mapLayers = ArcMap.Document.FocusMap as IMapLayers2;
int naLayerPosition = GetLayerIndex(naLayer as ILayer);
mapLayers.InsertLayer(groupLayer, false, naLayerPosition + 1);
}
catch (System.Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message, "Add-In Exception", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}
/// <summary>
/// AddNATraversalResultLayersToGroup will take the traversal results from an INAResult and add them to the map as a group layer
/// </summary>
private void AddNATraversalResultLayersToGroup(IGroupLayer groupLayer, INAResult result)
{
var naTraversalResultQuery = result as INATraversalResultQuery2;
groupLayer.Add(GetTraversalResultLayer(esriNetworkElementType.esriNETJunction, naTraversalResultQuery));
groupLayer.Add(GetTraversalResultLayer(esriNetworkElementType.esriNETTurn, naTraversalResultQuery));
groupLayer.Add(GetTraversalResultLayer(esriNetworkElementType.esriNETEdge, naTraversalResultQuery));
}
/// <summary>
/// GetTraversalResultLayer will generate a layer out of the traversal result for the specified element type
/// </summary>
private IFeatureLayer GetTraversalResultLayer(esriNetworkElementType elementType, INATraversalResultQuery2 naTraversalResultQuery)
{
//Junctions Traversal Result Feature Layer
IFeatureClass traversalResultFeatureClass = naTraversalResultQuery.get_FeatureClass(elementType);
if (traversalResultFeatureClass != null)
{
// save the rows in this class out when the MXD is saved
INAClass naClass = traversalResultFeatureClass as INAClass;
naClass.SaveRowsOnPersist = true;
// create the traversal result layer
IFeatureLayer traversalResultLayer = new FeatureLayerClass();
traversalResultLayer.FeatureClass = traversalResultFeatureClass;
traversalResultLayer.Name = traversalResultFeatureClass.AliasName;
// Set up the layer with an appropriate symbology
var geoFeatureLayer = traversalResultLayer as IGeoFeatureLayer;
geoFeatureLayer.RendererPropertyPageClassID = (new SingleSymbolPropertyPageClass()).ClassID;
geoFeatureLayer.Renderer = GetRenderer(elementType);
return traversalResultLayer;
}
return null;
}
/// <summary>
/// GetRenderer will return a feature renderer with symbology appropriate to the specified element type
/// </summary>
private IFeatureRenderer GetRenderer(esriNetworkElementType networkElementType)
{
ISimpleRenderer simpleRend = new SimpleRendererClass();
IRgbColor color = new RgbColorClass();
switch (networkElementType)
{
// The junction symbology will be a large yellow circle with a thick black outline
case esriNetworkElementType.esriNETJunction:
ISimpleMarkerSymbol junctionPointSymbol = new SimpleMarkerSymbolClass();
junctionPointSymbol.Style = esriSimpleMarkerStyle.esriSMSCircle;
junctionPointSymbol.Size = 10;
//yellow
color.Red = 255;
color.Blue = 0;
color.Green = 255;
junctionPointSymbol.Color = color;
junctionPointSymbol.Outline = true;
junctionPointSymbol.OutlineSize = 2;
//black
color.Red = 0;
color.Blue = 0;
color.Green = 0;
junctionPointSymbol.OutlineColor = color;
simpleRend.Label = "TRFC_Junctions";
simpleRend.Symbol = junctionPointSymbol as ISymbol;
return simpleRend as IFeatureRenderer;
// The turn symbology will be a thick purple line
case esriNetworkElementType.esriNETTurn:
ISimpleLineSymbol turnLineSymbol = new SimpleLineSymbolClass();
turnLineSymbol.Style = esriSimpleLineStyle.esriSLSSolid;
turnLineSymbol.Width = 4;
//purple
color.Red = 125;
color.Blue = 125;
color.Green = 0;
turnLineSymbol.Color = color;
simpleRend.Label = "TRFC_Turns";
simpleRend.Symbol = turnLineSymbol as ISymbol;
return simpleRend as IFeatureRenderer;
// The edge symbology will be a thick blue line
case esriNetworkElementType.esriNETEdge:
ISimpleLineSymbol edgeLineSymbol = new SimpleLineSymbolClass();
edgeLineSymbol.Style = esriSimpleLineStyle.esriSLSSolid;
edgeLineSymbol.Width = 4;
//blue
color.Red = 0;
color.Blue = 255;
color.Green = 0;
edgeLineSymbol.Color = color;
simpleRend.Label = "TRFC_Edges";
simpleRend.Symbol = edgeLineSymbol as ISymbol;
return simpleRend as IFeatureRenderer;
}
return null;
}
private int GetLayerIndex(ILayer layer)
{
for (int index = 0; index < ArcMap.Document.FocusMap.LayerCount; index++)
{
ILayer layerAtIndex = ArcMap.Document.FocusMap.get_Layer(index);
if (layerAtIndex == layer)
return index;
}
return -1;
}
protected override void OnUpdate()
{
Enabled = ArcMap.Application != null;
}
}
}
[Visual Basic .NET]
AddTraversalResultsToMap.vb
'*************************************************************************************
' ArcGIS Network Analyst extension - Add Traversal Results to Map Sample
'
' This simple code is an ArcGIS Add-In that shows how to take the traversal results
' from a solved network analysis layer and add them to the map as feature layers.
' The user can then step through the traversal results layers to see the
' individual features that make up the results.
'
'************************************************************************************
Imports Microsoft.VisualBasic
Imports System
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.NetworkAnalyst
Imports ESRI.ArcGIS.NetworkAnalystUI
Namespace NAAddTraversalResultToMap
Public Class AddTraversalResultsToMap
Inherits ESRI.ArcGIS.Desktop.AddIns.Button
Public Sub New()
End Sub
''' <summary>
''' OnClick is the main function for the add-in. When the button is clicked in ArcMap,
''' this code will execute. Note that if you re-solve the analysis layer associated with
''' the traversal result, any open attribute tables associated with the traversal result
''' will disconnect and need to be reopened.
''' </summary>
Protected Overrides Sub OnClick()
Try
Dim networkAnalystExtension As INetworkAnalystExtension = TryCast(ArcMap.Application.FindExtensionByName("Network Analyst"), INetworkAnalystExtension)
If networkAnalystExtension Is Nothing Then
Throw New System.Exception("Network Analyst Extension is not available.")
End If
Dim naLayer As INALayer = networkAnalystExtension.NAWindow.ActiveAnalysis
If naLayer Is Nothing Then
Throw New System.Exception("Cannot add a traversal result. There is no active network analysis layer.")
End If
Dim result As INAResult = naLayer.Context.Result
If result Is Nothing OrElse (Not result.HasValidResult) Then
Throw New System.Exception("Cannot add a traversal result. The active analysis layer either does not have a valid result or does not support traversal results.")
End If
' In the case of Vehicle Routing Problem (VRP) layers, get the traversal result from the internal route context, if available
Dim vrpResult As INAVRPResult = TryCast(result, INAVRPResult)
If vrpResult IsNot Nothing Then
If vrpResult.InternalRouteContext Is Nothing OrElse vrpResult.InternalRouteContext.Result Is Nothing OrElse Not vrpResult.InternalRouteContext.Result.HasValidResult Then
Throw New System.Exception("Cannot add a traversal result. VRP layers cannot have a shape type of none.")
End If
result = vrpResult.InternalRouteContext.Result
End If
Dim naTraversalResultEdit As INATraversalResultEdit = TryCast(result, INATraversalResultEdit)
If naTraversalResultEdit Is Nothing Then
Throw New System.Exception("Cannot add a traversal result. The active analysis layer does not support traversal results.")
End If
' Geometry needs to be inferred for traversal edges in cases where the route geometry is not already generated.
' It doesn't hurt to make this call, though, even when a geometry is already present.
naTraversalResultEdit.InferGeometry(String.Empty, Nothing, New CancelTrackerClass())
' Load the junction, edge and turn traversal results to the map
' also add the internal route and internal NAContext if available
Dim groupLayer As IGroupLayer = New GroupLayerClass()
groupLayer.Name = "NAResults - " & DirectCast(naLayer, ILayer).Name
AddNATraversalResultLayersToGroup(groupLayer, result)
' The newly added layer references in-memory features of the NALayer.
' Therefore, in order for the new layer to persist properly, it has to be
' placed below the layer it references.
Dim mapLayers As IMapLayers2 = TryCast(ArcMap.Document.FocusMap, IMapLayers2)
Dim naLayerPosition As Integer = GetLayerIndex(TryCast(naLayer, ILayer))
mapLayers.InsertLayer(groupLayer, False, naLayerPosition + 1)
Catch e As System.Exception
System.Windows.Forms.MessageBox.Show(e.Message, "Add-In Exception", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.[Error])
End Try
End Sub
''' <summary>
''' AddFeatureLayerToMap will take the traversal result from an NAResult and add it to the map as a layer
''' </summary>
Private Sub AddFeatureLayerToMap(ByVal result As INAResult, ByVal naLayerName As String, ByVal naLayerPosition As Integer, ByVal elementType As esriNetworkElementType)
Dim naTraversalResultQuery As INATraversalResultQuery = TryCast(result, ESRI.ArcGIS.NetworkAnalyst.INATraversalResultQuery)
' Note that the traversal result layer that is being created will update each time the referenced layer
' completes another solve.
Dim featureLayer As IFeatureLayer = New FeatureLayerClass()
featureLayer.FeatureClass = naTraversalResultQuery.FeatureClass(elementType)
featureLayer.Name = naLayerName & " - Traversal Result " & featureLayer.FeatureClass.AliasName
' The newly added layer references in-memory features of the NALayer.
' Therefore, in order for the new layer to persist properly, it has to be
' placed below the layer it references.
Dim mapLayers As IMapLayers2 = TryCast(ArcMap.Document.FocusMap, IMapLayers2)
mapLayers.InsertLayer(featureLayer, False, naLayerPosition + 1)
End Sub
''' <summary>
''' AddNATraversalResultLayersToGroup will take the traversal results from an INAResult and add them to the map as a group layer
''' </summary>
Private Sub AddNATraversalResultLayersToGroup(ByVal groupLayer As IGroupLayer, ByVal result As INAResult)
Dim naTraversalResultQuery As INATraversalResultQuery2 = TryCast(result, INATraversalResultQuery2)
groupLayer.Add(GetTraversalResultLayer(esriNetworkElementType.esriNETJunction, naTraversalResultQuery))
groupLayer.Add(GetTraversalResultLayer(esriNetworkElementType.esriNETTurn, naTraversalResultQuery))
groupLayer.Add(GetTraversalResultLayer(esriNetworkElementType.esriNETEdge, naTraversalResultQuery))
End Sub
''' <summary>
''' GetTraversalResultLayer will generate a layer out of the traversal result for the specified element type
''' </summary>
Private Function GetTraversalResultLayer(ByVal elementType As esriNetworkElementType, ByVal naTraversalResultQuery As INATraversalResultQuery2) As IFeatureLayer
'Junctions Traversal Result Feature Layer
Dim traversalResultFeatureClass As IFeatureClass = naTraversalResultQuery.FeatureClass(elementType)
If traversalResultFeatureClass IsNot Nothing Then
' save the rows in this class out when the MXD is saved
Dim naClass As INAClass = TryCast(traversalResultFeatureClass, INAClass)
naClass.SaveRowsOnPersist = True
' create the traversal result layer
Dim traversalResultLayer As IFeatureLayer = New FeatureLayerClass()
traversalResultLayer.FeatureClass = traversalResultFeatureClass
traversalResultLayer.Name = traversalResultFeatureClass.AliasName
' Set up the layer with an appropriate symbology
Dim geoFeatureLayer As IGeoFeatureLayer = TryCast(traversalResultLayer, IGeoFeatureLayer)
geoFeatureLayer.RendererPropertyPageClassID = (New ESRI.ArcGIS.CartoUI.SingleSymbolPropertyPageClass()).ClassID
geoFeatureLayer.Renderer = GetRenderer(elementType)
Return traversalResultLayer
End If
Return Nothing
End Function
''' <summary>
''' GetRenderer will return a feature renderer with symbology appropriate to the specified element type
''' </summary>
Private Function GetRenderer(ByVal networkElementType As esriNetworkElementType) As IFeatureRenderer
Dim simpleRend As ISimpleRenderer = New SimpleRendererClass()
Dim color As IRgbColor = New RgbColorClass()
Select Case networkElementType
' The junction symbology will be a large yellow circle with a thick black outline
Case esriNetworkElementType.esriNETJunction
Dim junctionPointSymbol As ISimpleMarkerSymbol = New SimpleMarkerSymbolClass()
junctionPointSymbol.Style = ESRI.ArcGIS.Display.esriSimpleMarkerStyle.esriSMSCircle
junctionPointSymbol.Size = 10
'yellow
color.Red = 255
color.Blue = 0
color.Green = 255
junctionPointSymbol.Color = color
junctionPointSymbol.Outline = True
junctionPointSymbol.OutlineSize = 2
'black
color.Red = 0
color.Blue = 0
color.Green = 0
junctionPointSymbol.OutlineColor = color
simpleRend.Label = "TRFC_Junctions"
simpleRend.Symbol = TryCast(junctionPointSymbol, ISymbol)
Return TryCast(simpleRend, IFeatureRenderer)
' The turn symbology will be a thick purple line
Case esriNetworkElementType.esriNETTurn
Dim turnLineSymbol As ISimpleLineSymbol = New SimpleLineSymbolClass()
turnLineSymbol.Style = ESRI.ArcGIS.Display.esriSimpleLineStyle.esriSLSSolid
turnLineSymbol.Width = 4
'purple
color.Red = 125
color.Blue = 125
color.Green = 0
turnLineSymbol.Color = color
simpleRend.Label = "TRFC_Turns"
simpleRend.Symbol = TryCast(turnLineSymbol, ISymbol)
Return TryCast(simpleRend, IFeatureRenderer)
' The edge symbology will be a thick blue line
Case esriNetworkElementType.esriNETEdge
Dim edgeLineSymbol As ISimpleLineSymbol = New SimpleLineSymbolClass()
edgeLineSymbol.Style = ESRI.ArcGIS.Display.esriSimpleLineStyle.esriSLSSolid
edgeLineSymbol.Width = 4
'blue
color.Red = 0
color.Blue = 255
color.Green = 0
edgeLineSymbol.Color = color
simpleRend.Label = "TRFC_Edges"
simpleRend.Symbol = TryCast(edgeLineSymbol, ISymbol)
Return TryCast(simpleRend, IFeatureRenderer)
End Select
Return Nothing
End Function
Private Function GetLayerIndex(ByVal layer As ILayer) As Integer
For index As Integer = 0 To ArcMap.Document.FocusMap.LayerCount - 1
Dim layerAtIndex As ILayer = ArcMap.Document.FocusMap.Layer(index)
If layerAtIndex Is layer Then
Return index
End If
Next index
Return -1
End Function
Protected Overrides Sub OnUpdate()
Enabled = Not ArcMap.Application Is Nothing
End Sub
End Class
End Namespace