public bool ClosestPtPointTriangle(TSVector a, TSVector b, TSVector c, ref SubSimplexClosestResult result) { result.usedVertices.Reset(); FP v, w; // Check if P in vertex region outside A TSVector ab = b - a; TSVector ac = c - a; FP d1 = TSVector.Dot(ab, a); FP d2 = TSVector.Dot(ac, a); if (d1 >= FP.Zero && d2 >= FP.Zero) { result.closestPointOnSimplex = a; result.usedVertices.UsedVertexA = true; result.SetBarycentricCoordinates(FP.One, FP.Zero, FP.Zero, FP.Zero); return(true); // a; // barycentric coordinates (1,0,0) } // Check if P in vertex region outside B FP d3 = TSVector.Dot(ab, b); FP d4 = TSVector.Dot(ac, b); if (d3 <= FP.Zero && d4 >= d3) { result.closestPointOnSimplex = b; result.usedVertices.UsedVertexB = true; result.SetBarycentricCoordinates(FP.Zero, FP.One, FP.Zero, FP.Zero); return(true); // b; // barycentric coordinates (0,1,0) } // Check if P in edge region of AB, if so return projection of P onto AB FP vc = d1 * d4 - d3 * d2; if (vc <= FP.Zero && d1 >= FP.Zero && d3 <= FP.Zero) { v = d1 / (d1 - d3); result.closestPointOnSimplex = a + v * ab; result.usedVertices.UsedVertexA = true; result.usedVertices.UsedVertexB = true; result.SetBarycentricCoordinates(FP.One - v, v, FP.Zero, FP.Zero); return(true); //return a + v * ab; // barycentric coordinates (1-v,v,0) } // Check if P in vertex region outside C FP d5 = TSVector.Dot(ab, c); FP d6 = TSVector.Dot(ac, c); if (d6 <= FP.Zero && d5 >= d6) { result.closestPointOnSimplex = c; result.usedVertices.UsedVertexC = true; result.SetBarycentricCoordinates(FP.Zero, FP.Zero, FP.One, FP.Zero); return(true);//c; // barycentric coordinates (0,0,1) } // Check if P in edge region of AC, if so return projection of P onto AC FP vb = d5 * d2 - d1 * d6; if (vb <= FP.Zero && d2 >= FP.Zero && d6 <= FP.Zero) { w = d2 / (d2 - d6); result.closestPointOnSimplex = a + w * ac; result.usedVertices.UsedVertexA = true; result.usedVertices.UsedVertexC = true; result.SetBarycentricCoordinates(FP.One - w, FP.Zero, w, FP.Zero); 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 FP va = d3 * d6 - d5 * d4; FP d34 = d4 - d3; FP d65 = d5 - d6; if (va <= FP.Zero && d34 >= FP.Zero && d65 >= FP.Zero) { w = d34 / (d34 + d65); result.closestPointOnSimplex = b + w * (c - b); result.usedVertices.UsedVertexB = true; result.usedVertices.UsedVertexC = true; result.SetBarycentricCoordinates(FP.Zero, FP.One - w, w, FP.Zero); 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) FP denom = FP.One / (va + vb + vc); v = vb * denom; w = vc * denom; result.closestPointOnSimplex = a + ab * v + ac * w; result.usedVertices.UsedVertexA = true; result.usedVertices.UsedVertexB = true; result.usedVertices.UsedVertexC = true; result.SetBarycentricCoordinates(FP.One - v - w, v, w, FP.Zero); return(true); }
public bool ClosestPtPointTetrahedron(TSVector a, TSVector b, TSVector c, TSVector d, ref SubSimplexClosestResult finalResult) { tempResult.Reset(); // Start out assuming point inside all halfspaces, so closest to itself finalResult.closestPointOnSimplex = TSVector.zero; finalResult.usedVertices.Reset(); finalResult.usedVertices.UsedVertexA = true; finalResult.usedVertices.UsedVertexB = true; finalResult.usedVertices.UsedVertexC = true; finalResult.usedVertices.UsedVertexD = true; int pointOutsideABC = PointOutsideOfPlane(a, b, c, d); int pointOutsideACD = PointOutsideOfPlane(a, c, d, b); int pointOutsideADB = PointOutsideOfPlane(a, d, b, c); int pointOutsideBDC = PointOutsideOfPlane(b, d, c, a); if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0) { finalResult.degenerate = true; return(false); } if (pointOutsideABC == 0 && pointOutsideACD == 0 && pointOutsideADB == 0 && pointOutsideBDC == 0) { return(false); } FP bestSqDist = FP.MaxValue; // If point outside face abc then compute closest point on abc if (pointOutsideABC != 0) { ClosestPtPointTriangle(a, b, c, ref tempResult); TSVector q = tempResult.closestPointOnSimplex; FP sqDist = q.sqrMagnitude; // Update best closest point if (squared) distance is less than current best if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.closestPointOnSimplex = q; //convert result bitmask! finalResult.usedVertices.Reset(); finalResult.usedVertices.UsedVertexA = tempResult.usedVertices.UsedVertexA; finalResult.usedVertices.UsedVertexB = tempResult.usedVertices.UsedVertexB; finalResult.usedVertices.UsedVertexC = tempResult.usedVertices.UsedVertexC; finalResult.SetBarycentricCoordinates( tempResult.barycentricCoords[VertexA], tempResult.barycentricCoords[VertexB], tempResult.barycentricCoords[VertexC], FP.Zero); } } // Repeat test for face acd if (pointOutsideACD != 0) { ClosestPtPointTriangle(a, c, d, ref tempResult); TSVector q = tempResult.closestPointOnSimplex; //convert result bitmask! FP sqDist = q.sqrMagnitude; if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.closestPointOnSimplex = q; finalResult.usedVertices.Reset(); finalResult.usedVertices.UsedVertexA = tempResult.usedVertices.UsedVertexA; finalResult.usedVertices.UsedVertexC = tempResult.usedVertices.UsedVertexB; finalResult.usedVertices.UsedVertexD = tempResult.usedVertices.UsedVertexC; finalResult.SetBarycentricCoordinates( tempResult.barycentricCoords[VertexA], FP.Zero, tempResult.barycentricCoords[VertexB], tempResult.barycentricCoords[VertexC]); } } // Repeat test for face adb if (pointOutsideADB != 0) { ClosestPtPointTriangle(a, d, b, ref tempResult); TSVector q = tempResult.closestPointOnSimplex; //convert result bitmask! FP sqDist = q.sqrMagnitude; if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.closestPointOnSimplex = q; finalResult.usedVertices.Reset(); finalResult.usedVertices.UsedVertexA = tempResult.usedVertices.UsedVertexA; finalResult.usedVertices.UsedVertexD = tempResult.usedVertices.UsedVertexB; finalResult.usedVertices.UsedVertexB = tempResult.usedVertices.UsedVertexC; finalResult.SetBarycentricCoordinates( tempResult.barycentricCoords[VertexA], tempResult.barycentricCoords[VertexC], FP.Zero, tempResult.barycentricCoords[VertexB]); } } // Repeat test for face bdc if (pointOutsideBDC != 0) { ClosestPtPointTriangle(b, d, c, ref tempResult); TSVector q = tempResult.closestPointOnSimplex; //convert result bitmask! FP sqDist = q.sqrMagnitude; if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.closestPointOnSimplex = q; finalResult.usedVertices.Reset(); finalResult.usedVertices.UsedVertexB = tempResult.usedVertices.UsedVertexA; finalResult.usedVertices.UsedVertexD = tempResult.usedVertices.UsedVertexB; finalResult.usedVertices.UsedVertexC = tempResult.usedVertices.UsedVertexC; finalResult.SetBarycentricCoordinates( FP.Zero, tempResult.barycentricCoords[VertexA], tempResult.barycentricCoords[VertexC], tempResult.barycentricCoords[VertexB]); } } //help! we ended up full ! if (finalResult.usedVertices.UsedVertexA && finalResult.usedVertices.UsedVertexB && finalResult.usedVertices.UsedVertexC && finalResult.usedVertices.UsedVertexD) { return(true); } return(true); }
public bool UpdateClosestVectorAndPoints() { if (_needsUpdate) { _cachedBC.Reset(); _needsUpdate = false; TSVector p, a, b, c, d; switch (NumVertices) { case 0: _cachedValidClosest = false; break; case 1: _cachedPA = _simplexPointsP[0]; _cachedPB = _simplexPointsQ[0]; _cachedV = _cachedPA - _cachedPB; _cachedBC.Reset(); _cachedBC.SetBarycentricCoordinates(FP.One, FP.Zero, FP.Zero, FP.Zero); _cachedValidClosest = _cachedBC.IsValid; break; case 2: //closest point origin from line segment TSVector from = _simplexVectorW[0]; TSVector to = _simplexVectorW[1]; //TSVector nearest; TSVector diff = TSVector.Negate(from); TSVector v = to - from; FP t = TSVector.Dot(v, diff); if (t > FP.Zero) { FP dotVV = v.sqrMagnitude; if (t < dotVV) { t /= dotVV; diff -= t * v; _cachedBC.usedVertices.UsedVertexA = true; _cachedBC.usedVertices.UsedVertexB = true; } else { t = FP.One; diff -= v; //reduce to 1 point _cachedBC.usedVertices.UsedVertexB = true; } } else { t = FP.Zero; //reduce to 1 point _cachedBC.usedVertices.UsedVertexA = true; } _cachedBC.SetBarycentricCoordinates(FP.One - t, t, FP.Zero, FP.Zero); //nearest = from + t * v; _cachedPA = _simplexPointsP[0] + t * (_simplexPointsP[1] - _simplexPointsP[0]); _cachedPB = _simplexPointsQ[0] + t * (_simplexPointsQ[1] - _simplexPointsQ[0]); _cachedV = _cachedPA - _cachedPB; ReduceVertices(_cachedBC.usedVertices); _cachedValidClosest = _cachedBC.IsValid; break; case 3: //closest point origin from triangle a = _simplexVectorW[0]; b = _simplexVectorW[1]; c = _simplexVectorW[2]; ClosestPtPointTriangle(a, b, c, ref _cachedBC); _cachedPA = _simplexPointsP[0] * _cachedBC.barycentricCoords[0] + _simplexPointsP[1] * _cachedBC.barycentricCoords[1] + _simplexPointsP[2] * _cachedBC.barycentricCoords[2]; _cachedPB = _simplexPointsQ[0] * _cachedBC.barycentricCoords[0] + _simplexPointsQ[1] * _cachedBC.barycentricCoords[1] + _simplexPointsQ[2] * _cachedBC.barycentricCoords[2]; _cachedV = _cachedPA - _cachedPB; ReduceVertices(_cachedBC.usedVertices); _cachedValidClosest = _cachedBC.IsValid; break; case 4: a = _simplexVectorW[0]; b = _simplexVectorW[1]; c = _simplexVectorW[2]; d = _simplexVectorW[3]; bool hasSeparation = ClosestPtPointTetrahedron(a, b, c, d, ref _cachedBC); if (hasSeparation) { _cachedPA = _simplexPointsP[0] * _cachedBC.barycentricCoords[0] + _simplexPointsP[1] * _cachedBC.barycentricCoords[1] + _simplexPointsP[2] * _cachedBC.barycentricCoords[2] + _simplexPointsP[3] * _cachedBC.barycentricCoords[3]; _cachedPB = _simplexPointsQ[0] * _cachedBC.barycentricCoords[0] + _simplexPointsQ[1] * _cachedBC.barycentricCoords[1] + _simplexPointsQ[2] * _cachedBC.barycentricCoords[2] + _simplexPointsQ[3] * _cachedBC.barycentricCoords[3]; _cachedV = _cachedPA - _cachedPB; ReduceVertices(_cachedBC.usedVertices); } else { if (_cachedBC.degenerate) { _cachedValidClosest = false; } else { _cachedValidClosest = true; //degenerate case == false, penetration = true + zero _cachedV.x = _cachedV.y = _cachedV.z = FP.Zero; } break; // !!!!!!!!!!!! proverit na vsakiy sluchai } _cachedValidClosest = _cachedBC.IsValid; //closest point origin from tetrahedron break; default: _cachedValidClosest = false; break; } } return(_cachedValidClosest); }