예제 #1
0
        public static unsafe void ValidateEdge(this NativeHull hull, NativeHalfEdge *edge)
        {
            Debug.Assert(hull.faceCount > 0);
            Debug.Assert(hull.edgeCount > 0);
            Debug.Assert(edge->twin != -1);

            NativeHalfEdge *curTwin = hull.edges + edge->twin;

            int edgeIndex = (int)(edge - hull.edges);

            Debug.Assert(curTwin->twin == edgeIndex, "The twin of the edge twin must be the edge itself");
            Debug.Assert(math.abs(edge->twin - edgeIndex) == 1, "The two edges must be close by one index.");
            Debug.Assert(hull.edges[edge->prev].next == edgeIndex, "The twin of the edge twin must be the edge");
            Debug.Assert(edge->origin != curTwin->origin, "Edges and their twin must point to each others' origin vertex");

            int             count = 0;
            NativeHalfEdge *start = edge;

            do
            {
                NativeHalfEdge *next = hull.edges + edge->next;
                NativeHalfEdge *twin = hull.edges + next->twin;
                edge = twin;

                Debug.Assert(edge->face != -1, "All edges must have a face index");

                bool infiniteLoop = count > hull.edgeCount;
                if (count > hull.edgeCount)
                {
                    Debug.Assert(true, "Possible infinite Edge Loop");
                    break;
                }
                ++count;
            }while (edge != start);
        }
예제 #2
0
        public static unsafe void ValidateFace(this NativeHull hull, NativeFace *face)
        {
            Debug.Assert(hull.faceCount > 0);
            Debug.Assert(hull.edgeCount > 0);
            Debug.Assert(face->edge != -1);

            ValidateEdge(hull, hull.edges + face->edge);
        }
 public static void DrawBasicHull(NativeHull hull1, RigidTransform t)
 {
     foreach (var edge in hull1.GetEdges())
     {
         var a = math.transform(t, edge.GetOrigin(hull1));
         var b = math.transform(t, edge.GetTwinOrigin(hull1));
         Debug.DrawLine(a, b, Color.black);
     }
 }
예제 #4
0
        public static CollisionInfo GetDebugCollisionInfo(RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            CollisionInfo result = default;

            QueryFaceDistance(out result.Face1, transform1, hull1, transform2, hull2);
            QueryFaceDistance(out result.Face2, transform2, hull2, transform1, hull1);
            QueryEdgeDistance(out result.Edge, transform1, hull1, transform2, hull2);
            result.IsColliding = result.Face1.Distance < 0 && result.Face2.Distance < 0 && result.Edge.Distance < 0;
            return(result);
        }
예제 #5
0
        public static unsafe void Validate(this NativeHull hull)
        {
            Debug.Assert(hull.faceCount > 0);
            Debug.Assert(hull.edgeCount > 0);

            for (int i = 0; i < hull.faceCount; ++i)
            {
                ValidateFace(hull, hull.faces + i);
            }
        }
        public static void DrawFaceWithOutline(int faceIndex, RigidTransform t, NativeHull hull, Color fillColor, Color outlineColor)
        {
            var verts  = hull.GetVertices(faceIndex).Select(cp => (Vector3)cp).ToArray();
            var tVerts = new List <Vector3>();

            for (int i = 0; i < verts.Length; i++)
            {
                var v = math.transform(t, verts[i]);
                tVerts.Add(v);
                var nextIndex = i + 1 < verts.Length ? i + 1 : 0;
                var next      = math.transform(t, verts[nextIndex]);
                Debug.DrawLine(v, next, outlineColor);
            }
            DebugDrawer.DrawAAConvexPolygon(tVerts.ToArray(), fillColor);
        }
        public static unsafe int GetSupportIndex(this NativeHull hull, float3 direction)
        {
            int   index = 0;
            float max   = dot(direction, hull.vertices[index]);

            for (int i = 1; i < hull.vertexCount; ++i)
            {
                float dot = math.dot(direction, hull.vertices[i]);
                if (dot > max)
                {
                    index = i;
                    max   = dot;
                }
            }
            return(index);
        }
