Creating geometric networks within a geodatabase


Summary
A geometric network can be used to model the behavior features in a utility network, such as electrical and wastewater networks. Geometric networks are created from feature classes that reside in the same feature dataset. The geometric network stores the connectivity of the features and maintains it during editing. Each geometric network has an associated logical network, which is where the connectivity of the features is stored. The logical network is the mechanism through which on-the-fly connectivity is maintained and fast network analysis is accomplished.
The NetworkLoader class allows the specification of input parameters for the geometric network. Once all parameters are specified, the LoadNetwork method is called to create the geometric network according to the specified parameters.
Before creating the geometric network, ensure that an exclusive schema lock has been obtained for the feature dataset that will contain it. Use the ISchemaLock interface to determine if other locks exist and to get an exclusive lock on the feature dataset.
This topic demonstrates a common workflow for creating geometric networks.


About creating geometric networks within a geodatabase

The first step in programmatically creating a geometric network is instantiating a NetworkLoader object. The INetworkLoader2 interface (which inherits the members of INetworkLoader) can be used to set its properties. See the following code example:
[C#]
INetworkLoader2 networkLoader2 = new NetworkLoaderClass();
[VB.NET]
Dim networkLoader2 As INetworkLoader2 = New NetworkLoaderClass()

Network name

The NetworkName property is required when creating a geometric network. The name of the geometric network (fully qualified name for ArcSDE geodatabases) must be unique within the geodatabase. The IWorkspace2.NameExists property can be used to verify the uniqueness of a name.
If the feature dataset being used only contains a single geometric network, it might be convenient to name the geometric network based on the name of the feature dataset. See the following code example:
[C#]
networkLoader2.NetworkName = "Water_Net";
[VB.NET]
networkLoader2.NetworkName = "Water_Net"

Network type

A geometric network can be one of two types—utility or street. The majority of the functionality in geometric networks has been implemented for utility networks. Network datasets are tailored for use with street networks. See the following code example:
[C#]
networkLoader2.NetworkType = esriNetworkType.esriNTUtilityNetwork;
[VB.NET]
networkLoader2.NetworkType = esriNetworkType.esriNTUtilityNetwork

Feature dataset name

Geometric networks can only be created within a feature dataset. The NetworkLoader needs a reference to a FeatureDatasetName object for the feature dataset that contains the geometric network. The featureDatasetName variable in the following code example is a reference to an instance of the FeatureDatasetName class:
[C#]
networkLoader2.FeatureDatasetName = (IDatasetName)featureDatasetName;
[VB.NET]
networkLoader2.FeatureDatasetName = CType(featureDatasetName, IDatasetName)

Adding feature classes

A geometric network is built from feature classes. These feature classes must be contained within the feature dataset specified by the INetworkLoader.FeatureDatasetName property. There are some restrictions on the types of feature classes that can participate in a geometric network. Feature classes must be lines or points, cannot already be participating in a geometric network, and in the case of SDE, must not be registered as versioned. Before adding a feature class, check for these violations and any others by calling the INetworkLoader2.CanUseFeatureClass method. See the following code example:
[C#]
// Add the two classes to the network.
if (networkLoader2.CanUseFeatureClass("Distribmains") ==
    esriNetworkLoaderFeatureClassCheck.esriNLFCCValid)
{
    networkLoader2.AddFeatureClass("Distribmains", esriFeatureType.esriFTComplexEdge,
        null, false);
}

if (networkLoader2.CanUseFeatureClass("Tanks") ==
    esriNetworkLoaderFeatureClassCheck.esriNLFCCValid)
{
    networkLoader2.AddFeatureClass("Tanks", esriFeatureType.esriFTSimpleJunction,
        null, false);
}
[VB.NET]
If networkLoader2.CanUseFeatureClass("Distribmains") = esriNetworkLoaderFeatureClassCheck.esriNLFCCValid Then
    networkLoader2.AddFeatureClass("Distribmains", esriFeatureType.esriFTComplexEdge, Nothing, False)
End If

If networkLoader2.CanUseFeatureClass("Tanks") = esriNetworkLoaderFeatureClassCheck.esriNLFCCValid Then
    networkLoader2.AddFeatureClass("Tanks", esriFeatureType.esriFTSimpleJunction, Nothing, False)
End If

Enabled or disabled field

Every feature class in a network must have a field that determines whether a feature is enabled or disabled. Enabled and disabled features affect how the flow and trace results are determined. Use the default name for the enabled and disabled field. If INetworkLoader.PutEnabledDisabledFieldName is not called for a feature class, the network loader uses the default name for the enabled and disabled field. See the following illustration:

The default name for the enabled and disabled field can be obtained from the INetworkLoaderProps.DefaultEnabledField property. If an existing field is specified as the enabled and disabled field, verify that this field is of the correct type and domain using the INetworkLoader2.CheckEnabledDisabledField method. The INetworkLoader2.PreserveEnabledValues property provides the option of resetting all values in the existing field to true or preserving the existing values. If the specified field does not exist, the network loader automatically adds it to the feature class when it builds the network, populating all values in this field with the value of true to indicate that the features are enabled.
The following code example demonstrates using the default enabled or disabled field name, and checking the field before calling PutEnabledDisabledFieldName (see the note that follows the code). The following code example also sets the PreserveEnabledValues property to true:
[C#]
INetworkLoaderProps networkLoaderProps = (INetworkLoaderProps)networkLoader2;
String defaultEnabledFieldName = networkLoaderProps.DefaultEnabledField;
esriNetworkLoaderFieldCheck enabledFieldCheck =
    networkLoader2.CheckEnabledDisabledField("Tanks", defaultEnabledFieldName);
switch (enabledFieldCheck)
{
    case esriNetworkLoaderFieldCheck.esriNLFCValid:
    case esriNetworkLoaderFieldCheck.esriNLFCNotFound:
        networkLoader2.PutEnabledDisabledFieldName("Tanks", defaultEnabledFieldName);
        break;
    default:
        Console.WriteLine(
            "The field {0} could not be used as an enabled/disabled field.",
            defaultEnabledFieldName);
        break;
}

networkLoader2.PreserveEnabledValues = true;
[VB.NET]
Dim networkLoaderProps As INetworkLoaderProps = CType(networkLoader2, INetworkLoaderProps)
Dim defaultEnabledFieldName As String = networkLoaderProps.DefaultEnabledField
Dim enabledFieldCheck As esriNetworkLoaderFieldCheck = networkLoader2.CheckEnabledDisabledField("Tanks", defaultEnabledFieldName)
Select Case enabledFieldCheck
    Case esriNetworkLoaderFieldCheck.esriNLFCValid
    Case esriNetworkLoaderFieldCheck.esriNLFCNotFound
        networkLoader2.PutEnabledDisabledFieldName("Tanks", defaultEnabledFieldName)
    Case Else
        Console.WriteLine("The field {0} could not be used as an enabled/disabled field.", defaultEnabledFieldName)
End Select

networkLoader2.PreserveEnabledValues = True
In reality, this code (with the exception of the call to PreserveEnabledValues) is not necessary, since in the absence of calls to PutEnabledDisabledFieldName for a feature class, the network loader assumes that the default enabled or disabled field should be used for that feature class. The preceding code example is provided for illustrative purposes only.

Ancillary roles

Geometric networks are used to model systems with directed flow where the direction of movement through the network is well defined. Flow direction in the geometric network is calculated using a series of sources and sinks. To participate as a source or sink, a feature class must be specified as having an ancillary role. Feature classes specified as having an ancillary role indicate that their features can act as sources or sinks to determine flow within the network. Only point feature classes can be specified as having an ancillary role; however, multiple point feature classes in a network can have ancillary roles. See the following illustration:
Use the INetworkLoader.PutAncillaryRole method to specify a feature class as participating as a source or sink. The field name passed in as the ancillaryRoleFieldName parameter should contain the ancillary role attribute for the feature class. Use the default name for the ancillary role field. The default name for the ancillary role field can be obtained from the INetworkLoaderProps.DefaultAncillaryRoleField property. If an existing field is specified as the ancillary role field, verify that this field is of the correct type and domain using the INetworkLoader2.CheckAncillaryRoleField method. If the specified field does not exist, the network loader automatically adds it to the feature class when it builds the network, populating all values in this field with 0.
The following code example demonstrates using the ancillary role field name and checking the ancillary role field before calling PutAncillaryRole:
[C#]
String defaultAncillaryRoleFieldName = networkLoaderProps.DefaultAncillaryRoleField;
esriNetworkLoaderFieldCheck ancillaryRoleFieldCheck =
    networkLoader2.CheckAncillaryRoleField("Tanks", defaultAncillaryRoleFieldName);
switch (ancillaryRoleFieldCheck)
{
    case esriNetworkLoaderFieldCheck.esriNLFCValid:
    case esriNetworkLoaderFieldCheck.esriNLFCNotFound:
        networkLoader2.PutAncillaryRole("Tanks",
            esriNetworkClassAncillaryRole.esriNCARSourceSink,
            defaultAncillaryRoleFieldName);
        break;
    default:
        Console.WriteLine(
            "The field {0} could not be used as an ancillary role field.",
            defaultAncillaryRoleFieldName);
        break;
}
[VB.NET]
Dim defaultAncillaryRoleFieldName As String = networkLoaderProps.DefaultAncillaryRoleField
Dim ancillaryRoleFieldCheck As esriNetworkLoaderFieldCheck = networkLoader2.CheckAncillaryRoleField("Tanks", defaultAncillaryRoleFieldName)
Select Case ancillaryRoleFieldCheck
    Case esriNetworkLoaderFieldCheck.esriNLFCValid
    Case esriNetworkLoaderFieldCheck.esriNLFCNotFound
        networkLoader2.PutAncillaryRole("Tanks", esriNetworkClassAncillaryRole.esriNCARSourceSink, defaultAncillaryRoleFieldName)
    Case Else
        Console.WriteLine("The field {0} could not be used as an ancillary role field.", defaultAncillaryRoleFieldName)
End Select

Configuration keyword

If the geometric network is created in an ArcSDE geodatabase, a configuration keyword can be specified for building the network. A configuration keyword is used to specify storage and location parameters for optimal space and disk location efficiency. The configuration keyword is provided by the database administrator. The variable workspace in the following code example is of type ESRI.ArcGIS.Geodatabase.IWorkspace:
[C#]
if (workspace.Type == esriWorkspaceType.esriRemoteDatabaseWorkspace)
{
    networkLoader2.ConfigurationKeyword = "Network_Defaults";
}
[VB.NET]
If workspace.Type = esriWorkspaceType.esriRemoteDatabaseWorkspace Then
    networkLoader2.ConfigurationKeyword = "Network_Defaults"
End If

Snapping

When a geometric network is built, feature connectivity is determined by the spatial relationship of the features. If features are geometrically coincident, they will be connected during network building.
It might be known, for example, where the line features of the network are located but not where the point features are located. In this case, specify that the point features should be snapped. The line features stay in the same position but the coordinates of the points change to match the line features. If more than one feature class is specified to be snapped, the mean coordinate is computed. Feature classes participate in snapping when they are added to the network loader using the INetworkLoader.AddFeatureClass method.

Snap tolerance

The snap tolerance controls the search distance used for establishing connectivity during the network building process. The snap tolerance is specified in map units.
The following code example shows how to specify the snap tolerance to be the minimum or default tolerance. Usually, the minimum snapping tolerance is used to ensure feature connectivity within a geometric network.
[C#]
networkLoader2.SnapTolerance = networkLoader2.MinSnapTolerance;
[VB.NET]
networkLoader2.SnapTolerance = networkLoader2.MinSnapTolerance

Adding weights

Weights can also be added to a network. A weight is the cost of moving along a feature in a network. In a water utility network, this can be the diameter of a pipe, which can have an effect on the amount of flow through the pipe. To get all the weights on a network, use the INetSchema interface. The following code example shows how to add a new integer weight:
[C#]
networkLoader2.AddWeight("MainWeight", esriWeightType.esriWTDouble, 0);

// For weights of type esriWTBitGate, the BitGateSize parameter should be set:
networkLoader2.AddWeight("WTBitGateEx", esriWeightType.esriWTBitGate, 5);
[VB.NET]
networkLoader2.AddWeight("MainWeight", esriWeightType.esriWTDouble, 0)

' For weights of type esriWTBitGate, the BitGateSize parameter should be set:
networkLoader2.AddWeight("WTBitGateEx", esriWeightType.esriWTBitGate, 5)
After adding a weight to the network, indicate the feature classes and fields the weight will be associated with. By default, weights are not associated with feature classes. Use the INetworkLoader.AddWeightAssociation method to indicate the feature classes and fields the weight uses.

Adding weight associations

The weights specified for the network need to have values. These values are taken from the fields of the feature classes that participate in the network. Adding weight associations indicates to the network which fields belong to which weights. A weight can be associated with multiple feature classes but can only be associated with a single field in each feature class. See the following code example:
[C#]
networkLoader2.AddWeightAssociation("MainWeight", "Distribmains", "DIAMETER");
[VB.NET]
networkLoader2.AddWeightAssociation("MainWeight", "Distribmains", "DIAMETER")
These associations are dependent on the type of field and the type of weight created. For example, a weight of type esriWTDouble can only be associated with a field of type esriFieldTypeDouble. For weights of type esriWTBitGate, the field type can be either esriFieldTypeInteger or esriFieldTypeSmallInteger.

Building the network

After specifying all of the parameters for the network, calling the INetworkLoader.LoadNetwork method builds the network. See the following code example:
[C#]
networkLoader2.LoadNetwork();
[VB.NET]
networkLoader2.LoadNetwork()

After building the network

The feature classes participating in the geometric network can contain features with invalid geometry. The types of invalid geometries are detailed in the esriNetworkErrorType enumeration. If these types of features exist, they will be identified during the network creation process and recorded into the geometric network error table. The error table is created only when features with invalid geometries are found.
The following set of properties can be used to discover if any invalid geometries were found during network creation and to return the total number of invalid geometries or the total for each feature class.
The following code example returns the name of the error table, which will generally be the name of the geometric network with "_ERR" appended to the end:
[C#]
String errorTableName = networkLoader2.ErrorTableName;
[VB.NET]
Dim errorTableName As String = networkLoader2.ErrorTableName
The following code example returns the number of invalid features for the specified feature class:
[C#]
int numInvalidFeatures = networkLoader2.get_NumInvalidFeatures("Distribmains");
[VB.NET]
Dim numInvalidFeatures As Integer = networkLoader2.NumInvalidFeatures("Distribmains")
The following code example returns the number of invalid features for all feature classes in the geometric network:
[C#]
int totalNumInvalidFeatures = networkLoader2.TotalNumInvalidFeatures;
[VB.NET]
Dim totalNumInvalidFeatures As Integer = networkLoader2.TotalNumInvalidFeatures

Complete code example

The following are complete code examples of the previously shown code:
[C#]
public void CreateGeometricNetwork(IWorkspace workspace, IFeatureDatasetName
    featureDatasetName)
{
    // Create a network loader.
    INetworkLoader2 networkLoader2 = new NetworkLoaderClass();

    // Set the network name.
    networkLoader2.NetworkName = "Water_Net";

    // Set the network type.
    networkLoader2.NetworkType = esriNetworkType.esriNTUtilityNetwork;

    // Set the containing feature dataset.
    networkLoader2.FeatureDatasetName = (IDatasetName)featureDatasetName;

    // Add the two classes to the network.
    if (networkLoader2.CanUseFeatureClass("Distribmains") ==
        esriNetworkLoaderFeatureClassCheck.esriNLFCCValid)
    {
        networkLoader2.AddFeatureClass("Distribmains",
            esriFeatureType.esriFTComplexEdge, null, false);
    }

    if (networkLoader2.CanUseFeatureClass("Tanks") ==
        esriNetworkLoaderFeatureClassCheck.esriNLFCCValid)
    {
        networkLoader2.AddFeatureClass("Tanks", esriFeatureType.esriFTSimpleJunction,
            null, false);
    }

    // Set the enabled field for the Distribmains class.
    INetworkLoaderProps networkLoaderProps = (INetworkLoaderProps)networkLoader2;
    String defaultEnabledFieldName = networkLoaderProps.DefaultEnabledField;
    esriNetworkLoaderFieldCheck enabledFieldCheck =
        networkLoader2.CheckEnabledDisabledField("Tanks", defaultEnabledFieldName);
    switch (enabledFieldCheck)
    {
        case esriNetworkLoaderFieldCheck.esriNLFCValid:
        case esriNetworkLoaderFieldCheck.esriNLFCNotFound:
            networkLoader2.PutEnabledDisabledFieldName("Tanks",
                defaultEnabledFieldName);
            break;
        default:
            Console.WriteLine(
                "The field {0} could not be used as an enabled/disabled field.",
                defaultEnabledFieldName);
            break;
    }

    networkLoader2.PreserveEnabledValues = true;

    // Set the ancillary role field for the tanks class.
    String defaultAncillaryRoleFieldName =
        networkLoaderProps.DefaultAncillaryRoleField;
    esriNetworkLoaderFieldCheck ancillaryRoleFieldCheck =
        networkLoader2.CheckAncillaryRoleField("Tanks",
        defaultAncillaryRoleFieldName);
    switch (ancillaryRoleFieldCheck)
    {
        case esriNetworkLoaderFieldCheck.esriNLFCValid:
        case esriNetworkLoaderFieldCheck.esriNLFCNotFound:
            networkLoader2.PutAncillaryRole("Tanks",
                esriNetworkClassAncillaryRole.esriNCARSourceSink,
                defaultAncillaryRoleFieldName);
            break;
        default:
            Console.WriteLine(
                "The field {0} could not be used as an ancillary role field.",
                defaultAncillaryRoleFieldName);
            break;
    }

    // If the geodatabase is an SDE GDB, set the configuration keyword.
    if (workspace.Type == esriWorkspaceType.esriRemoteDatabaseWorkspace)
    {
        networkLoader2.ConfigurationKeyword = "Network_Defaults";
    }

    // Set the snap tolerance for the network.
    networkLoader2.SnapTolerance = networkLoader2.MinSnapTolerance;

    // Add a weight with a double type to the network.
    networkLoader2.AddWeight("MainWeight", esriWeightType.esriWTDouble, 0);

    // For weights of type esriWTBitGate, the BitGateSize parameter should be set:
    networkLoader2.AddWeight("WTBitGateEx", esriWeightType.esriWTBitGate, 5);

    // Associate the MainWeight weight with the DIAMETER field of Distribmains.
    networkLoader2.AddWeightAssociation("MainWeight", "Distribmains", "DIAMETER");

    // Load the network.
    networkLoader2.LoadNetwork();

    // Get the name of the network's error table.
    String errorTableName = networkLoader2.ErrorTableName;

    // Display the number of invalid features in the Distribmains class.
    int numInvalidFeatures = networkLoader2.get_NumInvalidFeatures("Distribmains");
    Console.WriteLine("Distribmains contains {0} invalid features.",
        numInvalidFeatures);

    // Display the number of invalid features in the network.
    int totalNumInvalidFeatures = networkLoader2.TotalNumInvalidFeatures;
    Console.WriteLine("The network contains {0} invalid features.",
        totalNumInvalidFeatures);
}
[VB.NET]
Public Sub CreateGeometricNetwork(ByVal workspace As IWorkspace, ByVal featureDatasetName As IFeatureDatasetName)
    ' Create a network loader.
    Dim networkLoader2 As INetworkLoader2 = New NetworkLoaderClass()
    
    ' Set the network name.
    networkLoader2.NetworkName = "Water_Net"
    
    ' Set the network type.
    networkLoader2.NetworkType = esriNetworkType.esriNTUtilityNetwork
    
    ' Set the containing feature dataset.
    networkLoader2.FeatureDatasetName = CType(featureDatasetName, IDatasetName)
    
    ' Add the two classes to the network.
    If networkLoader2.CanUseFeatureClass("Distribmains") = esriNetworkLoaderFeatureClassCheck.esriNLFCCValid Then
        networkLoader2.AddFeatureClass("Distribmains", esriFeatureType.esriFTComplexEdge, Nothing, False)
    End If
    
    If networkLoader2.CanUseFeatureClass("Tanks") = esriNetworkLoaderFeatureClassCheck.esriNLFCCValid Then
        networkLoader2.AddFeatureClass("Tanks", esriFeatureType.esriFTSimpleJunction, Nothing, False)
    End If
    
    ' Set the enabled field for the Distribmains class.
    Dim networkLoaderProps As INetworkLoaderProps = CType(networkLoader2, INetworkLoaderProps)
    Dim defaultEnabledFieldName As String = networkLoaderProps.DefaultEnabledField
    Dim enabledFieldCheck As esriNetworkLoaderFieldCheck = networkLoader2.CheckEnabledDisabledField("Tanks", defaultEnabledFieldName)
    Select Case enabledFieldCheck
        Case esriNetworkLoaderFieldCheck.esriNLFCValid
        Case esriNetworkLoaderFieldCheck.esriNLFCNotFound
            networkLoader2.PutEnabledDisabledFieldName("Tanks", defaultEnabledFieldName)
        Case Else
            Console.WriteLine("The field {0} could not be used as an enabled/disabled field.", defaultEnabledFieldName)
    End Select
    
    networkLoader2.PreserveEnabledValues = True
    
    ' Set the ancillary role field for the tanks class.
    Dim defaultAncillaryRoleFieldName As String = networkLoaderProps.DefaultAncillaryRoleField
    Dim ancillaryRoleFieldCheck As esriNetworkLoaderFieldCheck = networkLoader2.CheckAncillaryRoleField("Tanks", defaultAncillaryRoleFieldName)
    Select Case ancillaryRoleFieldCheck
        Case esriNetworkLoaderFieldCheck.esriNLFCValid
        Case esriNetworkLoaderFieldCheck.esriNLFCNotFound
            networkLoader2.PutAncillaryRole("Tanks", esriNetworkClassAncillaryRole.esriNCARSourceSink, defaultAncillaryRoleFieldName)
        Case Else
            Console.WriteLine("The field {0} could not be used as an ancillary role field.", defaultAncillaryRoleFieldName)
    End Select
    
    ' If the geodatabase is an SDE GDB, set the configuration keyword.
    If workspace.Type = esriWorkspaceType.esriRemoteDatabaseWorkspace Then
        networkLoader2.ConfigurationKeyword = "Network_Defaults"
    End If
    
    ' Set the snap tolerance for the network.
    networkLoader2.SnapTolerance = networkLoader2.MinSnapTolerance
    
    ' Add a weight with a double type to the network.
    networkLoader2.AddWeight("MainWeight", esriWeightType.esriWTDouble, 0)
    
    ' For weights of type esriWTBitGate, the BitGateSize parameter should be set:
    networkLoader2.AddWeight("WTBitGateEx", esriWeightType.esriWTBitGate, 5)
    
    ' Associate the MainWeight weight with the DIAMETER field of Distribmains.
    networkLoader2.AddWeightAssociation("MainWeight", "Distribmains", "DIAMETER")
    
    ' Load the network.
    networkLoader2.LoadNetwork()
    
    ' Get the name of the network's error table.
    Dim errorTableName As String = networkLoader2.ErrorTableName
    
    ' Display the number of invalid features in the Distribmains class.
    Dim numInvalidFeatures As Integer = networkLoader2.NumInvalidFeatures("Distribmains")
    Console.WriteLine("Distribmains contains {0} invalid features.", numInvalidFeatures)
    
    ' Display the number of invalid features in the network.
    Dim totalNumInvalidFeatures As Integer = networkLoader2.TotalNumInvalidFeatures
    Console.WriteLine("The network contains {0} invalid features.", totalNumInvalidFeatures)
End Sub






To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):
Development licensing Deployment licensing
ArcGIS for Desktop Standard ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced
Engine Developer Kit Engine