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