Beispiel #1
0
 public static void RetireFormingEdge(Shape data, Node liveNode, Node newStaticNode)
 {
     if (data.formingEdges.ContainsKey(liveNode))
     {
         Edge formingEdge = data.formingEdges[liveNode];
         data.formingEdges.Remove(liveNode);
         formingEdge.ReplaceNode(liveNode, newStaticNode);
         formingEdge.UpdateValues();
         data.edges.Add(formingEdge);
     }
 }
Beispiel #2
0
        private void CollapseNodes(List <Node> nodes, Vector2 toPoint, float height)
        {
            Shape _shape = _core.shape;

            int   nodeCount = nodes.Count;
            float minHeight = nodes[0].height;
            float maxHeight = nodes[0].height;

            for (int n = 1; n < nodeCount; n++)
            {
                minHeight = Mathf.Min(minHeight, nodes[n].height);
                maxHeight = Mathf.Min(maxHeight, nodes[n].height);
            }

            Node survivor = nodes[0];

            survivor.position = toPoint;
            survivor.height   = maxHeight;

            int liveEdgeCount = _shape.liveEdges.Count;

            for (int e = 0; e < liveEdgeCount; e++)
            {
                Edge edge = _shape.liveEdges[e];
                if (!nodes.Contains(edge.nodeA) || !nodes.Contains(edge.nodeB))
                {
                    continue;
                }
                edge.UpdateValues();
                if (nodes.Contains(edge.nodeA) && nodes.Contains(edge.nodeB))
                {
                    OffsetShapeLog.AddLine(edge.ToString(), "has collapsed", edge.length, _core.pointAccuracy);
                    OffsetShapeLog.AddLine("Remove edge ", edge.ToString());
                    _shape.liveEdges.Remove(edge);//remove collapsed edge - from length reaching zero
                    liveEdgeCount--;
                    e--;
                    continue;
                    //                    if (!nodes.Contains(edge.nodeA))
                    //                        nodes.Add(edge.nodeA);
                    //                    if (!nodes.Contains(edge.nodeB))
                    //                        nodes.Add(edge.nodeB);
                }
                //else affected edge
                if (nodes.Contains(edge.nodeA))
                {
                    edge.ReplaceNode(edge.nodeA, survivor);
                }
                if (nodes.Contains(edge.nodeB))
                {
                    edge.ReplaceNode(edge.nodeB, survivor);
                }
            }



//            OffsetShapeLog.AddLine("Collapse Nodes:");
//            foreach (Node node in nodes)
//                OffsetShapeLog.Add(node.id + " ");
//            OffsetShapeLog.AddLine("to point: ", toPoint);
//            //            Node newStaticNode = new Node(toPoint, height);//new static node to mark point of collapse
//            //            _shape.AddStaticNode(newStaticNode);//add static node to node array
//            //            OffsetShapeLog.AddLine("new static node added ", newStaticNode.id);
//
//            //            Node newLiveNode = new Node(toPoint, height);//new live node to continue shape forming
//
//            for (int n = 0; n < nodeCount; n++)
//            {
//                nodes[n].position = toPoint;
//                nodes[n].height = maxHeight;
//            }
//
//            Edge collapsedEdge = null;
//            for (int e = 0; e < liveEdgeCount; e++)
//            {
//                Edge edge = _shape.liveEdges[e];
//                if (!nodes.Contains(edge.nodeA) || !nodes.Contains(edge.nodeB)) continue;
//                edge.UpdateValues();
//                if (edge.length < _core.pointAccuracy)//when the edge reaches 0 length it has flipped and should be collapsed
//                {
//                    OffsetShapeLog.AddLine(edge.ToString(), "has collapsed", edge.length, _core.pointAccuracy);
//                    //                    _shape.mesh.CollapseEdge(edge, newLiveNode, newStaticNode);
//                    OffsetShapeLog.AddLine("Remove edge ", edge.ToString());
//                    collapsedEdge = edge;
//                    _shape.liveEdges.Remove(edge);//remove collapsed edge - from length reaching zero
//                    liveEdgeCount--;
//                    e--;
//                    if (!nodes.Contains(edge.nodeA))
//                        nodes.Add(edge.nodeA);
//                    if (!nodes.Contains(edge.nodeB))
//                        nodes.Add(edge.nodeB);
//                }
//            }

//            OffsetShapeLog.AddLine("find live node edges");
//            for (int e = 0; e < liveEdgeCount; e++)
//            {
//                Edge edge = _shape.liveEdges[e];
//                if (!edge.Contains(nodes)) continue;
//                if (nodes.Contains(edge.nodeA) && nodes.Contains(edge.nodeB))
//                {
//                    OffsetShapeLog.AddLine("Remove collapsed edge ", edge.ToString());
//                    _shape.liveEdges.Remove(edge);//remove collapsed edge - likely from parallel
//                    liveEdgeCount--;
//                    e--;
//                    continue;
//                }
//                if (nodes.Contains(edge.nodeA) || newLiveNode == edge.nodeA)
//                {
//                    OffsetShapeLog.AddLine("replace node a");
//                    edge.ReplaceNode(edge.nodeA, newLiveNode);//replace old live node reference to new one
//                    liveEdges.Add(edge);
//                    continue;
//                }
//                if (nodes.Contains(edge.nodeB) || newLiveNode == edge.nodeB)
//                {
//                    OffsetShapeLog.AddLine("replace node b");
//                    edge.ReplaceNode(edge.nodeB, newLiveNode);//replace old live node reference to new one
//                    liveEdges.Add(edge);
//                }
//            }

            for (int n = 0; n < nodeCount; n++)
            {
                Node node = nodes[n];
                if (node == survivor)
                {
                    continue;
                }
                //                Utils.RetireFormingEdge(_shape, node, newStaticNode);
                _shape.liveNodes.Remove(node);
            }

            Utils.CheckParrallel(_shape);

//            OffsetShapeLog.AddLine("Live edges: ", liveEdges.Count);
//            if (liveEdges.Count > 0)//deal with left live edges after the collapse
//            {
//                _shape.AddLiveNode(newLiveNode);//new live node from collapse
//                Edge edgeA = null, edgeB = null;
//                liveEdgeCount = _shape.liveEdges.Count;
//                for (int e = 0; e < liveEdgeCount; e++)//find the two edges left from the collapse
//                {
//                    Edge edge = _shape.liveEdges[e];
//                    if (!_shape.liveEdges.Contains(edge)) continue;
//                    if (edge.nodeA == newLiveNode) edgeA = edge;
//                    if (edge.nodeB == newLiveNode) edgeB = edge;
//                }
//
//                if (edgeA != null && edgeB != null)//if there is a live edge
//                {
//                    Node x = edgeA.GetOtherNode(newLiveNode);
//                    Node y = edgeB.GetOtherNode(newLiveNode);
//                    Utils.CalculateNodeDirAng(newLiveNode, x, y);//recalculate node angle
//                    Utils.NewFormingEdge(_shape, newStaticNode, newLiveNode);//add new forming edge
//                }
//                else
//                {
//                    OffsetShapeLog.AddLine("New live node has not been calculated ", newLiveNode.id);
//                }
//            }

            //            foreach (Node node in nodes)
            //                _data.mesh.ReplaceNode(node, newStaticNode);
        }
