ArcGIS Pro 3.3 API Reference Guide
ArcGIS.Core.Data.Topology Namespace / Topology Class / GetExtent Method
Example

In This Topic
    GetExtent Method (Topology)
    In This Topic
    Gets an ArcGIS.Core.Geometry.Envelope representing the maximum extent of the union of all the feature classes that participate in the Topology. This method must be called on the MCT. Use QueuedTask.Run.
    Syntax
    public Envelope GetExtent()
    Public Function GetExtent() As Envelope

    Return Value

    An ArcGIS.Core.Geometry.Envelope representing the maximum extent of the union of all the feature classes that participate in the Topology.
    Exceptions
    ExceptionDescription
    A geodatabase-related exception has occurred.
    Remarks
    Unlike a geodatabase topology whose extent dynamically reflects that of its constituent participating feature classes, a feature service topology's extent remains static for the duration of the life time of the object. In other words, a feature service topology's extent will not change even if the geometry of its participating feature classes is modified. As a consequence, if this is a feature service topology, GetExtent should not be used as input for ValidationDescription.Extent because the extent may have grown since it was opened.
    Example
    ValidateTopology
    public void ValidateTopology()
    {
      using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\TestData\GrandTeton.gdb"))))
      using (Topology topology = geodatabase.OpenDataset<Topology>("Backcountry_Topology"))
      {
        // If the topology currently does not have dirty areas, calling Validate() returns an empty envelope.
    
        ValidationResult result = topology.Validate(new ValidationDescription(topology.GetExtent()));
        Console.WriteLine($"'AffectedArea' after validating a topology that has not been edited => {result.AffectedArea.ToJson()}");
    
        // Now create a feature that purposely violates the "PointProperlyInsideArea" topology rule.  This action will
        // create dirty areas.
    
        Feature newFeature = null;
    
        try
        {
          // Fetch the feature in the Campsites feature class whose objectID is 2.  Then create a new geometry slightly
          // altered from this and use it to create a new feature.
    
          using (Feature featureViaCampsites2 = GetFeature(geodatabase, "Campsites", 2))
          {
            Geometry currentGeometry = featureViaCampsites2.GetShape();
            Geometry newGeometry = GeometryEngine.Instance.Move(currentGeometry, (currentGeometry.Extent.XMax / 8),
              (currentGeometry.Extent.YMax / 8));
    
            using (FeatureClass campsitesFeatureClass = featureViaCampsites2.GetTable())
            using (FeatureClassDefinition definition = campsitesFeatureClass.GetDefinition())
            using (RowBuffer rowBuffer = campsitesFeatureClass.CreateRowBuffer())
            {
              rowBuffer[definition.GetShapeField()] = newGeometry;
    
              geodatabase.ApplyEdits(() =>
              {
                newFeature = campsitesFeatureClass.CreateRow(rowBuffer);
              });
            }
          }
    
          // After creating a new feature in the 'Campsites' participating feature class, the topology's state should be 
          // "Unanalyzed" because it has not been validated.
    
          Console.WriteLine($"The topology state after an edit has been applied => {topology.GetState()}");
    
          // Now validate the topology.  The result envelope corresponds to the dirty areas.
    
          result = topology.Validate(new ValidationDescription(topology.GetExtent()));
          Console.WriteLine($"'AffectedArea' after validating a topology that has just been edited => {result.AffectedArea.ToJson()}");
    
          // After Validate(), the topology's state should be "AnalyzedWithErrors" because the topology currently has errors.
    
          Console.WriteLine($"The topology state after validate topology => {topology.GetState()}");
    
          // If there are no dirty areas, the result envelope should be empty.
    
          result = topology.Validate(new ValidationDescription(topology.GetExtent()));
          Console.WriteLine($"'AffectedArea' after validating a topology that has just been validated => {result.AffectedArea.ToJson()}");
        }
        finally
        {
          if (newFeature != null)
          {
            geodatabase.ApplyEdits(() =>
            {
              newFeature.Delete();
            });
    
            newFeature.Dispose();
          }
        }
    
        // Validate again after deleting the newly-created feature.
    
        topology.Validate(new ValidationDescription(topology.GetExtent()));
      }
    }
    
    private Feature GetFeature(Geodatabase geodatabase, string featureClassName, long objectID)
    {
      using (FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>(featureClassName))
      {
        QueryFilter queryFilter = new QueryFilter()
        {
          ObjectIDs = new List<long>() { objectID }
        };
    
        using (RowCursor cursor = featureClass.Search(queryFilter))
        {
          System.Diagnostics.Debug.Assert(cursor.MoveNext());
          return (Feature)cursor.Current;
        }
      }
    }
    
    MarkAndUnmarkAsErrors
    // Get all the errors due to features violating the "PointProperlyInsideArea" topology rule.
    
    using (TopologyDefinition topologyDefinition = topology.GetDefinition())
    {
      TopologyRule pointProperlyInsideAreaRule = topologyDefinition.GetRules().First(rule => rule.RuleType == TopologyRuleType.PointProperlyInsideArea);
    
      ErrorDescription errorDescription = new ErrorDescription(topology.GetExtent())
      {
        TopologyRule = pointProperlyInsideAreaRule
      };
    
      IReadOnlyList<TopologyError> errorsDueToViolatingPointProperlyInsideAreaRule = topology.GetErrors(errorDescription);
      Console.WriteLine($"There are {errorsDueToViolatingPointProperlyInsideAreaRule.Count} feature violating the 'PointProperlyInsideArea' topology rule.");
    
      // Mark all errors from features violating the 'PointProperlyInsideArea' topology rule as exceptions.
    
      foreach (TopologyError error in errorsDueToViolatingPointProperlyInsideAreaRule)
      {
        topology.MarkAsException(error);
      }
    
      // Now verify all the errors from features violating the 'PointProperlyInsideArea' topology rule have indeed been
      // marked as exceptions.
      //
      // By default, ErrorDescription is initialized to ErrorType.ErrorAndException.  Here we want ErrorType.ErrorOnly.
    
      errorDescription = new ErrorDescription(topology.GetExtent())
      {
        ErrorType = ErrorType.ErrorOnly,
        TopologyRule = pointProperlyInsideAreaRule
      };
    
      IReadOnlyList<TopologyError> errorsAfterMarkedAsExceptions = topology.GetErrors(errorDescription);
      Console.WriteLine($"There are {errorsAfterMarkedAsExceptions.Count} feature violating the 'PointProperlyInsideArea' topology rule after all the errors have been marked as exceptions.");
    
      // Finally, reset all the exceptions as errors by unmarking them as exceptions.
    
      foreach (TopologyError error in errorsDueToViolatingPointProperlyInsideAreaRule)
      {
        topology.UnmarkAsException(error);
      }
    
      IReadOnlyList<TopologyError> errorsAfterUnmarkedAsExceptions = topology.GetErrors(errorDescription);
      Console.WriteLine($"There are {errorsAfterUnmarkedAsExceptions.Count} feature violating the 'PointProperlyInsideArea' topology rule after all the exceptions have been reset as errors.");
    }
    
    FindClosestElement
    public void FindClosestElement()
    {
      using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\TestData\GrandTeton.gdb"))))
      using (Topology topology = geodatabase.OpenDataset<Topology>("Backcountry_Topology"))
      {
        // Build a topology graph using the extent of the topology dataset.
    
        topology.BuildGraph(topology.GetExtent(), (topologyGraph) =>
        {
          MapPoint queryPointViaCampsites12 = null;
    
          using (Feature campsites12 = GetFeature(geodatabase, "Campsites", 12))
          {
            queryPointViaCampsites12 = campsites12.GetShape() as MapPoint;
          }
    
          double searchRadius = 1.0;
    
          TopologyElement topologyElementViaCampsites12 = 
              topologyGraph.FindClosestElement<TopologyElement>(
                        queryPointViaCampsites12, searchRadius);
    
          System.Diagnostics.Debug.Assert(
            topologyElementViaCampsites12 != null, "There should be a topology element corresponding to 'queryPointViaCampsites12' within the 'searchRadius' units.");
    
          IReadOnlyList<FeatureInfo> parentFeatures = topologyElementViaCampsites12.GetParentFeatures();
    
          Console.WriteLine("The parent features that spawn 'topologyElementViaCampsites12' are:");
          foreach (FeatureInfo parentFeature in parentFeatures)
          {
            Console.WriteLine($"\t{parentFeature.FeatureClassName}; OID: {parentFeature.ObjectID}");
          }
    
          TopologyNode topologyNodeViaCampsites12 = topologyGraph.FindClosestElement<TopologyNode>(queryPointViaCampsites12, searchRadius);
    
          if (topologyNodeViaCampsites12 != null)
          {
            // There exists a TopologyNode nearest to the query point within searchRadius units.
          }
    
          TopologyEdge topologyEdgeViaCampsites12 = topologyGraph.FindClosestElement<TopologyEdge>(queryPointViaCampsites12, searchRadius);
    
          if (topologyEdgeViaCampsites12 != null)
          {
            // There exists a TopologyEdge nearest to the query point within searchRadius units.
          }
        });
      }
    }
    
    Requirements

    Target Platforms: Windows 11, Windows 10

    ArcGIS Pro version: 3 or higher.
    See Also