예제 #8
0
        public static bool IsCollision(RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            FaceQueryResult faceQuery;

            QueryFaceDistance(out faceQuery, transform1, hull1, transform2, hull2);
            if (faceQuery.Distance > 0)
            {
                return(false);
            }

            QueryFaceDistance(out faceQuery, transform2, hull2, transform1, hull1);
            if (faceQuery.Distance > 0)
            {
                return(false);
            }

            QueryEdgeDistance(out EdgeQueryResult edgeQuery, transform1, hull1, transform2, hull2);
            if (edgeQuery.Distance > 0)
            {
                return(false);
            }

            return(true);
        }
        public static int CreateFaceContact(ref NativeManifold output, int referenceFaceIndex, RigidTransform transform1, NativeHull hull1, int incidentFaceIndex, RigidTransform transform2, NativeHull hull2)
        {
            Debug.Assert(output.IsCreated);

            var         refPlane       = hull1.GetPlane(referenceFaceIndex);
            NativePlane referencePlane = transform1 * refPlane;

            NativeList <ClipPlane> clippingPlanes = new NativeList <ClipPlane>((int)hull1.FaceCount, Allocator.Temp);

            GetClippingPlanes(ref clippingPlanes, referencePlane, referenceFaceIndex, transform1, hull1);

            // Create face polygon.
            NativeList <ClipVertex> incidentPolygon = new NativeList <ClipVertex>((int)hull1.VertexCount, Allocator.Temp);

            ComputeFaceClippingPolygon(ref incidentPolygon, incidentFaceIndex, transform2, hull2);

            // Clip face polygon against the clipping planes.
            for (int i = 0; i < clippingPlanes.Length; ++i)
            {
                NativeList <ClipVertex> outputPolygon = new NativeList <ClipVertex>((int)hull1.VertexCount, Allocator.Temp);
                Clip(clippingPlanes[i], ref incidentPolygon, ref outputPolygon);

                if (outputPolygon.Length == 0)
                {
                    return(-1);
                }

                incidentPolygon.Dispose();
                incidentPolygon = outputPolygon;
            }

            for (int i = 0; i < incidentPolygon.Length; ++i)
            {
                ClipVertex vertex   = incidentPolygon[i];
                float      distance = referencePlane.Distance(vertex.position);
                output.Add(vertex.position, distance, new ContactID {
                    FeaturePair = vertex.featurePair
                });
            }

            clippingPlanes.Dispose();
            incidentPolygon.Dispose();

            return(incidentFaceIndex);
        }
        public static int CreateFaceContact2(ref NativeManifold output, int referenceFaceIndex, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            // todo, clean this up, i'm reversing the args here so that closest face is the one clipped instead of incident.

            Debug.Assert(output.IsCreated);

            NativePlane referencePlane    = transform1 * hull1.GetPlane(referenceFaceIndex);
            var         incidentFaceIndex = ComputeIncidentFaceIndex(referencePlane, transform2, hull2);

            return(CreateFaceContact(ref output, incidentFaceIndex, transform2, hull2, referenceFaceIndex, transform1, hull1));
        }
        public static bool NativeHullHullContact(out NativeManifold output, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            output = new NativeManifold(Allocator.Persistent);

            // todo: collect faces and put them in combined manifold

            for (int i = 0; i < hull2.FaceCount; i++)
            {
                var tmp = new NativeManifold(Allocator.Temp);
                CreateFaceContact2(ref tmp, i, transform2, hull2, transform1, hull1);
                HullDrawingUtility.DebugDrawManifold(tmp);
                tmp.Dispose();
            }

            for (int i = 0; i < hull1.FaceCount; i++)
            {
                var tmp = new NativeManifold(Allocator.Temp);
                CreateFaceContact2(ref tmp, i, transform1, hull1, transform2, hull2);
                HullDrawingUtility.DebugDrawManifold(tmp);
                tmp.Dispose();
            }

            return(true);
        }
        public static unsafe void b3CreateEdgeContact(ref NativeManifold output, EdgeQueryResult input, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            Debug.Assert(output.IsCreated);

            ContactPoint cp = default;

            if (input.Index1 < 0 || input.Index2 < 0)
            {
                return;
            }

            NativeHalfEdge *edge1 = hull1.GetEdgePtr(input.Index1);
            NativeHalfEdge *twin1 = hull1.GetEdgePtr(edge1->Twin);

            float3 P1 = math.transform(transform1, hull1.GetVertex(edge1->Origin));
            float3 Q1 = math.transform(transform1, hull1.GetVertex(twin1->Origin));
            float3 E1 = Q1 - P1;

            NativeHalfEdge *edge2 = hull2.GetEdgePtr(input.Index2);
            NativeHalfEdge *twin2 = hull2.GetEdgePtr(edge2->Twin);

            float3 P2 = math.transform(transform1, hull2.GetVertex(edge2->Origin));
            float3 Q2 = math.transform(transform1, hull2.GetVertex(twin2->Origin));
            float3 E2 = Q2 - P2;

            float3 normal = math.normalize(math.cross(Q1 - P1, Q2 - P2));
            float3 C2C1   = transform2.pos - transform1.pos;

            if (math.dot(normal, C2C1) < 0)
            {
                // Flip
                output.Normal              = -normal;
                cp.Id.FeaturePair.InEdge1  = (sbyte)input.Index2;
                cp.Id.FeaturePair.OutEdge1 = (sbyte)(input.Index2 + 1);

                cp.Id.FeaturePair.InEdge2  = (sbyte)(input.Index1 + 1);
                cp.Id.FeaturePair.OutEdge2 = (sbyte)input.Index1;
            }
            else
            {
                output.Normal = normal;

                cp.Id.FeaturePair.InEdge1  = (sbyte)input.Index1;
                cp.Id.FeaturePair.OutEdge1 = (sbyte)(input.Index1 + 1);

                cp.Id.FeaturePair.InEdge2  = (sbyte)(input.Index2 + 1);
                cp.Id.FeaturePair.OutEdge2 = (sbyte)input.Index2;
            }

            // Compute the closest points between the two edges (center point of penetration)
            ClosestPointsSegmentSegment(P1, Q1, P2, Q2, out float3 C1, out float3 C2);

            float3 position = 0.5f * (C1 + C2);

            //// the closest points on each hull
            //cp.positionOnTarget = Math3d.ProjectPointOnLineSegment(P2, Q2, C2);
            //cp.positionOnSource = Math3d.ProjectPointOnLineSegment(P1, Q1, C1);

            cp.Penetration = C1 - C2;
            cp.Position    = position;
            cp.Distance    = input.Distance;

            output.Add(cp);
        }
