Exemple #1
0
 public void InsertLiveNode(int index, Node newNode)
 {
     OffsetShapeLog.AddLine("New live node " + _liveNodeIndex);
     liveNodes.Insert(index, newNode);
     newNode.id = _liveNodeIndex;
     _liveNodeIndex++;
 }
Exemple #2
0
 public void Merge(IEvent e)
 {
     OffsetShapeLog.AddLine("Merge Event type " + e.GetType());
     if (e.GetType() == typeof(FlipEvent))
     {
         Merge((FlipEvent)e);
     }
     if (e.GetType() == typeof(SplitEvent))
     {
         Merge((SplitEvent)e);
     }
     if (e.GetType() == typeof(MergedEvent))
     {
         Merge((MergedEvent)e);
     }
     affectedNodes.AddRange(e.affectedNodes);
     if (eventCount > 0)
     {
         height = Mathf.Min(height, e.height);
     }
     else
     {
         height = e.height;
     }
     percent = Mathf.Min(percent, e.percent);
     eventCount++;
 }
Exemple #3
0
 public void AddTriangle(SkeletonTri newTriangle)
 {
     OffsetShapeLog.AddLine("Add Triangle: " + newTriangle[0].id + " " + newTriangle[1].id + " " + newTriangle[2].id);
     newTriangle.id = _triIndex;
     _triIndex++;
     _tris.Add(newTriangle);
 }
Exemple #4
0
        public FlipEvent CreateFlipEvent(Edge edge, Vector2 atPoint)
        {
            Node nodeA = edge.nodeA;
            Node nodeB = edge.nodeB;

            OffsetShapeLog.AddLine("Flip event detected");
            //            Debug.Log("Flip event detected");
            FlipEvent flipEvent = new FlipEvent();

            flipEvent.edge = edge;
            OffsetShapeLog.AddLine(edge.ToString());
            Vector2 point          = atPoint;//intersectionInfo.Point0;
            float   pointADistance = Vector2.Distance(point, nodeA.previousPosition);
            float   pointBDistance = Vector2.Distance(point, nodeB.previousPosition);
            //            float percentA = pointADistance / nodeA.distance;
            //            float percentB = pointBDistance / nodeB.distance;
            float percentA = pointADistance / Mathf.Abs(nodeA.distance);
            float percentB = pointBDistance / Mathf.Abs(nodeB.distance);
            float height   = (nodeA.height + nodeB.height) * 0.5f;

            flipEvent.percent = Mathf.Min(percentA, percentB);
            flipEvent.point   = point;
            flipEvent.height  = height;
            //            AddEvent(flipEvent);
            return(flipEvent);
        }
Exemple #5
0
 public void AddLiveNode(Node newNode)
 {
     OffsetShapeLog.AddLine("New live node " + _liveNodeIndex);
     liveNodes.Add(newNode);
     newNode.id = _liveNodeIndex;
     _liveNodeIndex++;
 }
Exemple #6
0
        private void CalculateUVs(SkeletonTri tri)
        {
            int baseIndex = FindBaseIndex(tri);

            OffsetShapeLog.DrawLine(tri.centre, tri.positions[baseIndex], Color.red);
            Vector2 baseUV = Vector2.zero;

            OffsetShapeLog.AddLine("============");
            OffsetShapeLog.AddLine("triangle uv node find! ", tri.id, " base node id ", tri[baseIndex].id, " tangent ", tri.tangentV3);
            OffsetShapeLog.AddLine("============");
            foreach (UVNode uvnode in _uvnodes)
            {
                OffsetShapeLog.AddLine("uvnode! ", uvnode.node.id, uvnode.tangent);
                if (uvnode.node != tri[baseIndex])
                {
                    continue;
                }
                if (!uvnode.TangentCheck(tri.tangentV3))
                {
                    continue;
                }
                baseUV = uvnode.uv;
            }
            OffsetShapeLog.AddLine("!!!!!!!!!!!!");
            OffsetShapeLog.DrawLabel(tri.centre, baseUV.ToString());

            int indexB = (baseIndex + 1) % 3;
            int indexC = (baseIndex + 2) % 3;

            Vector3 p0 = tri.positions[baseIndex];
            Vector3 p1 = tri.positions[indexB];
            Vector3 p2 = tri.positions[indexC];

            Vector3 vA = p1 - p0;
            Vector3 vB = p2 - p0;

            Vector3 right   = tri.tangentV3;
            Vector3 up      = Vector3.Cross(right, tri.normal);
            Vector3 upVA    = Vector3.Project(vA, up);
            Vector3 rightVA = Vector3.Project(vA, right);
            Vector3 upVB    = Vector3.Project(vB, up);
            Vector3 rightVB = Vector3.Project(vB, right);

            float   apexUVAX = rightVA.magnitude * Mathf.Sign(Vector3.Dot(right, rightVA));
            float   apexUVAY = upVA.magnitude * Mathf.Sign(Vector3.Dot(up, upVA));
            Vector2 apexUVA  = baseUV + new Vector2(apexUVAX, apexUVAY);
            float   apexUVBX = rightVB.magnitude * Mathf.Sign(Vector3.Dot(right, rightVB));
            float   apexUVBY = upVB.magnitude * Mathf.Sign(Vector3.Dot(up, upVB));
            Vector2 apexUVB  = baseUV + new Vector2(apexUVBX, apexUVBY);

            _uvnodes.Add(new UVNode(tri[indexB], apexUVA, right));
            _uvnodes.Add(new UVNode(tri[indexC], apexUVB, right));

            Vector2[] uvs = new Vector2[3];
            uvs[baseIndex] = baseUV;
            uvs[indexB]    = apexUVA;
            uvs[indexC]    = apexUVB;
            tri.uvs        = uvs;
        }
