Wednesday, 13 July 2016

arcpy - Build Network Dataset with python comtypes


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


http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/index.html#/How_to_create_a_network_dataset/0001000000w7000000/


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:


http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/index.html#//0025000002ww000000


here is where it 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)

Here is my error:



Traceback (most recent call last):
File "\\arcserver1\GIS\_Resources\ESRI\Python\BMI_Library\arcobjects\network_dataset.py", line 114, in
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:


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)) # fails here
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'


Answer



OK going to have a stab at this:


Most of your code appears to be building a Network dataset but this line


fdx = fdxc.FindExtension(esriGeoDatabase.esriDatasetType(7))  # get error here

is trying to return a GeometricNetwork (7), have a try at returning a Networkdataset (19)?


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...