예제 #13
0
        public static unsafe NativeHull CreateFromMesh(Mesh mesh)
        {
            var faces       = new List <DetailedFaceDef>();
            var verts       = mesh.vertices.Select(RoundVertex).ToArray();
            var uniqueVerts = verts.Distinct().ToList();
            var indices     = mesh.triangles;

            // Create faces from Triangles and collapse multiple vertices with same position into shared vertices.
            for (int i = 0; i < mesh.triangles.Length; i = i + 3)
            {
                var idx1 = i;
                var idx2 = i + 1;
                var idx3 = i + 2;

                Vector3 p1 = verts[indices[idx1]];
                Vector3 p2 = verts[indices[idx2]];
                Vector3 p3 = verts[indices[idx3]];

                var normal = normalize(cross(p3 - p2, p1 - p2));

                // Round normal so that faces with only slight variances can be grouped properly together.
                var roundedNormal = RoundVertex(normal);

                faces.Add(new DetailedFaceDef
                {
                    Center = ((p1 + p2 + p3) / 3),
                    Normal = roundedNormal,
                    Verts  = new List <float3> {
                        p1, p2, p3
                    },
                    Indices = new List <int>
                    {
                        uniqueVerts.IndexOf(p1),
                        uniqueVerts.IndexOf(p2),
                        uniqueVerts.IndexOf(p3)
                    }
                });
            }

            var faceDefs      = new List <NativeFaceDef>();
            var orphanIndices = new HashSet <int>();

            // Merge all faces with the same normal and shared vertex
            var mergedFaces = GroupBySharedVertex(GroupByNormal(faces));

            foreach (var faceGroup in mergedFaces)
            {
                var indicesFromMergedFaces = faceGroup.SelectMany(face => face.Indices).ToArray();

                // Collapse points inside the new combined face by using only the border vertices.
                var border        = PolygonPerimeter.CalculatePerimeter(indicesFromMergedFaces, ref uniqueVerts);
                var borderIndices = border.Select(b => b.EndIndex).ToArray();

                foreach (var idx in indicesFromMergedFaces.Except(borderIndices))
                {
                    orphanIndices.Add(idx);
                }

                var v   = stackalloc int[borderIndices.Length];
                int max = 0;
                for (int i = 0; i < borderIndices.Length; i++)
                {
                    var idx = borderIndices[i];
                    if (idx > max)
                    {
                        max = idx;
                    }
                    v[i] = idx;
                }

                faceDefs.Add(new NativeFaceDef
                {
                    highestIndex = max,
                    vertexCount  = borderIndices.Length,
                    vertices     = v,
                });
            }

            // Remove vertices with no edges connected to them and fix all impacted face vertex references.
            foreach (var orphanIdx in orphanIndices.OrderByDescending(i => i))
            {
                uniqueVerts.RemoveAt(orphanIdx);

                foreach (var face in faceDefs.Where(f => f.highestIndex >= orphanIdx))
                {
                    for (int i = 0; i < face.vertexCount; i++)
                    {
                        var faceVertIdx = face.vertices[i];
                        if (faceVertIdx >= orphanIdx)
                        {
                            face.vertices[i] = --faceVertIdx;
                        }
                    }
                }
            }

            var result = new NativeHull();

            using (var faceNative = new NativeArray <NativeFaceDef>(faceDefs.ToArray(), Allocator.Temp))
                using (var vertsNative = new NativeArray <float3>(uniqueVerts.ToArray(), Allocator.Temp))
                {
                    NativeHullDef hullDef;
                    hullDef.vertexCount    = vertsNative.Length;
                    hullDef.verticesNative = vertsNative;
                    hullDef.faceCount      = faceNative.Length;
                    hullDef.facesNative    = faceNative;
                    SetFromFaces(ref result, hullDef);
                }

            result._isCreated = 1;
            return(result);
        }