Beispiel #3
0
        public void SplitEdge(SplitEvent e)
        {
            OffsetShapeLog.AddLine("Split event");
            OffsetShapeLog.AddLine("by node ", e.node.id);
            OffsetShapeLog.AddLine(e.edge.ToString());
            //nodes
            float realHeight = e.node.height;

            Node nodeStatic = (e.newStaticNode == null) ? new Node(e.point, realHeight) : e.newStaticNode;

            e.newStaticNode = nodeStatic;

            Node nodeOldA = e.edge.nodeA;
            Node nodeOldB = e.edge.nodeB;

            Edge[] edges = Utils.GetABEdge(shape, e.node);
            if (edges[0] == null || edges[1] == null)
            {
                //TODO work out what to really do here.
                return;
            }
            Edge byEdgeA = edges[0];
            Edge byEdgeB = edges[1];
            Node byNodeA = byEdgeA.GetOtherNode(e.node);
            Node byNodeB = byEdgeB.GetOtherNode(e.node);

            OffsetShapeLog.AddLine("by node a", byNodeA.id);
            OffsetShapeLog.AddLine("by node b", byNodeB.id);

            if (byNodeA == null || byNodeB == null)
            {
                return;
            }
            int insertionIndex = _core.shape.LiveIndex(e.node);

            _core.shape.AddStaticNode(nodeStatic);
            _core.shape.liveNodes.Remove(e.node);
            //discard the old edge
            OffsetShapeLog.AddLine("Discard old edge ", e.edge.ToString());
            _core.shape.liveEdges.Remove(e.edge);//
            if (!_splitEdges.ContainsKey(e.edge))
            {
                _splitEdges.Add(e.edge, e);
            }
            Utils.RetireFormingEdge(_core.shape, e.node, nodeStatic);

            Node newLiveNodeA = null;
            Node newLiveNodeB = null;

            //node a
            if (!e.edge.Contains(byNodeA))
            {
                newLiveNodeA   = new Node(e.point, realHeight);
                e.newLiveNodeA = newLiveNodeA;
                //calculate new node directions
                Utils.CalculateNodeDirAng(newLiveNodeA, byNodeA, nodeOldA);
                _core.shape.InsertLiveNode(insertionIndex, newLiveNodeA);
                byEdgeA.ReplaceNode(e.node, newLiveNodeA);
                //create the two new edges from the split
                Edge newEdgeA = new Edge(nodeOldA, newLiveNodeA);
                _core.shape.liveEdges.Add(newEdgeA);
                e.newLiveEdgeA = newEdgeA;
                Edge formingEdgeA = Utils.NewFormingEdge(_core.shape, nodeStatic, newLiveNodeA);

                OffsetShapeLog.AddLine("new live node a");
                OffsetShapeLog.AddLine(newLiveNodeA.id);
                OffsetShapeLog.AddLine("new edges - old edge - forming edge a");
                OffsetShapeLog.AddLine(newEdgeA.ToString());
                OffsetShapeLog.AddLine(byEdgeA.ToString());
                OffsetShapeLog.AddLine(formingEdgeA.ToString());
            }
            else
            {
                Utils.RetireFormingEdge(_core.shape, byNodeA, nodeStatic);
                _core.shape.liveNodes.Remove(byNodeA);
            }

            //node b
            if (!e.edge.Contains(byNodeB))
            {
                newLiveNodeB   = new Node(e.point, realHeight);
                e.newLiveNodeB = newLiveNodeB;
                Utils.CalculateNodeDirAng(newLiveNodeB, nodeOldB, byNodeB);
                _core.shape.InsertLiveNode(insertionIndex, newLiveNodeB);
                byEdgeB.ReplaceNode(e.node, newLiveNodeB);
                Edge newEdgeB = new Edge(newLiveNodeB, nodeOldB);
                _core.shape.liveEdges.Add(newEdgeB);
                e.newLiveEdgeB = newEdgeB;
                Edge formingEdgeB = Utils.NewFormingEdge(_core.shape, nodeStatic, newLiveNodeB);

                OffsetShapeLog.AddLine("new live node b");
                OffsetShapeLog.AddLine(newLiveNodeB.id);
                OffsetShapeLog.AddLine("new edges - old edge - forming edge b");
                OffsetShapeLog.AddLine(byEdgeB.ToString());
                OffsetShapeLog.AddLine(newEdgeB.ToString());
                OffsetShapeLog.AddLine(formingEdgeB.ToString());
            }
            else
            {
                Utils.RetireFormingEdge(_core.shape, byNodeB, nodeStatic);
                _core.shape.liveNodes.Remove(byNodeB);
            }

            if (newLiveNodeA != null && newLiveNodeB != null)
            {
                if (!_core.currentSplits.ContainsKey(newLiveNodeA.id))
                {
                    _core.currentSplits.Add(newLiveNodeA.id, new List <int>());
                }
                _core.currentSplits[newLiveNodeA.id].Add(newLiveNodeB.id);
                if (!_core.currentSplits.ContainsKey(newLiveNodeB.id))
                {
                    _core.currentSplits.Add(newLiveNodeB.id, new List <int>());
                }
                _core.currentSplits[newLiveNodeB.id].Add(newLiveNodeA.id);
            }
        }