Exemple #7
0
 public void ReplaceNode(Node oldNode, Node newNode)
 {
     OffsetShapeLog.AddLine("ReplaceNode: ", oldNode.id, newNode.id);
     if (oldNode == newNode)
     {
         return;
     }
     if (_nodeA == oldNode)
     {
         _nodeA = newNode;
     }
     if (_nodeB == oldNode)
     {
         _nodeB = newNode;
     }
     UpdateValues();
 }
Exemple #8
0
        public SplitEvent CreateSplitEvent(Shape data, Node node, Edge edge, Vector2 point, float eventPercent, Vector2 calculationPoint)
        {
            OffsetShapeLog.AddLine("Split event detected");
            SplitEvent splitEvent = new SplitEvent();

            splitEvent.node = node;
            splitEvent.edge = edge;
            OffsetShapeLog.AddLine(eventPercent.ToString("P"));
            OffsetShapeLog.AddLine("node " + node.id);
            OffsetShapeLog.AddLine("splits edge " + edge);

            Vector2 a = node.previousPosition;
            Vector2 b = node.position;
//            Vector2 x = point;//intersectionInfo.Point0;

            //            float movementMag = nodeMovement.magnitude;
            //            float intersectionMag = (x - a).magnitude;
            //            float eventPercent = intersectionMag / movementMag;
            Vector2 actualIntersectionPoint = Vector2.Lerp(a, b, eventPercent);//translate the point to the real movement point

            splitEvent.point             = actualIntersectionPoint;
            splitEvent.percent           = eventPercent;
            splitEvent.height            = node.height;
            splitEvent.nodeMovementStart = node.previousPosition; //movementSegment.P0;
            splitEvent.nodeMovementEnd   = node.position;         //calculationPoint;//movementSegment.P1;

            Edge[] edges = Utils.GetABEdge(data, node);
            if (edges[0] == null || edges[1] == null)
            {
                return(null);
            }
            splitEvent.nodeEdgeA = edges[0];
            splitEvent.nodeEdgeB = edges[1];

            if (splitEvent.ContainsNode(splitEvent.nodeEdgeA.GetOtherNode(node)))
            {
                OffsetShapeLog.AddLine("Split event collapses shape");
            }
            if (splitEvent.ContainsNode(splitEvent.nodeEdgeB.GetOtherNode(node)))
            {
                OffsetShapeLog.AddLine("Split event collapses shape");
            }

            //            AddEvent(splitEvent);
            return(splitEvent);
        }
Exemple #9
0
        public Node AddStaticNode(Node newNode)
        {
            int staticNodeCount = nodes.Count;

            for (int s = 0; s < staticNodeCount; s++)
            {
                if ((nodes[s].position - newNode.position).sqrMagnitude < (Mathf.Epsilon * Mathf.Epsilon))
                {
                    return(nodes[s]);
                }
            }
            OffsetShapeLog.AddLine("New static node " + _staticNodeIndex);
            nodes.Add(newNode);
            newNode.id = _staticNodeIndex;
            _staticNodeIndex++;
            return(newNode);
        }
        public void SplitEvent(SplitEvent sEvent)
        {
            if (_substitutions.ContainsKey(sEvent.node))
            {
                OffsetShapeLog.AddLine(sEvent.node + " is replaced with " + _substitutions[sEvent.node]);
                sEvent.node = _substitutions[sEvent.node];//replce any modified node values
            }

            if (sEvent.edge.Contains(sEvent.node))//edge splitting itself
            {
                return;
            }

            if (_collapsedEdges.ContainsKey(sEvent.edge))
            {
                CollapseNodes(new List <Node> {
                    sEvent.node, _collapsedEdges[sEvent.edge]
                }, sEvent.point, sEvent.height, sEvent);
                OffsetShapeLog.AddLine("Split event falls on edge collapse.");
                return;//if the edge we were splitting already collaped - merge it
            }

            if (_splitEdges.ContainsKey(sEvent.edge))
            {
                SplitEvent previousSplit = _splitEdges[sEvent.edge];

                float sqrMagA = Vector2.SqrMagnitude(sEvent.edge.nodeA.position - sEvent.point);
                float sqrMagB = Vector2.SqrMagnitude(previousSplit.edge.nodeA.position - previousSplit.point);

                if (sqrMagA < sqrMagB)
                {
                    OffsetShapeLog.AddLine(sEvent.edge.ToString() + " is replaced with " + previousSplit.newLiveEdgeA.ToString());
                    sEvent.edge = previousSplit.newLiveEdgeA;
                }
                else
                {
                    OffsetShapeLog.AddLine(sEvent.edge.ToString() + " is replaced with " + previousSplit.newLiveEdgeB.ToString());
                    sEvent.edge = previousSplit.newLiveEdgeB;
                }
            }

            SplitEdge(sEvent);
        }
        //        public void CollapseEdge(Edge edge, Vector2 toPoint, float height)
        //        {
        //            List<Node> nodes = new List<Node>();
        //            nodes.Add(edge.nodeA);
        //            nodes.Add(edge.nodeB);
        //            CollapseNodes(nodes, toPoint, height);
        //        }

        public void MergeEvent(MergedEvent mEvent)
        {
            OffsetShapeLog.AddLine("Complex merge event gynastics ahead");
            CollapseNodes(mEvent.mergeNodes, mEvent.point, mEvent.height, mEvent);

            int splitCount = mEvent.splitEvents.Count;

            OffsetShapeLog.AddLine("Do the splits - in percent order");
            float currentPercent = -1;

            for (int s = 0; s < splitCount; s++)
            {
                float      minimumPercent = 1;
                SplitEvent candidate      = null;
                for (int so = 0; so < splitCount; so++)
                {
                    SplitEvent sEvent = mEvent.splitEvents[so];
                    //                    OffsetShapeLog.AddLine(sEvent.ToString());
                    //                    OffsetShapeLog.AddLine(sEvent.percent, currentPercent);
                    if (sEvent.percent > currentPercent)
                    {
                        //                        OffsetShapeLog.AddLine(sEvent.percent, minimumPercent);
                        if (sEvent.percent < minimumPercent)
                        {
                            minimumPercent = sEvent.percent;
                            candidate      = sEvent;
                        }
                    }
                }
                if (candidate != null)
                {
                    SplitEvent(candidate);
                    currentPercent = candidate.percent;
                }
                //                mEvent.splitEvents[s].point = mEvent.point;
            }
        }
