9 #include "imstkLineMesh.h" 10 #include "imstkLogger.h" 11 #include "imstkParallelUtils.h" 12 #include "imstkPbdAreaConstraint.h" 13 #include "imstkPbdBendConstraint.h" 14 #include "imstkPbdConstantDensityConstraint.h" 15 #include "imstkPbdConstraint.h" 16 #include "imstkPbdDihedralConstraint.h" 17 #include "imstkPbdDistanceConstraint.h" 18 #include "imstkPbdFemConstraint.h" 19 #include "imstkPbdFemTetConstraint.h" 20 #include "imstkPbdVolumeConstraint.h" 21 #include "imstkPointSet.h" 22 #include "imstkSurfaceMesh.h" 23 #include "imstkTetrahedralMesh.h" 24 #include "imstkPbdConstraintContainer.h" 56 std::shared_ptr<std::unordered_set<size_t>> imstkNotUsed(vertices)) { }
76 std::function<void(PbdConstraintContainer&)> m_func =
nullptr;
87 void setGeometry(std::shared_ptr<PointSet> geom)
92 void setBodyIndex(
const int bodyIndex) { m_bodyIndex = bodyIndex; }
95 std::shared_ptr<PointSet> m_geom =
nullptr;
117 auto constraint = std::make_shared<PbdDistanceConstraint>();
118 constraint->initConstraint(vertices[i1], vertices[i2],
119 { m_bodyIndex, i1 }, { m_bodyIndex, i2 }, m_stiffness);
120 constraint->m_restLength *= m_stretch;
126 std::shared_ptr<VecDataArray<double, 3>> verticesPtr = m_geom->getVertexPositions();
129 auto addDistConstraint = [&](
130 std::vector<std::vector<bool>>& E,
int i1,
int i2)
141 auto c = makeDistConstraint(vertices, i1, i2);
146 if (
auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(m_geom))
148 std::shared_ptr<VecDataArray<int, 4>> elementsPtr = tetMesh->getCells();
150 const auto nV = tetMesh->getNumVertices();
151 std::vector<std::vector<bool>> E(nV, std::vector<bool>(nV, 1));
153 for (
int k = 0; k < elements.size(); ++k)
155 auto& tet = elements[k];
156 addDistConstraint(E, tet[0], tet[1]);
157 addDistConstraint(E, tet[0], tet[2]);
158 addDistConstraint(E, tet[0], tet[3]);
159 addDistConstraint(E, tet[1], tet[2]);
160 addDistConstraint(E, tet[1], tet[3]);
161 addDistConstraint(E, tet[2], tet[3]);
164 else if (
auto triMesh = std::dynamic_pointer_cast<SurfaceMesh>(m_geom))
166 std::shared_ptr<VecDataArray<int, 3>> elementsPtr = triMesh->getCells();
168 const auto nV = triMesh->getNumVertices();
169 std::vector<std::vector<bool>> E(nV, std::vector<bool>(nV, 1));
171 for (
int k = 0; k < elements.size(); ++k)
173 auto& tri = elements[k];
174 addDistConstraint(E, tri[0], tri[1]);
175 addDistConstraint(E, tri[0], tri[2]);
176 addDistConstraint(E, tri[1], tri[2]);
179 else if (
auto lineMesh = std::dynamic_pointer_cast<LineMesh>(m_geom))
181 std::shared_ptr<VecDataArray<int, 2>> elementsPtr = lineMesh->getCells();
183 const auto& nV = lineMesh->getNumVertices();
184 std::vector<std::vector<bool>> E(nV, std::vector<bool>(nV, 1));
186 for (
int k = 0; k < elements.size(); k++)
188 auto& seg = elements[k];
189 addDistConstraint(E, seg[0], seg[1]);
194 LOG(WARNING) <<
"PbdDistanceConstraint can only be generated with a TetrahedralMesh, SurfaceMesh, or LineMesh";
202 std::shared_ptr<std::unordered_set<size_t>> vertices)
override 204 std::shared_ptr<VecDataArray<double, 3>> initVerticesPtr = m_geom->getInitialVertexPositions();
207 std::set<std::pair<int, int>> distanceSet;
208 if (
auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(m_geom))
210 std::shared_ptr<VecDataArray<int, 3>> elementsPtr = surfMesh->getCells();
214 std::vector<std::vector<int>> vertexToCellMap(surfMesh->getNumVertices());
215 for (
int i = 0; i < elements.size(); i++)
217 const Vec3i& cell = elements[i];
219 vertexToCellMap[cell[1]].push_back(i);
220 vertexToCellMap[cell[2]].push_back(i);
222 for (std::vector<int>& faceIds : vertexToCellMap)
224 std::sort(faceIds.begin(), faceIds.end());
227 for (
const size_t vertIdx : *vertices)
229 const int vid =
static_cast<int>(vertIdx);
230 for (
const int cellId : vertexToCellMap[vertIdx])
232 const Vec3i& cell = elements[cellId];
235 for (
int i = 0; i < 3; i++)
237 if (cell[i] == static_cast<int>(vertIdx))
239 i1 = cell[(i + 1) % 3];
240 i2 = cell[(i + 2) % 3];
244 auto pair1 = std::make_pair(std::min(vid, i1), std::max(vid, i1));
245 auto pair2 = std::make_pair(std::min(vid, i2), std::max(vid, i2));
246 distanceSet.insert(pair1);
247 distanceSet.insert(pair2);
251 else if (
auto lineMesh = std::dynamic_pointer_cast<LineMesh>(m_geom))
253 std::shared_ptr<VecDataArray<int, 2>> elementsPtr = lineMesh->getCells();
257 std::vector<std::vector<int>> vertexToCellMap(lineMesh->getNumVertices());
258 for (
int k = 0; k < elements.size(); k++)
260 const Vec2i& cell = elements[k];
262 vertexToCellMap[cell[1]].push_back(k);
264 for (std::vector<int>& faceIds : vertexToCellMap)
266 std::sort(faceIds.begin(), faceIds.end());
269 for (
const size_t vertIdx : *vertices)
271 for (
const int triIdx : vertexToCellMap[vertIdx])
273 const Vec2i& cell = elements[triIdx];
275 auto pair1 = std::make_pair(std::min(cell[0], cell[1]), std::max(cell[0], cell[1]));
276 distanceSet.insert(pair1);
282 LOG(FATAL) <<
"Add element constraints does not support current mesh type";
286 for (
auto& c : distanceSet)
288 auto constraint = makeDistConstraint(initVertices, c.first, c.second);
297 double getStiffness()
const {
return m_stiffness; }
304 void setStretch(
double val) { m_stretch = val; }
308 double m_stiffness = 0.0;
309 double m_stretch = 1.0;
326 CHECK(std::dynamic_pointer_cast<TetrahedralMesh>(m_geom) !=
nullptr)
327 <<
"PbdFemTetConstraint can only be generated with a TetrahedralMesh";
333 std::shared_ptr<VecDataArray<int, 4>> elementsPtr = tetMesh->getCells();
336 std::shared_ptr<VecDataArray<double, 3>> strainParameters;
338 if (tetMesh->hasCellAttribute(TetrahedralMesh::StrainParameterName))
340 strainParameters = tetMesh->getStrainParameters();
343 ParallelUtils::parallelFor(elements.size(),
346 const Vec4i& tet = elements[k];
348 PbdFemTetConstraint::MaterialType materialType = m_matType;
350 if (strainParameters && strainParameters->at(k)[0] >= 0)
352 materialType =
static_cast<PbdFemTetConstraint::MaterialType
>((int)strainParameters->at(k)[0]);
353 config.setYoungAndPoisson(strainParameters->at(k)[1], strainParameters->at(k)[2]);
356 auto c = std::make_shared<PbdFemTetConstraint>(materialType);
359 vertices[tet[0]], vertices[tet[1]], vertices[tet[2]], vertices[tet[3]],
360 { m_bodyIndex, tet[0] }, { m_bodyIndex, tet[1] },
361 { m_bodyIndex, tet[2] }, { m_bodyIndex, tet[3] },
364 }, elements.size() > 100);
367 void setMaterialType(
const PbdFemTetConstraint::MaterialType materialType) { m_matType = materialType; }
368 PbdFemTetConstraint::MaterialType getMaterialType()
const {
return m_matType; }
370 void setFemConfig(std::shared_ptr<PbdFemConstraintConfig> femConfig) { m_femConfig = femConfig; }
371 std::shared_ptr<PbdFemConstraintConfig> getFemConfig()
const {
return m_femConfig; }
374 PbdFemTetConstraint::MaterialType m_matType = PbdFemTetConstraint::MaterialType::StVK;
375 std::shared_ptr<PbdFemConstraintConfig> m_femConfig =
nullptr;
392 CHECK(std::dynamic_pointer_cast<TetrahedralMesh>(m_geom) !=
nullptr)
393 <<
"PbdVolumeConstraint can only be generated with a TetrahedralMesh";
399 std::shared_ptr<VecDataArray<int, 4>> elementsPtr = tetMesh->getCells();
402 ParallelUtils::parallelFor(elements.size(),
405 auto& tet = elements[k];
406 auto c = std::make_shared<PbdVolumeConstraint>();
408 vertices[tet[0]], vertices[tet[1]], vertices[tet[2]], vertices[tet[3]],
409 { m_bodyIndex, tet[0] }, { m_bodyIndex, tet[1] },
410 { m_bodyIndex, tet[2] }, { m_bodyIndex, tet[3] },
420 double getStiffness()
const {
return m_stiffness; }
424 double m_stiffness = 0.0;
441 CHECK(std::dynamic_pointer_cast<SurfaceMesh>(m_geom) !=
nullptr)
442 <<
"PbdAreaConstraint can only be generated with a SurfaceMesh";
445 auto triMesh = std::dynamic_pointer_cast<
SurfaceMesh>(m_geom);
448 std::shared_ptr<VecDataArray<int, 3>> elemenstPtr = triMesh->getCells();
451 ParallelUtils::parallelFor(elements.size(),
454 auto& tri = elements[k];
455 auto c = std::make_shared<PbdAreaConstraint>();
456 c->initConstraint(vertices[tri[0]], vertices[tri[1]], vertices[tri[2]],
457 { m_bodyIndex, tri[0] }, { m_bodyIndex, tri[1] }, { m_bodyIndex, tri[2] },
464 std::shared_ptr<std::unordered_set<size_t>> vertices)
override 467 CHECK(std::dynamic_pointer_cast<SurfaceMesh>(m_geom) !=
nullptr)
468 <<
"Add element constraints does not support current mesh type.";
470 auto triMesh = std::dynamic_pointer_cast<
SurfaceMesh>(m_geom);
472 std::shared_ptr<VecDataArray<int, 3>> elementsPtr = triMesh->getCells();
478 std::vector<std::vector<size_t>> vertexToTriMap(triMesh->getNumVertices());
479 for (
int k = 0; k < elements.size(); k++)
481 const Vec3i& tri = elements[k];
483 vertexToTriMap[tri[1]].push_back(k);
484 vertexToTriMap[tri[2]].push_back(k);
486 for (std::vector<size_t>& faceIds : vertexToTriMap)
488 std::sort(faceIds.begin(), faceIds.end());
491 std::unordered_set<size_t> areaSet;
492 for (
const size_t& vertIdx : *vertices)
494 for (
const size_t& triIdx : vertexToTriMap[vertIdx])
496 areaSet.insert(triIdx);
500 auto addAreaConstraint =
501 [&](
size_t k,
double stiffness)
503 const Vec3i& tri = elements[k];
504 auto c = std::make_shared<PbdAreaConstraint>();
505 c->initConstraint(initVertices[tri[0]], initVertices[tri[1]], initVertices[tri[2]],
506 { m_bodyIndex, tri[0] }, { m_bodyIndex, tri[1] }, { m_bodyIndex, tri[2] },
512 for (
auto& c : areaSet)
514 addAreaConstraint(c, m_stiffness);
522 double getStiffness()
const {
return m_stiffness; }
526 double m_stiffness = 0.0;
543 CHECK(std::dynamic_pointer_cast<LineMesh>(m_geom) !=
nullptr)
544 <<
"PbdBendConstraint can only be generated with a LineMesh";
546 auto lineMesh = std::dynamic_pointer_cast<
LineMesh>(m_geom);
552 auto addBendConstraint =
553 [&](
const double k,
int i1,
int i2,
int i3)
566 auto c = std::make_shared<PbdBendConstraint>();
567 if (m_restLengthOverride >= 0.0)
569 c->initConstraint({ m_bodyIndex, i1 }, { m_bodyIndex, i2 }, { m_bodyIndex, i3 },
570 m_restLengthOverride, k);
574 c->initConstraint(vertices[i1], vertices[i2], vertices[i3],
575 { m_bodyIndex, i1 }, { m_bodyIndex, i2 }, { m_bodyIndex, i3 }, k);
581 for (
int k = 0; k < vertices.size() - m_stride * 2; k++)
583 addBendConstraint(m_stiffness, k, k + m_stride, k + 2 * m_stride);
591 double getStiffness()
const {
return m_stiffness; }
601 CHECK(m_stride >= 1) <<
"Stride should be at least 1.";
604 int getStride()
const {
return m_stride; }
612 void setRestLength(
const double restLength) { m_restLengthOverride = restLength; }
616 double m_stiffness = 0.0;
618 double m_restLengthOverride = -1.0;
636 CHECK(std::dynamic_pointer_cast<SurfaceMesh>(m_geom) !=
nullptr)
637 <<
"PbdDihedralConstraint can only be generated with a SurfaceMesh";
640 auto triMesh = std::dynamic_pointer_cast<
SurfaceMesh>(m_geom);
643 std::shared_ptr<VecDataArray<int, 3>> elementsPtr = triMesh->getCells();
645 const int nV = triMesh->getNumVertices();
646 std::vector<std::vector<int>> vertIdsToTriangleIds(nV);
648 for (
int k = 0; k < elements.size(); ++k)
650 const Vec3i& tri = elements[k];
651 vertIdsToTriangleIds[tri[0]].
push_back(k);
652 vertIdsToTriangleIds[tri[1]].push_back(k);
653 vertIdsToTriangleIds[tri[2]].push_back(k);
657 std::vector<std::vector<bool>> E(nV, std::vector<bool>(nV, 1));
659 auto addDihedralConstraint =
660 [&](
const std::vector<int>& r1,
const std::vector<int>& r2,
661 const int k,
int i1,
int i2)
672 std::vector<size_t> rs(2);
673 auto it = std::set_intersection(r1.begin(), r1.end(), r2.begin(), r2.end(), rs.begin());
674 rs.resize(static_cast<size_t>(it - rs.begin()));
677 int idx = (rs[0] == k) ? 1 : 0;
678 const Vec3i& tri0 = elements[k];
679 const Vec3i& tri1 = elements[rs[idx]];
682 for (
int i = 0; i < 3; i++)
684 if (tri0[i] != i1 && tri0[i] != i2)
688 if (tri1[i] != i1 && tri1[i] != i2)
693 auto c = std::make_shared<PbdDihedralConstraint>();
694 c->initConstraint(vertices[idx0], vertices[idx1], vertices[i1], vertices[i2],
695 { m_bodyIndex, idx0 }, { m_bodyIndex, idx1 },
696 { m_bodyIndex, i1 }, { m_bodyIndex, i2 }, m_stiffness);
702 for (
size_t i = 0; i < vertIdsToTriangleIds.size(); i++)
704 std::sort(vertIdsToTriangleIds[i].begin(), vertIdsToTriangleIds[i].end());
708 for (
int k = 0; k < elements.size(); ++k)
710 const Vec3i& tri = elements[k];
713 std::vector<int>& neighborTriangles0 = vertIdsToTriangleIds[tri[0]];
714 std::vector<int>& neighborTriangles1 = vertIdsToTriangleIds[tri[1]];
715 std::vector<int>& neighborTriangles2 = vertIdsToTriangleIds[tri[2]];
718 addDihedralConstraint(neighborTriangles0, neighborTriangles1, k, tri[0], tri[1]);
719 addDihedralConstraint(neighborTriangles0, neighborTriangles2, k, tri[0], tri[2]);
720 addDihedralConstraint(neighborTriangles1, neighborTriangles2, k, tri[1], tri[2]);
725 std::shared_ptr<std::unordered_set<size_t>> vertices)
override 728 CHECK(std::dynamic_pointer_cast<SurfaceMesh>(m_geom) !=
nullptr)
729 <<
"Add element constraints does not support current mesh type.";
731 auto triMesh = std::dynamic_pointer_cast<
SurfaceMesh>(m_geom);
733 std::shared_ptr<VecDataArray<int, 3>> elementsPtr = triMesh->getCells();
739 std::vector<std::vector<size_t>> vertexToTriMap(triMesh->getNumVertices());
740 for (
int k = 0; k < elements.size(); k++)
742 const Vec3i& tri = elements[k];
744 vertexToTriMap[tri[1]].push_back(k);
745 vertexToTriMap[tri[2]].push_back(k);
747 for (std::vector<size_t>& faceIds : vertexToTriMap)
749 std::sort(faceIds.begin(), faceIds.end());
752 std::map<std::pair<size_t, size_t>, std::pair<size_t, size_t>> dihedralSet;
753 for (
const size_t& vertIdx : *vertices)
755 for (
const size_t& triIdx : vertexToTriMap[vertIdx])
757 const Vec3i& tri = elements[triIdx];
758 for (
size_t i = 0; i < 3; i++)
760 size_t j = (i + 1) % 3;
767 const std::vector<size_t>& r0 = vertexToTriMap[i0];
768 const std::vector<size_t>& r1 = vertexToTriMap[i1];
769 std::vector<size_t> rs(2);
770 auto it = std::set_intersection(r0.begin(), r0.end(), r1.begin(), r1.end(), rs.begin());
771 rs.resize(static_cast<size_t>(it - rs.begin()));
774 dihedralSet[std::make_pair(i0, i1)] = std::make_pair(rs[0], rs[1]);
780 auto addDihedralConstraint =
781 [&](
int t0,
int t1,
int i1,
int i2,
double stiffness)
783 const Vec3i& tri0 = elements[t0];
784 const Vec3i& tri1 = elements[t1];
787 for (
int i = 0; i < 3; i++)
789 if (tri0[i] != i1 && tri0[i] != i2)
793 if (tri1[i] != i1 && tri1[i] != i2)
798 auto c = std::make_shared<PbdDihedralConstraint>();
799 c->initConstraint(initVertices[idx0], initVertices[idx1], initVertices[i1], initVertices[i2],
800 { m_bodyIndex, idx0 }, { m_bodyIndex, idx1 },
801 { m_bodyIndex, i1 }, { m_bodyIndex, i2 },
807 for (
auto& c : dihedralSet)
809 addDihedralConstraint(
810 static_cast<int>(c.second.first), static_cast<int>(c.second.second),
811 static_cast<int>(c.first.first), static_cast<int>(c.first.second),
820 double getStiffness()
const {
return m_stiffness; }
824 double m_stiffness = 0.0;
842 CHECK(std::dynamic_pointer_cast<PointSet>(m_geom) !=
nullptr)
843 <<
"PbdConstantDensityConstraint can only be generated with a PointSet";
845 auto c = std::make_shared<PbdConstantDensityConstraint>();
846 c->initConstraint(m_geom->getNumVertices(), m_bodyIndex, m_particleRadius, m_restDensity);
854 double getStiffness()
const {
return m_stiffness; }
861 double getParticleRadius()
const {
return m_particleRadius; }
868 double getRestDensity()
const {
return m_restDensity; }
872 double m_stiffness = 0.0;
873 double m_particleRadius = 0.2;
874 double m_restDensity = 6378.0;
PbdBendConstraintFunctor generates constraints per cell of a LineMesh.
void setRestDensity(const double restDensity)
Get/Set the resting density, default rest density of water for m.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
Container for pbd constraints.
virtual void reserve(const size_t n)
Reserve an amount of constraints in the pool, if you know ahead of time the number of constraints...
virtual std::shared_ptr< PbdDistanceConstraint > makeDistConstraint(const VecDataArray< double, 3 > &vertices, int i1, int i2)
Create the distance constraint.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
void setParticleRadius(const double particleRadius)
Get/Set the stiffness, how hard the constraint is.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
const std::vector< std::shared_ptr< PbdConstraint > > & getConstraints() const
Get the underlying container.
void setStiffness(const double stiffness)
Get/Set the stiffness, how hard the constraint is.
void setStiffness(const double stiffness)
Get/Set the stiffness, how hard the constraint is.
void setStiffness(const double stiffness)
Get/Set the stiffness, how hard the constraint is.
void push_back(const ValueType &val)
Append the data array to hold the new value, resizes if neccesary.
void setStiffness(const double stiffness)
Get/Set the stiffness, how hard the constraint is.
virtual void addConstraints(PbdConstraintContainer &imstkNotUsed(constraints), std::shared_ptr< std::unordered_set< size_t >> imstkNotUsed(vertices))
Appends a set of constraint to the container given a geometry and a set of newly inserted vertices Th...
Represents a set of tetrahedrons & vertices via an array of Vec3d double vertices & Vec4i integer ind...
PbdFemTetConstraintFunctor generates constraints per cell of a TetrahedralMesh.
PbdConstantDensityConstraintFunctor generates a global constant density constraint for an entire Poin...
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...
PbdConstraintFunctor that can be forwarded out to a function pointer.
void setStiffness(const double stiffness)
Get/Set the stiffness, how hard the constraint is.
void addConstraints(PbdConstraintContainer &constraints, std::shared_ptr< std::unordered_set< size_t >> vertices) override
Called when topology changed.
void setStiffness(const double stiffness)
Get/Set the stiffness, how hard the constraint is.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
PbdAreaConstraintFunctor generates constraints per cell of a SurfaceMesh.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
void operator()(PbdConstraintContainer &constraints) override
Appends a set of constraint to the container given a geometry & body.
PbdDistanceConstraintFunctor generates constraints between the edges of the input TetrahedralMesh...
std::shared_ptr< VecDataArray< double, 3 > > getInitialVertexPositions() const
Returns the vector of initial positions of the mesh vertices.
PbdConstraintFunctor take input geometry and produce constraints. It exists to allow extensible const...
virtual void addConstraint(std::shared_ptr< PbdConstraint > constraint)
Adds a constraint to the system, thread safe.
virtual void operator()(PbdConstraintContainer &constraints)=0
Appends a set of constraint to the container given a geometry & body.
double getRestLength() const
Get/Set the rest length, if not specified or negative the rest length will default to what it was whe...
PbdDihedralConstraintFunctor generates constraints per pair of triangle neighbors in a SurfaceMesh...
void setStride(const int stride)
Get/Set the stride, that is the amount of lines between every bend constraint.
PbdVolumeConstraintFunctor generates constraints per cell of a TetrahedralMesh.
Either mu/lambda used, may be computed from youngs modulus and poissons ratio.
Abstract PbdConstraintFunctor that assumes usage of a singular body & geometry.
double getStretch() const
Get/Set the factor that modifies the restlength.