Beispiel #4
0
        public void SplitEdge(SplitEvent e)
        {
            OffsetShapeLog.AddLine("Split event");
            OffsetShapeLog.AddLine("by node ", e.node.id);
            OffsetShapeLog.AddLine(e.edge.ToString());
            //nodes
            Node nodeStatic   = new Node(e.point, e.height);
            Node newLiveNodeA = new Node(e.point, e.height);
            Node newLiveNodeB = new Node(e.point, e.height);

            e.newLiveNodeA  = newLiveNodeA;
            e.newLiveNodeB  = newLiveNodeB;
            e.newStaticNode = nodeStatic;


            Node nodeOldA = e.edge.nodeA;
            Node nodeOldB = e.edge.nodeB;

            Edge byEdgeA = e.nodeEdgeA;
            Edge byEdgeB = e.nodeEdgeB;

            if (byEdgeA == null || byEdgeB == null)
            {
                //TODO work out what to really do here.
                return;
            }
            Node byNodeA = byEdgeA.GetOtherNode(e.node);
            Node byNodeB = byEdgeB.GetOtherNode(e.node);

            OffsetShapeLog.AddLine("by node a", byNodeA.id);
            OffsetShapeLog.AddLine("by node b", byNodeB.id);

            if (byNodeA == null || byNodeB == null)
            {
                return;
            }

            //calculate new node directions
            Utils.CalculateNodeDirAng(newLiveNodeA, byNodeA, nodeOldA);
            Utils.CalculateNodeDirAng(newLiveNodeB, nodeOldB, byNodeB);

            _shape.AddLiveNode(newLiveNodeA);
            _shape.AddLiveNode(newLiveNodeB);
            _shape.AddStaticNode(nodeStatic);
            _shape.liveNodes.Remove(e.node);

            //discard the old edge
            OffsetShapeLog.AddLine("Discard old edge ", e.edge.ToString());
            _shape.liveEdges.Remove(e.edge);//
            byEdgeA.ReplaceNode(e.node, newLiveNodeA);
            byEdgeB.ReplaceNode(e.node, newLiveNodeB);
            //create the two new edges from the split
            Edge newEdgeA = new Edge(nodeOldA, newLiveNodeA);

            _shape.liveEdges.Add(newEdgeA);
            e.newLiveEdgeA = newEdgeA;
            Edge newEdgeB = new Edge(newLiveNodeB, nodeOldB);

            _shape.liveEdges.Add(newEdgeB);
            e.newLiveEdgeB = newEdgeB;

            //forming edges
            Utils.RetireFormingEdge(_shape, e.node, nodeStatic);
            Edge formingEdgeA = Utils.NewFormingEdge(_shape, nodeStatic, newLiveNodeA);
            Edge formingEdgeB = Utils.NewFormingEdge(_shape, nodeStatic, newLiveNodeB);

            //            int aIndex = data.liveNodes.IndexOf(nodeLiveA);
            //            int bIndex = data.liveNodes.IndexOf(nodeLiveB);

            newLiveNodeA.MoveForward(0.1f, 1);
            newLiveNodeB.MoveForward(0.1f, 1);
            if (!currentSplits.ContainsKey(newLiveNodeA.id))
            {
                currentSplits.Add(newLiveNodeA.id, new List <int>());
            }
            currentSplits[newLiveNodeA.id].Add(newLiveNodeB.id);
            if (!currentSplits.ContainsKey(newLiveNodeB.id))
            {
                currentSplits.Add(newLiveNodeB.id, new List <int>());
            }
            currentSplits[newLiveNodeB.id].Add(newLiveNodeA.id);

            //            _shape.mesh.SplitEdge(e);

            OffsetShapeLog.AddLine("new live nodes");
            OffsetShapeLog.AddLine(newLiveNodeA.id);
            OffsetShapeLog.AddLine(newLiveNodeB.id);
            OffsetShapeLog.AddLine("new edges - old edge - forming edge a");
            OffsetShapeLog.AddLine(newEdgeA.ToString());
            OffsetShapeLog.AddLine(byEdgeA.ToString());
            OffsetShapeLog.AddLine(formingEdgeA.ToString());

            OffsetShapeLog.AddLine("new edges - old edge - forming edge b");
            OffsetShapeLog.AddLine(byEdgeB.ToString());
            OffsetShapeLog.AddLine(newEdgeB.ToString());
            OffsetShapeLog.AddLine(formingEdgeB.ToString());

            Utils.CheckParrallel(_shape);
        }