Exemple #12
0
        public MergedEvent CreateMergeEvent(Node[] nodes, Vector2 atPoint, float eventPercent, Vector2 calculationPoint)
        {
            OffsetShapeLog.AddLine("Merge event detected");
            OffsetShapeLog.Add(nodes);
            MergedEvent mergeEvent = new MergedEvent();

            mergeEvent.mergeNodes.AddRange(nodes);
            mergeEvent.point = atPoint;
            float height = 0;

            //            float eventPercent = 1;
            foreach (Node node in nodes)
            {
                height += node.height;

                //                float pointDistance = Vector2.Distance(atPoint, node.previousPosition);
                //                float pointPercent = pointDistance / node.distance;
                //                eventPercent = Mathf.Min(eventPercent, pointPercent);
            }
            mergeEvent.height  = height / nodes.Length;
            mergeEvent.percent = eventPercent;
            //            AddEvent(mergeEvent);
            return(mergeEvent);
        }
Exemple #13
0
        /// <summary>
        /// Remove any live edges that are now parallel and will no longer serve a purpose
        /// </summary>
        /// <param name="data"></param>
        public static void CheckParrallel(Shape data)
        {
            int liveEdgeCount = data.liveEdges.Count;

            for (int a = 0; a < liveEdgeCount; a++)
            {
                for (int b = 0; b < liveEdgeCount; b++)
                {
                    if (a == b)
                    {
                        continue;
                    }
                    Edge    edgeA = data.liveEdges[a];
                    Edge    edgeB = data.liveEdges[b];
                    Vector2 dirA  = edgeA.direction;
                    Vector2 dirB  = edgeB.direction;

                    if (ParallelLines(dirA, dirB))
                    {
                        Node nodeAA = edgeA.nodeA;
                        Node nodeAB = edgeA.nodeB;
                        Node nodeBA = edgeB.nodeA;
                        Node nodeBB = edgeB.nodeB;

                        bool connectedA = nodeAA == nodeBA || nodeAA == nodeBB;
                        bool connectedB = nodeAB == nodeBA || nodeAB == nodeBB;

                        if (connectedA && connectedB)//connected parallel lines serve no purpose
                        {
                            OffsetShapeLog.AddLine("Parallel Lines!");
                            OffsetShapeLog.AddLine(edgeA.ToString());
                            OffsetShapeLog.AddLine(edgeB.ToString());
                            OffsetShapeLog.DrawEdge(edgeA, new Color(1, 1, 0, 0.8f));
                            OffsetShapeLog.DrawEdge(edgeB, new Color(1, 0, 1, 0.8f));
                            OffsetShapeLog.LabelNode(nodeAA);
                            OffsetShapeLog.LabelNode(nodeAB);
                            OffsetShapeLog.LabelNode(nodeBA);
                            OffsetShapeLog.LabelNode(nodeBB);
                            Node newStaticNodeA = new Node(nodeAA.position, nodeAA.height);
                            Node newStaticNodeB = new Node(nodeAB.position, nodeAB.height);
                            data.liveEdges.Remove(edgeA);
                            data.liveEdges.Remove(edgeB);
                            data.liveNodes.Remove(nodeAA);
                            data.liveNodes.Remove(nodeAB);

                            newStaticNodeA = data.AddStaticNode(newStaticNodeA);
                            newStaticNodeB = data.AddStaticNode(newStaticNodeB);
                            data.edges.Add(edgeA);
                            data.edges.Add(edgeB);

                            RetireFormingEdge(data, nodeAA, newStaticNodeA);
                            RetireFormingEdge(data, nodeAB, newStaticNodeB);

                            NewFormingEdge(data, newStaticNodeA, nodeAA);
                            NewFormingEdge(data, newStaticNodeB, nodeAB);

                            CalculateNodeDirAng(data, nodeAA);
                            CalculateNodeDirAng(data, nodeAB);

                            a             = 0;
                            b             = 0;
                            liveEdgeCount = data.liveEdges.Count;
                        }
                        //                        else
                        //                        {
                        //                            OffsetShapeLog.AddLine("Parallel Lines but!");
                        //                            OffsetShapeLog.AddLine(edgeA.ToString());
                        //                            OffsetShapeLog.AddLine(edgeB.ToString());
                        //                        }
                    }
                }
            }
        }
Exemple #14
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);
        }
