Ejemplo n.º 1
0
        public bool ClosestPtPointTriangle(ref Vector3 p, ref Vector3 a, ref Vector3 b, ref Vector3 c, ref SubSimplexClosestResult result)
        {
            result.m_usedVertices.SetAll(false);

            // Check if P in vertex region outside A
            Vector3 ab = b - a;
            Vector3 ac = c - a;
            Vector3 ap = p - a;
            float d1 = Vector3.Dot(ab, ap);
            float d2 = Vector3.Dot(ac, ap);
            if (d1 <= 0f && d2 <= 0f)
            {
                result.m_closestPointOnSimplex = a;
                result.m_usedVertices.Set(0, true);
                result.SetBarycentricCoordinates(1, 0, 0, 0);
                return true;// a; // barycentric coordinates (1,0,0)
            }

            // Check if P in vertex region outside B
            Vector3 bp = p - b;
            float d3 = Vector3.Dot(ab, bp);
            float d4 = Vector3.Dot(ac, bp);
            if (d3 >= 0f && d4 <= d3)
            {
                result.m_closestPointOnSimplex = b;
                result.m_usedVertices.Set(1, true);
                result.SetBarycentricCoordinates(0, 1, 0, 0);

                return true; // b; // barycentric coordinates (0,1,0)
            }
            // Check if P in edge region of AB, if so return projection of P onto AB
            float vc = d1 * d4 - d3 * d2;
            if (vc <= 0f && d1 >= 0f && d3 <= 0f)
            {
                float v = d1 / (d1 - d3);
                result.m_closestPointOnSimplex = a + v * ab;
                result.m_usedVertices.Set(0, true);
                result.m_usedVertices.Set(1, true);
                result.SetBarycentricCoordinates(1 - v, v, 0, 0);
                return true;
                //return a + v * ab; // barycentric coordinates (1-v,v,0)
            }

            // Check if P in vertex region outside C
            Vector3 cp = p - c;
            float d5 = Vector3.Dot(ab, cp);
            float d6 = Vector3.Dot(ac, cp);
            if (d6 >= 0f && d5 <= d6)
            {
                result.m_closestPointOnSimplex = c;
                result.m_usedVertices.Set(2, true);
                result.SetBarycentricCoordinates(0, 0, 1, 0);
                return true;//c; // barycentric coordinates (0,0,1)
            }

            // Check if P in edge region of AC, if so return projection of P onto AC
            float vb = d5 * d2 - d1 * d6;
            if (vb <= 0f && d2 >= 0f && d6 <= 0f)
            {
                float w = d2 / (d2 - d6);
                result.m_closestPointOnSimplex = a + w * ac;
                result.m_usedVertices.Set(0, true);
                result.m_usedVertices.Set(2, true);
                result.SetBarycentricCoordinates(1 - w, 0, w, 0);
                return true;
                //return a + w * ac; // barycentric coordinates (1-w,0,w)
            }

            // Check if P in edge region of BC, if so return projection of P onto BC
            float va = d3 * d6 - d5 * d4;
            if (va <= 0f && (d4 - d3) >= 0f && (d5 - d6) >= 0f)
            {
                float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));

                result.m_closestPointOnSimplex = b + w * (c - b);
                result.m_usedVertices.Set(1, true);
                result.m_usedVertices.Set(2, true);
                result.SetBarycentricCoordinates(0, 1 - w, w, 0);
                return true;
                // return b + w * (c - b); // barycentric coordinates (0,1-w,w)
            }

            // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
            float denom = 1f / (va + vb + vc);
            float v1 = vb * denom;
            float w1 = vc * denom;

            result.m_closestPointOnSimplex = a + ab * v1 + ac * w1;
            result.m_usedVertices.Set(0, true);
            result.m_usedVertices.Set(1, true);
            result.m_usedVertices.Set(2, true);
            result.SetBarycentricCoordinates(1 - v1 - w1, v1, w1, 0);

            return true;
            //	return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = float(1.0) - v - w

        }