예제 #14
0
 public ref NativeHalfEdge GetTwin(NativeHull hull) => ref hull.GetEdgeRef(Twin);
예제 #15
0
 public ref NativeHalfEdge GetPrev(NativeHull hull) => ref hull.GetEdgeRef(Prev);
예제 #16
0
 public ref float3 GetNextOrigin(NativeHull hull) => ref GetNext(hull).GetOrigin(hull);
 public static IEnumerable <float3> GetVertices(this NativeHull hull)
 {
     return(new HullAllEdgesEnumerator(hull).Select(v => v.GetOrigin(hull)));
 }
 public static IEnumerable <float3> GetVertices(this NativeHull hull, int faceIndex)
 {
     return(new HullFaceEdgesEnumerator(hull, faceIndex).Select(v => v.GetOrigin(hull)));
 }
예제 #19
0
        public static unsafe void QueryFaceDistance(out FaceQueryResult result, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            // Perform computations in the local space of the second hull.
            RigidTransform transform = math.mul(math.inverse(transform2), transform1);

            result.Distance = -float.MaxValue;
            result.Index    = -1;

            for (int i = 0; i < hull1.FaceCount; ++i)
            {
                NativePlane plane    = transform * hull1.GetPlane(i);
                float3      support  = hull2.GetSupport(-plane.Normal);
                float       distance = plane.Distance(support);

                if (distance > result.Distance)
                {
                    result.Distance = distance;
                    result.Index    = i;
                }
            }
        }
