7 #include "imstkPbdObjectCellRemoval.h" 8 #include "imstkPbdConstraintContainer.h" 9 #include "imstkPbdModel.h" 10 #include "imstkPbdObject.h" 11 #include "imstkCellMesh.h" 12 #include "imstkSurfaceMesh.h" 13 #include "imstkPointwiseMap.h" 14 #include "imstkTetrahedralMesh.h" 22 static const std::array<imstk::Vec3i, 4> facePattern = {
23 imstk::Vec3i(0, 1, 2), imstk::Vec3i(0, 1, 3), imstk::Vec3i(0, 2, 3), imstk::Vec3i(1, 2, 3)
27 isOn(imstk::Vec3i tri, imstk::Vec4i tet)
29 const auto& triArray = tet.array();
30 for (
int i = 0; i < 3; ++i)
32 if (!(triArray == tri[i]).any())
41 getFace(
const std::array<imstk::Vec3i, 4>& pattern,
const imstk::Vec4i& tet,
int index)
44 tet[pattern[index][0]],
45 tet[pattern[index][1]],
46 tet[pattern[index][2]]);
50 tryGetSharedFace(imstk::Vec4i left, imstk::Vec4i right, std::pair<imstk::Vec3i, imstk::Vec3i>& faces)
52 for (
int leftIndex = 0; leftIndex < 4; ++leftIndex)
54 auto leftFace = getFace(facePattern, left, leftIndex);
55 for (
int rightIndex = 0; rightIndex < 4; ++rightIndex)
57 auto rightFace = getFace(facePattern, right, rightIndex);
59 for (
int i = 0; i < 3; ++i)
61 if (!(leftFace.array() == rightFace[i]).any())
69 faces.first = leftFace;
70 faces.second = rightFace;
81 PbdObjectCellRemoval::PbdObjectCellRemoval(std::shared_ptr<PbdObject> pbdObj, OtherMeshUpdateType alsoUpdate) :
83 m_updateMode(alsoUpdate)
88 m_mesh = std::dynamic_pointer_cast<AbstractCellMesh>(pbdObj->getPhysicsGeometry());
89 addDummyVertex(m_mesh);
92 for (
int fixedId = 0; fixedId < m_obj->getPbdBody()->fixedNodeIds.size(); fixedId++)
94 m_obj->getPbdBody()->fixedNodeIds[fixedId]++;
101 int alsoUpdateInt =
static_cast<int>(alsoUpdate);
103 if (alsoUpdateInt != 0)
105 auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(m_mesh);
107 if (tetMesh !=
nullptr)
109 if (pbdObj->getCollidingGeometry() == pbdObj->getVisualGeometry() && alsoUpdate != OtherMeshUpdateType::None)
111 alsoUpdate = OtherMeshUpdateType::Collision;
114 tetMesh->computeVertexToCellMap();
116 if ((alsoUpdateInt & static_cast<int>(OtherMeshUpdateType::Collision)) != 0)
118 auto mesh = std::dynamic_pointer_cast<SurfaceMesh>(pbdObj->getCollidingGeometry());
119 auto map = std::dynamic_pointer_cast<PointwiseMap>(pbdObj->getPhysicsToCollidingMap());
122 LOG(WARNING) <<
"Collision mesh not a surface mesh, can't maintain for cell removal";
124 else if (map ==
nullptr)
126 LOG(WARNING) <<
"PhysicsToCollidingMap not a Pointwise map, can't maintain for cell removal";
130 setupForExtraMeshUpdates(mesh, map);
134 if ((alsoUpdateInt & (static_cast<int>(OtherMeshUpdateType::VisualSeparateVertices) |
135 static_cast<int>(OtherMeshUpdateType::VisualReuseVertices))) != 0)
137 auto mesh = std::dynamic_pointer_cast<SurfaceMesh>(pbdObj->getVisualGeometry());
138 auto map = std::dynamic_pointer_cast<PointwiseMap>(pbdObj->getPhysicsToVisualMap());
141 LOG(WARNING) <<
"Visual mesh not a surface mesh, can't maintain for cell removal";
143 else if (map ==
nullptr)
145 LOG(WARNING) <<
"PhysicsToVisualMap not a Pointwise map, can't maintain for cell removal";
149 setupForExtraMeshUpdates(mesh, map);
150 m_linkedMeshData.back().newVertexOnSplit = alsoUpdate == OtherMeshUpdateType::VisualSeparateVertices;
156 LOG(WARNING) <<
"Underlying mesh not a tet mesh, cannot maintain other meshes";
157 m_updateMode = OtherMeshUpdateType::None;
165 m_cellsToRemove.push_back(cellId);
171 if (m_cellsToRemove.empty())
177 for (
auto& data : m_linkedMeshData)
184 m_removedCells.insert(m_removedCells.end(), m_cellsToRemove.begin(), m_cellsToRemove.end());
185 std::sort(m_removedCells.begin(), m_removedCells.end());
186 m_cellsToRemove.clear();
192 PbdObjectCellRemoval::updateMesh(LinkedMeshData& data)
194 auto cellVerts = std::dynamic_pointer_cast<
DataArray<int>>(m_mesh->getAbstractCells());
196 constexpr
int vertsPerTri = 3;
198 auto& triangles = *(data.surfaceMesh->getCells());
199 auto& vertices = *(data.surfaceMesh->getVertexPositions());
204 for (
int cellId : m_cellsToRemove)
206 auto range = data.tetToTriMap.equal_range(cellId);
207 for (
auto item = range.first; item != range.second; ++item)
209 triangles[item->second] = { 0, 0, 0 };
211 data.tetToTriMap.erase(cellId);
214 const auto& tetrahedra = *(tetMesh->getCells());
215 const auto& tetVertices = *(tetMesh->getVertexPositions());
218 for (
int cellId : m_cellsToRemove)
221 auto range = data.tetAdjancencyMap.equal_range(cellId);
222 for (
auto item = range.first; item != range.second; ++item)
224 auto otherTetIndex = item->second.first;
227 if (std::find(m_cellsToRemove.cbegin(), m_cellsToRemove.cend(), otherTetIndex) != m_cellsToRemove.cend()
228 || std::find(m_removedCells.cbegin(), m_removedCells.cend(), otherTetIndex) != m_removedCells.cend())
233 auto faceOnTetMesh = item->second.second;
235 Vec3i triangle = { 0, 0, 0 };
236 for (
int i = 0; i < vertsPerTri; ++i)
238 int tetVertexIndex = faceOnTetMesh[i];
241 auto found = data.tetVertToTriVertMap.find(tetVertexIndex);
245 if (data.newVertexOnSplit || found == data.tetVertToTriVertMap.cend())
247 triangle[i] = vertices.size();
248 vertices.push_back(tetVertices[tetVertexIndex]);
249 data.tetVertToTriVertMap[tetVertexIndex] = triangle[i];
250 data.map->addNewUniquePoint(triangle[i], tetVertexIndex);
254 triangle[i] = found->second;
258 const Vec3d& v0 = tetVertices[faceOnTetMesh[0]];
259 const Vec3d& v1 = tetVertices[faceOnTetMesh[1]];
260 const Vec3d& v2 = tetVertices[faceOnTetMesh[2]];
261 const Vec3d normal = ((v1 - v0).cross(v2 - v0));
262 const Vec3d centroid = (v0 + v1 + v2) / 3.0;
264 const Vec4i& tet = tetrahedra[otherTetIndex];
265 const Vec3d tetCentroid =
266 (tetVertices[tet[0]] +
267 tetVertices[tet[1]] +
268 tetVertices[tet[2]] +
269 tetVertices[tet[3]]) / 4.0;
271 int triangleIndex = triangles.size();
274 if (normal.dot(centroid - tetCentroid) < 0)
276 triangles.push_back({ triangle[0], triangle[2], triangle[1] });
280 triangles.push_back(triangle);
282 data.tetToTriMap.insert({ otherTetIndex, triangleIndex });
284 data.tetAdjancencyMap.erase(cellId);
287 for (
int cellId : m_cellsToRemove)
292 if (!m_cellsToRemove.empty())
294 data.surfaceMesh->postModified();
295 data.surfaceMesh->getVertexPositions()->postModified();
296 data.surfaceMesh->getCells()->postModified();
301 PbdObjectCellRemoval::removeConstraints()
304 int bodyId = m_obj->getPbdBody()->bodyHandle;
305 const int vertsPerCell = m_mesh->getAbstractCells()->getNumberOfComponents();
306 auto cellVerts = std::dynamic_pointer_cast<
DataArray<int>>(m_mesh->getAbstractCells());
309 std::shared_ptr<PbdConstraintContainer> constraintsPtr = m_obj->getPbdModel()->getConstraints();
310 const std::vector<std::shared_ptr<PbdConstraint>>& constraints = constraintsPtr->getConstraints();
312 for (
int i = 0; i < m_cellsToRemove.size(); i++)
314 int cellId = m_cellsToRemove[i];
317 for (
auto j = constraints.begin(); j != constraints.end();)
319 const std::vector<PbdParticleId>& vertexIds = (*j)->getParticles();
323 for (
int cVertId = 0; cVertId < vertexIds.size(); cVertId++)
325 if (vertexIds[cVertId].first == bodyId)
341 bool isOnlyBody =
true;
342 for (
int cVertId = 0; cVertId < vertexIds.size(); cVertId++)
344 if (vertexIds[cVertId].first != bodyId)
352 std::unordered_set<int> constraintVertIds;
353 std::unordered_set<int> cellVertIds;
355 for (
int vertId = 0; vertId < vertsPerCell; vertId++)
357 cellVertIds.insert((*cellVerts)[cellId * vertsPerCell + vertId]);
360 for (
int cVertId = 0; cVertId < vertexIds.size(); cVertId++)
362 constraintVertIds.insert(vertexIds[cVertId].second);
366 bool isSubset =
true;
367 for (
const auto& elem : constraintVertIds)
369 if (cellVertIds.find(elem) == cellVertIds.end())
377 bool isMultiBodyConstraint =
false;
378 if (isOnlyBody ==
false)
380 for (
int cVertId = 0; cVertId < vertexIds.size(); cVertId++)
382 if (vertexIds[cVertId].first == bodyId && cellVertIds.find(vertexIds[cVertId].second) != cellVertIds.end())
384 isMultiBodyConstraint =
true;
389 if (isSubset ==
true || (isMultiBodyConstraint && isSubset ==
false))
391 j = constraintsPtr->eraseConstraint(j);
400 for (
int k = 0; k < vertsPerCell; k++)
402 (*cellVerts)[cellId * vertsPerCell + k] = 0;
406 if (m_cellsToRemove.size() > 0)
411 std::cout <<
"Removing " << m_cellsToRemove.size() <<
" Cells";
416 PbdObjectCellRemoval::fixup()
419 if (volumeMesh ==
nullptr)
424 std::unordered_set<int> validTetVertices;
425 for (
const auto& tet : *volumeMesh->getTetrahedraIndices())
427 validTetVertices.insert(tet[0]);
428 validTetVertices.insert(tet[1]);
429 validTetVertices.insert(tet[2]);
430 validTetVertices.insert(tet[3]);
433 for (
auto& meshData : m_linkedMeshData)
435 auto map = meshData.map->getMap();
436 auto& triangles = *(meshData.surfaceMesh->getTriangleIndices());
437 for (
auto& tri : triangles)
439 for (
int j = 0; j < 3; j++)
441 if (tri[j] != 0 && validTetVertices.find(map[tri[j]]) == validTetVertices.end())
452 PbdObjectCellRemoval::setupForExtraMeshUpdates(std::shared_ptr<SurfaceMesh> surfaceMesh, std::shared_ptr<PointwiseMap> map)
456 CHECK(tetMesh !=
nullptr);
457 CHECK(surfaceMesh !=
nullptr);
458 CHECK(map !=
nullptr);
461 data.surfaceMesh = surfaceMesh;
464 std::multimap<int, int> tetToTriMap;
465 std::multimap<int, std::pair<int, Vec3i>> tetAdjancencyMap;
467 const auto& tetrahedra = *(tetMesh->getCells());
468 const auto& triangles = *(surfaceMesh->getCells());
471 addDummyVertex(surfaceMesh);
475 for (
auto entry : map->getMap())
477 data.tetVertToTriVertMap[entry.second] = entry.first;
483 const auto& triVertToTetVertMap = map->getMap();
485 for (
int tetIndex = 0; tetIndex < tetrahedra.size(); ++tetIndex)
487 const auto& tet = tetrahedra[tetIndex];
490 for (
int triIndex = 0; triIndex < triangles.size(); ++triIndex)
492 Vec3i triangle = triangles[triIndex];
493 bool allInTet =
true;
494 for (
int i = 0; i < 3; ++i)
496 auto found = triVertToTetVertMap.find(triangle[i]);
497 if (found == triVertToTetVertMap.cend())
502 triangle[i] = found->second;
505 if (allInTet && isOn(triangle, tet))
507 tetToTriMap.insert({ tetIndex, triIndex });
514 for (
int otherTetIndex = 0; otherTetIndex < tetrahedra.size(); ++otherTetIndex)
516 if (tetIndex == otherTetIndex)
522 auto range = tetAdjancencyMap.equal_range(otherTetIndex);
523 auto found = std::find_if(range.first, range.second, [tetIndex](
const auto& item) { return item.second.first == tetIndex; });
524 if (found != range.second)
529 auto other = tetrahedra[otherTetIndex];
530 std::pair<Vec3i, Vec3i> faces;
531 if (tryGetSharedFace(tet, other, faces))
533 tetAdjancencyMap.insert({ tetIndex, { otherTetIndex, faces.second } });
534 tetAdjancencyMap.insert({ otherTetIndex, { tetIndex, faces.first } });
539 data.tetToTriMap = tetToTriMap;
540 data.tetAdjancencyMap = tetAdjancencyMap;
541 m_linkedMeshData.push_back(data);
545 PbdObjectCellRemoval::addDummyVertexPointSet(std::shared_ptr<PointSet> pointSet)
548 std::shared_ptr<VecDataArray<double, 3>> verticesPtr = pointSet->getVertexPositions();
550 vertices.
resize(vertices.size() + 1);
552 for (
int i = vertices.size() - 1; i >= 1; i--)
554 vertices[i] = vertices[i - 1];
558 vertices[0] = Vec3d(0.0, 0.0, 0.0);
563 PbdObjectCellRemoval::addDummyVertex(std::shared_ptr<AbstractCellMesh> mesh)
565 addDummyVertexPointSet(mesh);
568 const int vertsPerCell = mesh->getAbstractCells()->getNumberOfComponents();
569 auto cellVerts = std::dynamic_pointer_cast<
DataArray<int>>(mesh->getAbstractCells());
572 for (
int cellId = 0; cellId < mesh->getNumCells(); cellId++)
574 for (
int vertId = 0; vertId < vertsPerCell; vertId++)
576 (*cellVerts)[cellId * vertsPerCell + vertId]++;
void removeCellOnApply(int cellId)
Adds cell to list of cells to be removed.
void resize(const int size) override
Resize data array to hold exactly size number of values.
Represents a set of tetrahedrons & vertices via an array of Vec3d double vertices & Vec4i integer ind...
void postModified()
emits signal to all observers, informing them on the current address in memory and size of array ...
void setTetrahedraAsRemoved(const unsigned int tetId)
Get/set method for removed elements from the mesh.
void apply()
removed cells and associated constraints
Simple dynamic array implementation that also supports event posting and viewing/facade.