7 #include "imstkSurfaceMeshCut.h" 8 #include "imstkAnalyticalGeometry.h" 9 #include "imstkGeometryUtilities.h" 10 #include "imstkLogger.h" 11 #include "imstkPlane.h" 12 #include "imstkSurfaceMesh.h" 18 SurfaceMeshCut::SurfaceMeshCut()
21 setOutput(std::make_shared<SurfaceMesh>());
24 std::shared_ptr<SurfaceMesh>
25 SurfaceMeshCut::getOutputMesh()
27 return std::dynamic_pointer_cast<SurfaceMesh>(
getOutput(0));
31 SurfaceMeshCut::setInputMesh(std::shared_ptr<SurfaceMesh> inputMesh)
38 std::map<int, bool>& cutVerts)
40 auto outputSurfaceMesh = std::dynamic_pointer_cast<
SurfaceMesh>(outputGeom);
42 std::shared_ptr<VecDataArray<int, 3>> cells = outputSurfaceMesh->getCells();
43 std::shared_ptr<VecDataArray<double, 3>> vertices = outputSurfaceMesh->getVertexPositions();
44 std::shared_ptr<VecDataArray<double, 3>> initVerts = outputSurfaceMesh->getInitialVertexPositions();
45 cells->reserve(cells->size() * 2);
46 vertices->reserve(vertices->size() * 2);
47 initVerts->reserve(initVerts->size() * 2);
50 std::map<std::pair<int, int>,
int> edgeVertMap;
51 for (
const auto& curCutData : *m_CutData)
53 const int curCutType = curCutData.cutType;
54 const int triId = curCutData.cellId;
55 const int ptId0 = curCutData.ptIds[0];
56 const int ptId1 = curCutData.ptIds[1];
57 const Vec3d& cood0 = curCutData.cutCoords[0];
58 const Vec3d& cood1 = curCutData.cutCoords[1];
59 const Vec3d& initCood0 = curCutData.initCoords[0];
60 const Vec3d& initCood1 = curCutData.initCoords[1];
62 if (curCutType == static_cast<int>(TriCutType::EDGE)
63 || curCutType ==
static_cast<int>(TriCutType::EDGE_VERT))
66 auto edge0 = std::pair<int, int>(ptId0, ptId1);
67 auto edge1 = std::pair<int, int>(ptId1, ptId0);
70 if (edgeVertMap.find(edge1) != edgeVertMap.end())
72 newPtId = edgeVertMap[edge1];
76 newPtId = vertices->size();
77 vertices->push_back(cood0);
78 initVerts->push_back(initCood0);
79 edgeVertMap[edge0] = newPtId;
83 Vec3i ptIds = (*cells)[triId];
85 if (ptIds[0] != ptId0 && ptIds[0] != ptId1)
89 else if (ptIds[1] != ptId0 && ptIds[1] != ptId1)
97 (*cells)[triId] = Vec3i(ptId2, ptId0, newPtId);
98 cells->push_back(Vec3i(ptId2, newPtId, ptId1));
101 if (curCutType == static_cast<int>(TriCutType::EDGE_VERT))
103 cutVerts[ptId2] = (cutVerts.find(ptId2) != cutVerts.end());
104 cutVerts[newPtId] = (cutVerts.find(newPtId) != cutVerts.end());
107 m_RemoveConstraintVertices->insert(ptId0);
108 m_RemoveConstraintVertices->insert(ptId1);
109 m_RemoveConstraintVertices->insert(ptId2);
110 m_AddConstraintVertices->insert(ptId0);
111 m_AddConstraintVertices->insert(ptId1);
112 m_AddConstraintVertices->insert(ptId2);
113 m_AddConstraintVertices->insert(newPtId);
115 else if (curCutType == static_cast<int>(TriCutType::EDGE_EDGE))
120 Vec3i ptIds = (*cells)[triId];
122 if (ptIds[0] != ptId0 && ptIds[0] != ptId1)
126 else if (ptIds[1] != ptId0 && ptIds[1] != ptId1)
135 auto edge00 = std::pair<int, int>(ptId2, ptId0);
136 auto edge01 = std::pair<int, int>(ptId0, ptId2);
137 auto edge10 = std::pair<int, int>(ptId1, ptId2);
138 auto edge11 = std::pair<int, int>(ptId2, ptId1);
141 if (edgeVertMap.find(edge01) != edgeVertMap.end())
143 newPtId0 = edgeVertMap[edge01];
147 newPtId0 = vertices->size();
148 vertices->push_back(cood0);
149 initVerts->push_back(initCood0);
150 edgeVertMap[edge00] = newPtId0;
152 if (edgeVertMap.find(edge11) != edgeVertMap.end())
154 newPtId1 = edgeVertMap[edge11];
158 newPtId1 = vertices->size();
159 vertices->push_back(cood1);
160 initVerts->push_back(initCood1);
161 edgeVertMap[edge10] = newPtId1;
165 (*cells)[triId] = Vec3i(ptId2, newPtId0, newPtId1);
166 cells->push_back(Vec3i(newPtId0, ptId0, ptId1));
167 cells->push_back(Vec3i(newPtId0, ptId1, newPtId1));
170 cutVerts[newPtId0] = (cutVerts.find(newPtId0) != cutVerts.end());
171 cutVerts[newPtId1] = (cutVerts.find(newPtId1) != cutVerts.end());
173 m_RemoveConstraintVertices->insert(ptId0);
174 m_RemoveConstraintVertices->insert(ptId1);
175 m_RemoveConstraintVertices->insert(ptId2);
176 m_AddConstraintVertices->insert(ptId0);
177 m_AddConstraintVertices->insert(ptId1);
178 m_AddConstraintVertices->insert(ptId2);
179 m_AddConstraintVertices->insert(newPtId0);
180 m_AddConstraintVertices->insert(newPtId1);
182 else if (curCutType == static_cast<int>(TriCutType::VERT_VERT))
185 cutVerts[ptId0] = (cutVerts.find(ptId0) != cutVerts.end()) ?
true :
false;
186 cutVerts[ptId1] = (cutVerts.find(ptId1) != cutVerts.end()) ?
true :
false;
188 m_RemoveConstraintVertices->insert(ptId0);
189 m_RemoveConstraintVertices->insert(ptId1);
190 m_AddConstraintVertices->insert(ptId0);
191 m_AddConstraintVertices->insert(ptId1);
202 std::map<int, bool>& cutVerts, std::shared_ptr<Geometry> cuttingGeom)
204 auto outputSurfaceMesh = std::dynamic_pointer_cast<
SurfaceMesh>(outputGeom);
206 std::shared_ptr<VecDataArray<int, 3>> triangles = outputSurfaceMesh->getCells();
207 std::shared_ptr<VecDataArray<double, 3>> vertices = outputSurfaceMesh->getVertexPositions();
208 std::shared_ptr<VecDataArray<double, 3>> initVerts = outputSurfaceMesh->getInitialVertexPositions();
210 std::shared_ptr<ImplicitGeometry> cutGeometry =
nullptr;
211 if (
auto implicitCutGeom = std::dynamic_pointer_cast<ImplicitGeometry>(cuttingGeom))
213 cutGeometry = implicitCutGeom;
215 else if (
auto surfMeshCutGeom = std::dynamic_pointer_cast<SurfaceMesh>(cuttingGeom))
218 auto cutTriangles = surfMeshCutGeom->getCells();
219 auto cutVertices = surfMeshCutGeom->getVertexPositions();
222 const Vec3d p0 = (*cutVertices)[(*cutTriangles)[0][0]];
223 const Vec3d p1 = (*cutVertices)[(*cutTriangles)[0][1]];
224 const Vec3d p2 = (*cutVertices)[(*cutTriangles)[0][2]];
225 const Vec3d cutNormal = ((p1 - p0).cross(p2 - p0)).normalized();
226 cutGeometry = std::make_shared<Plane>(p0, cutNormal);
228 CHECK(cutGeometry !=
nullptr) <<
229 "Unsupported cut geometry. Only SurfaceMesh and ImplicitGeometry supported";
232 std::vector<std::set<int>> vertexNeighborTriangles;
233 vertexNeighborTriangles.clear();
234 vertexNeighborTriangles.resize(vertices->size());
237 for (
const auto& tri : *triangles)
239 vertexNeighborTriangles.at(tri[0]).insert(triangleId);
240 vertexNeighborTriangles.at(tri[1]).insert(triangleId);
241 vertexNeighborTriangles.at(tri[2]).insert(triangleId);
246 for (
const auto& cutVert : cutVerts)
248 if (cutVert.second ==
false && !vertexOnBoundary(triangles, vertexNeighborTriangles[cutVert.first]))
251 (*m_CutVertMap)[cutVert.first] = cutVert.first;
256 int newPtId = vertices->size();
257 vertices->push_back((*vertices)[cutVert.first]);
258 initVerts->push_back((*initVerts)[cutVert.first]);
259 (*m_CutVertMap)[cutVert.first] = newPtId;
260 m_AddConstraintVertices->insert(newPtId);
262 for (
const auto& t : vertexNeighborTriangles[cutVert.first])
265 Vec3d pt0 = (*vertices)[(*triangles)[t][0]];
266 Vec3d pt1 = (*vertices)[(*triangles)[t][1]];
267 Vec3d pt2 = (*vertices)[(*triangles)[t][2]];
273 for (
int i = 0; i < 3; i++)
275 if ((*triangles)[t][i] == cutVert.first)
277 (*triangles)[t][i] = newPtId;
286 std::shared_ptr<std::vector<CutData>>
288 std::shared_ptr<Geometry> cuttingGeom,
289 std::shared_ptr<AbstractCellMesh> geomToCut)
291 if (
auto cuttingSurfMesh = std::dynamic_pointer_cast<SurfaceMesh>(cuttingGeom))
293 return generateSurfaceMeshCutData(cuttingSurfMesh,
294 std::dynamic_pointer_cast<SurfaceMesh>(geomToCut));
296 else if (
auto cuttingAnalyticGeom = std::dynamic_pointer_cast<AnalyticalGeometry>(cuttingGeom))
298 return generateImplicitCutData(cuttingAnalyticGeom,
299 std::dynamic_pointer_cast<SurfaceMesh>(geomToCut));
301 LOG(FATAL) <<
"No case for cut geometry";
305 std::shared_ptr<std::vector<CutData>>
306 SurfaceMeshCut::generateImplicitCutData(std::shared_ptr<AnalyticalGeometry> cuttingGeom,
307 std::shared_ptr<SurfaceMesh> geomToCut)
309 auto cutData = std::make_shared<std::vector<CutData>>();
311 std::shared_ptr<VecDataArray<int, 3>> triangles = geomToCut->getCells();
312 std::shared_ptr<VecDataArray<double, 3>> vertices = geomToCut->getVertexPositions();
313 std::shared_ptr<VecDataArray<double, 3>> initVerts = geomToCut->getInitialVertexPositions();
315 std::set<std::pair<int, int>> repeatEdges;
317 for (
int i = 0; i < triangles->size(); i++)
319 const Vec3i& tri = (*triangles)[i];
330 const int caseType = ptSide.squaredNorm();
336 for (
int j = 0; j < 3; j++)
340 int idx0 = (j + 1) % 3;
341 int idx1 = (j + 2) % 3;
342 int ptId0 = tri[idx0];
343 int ptId1 = tri[idx1];
345 std::pair<int, int> cutEdge = std::make_pair(ptId1, ptId0);
347 if (repeatEdges.find(cutEdge) != repeatEdges.end())
349 newCutData.cutType =
static_cast<int>(TriCutType::VERT_VERT);
350 newCutData.cellId = i;
351 newCutData.ptIds[0] = ptId0;
352 newCutData.ptIds[1] = ptId1;
353 newCutData.cutCoords[0] = (*vertices)[ptId0];
354 newCutData.cutCoords[1] = (*vertices)[ptId1];
355 newCutData.initCoords[0] = (*initVerts)[ptId0];
356 newCutData.initCoords[1] = (*initVerts)[ptId1];
357 cutData->push_back(newCutData);
361 repeatEdges.insert(std::make_pair(ptId0, ptId1));
367 if (ptSide.sum() == 0)
369 for (
int j = 0; j < 3; j++)
373 int idx0 = (j + 1) % 3;
374 int idx1 = (j + 2) % 3;
375 int ptId0 = tri[idx0];
376 int ptId1 = tri[idx1];
377 Vec3d pos0 = (*vertices)[ptId0];
378 Vec3d pos1 = (*vertices)[ptId1];
379 Vec3d initPos0 = (*initVerts)[ptId0];
380 Vec3d initPos1 = (*initVerts)[ptId1];
381 double func0 = cuttingGeom->getFunctionValue(pos0);
382 double func1 = cuttingGeom->getFunctionValue(pos1);
383 double frac = -func0 / (func1 - func0);
385 newCutData.cutType =
static_cast<int>(TriCutType::EDGE_VERT);
386 newCutData.cellId = i;
387 newCutData.ptIds[0] = ptId0;
388 newCutData.ptIds[1] = ptId1;
389 newCutData.cutCoords[0] = frac * (pos1 - pos0) + pos0;
390 newCutData.cutCoords[1] = (*vertices)[tri[j]];
391 newCutData.initCoords[0] = frac * (initPos1 - initPos0) + initPos0;
392 newCutData.initCoords[1] = (*initVerts)[tri[j]];
393 cutData->push_back(newCutData);
403 if (ptSide.sum() == -1 || ptSide.sum() == 1)
405 for (
int j = 0; j < 3; j++)
407 if (ptSide[j] == -ptSide.sum())
409 int idx0 = (j + 1) % 3;
410 int idx1 = (j + 2) % 3;
411 int ptId0 = tri[idx0];
412 int ptId1 = tri[idx1];
414 Vec3d pos0 = (*vertices)[ptId0];
415 Vec3d pos1 = (*vertices)[ptId1];
416 Vec3d pos2 = (*vertices)[ptId2];
417 Vec3d initPos0 = (*initVerts)[ptId0];
418 Vec3d initPos1 = (*initVerts)[ptId1];
419 Vec3d initPos2 = (*initVerts)[ptId2];
420 double func0 = cuttingGeom->getFunctionValue(pos0);
421 double func1 = cuttingGeom->getFunctionValue(pos1);
422 double func2 = cuttingGeom->getFunctionValue(pos2);
423 double frac0 = -func0 / (func2 - func0);
424 double frac1 = -func1 / (func2 - func1);
426 newCutData.cutType =
static_cast<int>(TriCutType::EDGE_EDGE);
427 newCutData.cellId = i;
428 newCutData.ptIds[0] = ptId0;
429 newCutData.ptIds[1] = ptId1;
430 newCutData.cutCoords[0] = frac0 * (pos2 - pos0) + pos0;
431 newCutData.cutCoords[1] = frac1 * (pos2 - pos1) + pos1;
432 newCutData.initCoords[0] = frac0 * (initPos2 - initPos0) + initPos0;
433 newCutData.initCoords[1] = frac1 * (initPos2 - initPos1) + initPos1;
434 cutData->push_back(newCutData);
450 std::shared_ptr<std::vector<CutData>>
451 SurfaceMeshCut::generateSurfaceMeshCutData(std::shared_ptr<SurfaceMesh> cuttingGeom,
452 std::shared_ptr<SurfaceMesh> geomToCut)
454 auto cutData = std::make_shared<std::vector<CutData>>();
456 std::shared_ptr<VecDataArray<int, 3>> cutTriangles = cuttingGeom->getCells();
457 std::shared_ptr<VecDataArray<double, 3>> cutVertices = cuttingGeom->getVertexPositions();
458 std::shared_ptr<VecDataArray<int, 3>> triangles = geomToCut->getCells();
459 std::shared_ptr<VecDataArray<double, 3>> vertices = geomToCut->getVertexPositions();
462 Vec3d p0 = (*cutVertices)[(*cutTriangles)[0][0]];
463 Vec3d p1 = (*cutVertices)[(*cutTriangles)[0][1]];
464 Vec3d p2 = (*cutVertices)[(*cutTriangles)[0][2]];
465 Vec3d cutNormal = (p1 - p0).cross(p2 - p0);
466 auto cutPlane = std::make_shared<Plane>(p0, cutNormal);
469 std::shared_ptr<std::vector<CutData>> planeCutData =
470 generateImplicitCutData(std::dynamic_pointer_cast<AnalyticalGeometry>(cutPlane), geomToCut);
473 for (
const CutData& curCutData : *planeCutData)
475 bool coord0In = pointProjectionInSurface(curCutData.cutCoords[0], cuttingGeom);
476 bool coord1In = pointProjectionInSurface(curCutData.cutCoords[1], cuttingGeom);
477 CutData newCurCutData = curCutData;
479 switch (curCutData.cutType)
481 case static_cast<int>(TriCutType::VERT_VERT):
482 if (coord0In && coord1In)
484 cutData->push_back(newCurCutData);
487 case static_cast<int>(TriCutType::EDGE_VERT):
492 cutData->push_back(newCurCutData);
496 newCurCutData.cutType =
static_cast<int>(TriCutType::EDGE);
497 cutData->push_back(newCurCutData);
501 case static_cast<int>(TriCutType::EDGE_EDGE):
506 cutData->push_back(newCurCutData);
510 auto& tri = (*triangles)[newCurCutData.cellId];
511 for (
int i = 0; i < 3; i++)
513 if (tri[i] == newCurCutData.ptIds[0])
515 int idx0 = (i + 2) % 3;
516 newCurCutData.ptIds[0] = tri[idx0];
517 newCurCutData.ptIds[1] = tri[i];
521 newCurCutData.cutType =
static_cast<int>(TriCutType::EDGE);
522 cutData->push_back(newCurCutData);
527 auto& tri = (*triangles)[newCurCutData.cellId];
528 for (
int i = 0; i < 3; i++)
530 if (tri[i] == curCutData.ptIds[0])
532 int idx0 = (i + 1) % 3;
533 int idx1 = (i + 2) % 3;
534 newCurCutData.ptIds[0] = tri[idx0];
535 newCurCutData.ptIds[1] = tri[idx1];
539 newCurCutData.cutCoords[0] = newCurCutData.cutCoords[1];
540 newCurCutData.initCoords[0] = newCurCutData.initCoords[1];
541 newCurCutData.cutType =
static_cast<int>(TriCutType::EDGE);
542 cutData->push_back(newCurCutData);
void splitVerts(std::shared_ptr< AbstractCellMesh > outputGeom, std::map< int, bool > &cutVerts, std::shared_ptr< Geometry > cuttingGeom) override
Split the cutting vertices, separating them into two.
int ptBoundarySign(const Vec3d &pt, std::shared_ptr< Geometry > geometry)
Determine the sign of the point -1 if inside, 1 if outside, 0 if on boundary defined by epsilon...
void setNumOutputPorts(const size_t numPorts)
Get/Set the amount of output ports.
std::shared_ptr< Geometry > getOutput(size_t port=0) const
Returns output geometry given port, returns nullptr if doesn't exist.
void setInput(std::shared_ptr< Geometry > inputGeometry, size_t port=0)
Set the input at the port.
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
std::shared_ptr< std::vector< CutData > > generateCutData(std::shared_ptr< Geometry > cuttingGeom, std::shared_ptr< AbstractCellMesh > geomToCut) override
Generate CutData which defines how the cut should be performed.
void setOutput(std::shared_ptr< Geometry > inputGeometry, const size_t port=0)
Set the output at the port.
void refinement(std::shared_ptr< AbstractCellMesh > outputGeom, std::map< int, bool > &cutVerts) override
Refine the mesh adding vertices and changing connectivity along the cut.