Ejemplo n.º 2
0
        public bool ClosestPtPointTetrahedron(ref Vector3 p, ref Vector3 a, ref Vector3 b, ref Vector3 c, ref Vector3 d, ref SubSimplexClosestResult finalResult)
        {
            SubSimplexClosestResult tempResult = new SubSimplexClosestResult();

            // Start ref assuming point inside all halfspaces, so closest to itself
            finalResult.m_closestPointOnSimplex = p;
            finalResult.m_usedVertices.SetAll(true);

            int pointOutsideABC = PointOutsideOfPlane(ref p, ref a, ref b, ref c, ref d);
            int pointOutsideACD = PointOutsideOfPlane(ref p, ref a, ref c, ref d, ref b);
            int pointOutsideADB = PointOutsideOfPlane(ref p, ref a, ref d, ref b, ref c);
            int pointOutsideBDC = PointOutsideOfPlane(ref p, ref b, ref d, ref c, ref a);

            if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0)
            {
                finalResult.m_degenerate = true;
                return false;
            }

            if (pointOutsideABC == 0 && pointOutsideACD == 0 && pointOutsideADB == 0 && pointOutsideBDC == 0)
            {
                return false;
            }


            float bestSqDist = float.MaxValue;
            // If point outside face abc then compute closest point on abc
            if (pointOutsideABC != 0)
            {
                ClosestPtPointTriangle(ref p, ref a, ref b, ref c, ref tempResult);
                Vector3 q = tempResult.m_closestPointOnSimplex;

                float sqDist = (q - p).LengthSquared();
                // Update best closest point if (squared) distance is less than current best
                if (sqDist < bestSqDist)
                {
                    bestSqDist = sqDist;
                    finalResult.m_closestPointOnSimplex = q;
                    //convert result bitmask!
                    finalResult.m_usedVertices.SetAll(false);
                    finalResult.m_usedVertices.Set(0, tempResult.m_usedVertices.Get(0));
                    finalResult.m_usedVertices.Set(1, tempResult.m_usedVertices.Get(1));
                    finalResult.m_usedVertices.Set(2, tempResult.m_usedVertices.Get(2));
                    finalResult.SetBarycentricCoordinates(
                            tempResult.m_barycentricCoords.X,
                            tempResult.m_barycentricCoords.Y,
                            tempResult.m_barycentricCoords.Z,
                            0
                    );

                }
            }


            // Repeat test for face acd
            if (pointOutsideACD != 0)
            {
                ClosestPtPointTriangle(ref p, ref a, ref c, ref d, ref tempResult);
                Vector3 q = tempResult.m_closestPointOnSimplex;

                float sqDist = (q - p).LengthSquared();
                // Update best closest point if (squared) distance is less than current best
                if (sqDist < bestSqDist)
                {
                    bestSqDist = sqDist;
                    finalResult.m_closestPointOnSimplex = q;
                    //convert result bitmask!
                    finalResult.m_usedVertices.SetAll(false);
                    finalResult.m_usedVertices.Set(0, tempResult.m_usedVertices.Get(0));
                    finalResult.m_usedVertices.Set(2, tempResult.m_usedVertices.Get(1));
                    finalResult.m_usedVertices.Set(3, tempResult.m_usedVertices.Get(2));
                    finalResult.SetBarycentricCoordinates(
                            tempResult.m_barycentricCoords.X,
                            0,
                            tempResult.m_barycentricCoords.Y,
                            tempResult.m_barycentricCoords.Z);
                }
            }
            // Repeat test for face adb


            if (pointOutsideADB != 0)
            {
                ClosestPtPointTriangle(ref p, ref a, ref d, ref b, ref tempResult);
                Vector3 q = tempResult.m_closestPointOnSimplex;

                float sqDist = (q - p).LengthSquared();
                // Update best closest point if (squared) distance is less than current best
                if (sqDist < bestSqDist)
                {
                    bestSqDist = sqDist;
                    finalResult.m_closestPointOnSimplex = q;
                    //convert result bitmask!
                    finalResult.m_usedVertices.SetAll(false);
                    finalResult.m_usedVertices.Set(0, tempResult.m_usedVertices.Get(0));
                    finalResult.m_usedVertices.Set(1, tempResult.m_usedVertices.Get(2));
                    finalResult.m_usedVertices.Set(3, tempResult.m_usedVertices.Get(1));
                    finalResult.SetBarycentricCoordinates(
                            tempResult.m_barycentricCoords.X,
                            tempResult.m_barycentricCoords.Z,
                            0,
                            tempResult.m_barycentricCoords.Y);
                }
            }
            // Repeat test for face bdc


            if (pointOutsideBDC != 0)
            {
                ClosestPtPointTriangle(ref p, ref b, ref d, ref c, ref tempResult);
                Vector3 q = tempResult.m_closestPointOnSimplex;

                float sqDist = (q - p).LengthSquared();
                // Update best closest point if (squared) distance is less than current best
                if (sqDist < bestSqDist)
                {
                    bestSqDist = sqDist;
                    finalResult.m_closestPointOnSimplex = q;
                    //convert result bitmask!
                    finalResult.m_usedVertices.SetAll(false);
                    finalResult.m_usedVertices.Set(1, tempResult.m_usedVertices.Get(0));
                    finalResult.m_usedVertices.Set(2, tempResult.m_usedVertices.Get(2));
                    finalResult.m_usedVertices.Set(3, tempResult.m_usedVertices.Get(1));
                    finalResult.SetBarycentricCoordinates(
                            0,
                            tempResult.m_barycentricCoords.X,
                            tempResult.m_barycentricCoords.Z,
                            tempResult.m_barycentricCoords.Y);
                }

            }

            //help! we ended up full !

            if (finalResult.m_usedVertices.Get(0) &&
                finalResult.m_usedVertices.Get(1) &&
                finalResult.m_usedVertices.Get(2) &&
                finalResult.m_usedVertices.Get(3))
            {
                return true;
            }

            return true;

        }