private static void ClipFace(ref NativeManifold tmp, int i, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2)
        {
            NativePlane plane             = transform1 * hull1.GetPlane(i);
            var         incidentFaceIndex = ComputeIncidentFaceIndex(plane, transform2, hull2);

            ClipFaceAgainstAnother(ref tmp, incidentFaceIndex, transform2, hull2, i, transform1, hull1);
        }
        /// <summary>
        /// Finds the point on the surface of a hull closest to a world point.
        /// </summary>
        public static float3 ClosestPoint(RigidTransform t, NativeHull hull, float3 point)
        {
            float       distance         = -float.MaxValue;
            int         closestFaceIndex = -1;
            NativePlane closestPlane     = default;

            // Find the closest face plane.
            for (int i = 0; i < hull.FaceCount; ++i)
            {
                NativePlane plane = t * hull.GetPlane(i);
                float       d     = plane.Distance(point);
                if (d > distance)
                {
                    distance         = d;
                    closestFaceIndex = i;
                    closestPlane     = plane;
                }
            }

            var closestPlanePoint = closestPlane.ClosestPoint(point);

            if (distance > 0)
            {
                // Use a point along the closest edge if the plane point would be outside the face bounds.
                ref NativeFace     face    = ref hull.GetFaceRef(closestFaceIndex);
                ref NativeHalfEdge start   = ref hull.GetEdgeRef(face.Edge);
        /// <summary>
        /// Populates a list with transformed face vertices.
        /// </summary>
        public static unsafe void ComputeFaceClippingPolygon(ref NativeBuffer <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);
        }
        /// <summary>
        /// Determines if a world point is contained within a hull
        /// </summary>
        public static bool Contains(RigidTransform t, NativeHull hull, float3 point)
        {
            float maxDistance = -float.MaxValue;

            for (int i = 0; i < hull.FaceCount; ++i)
            {
                NativePlane plane = t * hull.GetPlane(i);
                float       d     = plane.Distance(point);
                if (d > maxDistance)
                {
                    maxDistance = d;
                }
            }
            return(maxDistance < 0);
        }
        /// <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);
        }
        public static int ClipFaceAgainstAnother(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;

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

            // Get every plane on the other polygon
            GetClippingPlanes(ref clippingPlanes, referencePlane, referenceFaceIndex, transform1, hull1);

            // Create face polygon.
            NativeBuffer <ClipVertex> incidentPolygon = new NativeBuffer <ClipVertex>(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)
            {
                NativeBuffer <ClipVertex> outputPolygon = new NativeBuffer <ClipVertex>(math.max(hull1.VertexCount, hull2.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 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;
                }
            }
        }
        public unsafe static void CreateFaceContact(ref NativeManifold output, FaceQueryResult input, RigidTransform transform1, NativeHull hull1, RigidTransform transform2, NativeHull hull2, bool flipNormal)
        {
            var         refPlane       = hull1.GetPlane(input.Index);
            NativePlane referencePlane = transform1 * refPlane;

            var clippingPlanesStackPtr = stackalloc ClipPlane[hull1.FaceCount];
            var clippingPlanes         = new NativeBuffer <ClipPlane>(clippingPlanesStackPtr, hull1.FaceCount);

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

            // Find only the side planes of the reference face
            GetFaceSidePlanes(ref clippingPlanes, referencePlane, input.Index, transform1, hull1);

            var incidentPolygonStackPtr = stackalloc ClipVertex[hull1.FaceCount];
            var incidentPolygon         = new NativeBuffer <ClipVertex>(incidentPolygonStackPtr, hull1.VertexCount);

            var incidentFaceIndex = ComputeIncidentFaceIndex(referencePlane, transform2, hull2);

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

            //HullDrawingUtility.DrawFaceWithOutline(incidentFaceIndex, transform2, hull2, Color.yellow.ToOpacity(0.3f));

            var outputPolygonStackPtr = stackalloc ClipVertex[hull1.FaceCount];

            // Clip face polygon against the clipping planes.
            for (int i = 0; i < clippingPlanes.Length; ++i)
            {
                var outputPolygon = new NativeBuffer <ClipVertex>(outputPolygonStackPtr, hull1.FaceCount);

                Clip(clippingPlanes[i], ref incidentPolygon, ref outputPolygon);

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

                incidentPolygon = outputPolygon;
            }

            // Get all contact points below reference face.
            for (int i = 0; i < incidentPolygon.Length; ++i)
            {
                ClipVertex vertex   = incidentPolygon[i];
                float      distance = referencePlane.Distance(vertex.position);

                if (distance <= 0)
                {
                    // Below reference plane -> position constraint violated.
                    ContactID id = default;
                    id.FeaturePair = vertex.featurePair;

                    if (flipNormal)
                    {
                        output.Normal = -referencePlane.Normal;
                        Swap(id.FeaturePair.InEdge1, id.FeaturePair.InEdge2);
                        Swap(id.FeaturePair.OutEdge1, id.FeaturePair.OutEdge2);
                    }
                    else
                    {
                        output.Normal = referencePlane.Normal;
                    }

                    // Project clipped point onto reference plane.
                    float3 position = referencePlane.ClosestPoint(vertex.position);
                    // Add point and distance to the plane to the manifold.
                    output.Add(position, distance, id);
                }
            }

            //clippingPlanes.Dispose();
            //incidentPolygon.Dispose();
        }
        public static unsafe void GetFaceSidePlanes(ref NativeBuffer <ClipPlane> output, NativePlane facePlane, int faceIndex, RigidTransform transform, NativeHull hull)
        {
            NativeHalfEdge *start   = hull.GetEdgePtr(hull.GetFacePtr(faceIndex)->Edge);
            NativeHalfEdge *current = start;

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

                ClipPlane clipPlane = default;
                clipPlane.edgeId       = twin->Twin; //edge ID.
                clipPlane.plane.Normal = math.normalize(math.cross(Q - P, facePlane.Normal));
                clipPlane.plane.Offset = math.dot(clipPlane.plane.Normal, P);
                output.Add(clipPlane);

                current = hull.GetEdgePtr(current->Next);
            }while (current != start);
        }
        /// <summary>
        /// Populates a list with transformed face planes
        /// </summary>
        public static unsafe void GetClippingPlanes(ref NativeBuffer <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,
                });
            }
        }