Exemple #15
0
        /// <summary>
        /// Merge the two specified events
        /// </summary>
        /// <param name="eventA"></param>
        /// <param name="eventB"></param>
        /// <returns></returns>
        private MergedEvent MergeEvent(IEvent eventA, IEvent eventB)
        {
            OffsetShapeLog.AddLine(_events.Count);
            eventA.Log();
            eventB.Log();
            if (eventA.GetType() == typeof(MergedEvent))
            {
                if (eventA == eventB)
                {
                    return((MergedEvent)eventA);
                }
                MergedEvent mergeEvent = (MergedEvent)eventA;
                mergeEvent.Merge(eventB);
                _events.Remove(eventB);
                if (!_events.Contains(eventA))
                {
                    _events.Add(eventA);
                }
                OffsetShapeLog.AddLine("Event B merged into A");
                return(mergeEvent);
            }
            if (eventB.GetType() == typeof(MergedEvent))
            {
                if (eventA == eventB)
                {
                    return((MergedEvent)eventB);
                }
                MergedEvent mergeEvent = (MergedEvent)eventB;
                mergeEvent.Merge(eventA);
                _events.Remove(eventA);
                if (!_events.Contains(eventB))
                {
                    _events.Add(eventB);
                }
                OffsetShapeLog.AddLine("Event A merged into B");
                return(mergeEvent);
            }

            OffsetShapeLog.AddLine(_events.Count);
            //create the merge event and merge into it the two events
            MergedEvent mergedEvent = new MergedEvent();

            OffsetShapeLog.Add("merge percent ", mergedEvent.percent);
            mergedEvent.Merge(eventA);
            OffsetShapeLog.Add("merge percent ", mergedEvent.percent);
            mergedEvent.Merge(eventB);
            OffsetShapeLog.Add("merge percent ", mergedEvent.percent);
            eventA.Log();
            eventB.Log();
            mergedEvent.Log();
            _events.Remove(eventA);
            _events.Remove(eventB);
            if (_allEvents.Contains(eventA))
            {
                _allPoints.RemoveAt(_allEvents.IndexOf(eventA));
            }
            _allEvents.Remove(eventA);
            if (_allEvents.Contains(eventB))
            {
                _allPoints.RemoveAt(_allEvents.IndexOf(eventB));
            }
            _allEvents.Remove(eventB);

            OffsetShapeLog.AddLine("Current Events");
            foreach (IEvent evt in _events)
            {
                evt.Log();
            }

            OffsetShapeLog.AddLine(_events.Count);
            if (!_events.Contains(mergedEvent))
            {
                _events.Add(mergedEvent);
            }
            OffsetShapeLog.AddLine(_events.Count);
            return(mergedEvent);
        }
Exemple #16
0
        private IEvent CheckPoints(IEvent evnt)
        {
            Vector2 point      = evnt.point;
            int     pointCount = _allPoints.Count;

            if (pointCount == 0)
            {
                return(null);
            }

            //find if this event has nodes that are affected by another event and elect such an event for merging
            int eventCount = _events.Count;

            for (int e = 0; e < eventCount; e++)
            {
                IEvent aevnt = _events[e];
                if (aevnt == evnt)
                {
                    continue;
                }
                if (aevnt.ContainsNodes(evnt.affectedNodes))
                {
                    float percentDiff = Mathf.Abs(evnt.percent - aevnt.percent);
                    if (percentDiff > percentAccuracy)
                    {
                        continue;
                    }
                    float sqrMag = Vector2.SqrMagnitude(evnt.point - aevnt.point);
                    OffsetShapeLog.AddLine("SQR MAG ", sqrMag, _sqrPointAccuracy);
                    if (sqrMag < _sqrPointAccuracy)
                    {
                        return(aevnt);
                    }
                }
            }

            //find any events that are close to this one physically.
            //this could be any logged event
            //as the subject event exists in the main _event list
            float lowestMag      = Mathf.Infinity;
            int   lowestMagIndex = -1;

            for (int p = 0; p < pointCount; p++)
            {
                float sqrMag = Vector2.SqrMagnitude(point - _allPoints[p]);
                if (sqrMag < lowestMag)
                {
                    lowestMag      = sqrMag;
                    lowestMagIndex = p;
                }
            }
            if (lowestMagIndex != -1 && lowestMag < _sqrPointAccuracy)
            {
                float percentDiff = Mathf.Abs(evnt.percent - _allEvents[lowestMagIndex].percent);
                if (percentDiff <= percentAccuracy)
                {
                    return(_allEvents[lowestMagIndex]);
                }
            }

            return(null);
        }
Exemple #17
0
        public void AddEvent(IEvent newEvent)
        {
            OffsetShapeLog.AddLine("AddEvent", newEvent);
            if (newEvent == null)
            {
                return;
            }
//            OffsetShapeLog.AddLine(newEvent.percent);
//            OffsetShapeLog.AddLine(newEvent.percent > 1.0f - Mathf.Epsilon);
//            if (newEvent.percent > 0.99999f) return; //percent accuracy...
            OffsetShapeLog.AddLine("AddEvent");
            OffsetShapeLog.AddLine("current number of events: " + _events.Count);
            bool lowerPercent = _percent > newEvent.percent;
            bool closePercent = Mathf.Abs(_percent - newEvent.percent) < percentAccuracy;

            OffsetShapeLog.AddLine(lowerPercent + " " + closePercent + " " + _percent + " " + newEvent.percent);

            if (!lowerPercent && !closePercent)//if this event is later than the currently logged events, ignore
            {
                _discardedEvents.Add(newEvent);
                _allEvents.Add(newEvent);
                _allPoints.Add(newEvent.point);
                return;
            }
            if (lowerPercent && !closePercent)//if this event is sooner then clear the list and log these earlier events
            {
                _discardedEvents.AddRange(_events);
                _events.Clear();
            }

            Vector2 point  = newEvent.point;
            IEvent  pEvent = null;

            if (closePercent)
            {
                pEvent = CheckPoints(newEvent);
            }
            if (pEvent != null)
            {
                OffsetShapeLog.AddLine("Merge existing event");
                pEvent.Log();
                OffsetShapeLog.AddLine("Merge existing event");
                OffsetShapeLog.AddLine(pEvent);
                OffsetShapeLog.AddLine("With new event");
                OffsetShapeLog.AddLine(newEvent);
                OffsetShapeLog.AddLine("Merged Outcome");
                IEvent mergedEvent = MergeEvent(pEvent, newEvent);
                OffsetShapeLog.AddLine(mergedEvent);
                OffsetShapeLog.AddLine("percent set ", _percent, mergedEvent.percent);
                _percent = mergedEvent.percent;
                _allPoints.Add(point);
                _allEvents.Add(mergedEvent);

                int discardedListCount = _discardedEvents.Count;
                for (int a = 0; a < discardedListCount; a++)
                {
                    IEvent e = _discardedEvents[a];
                    if (mergedEvent.ContainsNodes(e.affectedNodes) && !_events.Contains(e))
                    {
                        float sqrDist = Vector2.SqrMagnitude(e.point - mergedEvent.point);
                        if (sqrDist < _sqrPointAccuracy)
                        {
                            _events.Add(e);
                            mergedEvent.affectedNodes.AddRange(e.affectedNodes);
                            a = 0;//restart to pick up other straglers
                        }
                    }
                }
            }
            else
            {
                OffsetShapeLog.AddLine("Add new event");
                newEvent.Log();
                _events.Add(newEvent);
                _allPoints.Add(point);
                _allEvents.Add(newEvent);
                OffsetShapeLog.AddLine("percent set ", _percent, newEvent.percent);
                _percent = Mathf.Min(_percent, newEvent.percent);
            }
        }
        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);
            }
        }
        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);
        }
