About the Implementing the ISchematicRulesHelper to easily develop a custom schematic rule Sample
[C#]
BisectorRule.cs
using ESRI.ArcGIS;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Schematic;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.esriSystem;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CustomRulesCS
{
[ClassInterface(ClassInterfaceType.None)]
[Guid(BisectorRule.GUID)]
[ProgId(BisectorRule.PROGID)]
public class BisectorRule : ISchematicRule, ISchematicRuleDesign
{
public const string GUID = "31C4B848-34AF-4369-97FA-CDD985BF0592";
public const string PROGID = "CustomRulesCS.BisectorRule";
// 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 double m_distance = 0.5;
private string m_description = "Bisector Rule C#";
private string m_parentNodeClassName;
private string m_targetNodeClassName;
private string m_targetLinkClassName;
private ISchematicInMemoryFeatureClass m_parentNodeClass;
private ISchematicInMemoryFeatureClass m_targetNodeClass;
private ISchematicInMemoryFeatureClass m_targetLinkClass;
private const string Separator = "_";
private const string extensionName = "BisectorRuleCS";
public BisectorRule()
{
}
~BisectorRule()
{
m_diagramClass = null;
m_parentNodeClass = null;
m_targetNodeClass = null;
m_targetLinkClass = null;
}
public double distance
{
get
{
return m_distance;
}
set
{
m_distance = value;
}
}
public string parentNodeClassName
{
get
{
return m_parentNodeClassName;
}
set
{
m_parentNodeClassName = value;
}
}
public string targetNodeClassName
{
get
{
return m_targetNodeClassName;
}
set
{
m_targetNodeClassName = value;
}
}
public string targetLinkClassName
{
get
{
return m_targetLinkClassName;
}
set
{
m_targetLinkClassName = value;
}
}
private string GetUniqueName(ISchematicInMemoryDiagram inMemoryDiagram, esriSchematicElementType elementType, string featureName)
{
string nameUnique = featureName;
ISchematicInMemoryFeature schInMemoryfeature = null;
int index = 1;
bool endWhile = false;
while (!endWhile)
{
schInMemoryfeature = inMemoryDiagram.GetSchematicInMemoryFeatureByType(elementType, nameUnique);
if (schInMemoryfeature == null)
{
endWhile = true;
}
else if (schInMemoryfeature.Displayed)
{
nameUnique = nameUnique + index.ToString();
index++;
}
else
{
endWhile = true;
}
}
return nameUnique;
}
private void AddNodesDegreeTwo(IEnumSchematicInMemoryFeature enumInMemoryFeature,
Dictionary<string, ISchematicInMemoryFeature> colSchfeatureNode, ISchematicRulesHelper rulesHelper)
{
ISchematicInMemoryFeature schInMemoryfeature;
if (enumInMemoryFeature == null || colSchfeatureNode == null || rulesHelper == null)
return;
enumInMemoryFeature.Reset();
schInMemoryfeature = enumInMemoryFeature.Next();
while (schInMemoryfeature != null)
{
if (schInMemoryfeature.Displayed)
{
IEnumSchematicInMemoryFeature enumLinks = rulesHelper.GetDisplayedIncidentLinks((ISchematicInMemoryFeatureNode)schInMemoryfeature, esriSchematicEndPointType.esriSchematicOriginOrExtremityNode);
if (enumLinks != null && enumLinks.Count == 2)
{
if (!colSchfeatureNode.ContainsKey(schInMemoryfeature.Name))
colSchfeatureNode.Add(schInMemoryfeature.Name, schInMemoryfeature);
}
}
schInMemoryfeature = enumInMemoryFeature.Next();
}
}
private ISchematicInMemoryFeatureClass GetSchematicInMemoryFeatureClass(ISchematicInMemoryDiagram inMemoryDiagram, ISchematicElementClass eltClass)
{
ISchematicInMemoryFeatureClassContainer SchInMemoryFeatureClassContainer = (ISchematicInMemoryFeatureClassContainer)inMemoryDiagram;
return SchInMemoryFeatureClassContainer.GetSchematicInMemoryFeatureClass(eltClass);
}
private double CalculateAngle(IPoint pointFrom, IPoint pointTo)
{
const double radToDegre = 180 / Math.PI;
double dX, dY, angle;
angle = 0;
dX = pointTo.X - pointFrom.X;
dY = pointTo.Y - pointFrom.Y;
if (dX != 0)
angle = Math.Atan(dY / dX) * radToDegre;
else // case 2 points are same abcisse
{
if (dY < 0)
{
angle = 270;
return angle;
}
else
{
angle = 90;
return angle;
}
}
if (dX < 0)
angle = angle + 180;
if (angle < 0)
angle = angle + 360;
return angle;
}
private double CalculateAngleBisector(double angle1, double angle2)
{
double angleFinal;
if (Math.Abs(angle1 - angle2) > 180)
angleFinal = (angle1 + angle2) / 2 + 180;
else
angleFinal = (angle1 + angle2) / 2;
return angleFinal;
}
private IPoint GetCoordPointBisector(IPoint pointOrigine, double degreeBiSectore, double distance)
{
IPoint pointBisector = new PointClass();
double angleBisector, degreeFinal;
double dX, dY;
int casAngle = 0;
if (degreeBiSectore <= 90)
{
degreeFinal = degreeBiSectore;
casAngle = 1;
}
else if (degreeBiSectore <= 180)
{
degreeFinal = 180 - degreeBiSectore;
casAngle = 2;
}
else if (degreeBiSectore <= 270)
{
degreeFinal = degreeBiSectore - 180;
casAngle = 3;
}
else
{
degreeFinal = 360 - degreeBiSectore;
casAngle = 4;
}
angleBisector = Math.PI * degreeFinal / 180.0;
dY = distance * Math.Sin(angleBisector);
dX = distance * Math.Cos(angleBisector);
switch (casAngle)
{
case 1: // case which the vector is on the first of the circle
pointBisector.X = pointOrigine.X + dX;
pointBisector.Y = pointOrigine.Y + dY;
break;
case 2: // case which the vector is on the second of the circle
pointBisector.X = pointOrigine.X - dX;
pointBisector.Y = pointOrigine.Y + dY;
break;
case 3: // case which the vector is on the thirst of the circle
pointBisector.X = pointOrigine.X - dX;
pointBisector.Y = pointOrigine.Y - dY;
break;
default: // case which the vector is on the fourth of the circle
pointBisector.X = pointOrigine.X + dX;
pointBisector.Y = pointOrigine.Y - dY;
break;
}
return pointBisector;
}
#region ISchematicRule Members
public void Alter(ISchematicDiagramClass schematicDiagramClass, ESRI.ArcGIS.esriSystem.IPropertySet propertySet)
{
m_diagramClass = schematicDiagramClass;
try
{
m_description = propertySet.GetProperty("DESCRIPTION").ToString();
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "property DESCRIPTION");
}
try
{
m_parentNodeClassName = propertySet.GetProperty("PARENTNODECLASS").ToString();
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "property PARENTNODECLASS");
}
try
{
m_targetNodeClassName = propertySet.GetProperty("TARGETNODECLASS").ToString();
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "property TARGETNODECLASS");
}
try
{
m_targetLinkClassName = propertySet.GetProperty("TARGETLINKCLASS").ToString();
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "property TARGETLINKCLASS");
}
try
{
m_distance = (double)propertySet.GetProperty("DISTANCE");
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "property DISTANCE");
}
}
public void Apply(ISchematicInMemoryDiagram inMemoryDiagram, ESRI.ArcGIS.esriSystem.ITrackCancel cancelTracker)
{
ISchematicRulesHelper rulesHelper = new SchematicRulesHelperClass();
System.Collections.Generic.Dictionary<string, ISchematicInMemoryFeature> colSchfeatureNode = new Dictionary<string, ISchematicInMemoryFeature>();
rulesHelper.InitHelper(inMemoryDiagram);
rulesHelper.KeepVertices = true;
ISchematicDiagramClass diagramClass = null;
ISchematicElementClass elementClass;
ISchematicElementClass elementClassParentNode = null;
IEnumSchematicElementClass enumSchEltCls;
try
{
diagramClass = inMemoryDiagram.SchematicDiagramClass;
}
catch { }
if (diagramClass == null) return;
enumSchEltCls = diagramClass.AssociatedSchematicElementClasses;
if (enumSchEltCls.Count == 0) return;
enumSchEltCls.Reset();
elementClass = enumSchEltCls.Next();
while (elementClass != null)
{
if (elementClass.Name == m_parentNodeClassName)
{
elementClassParentNode = elementClass;
m_parentNodeClass = GetSchematicInMemoryFeatureClass(inMemoryDiagram, elementClass);
}
if (elementClass.Name == m_targetNodeClassName)
{
m_targetNodeClass = GetSchematicInMemoryFeatureClass(inMemoryDiagram, elementClass);
}
if (elementClass.Name == m_targetLinkClassName)
{
m_targetLinkClass = GetSchematicInMemoryFeatureClass(inMemoryDiagram, elementClass);
}
elementClass = enumSchEltCls.Next();
}
if (m_parentNodeClass == null || m_targetNodeClass == null || m_targetLinkClass == null)
return;
IEnumSchematicInMemoryFeature enumSchematicInMemoryFeature;
// list nodes degree two
// get all feature of parent node class
enumSchematicInMemoryFeature = inMemoryDiagram.GetSchematicInMemoryFeaturesByClass(elementClassParentNode);
enumSchematicInMemoryFeature.Reset();
// add the node into collection if it contains only 2 links displayed.
AddNodesDegreeTwo(enumSchematicInMemoryFeature, colSchfeatureNode, rulesHelper);
ISchematicInMemoryFeature schFeatureParent;
foreach (KeyValuePair<string, ISchematicInMemoryFeature> kvp in colSchfeatureNode)
{
schFeatureParent = colSchfeatureNode[kvp.Key];
if (schFeatureParent == null)
continue;
// get 2 links connected of eache feature node
IEnumSchematicInMemoryFeature enumLinks = rulesHelper.GetDisplayedIncidentLinks((ISchematicInMemoryFeatureNode)schFeatureParent, esriSchematicEndPointType.esriSchematicOriginOrExtremityNode);
// enumLinks surely not null and it contain 2 links displayed
double angle1, angle2, angleBisector;
bool first = true;
angle1 = angle2 = angleBisector = 0;
IPoint pointParent = null;
ISchematicInMemoryFeatureNodeGeometry geoParent;
geoParent = (ISchematicInMemoryFeatureNodeGeometry)schFeatureParent;
pointParent = geoParent.InitialPosition;
IPoint pointSon = null;
bool enableCalculate = true;
ISchematicInMemoryFeature schInMemoryFeature = enumLinks.Next();
ISchematicInMemoryFeatureLink schInMemoryLink = (ISchematicInMemoryFeatureLink)schInMemoryFeature;
while (schInMemoryLink != null)
{
ISchematicInMemoryFeatureNodeGeometry nodeGeo;
// get angle of 2 links connected
if (schInMemoryLink.FromNode.Name == schFeatureParent.Name)
nodeGeo = (ISchematicInMemoryFeatureNodeGeometry)schInMemoryLink.ToNode;
else
nodeGeo = (ISchematicInMemoryFeatureNodeGeometry)schInMemoryLink.FromNode;
if (nodeGeo == null)
{
enableCalculate = false;
break;
}
pointSon = nodeGeo.InitialPosition;
if (first)
{
angle1 = CalculateAngle(pointParent, pointSon);
first = false;
}
else
angle2 = CalculateAngle(pointParent, pointSon);
schInMemoryFeature = enumLinks.Next();
schInMemoryLink = (ISchematicInMemoryFeatureLink)schInMemoryFeature;
}
// caculate angle bisector
if (enableCalculate)
angleBisector = CalculateAngleBisector(angle1, angle2);
else
continue;
// construct a geometry for the new node node
// now call alterNode to create a new schematic feature
// construct a correct name
string uniqueNodeName, featureCreateName;
featureCreateName = schFeatureParent.Name + Separator + extensionName;
esriSchematicElementType elementType = esriSchematicElementType.esriSchematicNodeType;
uniqueNodeName = GetUniqueName(inMemoryDiagram, elementType, featureCreateName);
IWorkspace workspace = null;
try
{
workspace = inMemoryDiagram.SchematicDiagramClass.SchematicDataset.SchematicWorkspace.Workspace;
}
catch { }
int datasourceID = -1;
if(workspace != null)
datasourceID = rulesHelper.FindDataSourceID(workspace, false);
if(datasourceID == -1)
datasourceID = m_diagramClass.SchematicDataset.DefaultSchematicDataSource.ID;
ISchematicInMemoryFeature schFeatureNodeCreate = null;
IPoint pointBisector = null;
pointBisector = GetCoordPointBisector(pointParent, angleBisector, m_distance);
try
{
schFeatureNodeCreate = rulesHelper.AlterNode(m_targetNodeClass, uniqueNodeName, null, (IGeometry)pointBisector, datasourceID, 0);
}
catch(Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Impossible to create a feature Node");
}
// now construct a unique link name
string linkName = schFeatureParent.Name + Separator + uniqueNodeName;
string uniqueLinkName;
elementType = esriSchematicElementType.esriSchematicLinkType;
uniqueLinkName = GetUniqueName(inMemoryDiagram, elementType, linkName);
// construct a link
ISchematicInMemoryFeature schFeatureLinkCreate = null;
try
{
schFeatureLinkCreate = rulesHelper.AlterLink(m_targetLinkClass, uniqueLinkName, null, null, datasourceID, 0, schFeatureParent.Name, uniqueNodeName, esriFlowDirection.esriFDWithFlow, 0, 0);
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Impossible to create a feature link");
}
}
if (colSchfeatureNode.Count > 0)
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 "Bisector 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("PARENTNODECLASS", m_parentNodeClassName);
propertySet.SetProperty("TARGETNODECLASS", m_targetNodeClassName);
propertySet.SetProperty("TARGETLINKCLASS", m_targetLinkClassName);
propertySet.SetProperty("DISTANCE", m_distance);
return propertySet;
}
}
ISchematicDiagramClass ISchematicRule.SchematicDiagramClass
{
get { return m_diagramClass; }
}
#endregion
#region ISchematicRuleDesign Members
public void Detach()
{
m_diagramClass = null;
m_parentNodeClass = null;
m_targetNodeClass = null;
m_targetLinkClass = null;
}
ESRI.ArcGIS.esriSystem.IPropertySet ISchematicRuleDesign.PropertySet
{
set
{
m_description = value.GetProperty("DESCRIPTION").ToString();
m_parentNodeClassName = value.GetProperty("PARENTNODECLASS").ToString();
m_targetNodeClassName = value.GetProperty("TARGETNODECLASS").ToString();
m_targetLinkClassName = value.GetProperty("TARGETLINKCLASS").ToString();
m_distance = (double)value.GetProperty("DISTANCE");
}
}
ISchematicDiagramClass ISchematicRuleDesign.SchematicDiagramClass
{
get
{
return m_diagramClass;
}
set
{
m_diagramClass = value;
}
}
#endregion ISchematicRuleDesign
}
}
[Visual Basic .NET]
BisectorRule.vb
Option Strict Off
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(BisectorRule.GUID)> _
<System.Runtime.InteropServices.ProgId(BisectorRule.PROGID)> _
Public Class BisectorRule
Implements ESRI.ArcGIS.Schematic.ISchematicRule
Implements ESRI.ArcGIS.Schematic.ISchematicRuleDesign
Public Const GUID As String = "36D59619-86EB-4244-A521-CEF2187EABCC"
Public Const PROGID As String = "CustomRulesVB.BisectorRule"
' 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_distance As Double = 0.5
Private m_parentNodeClassName As String
Private m_targetNodeClassName As String
Private m_targetLinkClassName As String
Private m_description As String = "Bisector Rule VBNet"
Private m_parentNodeClass As ISchematicInMemoryFeatureClass
Private m_targetNodeClass As ISchematicInMemoryFeatureClass
Private m_targetLinkClass As ISchematicInMemoryFeatureClass
Private Const Separator As String = "_"
Private Const extensionName As String = "BisectorRuleVB"
Public Sub New()
End Sub
Protected Overrides Sub Finalize()
m_diagramClass = Nothing
m_parentNodeClass = Nothing
m_targetNodeClass = Nothing
m_targetLinkClass = Nothing
MyBase.Finalize()
End Sub
Public Property Distance() As Double
Get
Return m_distance
End Get
Set(ByVal value As Double)
m_distance = value
End Set
End Property
Public Property parentNodeClassName() As String
Get
Return m_parentNodeClassName
End Get
Set(ByVal value As String)
m_parentNodeClassName = value
End Set
End Property
Public Property targetNodeClassName() As String
Get
Return m_targetNodeClassName
End Get
Set(ByVal value As String)
m_targetNodeClassName = value
End Set
End Property
Public Property targetLinkClassName() As String
Get
Return m_targetLinkClassName
End Get
Set(ByVal value As String)
m_targetLinkClassName = value
End Set
End Property
#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 ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "property DESCRIPTION")
End Try
Try
m_parentNodeClassName = propertySet.GetProperty("PARENTNODECLASS").ToString()
Catch ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "property PARENTNODECLASS")
End Try
Try
m_targetNodeClassName = propertySet.GetProperty("TARGETNODECLASS").ToString()
Catch ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "property TARGETNODECLASS")
End Try
Try
m_targetLinkClassName = propertySet.GetProperty("TARGETLINKCLASS").ToString()
Catch ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "property TARGETLINKCLASS")
End Try
Try
m_distance = CType(propertySet.GetProperty("DISTANCE"), Double)
Catch ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "property DISTANCE")
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 elementClass As ISchematicElementClass
Dim enumElementClass As IEnumSchematicElementClass
Dim elementClassParentNode As ISchematicElementClass = Nothing
rulesHelper.InitHelper(inMemoryDiagram)
rulesHelper.KeepVertices = True
Dim colSchfeatureNode As New System.Collections.Generic.Dictionary(Of String, ISchematicInMemoryFeature)
Try
diagramClass = inMemoryDiagram.SchematicDiagramClass
Catch
End Try
If (diagramClass Is Nothing) Then Exit Sub
enumElementClass = diagramClass.AssociatedSchematicElementClasses
If (enumElementClass Is Nothing) Then Exit Sub
enumElementClass.Reset()
elementClass = enumElementClass.Next()
While (elementClass IsNot Nothing)
If (elementClass.Name = m_parentNodeClassName) Then
elementClassParentNode = elementClass
m_parentNodeClass = GetSchematicInMemoryFeatureClass(inMemoryDiagram, elementClass)
End If
If (elementClass.Name = m_targetNodeClassName) Then
m_targetNodeClass = GetSchematicInMemoryFeatureClass(inMemoryDiagram, elementClass)
End If
If (elementClass.Name = m_targetLinkClassName) Then
m_targetLinkClass = GetSchematicInMemoryFeatureClass(inMemoryDiagram, elementClass)
End If
elementClass = enumElementClass.Next()
End While
If (m_parentNodeClass Is Nothing Or m_targetNodeClass Is Nothing Or m_targetLinkClass Is Nothing) Then
Exit Sub
End If
Dim enumSchematicInMemoryFeature As IEnumSchematicInMemoryFeature = Nothing
' list nodes degree two
' get all feature of parent node class
enumSchematicInMemoryFeature = inMemoryDiagram.GetSchematicInMemoryFeaturesByClass(elementClassParentNode)
enumSchematicInMemoryFeature.Reset()
'add the node into collection if it contains only 2 links displayed.
AddNodesDegreeTwo(enumSchematicInMemoryFeature, colSchfeatureNode, rulesHelper)
Dim schFeatureParent As ISchematicInMemoryFeature
Dim kvp As KeyValuePair(Of String, ISchematicInMemoryFeature)
For Each kvp In colSchfeatureNode
schFeatureParent = CType(colSchfeatureNode(kvp.Key), ISchematicInMemoryFeature)
If (schFeatureParent Is Nothing) Then Continue For
'get 2 links connected of eache feature node
Dim enumLinks As IEnumSchematicInMemoryFeature
enumLinks = rulesHelper.GetDisplayedIncidentLinks(CType(schFeatureParent, ISchematicInMemoryFeatureNode), esriSchematicEndPointType.esriSchematicOriginOrExtremityNode)
'enumLinks surely not null and it contain 2 links displayed
Dim angle1, angle2, angleBisector As Double
angle1 = 0
angle2 = 0
angleBisector = 0
Dim first As Boolean = True
Dim pointParent As IPoint
Dim geoParent As ISchematicInMemoryFeatureNodeGeometry
geoParent = CType(schFeatureParent, ISchematicInMemoryFeatureNodeGeometry)
pointParent = geoParent.InitialPosition
Dim pointSon As IPoint = Nothing
Dim schInMemoryFeature As ISchematicInMemoryFeature = enumLinks.Next()
Dim schInMemoryLink As ISchematicInMemoryFeatureLink = CType(schInMemoryFeature, ISchematicInMemoryFeatureLink)
Dim enableCalculate As Boolean = True
While (schInMemoryLink IsNot Nothing)
Dim nodeGeo As ISchematicInMemoryFeatureNodeGeometry
'get angle of 2 links connected
If (schInMemoryLink.FromNode Is schFeatureParent) Then
nodeGeo = CType(schInMemoryLink.ToNode, ISchematicInMemoryFeatureNodeGeometry)
Else
nodeGeo = CType(schInMemoryLink.FromNode, ISchematicInMemoryFeatureNodeGeometry)
End If
If (nodeGeo Is Nothing) Then
enableCalculate = False
Exit While
End If
pointSon = nodeGeo.InitialPosition
If (first) Then
angle1 = CalculateAngle(pointParent, pointSon)
first = False
Else
angle2 = CalculateAngle(pointParent, pointSon)
End If
schInMemoryFeature = enumLinks.Next()
schInMemoryLink = CType(schInMemoryFeature, ISchematicInMemoryFeatureLink)
End While
'caculate angle bisector
If (enableCalculate) Then
angleBisector = CalculateAngleBisector(angle1, angle2)
Else
Continue For
End If
'construct a geometry for the new node node
'now call alterNode to create a new schematic feature
'construct a correct name
Dim uniqueNodeName As String
Dim featureCreateName As String
featureCreateName = schFeatureParent.Name & Separator & extensionName
Dim elementType As esriSchematicElementType = esriSchematicElementType.esriSchematicNodeType
uniqueNodeName = GetUniqueName(inMemoryDiagram, esriSchematicElementType.esriSchematicNodeType, featureCreateName)
Dim workspace As IWorkspace = Nothing
Try
workspace = inMemoryDiagram.SchematicDiagramClass.SchematicDataset.SchematicWorkspace.Workspace
Catch
End Try
Dim datasourceID As Integer = -1
If (workspace IsNot Nothing) Then
datasourceID = rulesHelper.FindDataSourceID(workspace, False)
End If
If (datasourceID <> -1) Then
datasourceID = m_diagramClass.SchematicDataset.DefaultSchematicDataSource.ID
End If
Dim schFeatureNodeCreate As ISchematicInMemoryFeature = Nothing
Dim pointBisector As IPoint = Nothing
pointBisector = GetCoordPointBisector(pointParent, angleBisector, m_distance)
Try
schFeatureNodeCreate = rulesHelper.AlterNode(m_targetNodeClass, uniqueNodeName, Nothing, CType(pointBisector, IGeometry), datasourceID, 0)
Catch ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "Impossible to create a feature Node")
End Try
'now construct a unique link name
Dim linkName As String = schFeatureParent.Name & Separator & uniqueNodeName
Dim uniqueLinkName As String
elementType = esriSchematicElementType.esriSchematicLinkType
uniqueLinkName = GetUniqueName(inMemoryDiagram, elementType, linkName)
'construct a link
Dim schFeatureLinkCreate As ISchematicInMemoryFeature = Nothing
Try
schFeatureLinkCreate = rulesHelper.AlterLink(m_targetLinkClass, uniqueLinkName, Nothing, Nothing, datasourceID, 0, schFeatureParent.Name, uniqueNodeName, esriFlowDirection.esriFDWithFlow, 0, 0)
Catch ex As System.Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "Impossible to create a feature link")
End Try
Next
If colSchfeatureNode.Count > 0 Then
colSchfeatureNode.Clear()
End If
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 "Bisector 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("PARENTNODECLASS", m_parentNodeClassName)
propSet.SetProperty("TARGETNODECLASS", m_targetNodeClassName)
propSet.SetProperty("TARGETLINKCLASS", m_targetLinkClassName)
propSet.SetProperty("DISTANCE", m_distance)
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
m_parentNodeClass = Nothing
m_targetNodeClass = Nothing
m_targetLinkClass = 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_parentNodeClassName = value.GetProperty("PARENTNODECLASS").ToString()
m_targetNodeClassName = value.GetProperty("TARGETNODECLASS").ToString()
m_targetLinkClassName = value.GetProperty("TARGETLINKCLASS").ToString()
m_distance = CDbl(value.GetProperty("DISTANCE"))
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 "Bisector Members"
Private Function GetSchematicInMemoryFeatureClass(ByVal inMemoryDiagram As ESRI.ArcGIS.Schematic.ISchematicInMemoryDiagram, ByVal eltClass As ISchematicElementClass) As ISchematicInMemoryFeatureClass
Dim SchInMemoryFeatureClassContainer As ISchematicInMemoryFeatureClassContainer
SchInMemoryFeatureClassContainer = CType(inMemoryDiagram, ISchematicInMemoryFeatureClassContainer)
GetSchematicInMemoryFeatureClass = SchInMemoryFeatureClassContainer.GetSchematicInMemoryFeatureClass(eltClass)
End Function
Private Sub AddNodesDegreeTwo(ByVal enumInMemoryFeature As IEnumSchematicInMemoryFeature, ByVal colSchfeatureNode As System.Collections.Generic.Dictionary(Of String, ISchematicInMemoryFeature), ByVal ruleHelper As ISchematicRulesHelper)
Dim schInMemoryfeature As ISchematicInMemoryFeature
If (enumInMemoryFeature Is Nothing Or colSchfeatureNode Is Nothing Or ruleHelper Is Nothing) Then Return
enumInMemoryFeature.Reset()
schInMemoryfeature = enumInMemoryFeature.Next()
While (schInMemoryfeature IsNot Nothing)
If (schInMemoryfeature.Displayed) Then
Dim enumLinks As IEnumSchematicInMemoryFeature = Nothing
enumLinks = ruleHelper.GetDisplayedIncidentLinks(CType(schInMemoryfeature, ISchematicInMemoryFeatureNode), esriSchematicEndPointType.esriSchematicOriginOrExtremityNode)
If (enumLinks IsNot Nothing And enumLinks.Count = 2) Then
If (Not colSchfeatureNode.ContainsKey(schInMemoryfeature.Name)) Then colSchfeatureNode.Add(schInMemoryfeature.Name, schInMemoryfeature)
End If
End If
schInMemoryfeature = enumInMemoryFeature.Next()
End While
End Sub
Private Function GetUniqueName(ByVal inMemoryDiagram As ESRI.ArcGIS.Schematic.ISchematicInMemoryDiagram, ByVal elementType As esriSchematicElementType, ByVal featureName As String) As String
Dim nameUnique As String = featureName
Dim schInMemoryfeature As ISchematicInMemoryFeature
Dim index As Integer = 1
Dim endWhile As Boolean = False
Do While Not endWhile
schInMemoryfeature = inMemoryDiagram.GetSchematicInMemoryFeatureByType(elementType, nameUnique)
If schInMemoryfeature Is Nothing Then
endWhile = True
ElseIf (schInMemoryfeature.Displayed) Then
nameUnique = nameUnique & index.ToString()
index = index + 1
Else
endWhile = True
End If
Loop
GetUniqueName = nameUnique
End Function
Private Function CalculateAngle(ByVal pointFrom As IPoint, ByVal pointTo As IPoint) As Double
Const radToDegre As Double = 180 / Math.PI
Dim dX, dY As Double
CalculateAngle = 0
dX = pointTo.X - pointFrom.X
dY = pointTo.Y - pointFrom.Y
If (dX <> 0) Then
CalculateAngle = Math.Atan(dY / dX) * radToDegre
Else ' case 2 points are same abcisse
If (dY < 0) Then
CalculateAngle = 270
Else
CalculateAngle = 90
End If
End If
If (dX < 0) Then
CalculateAngle = CalculateAngle + 180
End If
If (CalculateAngle < 0) Then
CalculateAngle = CalculateAngle + 360
End If
End Function
Private Function CalculateAngleBisector(ByVal angle1 As Double, ByVal angle2 As Double) As Double
Dim angleFinal As Double
If (Math.Abs(angle1 - angle2) > 180) Then
angleFinal = (angle1 + angle2) / 2 + 180
Else
angleFinal = (angle1 + angle2) / 2
End If
CalculateAngleBisector = angleFinal
End Function
Private Function GetCoordPointBisector(ByVal pointOrigine As IPoint, ByVal degreeBiSectore As Double, ByVal distance As Double) As IPoint
Dim pointBisector As IPoint = New Point()
Dim angleBisector, degreeFinal, dX, dY As Double
Dim casAngle As Integer = 0
If (degreeBiSectore <= 90) Then
degreeFinal = degreeBiSectore
casAngle = 1
ElseIf (degreeBiSectore <= 180) Then
'degreeFinal = degreeBiSectore - 90
degreeFinal = 180 - degreeBiSectore
casAngle = 2
ElseIf (degreeBiSectore <= 270) Then
degreeFinal = degreeBiSectore - 180
casAngle = 3
Else
degreeFinal = 360 - degreeBiSectore
casAngle = 4
End If
angleBisector = Math.PI * degreeFinal / 180.0
dY = distance * Math.Sin(angleBisector)
dX = distance * Math.Cos(angleBisector)
Dim testx As Double = 0
Dim testy As Double = 0
Select Case casAngle
Case 1 ' case which the vector is on the first of the circle
pointBisector.X = pointOrigine.X + dX
pointBisector.Y = pointOrigine.Y + dY
Case 2 ' case which the vector is on the second of the circle
pointBisector.X = pointOrigine.X - dX
pointBisector.Y = pointOrigine.Y + dY
Case 3 ' case which the vector is on the thirst of the circle
pointBisector.X = pointOrigine.X - dX
pointBisector.Y = pointOrigine.Y - dY
Case Else ' case which the vector is on the fourth of the circle
pointBisector.X = pointOrigine.X + dX
pointBisector.Y = pointOrigine.Y - dY
End Select
GetCoordPointBisector = pointBisector
End Function
#End Region
End Class