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 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;
        }