Exemple #20
0
 public override void Log()
 {
     OffsetShapeLog.AddLine("Merge event ");
     base.Log();
 }
Exemple #21
0
        private void Merge(SplitEvent e)
        {
//            bool proximity = Vector2.Distance(e.point, point) < EventLog._pointAccuracy;
            OffsetShapeLog.AddLine("merging split event", e);

//            if (proximity)
//            {
//                splitEvents.Add(e);
//                int splitCount = splitEvents.Count;
//                for(int s = 0; s < splitCount; s++)
//                {
//                    if(Vector2.Distance(splitEvents[s].point, point) < EventLog._pointAccuracy)
//                    {
//                        if (!mergeNodes.Contains(splitEvents[s].node))
//                            mergeNodes.Add(splitEvents[s].node);
////                        if (!mergeNodes.Contains(splitEvents[s].edge.nodeA))
////                            mergeNodes.Add(splitEvents[s].edge.nodeA);
////                        if (!mergeNodes.Contains(splitEvents[s].edge.nodeB))
////                            mergeNodes.Add(splitEvents[s].edge.nodeB);
//                    }
//                }
//                point = e.point;
//                percent = Mathf.Min(percent, e.percent);
//            }
//            else
//            {
            int  splitCount = splitEvents.Count;
            bool addSplit   = true;

            for (int s = 0; s < splitCount; s++)
            {
                SplitEvent os = splitEvents[s];
                OffsetShapeLog.AddLine("checking against split event node", os.node);
                if (os.node == e.node)
                {
                    addSplit = false;
                    OffsetShapeLog.AddLine("new merged split conflicts with internal splits - disolving into collapsing node");
                    splitEvents.RemoveAt(s);

                    if (!mergeNodes.Contains(e.node))
                    {
                        mergeNodes.Add(e.node);
                    }
                    if (!mergeNodes.Contains(os.node))
                    {
                        mergeNodes.Add(os.node);
                    }

                    if (e.edge.nodeA == os.edge.nodeA || e.edge.nodeA == os.edge.nodeB && !mergeNodes.Contains(e.edge.nodeA))
                    {
                        mergeNodes.Add(e.edge.nodeA);
                    }

                    if (e.edge.nodeB == os.edge.nodeA || e.edge.nodeB == os.edge.nodeB && !mergeNodes.Contains(e.edge.nodeB))
                    {
                        mergeNodes.Add(e.edge.nodeB);
                    }

                    point   = e.point;
                    percent = Mathf.Min(percent, e.percent);
                    s--;
                    splitCount--;
                }
            }

            if (!addSplit)
            {
                return;
            }
            point = e.point;
            splitEvents.Add(e);
            percent = Mathf.Min(percent, e.percent);
//            }
        }
        public void OffsetPoly(float direction)
        {
            if (!_init)
            {
                return;
            }

            float amount        = _shape.shrinkLength * SHINK_MULTIPLIER * Mathf.Sign(direction);
            int   liveEdgeCount = _shape.liveEdges.Count;
            int   liveNodeCount = _shape.liveNodes.Count;

            if (liveNodeCount == 0 || liveEdgeCount == 0)//nothing more to calculate
            {
                OffsetShapeLog.AddLine("Skeleton Complete");
                _complete = true;
                if (OnCompleteEvent != null)
                {
                    OnCompleteEvent();
                }
                return;
            }

            bool  earlyTermination = false;
            float directionSign    = Mathf.Sign(direction);
            float maxOffsetSign    = Mathf.Sign(maxOffset);
            float useMaxOffset     = (directionSign == maxOffsetSign) ? maxOffset : -maxOffset;

            for (int l = 0; l < liveNodeCount; l++)
            {
                Node node = _shape.liveNodes[l];
                //                if(l==0)Debug.Log(node.height+" "+amount+" "+useMaxOffset);
                if (useMaxOffset > 0)
                {
                    if (node.height + amount >= useMaxOffset)//terminate nodes that have reached a defined maximum
                    {
                        amount           = useMaxOffset - node.height;
                        earlyTermination = true;
                    }
                }
                else if (useMaxOffset < 0)
                {
                    if (node.height + amount <= useMaxOffset)//terminate nodes that have reached a defined maximum
                    {
                        amount           = useMaxOffset - node.height;
                        earlyTermination = true;
                    }
                }
            }

            float maxMovement = 0;

            liveNodeCount = _shape.liveNodes.Count;
            float[] angleNodeMovements = new float[liveNodeCount];
            for (int l = 0; l < _shape.liveNodes.Count; l++)
            {
//                Debug.Log(l);
                Node node = _shape.liveNodes[l];//TODO out of range error
                angleNodeMovements[l] = amount / Mathf.Sin(node.angle * 0.5f * Mathf.Deg2Rad);
                if (Mathf.Abs(angleNodeMovements[l]) > Mathf.Abs(maxMovement) && Mathf.Abs(angleNodeMovements[l]) > 0)
                {
                    maxMovement = angleNodeMovements[l];

                    if (node.angle > 350)
                    {
                        Edge[] edges = Utils.GetABEdge(shape, node);
                        if (edges[0] == null || edges[1] == null)
                        {
                            continue;
                        }
                        float shortestLength = (edges[0].length + edges[1].length) * 0.5f;
                        //                        Debug.Log(Mathf.Abs(shortestLength / amount));
                        maxMovement /= Mathf.Abs(shortestLength / amount);
                    }

                    //                    Debug.Log(node.id+" "+node.angle);
                }
            }

            float angleScale = amount / maxMovement;

            if (angleScale == Mathf.Infinity)
            {
                angleScale = 1;
            }
            OffsetShapeLog.AddLine(angleScale);

            for (int l = 0; l < _shape.liveNodes.Count; l++)
            {
                Node node = _shape.liveNodes[l];
                if (node.direction.magnitude < Mathf.Epsilon)//directionless node
                {
                    _shape.liveNodes.Remove(node);
                    liveNodeCount--;
                    l--;
                    continue;
                }
                node.MoveForward(angleNodeMovements[l] * angleScale, amount * angleScale);
            }

            Vector2[] edgeMovements = new Vector2[liveEdgeCount];
            if (calculateInteractions)
            {
                //Event log will collect all events and sort them for us for use once we're happy everything has been processed
                EventLog eventLog = new EventLog();
                EventLog.pointAccuracy   = pointAccuracy;
                EventLog.percentAccuracy = percentAccuracy;

                //flip events
                for (int e = 0; e < liveEdgeCount; e++)//TODO check laters
                {
                    Edge edge = _shape.liveEdges[e];
                    edge.DebugDraw(Color.cyan);
                    edge.UpdateValues();//update the edge values to reflect the new node positions
                    Node nodeA = edge.nodeA;
                    Node nodeB = edge.nodeB;
                    edgeMovements[e] = (nodeA.movement + nodeB.movement) * 0.5f;
                    Vector2 intersectionPoint;
                    if (Utils.Intersects(edge.nodeA.previousPosition, edge.nodeA.position, edge.nodeB.previousPosition, edge.nodeB.position, out intersectionPoint))
                    {
                        eventLog.AddEvent(eventLog.CreateFlipEvent(edge, intersectionPoint));
                    }
                }

                //

                //split events
                for (int n = 0; n < _shape.liveNodeCount; n++)
                {
                    Node node   = _shape.liveNodes[n];
                    int  nodeID = node.id;

                    //find connecting nodes of splitting node
                    Node nodeA = null, nodeB = null;
                    for (int e = 0; e < liveEdgeCount; e++)
                    {
                        Edge edge = _shape.liveEdges[e];
                        if (edge.Contains(node))
                        {
                            if (edge.nodeA == node)
                            {
                                nodeB = edge.nodeB;
                            }
                            if (edge.nodeB == node)
                            {
                                nodeA = edge.nodeA;
                            }
                        }
                    }


                    for (int e = 0; e < liveEdgeCount; e++)
                    {
                        Edge edge = _shape.liveEdges[e];
                        if (edge.Contains(node))
                        {
                            continue;                     //nodes can't split their own edges - carry on!
                        }
                        if (nodeA != null && edge.Contains(nodeA))
                        {
                            continue;                                       //nodes can't split adjacent edges - carry on!
                        }
                        if (nodeB != null && edge.Contains(nodeB))
                        {
                            continue;                          //nodes can't split adjacent edges - carry on!
                        }
                        if (currentSplits.ContainsKey(nodeID)) //previous splits should never intersect - ingore
                        {
                            if (currentSplits[nodeID].Contains(edge.nodeA.id))
                            {
                                continue;
                            }
                            if (currentSplits[nodeID].Contains(edge.nodeB.id))
                            {
                                continue;
                            }
                        }

                        //                        if(!isPartOfShape(node, edge)) continue;

                        Vector2 edgeMovement = edgeMovements[e];
                        Vector2 nodeMovement = node.direction * node.distance - edgeMovement; //simulate collision by moving the point by the vectors of both the point and the edge,
                        //note: collisions are simpler if only one body is moving so we're going to add the edge vector onto the point vector, making the edge remain stationary
                        Vector2 calculationPoint = node.previousPosition + nodeMovement;      //calculate the point vector by adding the edge one to it
                        Vector2 edgePosA         = edge.nodeA.previousPosition;
                        Vector2 edgePosB         = edge.nodeB.previousPosition;
//                        float intersectionalDot = Vector2.Dot(edgeMovement.normalized, node.direction.normalized);

                        //                        OffsetShapeLog.DrawLine(node.previousPosition, calculationPoint,new Color(1,0,0,0.4f));
                        //                        OffsetShapeLog.DrawLine(edgePosA, edgePosB, new Color(1, 0, 1, 0.4f));

                        Vector2 intersectionPoint;
                        float   percent    = 0;
                        bool    intersects = false;
                        //                        if (intersectionalDot < -10.75f)
                        //                        {
                        //                            Debug.DrawLine(Utils.ToV3(node.previousPosition), Utils.ToV3(calculationPoint), Color.red);
                        //                            intersects = Utils.Intersects(node.previousPosition, calculationPoint, edgePosA, edgePosB, out intersectionPoint);
                        //                            if (intersects)
                        //                            {
                        //                                Debug.DrawLine(Utils.ToV3(calculationPoint), Utils.ToV3(calculationPoint) + Vector3.up * 5, Color.magenta);
                        //                            }
                        //                            Vector2 a = node.previousPosition;
                        //                            Vector2 b = node.position;
                        //                            float movementMag = nodeMovement.magnitude;
                        //                            float intersectionMag = (intersectionPoint - a).magnitude;
                        //                            percent = intersectionMag / movementMag;
                        //                            intersectionPoint = Vector2.Lerp(a, b, percent);//translate the point to the real movement point
                        //                        }
                        //                        else
                        //                        {
                        bool dbi = false;//node.id == 14;
                        intersects       = Utils.SweepIntersects2(edge.nodeA.previousPosition, edge.nodeB.previousPosition, edge.nodeA.position, edge.nodeB.position, node.previousPosition, node.position, out intersectionPoint, out percent, 0.1f, dbi);
                        calculationPoint = node.position;
                        //                        }
                        //                        if(Utils.Intersects(node.previousPosition, calculationPoint, edgePosA, edgePosB, out intersectionPoint))
                        //                        if (Utils.SweepIntersects(edge.nodeA.previousPosition , edge.nodeB.previousPosition, edge.nodeA.position, edge.nodeB.position, node.previousPosition, node.position, out intersectionPoint, out percent))
                        if (intersects)
                        {
                            for (int be = 0; be < shape.baseEdges.Count; be++)
                            {
                                Edge baseEdge = shape.edges[be];
                                if (Utils.FastLineIntersection(node.previousPosition, node.position, baseEdge.positionA, baseEdge.positionB))
                                {
                                    intersects = false;
                                }
                                if (Utils.FastLineIntersection(edge.nodeA.position, edge.nodeB.position, baseEdge.positionA, baseEdge.positionB))
                                {
                                    intersects = false;
                                }
                            }
                        }
                        if (intersects)
                        {
                            OffsetShapeLog.AddLine("Split event detected");
                            SplitEvent splitEvent = new SplitEvent();
                            splitEvent.node = node;
                            splitEvent.edge = edge;
                            OffsetShapeLog.AddLine("node " + node.id);
                            OffsetShapeLog.AddLine("splits edge " + edge.ToString());

                            OffsetShapeLog.DrawLine(node.previousPosition, calculationPoint, Color.red);
                            OffsetShapeLog.DrawLine(edgePosA, edgePosB, Color.magenta);

                            //                            Vector2 a = node.previousPosition;
                            //                            Vector2 b = node.position;
                            //                            Vector2 x = intersectionPoint;//intersectionInfo.Point0;

                            //                            float movementMag = nodeMovement.magnitude;
                            //                            float intersectionMag = (x - a).magnitude;
                            //                            float percent = intersectionMag / movementMag;
                            OffsetShapeLog.AddLine("at percent " + percent);
                            //                            Vector2 actualIntersectionPoint = Vector2.Lerp(a, b, percent);//translate the point to the real movement point

                            float newLengthA = (intersectionPoint - edge.positionA).magnitude;
                            float newLengthB = (intersectionPoint - edge.positionB).magnitude;
                            OffsetShapeLog.AddLine("line a length ", newLengthA);
                            OffsetShapeLog.AddLine("line b length ", newLengthB);

                            SplitEvent sEvent = eventLog.CreateSplitEvent(_shape, node, edge, intersectionPoint, percent, calculationPoint);
                            if (sEvent == null)
                            {
                                continue;
                            }
                            if (newLengthA > pointAccuracy && newLengthB > pointAccuracy)
                            {
                                eventLog.AddEvent(sEvent);//can split - split point not close to either edge nodes
                            }
                            else
                            {
                                Node[] nodes = null;
                                if (newLengthA < pointAccuracy && newLengthB < pointAccuracy)
                                {
                                    nodes = new[] { node, edge.nodeA, edge.nodeB }
                                }
                                ;                                                  //point will split the edge into two edges that can't exist - collapse all nodes
                                else if (newLengthA < pointAccuracy)
                                {
                                    nodes = new[] { node, edge.nodeA }
                                }
                                ;                                      //split point close to node a - collapse split node into edge.nodea
                                else if (newLengthB < pointAccuracy)
                                {
                                    nodes = new[] { node, edge.nodeB }
                                }
                                ;                                      //split point close to node b - collapse split node into edge.nodeb
                                if (nodes != null)
                                {
                                    MergedEvent mEvent = eventLog.CreateMergeEvent(nodes, intersectionPoint, percent, calculationPoint);
                                    mEvent.Merge(sEvent);
                                    eventLog.AddEvent(mEvent);
                                }
                            }
                        }
                    }
                }

                currentSplits.Clear();
                int eventCount = eventLog.count;
                OffsetShapeLog.AddLine("event count: ", eventCount);
                if (eventCount > 0)
                {
                    float percent = eventLog.percent;
                    earlyTermination = false;
                    foreach (Node node in _shape.liveNodes)
                    {
                        node.MoveBack(percent);//move all nodes back to the position of the event
                    }
                    foreach (Edge edge in _shape.liveEdges)
                    {
                        edge.UpdateValues();//update all edges to reflect this
                    }
                    foreach (Node node in _shape.liveNodes)
                    {
                        if (_shape.formingEdges.ContainsKey(node))
                        {
                            _shape.formingEdges[node].UpdateValues();
                        }
                    }
                    for (int e = 0; e < eventCount; e++)
                    {
                        IEvent sevent = eventLog[e];
                        sevent.DrawDebug();
                        OffsetShapeLog.AddLine(string.Format("Event {0} of type {4} at {1} percent and {2},{3}", e, sevent.percent, sevent.point.x, sevent.point.y, sevent.GetType()));
                        switch (sevent.GetType().ToString())
                        {
                        case "BuildR2.ShapeOffset.FlipEvent":
                            FlipEvent fEvent = (FlipEvent)sevent;
                            OffsetShapeLog.AddLine(fEvent.ToString());
                            if (OnFlipEvent != null)
                            {
                                OnFlipEvent(fEvent);
                            }
                            //                            CollapseEdge(fEvent.edge, fEvent.point, fEvent.height);
                            break;

                        case "BuildR2.ShapeOffset.SplitEvent":
                            SplitEvent sEvent = (SplitEvent)sevent;
                            OffsetShapeLog.AddLine(sevent.ToString());
                            if (OnSplitEvent != null)
                            {
                                OnSplitEvent(sEvent);
                            }
                            //                            SplitEdge(sEvent);
                            break;

                        case "BuildR2.ShapeOffset.MergedEvent":
                            MergedEvent mEvent = (MergedEvent)sevent;
                            OffsetShapeLog.AddLine(mEvent.ToString());
                            if (OnMergedEvent != null)
                            {
                                OnMergedEvent(mEvent);
                            }
                            //                            MergeEvent(mEvent);
                            break;
                        }
                    }
                }
                else
                {
                    if (!earlyTermination)
                    {
                        float percent = 1.0f - percentAccuracy;
                        earlyTermination = false;
                        foreach (Node node in _shape.liveNodes)
                        {
                            node.MoveBack(percent);//move all nodes back to the position of the event
                        }
                        foreach (Edge edge in _shape.liveEdges)
                        {
                            edge.UpdateValues();//update all edges to reflect this
                        }
                    }
                    foreach (Node node in _shape.liveNodes)
                    {
                        if (_shape.formingEdges.ContainsKey(node))
                        {
                            _shape.formingEdges[node].UpdateValues();
                        }
                    }
                }
            }

            if (earlyTermination)
            {
                _complete = true;
                _shape.TerminateAllNodes();
                if (OnCompleteEvent != null)
                {
                    OnCompleteEvent();
                }
                return;
            }
            else
            {
                //recalculate node directions
                foreach (Node node in _shape.liveNodes)
                {
                    Utils.CalculateNodeDirAng(_shape, node);
                }
            }
        }
        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);
        }
        public void Init(Vector2[] points, bool[] gables = null)
        {
            OffsetShapeLog.AddLine("Init");

            if (ShapeIntersection(points))
            {
                _error = true;
                OffsetShapeLog.AddLine("Shape intersection");
                if (OnErrorEvent != null)
                {
                    OnErrorEvent("Provided shape interescts with itself.");
                }
                return;
            }

            _shape = new Shape(points);
            int pointCount = points.Length;

            if (pointCount == 0)
            {
                Debug.LogError("no points sent!");
                return;
            }

            //bounds used to ensure no crazy values created
            _bounds = new Rect(points[0].x, points[0].y, 0, 0);

            //Initialise the data points
            for (int p = 0; p < pointCount; p++)
            {
                Vector2 point = points[p];
                if (point.x < _bounds.xMin)
                {
                    _bounds.xMin = point.x;
                }
                if (point.x > _bounds.xMax)
                {
                    _bounds.xMax = point.x;
                }
                if (point.y < _bounds.yMin)
                {
                    _bounds.yMin = point.y;
                }
                if (point.y > _bounds.yMax)
                {
                    _bounds.yMax = point.y;
                }

                Node outer = new Node(points[p], 0);//create outer node points that outline the shape
                outer.startNode = true;
                _shape.AddStaticNode(outer);

                Node live = new Node(points[p], 0);//create live inner nodes that will sweep inwards
                _shape.AddLiveNode(live);
                Utils.NewFormingEdge(_shape, outer, live);
            }

//            float boundsMargin = BOUNDS_MARGIN;
            _bounds.xMin -= BOUNDS_MARGIN;
            _bounds.xMax += BOUNDS_MARGIN;
            _bounds.yMin -= BOUNDS_MARGIN;
            _bounds.yMax += BOUNDS_MARGIN;

            float smallestLength = Mathf.Infinity;

            //create edges from previous points
            //calculate node directions
            for (int p = 0; p < pointCount; p++)
            {
                int indexA = p;
                int indexX = (p + 1) % pointCount;              //next index
                int indexY = (p - 1 + pointCount) % pointCount; //previous

                Node a         = _shape.StaticNode(indexA);
                Node x         = _shape.StaticNode(indexX);
                Node y         = _shape.StaticNode(indexY);
                Node la        = _shape.liveNodes[indexA];
                Node lb        = _shape.liveNodes[indexX];
                Edge outerEdge = new Edge(a, x);//outer edge - will not move
                _shape.baseEdges.Add(outerEdge);
                _shape.edges.Add(outerEdge);
                if (outerEdge.sqrMagnitude < smallestLength)
                {
                    smallestLength = outerEdge.sqrMagnitude;
                }

//                if (gables != null)
//                {
//                    bool leftIsGabled = gables[indexY];
//                    bool rightIsGabled = gables[indexA];
//
//                    if (!leftIsGabled && !rightIsGabled)
//                    {
//                        Utils.CalculateNodeDirAng(la, x, y);//assign the direction of the node for shrinkage
//                        Edge liveEdge = new Edge(la, lb);//create the live edge that will be sweeping inwards
//                        _shape.liveEdges.Add(liveEdge);
//                    }
//                    else if (leftIsGabled && !rightIsGabled)
//                    {
//                        Utils.CalculateNodeDirAng(la, x, y);//assign the direction of the node for shrinkage
//                        Node l = _shape.liveNodes[indexX];
//                        Edge liveEdge = new Edge(la, lb);//create the live edge that will be sweeping inwards
//                        _shape.liveEdges.Add(liveEdge);
//                    }
//                }
//                else
//                {
                Utils.CalculateNodeDirAng(la, x, y); //assign the direction of the node for shrinkage
                Edge liveEdge = new Edge(la, lb);    //create the live edge that will be sweeping inwards
                _shape.liveEdges.Add(liveEdge);
//                }

                //                a.startTangent = ((a.position - y.position).normalized + (x.position - a.position).normalized).normalized;
            }
            _shape.shrinkLength = Mathf.Sqrt(smallestLength);
            OffsetShapeLog.AddLine("shrink length " + _shape.shrinkLength);

            _complete = false;
            _error    = false;
            _init     = true;
        }