AnsweredAssumed Answered

Build Network Dataset with python comtypes and ArcObjects

Question asked by Caleb1987 on Aug 7, 2014
Latest reply on Aug 7, 2014 by Caleb1987

I know this isn't possible in arcpy, so I thought I'd give it a stab using comtypes and a modified version of the Snippets module. I am trying to translate some of the VB.NET code to create a network dataset from the help docs.

 

I'm trying to automate this process for an engineer as he is not very experienced with GIS. He will always be using a file geodatabase with one line feature class as edge features (fc name will vary) and two point feature classes as junction features (sources and sinks to act as origins and destinations). Once the network is built, he can use other script tools I am providing him to do the whole analysis.

 

I think I am pretty close as I am able to create the edge and junction features, but my code is failing at one of the last steps which is getting the extension for the IFeatureDatasetExtensionContainer interface via the FindExtension method. The help docs say I can use the esriGeoDatabase.esriDatasetType constant but this seems to be causing an error.  Here is the snippet that is failing:

 

# create network data set based on data element
fdxc = CType(fdsGDS, esriGeoDatabase.IFeatureDatasetExtensionContainer)
fdx = fdxc.FindExtension(esriGeoDatabase.esriDatasetType(7))  # get error here
dsc = CType(fdx, esriGeoDatabase.IDatasetContainer2)
netds = CType(dsc.CreateDataset(nd), esriGeoDatabase.INetworkDataset)

 

And here his my error:

 

Traceback (most recent call last):
  File "\\arcserver1\GIS\_Resources\ESRI\Python\BMI_Library\arcobjects\network_dataset.py", line 114, in <module>
  create_nd(gdb)
  File "\\arcserver1\GIS\_Resources\ESRI\Python\BMI_Library\arcobjects\network_dataset.py", line 98, in create_nd
  fdx = fdxc.FindExtension(esriGeoDatabase.esriDatasetType(7))
COMError: (-2147220729, None, (u'The specified feature dataset extension type was not found.', u'Esri GeoDatabase', u'esri_csGeoDatabase.hlp', 0, None))

And here is my full code if that helps:

 

from arcobjects import * #my modified version of Snippets (has CType and NewObj functions)
import arcpy, os

def create_nd(gdb):
    arcpy.CheckOutExtension('Network')
    getModule('esriGeoDatabase.olb')
    getModule('esriDataSourcesGDB.olb')
    import comtypes.gen.esriGeoDatabase as esriGeoDatabase
    import comtypes.gen.esriDataSourcesGDB as esriDataSourcesGDB

    # create new empty data element for buildable network dataset
    nd = NewObj(esriGeoDatabase.DENetworkDataset,
                esriGeoDatabase.IDENetworkDataset2)
    nd.Buildable = True
    nd.NetworkType = esriGeoDatabase.esriNetworkDatasetType(1)

    # open feature dataset and create IGeoDataset interface
    pWSF = NewObj(esriDataSourcesGDB.FileGDBWorkspaceFactory, esriGeoDatabase.IWorkspaceFactory)
    gdbWSF = CType(pWSF, esriGeoDatabase.IWorkspaceFactory)
    print gdbWSF.WorkspaceDescription, gdbWSF.WorkspaceType
    gdbFWS = CType(gdbWSF.OpenFromFile(gdb, 0), esriGeoDatabase.IFeatureWorkspace)
    print gdbFWS
    openFWS = gdbFWS.OpenFeatureDataset('FlowNet')
    fdsGDS = CType(openFWS, esriGeoDatabase.IGeoDataset)
    print fdsGDS

    # copy feature dataset's extent and spatial reference to network dataset element
    deGDS = CType(nd, esriGeoDatabase.IDEGeoDataset)
    deGDS.Extent = fdsGDS.Extent
    deGDS.SpatialReference = fdsGDS.SpatialReference
    print deGDS.Extent

    # get flow lines
    arcpy.env.workspace = os.path.join(gdb, 'FlowNet')
    lines = arcpy.ListFeatureClasses('*', 'Polyline')[0]  

    # create data element
    dataElement = CType(nd, esriGeoDatabase.IDataElement)
    dataElement.Name = 'FlowNetwork'
    print dataElement.Name

    # specify edge features
    edgeNet = NewObj(esriGeoDatabase.EdgeFeatureSource,
                     esriGeoDatabase.INetworkSource)
    edgeNet.Name = lines
    edgeNet.ElementType = esriGeoDatabase.esriNetworkElementType(2)
