iMSTK
Interactive Medical Simulation Toolkit
imstkLineMeshToLineMeshCCD.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 "imstkCollisionData.h"
8 #include "imstkEdgeEdgeCCDState.h"
9 #include "imstkLineMesh.h"
10 #include "imstkLineMeshToLineMeshCCD.h"
11 
12 namespace imstk
13 {
14 LineMeshToLineMeshCCD::LineMeshToLineMeshCCD()
15 {
16  setRequiredInputType<LineMesh>(0);
17  setRequiredInputType<LineMesh>(1);
18 
19  m_prevA = std::make_shared<LineMesh>();
20  m_prevB = std::make_shared<LineMesh>();
21 
22  // Add empty velocities and invMasses attribute arrays.
23  // Required for proper construction of ismtk::MeshSide defined in PbdCollisionHandling.
24  m_prevA->setVertexAttribute("Velocities", std::make_shared<VecDataArray<double, 3>>());
25  m_prevB->setVertexAttribute("Velocities", std::make_shared<VecDataArray<double, 3>>());
26  m_prevA->setVertexAttribute("InvMass", std::make_shared<VecDataArray<double, 3>>());
27  m_prevB->setVertexAttribute("InvMass", std::make_shared<VecDataArray<double, 3>>());
28 }
29 
30 namespace
31 {
36 bool
37 copyPointSetGeometry(const Geometry* source, PointSet& dest)
38 {
39  bool success = false;
40  // Make sure its a LineMesh.
41  if (auto sourceLineMeshPtr = dynamic_cast<const PointSet*>(source))
42  {
43  // Make sure it has a vertex buffer.
44  if (auto srcPointsPtr = sourceLineMeshPtr->getVertexPositions())
45  {
46  *dest.getVertexPositions() = *srcPointsPtr;
47  success = true;
48  }
49  }
50  return success;
51 }
52 } // namespace
53 
54 void
56  std::shared_ptr<const Geometry> geomA,
57  std::shared_ptr<const Geometry> geomB)
58 {
59  bool success = copyPointSetGeometry(geomA.get(), *m_prevA);
60  success = success && copyPointSetGeometry(geomB.get(), *m_prevB);
61  if (!success)
62  {
63  LOG(WARNING) << "Failed to make a copy of previous geometries.";
64  }
65 }
66 
67 void
68 LineMeshToLineMeshCCD::internalComputeCollision(
69  std::shared_ptr<Geometry> geomA,
70  std::shared_ptr<Geometry> geomB,
71  std::vector<CollisionElement>* elementsA,
72  std::vector<CollisionElement>* elementsB)
73 {
74  // incomplete inputs, early return
75  if (!geomA || !geomB || (!elementsA && !elementsB))
76  {
77  LOG(WARNING) << "Incomplete inputs: one of more of geomA, geomB, elementsA, or elementsB"
78  " are nullptr when they shouldn't be."
79  "\n Self-collision requries geomA == geomB.";
80  return;
81  }
82 
83  if (!m_prevA || !m_prevB)
84  {
85  LOG(WARNING) << "Invalid cache. Null pointers encountered.";
86  return;
87  }
88 
89  // Pass previous geometries to collisionData.
90  getCollisionData()->prevGeomA = m_prevA;
91  getCollisionData()->prevGeomB = m_prevB;
92 
93  // auto prevAPtr = m_prevA->getVertexPositions();
94  // auto prevBPtr = m_prevB->getVertexPositions();
95  const auto& prevA = *m_prevA->getVertexPositions().get();
96  const auto& prevB = *m_prevB->getVertexPositions().get();
97 
98  auto meshA = std::dynamic_pointer_cast<const LineMesh>(geomA);
99  auto meshB = std::dynamic_pointer_cast<const LineMesh>(geomB);
100 
101  if (meshA->getNumVertices() != prevA.size() || meshB->getNumVertices() != prevB.size())
102  {
103  LOG(WARNING) << "Invalid cache. Size of arrays do not match input.";
104  return;
105  }
106 
107  // Flag to identify two-body vs self collision
108  const bool selfCollision = (meshA == meshB);
109 
110  // Get vertex and cell data for current time step
111  std::shared_ptr<const VecDataArray<double, 3>> verticesPtrA = meshA->getVertexPositions();
112  std::shared_ptr<const VecDataArray<double, 3>> verticesPtrB = meshB->getVertexPositions();
113 
114  if (!verticesPtrA || !verticesPtrB)
115  {
116  //TODO: throw appropriate error: "Vertex/Cell data not found for colliding LineMesh objects".
117  return;
118  }
119 
120  const VecDataArray<double, 3>& verticesA = *verticesPtrA;
121  const VecDataArray<double, 3>& verticesB = *verticesPtrB;
122 
123  std::shared_ptr<VecDataArray<int, 2>> linesAPtr = meshA->getCells();
124  const VecDataArray<int, 2>& linesA = *linesAPtr;
125  std::shared_ptr<VecDataArray<int, 2>> linesBPtr = meshB->getCells();
126  const VecDataArray<int, 2>& linesB = *linesBPtr;
127  for (size_t i = 0; i < static_cast<size_t>(meshA->getNumCells()); ++i)
128  {
129  const Vec2i& cellA = linesA[i];
130  size_t j = selfCollision ? i + 2 : 0;
131  for (; j < static_cast<size_t>(meshB->getNumCells()); ++j)
132  {
133  // If performing self-collision, do not process self or immediate neighboring cells (lines).
134  if (selfCollision && (std::max(i, j) - std::min(i, j) <= 1))
135  {
136  continue;
137  }
138  const Vec2i& cellB = linesB[j];
139 
140  EdgeEdgeCCDState currState(verticesA[cellA(0)], verticesA[cellA(1)], verticesB[cellB(0)], verticesB[cellB(1)]);
141  EdgeEdgeCCDState prevState(prevA[cellA(0)], prevA[cellA(1)], prevB[cellB(0)], prevB[cellB(1)]);
142 
143  // Test for collision between current and previous timestep, and create collision info.
144  double relativeTimeOfImpact = 0.0;
145  int collisionCase = EdgeEdgeCCDState::testCollision(prevState, currState, relativeTimeOfImpact);
146  if (collisionCase != 0)
147  {
148  if (elementsA)
149  {
150  CellIndexElement elemA;
151  elemA.cellType = IMSTK_EDGE;
152  elemA.idCount = 2;
153  elemA.parentId = static_cast<int>(i); // line id
154  elemA.ids[0] = cellA(0);
155  elemA.ids[1] = cellA(1);
156  CollisionElement e(elemA);
157  e.m_ccdData = true;
158  elementsA->push_back(e);
159  }
160  if (elementsB)
161  {
162  CellIndexElement elemB;
163  elemB.cellType = IMSTK_EDGE;
164  elemB.idCount = 2;
165  elemB.parentId = static_cast<int>(j); // line id
166  elemB.ids[0] = cellB(0);
167  elemB.ids[1] = cellB(1);
168  CollisionElement e(elemB);
169  e.m_ccdData = true;
170  elementsB->push_back(e);
171  }
172  }
173  }
174  }
175 }
176 
177 void
179  std::shared_ptr<Geometry> geomA,
180  std::shared_ptr<Geometry> geomB,
181  std::vector<CollisionElement>& elementsA,
182  std::vector<CollisionElement>& elementsB)
183 {
184  internalComputeCollision(geomA, geomB, &elementsA, &elementsB);
185 }
186 
187 void
189  std::shared_ptr<Geometry> geomA,
190  std::shared_ptr<Geometry> geomB,
191  std::vector<CollisionElement>& elementsA)
192 {
193  internalComputeCollision(geomA, geomB, &elementsA, nullptr);
194 }
195 
196 void
198  std::shared_ptr<Geometry> geomA,
199  std::shared_ptr<Geometry> geomB,
200  std::vector<CollisionElement>& elementsB)
201 {
202  internalComputeCollision(geomA, geomB, nullptr, &elementsB);
203 }
204 } // namespace imstk
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.
Compound Geometry.
void computeCollisionDataA(std::shared_ptr< Geometry > geomA, std::shared_ptr< Geometry > geomB, std::vector< CollisionElement > &elementsA) override
Compute collision data for side A.
const std::shared_ptr< CollisionData > getCollisionData() const
Returns output collision data.
void computeCollisionDataB(std::shared_ptr< Geometry > geomA, std::shared_ptr< Geometry > geomB, std::vector< CollisionElement > &elementsB) override
Compute collision data for side B.
static int testCollision(const EdgeEdgeCCDState &prev, EdgeEdgeCCDState &curr, double &relativeTimeOfImpact)
Performs a collision test based on two given timesteps that store the state of two lines each...
Union of collision elements. We use a union to avoid polymorphism. There may be many elements and acc...
Base class for all volume mesh types.
Definition: imstkLineMesh.h:18
Represents a cell by a single cell id OR by N vertex ids. Which case can be determined by the idCount...
void updatePreviousTimestepGeometry(std::shared_ptr< const Geometry > geomA, std::shared_ptr< const Geometry > geomB) override
Copy LineMesh geometry information (points only), as previous timestep information. These are used with current geometries that are received in computeCollisionDataXX functions for computing the continuous collision detection.