Beispiel #5
0
        private void CollapseNodes(List <Node> nodes, Vector2 toPoint, float height, BaseEvent evt)
        {
            if (nodes.Count < 2)
            {
                return;
            }
            OffsetShapeLog.AddLine("Collapse Nodes:");
            foreach (Node node in nodes)
            {
                OffsetShapeLog.Add(node.id + " ");
            }
            OffsetShapeLog.AddLine("to point: ", toPoint);
            Node newStaticNode = (evt.newStaticNode == null) ? new Node(toPoint, height) : evt.newStaticNode;//new static node to mark point of collapse

            evt.newStaticNode = newStaticNode;
            _core.shape.AddStaticNode(newStaticNode);//add static node to node array

            int         liveEdgeCount = _core.shape.liveEdges.Count;
            List <Edge> liveEdges     = new List <Edge>();
            //            Node newLiveNode = new Node(toPoint, nodes[0].height);//new live node to continue shape forming

            int nodeCount = nodes.Count;

            for (int n = 0; n < nodeCount; n++)
            {
                nodes[n].position = toPoint;
            }

            for (int e = 0; e < liveEdgeCount; e++)
            {
                Edge edge = _core.shape.liveEdges[e];
                if (!nodes.Contains(edge.nodeA) || !nodes.Contains(edge.nodeB))
                {
                    continue;
                }
                edge.UpdateValues();
                if (edge.length < pointAccuracy)//when the edge reaches 0 length it has flipped and should be collapsed
                {
                    OffsetShapeLog.AddLine(edge.ToString(), "has collapsed", edge.length, pointAccuracy);
                    OffsetShapeLog.AddLine("Remove edge ", edge.ToString());
                    _core.shape.liveEdges.Remove(edge);//remove collapsed edge - from length reaching zero
                    _collapsedEdges.Add(edge, newStaticNode);
                    liveEdgeCount--;
                    e--;
                    if (!nodes.Contains(edge.nodeA))
                    {
                        nodes.Add(edge.nodeA);
                    }
                    if (!nodes.Contains(edge.nodeB))
                    {
                        nodes.Add(edge.nodeB);
                    }
                }
            }

            OffsetShapeLog.AddLine("find live node edges");
            Dictionary <Node, int> nodeOccurances = new Dictionary <Node, int>();//check parallel collapses

            for (int e = 0; e < liveEdgeCount; e++)
            {
                Edge edge = _core.shape.liveEdges[e];
                if (!edge.Contains(nodes))
                {
                    continue;                                                 //unaffected edge
                }
                if (nodes.Contains(edge.nodeA) && nodes.Contains(edge.nodeB)) //edge is completely affected by the merge and has collapsed
                {
                    OffsetShapeLog.AddLine("Remove collapsed edge ", edge.ToString());
                    _core.shape.liveEdges.Remove(edge);//remove collapsed edge
                    _collapsedEdges.Add(edge, newStaticNode);
                    liveEdgeCount--;
                    e--;
                    continue;
                }
                if (nodes.Contains(edge.nodeA))// || newLiveNode == edge.nodeA)
                {
                    //                    edge.ReplaceNode(edge.nodeA, newLiveNode);//replace old live node reference to new one //TODO
                    liveEdges.Add(edge);
                    OffsetShapeLog.AddLine("Live edges: ", edge);
                    if (nodeOccurances.ContainsKey(edge.nodeB))
                    {
                        nodeOccurances[edge.nodeB]++;
                    }
                    else
                    {
                        nodeOccurances.Add(edge.nodeB, 1);
                    }
                    continue;
                }
                if (nodes.Contains(edge.nodeB))// || newLiveNode == edge.nodeB)
                {
                    //                    edge.ReplaceNode(edge.nodeB, newLiveNode);//replace old live node reference to new one //TODO
                    liveEdges.Add(edge);
                    OffsetShapeLog.AddLine("Live edges: ", edge);
                    if (nodeOccurances.ContainsKey(edge.nodeA))
                    {
                        nodeOccurances[edge.nodeA]++;
                    }
                    else
                    {
                        nodeOccurances.Add(edge.nodeA, 1);
                    }
                }
            }

            int affectedLiveEdges = liveEdges.Count;

            foreach (KeyValuePair <Node, int> kv in nodeOccurances)
            {
                OffsetShapeLog.AddLine("node occured: ", kv.Key.id, kv.Value);
                if (kv.Value > 1)
                {
                    Node pinchedNode = kv.Key;
                    OffsetShapeLog.AddLine("Pinched node: ", pinchedNode.id);
                    pinchedNode.position = toPoint;
                    for (int a = 0; a < affectedLiveEdges; a++)
                    {
                        shape.formingEdges[kv.Key].ReplaceNode(kv.Key, newStaticNode);
                        if (liveEdges[a].Contains(kv.Key))//any live edges that contains the node should be culled - it has collapsed
                        {
                            Edge edge = liveEdges[a];
                            OffsetShapeLog.AddLine("Collapsed Edge: ", edge);
                            liveEdges.Remove(edge);
                            _core.shape.liveEdges.Remove(edge);//remove collapsed edge
                            affectedLiveEdges--;
                            a--;
                        }
                    }
                    Utils.RetireFormingEdge(shape, kv.Key, newStaticNode);
                    _core.shape.liveNodes.Remove(kv.Key);
                }
            }

            //            for (int n = 0; n < nodeCount; n++)
            //            {
            //                Node node = nodes[n];
            //                Utils.RetireFormingEdge(_core.shape, node, newStaticNode);
            //                _core.shape.liveNodes.Remove(node);
            ////                _substitutions.Add(node, newLiveNode); TODO EEK!
            //            }

            OffsetShapeLog.AddLine("Live edges: ", liveEdges.Count);
            if (affectedLiveEdges > 0)//deal with left live edges after the collapse - calculate the angle the new node needs to move into
            {
                float[] angles             = new float[affectedLiveEdges];
                int     smallestAngleIndex = 0;//keep this for when we need to loop the angle comparison
                float   smallestAngle      = Mathf.Infinity;
                for (int a = 0; a < affectedLiveEdges; a++)
                {
                    Node    from  = liveEdges[a].GetEdgeNode(nodes);
                    Node    to    = liveEdges[a].GetOtherNode(from);
                    Vector2 dir   = (to.position - from.position).normalized;
                    float   angle = Utils.SignAngle(dir);
                    angles[a] = angle;
                    OffsetShapeLog.AddLine(liveEdges[a], angle);
                    if (angle < smallestAngle)
                    {
                        smallestAngle      = angle;
                        smallestAngleIndex = a;
                    }
                }

                Edge startEdge = null;
                for (int a = 0; a < affectedLiveEdges; a++)
                {
                    if (nodes.Contains(liveEdges[a].nodeA))
                    {
                        startEdge = liveEdges[a];
                        break;
                    }
                }
                if (startEdge != null)
                {
                    Edge[] orderedEdges = new Edge[affectedLiveEdges];
                    orderedEdges[0] = startEdge;
                    Edge  currentEdge  = startEdge;
                    float currentAngle = angles[liveEdges.IndexOf(currentEdge)];
                    int   orderIndex   = 1;

                    OffsetShapeLog.AddLine("order edges by angle");
                    OffsetShapeLog.AddLine(0, startEdge);
                    while (orderIndex < affectedLiveEdges)
                    {
                        Edge  candidate      = null;
                        float candidateAngle = Mathf.Infinity;
                        for (int a = 0; a < affectedLiveEdges; a++)
                        {
                            Edge nextEdge = liveEdges[a];
                            if (currentEdge == nextEdge)
                            {
                                continue;
                            }
                            float nextAngle = angles[liveEdges.IndexOf(nextEdge)];
                            if (nextAngle > currentAngle)
                            {
                                if (nextAngle < candidateAngle)
                                {
                                    candidateAngle = nextAngle;
                                    candidate      = nextEdge;
                                }
                            }
                        }

                        if (candidate == null)
                        {
                            candidate = liveEdges[smallestAngleIndex];
                        }

                        if (candidate != null)
                        {
                            OffsetShapeLog.AddLine(orderIndex, candidate);
                            orderedEdges[orderIndex] = candidate;
                            orderIndex++;
                            currentEdge  = candidate;
                            currentAngle = angles[liveEdges.IndexOf(currentEdge)];
                        }
                    }

                    OffsetShapeLog.AddLine("affected Live Edge count" + affectedLiveEdges);
                    List <Node> newLiveNodes = new List <Node>();
                    if (affectedLiveEdges % 2 != 0)
                    {
                        //                        Debug.LogError("affected Live Edge count uneven: "+ affectedLiveEdges);
                        //                        Debug.LogError("");
                        return;
                    }
                    for (int o = 0; o < affectedLiveEdges; o += 2)
                    {
                        Edge splitEdgeA = orderedEdges[o];
                        Edge splitEdgeB = orderedEdges[o + 1];
                        OffsetShapeLog.AddLine("split Edge A", splitEdgeA);
                        OffsetShapeLog.AddLine("split Edge B", splitEdgeB);

                        Node newLiveNode = new Node(toPoint, nodes[0].height); //new live node to continue shape forming
                        _core.shape.AddLiveNode(newLiveNode);                  //new live node from collapse
                        newLiveNodes.Add(newLiveNode);

                        if (nodes.Contains(splitEdgeA.nodeA))
                        {
                            splitEdgeA.ReplaceNode(splitEdgeA.nodeA, newLiveNode);//replace old live node reference to new one
                        }
                        else
                        {
                            splitEdgeA.ReplaceNode(splitEdgeA.nodeB, newLiveNode);//replace old live node reference to new one
                        }
                        if (nodes.Contains(splitEdgeB.nodeA))
                        {
                            splitEdgeB.ReplaceNode(splitEdgeB.nodeA, newLiveNode);//replace old live node reference to new one
                        }
                        else
                        {
                            splitEdgeB.ReplaceNode(splitEdgeB.nodeB, newLiveNode);//replace old live node reference to new one
                        }
                        Node x = splitEdgeA.GetOtherNode(newLiveNode);
                        Node y = splitEdgeB.GetOtherNode(newLiveNode);
                        Utils.CalculateNodeDirAng(newLiveNode, x, y);                  //recalculate node angle
                        Utils.NewFormingEdge(_core.shape, newStaticNode, newLiveNode); //add new forming edge
                    }

                    int newLiveNodeCount = newLiveNodes.Count;
                    for (int l = 0; l < newLiveNodeCount; l++)
                    {
                        Node lNode = newLiveNodes[l];
                        if (!_core.currentSplits.ContainsKey(lNode.id))
                        {
                            _core.currentSplits.Add(lNode.id, new List <int>());
                        }

                        for (int lb = 0; lb < newLiveNodeCount; lb++)
                        {
                            if (l == lb)
                            {
                                continue;
                            }
                            Node lbNode = newLiveNodes[lb];
                            _core.currentSplits[lNode.id].Add(lbNode.id);
                        }
                    }
                }



                //                Edge edgeA = null, edgeB = null;
                //                liveEdgeCount = _core.shape.liveEdges.Count;
                //                for (int e = 0; e < liveEdgeCount; e++)//find the two edges left from the collapse
                //                {
                //                    Edge edge = _core.shape.liveEdges[e];
                //                    if (!_core.shape.liveEdges.Contains(edge)) continue;//not a live edge
                //                    if (edge.nodeA == newLiveNode) edgeA = edge;
                //                    if (edge.nodeB == newLiveNode) edgeB = edge;
                //                }
                //
                //                if (edgeA != null && edgeB != null)//if there is a live edge
                //                {
                //                    Node x = edgeA.GetOtherNode(newLiveNode);
                //                    Node y = edgeB.GetOtherNode(newLiveNode);
                //                    Utils.CalculateNodeDirAng(newLiveNode, x, y);//recalculate node angle
                //                    Utils.NewFormingEdge(_core.shape, newStaticNode, newLiveNode);//add new forming edge
                //                }
                //                else
                //                {
                //                    OffsetShapeLog.AddLine("New live node has not been calculted ", newLiveNode.id);
                //                }
            }


            for (int n = 0; n < nodeCount; n++)
            {
                Node node = nodes[n];
                Utils.RetireFormingEdge(_core.shape, node, newStaticNode);
                _core.shape.liveNodes.Remove(node);
                //                _substitutions.Add(node, newLiveNode); TODO EEK!
            }

            Utils.CheckParrallel(_core.shape);
        }