How to check for topology error features in a geodatabase topology


Summary
This document describes the different ways to search for and find error features discovered during validation of a geodatabase topology. The examples are based on the Montgomery_full file geodatabase, found with the Desktop tutorial data (the default directory is C:\arcgis\ArcTutor\EditingWithArcGIS).

In this topic


Making Edits to Violate the Topology's Rules

In it's original form, the Montgomery_full geodatabase's Landbase_topology will validate without any errors found.  As the purpose of this article is finding and displaying error features, we first need to create new features which will violate the topology's rules.  If you aren't using the Montgomery_full geodatabase, but another geodatabase with a topology that already has error features, you may want to skip to the next section.
The Landbase_topology has two feature classes participating in it, the parcels feature class (polygons representing parcels of land, including roads) and the blocks feature class (polygons representing neighborhood blocks - roads are not included).  It has two rules by default:  parcels must not overlap other parcels, and residential parcels must be covered by residential blocks.  The second rule specifies residential parcels and blocks by only applying to the feature classes' residential subtypes.
Walking step-by-step through this article requires editing feature classes from the Montgomery_full geodatabase.  If you want to retain a copy of the original, it is recommended that you copy the geodatabase at this point (for example, by using ArcCatalog) and use the copy to follow this example.
For the purposes of the examples below, two new features need to be created.  The first will be a new non-residential parcel in the middle of a residential block, overlapping several existing parcels.  The second will be a new parcel (with a residential subtype) over an existing parcel and block (both with non-residential subtypes).  The first new feature will violate the first rule, and the second will violate both rules.
The following images show examples of placements in ArcMap:
Zooming out and validating the topology will show two areas with errors (which are actually four separate error features):

Opening the Topology

After saving the edits and closing ArcMap, we can start writing code to access the error features programmatically.  The first step is opening the topology.  This is done by opening a feature dataset, casting it to the ITopologyContainer interface, then opening the topology using the ITopologyContainer.TopologyByName property.  The following code shows how to do this:
[Java]
// For example, featureDatasetName = "Landbase"
// topologyName = "Landbase_topology"
public static ITopology openTopologyFromFeatureWorkspace(IFeatureWorkspace
    featureWorkspace, String featureDatasetName, String topologyName)throws
    Exception{
    // Open the feature dataset and cast it to the ITopologyContainer interface.
    IFeatureDataset featureDataset = featureWorkspace.openFeatureDataset
        (featureDatasetName);
    ITopologyContainer topologyContainer = (ITopologyContainer)featureDataset;
    // Open the topology and return it.
    ITopology topology = topologyContainer.getTopologyByName(topologyName);
    return topology;
}

}
Checking for Topology Error Features
Once you've made edits to a feature class that participates in a topology and validate those edits, there may be topological errors. You can check whether there are any errors in your topology through the use of the ITopology.State property. ITopology.State returns a value from the esriTopologyState enumeration; if errors are found, the esriTopologyState.esriTSAnalyzedWithErrors value will be returned.
Viewing a Topology's Rules
The topology's rules can be accessed using the ITopologyRuleContainer interface, which a topology can be cast to.  The ITopologyRuleContainer interface has several methods for viewing a topology's rules based on a feature class' ID or a specific subtype of a feature class.  The following example shows how to acquire and use an enumerator for all of a topology's rules:
[Java]
public static void displayTypesForEachRule(ITopology topology)throws Exception{
    // Cast the topology to the ITopologyRuleContainer interface and get the rule enumerator.
    ITopologyRuleContainer topologyRuleContainer = (ITopologyRuleContainer)topology;
    IEnumRule enumRule = topologyRuleContainer.getRules();
    // Iterate through each rule.
    enumRule.reset();
    IRule rule = null;
    while ((rule = enumRule.next()) != null){
        // Cast to the ITopology interface and display the rule type.
        ITopologyRule topologyRule = (ITopologyRule)rule;
        System.out.println("Rule type: " + topologyRule.getTopologyRuleType());
    }
}
For the Montgomery_full example, the code example above should display two rules:
For more information about these types (as well as other topology rule types), see the ITopologyRule interface and the esriTopologyRuleType enumeration.

