About the Reducing schematic nodes and computing a cumulative attribute via a schematic rule Sample
[C#]
NodeReductionRule.cs
using ESRI.ArcGIS; using ESRI.ArcGIS.ADF.CATIDs; using ESRI.ArcGIS.Schematic; using ESRI.ArcGIS.Framework; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.esriSystem; using System; using System.Runtime.InteropServices; using System.Collections.Generic; namespace CustomRulesCS { [ClassInterface(ClassInterfaceType.None)] [Guid(NodeReductionRule.GUID)] [ProgId(NodeReductionRule.PROGID)] public class NodeReductionRule : ISchematicRule, ISchematicRuleDesign { public const string GUID = "A6CB9935-AE08-46FB-9850-77C2B4E7C6A9"; public const string PROGID = "CustomRulesCS.NodeReductionRule"; // Register/unregister categories for this class #region "Component Category Registration" [System.Runtime.InteropServices.ComRegisterFunction()] public static void Register(string CLSID) { SchematicRules.Register(CLSID); } [System.Runtime.InteropServices.ComUnregisterFunction()] public static void Unregister(string CLSID) { SchematicRules.Unregister(CLSID); } #endregion private ISchematicDiagramClass m_diagramClass; private string m_description = "Reduction Node Rule - Report cumulative value C#"; private string m_lengthAttributeName; private string m_reducedNodeClassName; private string m_superspanLinkClassName; private string m_linkAttributeName; private bool m_keepVertices = true; private bool m_linkAttribute = false; #region NodeReductionRule interface public NodeReductionRule() { } ~NodeReductionRule() { m_diagramClass = null; } public bool LinkAttribute { get { return m_linkAttribute; } set { m_linkAttribute = value; } } public string LinkAttributeName { get { return m_linkAttributeName; } set { m_linkAttributeName = value; } } public bool KeepVertices { get { return m_keepVertices; } set { m_keepVertices = value; } } public string LengthAttributeName { get { return m_lengthAttributeName; } set { m_lengthAttributeName = value; } } public string ReducedNodeClassName { get { return m_reducedNodeClassName; } set { m_reducedNodeClassName = value; } } public string SuperpanLinkClassName { get { return m_superspanLinkClassName; } set { m_superspanLinkClassName = value; } } #endregion #region ISchematicRule Members public void Alter(ISchematicDiagramClass schematicDiagramClass, ESRI.ArcGIS.esriSystem.IPropertySet propertySet) { m_diagramClass = schematicDiagramClass; try { m_description = propertySet.GetProperty("DESCRIPTION").ToString(); } catch { } try { m_reducedNodeClassName = propertySet.GetProperty("REDUCEDNODECLASS").ToString(); } catch { } try { m_superspanLinkClassName = propertySet.GetProperty("SUPERSPANLINKCLASS").ToString(); } catch { } try { m_lengthAttributeName = propertySet.GetProperty("LENGTHATTRIBUTENAME").ToString(); } catch { } try { m_keepVertices = (bool)propertySet.GetProperty("KEEPVERTICES"); } catch { } try { m_linkAttribute = (bool)propertySet.GetProperty("LINKATTRIBUTE"); } catch { } try { m_linkAttributeName = propertySet.GetProperty("LINKATTRIBUTENAME").ToString(); } catch { } } public void Apply(ISchematicInMemoryDiagram inMemoryDiagram, ESRI.ArcGIS.esriSystem.ITrackCancel cancelTracker) { if (m_reducedNodeClassName == "" || inMemoryDiagram == null) return; // initialize the schematic rules helper ISchematicRulesHelper rulesHelper = new SchematicRulesHelperClass(); rulesHelper.InitHelper(inMemoryDiagram); rulesHelper.KeepVertices = m_keepVertices; //////////////////////// // get the feature classes processed by the rule ISchematicDiagramClass diagramClass = null; try { diagramClass = inMemoryDiagram.SchematicDiagramClass; } catch { } if (diagramClass == null) return; ISchematicDataset schematicDataset = null; try { schematicDataset = diagramClass.SchematicDataset; } catch { } ISchematicElementClassContainer elementclassContainer = (ISchematicElementClassContainer)schematicDataset; if (elementclassContainer == null) return; ISchematicElementClass elementClassReducedNode = null; elementClassReducedNode = elementclassContainer.GetSchematicElementClass(m_reducedNodeClassName); ISchematicElementClass elementClassSuperspan = null; elementClassSuperspan = elementclassContainer.GetSchematicElementClass(m_superspanLinkClassName); if (elementClassSuperspan == null || elementClassReducedNode == null) return; ISchematicInMemoryFeatureClassContainer featureClassContainer = (ISchematicInMemoryFeatureClassContainer)inMemoryDiagram; if (featureClassContainer == null) return; ISchematicInMemoryFeatureClass superspanLinkClass = featureClassContainer.GetSchematicInMemoryFeatureClass(elementClassSuperspan); // ///////////////////////// // fetch the superspan spatial reference IGeoDataset geoDataset = (IGeoDataset)superspanLinkClass; ISpatialReference spatialRef = null; if (geoDataset != null) spatialRef = geoDataset.SpatialReference; if (spatialRef == null) return; // Retrieve the schematic in memory feature nodes to reduce System.Collections.Generic.Dictionary<string, ISchematicInMemoryFeature> colSchfeatureNode = new Dictionary<string, ISchematicInMemoryFeature>(); // get all feature of parent node class IEnumSchematicInMemoryFeature enumSchematicInMemoryFeature = inMemoryDiagram.GetSchematicInMemoryFeaturesByClass(elementClassReducedNode); // retain only the nodes of degree two RetainNodesDegreeTwo(enumSchematicInMemoryFeature, colSchfeatureNode, rulesHelper); // there would be inserted a SQL query to also filter by attributes IProgressor msgProgressor = null; if (cancelTracker != null) { msgProgressor = cancelTracker.Progressor; IStepProgressor stepProgressor = (IStepProgressor)msgProgressor; if (stepProgressor != null) { stepProgressor.MinRange = 0; stepProgressor.MaxRange = colSchfeatureNode.Count; stepProgressor.StepValue = 1; stepProgressor.Position = 0; stepProgressor.Message = m_description; cancelTracker.Reset(); cancelTracker.Progressor = msgProgressor; stepProgressor.Show(); } } ISchematicInMemoryFeature schFeatureToReduce; foreach (KeyValuePair<string, ISchematicInMemoryFeature> kvp in colSchfeatureNode) { if (cancelTracker != null) if (cancelTracker.Continue() == false) break; schFeatureToReduce = colSchfeatureNode[kvp.Key]; if (schFeatureToReduce != null) ReduceNode(rulesHelper, superspanLinkClass, spatialRef, schFeatureToReduce); } // release memory colSchfeatureNode.Clear(); colSchfeatureNode = null; rulesHelper = null; } public ESRI.ArcGIS.esriSystem.UID ClassID { get { ESRI.ArcGIS.esriSystem.UID ruleID = new ESRI.ArcGIS.esriSystem.UID(); ruleID.Value = PROGID; return ruleID; } } public string Description { get { return m_description; } set { m_description = value; } } string ISchematicRule.Description { get { return m_description; } } public string Name { get { return "Node Reduction Rule C#"; } } public ESRI.ArcGIS.esriSystem.IPropertySet PropertySet { get { ESRI.ArcGIS.esriSystem.IPropertySet propertySet = new ESRI.ArcGIS.esriSystem.PropertySet(); propertySet.SetProperty("DESCRIPTION", m_description); propertySet.SetProperty("REDUCEDNODECLASS", m_reducedNodeClassName); propertySet.SetProperty("SUPERSPANLINKCLASS", m_superspanLinkClassName); propertySet.SetProperty("KEEPVERTICES", m_keepVertices); propertySet.SetProperty("LENGTHATTRIBUTENAME", m_lengthAttributeName); propertySet.SetProperty("LINKATTRIBUTE", m_linkAttribute); propertySet.SetProperty("LINKATTRIBUTENAME", m_linkAttributeName); return propertySet; } } ISchematicDiagramClass ISchematicRule.SchematicDiagramClass { get { return m_diagramClass; } } #endregion #region ISchematicRuleDesign Members public void Detach() { m_diagramClass = null; } ESRI.ArcGIS.esriSystem.IPropertySet ISchematicRuleDesign.PropertySet { set { m_description = value.GetProperty("DESCRIPTION").ToString(); m_reducedNodeClassName = value.GetProperty("REDUCEDNODECLASS").ToString(); m_superspanLinkClassName = value.GetProperty("SUPERSPANLINKCLASS").ToString(); m_keepVertices = (bool)value.GetProperty("KEEPVERTICES"); m_lengthAttributeName = value.GetProperty("LENGTHATTRIBUTENAME").ToString(); m_linkAttribute = (bool)value.GetProperty("LINKATTRIBUTE"); m_linkAttributeName = value.GetProperty("LINKATTRIBUTENAME").ToString(); } } ISchematicDiagramClass ISchematicRuleDesign.SchematicDiagramClass { get { return m_diagramClass; } set { m_diagramClass = value; } } #endregion ISchematicRuleDesign #region private methods private void ReduceNode(ISchematicRulesHelper rulesHelper, ISchematicInMemoryFeatureClass superspanLinkClass , ISpatialReference spatialRef, ISchematicInMemoryFeature schFeatureToReduce) { if (schFeatureToReduce.Displayed == false || rulesHelper == null || spatialRef == null) return; // get the two connected links IEnumSchematicInMemoryFeature enumLink = rulesHelper.GetDisplayedIncidentLinks((ISchematicInMemoryFeatureNode)schFeatureToReduce, esriSchematicEndPointType.esriSchematicOriginOrExtremityNode); if (enumLink == null || enumLink.Count != 2) return; enumLink.Reset(); ISchematicInMemoryFeature schFeat1 = enumLink.Next(); ISchematicInMemoryFeature schFeat2 = enumLink.Next(); ISchematicInMemoryFeatureLink schLink1 = (ISchematicInMemoryFeatureLink)schFeat1; ISchematicInMemoryFeatureLink schLink2 = (ISchematicInMemoryFeatureLink)schFeat2; if (schLink1 == null || schLink2 == null) return; ISchematicInMemoryFeature schFeatureSuperspan = null; ISchematicInMemoryFeature schFeatureTmp = null; ISchematicInMemoryFeatureNode schNodeToReduce = (ISchematicInMemoryFeatureNode)schFeatureToReduce; ISchematicInMemoryFeatureNode schFromNode; ISchematicInMemoryFeatureNode schToNode; int iFromPort; int iToPort; IGeometry superspanGeometry; if (schLink2.FromNode == schNodeToReduce) { superspanGeometry = BuildLinkGeometry(schLink1, schNodeToReduce, schLink2, rulesHelper); if (schLink1.ToNode == schNodeToReduce) { schFromNode = schLink1.FromNode; iFromPort = schLink1.FromPort; } else { schFromNode = schLink1.ToNode; iFromPort = schLink1.ToPort; } schToNode = schLink2.ToNode; iToPort = schLink2.ToPort; } else { superspanGeometry = BuildLinkGeometry(schLink2, schNodeToReduce, schLink1, rulesHelper); schFromNode = schLink2.FromNode; iFromPort = schLink2.FromPort; if (schLink1.FromNode == schNodeToReduce) { schToNode = schLink1.ToNode; iToPort = schLink1.ToPort; } else { schToNode = schLink1.FromNode; iToPort = schLink1.FromPort; } } if (superspanGeometry != null) superspanGeometry.SpatialReference = spatialRef; // find a unique name for the superspan string strFromName = schFromNode.Name; string strtoName = schToNode.Name; string strName; long lCount = 1; while (schFeatureSuperspan == null) { strName = strFromName + ";" + strtoName + ";" + lCount.ToString(); if (strName.Length >= 128) break; // too long a name try { schFeatureTmp = rulesHelper.AlterLink(superspanLinkClass, strName, null, superspanGeometry, -2, -2, strFromName, strtoName, esriFlowDirection.esriFDWithFlow, iFromPort, iToPort); } catch { schFeatureTmp = null; } if (schFeatureTmp == null) continue; // valid new feature schFeatureSuperspan = schFeatureTmp; } // last chance for a unique name lCount = 1; while (schFeatureSuperspan == null) { strName = schNodeToReduce.Name + ";" + lCount.ToString(); if (strName.Length >= 128) break; // too long a name try { schFeatureTmp = rulesHelper.AlterLink(superspanLinkClass, strName, null, superspanGeometry, -2, -2, strFromName, strtoName, esriFlowDirection.esriFDWithFlow, iFromPort, iToPort); } catch { schFeatureTmp = null; } if (schFeatureTmp == null) continue; // valid new feature schFeatureSuperspan = schFeatureTmp; } if (schFeatureSuperspan == null) return; // cannot find a unique name // otherwise report the cumulated length of the reduced links to the superspan ReportCumulativeValues(schFeat1, schFeat2, schFeatureSuperspan); // report the associations on the superspan link rulesHelper.ReportAssociations(schFeatureToReduce, schFeatureSuperspan); rulesHelper.ReportAssociations(schFeat1, schFeatureSuperspan); rulesHelper.ReportAssociations(schFeat2, schFeatureSuperspan); // hide the reduced objects rulesHelper.HideFeature(schFeatureToReduce); rulesHelper.HideFeature(schFeat1); rulesHelper.HideFeature(schFeat2); } private void ReportCumulativeValues(ISchematicInMemoryFeature schFeat1, ISchematicInMemoryFeature schFeat2, ISchematicInMemoryFeature schTargetFeat) { if (schFeat1 == null || schFeat2 == null || schTargetFeat == null) return; // assume the attribute field name is the same on every schematic feature link classes IFields linkFields = schFeat1.Fields; int iIndex = linkFields.FindField(m_lengthAttributeName); if (iIndex < 0) return; // attribute field does not exist object value1 = schFeat1.get_Value(iIndex); linkFields = schFeat2.Fields; iIndex = linkFields.FindField(m_lengthAttributeName); if (iIndex < 0) return; // attribute field does not exist object value2 = schFeat2.get_Value(iIndex); double dValue1 = 0; double dValue2 = 0; if (!DBNull.Value.Equals(value1)) { try { dValue1 = Convert.ToDouble(value1); } catch { } } if (!DBNull.Value.Equals(value2)) { try { dValue2 = Convert.ToDouble(value2); } catch{ } } // assume the values to be numeric double dlength = dValue1 + dValue2; linkFields = schTargetFeat.Fields; iIndex = linkFields.FindField(m_lengthAttributeName); if (iIndex < 0) return; // attribute field does not exist schTargetFeat.set_Value(iIndex, dlength); } private IGeometry BuildLinkGeometry(ISchematicInMemoryFeatureLink schLink1, ISchematicInMemoryFeatureNode schNodeToReduce, ISchematicInMemoryFeatureLink schLink2, ISchematicRulesHelper rulesHelper) { if (schLink1 == null || schLink2 == null || schNodeToReduce == null || rulesHelper == null) return null; if (m_keepVertices == false) return null; // no geometry Polyline newPoly = new Polyline(); IPolyline polyLink1 = rulesHelper.GetLinkPoints(schLink1, (schLink1.FromNode == schNodeToReduce)); IPolyline polyLink2 = rulesHelper.GetLinkPoints(schLink2, (schLink2.ToNode == schNodeToReduce)); IPoint nodePt = rulesHelper.GetNodePoint(schNodeToReduce); IPoint Pt; IPointCollection newPts = (IPointCollection)newPoly; IPointCollection link1Pts = (IPointCollection)polyLink1; IPointCollection link2Pts = (IPointCollection)polyLink2; int Count = link1Pts.PointCount; int i; for (i = 0; i < Count - 1; i++) { Pt = link1Pts.get_Point(i); newPts.AddPoint(Pt); } newPts.AddPoint(nodePt); Count = link2Pts.PointCount; for (i = 1; i < Count; i++) { Pt = link2Pts.get_Point(i); newPts.AddPoint(Pt); } IGeometry buildGeometry = (IGeometry)newPoly; return buildGeometry; } private void RetainNodesDegreeTwo(IEnumSchematicInMemoryFeature enumInMemoryFeature, Dictionary<string, ISchematicInMemoryFeature> colSchfeatureNode, ISchematicRulesHelper ruleHelper) { ISchematicInMemoryFeature schInMemoryfeature; if (ruleHelper == null) return; enumInMemoryFeature.Reset(); schInMemoryfeature = enumInMemoryFeature.Next(); while (schInMemoryfeature != null) { if (schInMemoryfeature.Displayed) { IEnumSchematicInMemoryFeature enumLinks = ruleHelper.GetDisplayedIncidentLinks((ISchematicInMemoryFeatureNode)schInMemoryfeature, esriSchematicEndPointType.esriSchematicOriginOrExtremityNode); if (enumLinks != null && enumLinks.Count == 2) { // Valid degree two node if (!colSchfeatureNode.ContainsKey(schInMemoryfeature.Name)) { if (!LinkAttribute) colSchfeatureNode.Add(schInMemoryfeature.Name, schInMemoryfeature); else { if(SameIncidentLinkAttributeValue(enumLinks, LinkAttributeName, ruleHelper)) colSchfeatureNode.Add(schInMemoryfeature.Name, schInMemoryfeature); } } } } schInMemoryfeature = enumInMemoryFeature.Next(); } } private bool SameIncidentLinkAttributeValue(IEnumSchematicInMemoryFeature enumInMemoryLinks, string attributeName, ISchematicRulesHelper ruleHelper) { ISchematicInMemoryFeature inMemoryFeature = null; enumInMemoryLinks.Reset(); bool bFirstVariant = true; object vPreviousValue = null; object vCurrentValue = null; inMemoryFeature = enumInMemoryLinks.Next(); while (inMemoryFeature != null) { // Do not take account the link if the link is not displayed // // Search for an attribute with the given name // ISchematicElementClass schematicElementClass; schematicElementClass = inMemoryFeature.SchematicElementClass; ISchematicAttributeContainer attributeContainer = (ISchematicAttributeContainer)schematicElementClass; ISchematicAttribute schematicAttribute = null; if (attributeContainer != null) schematicAttribute = attributeContainer.GetSchematicAttribute(attributeName, true); if (schematicAttribute != null) { ISchematicObject schematicObject = (ISchematicObject)inMemoryFeature; vCurrentValue = schematicAttribute.GetValue(schematicObject); } else { // If schematic attribute not existing ==> find a field in the associated feature IObject iObject = null; ISchematicInMemoryFeaturePrimaryAssociation primaryAssociation = (ISchematicInMemoryFeaturePrimaryAssociation)inMemoryFeature; if (primaryAssociation != null) iObject = primaryAssociation.AssociatedObject; IRow row = (IRow)iObject; int fieldIndex = 0; if (row != null) { IFields fields = row.Fields; if (fields != null) fieldIndex = fields.FindField(attributeName); } if (fieldIndex > 0) { vCurrentValue = row.get_Value(fieldIndex); if (DBNull.Value.Equals(vCurrentValue)) return false; } else return false; } if (bFirstVariant) { vPreviousValue = vCurrentValue; bFirstVariant = false; } else { // Compare PreviousValue and CurrentValue if (vPreviousValue.GetType() != vCurrentValue.GetType()) return false; if (DBNull.Value.Equals(vPreviousValue) || DBNull.Value.Equals(vCurrentValue)) return false; if (vPreviousValue.GetType().FullName is System.String)//Speciale Case for string. { string str1 = (string)vPreviousValue; string str2 = (string)vCurrentValue; if( string.Compare(str1, str2, true) != 0) return false; } else if (vPreviousValue != vCurrentValue)// == or != operator compare for Variant match the right type. return false; } inMemoryFeature = enumInMemoryLinks.Next(); } return true; } } #endregion }
[Visual Basic .NET]
NodeReductionRule.vb
Option Strict On Imports System Imports System.Collections.Generic Imports System.Runtime.InteropServices Imports ESRI.ArcGIS Imports ESRI.ArcGIS.ADF.CATIDs Imports ESRI.ArcGIS.Schematic Imports ESRI.ArcGIS.Geometry Imports ESRI.ArcGIS.Geodatabase Imports esriSystem = ESRI.ArcGIS.esriSystem <System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)> _ <System.Runtime.InteropServices.Guid(NodeReductionRule.GUID)> _ <System.Runtime.InteropServices.ProgId(NodeReductionRule.PROGID)> _ Public Class NodeReductionRule Implements ESRI.ArcGIS.Schematic.ISchematicRule Implements ESRI.ArcGIS.Schematic.ISchematicRuleDesign Public Const GUID As String = "5CA4A4C9-CBDF-4B4E-8932-53A962C92C22" Public Const PROGID As String = "CustomRulesVB.NodeReductionRule" ' Register/unregister categories for this class #Region "Component Category Registration" <System.Runtime.InteropServices.ComRegisterFunction()> _ Shared Sub Register(ByVal CLSID As String) ESRI.ArcGIS.ADF.CATIDs.SchematicRules.Register(CLSID) End Sub <System.Runtime.InteropServices.ComUnregisterFunction()> _ Shared Sub Unregister(ByVal CLSID As String) ESRI.ArcGIS.ADF.CATIDs.SchematicRules.Unregister(CLSID) End Sub #End Region Private m_diagramClass As ESRI.ArcGIS.Schematic.ISchematicDiagramClass Private m_reducedNodeClassName As String Private m_lengthAttributeName As String Private m_superspanLinkClassName As String Private m_linkAttributeName As String Private m_description As String = "Reduction Node Rule - Report cumulative value VBNet" Private m_keepVertices As Boolean = True Private m_linkAttribute As Boolean = False #Region "NodeReductionRule Members" Public Sub New() End Sub Protected Overrides Sub Finalize() m_diagramClass = Nothing MyBase.Finalize() End Sub Public Property LinkAttribute() As Boolean Get Return m_linkAttribute End Get Set(ByVal value As Boolean) m_linkAttribute = value End Set End Property Public Property LinkAttributeName() As String Get Return m_linkAttributeName End Get Set(ByVal value As String) m_linkAttributeName = value End Set End Property Public Property KeepVertices() As Boolean Get Return m_keepVertices End Get Set(ByVal value As Boolean) m_keepVertices = value End Set End Property Public Property ReducedNodeClassName() As String Get Return m_reducedNodeClassName End Get Set(ByVal value As String) m_reducedNodeClassName = value End Set End Property Public Property LengthAttributeName() As String Get Return m_lengthAttributeName End Get Set(ByVal value As String) m_lengthAttributeName = value End Set End Property Public Property SuperpanLinkClassName() As String Get Return m_superspanLinkClassName End Get Set(ByVal value As String) m_superspanLinkClassName = value End Set End Property #End Region #Region "ISchematicRule Members" Public Sub Alter(ByVal schematicDiagramClass As ESRI.ArcGIS.Schematic.ISchematicDiagramClass, ByVal propertySet As ESRI.ArcGIS.esriSystem.IPropertySet) Implements ESRI.ArcGIS.Schematic.ISchematicRule.Alter m_diagramClass = schematicDiagramClass Try m_description = propertySet.GetProperty("DESCRIPTION").ToString() Catch End Try Try m_reducedNodeClassName = propertySet.GetProperty("REDUCEDNODECLASS").ToString() Catch End Try Try m_superspanLinkClassName = propertySet.GetProperty("SUPERSPANLINKCLASS").ToString() Catch End Try Try m_keepVertices = CBool(propertySet.GetProperty("KEEPVERTICES")) Catch End Try Try m_lengthAttributeName = propertySet.GetProperty("LENGTHATTRIBUTENAME").ToString() Catch End Try Try m_linkAttribute = CBool(propertySet.GetProperty("LINKATTRIBUTE")) Catch End Try Try m_linkAttributeName = propertySet.GetProperty("LINKATTRIBUTENAME").ToString() Catch End Try End Sub Public Sub Apply(ByVal inMemoryDiagram As ESRI.ArcGIS.Schematic.ISchematicInMemoryDiagram, Optional ByVal cancelTracker As ESRI.ArcGIS.esriSystem.ITrackCancel = Nothing) Implements ESRI.ArcGIS.Schematic.ISchematicRule.Apply Dim rulesHelper As ISchematicRulesHelper = New SchematicRulesHelper() Dim diagramClass As ISchematicDiagramClass = Nothing Dim elementClassReducedNode As ISchematicElementClass = Nothing Dim elementClassSuperspan As ISchematicElementClass = Nothing Dim elementClassContainer As ISchematicElementClassContainer Dim superspanLinkClass As ISchematicInMemoryFeatureClass Dim schematicDataset As ISchematicDataset Dim featureClassContainer As ISchematicInMemoryFeatureClassContainer Dim geoDataset As IGeoDataset Dim spatialRef As ISpatialReference = Nothing Dim colSchfeatureNode As New System.Collections.Generic.Dictionary(Of String, ISchematicInMemoryFeature) Dim kvp As KeyValuePair(Of String, ISchematicInMemoryFeature) Dim enumSchematicInMemoryFeature As IEnumSchematicInMemoryFeature = Nothing Dim msgProgressor As ESRI.ArcGIS.esriSystem.IProgressor = Nothing Dim stepProgressor As ESRI.ArcGIS.esriSystem.IStepProgressor Dim schFeatureToReduce As ISchematicInMemoryFeature If (m_reducedNodeClassName Is Nothing Or inMemoryDiagram Is Nothing) Then Return ' initialize the schematic rules helper rulesHelper.InitHelper(inMemoryDiagram) rulesHelper.KeepVertices = m_keepVertices 'Get the feature classes processed by the rule Try diagramClass = inMemoryDiagram.SchematicDiagramClass Catch End Try If (diagramClass Is Nothing) Then Return Try schematicDataset = diagramClass.SchematicDataset Catch schematicDataset = Nothing End Try elementClassContainer = CType(schematicDataset, ISchematicElementClassContainer) If (elementClassContainer Is Nothing) Then Return elementClassReducedNode = elementClassContainer.GetSchematicElementClass(m_reducedNodeClassName) elementClassSuperspan = elementClassContainer.GetSchematicElementClass(m_superspanLinkClassName) If (elementClassSuperspan Is Nothing Or elementClassReducedNode Is Nothing) Then Return featureClassContainer = CType(inMemoryDiagram, ISchematicInMemoryFeatureClassContainer) If (featureClassContainer Is Nothing) Then Return superspanLinkClass = featureClassContainer.GetSchematicInMemoryFeatureClass(elementClassSuperspan) ' fetch the superspan spatial reference geoDataset = CType(superspanLinkClass, IGeoDataset) If (geoDataset IsNot Nothing) Then spatialRef = geoDataset.SpatialReference If (spatialRef Is Nothing) Then Return ' Retrieve the schematic in memory feature nodes to reduce ' get all feature of parent node class enumSchematicInMemoryFeature = inMemoryDiagram.GetSchematicInMemoryFeaturesByClass(elementClassReducedNode) ' retain only the nodes of degree two RetainNodesDegreeTwo(enumSchematicInMemoryFeature, colSchfeatureNode, rulesHelper) ' there would be inserted a SQL query to also filter by attributes If (cancelTracker IsNot Nothing) Then msgProgressor = cancelTracker.Progressor stepProgressor = CType(msgProgressor, ESRI.ArcGIS.esriSystem.IStepProgressor) If (stepProgressor IsNot Nothing) Then stepProgressor.MinRange = 0 stepProgressor.MaxRange = colSchfeatureNode.Count stepProgressor.StepValue = 1 stepProgressor.Position = 0 stepProgressor.Message = m_description cancelTracker.Reset() cancelTracker.Progressor = msgProgressor stepProgressor.Show() End If End If For Each kvp In colSchfeatureNode If (cancelTracker IsNot Nothing) Then If (cancelTracker.Continue() = False) Then Exit For End If schFeatureToReduce = CType(colSchfeatureNode(kvp.Key), ISchematicInMemoryFeature) If (schFeatureToReduce IsNot Nothing) Then ReduceNode(rulesHelper, superspanLinkClass, spatialRef, schFeatureToReduce) Next colSchfeatureNode.Clear() colSchfeatureNode = Nothing rulesHelper = Nothing End Sub Public ReadOnly Property ClassID() As ESRI.ArcGIS.esriSystem.UID Implements ESRI.ArcGIS.Schematic.ISchematicRule.ClassID Get Dim ruleID As esriSystem.UID = New esriSystem.UID() ruleID.Value = PROGID Return ruleID End Get End Property Public ReadOnly Property Description1() As String Implements ESRI.ArcGIS.Schematic.ISchematicRule.Description Get Return m_description End Get End Property Public Property Description() As String Get Return m_description End Get Set(ByVal value As String) m_description = value End Set End Property Public ReadOnly Property Name() As String Implements ESRI.ArcGIS.Schematic.ISchematicRule.Name Get Return "Node Reduction Rule VBNet" End Get End Property Public ReadOnly Property PropertySet() As ESRI.ArcGIS.esriSystem.IPropertySet Implements ESRI.ArcGIS.Schematic.ISchematicRule.PropertySet Get Dim propSet As esriSystem.IPropertySet = New esriSystem.PropertySet() propSet.SetProperty("DESCRIPTION", m_description) propSet.SetProperty("REDUCEDNODECLASS", m_reducedNodeClassName) propSet.SetProperty("SUPERSPANLINKCLASS", m_superspanLinkClassName) propSet.SetProperty("KEEPVERTICES", m_keepVertices) propSet.SetProperty("LENGTHATTRIBUTENAME", m_lengthAttributeName) propSet.SetProperty("LINKATTRIBUTENAME", m_linkAttributeName) propSet.SetProperty("LINKATTRIBUTE", m_linkAttribute) Return propSet End Get End Property Public ReadOnly Property SchematicDiagramClass() As ESRI.ArcGIS.Schematic.ISchematicDiagramClass Implements ESRI.ArcGIS.Schematic.ISchematicRule.SchematicDiagramClass Get Return m_diagramClass End Get End Property #End Region #Region "ISchematicRuleDesign Members" Public Sub Detach() Implements ESRI.ArcGIS.Schematic.ISchematicRuleDesign.Detach m_diagramClass = Nothing End Sub Public WriteOnly Property PropertySet1() As ESRI.ArcGIS.esriSystem.IPropertySet Implements ESRI.ArcGIS.Schematic.ISchematicRuleDesign.PropertySet Set(ByVal value As ESRI.ArcGIS.esriSystem.IPropertySet) m_description = value.GetProperty("DESCRIPTION").ToString() m_reducedNodeClassName = value.GetProperty("REDUCEDNODECLASS").ToString() m_superspanLinkClassName = value.GetProperty("SUPERSPANLINKCLASS").ToString() m_keepVertices = CBool(value.GetProperty("KEEPVERTICES")) m_lengthAttributeName = value.GetProperty("LENGTHATTRIBUTENAME").ToString() m_linkAttribute = CBool(value.GetProperty("LINKATTRIBUTE")) m_linkAttributeName = value.GetProperty("LINKATTRIBUTENAME").ToString() End Set End Property Public Property SchematicDiagramClass1() As ESRI.ArcGIS.Schematic.ISchematicDiagramClass Implements ESRI.ArcGIS.Schematic.ISchematicRuleDesign.SchematicDiagramClass Get Return m_diagramClass End Get Set(ByVal value As ESRI.ArcGIS.Schematic.ISchematicDiagramClass) m_diagramClass = value End Set End Property #End Region #Region "Node Reduction Rule private Members" Private Sub ReduceNode(ByVal rulesHelper As ISchematicRulesHelper, ByVal superspanLinkClass As ISchematicInMemoryFeatureClass, ByVal spatialRef As ISpatialReference, ByVal schFeatureToReduce As ISchematicInMemoryFeature) Dim enumLink As IEnumSchematicInMemoryFeature Dim schFeatureSuperspan As ISchematicInMemoryFeature = Nothing Dim schFeatureTmp As ISchematicInMemoryFeature = Nothing Dim schFeat1 As ISchematicInMemoryFeature = Nothing Dim schFeat2 As ISchematicInMemoryFeature = Nothing Dim schLink1 As ISchematicInMemoryFeatureLink = Nothing Dim schLink2 As ISchematicInMemoryFeatureLink = Nothing Dim schNodeToReduce As ISchematicInMemoryFeatureNode = Nothing Dim schFromNode As ISchematicInMemoryFeatureNode = Nothing Dim schToNode As ISchematicInMemoryFeatureNode = Nothing Dim superspanGeometry As IGeometry = Nothing Dim iFromPort As Integer Dim iToPort As Integer Dim lCount As Long = 1 Dim strFromName As String Dim strtoName As String Dim strName As String If (schFeatureToReduce.Displayed = False Or rulesHelper Is Nothing Or spatialRef Is Nothing) Then Exit Sub ' get the two connected links enumLink = rulesHelper.GetDisplayedIncidentLinks(CType(schFeatureToReduce, ISchematicInMemoryFeatureNode), esriSchematicEndPointType.esriSchematicOriginOrExtremityNode) If (enumLink Is Nothing Or enumLink.Count <> 2) Then Exit Sub enumLink.Reset() schFeat1 = enumLink.Next() schFeat2 = enumLink.Next() schLink1 = CType(schFeat1, ISchematicInMemoryFeatureLink) schLink2 = CType(schFeat2, ISchematicInMemoryFeatureLink) If (schLink1 Is Nothing Or schLink2 Is Nothing) Then Exit Sub schNodeToReduce = CType(schFeatureToReduce, ISchematicInMemoryFeatureNode) If (schLink2.FromNode Is schNodeToReduce) Then superspanGeometry = BuildLinkGeometry(schLink1, schNodeToReduce, schLink2, rulesHelper) If (schLink1.ToNode Is schNodeToReduce) Then schFromNode = schLink1.FromNode iFromPort = schLink1.FromPort Else schFromNode = schLink1.ToNode iFromPort = schLink1.ToPort End If schToNode = schLink2.ToNode iToPort = schLink2.ToPort Else superspanGeometry = BuildLinkGeometry(schLink2, schNodeToReduce, schLink1, rulesHelper) schFromNode = schLink2.FromNode iFromPort = schLink2.FromPort If (schLink1.FromNode Is schNodeToReduce) Then schToNode = schLink1.ToNode iToPort = schLink1.ToPort Else schToNode = schLink1.FromNode iToPort = schLink1.FromPort End If End If If (superspanGeometry IsNot Nothing) Then superspanGeometry.SpatialReference = spatialRef ' find a unique name for the superspan strFromName = schFromNode.Name strtoName = schToNode.Name lCount = 1 While (schFeatureSuperspan Is Nothing) strName = strFromName + ";" + strtoName + ";" + lCount.ToString() If (strName.Length >= 128) Then Exit While ' too long a name Try schFeatureTmp = rulesHelper.AlterLink(superspanLinkClass, strName, Nothing, superspanGeometry, -2, -2, strFromName, strtoName, esriFlowDirection.esriFDWithFlow, iFromPort, iToPort) Catch schFeatureTmp = Nothing End Try If (schFeatureTmp IsNot Nothing) Then ' valid new feature schFeatureSuperspan = schFeatureTmp Exit While End If End While ' last chance for a unique name lCount = 1 While (schFeatureSuperspan Is Nothing) strName = schNodeToReduce.Name + ";" + lCount.ToString() If (strName.Length >= 128) Then Exit While ' too long a name Try schFeatureTmp = rulesHelper.AlterLink(superspanLinkClass, strName, Nothing, superspanGeometry, -2, -2, strFromName, strtoName, esriFlowDirection.esriFDWithFlow, iFromPort, iToPort) Catch schFeatureTmp = Nothing End Try If (schFeatureTmp IsNot Nothing) Then ' valid new feature schFeatureSuperspan = schFeatureTmp Exit While End If End While If (schFeatureSuperspan Is Nothing) Then Exit Sub ' cannot find a unique name ' otherwise report the cumulated length of the reduced links to the superspan ReportCumulativeValues(schFeat1, schFeat2, schFeatureSuperspan) ' report the associations on the superspan link rulesHelper.ReportAssociations(schFeatureToReduce, schFeatureSuperspan) rulesHelper.ReportAssociations(schFeat1, schFeatureSuperspan) rulesHelper.ReportAssociations(schFeat2, schFeatureSuperspan) ' hide the reduced objects rulesHelper.HideFeature(schFeatureToReduce) rulesHelper.HideFeature(schFeat1) rulesHelper.HideFeature(schFeat2) End Sub Private Sub ReportCumulativeValues(ByVal schFeat1 As ISchematicInMemoryFeature, ByVal schFeat2 As ISchematicInMemoryFeature, ByVal schTargetFeat As ISchematicInMemoryFeature) Dim linkFields As IFields = Nothing Dim value1 As Object Dim value2 As Object Dim iIndex As Integer Dim dLength As Double Dim dValue1 As Double = 0 Dim dValue2 As Double = 0 If (schFeat1 Is Nothing Or schFeat2 Is Nothing Or schTargetFeat Is Nothing) Then Exit Sub ' assume the attribute field name is the same on every schematic feature link classes linkFields = schFeat1.Fields iIndex = linkFields.FindField(m_lengthAttributeName) If (iIndex < 0) Then Exit Sub ' attribute field does not exist value1 = schFeat1.Value(iIndex) linkFields = schFeat2.Fields iIndex = linkFields.FindField(m_lengthAttributeName) If (iIndex < 0) Then Exit Sub ' attribute field does not exist value2 = schFeat2.Value(iIndex) If (Not DBNull.Value.Equals(value1)) Then dValue1 = CDbl(value1) End If If (Not DBNull.Value.Equals(value2)) Then dValue2 = CDbl(value2) End If ' assume the values to be numeric dLength = dValue1 + dValue2 linkFields = schTargetFeat.Fields iIndex = linkFields.FindField(m_lengthAttributeName) If (iIndex < 0) Then Exit Sub ' attribute field does not exist schTargetFeat.Value(iIndex) = dLength End Sub Private Function BuildLinkGeometry(ByVal schLink1 As ISchematicInMemoryFeatureLink, ByVal schNodeToReduce As ISchematicInMemoryFeatureNode, ByVal schLink2 As ISchematicInMemoryFeatureLink, ByVal rulesHelper As ISchematicRulesHelper) As IGeometry If (schLink1 Is Nothing Or schLink2 Is Nothing Or schNodeToReduce Is Nothing Or rulesHelper Is Nothing) Then Return Nothing If (m_keepVertices = False) Then Return Nothing 'no geometry Dim polyLink1 As IPolyline = Nothing Dim polyLink2 As IPolyline = Nothing Dim nodePt As IPoint = Nothing Dim Pt As IPoint = Nothing Dim newPts As IPointCollection = Nothing Dim link1Pts As IPointCollection = Nothing Dim link2Pts As IPointCollection = Nothing Dim buildGeometry As IGeometry = New Polyline() Dim iCount As Integer Dim i As Integer polyLink1 = rulesHelper.GetLinkPoints(schLink1, (schLink1.FromNode Is schNodeToReduce)) polyLink2 = rulesHelper.GetLinkPoints(schLink2, (schLink2.ToNode Is schNodeToReduce)) nodePt = rulesHelper.GetNodePoint(schNodeToReduce) newPts = CType(buildGeometry, IPointCollection) link1Pts = CType(polyLink1, IPointCollection) link2Pts = CType(polyLink2, IPointCollection) iCount = link1Pts.PointCount For i = 0 To iCount - 2 Step 1 Pt = link1Pts.Point(i) newPts.AddPoint(Pt) Next newPts.AddPoint(nodePt) iCount = link2Pts.PointCount For i = 1 To iCount - 1 Step 1 Pt = link2Pts.Point(i) newPts.AddPoint(Pt) Next Return buildGeometry End Function Private Sub RetainNodesDegreeTwo(ByRef enumInMemoryFeature As IEnumSchematicInMemoryFeature, ByRef colSchfeatureNode As System.Collections.Generic.Dictionary(Of String, ISchematicInMemoryFeature), ByVal ruleHelper As ISchematicRulesHelper) Dim schInMemoryfeature As ISchematicInMemoryFeature = Nothing enumInMemoryFeature.Reset() schInMemoryfeature = enumInMemoryFeature.Next() While (schInMemoryfeature IsNot Nothing) If (schInMemoryfeature.Displayed) Then Dim schInMemoryNode As ISchematicInMemoryFeatureNode = Nothing schInMemoryNode = CType(schInMemoryfeature, ISchematicInMemoryFeatureNode) Dim enumLinks As IEnumSchematicInMemoryFeature = Nothing enumLinks = ruleHelper.GetDisplayedIncidentLinks(schInMemoryNode, esriSchematicEndPointType.esriSchematicOriginOrExtremityNode) If (enumLinks IsNot Nothing And enumLinks.Count = 2) Then ' Valid degree two node If (Not colSchfeatureNode.ContainsKey(schInMemoryfeature.Name)) Then If (Not LinkAttribute) Then colSchfeatureNode.Add(schInMemoryfeature.Name, schInMemoryfeature) ElseIf (SameIncidentLinkAttributeValue(enumLinks, LinkAttributeName, ruleHelper)) Then colSchfeatureNode.Add(schInMemoryfeature.Name, schInMemoryfeature) End If End If End If End If schInMemoryfeature = enumInMemoryFeature.Next() End While End Sub Private Function SameIncidentLinkAttributeValue(ByVal enumInMemoryLinks As IEnumSchematicInMemoryFeature, ByVal attributeName As String, ByVal ruleHelper As ISchematicRulesHelper) As Boolean Dim inMemoryFeature As ISchematicInMemoryFeature = Nothing Dim bFirstVariant As Boolean = True Dim vPreviousValue As Object = Nothing Dim vCurrentValue As Object = Nothing enumInMemoryLinks.Reset() inMemoryFeature = enumInMemoryLinks.Next() While (inMemoryFeature IsNot Nothing) ' Do not take account the link if the link is not displayed ' Search for an attribute with the given name Dim schematicElementClass As ISchematicElementClass schematicElementClass = inMemoryFeature.SchematicElementClass Dim attributeContainer As ISchematicAttributeContainer = CType(schematicElementClass, ISchematicAttributeContainer) Dim schematicAttribute As ISchematicAttribute = Nothing If (attributeContainer IsNot Nothing) Then schematicAttribute = attributeContainer.GetSchematicAttribute(attributeName, True) End If If (schematicAttribute IsNot Nothing) Then Dim schematicObject As ISchematicObject = CType(inMemoryFeature, ISchematicObject) vCurrentValue = schematicAttribute.GetValue(schematicObject) Else 'If schematic attribute not existing ==> find a field in the associated feature Dim iObject As IObject = Nothing Dim primaryAssociation As ISchematicInMemoryFeaturePrimaryAssociation = CType(inMemoryFeature, ISchematicInMemoryFeaturePrimaryAssociation) If (primaryAssociation IsNot Nothing) Then iObject = primaryAssociation.AssociatedObject End If Dim row As IRow = CType(iObject, IRow) Dim fieldIndex As Integer = 0 If (row IsNot Nothing) Then Dim fields As IFields = row.Fields If (fields IsNot Nothing) Then fieldIndex = fields.FindField(attributeName) End If If (fieldIndex > 0) Then vCurrentValue = row.Value(fieldIndex) If (DBNull.Value.Equals(vCurrentValue)) Then Return False Else Return False End If End If If (bFirstVariant) Then vPreviousValue = vCurrentValue bFirstVariant = False Else ' Compare PreviousValue and CurrentValue If (vPreviousValue.GetType() IsNot vCurrentValue.GetType()) Then Return False If (DBNull.Value.Equals(vPreviousValue) Or DBNull.Value.Equals(vCurrentValue)) Then Return False If (TypeOf (vPreviousValue.GetType().FullName) Is System.String) Then 'Speciale Case for string. Dim str1 As String = vPreviousValue.ToString() Dim str2 As String = vCurrentValue.ToString() If (String.Compare(str1, str2, True) <> 0) Then Return False ElseIf (Not vPreviousValue.Equals(vCurrentValue)) Then Return False ' == or != operator compare for Variant match the right type. End If End If inMemoryFeature = enumInMemoryLinks.Next() End While Return True End Function #End Region End Class