Next Upstream Device Task
NextUpstreamDevice.cls

' Copyright 2008 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See use restrictions at <your ArcGIS install location>/developerkit/userestrictions.txt.
' 




'The New Upstream trace task performs an upstream trace, the same as the Find Upstream
'trace task that is provided by ArcMap. To use the New Upstream trace task, you must
'place at least one flag on the current network. This trace task also uses the
'barriers, disabled layers, selected features, and weight filters that you specify
'using the Utility Network Analyst toolbar to perform the trace.

Option Explicit

Implements ITraceTask
Implements ITraceTaskResults

'declare a module-level variable to hold a reference the Utility Network Analysis extension
Private m_pUtilityNetworkAnalysisExt As esriEditorExt.IUtilityNetworkAnalysisExt

'declare module-level variables to hold the result edges and junctions of the last trace
Private m_pResultJunctions As IEnumNetEID
Private m_pResultEdges As IEnumNetEID
Private m_lJuncEID As Long

Private Property Get ITraceTask_EnableSolve() As Boolean
'determines whether to enable or disable the Solve button on the toolbar.
'this trace task can be enabled if there is at least one flag on the network.

  Dim pNetworkAnalysisExtFlags As esriEditorExt.INetworkAnalysisExtFlags
  Dim pNetworkAnalysisExt As esriEditorExt.INetworkAnalysisExt
  Dim lngNetworkCount As Long
  
  'by default, the Solve button will be disabled
  ITraceTask_EnableSolve = False
  
  'QI for the INetworkAnalysisExt interface using IUtilityNetworkAnalysisExt
  Set pNetworkAnalysisExt = m_pUtilityNetworkAnalysisExt
  'determine the number of networks currently loaded
  lngNetworkCount = pNetworkAnalysisExt.NetworkCount
  'if there are no networks loaded, then the Solve button is disabled
  If lngNetworkCount = 0 Then Exit Property

  'QI for the INetworkAnalysisExtFlags interface using IUtilityNetworkAnalysisExt
  Set pNetworkAnalysisExtFlags = m_pUtilityNetworkAnalysisExt
  'if there is one flag on the network then enable the task
  With pNetworkAnalysisExtFlags
    If .JunctionFlagCount = 1 Or .EdgeFlagCount = 1 Then
      'there is at least one flag on the current network
      ITraceTask_EnableSolve = True
    Else
      'there are no flags on the current network
      Exit Property
    End If
  End With
  
End Property

Private Property Get ITraceTask_Name() As String
  ITraceTask_Name = "Next Upstream Device"
End Property

Private Sub ITraceTask_OnCreate(ByVal utilityNetworkAnalysis As esriEditorExt.IUtilityNetworkAnalysisExt)
'assign the input argument to the module-level variable.
'this maintains a reference to the Utility Network Analysis extension.
  Set m_pUtilityNetworkAnalysisExt = utilityNetworkAnalysis
End Sub

Private Sub ITraceTask_OnTraceExecution()
'perform the upstream trace task, using the flags, barriers, disabled layers,
'and weight filters that were specified using the toolbar.
  On Error GoTo ErrorHandler
  
  Dim pNetworkAnalysisExtFlags As esriEditorExt.INetworkAnalysisExtFlags
  Dim pTraceFlowSolver As esriNetworkAnalysis.ITraceFlowSolver
  Dim pResultEdges As esriGeoDatabase.IEnumNetEID
  Dim pResultJunctions As esriGeoDatabase.IEnumNetEID
  Dim pNetworkAnalysisExtResults As esriEditorExt.INetworkAnalysisExtResults
    
  'prepare the network solver
  m_lJuncEID = -1
  Set pTraceFlowSolver = UTIL_CoreTraceSetup
  If pTraceFlowSolver Is Nothing Then Exit Sub
      
  'Run the trace the first time to get all upstream devices
  pTraceFlowSolver.FindFlowElements esriFMUpstream, esriFEJunctions, _
   pResultJunctions, pResultEdges
   
  'Reset the trace for the second pass
  Set pTraceFlowSolver = UTIL_CoreTraceSetup
  
  'Create a barrier set based on the disabled layers that are set and the junction returned
  'from the first trace.
  UTIL_SetBarriers pResultJunctions, pTraceFlowSolver
  
  pTraceFlowSolver.FindFlowEndElements esriFMUpstream, esriFEJunctions, _
   pResultJunctions, pResultEdges
  
  'copy the results to the module level
  Set m_pResultJunctions = pResultJunctions
  Set m_pResultEdges = pResultEdges
  
  'update the extension with the results
  'QI for the INetworkAnalysisExtResults interface using IUtilityNetworkAnalysisExt
  Set pNetworkAnalysisExtResults = m_pUtilityNetworkAnalysisExt
  'first, clear the previous results
  pNetworkAnalysisExtResults.ClearResults
  
  'Create the selection
  pNetworkAnalysisExtResults.CreateSelection pResultJunctions, pResultEdges
  
  ResultNotification
  
  Exit Sub
  
