iMSTK
Interactive Medical Simulation Toolkit
imstkClosedSurfaceMeshToMeshCD.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkClosedSurfaceMeshToMeshCD.h"
8 #include "imstkCollisionUtils.h"
9 #include "imstkLineMesh.h"
10 #include "imstkSurfaceMesh.h"
11 #include "imstkVecDataArray.h"
12 
13 #include <unordered_set>
14 
15 namespace imstk
16 {
20 struct EdgePair
21 {
22  EdgePair(uint32_t a1, uint32_t a2, uint32_t b1, uint32_t b2)
23  {
24  edgeA[0] = a1;
25  edgeA[1] = a2;
26  edgeB[0] = b1;
27  edgeB[1] = b2;
28 
29  edgeAId = getIdA();
30  edgeBId = getIdB();
31  }
32 
37  bool operator==(const EdgePair& other) const
38  {
39  return (edgeAId == other.edgeAId && edgeBId == other.edgeBId)
40  || (edgeAId == other.edgeBId && edgeBId == other.edgeAId);
41  }
42 
43  // These functions return a unique int for an edge, order doesn't matter
44  // ie: f(vertexId1, vertexId2)=f(vertexId2, vertexId1)
45  const uint32_t getIdA() const
46  {
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;
50  }
51 
52  const uint32_t getIdB() const
53  {
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;
57  }
58 
59  uint32_t edgeA[2];
60  uint32_t edgeAId;
61  uint32_t edgeB[2];
62  uint32_t edgeBId;
63 };
64 } // namespace imstk
65 
66 namespace std
67 {
68 template<>
70 {
71  // EdgePair has 4 uints to hash, they bound the same range, 0 to max vertices of a mesh
72  // A complete unique hash split into 4, would limit us to 256 max vertices so we will have
73  // collisions but they will be unlikely given small portions of the mesh are in contact at
74  // any one time
75  std::size_t operator()(const imstk::EdgePair& k) const
76  {
77  // Shift by 8 each time, there will be overlap every 256 ints
78  //return ((k.edgeA[0] ^ (k.edgeA[1] << 8)) ^ (k.edgeB[0] << 16)) ^ (k.edgeB[1] << 24);
79 
80  // The edge ids are more compact since f(1,0)=f(0,1) there are fewer permutations,
81  // This should allow up to ~360 max vertices..., not that much better
82  return (k.edgeAId ^ (k.edgeBId << 16));
83  }
84 };
85 } // namespace std
86 
87 namespace imstk
88 {
90 {
91  PointSetData(std::shared_ptr<PointSet> pointSet);
92 
93  // Get geometry A data
94  std::shared_ptr<PointSet> m_pointSet;
95  const VecDataArray<double, 3>& vertices;
96 };
97 
99 {
100  SurfMeshData(std::shared_ptr<SurfaceMesh> surfMesh);
101 
102  // Get geometry B data
103  std::shared_ptr<SurfaceMesh> m_surfMesh;
104  const VecDataArray<int, 3>& cells;
105  const VecDataArray<double, 3>& vertices;
106  const std::vector<std::unordered_set<int>>& vertexFaces;
107  const VecDataArray<double, 3>& faceNormals;
108 };
109 
110 PointSetData::PointSetData(std::shared_ptr<PointSet> pointSet) :
111  m_pointSet(pointSet),
112  vertices(*pointSet->getVertexPositions())
113 {
114 }
115 
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())
122 {
123 }
124 
128 static Vec3d
129 vertexPseudoNormalFromTriangle(const int vertexIndex, const SurfMeshData& surfMeshData)
130 {
131  // Compute the pseudonormal on the mesh at the point
132  // Identify incident faces to the point and weight sum their normals
133  double sum = 0.0;
134  Vec3d nSum = Vec3d::Zero();
135  for (int neighborFaceIndex : surfMeshData.vertexFaces[vertexIndex])
136  {
137  Vec3i cell = surfMeshData.cells[neighborFaceIndex];
138  // Ensure vertexIndex is in 0
139  if (cell[1] == vertexIndex)
140  {
141  std::swap(cell[0], cell[1]);
142  }
143  else if (cell[2] == vertexIndex)
144  {
145  std::swap(cell[0], cell[2]);
146  }
147 
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];
152 
153  sum += n.norm();
154  nSum += n;
155  }
156  return nSum / sum;
157 }
158 
162 static Vec3d
163 edgePseudoNormalFromTriangle(const Vec2i& vertexIds, const SurfMeshData& surfMeshData)
164 {
165  // Find the two cells that have both vertexIds
166  double sum = 0.0;
167  Vec3d nSum = Vec3d::Zero();
168  for (int neighborFaceIndex : surfMeshData.vertexFaces[vertexIds[0]])
169  {
170  const Vec3i& cell = surfMeshData.cells[neighborFaceIndex];
171  bool found[2] = { false, false };
172  for (int j = 0; j < 3; j++)
173  {
174  if (cell[j] == vertexIds[0])
175  {
176  found[0] = true;
177  }
178  else if (cell[j] == vertexIds[1])
179  {
180  found[1] = true;
181  }
182  }
183  // If it contains both vertices its a face to the edge
184  if (found[0] && found[1])
185  {
186  const Vec3d n = PI * surfMeshData.faceNormals[neighborFaceIndex];
187  sum += n.norm();
188  nSum += n;
189  }
190  }
191  return nSum / sum;
192 }
193 
203 static double
204 polySignedDist(const Vec3d& pos, const SurfMeshData& surfMeshData,
205  int& caseType, Vec3i& vIds, int& closestCell)
206 {
207  closestCell = -1;
208  Vec3d closestPt = Vec3d::Zero();
209  double minSqrDist = IMSTK_DOUBLE_MAX;
210  int closestCellCase = -1;
211 
212  // Find the closest point out of all elements
213  // \todo: We could early reject backface cull all triangles (this is effectively case 6 done early)
214  for (int j = 0; j < surfMeshData.cells.size(); j++)
215  {
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]];
220 
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)
225  {
226  minSqrDist = sqrDist;
227  closestPt = closestPtOnTri;
228  closestCell = j;
229  closestCellCase = ptOnTriangleCaseType;
230  }
231  }
232 
233  // We use the normal of the nearest element to determine sign, but we can't just use the
234  // normal as there are discontinuities at the edges and vertices. We instead use the
235  // "angle-weighted psuedonormal" given adjacent elements
236 
237  // Closest element is a vertex
238  if (closestCellCase == 0 || closestCellCase == 1 || closestCellCase == 2)
239  {
240  int vertexIndex = surfMeshData.cells[closestCell][0]; // a
241  if (closestCellCase == 1)
242  {
243  vertexIndex = surfMeshData.cells[closestCell][1]; // b
244  }
245  else if (closestCellCase == 2)
246  {
247  vertexIndex = surfMeshData.cells[closestCell][2]; // c
248  }
249 
250  const Vec3d psuedoN = vertexPseudoNormalFromTriangle(vertexIndex, surfMeshData);
251  caseType = 0;
252  vIds[0] = vertexIndex;
253  return (pos - closestPt).dot(psuedoN);
254  }
255  // Closest element is an edge
256  else if (closestCellCase == 3 || closestCellCase == 4 || closestCellCase == 5)
257  {
258  Vec2i vertexIds = { surfMeshData.cells[closestCell][0], surfMeshData.cells[closestCell][1] }; // ab
259  if (closestCellCase == 4)
260  {
261  vertexIds = { surfMeshData.cells[closestCell][1], surfMeshData.cells[closestCell][2] }; // bc
262  }
263  else if (closestCellCase == 5)
264  {
265  vertexIds = { surfMeshData.cells[closestCell][2], surfMeshData.cells[closestCell][0] }; // ca
266  }
267 
268  const Vec3d psuedoN = edgePseudoNormalFromTriangle(vertexIds, surfMeshData);
269  caseType = 1;
270  vIds[0] = vertexIds[0];
271  vIds[1] = vertexIds[1];
272  return (pos - closestPt).dot(psuedoN);
273  }
274  // Closest element is the triangle
275  else if (closestCellCase == 6)
276  {
277  //const Vec3d psuedoN = (2.0 * PI * faceNormals[closestCell]).normalized();
278  const Vec3d psuedoN = surfMeshData.faceNormals[closestCell]; // Assume normalized
279  caseType = 2;
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);
284  }
285  // Should only ever occur if there are no elements
286  else
287  {
288  caseType = -1;
289  return IMSTK_DOUBLE_MAX;
290  }
291 }
292 
293 ClosedSurfaceMeshToMeshCD::ClosedSurfaceMeshToMeshCD()
294 {
295  setRequiredInputType<PointSet>(0);
296  setRequiredInputType<SurfaceMesh>(1);
297 }
298 
299 void
301  std::shared_ptr<Geometry> geomA,
302  std::shared_ptr<Geometry> geomB,
303  std::vector<CollisionElement>& elementsA,
304  std::vector<CollisionElement>& elementsB)
305 {
306  // Broad phase collision
307  if (doBroadPhaseCollisionCheck(geomA, geomB))
308  {
309  auto pointSet = std::dynamic_pointer_cast<PointSet>(geomA);
310  auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(geomB);
311  surfMesh->computeTrianglesNormals();
312  surfMesh->computeVertexToCellMap();
313 
314  // Narrow phase
315  if (m_generateVertexTriangleContacts)
316  {
317  if (m_vertexInside.size() < pointSet->getNumVertices())
318  {
319  m_vertexInside = std::vector<bool>(pointSet->getNumVertices(), false);
320  }
321  if (m_signedDistances.size() < pointSet->getNumVertices())
322  {
323  m_signedDistances = DataArray<double>(pointSet->getNumVertices());
324  }
325 
326  vertexToTriangleTest(geomA, geomB, elementsA, elementsB);
327 
328  if (m_generateEdgeEdgeContacts)
329  {
330  if (geomA->getTypeName() == LineMesh::getStaticTypeName())
331  {
332  lineMeshEdgeToTriangleTest(geomA, geomB, elementsA, elementsB);
333  }
334  else if (geomA->getTypeName() == SurfaceMesh::getStaticTypeName())
335  {
336  surfMeshEdgeToTriangleTest(geomA, geomB, elementsA, elementsB);
337  }
338  }
339  }
340  }
341 }
342 
343 void
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)
349 {
350  PointSetData pointSetData(std::dynamic_pointer_cast<PointSet>(geomA));
351  SurfMeshData surfMeshData(std::dynamic_pointer_cast<SurfaceMesh>(geomB));
352 
353  // For every vertex
354  for (int i = 0; i < pointSetData.vertices.size(); i++)
355  {
356  const Vec3d& p = pointSetData.vertices[i];
357 
358  int caseType = -1;
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)
364  {
365  m_vertexInside[i] = true;
366  // The nearest feature to this vertex is another vertex
367  if (caseType == 0)
368  {
369  CellIndexElement elemA;
370  elemA.ids[0] = i;
371  elemA.idCount = 1;
372  elemA.cellType = IMSTK_VERTEX;
373 
374  CellIndexElement elemB;
375  elemB.ids[0] = vertexIds[0];
376  elemB.parentId = closestCell; // Triangle id
377  elemB.idCount = 1;
378  elemB.cellType = IMSTK_VERTEX;
379 
380  elementsA.push_back(elemA);
381  elementsB.push_back(elemB);
382  }
383  // The nearest feature to this vertex is an edge
384  else if (caseType == 1)
385  {
386  CellIndexElement elemA;
387  elemA.ids[0] = i;
388  elemA.idCount = 1;
389  elemA.cellType = IMSTK_VERTEX;
390 
391  CellIndexElement elemB;
392  elemB.ids[0] = vertexIds[0];
393  elemB.ids[1] = vertexIds[1];
394  elemB.parentId = closestCell; // Triangle id
395  elemB.idCount = 2;
396  elemB.cellType = IMSTK_EDGE;
397 
398  elementsA.push_back(elemA);
399  elementsB.push_back(elemB);
400  }
401  // The nearest feature to this vertex is a triangle face
402  else if (caseType == 2)
403  {
404  CellIndexElement elemA;
405  elemA.ids[0] = i;
406  elemA.idCount = 1;
407  elemA.cellType = IMSTK_VERTEX;
408 
409  CellIndexElement elemB;
410  elemB.ids[0] = vertexIds[0];
411  elemB.ids[1] = vertexIds[1];
412  elemB.ids[2] = vertexIds[2];
413  elemB.parentId = closestCell; // Triangle id
414  elemB.idCount = 3;
415  elemB.cellType = IMSTK_TRIANGLE;
416 
417  elementsA.push_back(elemA);
418  elementsB.push_back(elemB);
419  }
420  }
421  else
422  {
423  m_vertexInside[i] = false;
424  }
425  }
426 }
427 
428 void
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)
434 {
435  SurfMeshData surfMeshBData(std::dynamic_pointer_cast<SurfaceMesh>(geomB));
436 
437  // Get geometry A data
438  std::shared_ptr<LineMesh> lineMesh = std::dynamic_pointer_cast<LineMesh>(geomA);
439  std::shared_ptr<VecDataArray<double, 3>> meshAVerticesPtr = lineMesh->getVertexPositions();
440  const VecDataArray<double, 3>& meshAVertices = *meshAVerticesPtr;
441  std::shared_ptr<VecDataArray<int, 2>> meshACellsPtr = lineMesh->getCells();
442  VecDataArray<int, 2>& meshACells = *meshACellsPtr;
443 
444  const int triEdgePattern[3][2] = { { 0, 1 }, { 1, 2 }, { 2, 0 } };
445 
446  // For every edge/line segment of the line mesh
447  for (int i = 0; i < meshACells.size(); i++)
448  {
449  const Vec2i& edgeA = meshACells[i];
450 
451  // Only check edges that don't exist totally inside
452  if (!m_vertexInside[edgeA[0]] && !m_vertexInside[edgeA[1]])
453  {
454  double minSqrDist = IMSTK_DOUBLE_MAX;
455  int closestTriId = -1;
456  int closestEdgeId = -1;
457 
458  // For every triangle/cell of meshB
459  for (int j = 0; j < surfMeshBData.cells.size(); j++)
460  {
461  const Vec3i& cellB = surfMeshBData.cells[j];
462 
463  // For every edge of that triangle
464  for (int k = 0; k < 3; k++)
465  {
466  const Vec2i edgeB(cellB[triEdgePattern[k][0]], cellB[triEdgePattern[k][1]]);
467 
468  // Compute the closest point on the two edges
469  // Check the case, the edges must be within each others bounds/ranges
470  Vec3d ptA, ptB;
471  if (CollisionUtils::edgeToEdgeClosestPoints(
472  meshAVertices[edgeA[0]], meshAVertices[edgeA[1]],
473  surfMeshBData.vertices[edgeB[0]], surfMeshBData.vertices[edgeB[1]],
474  ptA, ptB) == 0)
475  {
476  // Find the closest element to this point on the edge
477  const double sqrDist = (ptB - ptA).squaredNorm();
478  // Use the closest one only
479  if (sqrDist < minSqrDist)
480  {
481  // Check if the point on the oppositie edge nearest to edgeB is inside B
482  int caseType = -1;
483  int closestCell = -1;
484  Vec3i vIds = Vec3i::Zero();
485  const double signedDist = polySignedDist(ptA, surfMeshBData, caseType, vIds, closestCell);
486  if (signedDist <= 0.0)
487  {
488  minSqrDist = sqrDist;
489  closestTriId = j;
490  closestEdgeId = k;
491  }
492  }
493  }
494  }
495  }
496 
497  if (closestTriId != -1)
498  {
499  CellIndexElement elemA;
500  elemA.ids[0] = edgeA[0];
501  elemA.ids[1] = edgeA[1];
502  elemA.parentId = i; // Edge id
503  elemA.idCount = 2;
504  elemA.cellType = IMSTK_EDGE;
505 
506  CellIndexElement elemB;
507  elemB.ids[0] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][0]];
508  elemB.ids[1] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][1]];
509  elemB.parentId = closestTriId; // Triangle id
510  elemB.idCount = 2;
511  elemB.cellType = IMSTK_EDGE;
512 
513  elementsA.push_back(elemA);
514  elementsB.push_back(elemB);
515  }
516  }
517  }
518 }
519 
520 void
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)
526 {
527  SurfMeshData surfMeshBData(std::dynamic_pointer_cast<SurfaceMesh>(geomB));
528 
529  // Get geometry A data
530  std::shared_ptr<SurfaceMesh> surfMeshA = std::dynamic_pointer_cast<SurfaceMesh>(geomA);
531  std::shared_ptr<VecDataArray<double, 3>> meshAVerticesPtr = surfMeshA->getVertexPositions();
532  const VecDataArray<double, 3>& meshAVertices = *meshAVerticesPtr;
533  std::shared_ptr<VecDataArray<int, 3>> meshACellsPtr = surfMeshA->getCells();
534  VecDataArray<int, 3>& meshACells = *meshACellsPtr;
535 
536  std::unordered_set<EdgePair> hashedEdges;
537 
538  // We find the nearest points on every edge with every other edge. Sampling this point we
539  // can determine the signed distance and whether that edge is "inside" another.
540  //
541  // We choose the nearest edge to resolve. Unfortunately we resolving to the nearest doesn't
542  // give the same effect as in the vertex-triangle case.
543  //
544  // This works so long as the edges don't move too far past each other.
545  // This is ultimately an effect of not having signs on the edges.
546  //
547  // Additionally we don't check edges whose vertices are already inside the closed surface (determined
548  // in the vertex-triangle pass)
549  const int triEdgePattern[3][2] = { { 0, 1 }, { 1, 2 }, { 2, 0 } };
550  int edgeCheckCount = 0;
551  if (m_generateEdgeEdgeContacts)
552  {
553  // For every edge/line segment of the line mesh
554  for (int i = 0; i < meshACells.size(); i++)
555  {
556  const Vec3i& cellA = meshACells[i];
557 
558  // For every edge of triangle A
559  for (int j = 0; j < 3; j++)
560  {
561  const Vec2i edgeA = Vec2i(cellA[triEdgePattern[j][0]], cellA[triEdgePattern[j][1]]);
562 
563  // Only check edges that don't exist totally inside
564  if (!m_vertexInside[edgeA[0]] && !m_vertexInside[edgeA[1]])
565  {
566  double minSqrDist = IMSTK_DOUBLE_MAX;
567  int closestTriId = -1;
568  int closestEdgeId = -1;
569 
570  // If proximity is used, only check edges with vertices within proximity of the closed surface
571  if (m_proximity <= 0.0 || (m_signedDistances[edgeA[0]] < m_proximity && m_signedDistances[edgeA[1]] < m_proximity))
572  {
573  edgeCheckCount++;
574  // For every triangle/cell of meshB
575  for (int k = 0; k < surfMeshBData.cells.size(); k++)
576  {
577  const Vec3i& cellB = surfMeshBData.cells[k];
578 
579  // For every edge of that triangle
580  for (int edgeId = 0; edgeId < 3; edgeId++)
581  {
582  const Vec2i edgeB(cellB[triEdgePattern[edgeId][0]], cellB[triEdgePattern[edgeId][1]]);
583 
584  // Compute the closest point on the two edges
585  // Check the case, the edges must be within each others bounds/ranges
586  Vec3d ptA, ptB;
587  if (CollisionUtils::edgeToEdgeClosestPoints(
588  meshAVertices[edgeA[0]], meshAVertices[edgeA[1]],
589  surfMeshBData.vertices[edgeB[0]], surfMeshBData.vertices[edgeB[1]],
590  ptA, ptB) == 0)
591  {
592  // Find the closest element to this point on the edge
593  const double sqrDist = (ptB - ptA).squaredNorm();
594  // Use the closest one only
595  if (sqrDist < minSqrDist)
596  {
597  // Check if the point on the oppositie edge nearest to edgeB is inside B
598  int caseType = -1;
599  int closestCell = -1;
600  Vec3i vIds = Vec3i::Zero();
601  const double signedDist = polySignedDist(ptA, surfMeshBData, caseType, vIds, closestCell);
602  if (signedDist <= 0.0)
603  {
604  minSqrDist = sqrDist;
605  closestTriId = k;
606  closestEdgeId = edgeId;
607  }
608  }
609  }
610  }
611  }
612  }
613 
614  if (closestTriId != -1)
615  {
616  // Before inserting check if it already exists
617  EdgePair edgePair(
618  edgeA[0], edgeA[1],
619  surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][0]],
620  surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][1]]);
621  if (hashedEdges.count(edgePair) == 0)
622  {
623  CellIndexElement elemA;
624  elemA.ids[0] = edgeA[0];
625  elemA.ids[1] = edgeA[1];
626  elemA.parentId = i; // Triangle id
627  elemA.idCount = 2;
628  elemA.cellType = IMSTK_EDGE;
629 
630  CellIndexElement elemB;
631  elemB.ids[0] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][0]];
632  elemB.ids[1] = surfMeshBData.cells[closestTriId][triEdgePattern[closestEdgeId][1]];
633  elemB.parentId = closestTriId; // Triangle id
634  elemB.idCount = 2;
635  elemB.cellType = IMSTK_EDGE;
636 
637  elementsA.push_back(elemA);
638  elementsB.push_back(elemB);
639 
640  hashedEdges.insert(edgePair);
641  }
642  }
643  }
644  }
645  }
646  }
647 }
648 
649 bool
650 ClosedSurfaceMeshToMeshCD::doBroadPhaseCollisionCheck(
651  std::shared_ptr<Geometry> geomA,
652  std::shared_ptr<Geometry> geomB) const
653 {
654  if (!m_doBroadPhase)
655  {
656  return true;
657  }
658 
659  const auto mesh1 = std::dynamic_pointer_cast<PointSet>(geomA);
660  const auto mesh2 = std::dynamic_pointer_cast<PointSet>(geomB);
661 
662  // Edge Case Ex: One point vs non-manifold SurfaceMesh (like a single triangle or plane)
663  if (mesh1->getNumVertices() == 1 || mesh2->getNumVertices() == 1)
664  {
665  return true;
666  }
667 
668  Vec3d min1, max1;
669  mesh1->computeBoundingBox(min1, max1);
670 
671  Vec3d min2, max2;
672  mesh2->computeBoundingBox(min2, max2);
673 
674  // Padding here helps with thin vs thin geometry
675  min1 -= m_padding;
676  max1 += m_padding;
677  min2 -= m_padding;
678  max2 += m_padding;
679 
680  return CollisionUtils::testAabbToAabb(
681  min1[0], max1[0],
682  min1[1], max1[1],
683  min1[2], max1[2],
684  min2[0], max2[0],
685  min2[1], max2[1],
686  min2[2], max2[2]);
687 }
688 } // namespace imstk
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
Definition: imstkPointSet.h:25
Hash together a pair of edges.
Compound Geometry.
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.
Definition: imstkLineMesh.h:18
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.