##    edgeNet.SourceType = esriGeoDatabase.esriNetworkSourceType(3)
##    edgeNet.UsesGeometryInConnectivity = True

    #set edge feature's connectivity (Any Vertex)
    edgeFS = CType(edgeNet, esriGeoDatabase.IEdgeFeatureSource)
    edgeFS.UsesSubtypes = False
    edgeFS.ClassConnectivityGroup = 1
    edgeFS.ClassConnectivityPolicy = esriGeoDatabase.esriNetworkEdgeConnectivityPolicy(0) # any vertex
    

    # add sources and sinks as junctions
    # make origins
    sinkNet = NewObj(esriGeoDatabase.JunctionFeatureSource,
                     esriGeoDatabase.INetworkSource)
    sinkNet.Name = 'Sinks'
    sinkNet.ElementType = esriGeoDatabase.esriNetworkElementType(1)
##    sinkNet.SourceType = esriGeoDatabase.esriNetworkSourceType(2)
##    sinkNet.UsesGeometryInConnectivity = True

    # set connectivity
    sinkElm = CType(sinkNet, esriGeoDatabase.IJunctionFeatureSource)
    sinkElm.UsesSubtypes = False
    sinkElm.ClassConnectivityGroup = 1
    sinkElm.ClassConnectivityPolicy = esriGeoDatabase.esriNetworkJunctionConnectivityPolicy(0) # honor

    # make destinations
    sourceNet = NewObj(esriGeoDatabase.JunctionFeatureSource,
                     esriGeoDatabase.INetworkSource)
    sourceNet.Name = 'Sources'
    sourceNet.ElementType = esriGeoDatabase.esriNetworkElementType(1)
##    sourceNet.SourceType = esriGeoDatabase.esriNetworkSourceType(2)
##    sourceNet.UsesGeometryInConnectivity = True

    # set connectivity
    sourceElm = CType(sourceNet, esriGeoDatabase.IJunctionFeatureSource)
    sourceElm.UsesSubtypes = False
    sourceElm.ClassConnectivityGroup = 1
    sourceElm.ClassConnectivityPolicy = esriGeoDatabase.esriNetworkJunctionConnectivityPolicy(0) # honor
    
    # add attributes (Length, Cost, Units)
    evalNetAttr = NewObj(esriGeoDatabase.EvaluatedNetworkAttribute,
                         esriGeoDatabase.IEvaluatedNetworkAttribute)
    newAttr2 = CType(evalNetAttr, esriGeoDatabase.INetworkAttribute2)
    newAttr2.Name = 'Length'
    newAttr2.UsageType = esriGeoDatabase.esriNetworkAttributeUsageType(0) # cost
    newAttr2.DataType = esriGeoDatabase.esriNetworkAttributeDataType(2) # double
    newAttr2.Units = esriGeoDatabase.esriNetworkAttributeUnits(3)  # feet
    newAttr2.UseByDefault = True

    # create network data set based on data element
    fdxc = CType(fdsGDS, esriGeoDatabase.IFeatureDatasetExtensionContainer)
    fdx = fdxc.FindExtension(esriGeoDatabase.esriDatasetType(7))
    dsc = CType(fdx, esriGeoDatabase.IDatasetContainer2)
    netds = CType(dsc.CreateDataset(nd), esriGeoDatabase.INetworkDataset)

    # build network dataset now that it's created
    netBuild = CType(netds, esriGeoDatabase.INetworkBuild)
    for item in [edgeNet, sinkNet, sourceNet]:
        netBuild.AddSource(item)
    netBuild.AddAttribute(newAttr2)
    netBuild.BuildNetwork(fsdGDS.Extent)
    arcpy.CheckInExtension('Network')
    return

if __name__ == '__main__':

    gdb = r'C:\Users\calebma\Desktop\NA_Testing\test2.gdb'
    create_nd(gdb)
    print 'done'

Outcomes