Select to view content in your preferred language

Create topology with different feature classes both as single and multiple then run validate topology to find the errors using ArcObjects

78
1
10 hours ago
NinadPandit
New Contributor


I am writing code using ArcObjects 10.8.1 to find and delete the topology with a name and recreate a new topology with same name but with single feature class or different set of feature classes. However I am getting error code [-2147215017] error message [Exception from HRESULT: 0x80041957]. Here someone help with a clean code or fail safe code to implement the requirement.

Partial Code


public void RegisterClassToTopology(IFeatureDataset featureDataset, ITopology topology, IFeatureClass featureClass)
{
try
{
// 3. Verify the class belongs to the same Feature Dataset
if (featureClass.FeatureDataset.Name != featureDataset.Name)
{
throw new Exception("Feature Class must reside in the same Feature Dataset as the topology.");
}

// 4. Add the Feature Class to the topology framework
// Parameters: (IFeatureClass, Weight, XYRank, ZRank)
if (!IsClassAlreadyInTopology(topology, featureClass))
{
topology.AddClass(featureClass, 5, 1, 1, true);
}

System.Diagnostics.Debug.WriteLine("Feature class successfully added to topology via code.");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to add class: {ex.Message}");
throw;
}
}
public ITopologyRule AddTopologyRule(IFeatureDataset featureDataset, ITopology topology, IFeatureClass sfeatureClass, IFeatureClass cfeatureClass)
{
// 1. Cast to Topology Container
ISchemaLock schemaLock = (ISchemaLock)featureDataset;

try
{
// 2. Request an Exclusive Schema Lock to allow modifications
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);


//topology.AddClass(sourcefc, 5, 1, 1, false);
RegisterClassToTopology(featureDataset, topology, sfeatureClass);

if (cfeatureClass != null)
//topology.AddClass(connectedfc, 5, 1, 1, false);
RegisterClassToTopology(featureDataset, topology, cfeatureClass);

ITopologyRuleContainer ruleContainer = (ITopologyRuleContainer)topology;

esriTopologyRuleType ruletype = GetTopologyRuleType(sfeatureClass, cfeatureClass);

ITopologyRule rule = new TopologyRuleClass();

rule.Name = "Must Not Overlap";
rule.TopologyRuleType = ruletype;
rule.OriginClassID = sfeatureClass.FeatureClassID;

if (cfeatureClass != null)
{
rule.DestinationClassID = cfeatureClass.FeatureClassID;
}

// HANDLE SUBTYPES SAFELY
if (rule.OriginSubtypeSpecified)
{
ISubtypes subtypes = (ISubtypes)sfeatureClass;
rule.OriginSubtype = subtypes.HasSubtype ? subtypes.DefaultSubtypeCode : 0;
}

if (cfeatureClass != null && rule.DestinationSubtypeSpecified)
{
ISubtypes subtypes = (ISubtypes)cfeatureClass;
rule.DestinationSubtype = subtypes.HasSubtype ? subtypes.DefaultSubtypeCode : 0;
}

// CHECK EXISTING RULES PROPERLY
IEnumRule existingRules = ruleContainer.Rules;
existingRules.Reset();

IRule existingRule = existingRules.Next();

while (existingRule != null)
{
ITopologyRule thisrule = existingRule as ITopologyRule;
if (thisrule.TopologyRuleType == rule.TopologyRuleType &&
thisrule.OriginClassID == rule.OriginClassID &&
thisrule.DestinationClassID == rule.DestinationClassID)
{
Console.WriteLine("Rule already exists. Skipping.");
return thisrule;
}

existingRule = existingRules.Next();
}

// ADD RULE ONLY ONCE
ruleContainer.AddRule(rule);

Console.WriteLine("Rule added successfully.");
return rule;
}
catch (System.Runtime.InteropServices.COMException comEx)
{
// Extract the specific HRESULT code
int errorCode = comEx.ErrorCode;
string errorMessage = comEx.Message;

Console.WriteLine($"Failed to add topology rule. Code: {errorCode}. Message: {errorMessage}");
throw;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Failed to add class: {ex.Message}");
throw;
}
finally
{
// 5. CRITICAL: Always downgrade the lock back to Shared
schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
}
// The code has to handle single feature class and multiple feature class as well
public void CreateTopologyWithCrossorSameDatasetRules(IFeatureDataset featureDataset, string sourcefcname, string connectedfcname, ref StreamWriter sw)
{
// 1. Cast to topology container
ITopologyContainer2 topoContainer = (ITopologyContainer2)featureDataset;

DeleteTopologyIfExists(topoContainer, TEMP_TOPOLOGY_NAME);

try
{

// 2. Create topology
ITopology topology = topoContainer.CreateTopology(
TEMP_TOPOLOGY_NAME,
0.001, // Cluster tolerance
-1, // XY ranks default
""); // Config keyword

// 3. Open feature classes (must be in same feature dataset)
IFeatureWorkspace fws = (IFeatureWorkspace)featureDataset.Workspace;

IFeatureClass sourcefc = fws.OpenFeatureClass(sourcefcname);
IFeatureClass connectedfc = null;

if (!sourcefcname.Equals(connectedfcname))
{
connectedfc = fws.OpenFeatureClass(connectedfcname);
}

ITopologyRule addedrule = AddTopologyRule(featureDataset, topology, sourcefc, connectedfc);

// 6. Validate topology
IEnvelope envelope = ((IGeoDataset)featureDataset).Extent;
ISpatialReference datasetspatialreference = ((IGeoDataset)featureDataset).SpatialReference;

IWorkspaceEdit wsEdit = (IWorkspaceEdit)featureDataset.Workspace;

wsEdit.StartEditing(false);
wsEdit.StartEditOperation();

topology.ValidateTopology(envelope);

wsEdit.StopEditOperation();
wsEdit.StopEditing(true);

wsEdit.AbortEditOperation();
wsEdit.StopEditing(false);

// Assuming you have an ITopology object named pTopology
IErrorFeatureContainer pErrorContainer = topology as IErrorFeatureContainer;

// Define an envelope to check for errors (or use the validated area)
//IEnvelope pEnvelope = topology.Extent;

// Retrieve errors within the area
IEnumTopologyErrorFeature pEnumTopoError = pErrorContainer.ErrorFeatures[
datasetspatialreference,
addedrule,
envelope,
true, // Include errors
true // Include exceptions
];

ITopologyErrorFeature pTopoError = pEnumTopoError.Next();

while (pTopoError != null)
{
// Access error details
int errorID = pTopoError.OriginOID;
int desterrorID = pTopoError.DestinationOID;

IFeature originfeature = sourcefc.GetFeature(errorID);
IFeature destfeature = connectedfc.GetFeature(desterrorID);

IGeometry ogeom = originfeature.Shape;
IGeometry dgeom = destfeature.Shape;


ITopologicalOperator targetTopoOp = (ITopologicalOperator)ogeom;
IGeometry overlapGeometry = targetTopoOp.Intersect(dgeom, esriGeometryDimension.esriGeometry1Dimension);
double overlapLength = 0.0d;
double overlapPercent = 0.0f;

IPolyline overlapPolyline = (IPolyline)overlapGeometry;
double overlaplength = overlapPolyline.Length;
overlapLength = Math.Round(overlaplength, ROUND_OFF_VALUE);
ICurve lgeomcurve = ogeom as ICurve;
ICurve interCurve = overlapGeometry as ICurve;
// 4. Calculate Percentage
overlapPercent = Math.Round((interCurve.Length / lgeomcurve.Length) * 100, ROUND_OFF_VALUE);

esriTopologyRuleType ruleID = pTopoError.TopologyRuleType;
//IGeometry errorShape = pTopoError.Shape;

// Process error (e.g., log to file, highlight in map)
Console.WriteLine($"Error ID: {errorID}, Rule Type: {ruleID}");

dataGridViewOverlapping.Rows.Add(errorID, desterrorID, sourcefc.AliasName, connectedfc.AliasName, overlapLength, overlapPercent, "Overlapping");
string resultValue = errorID + "," + desterrorID + "," + sourcefc.AliasName + "," + connectedfc.AliasName + "," + overlapLength + "," + overlapPercent + "," + "Overlapping";
sw.WriteLine(resultValue);

pTopoError = pEnumTopoError.Next();
}

//schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
catch (System.Runtime.InteropServices.COMException comEx)
{
// Extract the specific HRESULT code
int errorCode = comEx.ErrorCode;
string errorMessage = comEx.Message;

Console.WriteLine($"Failed to add topology rule. Code: {errorCode}. Message: {errorMessage}");
}
finally
{

}
}

// This function finds the topology by name and deletes if it exists.
public void DeleteTopologyIfExists(ITopologyContainer topologyContainer, string topologyName)
{
if (topologyContainer != null)
{
ITopology topology = null;

try
{
// 3. Find and Delete Topology
topology = topologyContainer.get_TopologyByName(topologyName);
if (topology != null)
{
IDataset dataset = (IDataset)topology;
if (dataset.CanDelete())
{
dataset.Delete();
System.Diagnostics.Debug.WriteLine(topologyName + " deleted successfully.");
}
}

ITopology removedtopology = topologyContainer.TopologyByName[topologyName];
}
catch (System.Runtime.InteropServices.COMException ex)
{
System.Diagnostics.Debug.WriteLine("Topology not found or cannot be deleted: " + ex.Message);
}
finally
{
if (topology != null)
{
Marshal.ReleaseComObject(topology);
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
}

 

 

0 Kudos
1 Reply
NinadPandit
New Contributor

In addition to above, the line of code that generates error is mentioned below.

// ADD RULE ONLY ONCE
ruleContainer.AddRule(rule);

0 Kudos