Пример #1
0
    // Returns true if the specified convex vertex is an ear tip
    private static bool IsEarTip(Vector3[] a_rMeshVertices, int a_iEarTipConvexVertexIndex, CircularLinkedList <int> a_rContourVertexIndexesList, LinkedList <int> a_rReflexVertexIndexesList)
    {
        CircularLinkedListNode <int> rContourVertexNode = a_rContourVertexIndexesList.Find(a_iEarTipConvexVertexIndex);

        int iPreviousContourVertexIndex = rContourVertexNode.Previous.Value;
        int iNextContourVertexIndex     = rContourVertexNode.Next.Value;

        // Retrieve previous (i-1) / current (i) / next (i+1) vertices to form the triangle < Vi-1, Vi, Vi+1 >
        Vector3 f3ConvexContourVertex   = a_rMeshVertices[a_iEarTipConvexVertexIndex];
        Vector3 f3PreviousContourVertex = a_rMeshVertices[iPreviousContourVertexIndex];
        Vector3 f3NextContourVertex     = a_rMeshVertices[iNextContourVertexIndex];

        // Look for an inner point into the triangle formed by the 3 vertices
        // Only need to look over the reflex vertices.
        for (LinkedListNode <int> rReflexIndexNode = a_rReflexVertexIndexesList.First; rReflexIndexNode != null; rReflexIndexNode = rReflexIndexNode.Next)
        {
            // Retrieve the reflex vertex
            int iReflexContourVertexIndex = rReflexIndexNode.Value;

            // Is the point inside the triangle?
            // (Exclude the triangle points themselves)
            Vector3 f3ReflexContourVertex = a_rMeshVertices[iReflexContourVertexIndex];
            if (f3ReflexContourVertex != f3PreviousContourVertex && f3ReflexContourVertex != f3ConvexContourVertex && f3ReflexContourVertex != f3NextContourVertex)
            {
                if (Uni2DMathUtils.IsPointInsideTriangle(f3PreviousContourVertex, f3ConvexContourVertex, f3NextContourVertex, f3ReflexContourVertex) == true)
                {
                    // Point is inside triangle: not an ear tip
                    return(false);
                }
            }
        }

        // No point inside the triangle: ear tip found!
        return(true);
    }
Пример #2
0
    // Returns true if a 2D ray intersects a 2D segment defined by a_f2SegmentStart and a_f2SegmentEnd
    // The T factor is returned into a_fRayHitT var
    public static bool Raycast2DSegment(Ray a_rRay, Vector2 a_f2SegmentStart, Vector2 a_f2SegmentEnd, out float a_fRayHitDistance)
    {
        // Vector orthogonal to ray direction vector
        Vector2 f2PerpRay = Uni2DMathUtils.PerpVector2(a_rRay.direction);

        // Vector orthogonal to segment vector
        Vector2 f2PerpSegment = Uni2DMathUtils.PerpVector2(a_f2SegmentEnd - a_f2SegmentStart);

        // Dot product between the 2 previously created vector
        float fDotPerpSegmentRayDirection = Vector2.Dot(f2PerpSegment, a_rRay.direction);

        // Ray( T ) default value...
        a_fRayHitDistance = 0.0f;

        // Vector3->Vector2
        Vector2 f2RayOrigin = new Vector2(a_rRay.origin.x, a_rRay.origin.y);

        // If not parallel...
        if (Mathf.Approximately(fDotPerpSegmentRayDirection, 0.0f) == false)
        {
            float fS = Vector2.Dot(f2PerpSegment, a_f2SegmentStart - f2RayOrigin) / fDotPerpSegmentRayDirection;
            float fT = Vector2.Dot(f2PerpRay, a_f2SegmentStart - f2RayOrigin) / fDotPerpSegmentRayDirection;

            // If belongs to segment ( 0 <= T <= 1 ) and in ray forward direction ( 0 <= S )
            if (0.0f <= fT && fT <= 1.0f && 0.0f <= fS)
            {
                a_fRayHitDistance = fS;
                return(true);
            }
            return(false);
        }
        return(false);
    }
Пример #3
0
    private float ComputeDistanceToBone(Uni2DSmoothBindingBone a_rBone, Vector3 a_f3VertexCoords)
    {
        Vector3 f3LocalRootPosition = this.transform.InverseTransformPoint(a_rBone.transform.position);
        float   fMinDistance        = Vector3.Distance(f3LocalRootPosition, a_f3VertexCoords);

        foreach (Uni2DSmoothBindingBone rBoneChild in a_rBone.Children)
        {
            float fDistance = Uni2DMathUtils.DistancePointToLineSegment(a_f3VertexCoords, f3LocalRootPosition, this.transform.InverseTransformPoint(rBoneChild.transform.position));
            fMinDistance = Mathf.Min(fMinDistance, fDistance);
        }

        return(fMinDistance);
    }
