7 #include "imstkPbdCollisionHandling.h" 8 #include "imstkPbdContactConstraint.h" 9 #include "imstkPbdEdgeEdgeCCDConstraint.h" 10 #include "imstkPbdEdgeEdgeConstraint.h" 11 #include "imstkPbdModel.h" 12 #include "imstkPbdModelConfig.h" 13 #include "imstkPbdObject.h" 14 #include "imstkPbdPointEdgeConstraint.h" 15 #include "imstkPbdPointPointConstraint.h" 16 #include "imstkPbdPointTriangleConstraint.h" 17 #include "imstkPbdSolver.h" 18 #include "imstkPointSet.h" 19 #include "imstkPointwiseMap.h" 23 #define REGISTER_CASE(case0, case1, case2, func) \ 24 m_funcTable[{ case0, case1, case2 }] = [this](const ColElemSide& sideA, const ColElemSide& sideB) \ 25 { func(sideA, sideB); } 27 std::pair<PbdParticleId, Vec3d>
30 if (elem.m_type == CollisionElementType::PointDirection)
32 return { { data.bodyId, 0 }, elem.m_element.m_PointDirectionElement.pt };
37 return { { data.bodyId, 0 }, (*data.vertices)[ptBv.second] };
46 template<
typename ArrType,
int cellType>
47 static std::array<PbdParticleId, ArrType::NumComponents>
51 typename ArrType::ValueType cell = -ArrType::ValueType::Ones();
52 if (elem.m_type == CollisionElementType::CellIndex && elem.m_element.m_CellIndexElement.cellType == cellType)
55 if (elem.m_element.m_CellIndexElement.idCount == 1)
57 cell = (*
dynamic_cast<ArrType*
>(side.indicesPtr))[elem.m_element.m_CellIndexElement.ids[0]];
59 else if (elem.m_element.m_CellIndexElement.idCount == ArrType::NumComponents)
61 for (
int i = 0; i < ArrType::NumComponents; i++)
63 cell[i] = elem.m_element.m_CellIndexElement.ids[i];
68 std::array<PbdParticleId, ArrType::NumComponents> results;
69 for (
int i = 0; i < ArrType::NumComponents; i++)
71 results[i] = { -1, -1 };
75 if (side.mapPtr !=
nullptr)
77 for (
int i = 0; i < ArrType::NumComponents; i++)
82 for (
int i = 0; i < ArrType::NumComponents; i++)
89 results[i] = { side.bodyId, vid };
95 std::array<PbdParticleId, 2>
98 return getElementVertIds<VecDataArray<int, 2>, IMSTK_EDGE>(elem, side);
101 std::array<PbdParticleId, 3>
104 return getElementVertIds<VecDataArray<int, 3>, IMSTK_TRIANGLE>(elem, side);
107 std::array<PbdParticleId, 1>
110 std::array<PbdParticleId, 1> results = {
PbdParticleId(-1, -1) };
112 if (elem.m_type == CollisionElementType::CellIndex && elem.m_element.m_CellIndexElement.cellType == IMSTK_VERTEX)
114 ptId = elem.m_element.m_CellIndexElement.ids[0];
116 else if (elem.m_type == CollisionElementType::PointIndexDirection)
118 ptId = elem.m_element.m_PointIndexDirectionElement.ptIndex;
122 if (side.mapPtr !=
nullptr)
126 if (side.bodyId == 0)
130 results[0] = { side.bodyId, ptId };
134 if (elem.m_type == CollisionElementType::PointDirection)
136 results[0] = { side.model->
addVirtualParticle(elem.m_element.m_PointDirectionElement.pt, 0.0) };
143 static std::array<Vec3d*, N>
144 getElementVertIdsPrev(
const std::array<PbdParticleId, N>& ids,
147 std::array<Vec3d*, N> results;
148 for (
int i = 0; i < N; i++)
151 std::shared_ptr<VecDataArray<double, 3>> vertices =
152 dynamic_cast<PointSet*
>(side.prevGeometry)->getVertexPositions();
153 const int vertexId = ids[i].second;
154 results[i] = &(*vertices)[vertexId];
162 os << getContactCaseStr(key.elemAType) <<
" vs " <<
163 getContactCaseStr(key.elemBType) <<
", CCD: " << key.ccd;
167 PbdCollisionHandling::PbdCollisionHandling()
169 REGISTER_CASE(PbdContactCase::Vertex, PbdContactCase::Vertex,
false, addConstraint_V_V);
170 REGISTER_CASE(PbdContactCase::Vertex, PbdContactCase::Edge,
false, addConstraint_V_E);
171 REGISTER_CASE(PbdContactCase::Edge, PbdContactCase::Edge,
false, addConstraint_E_E);
172 REGISTER_CASE(PbdContactCase::Vertex, PbdContactCase::Triangle,
false, addConstraint_V_T);
174 REGISTER_CASE(PbdContactCase::Body, PbdContactCase::Triangle,
false, addConstraint_Body_T);
175 REGISTER_CASE(PbdContactCase::Body, PbdContactCase::Edge,
false, addConstraint_Body_E);
176 REGISTER_CASE(PbdContactCase::Body, PbdContactCase::Vertex,
false, addConstraint_Body_V);
177 REGISTER_CASE(PbdContactCase::Body, PbdContactCase::Primitive,
false, addConstraint_Body_V);
178 REGISTER_CASE(PbdContactCase::Body, PbdContactCase::Body,
false, addConstraint_Body_Body);
181 REGISTER_CASE(PbdContactCase::Primitive, PbdContactCase::Triangle,
false, addConstraint_V_T);
182 REGISTER_CASE(PbdContactCase::Primitive, PbdContactCase::Edge,
false, addConstraint_V_E);
183 REGISTER_CASE(PbdContactCase::Primitive, PbdContactCase::Vertex,
false, addConstraint_V_V);
186 REGISTER_CASE(PbdContactCase::Vertex, PbdContactCase::None,
false, addConstraint_V_V);
187 REGISTER_CASE(PbdContactCase::Body, PbdContactCase::None,
false, addConstraint_Body_V);
190 REGISTER_CASE(PbdContactCase::Edge, PbdContactCase::Edge,
true, addConstraint_E_E_CCD);
193 PbdCollisionHandling::~PbdCollisionHandling()
195 deleteCollisionConstraints();
203 auto pbdObj = std::dynamic_pointer_cast<
PbdObject>(obj);
204 side.pbdObj = pbdObj.get();
205 side.colObj = obj.get();
206 side.objType = ObjType::Colliding;
207 std::shared_ptr<Geometry> collidingGeometry = side.colObj->getCollidingGeometry();
208 side.geometry = collidingGeometry.get();
210 if (side.pbdObj !=
nullptr)
212 if (side.pbdObj->
getPbdBody()->bodyType == PbdBody::Type::RIGID)
214 side.objType = ObjType::PbdRigid;
218 side.objType = ObjType::PbdDeformable;
220 std::shared_ptr<PbdModel> model = side.pbdObj->
getPbdModel();
221 side.model = model.get();
227 side.geometry = physicsGeometry.get();
228 side.bodyId = side.pbdObj->
getPbdBody()->bodyHandle;
231 side.mapPtr = map.get();
233 side.pointSet =
dynamic_cast<PointSet*
>(side.geometry);
234 side.vertices = (side.pointSet ==
nullptr) ?
nullptr : side.pointSet->
getVertexPositions().get();
235 if (side.objType == ObjType::PbdRigid)
237 if (
auto pointSet = std::dynamic_pointer_cast<PointSet>(side.colObj->getCollidingGeometry()))
239 std::shared_ptr<VecDataArray<double, 3>> vertices = pointSet->getVertexPositions();
240 side.vertices = vertices.get();
244 side.indicesPtr =
nullptr;
245 if (
auto cellMesh = std::dynamic_pointer_cast<AbstractCellMesh>(side.colObj->getCollidingGeometry()))
247 std::shared_ptr<AbstractDataArray> indicesPtr = cellMesh->getAbstractCells();
248 side.indicesPtr = indicesPtr.get();
257 if (elem.data->objType == ObjType::PbdRigid)
259 return PbdContactCase::Body;
263 if (elem.elem->m_type == CollisionElementType::PointDirection)
265 return PbdContactCase::Primitive;
267 else if (elem.elem->m_type == CollisionElementType::CellIndex)
270 return static_cast<PbdContactCase
>(
271 elem.elem->m_element.m_CellIndexElement.cellType);
273 else if (elem.elem->m_type == CollisionElementType::CellVertex)
275 return static_cast<PbdContactCase
>(
276 elem.elem->m_element.m_CellVertexElement.size);
279 else if (elem.elem->m_type == CollisionElementType::PointIndexDirection)
281 return PbdContactCase::Vertex;
284 return PbdContactCase::None;
289 PbdCollisionHandling::getCachedConstraint(ConstraintType type)
291 if (!m_constraintCache[type].empty())
293 T* result =
static_cast<T*
>(m_constraintCache[type].back());
294 m_constraintCache[type].pop_back();
305 const std::vector<CollisionElement>& elementsA,
306 const std::vector<CollisionElement>& elementsB)
315 if (elementsA.size() != 0 || elementsB.size() != 0)
320 dataSideA.compliance = m_compliance;
321 dataSideA.stiffness = m_stiffness[0];
323 dataSideB.compliance = m_compliance;
324 dataSideB.stiffness = (dataSideB.pbdObj ==
nullptr) ? 0.0 : m_stiffness[1];
328 if (dataSideB.model ==
nullptr)
330 dataSideB.model = dataSideA.model;
334 CHECK(dataSideB.pbdObj ==
nullptr || dataSideA.model == dataSideB.model) <<
335 "PbdCollisionHandling input objects must share PbdModel";
338 dataSideA.prevGeometry =
m_colData->prevGeomA.get();
339 dataSideB.prevGeometry =
m_colData->prevGeomB.get();
341 if (elementsA.size() == elementsB.size())
344 for (
size_t i = 0; i < elementsA.size(); i++)
347 { &elementsA[i], &dataSideA },
348 { &elementsB[i], &dataSideB });
354 for (
size_t i = 0; i < elementsA.size(); i++)
357 { &elementsA[i], &dataSideA },
358 {
nullptr,
nullptr });
360 for (
size_t i = 0; i < elementsB.size(); i++)
363 { &elementsB[i], &dataSideB },
364 {
nullptr,
nullptr });
368 size_t constraints = 0;
369 for (
int i = 0; i < NumTypes; ++i)
371 constraints += m_constraintBins[i].size();
375 if (m_processConstraints)
377 orderCollisionConstraints();
394 key.elemBType = PbdContactCase::None;
395 key.ccd = sideA.elem->m_ccdData;
398 if (sideB.data !=
nullptr)
401 if (sideB.elem->m_ccdData)
411 if ((key.elemAType == PbdContactCase::Triangle && key.elemBType == PbdContactCase::Vertex)
412 || (key.elemAType == PbdContactCase::Edge && key.elemBType == PbdContactCase::Vertex)
413 || (key.elemBType == PbdContactCase::Body && key.elemAType != PbdContactCase::Body)
414 || (key.elemAType != PbdContactCase::Primitive && key.elemBType == PbdContactCase::Primitive))
416 if (!(key.elemAType == PbdContactCase::Body && key.elemBType == PbdContactCase::Primitive))
418 std::swap(key.elemAType, key.elemBType);
419 std::swap(sideA, sideB);
424 auto iter = m_funcTable.find(key);
425 if (iter != m_funcTable.end())
427 iter->second(sideA, sideB);
432 LOG(INFO) <<
"Could not find handling case " << key;
443 if (sideB.data ==
nullptr)
448 if (sideA.elem->m_type == CollisionElementType::PointIndexDirection)
450 const Vec3d& pos = ptAAndContact.second;
451 const Vec3d& dir = elem.m_PointIndexDirectionElement.dir;
452 const double depth = elem.m_PointIndexDirectionElement.penetrationDepth;
453 resolvePos = pos + dir * depth;
455 else if (sideA.elem->m_type == CollisionElementType::PointDirection)
457 const Vec3d& pos = elem.m_PointDirectionElement.pt;
458 const Vec3d& dir = elem.m_PointDirectionElement.dir;
459 const double depth = elem.m_PointDirectionElement.penetrationDepth;
460 resolvePos = pos + dir * depth;
470 ptB =
getVertex(*sideB.elem, *sideB.data)[0];
476 ptAAndContact.second,
478 sideA.data->compliance);
479 constraint->setFriction(m_friction);
480 constraint->setRestitution(m_restitution);
481 constraint->setCorrectVelocity(m_useCorrectVelocity);
482 m_constraintBins[BodyVertex].push_back(constraint);
489 std::array<PbdParticleId, 2> ptsB = getEdge(*sideB.elem, *sideB.data);
494 ptAAndContact.second,
496 sideA.data->compliance);
497 constraint->setFriction(m_friction);
498 constraint->setRestitution(m_restitution);
499 constraint->setCorrectVelocity(m_useCorrectVelocity);
500 m_constraintBins[BodyEdge].push_back(constraint);
507 std::array<PbdParticleId, 3> ptsB = getTriangle(*sideB.elem, *sideB.data);
512 ptAAndContact.second,
513 ptsB[0], ptsB[1], ptsB[2],
514 sideA.data->compliance);
515 constraint->setFriction(m_friction);
516 constraint->setRestitution(m_restitution);
517 constraint->setCorrectVelocity(m_useCorrectVelocity);
518 m_constraintBins[BodyTriangle].push_back(constraint);
527 Vec3d normal = Vec3d::Zero();
528 if (sideA.elem->m_type == CollisionElementType::PointDirection)
530 normal = sideA.elem->m_element.m_PointDirectionElement.dir;
536 sideA.data->model->getBodies(),
538 ptAAndContact.second,
540 ptBAndContact.second,
542 sideA.data->compliance);
543 constraint->setFriction(m_friction);
544 constraint->setRestitution(m_restitution);
545 constraint->setCorrectVelocity(m_useCorrectVelocity);
546 m_constraintBins[BodyBody].push_back(constraint);
553 std::array<PbdParticleId, 3> ptsB = getTriangle(*sideB.elem, *sideB.data);
557 sideA.data->stiffness, sideB.data->stiffness);
558 constraint->setFriction(m_friction);
559 constraint->setRestitution(m_restitution);
561 constraint->setCorrectVelocity(m_useCorrectVelocity);
562 m_constraintBins[VertexTriangle].push_back(constraint);
568 std::array<PbdParticleId, 2> ptsA = getEdge(*sideA.elem, *sideA.data);
569 std::array<PbdParticleId, 2> ptsB = getEdge(*sideB.elem, *sideB.data);
573 sideA.data->stiffness, sideB.data->stiffness);
574 constraint->setFriction(m_friction);
575 constraint->setRestitution(m_restitution);
577 constraint->setCorrectVelocity(m_useCorrectVelocity);
578 m_constraintBins[EdgeEdge].push_back(constraint);
582 PbdCollisionHandling::addConstraint_E_E_CCD(
586 std::array<PbdParticleId, 2> ptsA = getEdge(*sideA.elem, *sideA.data);
587 std::array<PbdParticleId, 2> ptsB = getEdge(*sideB.elem, *sideB.data);
591 std::array<Vec3d*, 2> prevPtsA = getElementVertIdsPrev<2>(ptsA, *sideA.data);
592 std::array<Vec3d*, 2> prevPtsB = getElementVertIdsPrev<2>(ptsB, *sideB.data);
596 prevPtsA[0], prevPtsA[1], prevPtsB[0], prevPtsB[1],
597 ptsA[0], ptsA[1], ptsB[0], ptsB[1],
598 sideA.data->stiffness, sideB.data->stiffness,
600 constraint->setEnableBoundaryCollisions(m_enableBoundaryCollisions);
601 constraint->setCorrectVelocity(m_useCorrectVelocity);
602 m_constraintBins[EdgeEdgeCCD].push_back(constraint);
609 std::array<PbdParticleId, 2> ptsB = getEdge(*sideB.elem, *sideB.data);
613 sideA.data->stiffness, sideB.data->stiffness);
614 constraint->setFriction(m_friction);
615 constraint->setRestitution(m_restitution);
617 constraint->setCorrectVelocity(m_useCorrectVelocity);
618 m_constraintBins[VertexEdge].push_back(constraint);
629 if (sideB.data ==
nullptr)
634 if (sideA.elem->m_type == CollisionElementType::PointIndexDirection)
636 const Vec3d& pos = sideA.data->model->getBodies().getPosition(ptA);
637 const Vec3d& dir = elem.m_PointIndexDirectionElement.dir;
638 const double depth = elem.m_PointIndexDirectionElement.penetrationDepth;
639 resolvePos = pos + dir * depth;
641 else if (sideA.elem->m_type == CollisionElementType::PointDirection)
643 const Vec3d& pos = elem.m_PointDirectionElement.pt;
644 const Vec3d& dir = elem.m_PointDirectionElement.dir;
645 const double depth = elem.m_PointDirectionElement.penetrationDepth;
646 resolvePos = pos + dir * depth;
656 ptB =
getVertex(*sideB.elem, *sideB.data)[0];
661 sideA.data->stiffness,
662 (sideB.data ==
nullptr) ? 0.0 : sideB.data->stiffness);
663 constraint->setFriction(m_friction);
664 constraint->setRestitution(m_restitution);
666 constraint->setCorrectVelocity(m_useCorrectVelocity);
667 m_constraintBins[VertexVertex].push_back(constraint);
671 PbdCollisionHandling::deleteCollisionConstraints()
676 for (
int i = 0; i < NumTypes; i++)
678 for (
size_t j = 0; j < m_constraintCache[i].size(); j++)
680 delete m_constraintCache[i][j];
682 m_constraintCache[i].resize(0);
684 for (
size_t j = 0; j < m_constraintBins[i].size(); j++)
686 delete m_constraintBins[i][j];
688 m_constraintBins[i].resize(0);
695 PbdCollisionHandling::orderCollisionConstraints()
698 for (
int i = 0; i < NumTypes; i++)
701 m_constraintCache[i].insert(m_constraintCache[i].end(), m_constraintBins[i].begin(), m_constraintBins[i].end());
702 m_constraintBins[i].resize(0);
Base class for all geometries represented by discrete points and elements The pointsets follow a pipe...
The PbdPointTriangleConstraint moves a point to a triangle, and the triangle to the point...
void initConstraint(const PbdState &state, const PbdParticleId &bodyId, const Vec3d contactPtOnBody, const PbdParticleId &x0, const PbdParticleId &x1, const double compliance=0.0)
Initialize the constraint.
CollisionSideData getDataFromObject(std::shared_ptr< CollidingObject > obj)
Creates a CollisionSideData struct from the provided object, this gives all the info needed to respon...
std::pair< int, int > PbdParticleId
Index pair that refers to a particle in a PbdState. Index 0 is the body id, Index 1 is the particle i...
std::shared_ptr< const CollisionData > m_colData
Collision data.
Resolves a point on body to a triangle with linear and angular movement.
std::shared_ptr< GeometryMap > getPhysicsToCollidingMap() const
Set/Get the Physics-to-Collision map.
std::shared_ptr< PbdModel > getPbdModel()
void initConstraint(const PbdState &state, const PbdParticleId &bodyId0, const Vec3d contactPt0, const PbdParticleId &bodyId1, const Vec3d contactPt1, const Vec3d contactNormal0To1, const double compliance)
Initialize the constraint ptOnBody is global position.
void initConstraint(const PbdParticleId &ptA1, const PbdParticleId &ptA2, const PbdParticleId &ptB1, const PbdParticleId &ptB2, double stiffnessA, double stiffnessB)
Initialize constraint.
void handle(const std::vector< CollisionElement > &elementsA, const std::vector< CollisionElement > &elementsB) override
Add collision constraints based off contact data.
Resolves a point on body to an edge with linear and angular movement.
void initConstraint(Vec3d *prevPtA0, Vec3d *prevPtA1, Vec3d *prevPtB0, Vec3d *prevPtB1, const PbdParticleId &ptA0, const PbdParticleId &ptA1, const PbdParticleId &ptB0, const PbdParticleId &ptB1, double stiffnessA, double stiffnessB, int ccdSubsteps=25)
Initialize constraint.
void initConstraint(const PbdParticleId &ptA1, const PbdParticleId &ptB1, const PbdParticleId &ptB2, double stiffnessA, double stiffnessB)
Initialize the constraint.
std::array< PbdParticleId, 1 > getVertex(const CollisionElement &elem, const CollisionSideData &side)
getVertex takes slightly differing paths than the others, as the cell vertex directly refers to the v...
int getParentVertexId(const int childVertexId) const
Get the mapped/corresponding parent index, given a child index. returns -1 if no correspondence found...
Union of collision elements. We use a union to avoid polymorphism. There may be many elements and acc...
PbdParticleId addVirtualParticle(const Vec3d &pos, const Quatd &orientation, const double mass, const Mat3d inertia, const Vec3d &velocity=Vec3d::Zero(), const Vec3d &angularVelocity=Vec3d::Zero(), const bool persist=false)
Add a particle to a virtual pool/buffer of particles for quick removal/insertion The persist flag ind...
void initConstraint(const PbdState &state, const PbdParticleId &bodyId, const Vec3d contactPtOnBody, const PbdParticleId &x0, const PbdParticleId &x1, const PbdParticleId &x2, const double compliance=0.0)
Initialize the constraint.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
void handleElementPair(ColElemSide sideA, ColElemSide sideB)
Handle a single element.
Base class for scene objects that move and/or deform under position based dynamics formulation...
void initConstraint(const PbdState &state, const PbdParticleId &bodyId, const Vec3d contactPtOnBody, const PbdParticleId &x0, const double compliance=0.0)
Initialize the constraint.
void initConstraint(const PbdParticleId &ptA, const PbdParticleId &ptB1, const PbdParticleId &ptB2, const PbdParticleId &ptB3, double stiffnessA, double stiffnessB)
Initialize the constraint.
std::shared_ptr< PbdBody > getPbdBody()
Returns body in the model.
std::shared_ptr< CollidingObject > getInputObjectA() const
Get the input objects.
Resolves an edge given by two pbd particles to coincide with another edge.
void setEnableBoundaryCollisions(const double enableBoundaryCollisions)
Get enableBoundaryCollision.
std::shared_ptr< Geometry > getPhysicsGeometry() const
Set/Get the geometry used for Physics computations.
PointwiseMap can compute & apply a mapping between parent and child PointSet geometries.
Packs the collision element together with the data it will need to process it (for swapping) ...
std::vector< PbdConstraint * > m_collisionConstraints
Vector of all collision constraints.
This constraint resolves two vertices to each other.
Pushes an edge "outside" the other edge.
void initConstraint(const PbdParticleId &ptA, const PbdParticleId &ptB, double stiffnessA, double stiffnessB)
Initialize constraint.
PbdContactCase getCaseFromElement(const ColElemSide &elem)
Get the contact case from the collision element and data as additional context.
std::pair< PbdParticleId, Vec3d > getBodyAndContactPoint(const CollisionElement &elem, const CollisionSideData &data)
Get the body particle id from the collision side as well as the contact point on the body (in global ...
Used as a key in a function table to decide how to handle resulting collision.