ErrorHandler:
  'an unexpected error occured somewhere in the function
  'notify the user that an error occurred and exit the sub
  MsgBox "ITraceTask_OnTraceExecution - " & Err.Description
End Sub

Private Sub ResultNotification()
On Error GoTo ErrHand:
  If m_pResultJunctions.Count = 1 Then
    Dim pApp As IApplication, pDoc As IMxDocument, pMap As IMap, lLoop As Long
    Dim pFeatSel As IFeatureSelection
    Set pApp = New AppRef
    Set pDoc = pApp.Document
    Set pMap = pDoc.FocusMap
    For lLoop = 0 To pMap.LayerCount - 1
      If TypeOf pMap.Layer(lLoop) Is IFeatureSelection Then
        Set pFeatSel = pMap.Layer(lLoop)
        If pFeatSel.SelectionSet.Count = 1 Then
          MsgBox "1 " & pMap.Layer(lLoop).Name & " feature selected."
          Exit For
        End If
      End If
    Next lLoop
  Else
    MsgBox m_pResultJunctions.Count & " feature(s) selected."
  End If

  Exit Sub
ErrHand:
  MsgBox "ResultNotification - " & Err.Description
End Sub

'the properties of the ITraceTaskResults interface return the
'results of the last trace performed by this trace task.
Private Property Get ITraceTaskResults_ResultEdges() As IEnumNetEID
  Set ITraceTaskResults_ResultEdges = m_pResultEdges
End Property

Private Property Get ITraceTaskResults_ResultJunctions() As IEnumNetEID
  Set ITraceTaskResults_ResultJunctions = m_pResultJunctions
End Property

Private Sub UTIL_SetBarriers(pResultJunctions As IEnumNetEID, pNetSolver As INetSolver)
On Error GoTo ErrHand:
  Dim lLoop As Integer, pFeatureLayer As IFeatureLayer
  Dim pNetworkAnalysisExt As esriEditorExt.INetworkAnalysisExt
'  Dim pNetElementBarrier As INetElementBarriers2
  Dim pNetElementBarrier As INetElementBarriers
  Dim pNetworkAnalysisExtBarriers As INetworkAnalysisExtBarriers
  Dim lNetEID As Long, lLoop2 As Long, lFeatClass As Long
  Dim lNetEIDs() As Long, lCount As Long
  Dim pNetElems As INetElements
  Dim lUserIDClass As Long, lUserID As Long, lSub As Long
  
  'Initialize the barrier set
  Set pNetworkAnalysisExt = m_pUtilityNetworkAnalysisExt
  Set pNetworkAnalysisExtBarriers = pNetworkAnalysisExt
  Set pNetElementBarrier = New NetElementBarriers
  pNetElementBarrier.ElementType = esriETJunction
  Set pNetElementBarrier.Network = pNetworkAnalysisExt.CurrentNetwork.Network
  Set pNetElems = pNetworkAnalysisExt.CurrentNetwork.Network
  
  'Make a string of the disabled layer feature class IDs
  For lLoop = 0 To pNetworkAnalysisExt.FeatureLayerCount - 1
    Set pFeatureLayer = pNetworkAnalysisExt.FeatureLayer(lLoop)
    If pNetworkAnalysisExtBarriers.GetDisabledLayer(pFeatureLayer) Then
      lFeatClass = pFeatureLayer.FeatureClass.FeatureClassID
    
      'Add barriers to the isolation features that are not currently part of the FindPath
      lCount = 0
      pResultJunctions.Reset
      For lLoop2 = 1 To pResultJunctions.Count
        lNetEID = pResultJunctions.Next
        If m_lJuncEID <> lNetEID Then
          pNetElems.QueryIDs lNetEID, esriETJunction, lUserIDClass, lUserID, lSub
          If lUserIDClass = lFeatClass Then
            ReDim Preserve lNetEIDs(lCount)
            lNetEIDs(lCount) = lUserID
            lCount = lCount + 1
          End If
        End If
      Next lLoop2
        
      If lCount > 0 Then
        pNetElementBarrier.SetBarriers lFeatClass, lCount, lNetEIDs(0)
        Set pNetSolver.ElementBarriers(esriETJunction) = pNetElementBarrier
      End If
    End If
  Next lLoop
    
  Exit Sub

ErrHand:
  MsgBox "UTIL_SetBarriers - " & Err.Description
End Sub