Пример #4
0
    // Finds a pair of inner contour vertex / outer contour vertex that are mutually visible
    public static Contour InsertInnerContourIntoOuterContour(Contour a_rOuterContour, Contour a_rInnerContour)
    {
        // Look for the inner vertex of maximum x-value
        Vector2 f2InnerContourVertexMax = Vector2.one * int.MinValue;
        CircularLinkedListNode <Vector2> rMutualVisibleInnerContourVertexNode = null;

        CircularLinkedList <Vector2>     rInnerContourVertexList = a_rInnerContour.Vertices;
        CircularLinkedListNode <Vector2> rInnerContourVertexNode = rInnerContourVertexList.First;

        do
        {
            // x-value
            Vector2 f2InnerContourVertex = rInnerContourVertexNode.Value;

            // New max x found
            if (f2InnerContourVertexMax.x < f2InnerContourVertex.x)
            {
                f2InnerContourVertexMax = f2InnerContourVertex;
                rMutualVisibleInnerContourVertexNode = rInnerContourVertexNode;
            }

            // Go to next vertex
            rInnerContourVertexNode = rInnerContourVertexNode.Next;
        }while(rInnerContourVertexNode != rInnerContourVertexList.First);

        // Visibility ray
        Ray     oInnerVertexVisibilityRay = new Ray(f2InnerContourVertexMax, Vector3.right);
        float   fClosestDistance          = int.MaxValue;
        Vector2 f2ClosestOuterEdgeStart   = Vector2.zero;
        Vector2 f2ClosestOuterEdgeEnd     = Vector2.zero;

        Contour rOuterCutContour = new Contour(a_rOuterContour.Region);

        rOuterCutContour.AddLast(a_rOuterContour.Vertices);

        CircularLinkedList <Vector2>     rOuterCutContourVertexList   = rOuterCutContour.Vertices;
        CircularLinkedListNode <Vector2> rOuterContourVertexEdgeStart = null;

        // Raycast from the inner contour vertex to every edge
        CircularLinkedListNode <Vector2> rOuterContourVertexNode = rOuterCutContourVertexList.First;

        do
        {
            // Construct outer edge from current and next outer contour vertices
            Vector2 f2OuterEdgeStart = rOuterContourVertexNode.Value;
            Vector2 f2OuterEdgeEnd   = rOuterContourVertexNode.Next.Value;
            Vector2 f2OuterEdge      = f2OuterEdgeEnd - f2OuterEdgeStart;

            // Orthogonal vector to edge (pointing to polygon interior)
            Vector2 f2OuterEdgeNormal = Uni2DMathUtils.PerpVector2(f2OuterEdge);

            // Vector from edge start to inner vertex
            Vector2 f2OuterEdgeStartToInnerVertex = f2InnerContourVertexMax - f2OuterEdgeStart;

            // If the inner vertex is on the left of the edge (interior),
            // test if there's any intersection
            if (Vector2.Dot(f2OuterEdgeStartToInnerVertex, f2OuterEdgeNormal) >= 0.0f)
            {
                float fDistanceT;

                // If visibility intersects outer edge...
                if (Uni2DMathUtils.Raycast2DSegment(oInnerVertexVisibilityRay, f2OuterEdgeStart, f2OuterEdgeEnd, out fDistanceT) == true)
                {
                    // Is it the closest intersection we found?
                    if (fClosestDistance > fDistanceT)
                    {
                        fClosestDistance             = fDistanceT;
                        rOuterContourVertexEdgeStart = rOuterContourVertexNode;

                        f2ClosestOuterEdgeStart = f2OuterEdgeStart;
                        f2ClosestOuterEdgeEnd   = f2OuterEdgeEnd;
                    }
                }
            }

            // Go to next edge
            rOuterContourVertexNode = rOuterContourVertexNode.Next;
        }while(rOuterContourVertexNode != rOuterCutContourVertexList.First);

        // Take the vertex of maximum x-value from the closest intersected edge
        Vector2 f2ClosestVisibleOuterContourVertex;
        CircularLinkedListNode <Vector2> rMutualVisibleOuterContourVertexNode;

        if (f2ClosestOuterEdgeStart.x < f2ClosestOuterEdgeEnd.x)
        {
            f2ClosestVisibleOuterContourVertex   = f2ClosestOuterEdgeEnd;
            rMutualVisibleOuterContourVertexNode = rOuterContourVertexEdgeStart.Next;
        }
        else
        {
            f2ClosestVisibleOuterContourVertex   = f2ClosestOuterEdgeStart;
            rMutualVisibleOuterContourVertexNode = rOuterContourVertexEdgeStart;
        }

        // Looking for points inside the triangle defined by inner vertex, intersection point an closest outer vertex
        // If a point is inside this triangle, at least one is a reflex vertex
        // The closest reflex vertex which minimises the angle this-vertex/inner vertex/intersection vertex
        // would be choosen as the mutual visible vertex
        Vector3 f3IntersectionPoint = oInnerVertexVisibilityRay.GetPoint(fClosestDistance);
        Vector2 f2InnerContourVertexToIntersectionPoint           = new Vector2(f3IntersectionPoint.x, f3IntersectionPoint.y) - f2InnerContourVertexMax;
        Vector2 f2NormalizedInnerContourVertexToIntersectionPoint = f2InnerContourVertexToIntersectionPoint.normalized;

        float fMaxDotAngle = float.MinValue;
        float fMinDistance = float.MaxValue;

        rOuterContourVertexNode = rOuterCutContourVertexList.First;
        do
        {
            Vector2 f2OuterContourVertex = rOuterContourVertexNode.Value;

            // if vertex not part of triangle
            if (f2OuterContourVertex != f2ClosestVisibleOuterContourVertex)
            {
                // if vertex is inside triangle...
                if (Uni2DMathUtils.IsPointInsideTriangle(f2InnerContourVertexMax, f3IntersectionPoint, f2ClosestVisibleOuterContourVertex, f2OuterContourVertex) == true)
                {
                    // if vertex is reflex
                    Vector2 f2PreviousOuterContourVertex = rOuterContourVertexNode.Previous.Value;
                    Vector2 f2NextOuterContourVertex     = rOuterContourVertexNode.Next.Value;

                    if (IsReflexVertex(f2OuterContourVertex, f2PreviousOuterContourVertex, f2NextOuterContourVertex) == true)
                    {
                        // Use dot product as distance
                        Vector2 f2InnerContourVertexToReflexVertex = f2OuterContourVertex - f2InnerContourVertexMax;

                        // INFO: f2NormalizedInnerContourVertexToIntersectionPoint == Vector3.right (if everything is right)
                        float fDistance = Vector2.Dot(f2NormalizedInnerContourVertexToIntersectionPoint, f2InnerContourVertexToReflexVertex);
                        float fDotAngle = Vector2.Dot(f2NormalizedInnerContourVertexToIntersectionPoint, f2InnerContourVertexToReflexVertex.normalized);

                        // New mutual visible vertex if angle smaller (e.g. dot angle larger) than min or equal and closer
                        if (fDotAngle > fMaxDotAngle || (fDotAngle == fMaxDotAngle && fDistance < fMinDistance))
                        {
                            fMaxDotAngle = fDotAngle;
                            fMinDistance = fDistance;
                            rMutualVisibleOuterContourVertexNode = rOuterContourVertexNode;
                        }
                    }
                }
            }

            // Go to next vertex
            rOuterContourVertexNode = rOuterContourVertexNode.Next;
        }while(rOuterContourVertexNode != rOuterCutContourVertexList.First);

        // Insert now the cut into the polygon
        // The cut starts from the outer contour mutual visible vertex to the inner vertex
        CircularLinkedListNode <Vector2> rOuterContourVertexNodeToInsertBefore = rMutualVisibleOuterContourVertexNode.Next;

        // Loop over the inner contour starting from the inner contour vertex...
        rInnerContourVertexNode = rMutualVisibleInnerContourVertexNode;
        do
        {
            // ... add the inner contour vertex before the outer contour vertex after the cut
            rOuterCutContourVertexList.AddBefore(rOuterContourVertexNodeToInsertBefore, rInnerContourVertexNode.Value);
            rInnerContourVertexNode = rInnerContourVertexNode.Next;
        }while(rInnerContourVertexNode != rMutualVisibleInnerContourVertexNode);

        // Close the cut by doubling the inner and outer contour vertices
        rOuterCutContourVertexList.AddBefore(rOuterContourVertexNodeToInsertBefore, rMutualVisibleInnerContourVertexNode.Value);
        rOuterCutContourVertexList.AddBefore(rOuterContourVertexNodeToInsertBefore, rMutualVisibleOuterContourVertexNode.Value);

        return(rOuterCutContour);
    }