예제 #20
0
        public static unsafe NativeHull CreateBox(float3 scale)
        {
            float3[] cubeVertices =
            {
                new float3(1,   1, -1),
                new float3(-1,  1, -1),
                new float3(-1, -1, -1),
                new float3(1,  -1, -1),
                new float3(1,   1,  1),
                new float3(-1,  1,  1),
                new float3(-1, -1,  1),
                new float3(1,  -1,  1),
            };

            for (int i = 0; i < 8; ++i)
            {
                cubeVertices[i].x *= scale.x;
                cubeVertices[i].y *= scale.y;
                cubeVertices[i].z *= scale.z;
            }

            int *left  = stackalloc int[] { 1, 2, 6, 5 };
            int *right = stackalloc int[] { 4, 7, 3, 0 };
            int *down  = stackalloc int[] { 3, 7, 6, 2 };
            int *up    = stackalloc int[] { 0, 1, 5, 4 };
            int *back  = stackalloc int[] { 4, 5, 6, 7 };
            int *front = stackalloc int[] { 0, 3, 2, 1 };

            NativeFaceDef[] boxFaces =
            {
                new NativeFaceDef {
                    vertexCount = 4, vertices = left
                },
                new NativeFaceDef {
                    vertexCount = 4, vertices = right
                },
                new NativeFaceDef {
                    vertexCount = 4, vertices = down
                },
                new NativeFaceDef {
                    vertexCount = 4, vertices = up
                },
                new NativeFaceDef {
                    vertexCount = 4, vertices = back
                },
                new NativeFaceDef {
                    vertexCount = 4, vertices = front
                },
            };

            var result = new NativeHull();

            using (var boxFacesNative = new NativeArray <NativeFaceDef>(boxFaces, Allocator.Temp))
                using (var cubeVertsNative = new NativeArray <float3>(cubeVertices, Allocator.Temp))
                {
                    NativeHullDef hullDef;
                    hullDef.vertexCount    = 8;
                    hullDef.verticesNative = cubeVertsNative;
                    hullDef.faceCount      = 6;
                    hullDef.facesNative    = boxFacesNative;
                    SetFromFaces(ref result, hullDef);
                }

            result._isCreated = 1;
            return(result);
        }