Public Function UTIL_CoreTraceSetup() As esriNetworkAnalysis.ITraceFlowSolver
'this function prepares the network for tracing.
  
  On Error GoTo ErrorHandler
  
  Dim pNetworkAnalysisExt As esriEditorExt.INetworkAnalysisExt
  Dim pNetSolver As esriNetworkAnalysis.INetSolver
  Dim pNetworkAnalysisExtFlags As esriEditorExt.INetworkAnalysisExtFlags
  Dim pFlagDisplay As esriNetworkAnalysis.IFlagDisplay
  Dim pEdgeFlagDisplay As esriNetworkAnalysis.IEdgeFlagDisplay
  Dim pEdgeFlags() As esriNetworkAnalysis.IEdgeFlag
  Dim pJunctionFlags() As esriNetworkAnalysis.IJunctionFlag
  Dim pNetFlag As esriNetworkAnalysis.INetFlag
  Dim pEdgeFlag As esriNetworkAnalysis.IEdgeFlag
  Dim pTraceFlowSolver As esriNetworkAnalysis.ITraceFlowSolver
  Dim pTraceTasks As esriEditorExt.ITraceTasks
  Dim lngEdgeFlagCount As Long
  Dim lngJunctionFlagCount As Long
  Dim lLoop As Long
  Dim pNetElems As INetElements
  
  Set pNetworkAnalysisExt = m_pUtilityNetworkAnalysisExt
  Set pNetElems = pNetworkAnalysisExt.CurrentNetwork.Network
  
  'initialize the trace flow solver
  'co-create a new TraceFlowSolver object
  Set pNetSolver = New esriNetworkAnalysis.TraceFlowSolver
  'set the source network for the solver
  Set pNetSolver.SourceNetwork = pNetElems
    
  'assign the flags to the network solver
  'first, get the edge flags
  'QI for the ITraceFlowSolver interface using INetSolver interface
  Set pTraceFlowSolver = pNetSolver
  'QI for the INetworkAnalysisExtFlags interface using IUtilityNetworkAnalysisExt
  Set pNetworkAnalysisExtFlags = m_pUtilityNetworkAnalysisExt
  'determine the number of edge flags on the current network
  lngEdgeFlagCount = pNetworkAnalysisExtFlags.EdgeFlagCount
  'only execute this next bit if there are any edge flags
  If Not lngEdgeFlagCount = 0 Then
    'redimension the array to hold the correct number of edge flags
    ReDim pEdgeFlags(0 To lngEdgeFlagCount - 1)
    For lLoop = 0 To lngEdgeFlagCount - 1
      'assign to a local IFlagDisplay and IEdgeFlagDisplay variables
      Set pFlagDisplay = pNetworkAnalysisExtFlags.EdgeFlag(lLoop)
      Set pEdgeFlagDisplay = pFlagDisplay
      'co-create a new EdgeFlag object
      Set pNetFlag = New esriNetworkAnalysis.EdgeFlag
      Set pEdgeFlag = pNetFlag
      'assign the properties of the EdgeFlagDisplay object to the EdgeFlag object
      pEdgeFlag.Position = pEdgeFlagDisplay.Percentage
      pNetFlag.UserClassID = pFlagDisplay.FeatureClassID
      pNetFlag.UserID = pFlagDisplay.FID
      pNetFlag.UserSubID = pFlagDisplay.SubID
      'add the new EdgeFlag object to the array
      Set pEdgeFlags(lLoop) = pNetFlag
    Next lLoop
    'add the edge flags to the network solver
    pTraceFlowSolver.PutEdgeOrigins lngEdgeFlagCount, pEdgeFlags(0)
  End If
  
  'next, get the junction flags
  'determine the number of junction flags on the network
  lngJunctionFlagCount = pNetworkAnalysisExtFlags.JunctionFlagCount
  'only execute this next bit if there are junction flags
  If Not lngJunctionFlagCount = 0 Then
    'redimension the array to hold the correct number of junction flags
    ReDim pJunctionFlags(0 To lngJunctionFlagCount - 1)
    For lLoop = 0 To lngJunctionFlagCount - 1
      'assign to a local IFlagDisplay variable
      Set pFlagDisplay = pNetworkAnalysisExtFlags.JunctionFlag(lLoop)
      'co-create a new JunctionFlag object
      Set pNetFlag = New esriNetworkAnalysis.JunctionFlag
      'assign the properties of the JunctionFlagDisplay object to the JunctionFlag object
      pNetFlag.UserClassID = pFlagDisplay.FeatureClassID
      pNetFlag.UserID = pFlagDisplay.FID
      pNetFlag.UserSubID = pFlagDisplay.SubID
      'add the new junction flag to the array of junction flags
      Set pJunctionFlags(lLoop) = pNetFlag
      m_lJuncEID = pNetElems.GetEID(pFlagDisplay.FeatureClassID, pFlagDisplay.FID, _
       pFlagDisplay.SubID, esriETJunction)
    Next lLoop
    'add the junction flags to the network solver
    pTraceFlowSolver.PutJunctionOrigins lngJunctionFlagCount, pJunctionFlags(0)
  End If
  
  'set the option for tracing on indeterminate flow
  'QI for the ITraceTasks interface using IUtilityNetworkAnalysisExt
  Set pTraceTasks = m_pUtilityNetworkAnalysisExt
  pTraceFlowSolver.TraceIndeterminateFlow = pTraceTasks.TraceIndeterminateFlow
  
  'pass the TraceFlowSolver object back the network solver
  Set UTIL_CoreTraceSetup = pTraceFlowSolver
  
  Exit Function
  
ErrorHandler:
  'an unexpected error occured somewhere in the function
  'notify the user that an error occurred and exit the sub
  MsgBox "Unexpected error:" & vbCrLf & Err.Description, vbOKOnly, "My Upstream Trace"
  
End Function