7 #include "imstkClosedSurfaceMeshToMeshCD.h" 8 #include "imstkCollisionUtils.h" 9 #include "imstkLineMesh.h" 10 #include "imstkSurfaceMesh.h" 11 #include "imstkVecDataArray.h" 13 #include <unordered_set> 22 EdgePair(uint32_t a1, uint32_t a2, uint32_t b1, uint32_t b2)
39 return (edgeAId == other.edgeAId && edgeBId == other.edgeBId)
40 || (edgeAId == other.edgeBId && edgeBId == other.edgeAId);
45 const uint32_t getIdA()
const 47 const uint32_t max = std::max(edgeA[0], edgeA[1]);
48 const uint32_t min = std::min(edgeA[0], edgeA[1]);
49 return max * (max + 1) / 2 + min;
52 const uint32_t getIdB()
const 54 const uint32_t max = std::max(edgeB[0], edgeB[1]);
55 const uint32_t min = std::min(edgeB[0], edgeB[1]);
56 return max * (max + 1) / 2 + min;
82 return (k.edgeAId ^ (k.edgeBId << 16));
94 std::shared_ptr<PointSet> m_pointSet;
103 std::shared_ptr<SurfaceMesh> m_surfMesh;
106 const std::vector<std::unordered_set<int>>& vertexFaces;
110 PointSetData::PointSetData(std::shared_ptr<PointSet> pointSet) :
111 m_pointSet(pointSet),
112 vertices(*pointSet->getVertexPositions())
116 SurfMeshData::SurfMeshData(std::shared_ptr<SurfaceMesh> surfMesh) :
117 m_surfMesh(surfMesh),
118 cells(*surfMesh->getCells()),
119 vertices(*surfMesh->getVertexPositions()),
120 vertexFaces(surfMesh->getVertexToCellMap()),
121 faceNormals(*surfMesh->getCellNormals())
129 vertexPseudoNormalFromTriangle(
const int vertexIndex,
const SurfMeshData& surfMeshData)
134 Vec3d nSum = Vec3d::Zero();
135 for (
int neighborFaceIndex : surfMeshData.vertexFaces[vertexIndex])
137 Vec3i cell = surfMeshData.cells[neighborFaceIndex];
139 if (cell[1] == vertexIndex)
141 std::swap(cell[0], cell[1]);
143 else if (cell[2] == vertexIndex)
145 std::swap(cell[0], cell[2]);
148 const Vec3d ab = (surfMeshData.vertices[cell[1]] - surfMeshData.vertices[vertexIndex]).normalized();
149 const Vec3d bc = (surfMeshData.vertices[cell[2]] - surfMeshData.vertices[vertexIndex]).normalized();
150 const double angle = acos(ab.dot(bc));
151 const Vec3d n = angle * surfMeshData.faceNormals[neighborFaceIndex];
163 edgePseudoNormalFromTriangle(
const Vec2i& vertexIds,
const SurfMeshData& surfMeshData)
167 Vec3d nSum = Vec3d::Zero();
168 for (
int neighborFaceIndex : surfMeshData.vertexFaces[vertexIds[0]])
170 const Vec3i& cell = surfMeshData.cells[neighborFaceIndex];
171 bool found[2] = {
false,
false };
172 for (
int j = 0; j < 3; j++)
174 if (cell[j] == vertexIds[0])
178 else if (cell[j] == vertexIds[1])
184 if (found[0] && found[1])
186 const Vec3d n = PI * surfMeshData.faceNormals[neighborFaceIndex];
204 polySignedDist(
const Vec3d& pos,
const SurfMeshData& surfMeshData,
205 int& caseType, Vec3i& vIds,
int& closestCell)
208 Vec3d closestPt = Vec3d::Zero();
209 double minSqrDist = IMSTK_DOUBLE_MAX;
210 int closestCellCase = -1;
214 for (
int j = 0; j < surfMeshData.cells.size(); j++)
216 const Vec3i& cell = surfMeshData.cells[j];
217 const Vec3d& x1 = surfMeshData.vertices[cell[0]];
218 const Vec3d& x2 = surfMeshData.vertices[cell[1]];
219 const Vec3d& x3 = surfMeshData.vertices[cell[2]];
221 int ptOnTriangleCaseType;
222 const Vec3d closestPtOnTri = CollisionUtils::closestPointOnTriangle(pos, x1, x2, x3, ptOnTriangleCaseType);
223 const double sqrDist = (closestPtOnTri - pos).squaredNorm();
224 if (sqrDist < minSqrDist)
226 minSqrDist = sqrDist;
227 closestPt = closestPtOnTri;
229 closestCellCase = ptOnTriangleCaseType;
238 if (closestCellCase == 0 || closestCellCase == 1 || closestCellCase == 2)
240 int vertexIndex = surfMeshData.cells[closestCell][0];
241 if (closestCellCase == 1)
243 vertexIndex = surfMeshData.cells[closestCell][1];
245 else if (closestCellCase == 2)
247 vertexIndex = surfMeshData.cells[closestCell][2];
250 const Vec3d psuedoN = vertexPseudoNormalFromTriangle(vertexIndex, surfMeshData);
252 vIds[0] = vertexIndex;
253 return (pos - closestPt).dot(psuedoN);
256 else if (closestCellCase == 3 || closestCellCase == 4 || closestCellCase == 5)
258 Vec2i vertexIds = { surfMeshData.cells[closestCell][0], surfMeshData.cells[closestCell][1] };
259 if (closestCellCase == 4)
261 vertexIds = { surfMeshData.cells[closestCell][1], surfMeshData.cells[closestCell][2] };
263 else if (closestCellCase == 5)
265 vertexIds = { surfMeshData.cells[closestCell][2], surfMeshData.cells[closestCell][0] };
268 const Vec3d psuedoN = edgePseudoNormalFromTriangle(vertexIds, surfMeshData);
270 vIds[0] = vertexIds[0];
271 vIds[1] = vertexIds[1];
272 return (pos - closestPt).dot(psuedoN);
275 else if (closestCellCase == 6)
278 const Vec3d psuedoN = surfMeshData.faceNormals[closestCell];
280 vIds[0] = surfMeshData.cells[closestCell][0];
281 vIds[1] = surfMeshData.cells[closestCell][1];
282 vIds[2] = surfMeshData.cells[closestCell][2];
283 return (pos - closestPt).dot(psuedoN);
289 return IMSTK_DOUBLE_MAX;
293 ClosedSurfaceMeshToMeshCD::ClosedSurfaceMeshToMeshCD()
295 setRequiredInputType<PointSet>(0);
296 setRequiredInputType<SurfaceMesh>(1);
301 std::shared_ptr<Geometry> geomA,
302 std::shared_ptr<Geometry> geomB,
303 std::vector<CollisionElement>& elementsA,
304 std::vector<CollisionElement>& elementsB)
307 if (doBroadPhaseCollisionCheck(geomA, geomB))
309 auto pointSet = std::dynamic_pointer_cast<
PointSet>(geomA);
310 auto surfMesh = std::dynamic_pointer_cast<
SurfaceMesh>(geomB);
312 surfMesh->computeVertexToCellMap();
315 if (m_generateVertexTriangleContacts)
317 if (m_vertexInside.size() < pointSet->getNumVertices())
319 m_vertexInside = std::vector<bool>(pointSet->getNumVertices(),
false);
321 if (m_signedDistances.size() < pointSet->getNumVertices())
326 vertexToTriangleTest(geomA, geomB, elementsA, elementsB);
328 if (m_generateEdgeEdgeContacts)
330 if (geomA->getTypeName() == LineMesh::getStaticTypeName())
332 lineMeshEdgeToTriangleTest(geomA, geomB, elementsA, elementsB);
334 else if (geomA->getTypeName() == SurfaceMesh::getStaticTypeName())
336 surfMeshEdgeToTriangleTest(geomA, geomB, elementsA, elementsB);
344 ClosedSurfaceMeshToMeshCD::vertexToTriangleTest(
345 std::shared_ptr<Geometry> geomA,
346 std::shared_ptr<Geometry> geomB,
347 std::vector<CollisionElement>& elementsA,
348 std::vector<CollisionElement>& elementsB)
350 PointSetData pointSetData(std::dynamic_pointer_cast<PointSet>(geomA));
351 SurfMeshData surfMeshData(std::dynamic_pointer_cast<SurfaceMesh>(geomB));
354 for (
int i = 0; i < pointSetData.vertices.size(); i++)
356 const Vec3d& p = pointSetData.vertices[i];
359 int closestCell = -1;
360 Vec3i vertexIds = Vec3i::Zero();
361 const double signedDist = polySignedDist(p, surfMeshData, caseType, vertexIds, closestCell);
362 m_signedDistances[i] = signedDist;
363 if (signedDist <= 0.0)
365 m_vertexInside[i] =
true;
372 elemA.cellType = IMSTK_VERTEX;
375 elemB.ids[0] = vertexIds[0];
376 elemB.parentId = closestCell;
378 elemB.cellType = IMSTK_VERTEX;
380 elementsA.push_back(elemA);
381 elementsB.push_back(elemB);
384 else if (caseType == 1)
389 elemA.cellType = IMSTK_VERTEX;
392 elemB.ids[0] = vertexIds[0];
393 elemB.ids[1] = vertexIds[1];
394 elemB.parentId = closestCell;
396 elemB.cellType = IMSTK_EDGE;
398 elementsA.push_back(elemA);
399 elementsB.push_back(elemB);
402 else if (caseType == 2)
407 elemA.cellType = IMSTK_VERTEX;
410 elemB.ids[0] = vertexIds[0];
411 elemB.ids[1] = vertexIds[1];
412 elemB.ids[2] = vertexIds[2];
413 elemB.parentId = closestCell;
415 elemB.cellType = IMSTK_TRIANGLE;
417 elementsA.push_back(elemA);
418 elementsB.push_back(elemB);
423 m_vertexInside[i] =
false;
429 ClosedSurfaceMeshToMeshCD::lineMeshEdgeToTriangleTest(
430 std::shared_ptr<Geometry> geomA,
431 std::shared_ptr<Geometry> geomB,
432 std::vector<CollisionElement>& elementsA,
433 std::vector<CollisionElement>& elementsB)
435 SurfMeshData surfMeshBData(std::dynamic_pointer_cast<SurfaceMesh>(geomB));
438 std::shared_ptr<LineMesh> lineMesh = std::dynamic_pointer_cast<
LineMesh>(geomA);
439 std::shared_ptr<VecDataArray<double, 3>> meshAVerticesPtr = lineMesh->
getVertexPositions();
441 std::shared_ptr<VecDataArray<int, 2>> meshACellsPtr = lineMesh->getCells();
444 const int triEdgePattern[3][2] = { { 0, 1 }, { 1, 2 }, { 2, 0 } };
447 for (
int i = 0; i < meshACells.size(); i++)
449 const Vec2i& edgeA = meshACells[i];
452 if (!m_vertexInside[edgeA[0]] && !m_vertexInside[edgeA[1]])
454 double minSqrDist = IMSTK_DOUBLE_MAX;
455 int closestTriId = -1;
456 int closestEdgeId = -1;
459 for (
int j = 0; j < surfMeshBData.cells.size(); j++)
461 const Vec3i& cellB = surfMeshBData.cells[j];
464 for (
int k = 0; k < 3; k++)
466 const Vec2i edgeB(cellB[triEdgePattern[k][0]], cellB[triEdgePattern[k][1]]);
471 if (CollisionUtils::edgeToEdgeClosestPoints(
472 meshAVertices[edgeA[0]], meshAVertices[edgeA[1]],
473 surfMeshBData.vertices[edgeB[0]], surfMeshBData.vertices[edgeB[1]],
477 const double sqrDist = (ptB - ptA).squaredNorm();
479 if (sqrDist < minSqrDist)
483 int closestCell = -1;
484 Vec3i vIds = Vec3i::Zero();
485 const double signedDist = polySignedDist(ptA, surfMeshBData, caseType, vIds, closestCell);
486 if (signedDist <= 0.0)
488 minSqrDist = sqrDist;
497 if (closestTriId != -1)
500 elemA.ids[0] = edgeA[0];
501 elemA.ids[1] = edgeA[1];
504 elemA.cellType = IMSTK_EDGE;
507 elemB.ids[0] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][0]];
508 elemB.ids[1] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][1]];
509 elemB.parentId = closestTriId;
511 elemB.cellType = IMSTK_EDGE;
513 elementsA.push_back(elemA);
514 elementsB.push_back(elemB);
521 ClosedSurfaceMeshToMeshCD::surfMeshEdgeToTriangleTest(
522 std::shared_ptr<Geometry> geomA,
523 std::shared_ptr<Geometry> geomB,
524 std::vector<CollisionElement>& elementsA,
525 std::vector<CollisionElement>& elementsB)
527 SurfMeshData surfMeshBData(std::dynamic_pointer_cast<SurfaceMesh>(geomB));
530 std::shared_ptr<SurfaceMesh> surfMeshA = std::dynamic_pointer_cast<
SurfaceMesh>(geomA);
531 std::shared_ptr<VecDataArray<double, 3>> meshAVerticesPtr = surfMeshA->
getVertexPositions();
533 std::shared_ptr<VecDataArray<int, 3>> meshACellsPtr = surfMeshA->getCells();
536 std::unordered_set<EdgePair> hashedEdges;
549 const int triEdgePattern[3][2] = { { 0, 1 }, { 1, 2 }, { 2, 0 } };
550 int edgeCheckCount = 0;
551 if (m_generateEdgeEdgeContacts)
554 for (
int i = 0; i < meshACells.size(); i++)
556 const Vec3i& cellA = meshACells[i];
559 for (
int j = 0; j < 3; j++)
561 const Vec2i edgeA = Vec2i(cellA[triEdgePattern[j][0]], cellA[triEdgePattern[j][1]]);
564 if (!m_vertexInside[edgeA[0]] && !m_vertexInside[edgeA[1]])
566 double minSqrDist = IMSTK_DOUBLE_MAX;
567 int closestTriId = -1;
568 int closestEdgeId = -1;
571 if (m_proximity <= 0.0 || (m_signedDistances[edgeA[0]] < m_proximity && m_signedDistances[edgeA[1]] < m_proximity))
575 for (
int k = 0; k < surfMeshBData.cells.size(); k++)
577 const Vec3i& cellB = surfMeshBData.cells[k];
580 for (
int edgeId = 0; edgeId < 3; edgeId++)
582 const Vec2i edgeB(cellB[triEdgePattern[edgeId][0]], cellB[triEdgePattern[edgeId][1]]);
587 if (CollisionUtils::edgeToEdgeClosestPoints(
588 meshAVertices[edgeA[0]], meshAVertices[edgeA[1]],
589 surfMeshBData.vertices[edgeB[0]], surfMeshBData.vertices[edgeB[1]],
593 const double sqrDist = (ptB - ptA).squaredNorm();
595 if (sqrDist < minSqrDist)
599 int closestCell = -1;
600 Vec3i vIds = Vec3i::Zero();
601 const double signedDist = polySignedDist(ptA, surfMeshBData, caseType, vIds, closestCell);
602 if (signedDist <= 0.0)
604 minSqrDist = sqrDist;
606 closestEdgeId = edgeId;
614 if (closestTriId != -1)
619 surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][0]],
620 surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][1]]);
621 if (hashedEdges.count(edgePair) == 0)
624 elemA.ids[0] = edgeA[0];
625 elemA.ids[1] = edgeA[1];
628 elemA.cellType = IMSTK_EDGE;
631 elemB.ids[0] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][0]];
632 elemB.ids[1] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][1]];
633 elemB.parentId = closestTriId;
635 elemB.cellType = IMSTK_EDGE;
637 elementsA.push_back(elemA);
638 elementsB.push_back(elemB);
640 hashedEdges.insert(edgePair);
650 ClosedSurfaceMeshToMeshCD::doBroadPhaseCollisionCheck(
651 std::shared_ptr<Geometry> geomA,
652 std::shared_ptr<Geometry> geomB)
const 659 const auto mesh1 = std::dynamic_pointer_cast<
PointSet>(geomA);
660 const auto mesh2 = std::dynamic_pointer_cast<
PointSet>(geomB);
663 if (mesh1->getNumVertices() == 1 || mesh2->getNumVertices() == 1)
672 mesh2->computeBoundingBox(min2, max2);
680 return CollisionUtils::testAabbToAabb(
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Hash together a pair of edges.
bool operator==(const EdgePair &other) const
Reversible edges are equivalent, reversible vertices in the edges are equivalent as well EdgePair(0...
virtual void computeBoundingBox(Vec3d &lowerCorner, Vec3d &upperCorner, const double paddingPercent=0.0) override
Compute the bounding box for the entire mesh.
Returns a hash value for a PointEntry.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
Base class for all volume mesh types.
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
Represents a cell by a single cell id OR by N vertex ids. Which case can be determined by the idCount...
void computeCollisionDataAB(std::shared_ptr< Geometry > geomA, std::shared_ptr< Geometry > geomB, std::vector< CollisionElement > &elementsA, std::vector< CollisionElement > &elementsB) override
Compute collision data for AB simultaneously.
void computeTrianglesNormals()
Compute the normals of all the triangles.