예제 #21
0
        public static unsafe void QueryEdgeDistance(out EdgeQueryResult result, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            // Perform computations in the local space of the second hull.
            RigidTransform transform = math.mul(math.inverse(transform2), transform1);

            float3 C1 = transform.pos;

            result.Distance = -float.MaxValue;
            result.Index1   = -1;
            result.Index2   = -1;

            for (int i = 0; i < hull1.EdgeCount; i += 2)
            {
                NativeHalfEdge *edge1 = hull1.GetEdgePtr(i);
                NativeHalfEdge *twin1 = hull1.GetEdgePtr(i + 1);

                Debug.Assert(edge1->Twin == i + 1 && twin1->Twin == i);

                float3 P1 = math.transform(transform, hull1.GetVertex(edge1->Origin));
                float3 Q1 = math.transform(transform, hull1.GetVertex(twin1->Origin));
                float3 E1 = Q1 - P1;

                float3 U1 = math.rotate(transform, hull1.GetPlane(edge1->Face).Normal);
                float3 V1 = math.rotate(transform, hull1.GetPlane(twin1->Face).Normal);

                for (int j = 0; j < hull2.EdgeCount; j += 2)
                {
                    NativeHalfEdge *edge2 = hull2.GetEdgePtr(j);
                    NativeHalfEdge *twin2 = hull2.GetEdgePtr(j + 1);

                    Debug.Assert(edge2->Twin == j + 1 && twin2->Twin == j);

                    float3 P2 = hull2.GetVertex(edge2->Origin);
                    float3 Q2 = hull2.GetVertex(twin2->Origin);
                    float3 E2 = Q2 - P2;

                    float3 U2 = hull2.GetPlane(edge2->Face).Normal;
                    float3 V2 = hull2.GetPlane(twin2->Face).Normal;

                    if (IsMinkowskiFace(U1, V1, -E1, -U2, -V2, -E2))
                    {
                        float distance = Project(P1, E1, P2, E2, C1);
                        if (distance > result.Distance)
                        {
                            result.Index1   = i;
                            result.Index2   = j;
                            result.Distance = distance;
                        }
                    }
                }
            }
        }
예제 #22
0
 public ref NativeFace GetFace(NativeHull hull) => ref hull.GetFaceRef(Face);
예제 #23
0
 public ref NativeHalfEdge GetNext(NativeHull hull) => ref hull.GetEdgeRef(Next);
 /// <summary>
 /// Populates a list with transformed face planes
 /// </summary>
 public static unsafe void GetClippingPlanes(ref NativeList <ClipPlane> output, NativePlane facePlane, int faceIndex, RigidTransform transform, NativeHull hull)
 {
     Debug.Assert(output.IsCreated);
     for (int i = 0; i < hull.FaceCount; i++)
     {
         var p = hull.GetPlane(i);
         output.Add(new ClipPlane
         {
             plane = transform * p,
         });
     }
 }
예제 #25
0
 public ref float3 GetOrigin(NativeHull hull) => ref hull.GetVertexRef(Origin);
        /// <summary>
        /// Populates a list with transformed face vertices.
        /// </summary>
        public static unsafe void ComputeFaceClippingPolygon(ref NativeList <ClipVertex> output, int faceIndex, RigidTransform t, NativeHull hull)
        {
            Debug.Assert(output.IsCreated);

            NativeFace *    face    = hull.GetFacePtr(faceIndex);
            NativePlane     plane   = hull.GetPlane(faceIndex);
            NativeHalfEdge *start   = hull.GetEdgePtr(face->Edge);
            NativeHalfEdge *current = start;

            do
            {
                NativeHalfEdge *twin   = hull.GetEdgePtr(current->Twin);
                float3          vertex = hull.GetVertex(current->Origin);
                float3          P      = math.transform(t, vertex);

                ClipVertex clipVertex;
                clipVertex.featurePair.InEdge1  = -1;
                clipVertex.featurePair.OutEdge1 = -1;
                clipVertex.featurePair.InEdge2  = (sbyte)current->Next;
                clipVertex.featurePair.OutEdge2 = (sbyte)twin->Twin;
                clipVertex.position             = P;
                clipVertex.hull2local           = vertex;
                clipVertex.plane = plane;

                output.Add(clipVertex);

                current = hull.GetEdgePtr(current->Next);
            } while (current != start);
        }
예제 #27
0
 public ref float3 GetTwinOrigin(NativeHull hull) => ref GetTwin(hull).GetOrigin(hull);
