iMSTK
Interactive Medical Simulation Toolkit
imstkPbdObjectCutting.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 "imstkPbdObjectCutting.h"
8 #include "imstkAnalyticalGeometry.h"
9 #include "imstkLineMesh.h"
10 #include "imstkLineMeshCut.h"
11 #include "imstkPbdConstraintContainer.h"
12 #include "imstkPbdModel.h"
13 #include "imstkPbdObject.h"
14 #include "imstkPbdSolver.h"
15 #include "imstkSurfaceMesh.h"
16 #include "imstkSurfaceMeshCut.h"
17 #include "imstkLineMeshCut.h"
18 
19 namespace imstk
20 {
21 PbdObjectCutting::PbdObjectCutting(std::shared_ptr<PbdObject> pbdObj, std::shared_ptr<CollidingObject> cutObj) :
22  m_objA(pbdObj), m_objB(cutObj)
23 {
24  CHECK(std::dynamic_pointer_cast<SurfaceMesh>(pbdObj->getPhysicsGeometry()) != nullptr
25  || std::dynamic_pointer_cast<LineMesh>(pbdObj->getPhysicsGeometry())) <<
26  "PbdObj is not a SurfaceMesh, could not create cutting pair";
27 
28  // check whether cut object is valid
29  if (std::dynamic_pointer_cast<SurfaceMesh>(cutObj->getCollidingGeometry()) == nullptr
30  && std::dynamic_pointer_cast<AnalyticalGeometry>(cutObj->getCollidingGeometry()) == nullptr)
31  {
32  LOG(WARNING) << "CutObj is neither a SurfaceMesh nor an AnalyticalGeometry, could not create cutting pair";
33  return;
34  }
35 }
36 
37 void
39 {
40  std::shared_ptr<PbdModel> pbdModel = m_objA->getPbdModel();
41 
42  m_addConstraintVertices->clear();
43  m_removeConstraintVertices->clear();
44 
45  // Perform cutting
46  if (auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(m_objA->getPhysicsGeometry()))
47  {
48  SurfaceMeshCut cutter;
49  cutter.setInputMesh(surfMesh);
50  cutter.setCutGeometry(m_objB->getCollidingGeometry());
51  cutter.setEpsilon(m_epsilon);
52  cutter.update();
53 
54  std::shared_ptr<SurfaceMesh> newMesh = cutter.getOutputMesh();
55 
56  // Only remove and add constraints related to the topological changes
57  m_removeConstraintVertices = cutter.getRemoveConstraintVertices();
58  m_addConstraintVertices = cutter.getAddConstraintVertices();
59 
60  // update pbd mesh
61  surfMesh->setInitialVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newMesh->getInitialVertexPositions()));
62  surfMesh->setVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newMesh->getVertexPositions()));
63  surfMesh->setCells(std::make_shared<VecDataArray<int, 3>>(*newMesh->getCells()));
64  }
65  else if (auto lineMesh = std::dynamic_pointer_cast<LineMesh>(m_objA->getPhysicsGeometry()))
66  {
67  LineMeshCut cutter;
68  cutter.setInputMesh(lineMesh);
69  cutter.setCutGeometry(m_objB->getCollidingGeometry());
70  cutter.setEpsilon(m_epsilon);
71  cutter.update();
72 
73  std::shared_ptr<LineMesh> newMesh = cutter.getOutputMesh();
74 
75  // Only remove and add constraints related to the topological changes
76  m_removeConstraintVertices = cutter.getRemoveConstraintVertices();
77  m_addConstraintVertices = cutter.getAddConstraintVertices();
78 
79  // update pbd mesh
80  lineMesh->setInitialVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newMesh->getInitialVertexPositions()));
81  lineMesh->setVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newMesh->getVertexPositions()));
82  lineMesh->setCells(std::make_shared<VecDataArray<int, 2>>(*newMesh->getCells()));
83  }
84 
85  // update pbd states, constraints and solver
86  m_objA->setBodyFromGeometry();
87  pbdModel->getConstraints()->removeConstraints(m_removeConstraintVertices,
88  m_objA->getPbdBody()->bodyHandle);
89  pbdModel->addConstraints(m_addConstraintVertices, m_objA->getPbdBody()->bodyHandle);
90 
91  m_objA->getPhysicsGeometry()->postModified();
92 }
93 
94 void
95 PbdObjectCutting::addVertices(std::shared_ptr<SurfaceMesh> pbdMesh,
96  std::shared_ptr<VecDataArray<double, 3>> newVertices,
97  std::shared_ptr<VecDataArray<double, 3>> newInitialVertices)
98 {
99  auto vertices = pbdMesh->getVertexPositions();
100  auto initialVertices = pbdMesh->getInitialVertexPositions();
101 
102  auto nVertices = vertices->size();
103  auto nNewVertices = newVertices->size();
104  if (nNewVertices != newInitialVertices->size())
105  {
106  LOG(WARNING) << "Number of new vertices does not match number of new initial vertices";
107  return;
108  }
109 
110  vertices->reserve(nVertices + nNewVertices);
111  initialVertices->reserve(nVertices + nNewVertices);
112  for (int i = 0; i < nNewVertices; ++i)
113  {
114  vertices->push_back((*newVertices)[i]);
115  initialVertices->push_back((*newInitialVertices)[i]);
116  }
117 }
118 
119 void
120 PbdObjectCutting::modifyVertices(std::shared_ptr<SurfaceMesh> pbdMesh,
121  std::shared_ptr<std::vector<size_t>> modifiedVertexIndices,
122  std::shared_ptr<VecDataArray<double, 3>> modifiedVertices,
123  std::shared_ptr<VecDataArray<double, 3>> modifiedInitialVertices)
124 {
125  auto vertices = pbdMesh->getVertexPositions();
126  auto initialVertices = pbdMesh->getInitialVertexPositions();
127 
128  auto nModifiedVertices = modifiedVertices->size();
129  if (nModifiedVertices != modifiedInitialVertices->size()
130  || static_cast<size_t>(nModifiedVertices) != modifiedVertexIndices->size())
131  {
132  LOG(WARNING) << "Numbers of vertices do not match.";
133  return;
134  }
135 
136  for (int i = 0; i < nModifiedVertices; ++i)
137  {
138  auto vertexIdx = modifiedVertexIndices->at(i);
139  (*vertices)[vertexIdx] = (*modifiedVertices)[i];
140  (*initialVertices)[vertexIdx] = (*modifiedInitialVertices)[i];
141  m_removeConstraintVertices->insert(vertexIdx);
142  m_addConstraintVertices->insert(vertexIdx);
143  }
144 }
145 
146 void
147 PbdObjectCutting::modifyTriangles(std::shared_ptr<SurfaceMesh> pbdMesh,
148  std::shared_ptr<std::vector<size_t>> modifiedTriangleIndices,
149  std::shared_ptr<VecDataArray<int, 3>> modifiedTriangles)
150 {
151  auto triangles = pbdMesh->getCells();
152  auto nModifiedTriangles = static_cast<size_t>(modifiedTriangles->size());
153  if (nModifiedTriangles != modifiedTriangleIndices->size())
154  {
155  LOG(WARNING) << "Numbers of vertices do not match.";
156  return;
157  }
158 
159  for (size_t i = 0; i < nModifiedTriangles; ++i)
160  {
161  auto triId = (*modifiedTriangleIndices)[i];
162  auto& oldTri = (*triangles)[triId];
163  m_removeConstraintVertices->insert(oldTri[0]);
164  m_removeConstraintVertices->insert(oldTri[1]);
165  m_removeConstraintVertices->insert(oldTri[2]);
166 
167  auto& newTri = (*modifiedTriangles)[i];
168  (*triangles)[triId] = newTri;
169  m_addConstraintVertices->insert(newTri[0]);
170  m_addConstraintVertices->insert(newTri[1]);
171  m_addConstraintVertices->insert(newTri[2]);
172  }
173 }
174 } // namespace imstk
void modifyTriangles(std::shared_ptr< SurfaceMesh > pbdMesh, std::shared_ptr< std::vector< size_t >> elementIndices, std::shared_ptr< VecDataArray< int, 3 >> elements)
Modify existing elements of pbdObj.
void apply()
Applies the cut when called.
Compound Geometry.
void update()
Do the actual algorithm.
void modifyVertices(std::shared_ptr< SurfaceMesh > pbdMesh, std::shared_ptr< std::vector< size_t >> vertexIndices, std::shared_ptr< VecDataArray< double, 3 >> vertices, std::shared_ptr< VecDataArray< double, 3 >> initialVertices)
Modify current vertices of pbdObj.
This filter cuts the lines of a LineMesh into smaller lines using input cutting geometry Only support...
void addVertices(std::shared_ptr< SurfaceMesh > pbdMesh, std::shared_ptr< VecDataArray< double, 3 >> vertices, std::shared_ptr< VecDataArray< double, 3 >> initialVertices)
Add new vertices to pbdObj.
This filter cuts the triangles of a SurfaceMesh into smaller triangles using input cutting geometry...