Hello guys and gals
I am trying to traverse geometric network and getting a single property out of every feature on the way. My starting point is certain IFeature which i cast into ISimpleJunctionFeature and use it in IForwardStarGEN.FindAdjacent which provides me only with number of adjacent elements. I then use IForwardStarGEN.QueryAdjacentEdge etc. and i get
which in turn getse me IFeature, the property i needed class id etc. But how can i continue the path down the geometric network? I assume i need a recursion, but I seem to be stuck and there seems to be no examples on the web whatsoever, plus the documentation is a bit shoddy.
Thank you for any hints
Best regards,
Matej
You say "...how can I continue the path down the geometric network". From your description it sounds like you were starting at a location and then trying to traverse downstream, say a river network? Well a better way would be to SOLVE the routing problem then process the returned edges. You solve network tracing problems with the ITraceFlowSolver interface. The FindPath method returns an enumerator over the edges that make up the route. From that you can drill down to the individual features and query any associated attributes.
Sounds like I've missed a step or two, thank you for nudging me to the right direction.
best regards,
Matej
Matej,
I can go one better, here is some old VBA code I had developed to create a route between 2 points on a river network. This will certainly help you in understand the steps as it's not immediately obvious what the sequence is!
Some of it may not be relevant to you as this function is trying to return a polyline.
Public Function Generate_route_between_2_points(theStartPoint As IPoint, theEndpoint As IPoint) As ICurve
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Description: '
' This public function attempts to calculate the route along the network between '
' the 2 points supplied to it. If it fails (due to snap tolerance) then a NULL '
' geometry is returned. It returns a geometry of type ICurve. '
' '
' Updated on 14/5/2003
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Show_message_in_StatusBar "Tracing network..."
'''''''''''''''''''''''''
' Define an empty curve '
'''''''''''''''''''''''''
Dim anEmptyCurve As ICurve
Set anEmptyCurve = Nothing
''''''''''''''''''''''''''''''
' Get handle on featureclass '
''''''''''''''''''''''''''''''
Dim pMXDocument As IMxDocument
Set pMXDocument = ThisDocument
Dim pmap As IMap
Set pmap = pMXDocument.FocusMap
Dim pLayer As ILayer
Dim pFeatureLayer As IFeatureLayer
Set pFeatureLayer = FindLayer("Rivers")
'''''''''''''''''''''''''
' Get handle on network '
'''''''''''''''''''''''''
Dim pFeatureClass As IFeatureClass
Set pFeatureClass = pFeatureLayer.FeatureClass
Dim pFeatureDataset As IFeatureDataset
Set pFeatureDataset = pFeatureClass.FeatureDataset
Dim pNetworkCollection As INetworkCollection
Set pNetworkCollection = pFeatureDataset
Dim pGeometricNetWork As IGeometricNetwork
Set pGeometricNetWork = pNetworkCollection.GeometricNetwork(0)
Dim pNetwork As INetwork
Set pNetwork = pGeometricNetWork.Network
'''''''''''''''''''''''''''''''''''
' Test to see if network is Valid '
'''''''''''''''''''''''''''''''''''
If pNetwork.status <> esriNSValidNetwork Then
MsgBox "Network is not valid! Bailing out now to stop system crash.", vbCritical, "Fatal Error!"
End
End If
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Point to EID - Find nearest edge to point within 100 map units. Note that the '
' returned point "theFirstLocation" is used later for identifying the sub curve '
' of the traced route. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim pPointToEID As IPointToEID
Set pPointToEID = New PointToEID
Dim nearestEdgeEID As Long
Dim theFirstLocation As IPoint
Dim aPercentage As Double
With pPointToEID
.SnapTolerance = 100
Set .SourceMap = pmap
Set .GeometricNetwork = pGeometricNetWork
.GetNearestEdge theStartPoint, nearestEdgeEID, theFirstLocation, aPercentage
End With
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Check to see if theStartPoint selected an edge feature, if not return a NULL shape '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If theFirstLocation Is Nothing Then
Set Generate_route_between_2_points = anEmptyCurve
Exit Function
End If
'
' Convert the EID to a feature class ID, feature ID, and sub ID
'
Dim lFCID As Long, lFID As Long, lSubID As Long
Dim pNetElements As INetElements
Set pNetElements = pNetwork
pNetElements.QueryIDs nearestEdgeEID, esriETEdge, lFCID, lFID, lSubID
'
' Now create the flag that will be used by the tracesolver
'
Dim pNetFlag As INetFlag
Set pNetFlag = New EdgeFlag
With pNetFlag
.UserClassID = lFCID
.UserID = lFID
.UserSubID = lSubID
End With
'
' Now do it all again with the second point!
'
Set pPointToEID = New PointToEID
Dim theSecondLocation As IPoint
With pPointToEID
.SnapTolerance = 100
Set .SourceMap = pmap
Set .GeometricNetwork = pGeometricNetWork
.GetNearestEdge theEndpoint, nearestEdgeEID, theSecondLocation, aPercentage
End With
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Check to see if theEndPoint selected an edge feature, if not return a NULL shape '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If theSecondLocation Is Nothing Then
Set Generate_route_between_2_points = anEmptyCurve
Exit Function
End If
Set pNetElements = pNetwork
pNetElements.QueryIDs nearestEdgeEID, esriETEdge, lFCID, lFID, lSubID
Dim anotherpNetFlag As INetFlag
Set anotherpNetFlag = New EdgeFlag
With anotherpNetFlag
.UserClassID = lFCID
.UserID = lFID
.UserSubID = lSubID
End With
''''''''''''''''''''''''''''''''''''''''
' Establish a trace flow solver object '
''''''''''''''''''''''''''''''''''''''''
Dim pTraceFlowSolver As ITraceFlowSolver
Set pTraceFlowSolver = New TraceFlowSolver
Dim pNetSolver As INetSolver
Set pNetSolver = pTraceFlowSolver
Set pNetSolver.SourceNetwork = pNetwork
''''''''''''''''''''''''''''''
' Ensure solver uses weights '
''''''''''''''''''''''''''''''
Dim pNetSolverWeights As INetSolverWeights
Set pNetSolverWeights = pTraceFlowSolver
Dim pNetWeight As INetWeight
Dim pNetSchema As INetSchema
Set pNetSchema = pNetwork
Set pNetWeight = pNetSchema.WeightByName("Length_Weight")
Set pNetSolverWeights.FromToEdgeWeight = pNetWeight
Set pNetSolverWeights.ToFromEdgeWeight = pNetWeight
'''''''''''''''''''''''''''''''''''
' Load trace solver with netflags '
'''''''''''''''''''''''''''''''''''
Dim arrayOfEdgeFlags(2) As IEdgeFlag
Set arrayOfEdgeFlags(0) = pNetFlag
Set arrayOfEdgeFlags(1) = anotherpNetFlag
pTraceFlowSolver.PutEdgeOrigins 2, arrayOfEdgeFlags(0)
'''''''''''''
' Run trace '
'''''''''''''
Dim pEnumJuncIDs As IEnumNetEID
Dim pEnumEdgeIDs As IEnumNetEID
Dim pSegs(1) As Variant
pTraceFlowSolver.FindPath esriFMConnected, esriSPObjFnMinSum, pEnumJuncIDs, pEnumEdgeIDs, 1, pSegs(0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' In ArcView a path could be created without any cost, ie a zero length path. Not '
' sure if ArcMap does the same thing so test here to see if the generated path '
' actually has an associated cost (more than 0 segments). If it does not, return '
' a NULL ICurve. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If pSegs(0) < 1 Then
Set Generate_route_between_2_points = anEmptyCurve
Exit Function
End If
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' FindPath has returned the enumerate pEnumEdgeIDs which we will now use to get the '
' features and build a long polyline '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim pEIDInfo As IEIDInfo
Dim pEnumEIDInfo As IEnumEIDInfo
Dim pEIDHelper As IEIDHelper
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Create a new object of EIDHelper and set some propertise '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set pEIDHelper = New EIDHelper
Set pEIDHelper.GeometricNetwork = pGeometricNetWork
Set pEIDHelper.OutputSpatialReference = Nothing
pEIDHelper.ReturnFeatures = True
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Now create an enumerate object from EIDHelper and make sure it's reset '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set pEnumEIDInfo = pEIDHelper.CreateEnumEIDInfo(pEnumEdgeIDs)
pEnumEIDInfo.Reset
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Loop through pEnumEIDInfo getting the features of the individual elements '
' that make up the route and union them into a single geometry (polyline). '
' This section of code was updated on 14/5/2003 to improve speed of '
' constructing polyline from trace on network. Previous code used to loop '
' throught each network element merging them together one by one, we now use '
' the more efficient GeometryBag and topological operator constructUnion. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim pGeometryCollection As IGeometryCollection
Set pGeometryCollection = New GeometryBag
Dim pTopologicalOperator As ITopologicalOperator
Dim pFeature As IFeature
Dim pGeometry As IGeometry
'''''''''''''''''''''''''''''''''''''''''''''''''''
' Now loop through adding them to the geometrybag '
' via it's interface of geometry collection. '
'''''''''''''''''''''''''''''''''''''''''''''''''''
Show_message_in_StatusBar "Turning trace into polyline..."
For aCounter = 1 To pEnumEIDInfo.count
Set pEIDInfo = pEnumEIDInfo.Next
Set pFeature = pEIDInfo.Feature
Set pGeometry = pFeature.ShapeCopy
pGeometryCollection.AddGeometry pGeometry
Next aCounter
'''''''''''''''''''''''''''''''''''''''''''''''
' Having add the geometries to the collection '
' we now union them into a single polyline. '
'''''''''''''''''''''''''''''''''''''''''''''''
Set pTopologicalOperator = New Polyline
pTopologicalOperator.ConstructUnion pGeometryCollection
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' This new line is constructed from all the edges that it traced along, this includes '
' the full length of the edge that the flag was on. We do not want this, we want the '
' distance travelled between the 2 points '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim pCurve As ICurve
Dim pNewCurve As ICurve
Dim aDummyPoint As IPoint
Dim bRight As Boolean
Dim distanceAlongCurve As Double
Dim distanceFromCurve As Double
Dim FirstPointAlong As Double
Dim SecondPointAlong As Double
Set pCurve = pTopologicalOperator
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Query curve to find distance along curve for theFirstLocation, unfortunately also '
' need to supply other variables as these are required '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
pCurve.QueryPointAndDistance esriNoExtension, theFirstLocation, False, aDummyPoint, distanceAlongCurve, distanceFromCurve, bRight
FirstPointAlong = distanceAlongCurve
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Query curve to find distance along curve for theSecondLocation, unfortunately also '
' need to supply other variables as these are required '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
pCurve.QueryPointAndDistance esriNoExtension, theSecondLocation, False, aDummyPoint, distanceAlongCurve, distanceFromCurve, bRight
SecondPointAlong = distanceAlongCurve
'''''''''''''''''''''''
' Construct sub curve '
'''''''''''''''''''''''
pCurve.GetSubcurve FirstPointAlong, SecondPointAlong, False, pNewCurve
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Test if the final curve has any length, just to be on the safe side.... '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If pNewCurve.Length > 0 Then
Set Generate_route_between_2_points = pNewCurve
Else
Set Generate_route_between_2_points = anEmptyCurve
End If
End Function
Thank you again, once im back to project regarding traversing I'll use this excerpt.