Example #1
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);
        }
Example #2
0
        private void OnFlip(FlipEvent fEvent)
        {
            fEvent.DrawDebug();

            List <Node> nodes = new List <Node>();

            nodes.Add(fEvent.edge.nodeA);
            nodes.Add(fEvent.edge.nodeB);
            CollapseNodes(nodes, fEvent.point, fEvent.height, fEvent);
            //CollapseEdge(fEvent.edge, fEvent.point, fEvent.height);
        }
Example #3
0
 private void Merge(FlipEvent e)
 {
     point = e.point;
     if (!mergeNodes.Contains(e.edge.nodeA))
     {
         mergeNodes.Add(e.edge.nodeA);
     }
     if (!mergeNodes.Contains(e.edge.nodeB))
     {
         mergeNodes.Add(e.edge.nodeB);
     }
     percent = Mathf.Min(percent, e.percent);
 }
Example #4
0
 private void OnFlip(FlipEvent fEvent)
 {
     CollapseEdge(fEvent.edge, fEvent.point, fEvent.height);
 }
Example #5
0
        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);
                }
            }
        }