Accessing a Topology's Error Features

Topologies can be cast to the IErrorFeatureContainer interface, which has properties that can be used to return the error features associated with a topology. Once you return the error features associated with a topology, you can examine the following properties, through the ITopologyErrorFeature interface:
Each property on the IErrorFeatureContainer interface requires a spatial reference parameter. For most users, this will be the spatial reference of the topology.  The following code example demonstrates the quickest method for obtaining the spatial reference of a topology:
[Java]
public ISpatialReference getSpatialReferenceFromTopology(ITopology topology)throws
    Exception{

    IGeoDataset geoDataset = (IGeoDataset)topology;
    ISpatialReference spatialReference = geoDataset.getSpatialReference();
}
The code above will be included as part of the later samples in this article.
Accessing Error Features With An ITopologyRule
There are four properties on the IErrorFeatureContainer interface, each with its own purpose and use. The IErrorFeatureContainer.ErrorFeatures property returns an enumeration of error features belonging to the specified topology rule within the supplied extent.  The following example shows how to get the error features for the extent of the topology:
[Java]
// Given the topology and specific topology rule, return the error features for that rule.
public static void displayErrorFeaturesForRule(ITopology topology, ITopologyRule
    topologyRule)throws Exception{
    // Cast to required interfaces and get the spatial reference.
    IErrorFeatureContainer errorFeatureContainer = (IErrorFeatureContainer)topology;
    IGeoDataset geoDataset = (IGeoDataset)topology;
    ISpatialReference spatialReference = geoDataset.getSpatialReference();
    // Get an enumerator for the error features.
    IEnumTopologyErrorFeature enumTopologyErrorFeature =
        errorFeatureContainer.getErrorFeatures(spatialReference, topologyRule,
        geoDataset.getExtent(), true, false);
    // Display the origin IDs for each of the error features.
    ITopologyErrorFeature topologyErrorFeature = null;
    while ((topologyErrorFeature = enumTopologyErrorFeature.next()) != null){
        System.out.println("Origin feature OID: " +
            topologyErrorFeature.getOriginOID());
    }
}
The final two parameters of the IErrorFeatureContainer.ErrorFeatures property indicate, respectively, whether error features and error features marked as exceptions should be retrieved.  The example above will only show error features, and not exceptions.  At least one of the parameters must have a true value, or the property will fail.
For the Montgomery_full example, the above code will show four error features if provided with the first rule (of type esriTRTAreaNoOverlap) and one error feature if provided with the second rule (of type esriTRTAreaCoveredByArea).
Accessing Error Features By Geometry Type
The IErrorFeatureContainer.ErrorFeaturesByGeometryType property returns all error features of a certain geometry. See the following code, which writes the ID properties for each error feature with the specified geometry type to the console:
[Java]
public static void displayErrorFeatureByGeometryType(ITopology topology, int
    geometryType)throws Exception{
    // Cast to required interfaces and get the spatial reference.
    IErrorFeatureContainer errorFeatureContainer = (IErrorFeatureContainer)topology;
    IGeoDataset geoDataset = (IGeoDataset)topology;
    ISpatialReference spatialReference = geoDataset.getSpatialReference();
    // Get all the errors that have the specified geometry type.
    IEnumTopologyErrorFeature enumTopologyErrorFeature =
        errorFeatureContainer.getErrorFeaturesByGeometryType(spatialReference,
        geometryType, false);
    // Display each error feature (if any exist) and display their properties.
    ITopologyErrorFeature topologyErrorFeature = null;
    while ((topologyErrorFeature = enumTopologyErrorFeature.next()) != null){
        System.out.println("Error Feature Origin Class ID: " +
            topologyErrorFeature.getOriginClassID());
        System.out.println("Error Feature Origin Feature ID: " +
            topologyErrorFeature.getOriginOID());
        System.out.println("Error Feature Dest. Class ID: " +
            topologyErrorFeature.getDestinationClassID());
        System.out.println("Error Feature Dest. Feature ID: " +
            topologyErrorFeature.getDestinationOID());
    }
}
Similar to the IErrorFeatureContainer.ErrorFeatures property, the final parameter of the IErrorFeatureContainer.ErrorFeaturesByGeometryType property is a boolean indicating whether errors or exceptions should be returned.  If it's set to false (as it is above), only error features will be returned; if it's set to true, only exceptions will be returned.
In the Montgomery_full example, the above code - if provided with the esriGeometryPolygon value from the esriGeometryType enumeration - should display the properties for all four error features created.
Accessing Error Features By Rule Type
The IErrorFeatureContainer.ErrorFeaturesByRuleType property returns an enumeration of error features belonging to the specified topology rule type within the supplied extent.  Note how this differs from the IErrorFeatureContainer.ErrorFeatures property, in that a reference to an ITopologyRule isn't required, but rather a value from the esriTopologyRuleType enumeration is.  This also differs from the other property in that no specific rule is specified, so if several rules have the same rule type, error features from each will be returned.  See the following:
[Java]
public static void displayErrorFeatureByRuleType(ITopology topology, int
    topologyRuleType)throws Exception{
    // Cast to required interfaces and get the spatial reference.
    IErrorFeatureContainer errorFeatureContainer = (IErrorFeatureContainer)topology;
    IGeoDataset geoDataset = (IGeoDataset)topology;
    ISpatialReference spatialReference = geoDataset.getSpatialReference();
    // Return all the errors for the supplied rule in the given extent, then retrieve the first one.
    IEnumTopologyErrorFeature enumTopologyErrorFeature =
        errorFeatureContainer.getErrorFeaturesByRuleType(spatialReference,
        topologyRuleType, geoDataset.getExtent(), true, false);
    // Get the first error feature (if any exist) and display its properties.
    ITopologyErrorFeature topologyErrorFeature = enumTopologyErrorFeature.next();
    if (topologyErrorFeature != null){
        System.out.println("Error Feature Origin Class ID: " +
            topologyErrorFeature.getOriginClassID());
        System.out.println("Error Feature Origin Feature ID: " +
            topologyErrorFeature.getOriginOID());
        System.out.println("Error Feature Dest. Class ID: " +
            topologyErrorFeature.getDestinationClassID());
        System.out.println("Error Feature Dest. Feature ID: " +
            topologyErrorFeature.getDestinationOID());
    }
}
As with the IErrorFeatureContainer.ErrorFeatures property, the final two parameters are booleans, the first indicating whether error features will be returned, the second indicating whether exceptions will be returned.  The code sample above will only return error features, not exceptions.  Also, as with the IErrorFeatureContainer.ErrorFeatures property, if used with the Montgomery_full example, the above code will show four error features if provided with the first rule type (esriTRTAreaNoOverlap) and one error feature if provided with the second rule type (esriTRTAreaCoveredByArea).
Accessing Error Features Individually
The IErrorFeatureContainer.ErrorFeature property returns a specific topology error feature corresponding to the rule type, geometry type, and source feature information. The rule and geometry type are both required, as topological rules can result in error features with different geometries: point, line, or polygon. See the following:
[Java]
// The following example returns a polygon topology error feature for Must Not Overlap rule.
public static ITopologyErrorFeature getErrorFeatureForNoOverlapRule(ITopology
    topology, IFeatureClass featureClass, int originFeatureOID, int destFeatureOID)
    throws Exception{
    // Cast to required interfaces and get the spatial reference.
    IErrorFeatureContainer errorFeatureContainer = (IErrorFeatureContainer)topology;
    IGeoDataset geoDataset = (IGeoDataset)topology;
    ISpatialReference spatialReference = geoDataset.getSpatialReference();
    // Find the error feature and return it.
    ITopologyErrorFeature topologyErrorFeature =
        errorFeatureContainer.getErrorFeature(spatialReference,
        esriTopologyRuleType.esriTRTAreaNoOverlap,
        esriGeometryType.esriGeometryPolygon, featureClass.getFeatureClassID(),
        originFeatureOID, featureClass.getFeatureClassID(), destFeatureOID);
    return topologyErrorFeature;
}
In the Montgomery_full example, if we wanted the largest error feature created earlier (the one created in the second step), the origin feature OID parameter for the previous code sample would be 3297, and the destination feature OID parameter will vary depending on your editing workflow (in the example above it is 3741).  This shows how inconvenient this approach is for finding error features - nearly everything about the error feature must be known in order to retrieve it.
The IErrorFeatureContainer.ErrorFeature property has five parameters which require knowledge of the rule being used and the feature classes and features resulting in the error feature.  They are:
Passing correct values into each of these parameters is crucial, as the property will return a null value if any are incorrect.  In addition, not all of the parameters are applicable for each rule type.  An example is the "Must Not Have Gaps" rule.  Since gaps don't really belong to features, both the OriginOID and DestinationOID parameters must have values of 0.
Many rules involve a single class, with no "destination" class involved.  The previous code sample is an example of this.  Since two features are involved, both feature class IDs must be specified, even though the origin and destination class ID is the same.  For the most part, if only one feature class is part of the rule, and only a single feature is involved, the destination class ID can be set to 0.
Other rules use two classes but only an origin feature.  The polygon rule "Contains Point" follows this pattern.  The origin and destination class ID parameters must contain valid class IDs, but since the error features indicate the absence of a feature (a point within a polygon), the destination object ID will always be 0.  The polygon rule "Must Cover Each Other" requires features of two different polygon feature classes to cover each other; if it has an origin feature uncovered, the destination feature ID will be 0, but if a destination feature is uncovered, the origin feature ID will be 0.
Selecting the correct geometry type for the error feature is also important, as a rule that is applied to a feature class of a specific geometry type may return error features of a different geometry type.  An example of this is the "Must Not Have Gaps" rule, which applies to feature classes containing polygons but returns error features with polyline geometries.  Further complicating the situation is that not all rules consistently return error features with the same geometry type.  The rule for lines, "Must Not Intersect", is an example of this, as it can return error features with point or line geometries, depending on the cause of the error.  If an incorrect geometry type is passed to the IErrorFeatureContainer.ErrorFeature property, a null value will be returned, even if all of the other parameters are correct.
Accessing Error Features By Extent
There are several common searches that are performed when looking for topology error features.  The previous examples walked you through using the properties on the IErrorFeatureContainer interface to perform some of them.  Another common task is discovering the topology errors for all rules that are present within a given extent. 
The following code example demonstrates how to find all the topology error features for a given extent:
[Java]
public static void findAllErrorFeatures(ITopology topology, IEnvelope searchExtent)
    throws Exception{
    // Cast to required interfaces and get the spatial reference.
    IErrorFeatureContainer errorFeatureContainer = (IErrorFeatureContainer)topology;
    IGeoDataset geoDataset = (IGeoDataset)topology;
    ISpatialReference spatialReference = geoDataset.getSpatialReference();
    ITopologyRuleContainer topologyRuleContainer = (ITopologyRuleContainer)topology;
    // Get an enumerator for the topology's rules and iterate through them.
    IEnumRule enumRule = topologyRuleContainer.getRules();
    enumRule.reset();
    IRule rule = null;
    while ((rule = enumRule.next()) != null){
        // For each rule, get an enumerator for all of the error features and exceptions.
        ITopologyRule topologyRule = (ITopologyRule)rule;
        IEnumTopologyErrorFeature enumTopologyErrorFeature =
            errorFeatureContainer.getErrorFeatures(spatialReference, topologyRule,
            searchExtent, true, true);
        ITopologyErrorFeature topologyErrorFeature = null;
        while ((topologyErrorFeature = enumTopologyErrorFeature.next()) != null){
            // For each error feature, display the class ID, object ID, and whether or not its an exception.
            System.out.println("Class ID:" + topologyErrorFeature.getOriginClassID()
                + " Object ID: " + topologyErrorFeature.getOriginOID() + 
                " IsException " + topologyErrorFeature.isException());
        }
    }
}


See Also:

How to create a topology in the geodatabase
Topology Rules Poster




Development licensingDeployment licensing
ArcGIS for Desktop StandardArcGIS for Desktop Standard
ArcGIS for Desktop AdvancedArcGIS for Desktop Advanced
Engine Developer KitEngine: Geodatabase Update