예제 #28
0
        public unsafe static void SetFromFaces(ref NativeHull hull, NativeHullDef def)
        {
            Debug.Assert(def.faceCount > 0);
            Debug.Assert(def.vertexCount > 0);

            hull.vertexCount = def.vertexCount;
            var arr = def.verticesNative.ToArray();

            hull.verticesNative = new NativeArrayNoLeakDetection <float3>(arr, Allocator.Persistent);
            hull.vertices       = (float3 *)hull.verticesNative.GetUnsafePtr();
            hull.faceCount      = def.faceCount;
            hull.facesNative    = new NativeArrayNoLeakDetection <NativeFace>(hull.faceCount, Allocator.Persistent);
            hull.faces          = (NativeFace *)hull.facesNative.GetUnsafePtr();

            // Initialize all faces by assigning -1 to each edge reference.
            for (int k = 0; k < def.faceCount; ++k)
            {
                NativeFace *f = hull.faces + k;
                f->edge = -1;
            }

            CreateFacesPlanes(ref hull, ref def);

            var edgeMap   = new Dictionary <(int v1, int v2), int>();
            var edgesList = new NativeHalfEdge[10000]; // todo lol

            // Loop through all faces.
            for (int i = 0; i < def.faceCount; ++i)
            {
                NativeFaceDef face      = def.facesNative[i];
                int           vertCount = face.vertexCount;

                Debug.Assert(vertCount >= 3);

                int *vertices = face.vertices;

                var faceHalfEdges = new List <int>();

                // Loop through all face edges.
                for (int j = 0; j < vertCount; ++j)
                {
                    int v1 = vertices[j];
                    int v2 = j + 1 < vertCount ? vertices[j + 1] : vertices[0];

                    bool edgeFound12 = edgeMap.TryGetValue((v1, v2), out int iter12);
                    bool edgeFound21 = edgeMap.ContainsKey((v2, v1));

                    Debug.Assert(edgeFound12 == edgeFound21);

                    if (edgeFound12)
                    {
                        // The edge is shared by two faces.
                        int e12 = iter12;

                        // Link adjacent face to edge.
                        if (edgesList[e12].face == -1)
                        {
                            edgesList[e12].face = i;
                        }
                        else
                        {
                            throw new Exception("Two shared edges can't have the same vertices in the same order");
                        }

                        if (hull.faces[i].edge == -1)
                        {
                            hull.faces[i].edge = e12;
                        }

                        faceHalfEdges.Add(e12);
                    }
                    else
                    {
                        // The next edge of the current half edge in the array is the twin edge.
                        int e12 = hull.edgeCount++;
                        int e21 = hull.edgeCount++;

                        if (hull.faces[i].edge == -1)
                        {
                            hull.faces[i].edge = e12;
                        }

                        faceHalfEdges.Add(e12);

                        edgesList[e12].prev   = -1;
                        edgesList[e12].next   = -1;
                        edgesList[e12].twin   = e21;
                        edgesList[e12].face   = i;
                        edgesList[e12].origin = v1;

                        edgesList[e21].prev   = -1;
                        edgesList[e21].next   = -1;
                        edgesList[e21].twin   = e12;
                        edgesList[e21].face   = -1;
                        edgesList[e21].origin = v2;

                        // Add edges to map.
                        edgeMap[(v1, v2)] = e12;
예제 #29
0
 public ref NativeHalfEdge AsRef(NativeHull hull) => ref GetTwin(hull).GetTwin(hull);
        /// <summary>
        /// Finds the index to the least parallel face on the other hull.
        /// </summary>
        /// <param name="facePlane"></param>
        /// <param name="transform"></param>
        /// <param name="hull"></param>
        /// <returns></returns>
        public static unsafe int ComputeIncidentFaceIndex(NativePlane facePlane, RigidTransform transform, NativeHull hull)
        {
            int   faceIndex = 0;
            float min       = math.dot(facePlane.Normal, (transform * hull.GetPlane(faceIndex)).Normal);

            for (int i = 1; i < hull.FaceCount; ++i)
            {
                float dot = math.dot(facePlane.Normal, (transform * hull.GetPlane(i)).Normal);
                if (dot < min)
                {
                    min       = dot;
                    faceIndex = i;
                }
            }
            return(faceIndex);
        }