7 #include "imstkGeometryUtilities.h" 8 #include "imstkCapsule.h" 9 #include "imstkCylinder.h" 10 #include "imstkHexahedralMesh.h" 11 #include "imstkImageData.h" 12 #include "imstkLineMesh.h" 13 #include "imstkLogger.h" 14 #include "imstkOrientedBox.h" 15 #include "imstkParallelUtils.h" 16 #include "imstkPlane.h" 17 #include "imstkSphere.h" 18 #include "imstkSurfaceMesh.h" 19 #include "imstkTetrahedralMesh.h" 21 #include <vtkCapsuleSource.h> 22 #include <vtkCellData.h> 23 #include <vtkCharArray.h> 24 #include <vtkCleanPolyData.h> 25 #include <vtkCubeSource.h> 26 #include <vtkCylinderSource.h> 27 #include <vtkDoubleArray.h> 28 #include <vtkFeatureEdges.h> 29 #include <vtkFloatArray.h> 30 #include <vtkImageData.h> 31 #include <vtkMassProperties.h> 32 #include <vtkPlaneSource.h> 33 #include <vtkPointData.h> 34 #include <vtkShortArray.h> 35 #include <vtkSphereSource.h> 36 #include <vtkTransform.h> 37 #include <vtkTransformFilter.h> 38 #include <vtkTriangleFilter.h> 39 #include <vtkUnsignedCharArray.h> 40 #include <vtkUnsignedIntArray.h> 41 #include <vtkUnsignedLongArray.h> 42 #include <vtkUnsignedLongLongArray.h> 43 #include <vtkUnsignedShortArray.h> 44 #include <vtkUnstructuredGrid.h> 46 static vtkSmartPointer<vtkDataArray>
47 makeVtkDataArray(
unsigned char type)
49 vtkSmartPointer<vtkDataArray> arr =
nullptr;
53 arr = vtkSmartPointer<vtkCharArray>::New();
55 case VTK_UNSIGNED_CHAR:
56 arr = vtkSmartPointer<vtkUnsignedCharArray>::New();
59 arr = vtkSmartPointer<vtkShortArray>::New();
61 case VTK_UNSIGNED_SHORT:
62 arr = vtkSmartPointer<vtkUnsignedShortArray>::New();
65 arr = vtkSmartPointer<vtkIntArray>::New();
67 case VTK_UNSIGNED_INT:
68 arr = vtkSmartPointer<vtkUnsignedIntArray>::New();
71 arr = vtkSmartPointer<vtkFloatArray>::New();
74 arr = vtkSmartPointer<vtkDoubleArray>::New();
77 arr = vtkSmartPointer<vtkLongLongArray>::New();
79 case VTK_UNSIGNED_LONG:
80 arr = vtkSmartPointer<vtkUnsignedLongArray>::New();
82 case VTK_UNSIGNED_LONG_LONG:
83 arr = vtkSmartPointer<vtkUnsignedLongLongArray>::New();
85 LOG(WARNING) <<
"Unknown scalar type";
94 vtkSmartPointer<vtkDataArray>
97 CHECK(imstkArray !=
nullptr) <<
"AbstractDataArray provided is not valid!";
98 CHECK(imstkArray->getVoidPointer() !=
nullptr) <<
"AbstractDataArray data provided is not valid!";
101 vtkSmartPointer<vtkDataArray> arr = makeVtkDataArray(imstkToVtkScalarType[imstkArray->getScalarType()]);
102 arr->SetNumberOfComponents(imstkArray->getNumberOfComponents());
103 arr->SetVoidArray(imstkArray->getVoidPointer(), imstkArray->size(), 1);
108 vtkSmartPointer<vtkImageData>
109 GeometryUtils::coupleVtkImageData(std::shared_ptr<ImageData> imageData)
111 CHECK(imageData !=
nullptr) <<
"ImageData provided is not valid!";
114 std::shared_ptr<AbstractDataArray> arr = imageData->getScalars();
117 vtkSmartPointer<vtkImageData> imageDataVtk = vtkSmartPointer<vtkImageData>::New();
118 imageDataVtk->SetDimensions(imageData->getDimensions().data());
119 imageDataVtk->SetSpacing(imageData->getSpacing().data());
120 const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5;
121 imageDataVtk->SetOrigin(vtkOrigin.data());
122 imageDataVtk->SetNumberOfScalarComponents(imageData->getNumComponents(), imageDataVtk->GetInformation());
123 imageDataVtk->SetScalarType(imstkToVtkScalarType[arr->getScalarType()], imageDataVtk->GetInformation());
124 imageDataVtk->GetPointData()->SetScalars(vtkArr);
128 vtkSmartPointer<vtkDataArray>
131 CHECK(imstkArray !=
nullptr) <<
"AbstractDataArray provided is not valid!";
134 vtkSmartPointer<vtkDataArray> arr = makeVtkDataArray(imstkToVtkScalarType[imstkArray->getScalarType()]);
135 arr->SetNumberOfComponents(imstkArray->getNumberOfComponents());
136 arr->SetNumberOfTuples(imstkArray->size() / imstkArray->getNumberOfComponents());
137 switch (imstkArray->getScalarType())
139 TemplateMacro(std::copy_n(static_cast<IMSTK_TT*>(imstkArray->getVoidPointer()), imstkArray->size(),
static_cast<IMSTK_TT*
>(arr->GetVoidPointer(0))); );
141 LOG(WARNING) <<
"Unknown scalar type";
148 std::shared_ptr<AbstractDataArray>
149 GeometryUtils::copyToDataArray(vtkSmartPointer<vtkDataArray> vtkArray)
151 CHECK(vtkArray !=
nullptr) <<
"vtkDataArray provided is not valid!";
153 std::shared_ptr<AbstractDataArray> arr =
nullptr;
155 const int numComps = vtkArray->GetNumberOfComponents();
158 switch (vtkToImstkScalarType[vtkArray->GetDataType()])
165 arr = std::make_shared<DataArray<IMSTK_TT>>(vtkArray->GetNumberOfTuples() * vtkArray->GetNumberOfComponents());
166 std::copy_n(static_cast<IMSTK_TT*>(vtkArray->GetVoidPointer(0)), vtkArray->GetNumberOfValues(),
static_cast<IMSTK_TT*
>(arr->getVoidPointer()));
168 else if (numComps == 2)
170 arr = (std::make_shared<VecDataArray<IMSTK_TT, 2>>(vtkArray->GetNumberOfTuples()));
171 std::copy_n(static_cast<IMSTK_TT*>(vtkArray->GetVoidPointer(0)), vtkArray->GetNumberOfValues(),
static_cast<IMSTK_TT*
>(arr->getVoidPointer()));
173 else if (numComps == 3)
175 arr = (std::make_shared<VecDataArray<IMSTK_TT, 3>>(vtkArray->GetNumberOfTuples()));
176 std::copy_n(static_cast<IMSTK_TT*>(vtkArray->GetVoidPointer(0)), vtkArray->GetNumberOfValues(),
static_cast<IMSTK_TT*
>(arr->getVoidPointer()));
178 else if (numComps == 4)
180 arr = (std::make_shared<VecDataArray<IMSTK_TT, 4>>(vtkArray->GetNumberOfTuples()));
181 std::copy_n(static_cast<IMSTK_TT*>(vtkArray->GetVoidPointer(0)), vtkArray->GetNumberOfValues(),
static_cast<IMSTK_TT*
>(arr->getVoidPointer()));
185 LOG(WARNING) <<
"Unknown scalar type";
191 std::shared_ptr<ImageData>
192 GeometryUtils::copyToImageData(vtkSmartPointer<vtkImageData> vtkImage)
194 CHECK(vtkImage !=
nullptr) <<
"vtkImageData provided is not valid!";
196 double* spacingPtr = vtkImage->GetSpacing();
197 const Vec3d spacing = Vec3d(spacingPtr[0], spacingPtr[1], spacingPtr[2]);
199 double* bounds = vtkImage->GetBounds();
201 const Vec3d origin = Vec3d(bounds[0], bounds[2], bounds[4]) - spacing * 0.5;
203 std::unique_ptr<ImageData> imageData = std::make_unique<ImageData>();
204 imageData->setScalars(copyToDataArray(vtkImage->GetPointData()->GetScalars()),
205 vtkImage->GetNumberOfScalarComponents(), vtkImage->GetDimensions());
206 imageData->setSpacing(spacing);
207 imageData->setOrigin(origin);
211 vtkSmartPointer<vtkImageData>
212 GeometryUtils::copyToVtkImageData(std::shared_ptr<ImageData> imageData)
214 CHECK(imageData !=
nullptr) <<
"ImageData provided is not valid!";
217 const Vec3i& dim = imageData->getDimensions();
219 vtkSmartPointer<vtkImageData> imageDataVtk = vtkSmartPointer<vtkImageData>::New();
220 imageDataVtk->SetSpacing(imageData->getSpacing().data());
221 const Vec3d vtkOrigin = imageData->getOrigin() + imageData->getSpacing() * 0.5;
222 imageDataVtk->SetOrigin(vtkOrigin.data());
223 imageDataVtk->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
224 imageDataVtk->AllocateScalars(imstkToVtkScalarType[imageData->getScalarType()], imageData->getNumComponents());
225 imageDataVtk->GetPointData()->SetScalars(
copyToVtkDataArray(imageData->getScalars()));
229 std::shared_ptr<PointSet>
232 CHECK(vtkMesh !=
nullptr) <<
"vtkPolyData provided is not valid!";
234 std::shared_ptr<VecDataArray<double, 3>> vertices =
copyToVecDataArray(vtkMesh->GetPoints());
236 auto mesh = std::make_unique<PointSet>();
237 mesh->initialize(vertices);
240 std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> dataMap;
242 if (!dataMap.empty())
244 mesh->setVertexAttributes(dataMap);
245 vtkPointData* pointData = vtkMesh->GetPointData();
246 vtkDataArray* normals = pointData->GetNormals();
247 vtkDataArray* tCoords = pointData->GetTCoords();
248 vtkDataArray* scalars = pointData->GetScalars();
249 vtkDataArray* tangents = pointData->GetTangents();
250 if (normals !=
nullptr)
252 mesh->setVertexNormals(std::string(normals->GetName()));
254 if (tCoords !=
nullptr)
256 mesh->setVertexTCoords(std::string(tCoords->GetName()));
258 if (scalars !=
nullptr)
260 mesh->setVertexScalars(std::string(scalars->GetName()));
262 if (tangents !=
nullptr)
264 mesh->setVertexTangents(std::string(tangents->GetName()));
271 std::shared_ptr<SurfaceMesh>
274 CHECK(vtkMesh !=
nullptr) <<
"vtkPolyData provided is not valid!";
276 std::shared_ptr<VecDataArray<double, 3>> vertices =
copyToVecDataArray(vtkMesh->GetPoints());
277 std::shared_ptr<VecDataArray<int, 3>> cells = copyToVecDataArray<3>(vtkMesh->GetPolys());
279 auto mesh = std::make_unique<SurfaceMesh>();
280 mesh->initialize(vertices, cells);
283 std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> vertexDataMap;
285 if (!vertexDataMap.empty())
287 mesh->setVertexAttributes(vertexDataMap);
288 vtkPointData* pointData = vtkMesh->GetPointData();
289 vtkDataArray* normals = pointData->GetNormals();
290 vtkDataArray* tCoords = pointData->GetTCoords();
291 vtkDataArray* scalars = pointData->GetScalars();
292 vtkDataArray* tangents = pointData->GetTangents();
293 if (normals !=
nullptr)
295 mesh->setVertexNormals(std::string(normals->GetName()));
297 if (tCoords !=
nullptr)
299 mesh->setVertexTCoords(std::string(tCoords->GetName()));
301 if (scalars !=
nullptr)
303 mesh->setVertexScalars(std::string(scalars->GetName()));
305 if (tangents !=
nullptr)
307 mesh->setVertexTangents(std::string(tangents->GetName()));
312 std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> cellDataMap;
314 if (!cellDataMap.empty())
316 mesh->setCellAttributes(cellDataMap);
317 vtkCellData* cellData = vtkMesh->GetCellData();
318 vtkDataArray* normals = cellData->GetNormals();
319 vtkDataArray* scalars = cellData->GetScalars();
320 vtkDataArray* tangents = cellData->GetTangents();
321 if (normals !=
nullptr)
323 mesh->setCellNormals(std::string(normals->GetName()));
325 if (scalars !=
nullptr)
327 mesh->setCellScalars(std::string(scalars->GetName()));
329 if (tangents !=
nullptr)
331 mesh->setCellTangents(std::string(tangents->GetName()));
336 if (
auto pointData = vtkMesh->GetPointData())
338 if (
auto tcoords = pointData->GetTCoords())
340 mesh->setVertexTCoords(tcoords->GetName());
347 std::shared_ptr<TetrahedralMesh>
349 const Vec3d& center,
const Vec3d& size,
const Vec3i& dim,
350 const Quatd orientation)
352 auto verticesPtr = std::make_shared<VecDataArray<double, 3>>(dim[0] * dim[1] * dim[2]);
354 const Vec3d dx = size.cwiseQuotient((dim - Vec3i(1, 1, 1)).cast<double>());
356 for (
int z = 0; z < dim[2]; z++)
358 for (
int y = 0; y < dim[1]; y++)
360 for (
int x = 0; x < dim[0]; x++, iter++)
362 vertices[iter] = Vec3i(x, y, z).
cast<
double>().cwiseProduct(dx) - size * 0.5 + center;
368 auto indicesPtr = std::make_shared<VecDataArray<int, 4>>();
370 for (
int z = 0; z < dim[2] - 1; z++)
372 for (
int y = 0; y < dim[1] - 1; y++)
374 for (
int x = 0; x < dim[0] - 1; x++)
378 x + dim[0] * (y + dim[1] * z),
379 (x + 1) + dim[0] * (y + dim[1] * z),
380 (x + 1) + dim[0] * (y + dim[1] * (z + 1)),
381 x + dim[0] * (y + dim[1] * (z + 1)),
382 x + dim[0] * ((y + 1) + dim[1] * z),
383 (x + 1) + dim[0] * ((y + 1) + dim[1] * z),
384 (x + 1) + dim[0] * ((y + 1) + dim[1] * (z + 1)),
385 x + dim[0] * ((y + 1) + dim[1] * (z + 1))
389 if ((z % 2 ^ x % 2) ^ y % 2)
391 indices.
push_back(Vec4i(cubeIndices[0], cubeIndices[7], cubeIndices[5], cubeIndices[4]));
392 indices.push_back(Vec4i(cubeIndices[3], cubeIndices[7], cubeIndices[2], cubeIndices[0]));
393 indices.push_back(Vec4i(cubeIndices[2], cubeIndices[7], cubeIndices[5], cubeIndices[0]));
394 indices.push_back(Vec4i(cubeIndices[1], cubeIndices[2], cubeIndices[0], cubeIndices[5]));
395 indices.push_back(Vec4i(cubeIndices[2], cubeIndices[6], cubeIndices[7], cubeIndices[5]));
399 indices.push_back(Vec4i(cubeIndices[3], cubeIndices[7], cubeIndices[6], cubeIndices[4]));
400 indices.push_back(Vec4i(cubeIndices[1], cubeIndices[3], cubeIndices[6], cubeIndices[4]));
401 indices.push_back(Vec4i(cubeIndices[3], cubeIndices[6], cubeIndices[2], cubeIndices[1]));
402 indices.push_back(Vec4i(cubeIndices[1], cubeIndices[6], cubeIndices[5], cubeIndices[4]));
403 indices.push_back(Vec4i(cubeIndices[0], cubeIndices[3], cubeIndices[1], cubeIndices[4]));
410 for (
int i = 0; i < indices.size(); i++)
412 if (tetVolume(vertices[indices[i][0]], vertices[indices[i][1]], vertices[indices[i][2]], vertices[indices[i][3]]) < 0.0)
414 std::swap(indices[i][0], indices[i][2]);
418 auto tetMesh = std::make_shared<TetrahedralMesh>();
419 tetMesh->initialize(verticesPtr, indicesPtr);
420 tetMesh->rotate(orientation, Geometry::TransformType::ApplyToData);
424 std::shared_ptr<SurfaceMesh>
426 const Vec3d& center,
const Vec2d& size,
const Vec2i& dim,
427 const Quatd orientation,
428 const double uvScale)
431 std::make_shared<VecDataArray<double, 3>>(dim[0] * dim[1]);
433 const Vec3d size3 = Vec3d(size[0], 0.0, size[1]);
434 const Vec3i dim3 = Vec3i(dim[0], 0, dim[1]);
435 Vec3d dx = size3.cwiseQuotient((dim3 - Vec3i(1, 0, 1)).cast<double>());
438 for (
int y = 0; y < dim[1]; y++)
440 for (
int x = 0; x < dim[0]; x++, iter++)
442 vertices[iter] = Vec3i(x, 0, y).cast<
double>().cwiseProduct(dx) + center - size3 * 0.5;
447 auto indicesPtr = std::make_shared<VecDataArray<int, 3>>();
449 for (
int y = 0; y < dim[1] - 1; y++)
451 for (
int x = 0; x < dim[0] - 1; x++)
453 const int index1 = y * dim[0] + x;
454 const int index2 = index1 + dim[0];
455 const int index3 = index1 + 1;
456 const int index4 = index2 + 1;
461 indices.
push_back(Vec3i(index1, index2, index3));
462 indices.push_back(Vec3i(index4, index3, index2));
466 indices.push_back(Vec3i(index2, index4, index1));
467 indices.push_back(Vec3i(index4, index3, index1));
472 auto uvCoordsPtr = std::make_shared<VecDataArray<float, 2>>(dim[0] * dim[1]);
475 for (
int i = 0; i < dim[1]; i++)
477 for (
int j = 0; j < dim[0]; j++, iter++)
479 uvCoords[iter] = Vec2f(
480 static_cast<float>(i) / dim[1],
481 static_cast<float>(j) / dim[0]) * uvScale;
485 auto triMesh = std::make_shared<SurfaceMesh>();
486 triMesh->initialize(verticesPtr, indicesPtr);
487 triMesh->setVertexTCoords(
"uvs", uvCoordsPtr);
488 triMesh->rotate(orientation, Geometry::TransformType::ApplyToData);
492 std::shared_ptr<LineMesh>
494 const Vec3d& start,
const Vec3d& dir,
495 const double length,
const int dim)
497 auto verticesPtr = std::make_shared<VecDataArray<double, 3>>(dim);
498 const Vec3d dirN = dir.normalized();
500 for (
int i = 0; i < dim; i++)
502 double t =
static_cast<double>(i) / (dim - 1);
503 vertices[i] = start + dirN * t * length;
507 auto indicesPtr = std::make_shared<VecDataArray<int, 2>>();
509 for (
int i = 0; i < dim - 1; i++)
515 auto lineMesh = std::make_shared<LineMesh>();
516 lineMesh->initialize(verticesPtr, indicesPtr);
520 std::shared_ptr<LineMesh>
523 CHECK(vtkMesh !=
nullptr) <<
"vtkPolyData provided is not valid!";
525 std::shared_ptr<VecDataArray<double, 3>> vertices =
copyToVecDataArray(vtkMesh->GetPoints());
526 std::shared_ptr<VecDataArray<int, 2>> cells = copyToVecDataArray<2>(vtkMesh->GetPolys());
529 if (cells->size() == 0)
531 cells = copyToVecDataArray<2>(vtkMesh->GetLines());
534 auto mesh = std::make_unique<LineMesh>();
535 mesh->initialize(vertices, cells);
538 std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> dataMap;
540 if (!dataMap.empty())
542 mesh->setVertexAttributes(dataMap);
543 vtkPointData* pointData = vtkMesh->GetPointData();
544 vtkDataArray* normals = pointData->GetNormals();
545 vtkDataArray* tCoords = pointData->GetTCoords();
546 vtkDataArray* scalars = pointData->GetScalars();
547 vtkDataArray* tangents = pointData->GetTangents();
548 if (normals !=
nullptr)
550 mesh->setVertexNormals(std::string(normals->GetName()));
552 if (tCoords !=
nullptr)
554 mesh->setVertexTCoords(std::string(tCoords->GetName()));
556 if (scalars !=
nullptr)
558 mesh->setVertexScalars(std::string(scalars->GetName()));
560 if (tangents !=
nullptr)
562 mesh->setVertexTangents(std::string(tangents->GetName()));
567 std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> cellDataMap;
569 if (!cellDataMap.empty())
571 mesh->setCellAttributes(cellDataMap);
572 vtkCellData* cellData = vtkMesh->GetCellData();
573 vtkDataArray* scalars = cellData->GetScalars();
574 if (scalars !=
nullptr)
576 mesh->setCellScalars(std::string(scalars->GetName()));
583 std::shared_ptr<AbstractCellMesh>
586 CHECK(vtkMesh !=
nullptr) <<
"vtkUnstructuredGrid provided is not valid!";
588 std::shared_ptr<VecDataArray<double, 3>> vertices =
copyToVecDataArray(vtkMesh->GetPoints());
590 const int cellType = vtkMesh->GetCellType(vtkMesh->GetNumberOfCells() - 1);
591 std::shared_ptr<AbstractCellMesh> vMesh =
nullptr;
592 if (cellType == VTK_TETRA)
594 std::shared_ptr<VecDataArray<int, 4>> cells = copyToVecDataArray<4>(vtkMesh->GetCells());
596 std::shared_ptr<TetrahedralMesh> mesh = std::make_unique<TetrahedralMesh>();
598 mesh->initialize(vertices, cells);
600 else if (cellType == VTK_HEXAHEDRON)
602 std::shared_ptr<VecDataArray<int, 8>> cells = copyToVecDataArray<8>(vtkMesh->GetCells());
604 std::shared_ptr<HexahedralMesh> mesh = std::make_unique<HexahedralMesh>();
606 mesh->initialize(vertices, cells);
610 LOG(FATAL) <<
"No support for vtkCellType = " 615 std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> vertexDataMap;
617 if (!vertexDataMap.empty())
619 vMesh->setVertexAttributes(vertexDataMap);
620 vtkPointData* pointData = vtkMesh->GetPointData();
621 vtkDataArray* normals = pointData->GetNormals();
622 vtkDataArray* tCoords = pointData->GetTCoords();
623 vtkDataArray* scalars = pointData->GetScalars();
624 vtkDataArray* tangents = pointData->GetTangents();
625 if (normals !=
nullptr)
627 vMesh->setVertexNormals(std::string(normals->GetName()));
629 if (tCoords !=
nullptr)
631 vMesh->setVertexTCoords(std::string(tCoords->GetName()));
633 if (scalars !=
nullptr)
635 vMesh->setVertexScalars(std::string(scalars->GetName()));
637 if (tangents !=
nullptr)
639 vMesh->setVertexTangents(std::string(tangents->GetName()));
657 vtkSmartPointer<vtkPointSet>
660 vtkSmartPointer<vtkPoints> points =
copyToVtkPoints(imstkMesh->getVertexPositions());
662 auto polydata = vtkSmartPointer<vtkPolyData>::New();
663 polydata->SetPoints(points);
666 if (imstkMesh->getActiveVertexNormals() !=
"")
668 polydata->GetPointData()->SetActiveNormals(imstkMesh->getActiveVertexNormals().c_str());
670 if (imstkMesh->getActiveVertexScalars() !=
"")
672 polydata->GetPointData()->SetActiveScalars(imstkMesh->getActiveVertexScalars().c_str());
674 if (imstkMesh->getActiveVertexTangents() !=
"")
676 polydata->GetPointData()->SetActiveTangents(imstkMesh->getActiveVertexTangents().c_str());
678 if (imstkMesh->getActiveVertexTCoords() !=
"")
680 polydata->GetPointData()->SetActiveTCoords(imstkMesh->getActiveVertexTCoords().c_str());
686 vtkSmartPointer<vtkPolyData>
689 vtkSmartPointer<vtkPoints> points =
copyToVtkPoints(imstkMesh->getVertexPositions());
691 vtkSmartPointer<vtkCellArray> polys = copyToVtkCellArray<2>(imstkMesh->getCells());
693 auto polydata = vtkSmartPointer<vtkPolyData>::New();
694 polydata->SetPoints(points);
695 polydata->SetLines(polys);
699 if (imstkMesh->getActiveVertexNormals() !=
"")
701 polydata->GetPointData()->SetActiveNormals(imstkMesh->getActiveVertexNormals().c_str());
703 if (imstkMesh->getActiveVertexScalars() !=
"")
705 polydata->GetPointData()->SetActiveScalars(imstkMesh->getActiveVertexScalars().c_str());
707 if (imstkMesh->getActiveVertexTangents() !=
"")
709 polydata->GetPointData()->SetActiveTangents(imstkMesh->getActiveVertexTangents().c_str());
711 if (imstkMesh->getActiveVertexTCoords() !=
"")
713 polydata->GetPointData()->SetActiveTCoords(imstkMesh->getActiveVertexTCoords().c_str());
718 if (imstkMesh->getActiveCellScalars() !=
"")
720 polydata->GetCellData()->SetActiveScalars(imstkMesh->getActiveCellScalars().c_str());
726 vtkSmartPointer<vtkPolyData>
729 vtkSmartPointer<vtkPoints> points =
copyToVtkPoints(imstkMesh->getVertexPositions());
730 vtkSmartPointer<vtkCellArray> polys = copyToVtkCellArray<3>(imstkMesh->getCells());
732 auto polydata = vtkSmartPointer<vtkPolyData>::New();;
733 polydata->SetPoints(points);
734 polydata->SetPolys(polys);
738 if (imstkMesh->getActiveVertexNormals() !=
"")
740 polydata->GetPointData()->SetActiveNormals(imstkMesh->getActiveVertexNormals().c_str());
742 if (imstkMesh->getActiveVertexScalars() !=
"")
744 polydata->GetPointData()->SetActiveScalars(imstkMesh->getActiveVertexScalars().c_str());
746 if (imstkMesh->getActiveVertexTangents() !=
"")
748 polydata->GetPointData()->SetActiveTangents(imstkMesh->getActiveVertexTangents().c_str());
750 if (imstkMesh->getActiveVertexTCoords() !=
"")
752 polydata->GetPointData()->SetActiveTCoords(imstkMesh->getActiveVertexTCoords().c_str());
757 if (imstkMesh->getActiveCellNormals() !=
"")
759 polydata->GetCellData()->SetActiveNormals(imstkMesh->getActiveCellNormals().c_str());
761 if (imstkMesh->getActiveCellScalars() !=
"")
763 polydata->GetCellData()->SetActiveScalars(imstkMesh->getActiveCellScalars().c_str());
765 if (imstkMesh->getActiveCellTangents() !=
"")
767 polydata->GetCellData()->SetActiveTangents(imstkMesh->getActiveCellTangents().c_str());
773 vtkSmartPointer<vtkUnstructuredGrid>
776 vtkSmartPointer<vtkPoints> points =
copyToVtkPoints(imstkMesh->getVertexPositions());
777 vtkSmartPointer<vtkCellArray> tetras = copyToVtkCellArray<4>(imstkMesh->getCells());
779 auto ug = vtkSmartPointer<vtkUnstructuredGrid>::New();
780 ug->SetPoints(points);
781 ug->SetCells(VTK_TETRA, tetras);
784 if (imstkMesh->getActiveVertexNormals() !=
"")
786 ug->GetPointData()->SetActiveNormals(imstkMesh->getActiveVertexNormals().c_str());
788 if (imstkMesh->getActiveVertexScalars() !=
"")
790 ug->GetPointData()->SetActiveScalars(imstkMesh->getActiveVertexScalars().c_str());
792 if (imstkMesh->getActiveVertexTangents() !=
"")
794 ug->GetPointData()->SetActiveTangents(imstkMesh->getActiveVertexTangents().c_str());
796 if (imstkMesh->getActiveVertexTCoords() !=
"")
798 ug->GetPointData()->SetActiveTCoords(imstkMesh->getActiveVertexTCoords().c_str());
806 vtkSmartPointer<vtkUnstructuredGrid>
809 vtkSmartPointer<vtkPoints> points =
copyToVtkPoints(imstkMesh->getVertexPositions());
810 vtkSmartPointer<vtkCellArray> bricks = copyToVtkCellArray<8>(imstkMesh->getCells());
812 auto ug = vtkSmartPointer<vtkUnstructuredGrid>::New();
813 ug->SetPoints(points);
814 ug->SetCells(VTK_HEXAHEDRON, bricks);
817 if (imstkMesh->getActiveVertexNormals() !=
"")
819 ug->GetPointData()->SetActiveNormals(imstkMesh->getActiveVertexNormals().c_str());
821 if (imstkMesh->getActiveVertexScalars() !=
"")
823 ug->GetPointData()->SetActiveScalars(imstkMesh->getActiveVertexScalars().c_str());
825 if (imstkMesh->getActiveVertexTangents() !=
"")
827 ug->GetPointData()->SetActiveTangents(imstkMesh->getActiveVertexTangents().c_str());
829 if (imstkMesh->getActiveVertexTCoords() !=
"")
831 ug->GetPointData()->SetActiveTCoords(imstkMesh->getActiveVertexTCoords().c_str());
839 std::shared_ptr<VecDataArray<double, 3>>
842 CHECK(points !=
nullptr) <<
"No valid point data provided!";
844 std::shared_ptr<VecDataArray<double, 3>> vertices = std::make_shared<VecDataArray<double, 3>>(points->GetNumberOfPoints());
846 for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
849 points->GetPoint(i, pos);
850 vertexData[i] = Vec3d(pos[0], pos[1], pos[2]);
855 vtkSmartPointer<vtkPoints>
858 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
860 points->SetNumberOfPoints(vertexData.size());
861 for (
int i = 0; i < vertexData.size(); i++)
863 points->SetPoint(i, vertexData[i][0], vertexData[i][1], vertexData[i][2]);
869 vtkSmartPointer<vtkCellArray>
872 vtkSmartPointer<vtkCellArray> vtkCells = vtkSmartPointer<vtkCellArray>::New();
875 for (
int i = 0; i < cells.size(); i++)
877 vtkCells->InsertNextCell(dim);
878 for (
size_t k = 0; k < dim; k++)
880 vtkCells->InsertCellPoint(cells[i][k]);
887 std::shared_ptr<VecDataArray<int, dim>>
890 using ValueType =
typename VecDataArray<int, dim>::ValueType;
892 CHECK(vtkCells !=
nullptr) <<
"No cells found!";
894 std::shared_ptr<VecDataArray<int, dim>> indices = std::make_shared<VecDataArray<int, dim>>();
895 indices->reserve(vtkCells->GetNumberOfCells());
897 vtkNew<vtkIdList> vtkCell;
898 vtkCells->InitTraversal();
899 while (vtkCells->GetNextCell(vtkCell))
901 if (vtkCell->GetNumberOfIds() != dim)
906 for (
size_t i = 0; i < dim; i++)
908 cell[i] = vtkCell->GetId(i);
910 indices->push_back(cell);
919 CHECK(dataAttributes !=
nullptr) <<
"No point data provided!";
921 for (
int i = 0; i < dataAttributes->GetNumberOfArrays(); ++i)
923 vtkDataArray* array = dataAttributes->GetArray(i);
924 std::string name =
"unnamed";
925 if (array->GetName() == NULL)
929 while (dataMap.count(name + std::to_string(iter)) != 0)
933 name = name + std::to_string(iter);
934 array->SetName(name.c_str());
938 name = std::string(array->GetName());
940 dataMap[name] = copyToDataArray(array);
947 CHECK(pointData !=
nullptr) <<
"No point data provided!";
949 for (
auto i : dataMap)
954 arr->SetName(i.first.c_str());
956 pointData->AddArray(arr);
960 std::shared_ptr<SurfaceMesh>
962 const unsigned int phiDivisions,
const unsigned int thetaDivisions)
964 vtkNew<vtkSphereSource> sphereSource;
965 sphereSource->SetCenter(sphere->getPosition(Geometry::DataType::PreTransform).data());
966 sphereSource->SetRadius(sphere->getRadius());
967 sphereSource->SetPhiResolution(phiDivisions);
968 sphereSource->SetThetaResolution(thetaDivisions);
969 sphereSource->Update();
971 vtkNew<vtkTransform> transform;
972 transform->SetMatrix(mat4dTranslate(sphere->getPosition()).data());
974 vtkNew<vtkTransformFilter> transformFilter;
975 transformFilter->SetInputData(sphereSource->GetOutput());
976 transformFilter->SetTransform(transform);
977 transformFilter->Update();
978 vtkNew<vtkTriangleFilter> triangulate;
979 triangulate->SetInputData(transformFilter->GetOutput());
980 triangulate->Update();
981 vtkNew<vtkCleanPolyData> cleanData;
982 cleanData->SetInputData(triangulate->GetOutput());
988 std::shared_ptr<SurfaceMesh>
991 vtkSmartPointer<vtkPointSet> results =
nullptr;
992 if (
auto plane = std::dynamic_pointer_cast<Plane>(geom))
994 const Quatd r = Quatd(plane->getRotation());
995 const Vec3d i = r._transformVector(Vec3d(1.0, 0.0, 0.0));
996 const Vec3d j = r._transformVector(Vec3d(0.0, 0.0, 1.0));
999 Vec3d p2 = plane->getPosition() + plane->getWidth() * (i - j);
1000 Vec3d p3 = plane->getPosition() + plane->getWidth() * (-i + j);
1001 Vec3d p4 = plane->getPosition() + plane->getWidth() * (-i - j);
1003 vtkNew<vtkPlaneSource> source;
1004 source->SetOrigin(p4.data());
1005 source->SetPoint1(p3.data());
1006 source->SetPoint2(p2.data());
1008 results = source->GetOutput();
1010 else if (
auto orientedBox = std::dynamic_pointer_cast<OrientedBox>(geom))
1012 vtkNew<vtkCubeSource> source;
1013 Vec3d extents = orientedBox->getExtents(Geometry::DataType::PreTransform);
1014 source->SetCenter(0.0, 0.0, 0.0);
1015 source->SetXLength(extents[0] * 2.0);
1016 source->SetYLength(extents[1] * 2.0);
1017 source->SetZLength(extents[2] * 2.0);
1020 AffineTransform3d T = AffineTransform3d::Identity();
1021 T.translate(orientedBox->getPosition(Geometry::DataType::PostTransform));
1022 T.rotate(orientedBox->getOrientation(Geometry::DataType::PostTransform));
1023 T.scale(orientedBox->getScaling());
1024 T.matrix().transposeInPlace();
1026 vtkNew<vtkTransform> transformVtk;
1027 transformVtk->SetMatrix(T.data());
1029 vtkNew<vtkTransformFilter> transformFilter;
1030 transformFilter->SetInputData(source->GetOutput());
1031 transformFilter->SetTransform(transformVtk);
1032 transformFilter->Update();
1033 results = transformFilter->GetOutput();
1035 else if (
auto cylinder = std::dynamic_pointer_cast<Cylinder>(geom))
1037 vtkNew<vtkCylinderSource> source;
1038 source->SetCenter(0.0, 0.0, 0.0);
1039 source->SetRadius(cylinder->getRadius());
1040 source->SetHeight(cylinder->getLength());
1041 source->SetResolution(20);
1044 AffineTransform3d T = AffineTransform3d::Identity();
1045 T.translate(cylinder->getPosition(Geometry::DataType::PostTransform));
1046 T.rotate(cylinder->getOrientation(Geometry::DataType::PostTransform));
1048 T.matrix().transposeInPlace();
1050 vtkNew<vtkTransform> transformVtk;
1051 transformVtk->SetMatrix(T.data());
1053 vtkNew<vtkTransformFilter> transformFilter;
1054 transformFilter->SetInputData(source->GetOutput());
1055 transformFilter->SetTransform(transformVtk);
1056 transformFilter->Update();
1057 results = transformFilter->GetOutput();
1059 else if (
auto capsule = std::dynamic_pointer_cast<Capsule>(geom))
1061 vtkNew<vtkCapsuleSource> source;
1062 source->SetCenter(0.0, 0.0, 0.0);
1063 source->SetRadius(capsule->getRadius());
1064 source->SetCylinderLength(capsule->getLength());
1065 source->SetLatLongTessellation(20);
1066 source->SetPhiResolution(20);
1067 source->SetThetaResolution(20);
1070 AffineTransform3d T = AffineTransform3d::Identity();
1071 T.translate(capsule->getPosition(Geometry::DataType::PostTransform));
1072 T.rotate(capsule->getOrientation(Geometry::DataType::PostTransform));
1074 T.matrix().transposeInPlace();
1076 vtkNew<vtkTransform> transformVtk;
1077 transformVtk->SetMatrix(T.data());
1079 vtkNew<vtkTransformFilter> transformFilter;
1080 transformFilter->SetInputData(source->GetOutput());
1081 transformFilter->SetTransform(transformVtk);
1082 transformFilter->Update();
1083 results = transformFilter->GetOutput();
1087 LOG(WARNING) <<
"Failed to produce SurfaceMesh from provided AnalyticalGeometry";
1092 vtkNew<vtkTriangleFilter> triangulate;
1093 triangulate->SetInputData(results);
1094 triangulate->Update();
1095 vtkNew<vtkCleanPolyData> cleanData;
1096 cleanData->SetInputConnection(triangulate->GetOutputPort());
1097 cleanData->Update();
1104 vtkNew<vtkFeatureEdges> checkClosed;
1106 checkClosed->FeatureEdgesOff();
1107 checkClosed->BoundaryEdgesOn();
1108 checkClosed->NonManifoldEdgesOn();
1109 checkClosed->Update();
1110 return checkClosed->GetOutput()->GetNumberOfCells();
1116 vtkNew<vtkMassProperties> massProps;
1118 massProps->Update();
1119 return massProps->GetVolume();
1131 template<
typename ElemConn>
1133 buildVertexToVertexConnectivity(
const std::vector<ElemConn>& conn,
1134 const size_t numVerts,
1135 std::vector<std::unordered_set<size_t>>& vertToVert)
1138 std::vector<size_t> vertToElemPtr(numVerts + 1, 0);
1139 std::vector<size_t> vertToElem;
1142 for (
const auto& vertices : conn)
1144 for (
auto vid : vertices)
1146 vertToElemPtr[vid + 1] += 1;
1151 for (
size_t i = 0; i < numVerts; ++i)
1153 vertToElemPtr[i + 1] += vertToElemPtr[i];
1157 auto pos = vertToElemPtr;
1159 const size_t totNum = vertToElemPtr.back();
1161 vertToElem.resize(totNum);
1163 for (
size_t eid = 0; eid < conn.size(); ++eid)
1165 for (
auto vid : conn[eid])
1167 vertToElem[pos[vid]] = eid;
1173 vertToVert.resize(numVerts);
1174 auto getVertexNbrs = [&vertToElem, &vertToElemPtr, &conn, &vertToVert](
const size_t i)
1176 const auto ptr0 = vertToElemPtr[i];
1177 const auto ptr1 = vertToElemPtr[i + 1];
1179 for (
auto ptr = ptr0; ptr < ptr1; ++ptr)
1181 for (
auto vid : conn[vertToElem[ptr]])
1184 vertToVert[i].insert(vid);
1193 ParallelUtils::parallelFor(numVerts, getVertexNbrs);
1204 template<
typename NeighborContainer>
1205 static std::vector<size_t>
1206 RCM(
const std::vector<NeighborContainer>& neighbors)
1208 const size_t invalid = std::numeric_limits<size_t>::max();
1211 auto isGreater = [&neighbors](
const size_t i,
const size_t j) {
1212 return neighbors[i].size() > neighbors[j].size() ? true :
false;
1215 const size_t numVerts = neighbors.size();
1217 std::vector<size_t> P(numVerts);
1218 for (
size_t i = 0; i < numVerts; ++i)
1222 std::sort(P.begin(), P.end(), isGreater);
1231 std::vector<size_t> R(numVerts, invalid);
1232 std::queue<size_t> Q;
1233 std::vector<bool> isInP(numVerts,
true);
1240 auto moveVertexIntoRAndItsNeighborsIntoQ = [&neighbors, &isInP, &pos, &R, &Q](
const size_t vid)
1248 std::set<size_t> unorderedNbrs;
1249 for (
auto nbr : neighbors[vid])
1253 unorderedNbrs.insert(nbr);
1257 for (
auto nbr : unorderedNbrs)
1269 size_t parent = invalid;
1270 for (
size_t vid = pCur; vid < isInP.size(); ++vid)
1280 if (parent == invalid)
1285 moveVertexIntoRAndItsNeighborsIntoQ(parent);
1291 moveVertexIntoRAndItsNeighborsIntoQ(parent);
1297 CHECK(pos == numVerts) <<
"RCM ordering: we should never get here";
1299 std::reverse(R.begin(), R.end());
1311 template<
typename ElemConn>
1312 static std::vector<size_t>
1313 RCM(
const std::vector<ElemConn>& conn,
const size_t numVerts)
1316 std::vector<std::unordered_set<size_t>> vertToVert;
1317 buildVertexToVertexConnectivity(conn, numVerts, vertToVert);
1318 return RCM(vertToVert);
1329 markPointsInsideAndOut(std::vector<bool>& isInside,
1331 const StdVectorOfVec3d& coords)
1334 isInside.resize(coords.size(),
false);
1336 Vec3d aabbMin, aabbMax;
1355 auto triangleRayIntersection = [](
const Vec3d& xyz,
1356 const Vec3d& triVert0,
1357 const Vec3d& triVert1,
1358 const Vec3d& triVert2,
1359 const Vec3d& direction)
1362 constexpr
const double eps = std::numeric_limits<double>::epsilon();
1363 Vec3d edge0 = triVert1 - triVert0;
1364 Vec3d edge1 = triVert2 - triVert0;
1365 Vec3d pvec = direction.cross(edge1);
1366 double det = edge0.dot(pvec);
1368 if (det > -eps && det < eps)
1372 double inv_det = 1.0 / det;
1373 Vec3d tvec = xyz - triVert0;
1374 double u = tvec.dot(pvec) * inv_det;
1375 if (u < 0.0 || u > 1.0)
1379 Vec3d qvec = tvec.cross(edge0);
1380 double v = direction.dot(qvec) * inv_det;
1381 if (v < 0.0 || u + v > 1.0)
1386 double t = edge1.dot(qvec) * inv_det;
1397 std::vector<Vec3d> bBoxMin;
1398 std::vector<Vec3d> bBoxMax;
1404 for (
int idx = 0; idx < surfaceMesh.
getNumCells(); ++idx)
1406 const auto& verts = indices[idx];
1414 bBoxMin[idx][0] = xyz0[0];
1415 bBoxMin[idx][1] = xyz0[1];
1416 bBoxMin[idx][2] = xyz0[2];
1417 bBoxMax[idx][0] = xyz0[0];
1418 bBoxMax[idx][1] = xyz0[1];
1419 bBoxMax[idx][2] = xyz0[2];
1421 bBoxMin[idx][0] = std::min(bBoxMin[idx][0], xyz1[0]);
1422 bBoxMin[idx][1] = std::min(bBoxMin[idx][1], xyz1[1]);
1423 bBoxMin[idx][2] = std::min(bBoxMin[idx][2], xyz1[2]);
1424 bBoxMin[idx][0] = std::min(bBoxMin[idx][0], xyz2[0]);
1425 bBoxMin[idx][1] = std::min(bBoxMin[idx][1], xyz2[1]);
1426 bBoxMin[idx][2] = std::min(bBoxMin[idx][2], xyz2[2]);
1428 bBoxMax[idx][0] = std::max(bBoxMax[idx][0], xyz1[0]);
1429 bBoxMax[idx][1] = std::max(bBoxMax[idx][1], xyz1[1]);
1430 bBoxMax[idx][2] = std::max(bBoxMax[idx][2], xyz1[2]);
1431 bBoxMax[idx][0] = std::max(bBoxMax[idx][0], xyz2[0]);
1432 bBoxMax[idx][1] = std::max(bBoxMax[idx][1], xyz2[1]);
1433 bBoxMax[idx][2] = std::max(bBoxMax[idx][2], xyz2[2]);
1436 auto rayTracingFunc = [&](
const size_t i)
1438 bool outBox = coords[i][0] < aabbMin[0] || coords[i][0] > aabbMax[0]
1439 || coords[i][1] < aabbMin[1] || coords[i][1] > aabbMax[1]
1440 || coords[i][2] < aabbMin[2] || coords[i][2] > aabbMax[2];
1447 const Vec3d direction = { 0.0, 0.0, 1.0 };
1451 int numIntersections = 0;
1454 for (
int j = 0; j < surfaceMesh.
getNumCells(); ++j)
1456 const Vec3i& verts = indices[j];
1459 if (coords[i][2] > bBoxMax[j][2])
1464 if (coords[i][0] > bBoxMax[j][0])
1468 if (coords[i][0] < bBoxMin[j][0])
1472 if (coords[i][1] > bBoxMax[j][1])
1476 if (coords[i][1] < bBoxMin[j][1])
1481 auto intersected = triangleRayIntersection(coords[i],
1492 if (numIntersections % 2 == 1)
1505 ParallelUtils::parallelFor(coords.size(), rayTracingFunc);
1519 markPointsInsideAndOut(std::vector<bool>& isInside,
1527 isInside.resize(coords.size(),
false);
1529 Vec3d aabbMin, aabbMax;
1532 const Vec3d h = { coords[1][0] - coords[0][0], coords[nx][1] - coords[0][1], coords[nx * ny][2] - coords[0][2] };
1539 auto triangleRayIntersection = [](
const Vec3d& xyz,
const Vec3d& triVert0,
const Vec3d& triVert1,
const Vec3d& triVert2,
const Vec3d& direction,
double& distance)
1541 const double eps = std::numeric_limits<double>::epsilon();
1542 const Vec3d edge0 = triVert1 - triVert0;
1543 const Vec3d edge1 = triVert2 - triVert0;
1544 const Vec3d pvec = direction.cross(edge1);
1545 const double det = edge0.dot(pvec);
1547 if (det > -eps && det < eps)
1551 const double inv_det = 1.0 / det;
1552 const Vec3d tvec = xyz - triVert0;
1553 const double u = tvec.dot(pvec) * inv_det;
1554 if (u < 0.0 || u > 1.0)
1558 const Vec3d qvec = tvec.cross(edge0);
1559 const double v = direction.dot(qvec) * inv_det;
1560 if (v < 0.0 || u + v > 1.0)
1565 distance = edge1.dot(qvec) * inv_det;
1576 std::vector<Vec3d> bBoxMin;
1577 std::vector<Vec3d> bBoxMax;
1584 auto findBoundingBox = [&](
const size_t idx)
1586 const auto& verts = indices[idx];
1588 const auto& xyz0 = vertXyz[verts[0]];
1589 const auto& xyz1 = vertXyz[verts[1]];
1590 const auto& xyz2 = vertXyz[verts[2]];
1592 bBoxMin[idx][0] = xyz0[0];
1593 bBoxMin[idx][1] = xyz0[1];
1594 bBoxMin[idx][2] = xyz0[2];
1595 bBoxMax[idx][0] = xyz0[0];
1596 bBoxMax[idx][1] = xyz0[1];
1597 bBoxMax[idx][2] = xyz0[2];
1599 bBoxMin[idx][0] = std::min(bBoxMin[idx][0], xyz1[0]);
1600 bBoxMin[idx][1] = std::min(bBoxMin[idx][1], xyz1[1]);
1601 bBoxMin[idx][2] = std::min(bBoxMin[idx][2], xyz1[2]);
1602 bBoxMin[idx][0] = std::min(bBoxMin[idx][0], xyz2[0]);
1603 bBoxMin[idx][1] = std::min(bBoxMin[idx][1], xyz2[1]);
1604 bBoxMin[idx][2] = std::min(bBoxMin[idx][2], xyz2[2]);
1606 bBoxMax[idx][0] = std::max(bBoxMax[idx][0], xyz1[0]);
1607 bBoxMax[idx][1] = std::max(bBoxMax[idx][1], xyz1[1]);
1608 bBoxMax[idx][2] = std::max(bBoxMax[idx][2], xyz1[2]);
1609 bBoxMax[idx][0] = std::max(bBoxMax[idx][0], xyz2[0]);
1610 bBoxMax[idx][1] = std::max(bBoxMax[idx][1], xyz2[1]);
1611 bBoxMax[idx][2] = std::max(bBoxMax[idx][2], xyz2[2]);
1614 ParallelUtils::parallelFor(surfaceMesh.
getNumCells(), findBoundingBox);
1618 auto rayTracingLine = [&](
const size_t jk)
1620 size_t idx0 = jk * nx;
1621 bool outBox = coords[idx0][0] < aabbMin[0] || coords[idx0][0] > aabbMax[0]
1622 || coords[idx0][1] < aabbMin[1] || coords[idx0][1] > aabbMax[1]
1623 || coords[idx0][2] < aabbMin[2] || coords[idx0][2] > aabbMax[2];
1629 const Vec3d direction = { 1.0, 0.0, 0.0 };
1635 size_t idx = idx0 + i;
1636 int numIntersections = 0;
1638 double distMin = h[0] * (nz + 1);
1640 for (
int j = 0; j < surfaceMesh.
getNumCells(); ++j)
1642 const Vec3i& verts = indices[j];
1645 if (coords[idx][0] > bBoxMax[j][0])
1650 if (coords[idx][1] > bBoxMax[j][1])
1654 if (coords[idx][1] < bBoxMin[j][1])
1658 if (coords[idx][2] > bBoxMax[j][2])
1662 if (coords[idx][2] < bBoxMin[j][2])
1667 auto intersected = triangleRayIntersection(coords[idx],
1676 distMin = std::min(dist, distMin);
1681 size_t iEnd = i +
static_cast<size_t>(distMin / h[0]) + 1;
1682 iEnd = std::min(iEnd, nx);
1684 if (numIntersections % 2 == 1)
1686 for (
size_t ii = idx; ii < idx0 + iEnd; ++ii)
1688 isInside[ii] =
true;
1696 ParallelUtils::parallelFor(ny * nz, rayTracingLine);
1700 std::shared_ptr<TetrahedralMesh>
1702 const Vec3d& aabbMax,
1707 const Vec3d h = { (aabbMax[0] - aabbMin[0]) / nx,
1708 (aabbMax[1] - aabbMin[1]) / ny,
1709 (aabbMax[2] - aabbMin[2]) / nz };
1710 LOG_IF(FATAL, (h[0] <= 0.0 || h[1] <= 0.0 || h[2] <= 0.0)) <<
"Invalid bounding box";
1712 const size_t numVertices = (nx + 1) * (ny + 1) * (nz + 1);
1715 std::shared_ptr<VecDataArray<double, 3>> coords = std::make_shared<VecDataArray<double, 3>>();
1717 vertices.
resize(static_cast<int>(numVertices));
1720 for (
int k = 0; k < nz + 1; ++k)
1722 double z = aabbMin[2] + k * h[2];
1723 for (
int j = 0; j < ny + 1; ++j)
1725 double y = aabbMin[1] + j * h[1];
1726 for (
int i = 0; i < nx + 1; ++i)
1728 double x = aabbMin[0] + i * h[0];
1729 vertices[cnt] = { x, y, z };
1735 const int numDiv = 6;
1736 const int numTets = numDiv * nx * ny * nz;
1738 std::shared_ptr<VecDataArray<int, 4>> indicesPtr = std::make_shared<VecDataArray<int, 4>>();
1740 indices.
resize(static_cast<int>(numTets));
1742 std::vector<int> indx(8);
1744 for (
int k = 0; k < nz; ++k)
1746 for (
int j = 0; j < ny; ++j)
1748 for (
int i = 0; i < nx; ++i)
1750 indx[3] = i + j * (nx + 1) + k * (nx + 1) * (ny + 1);
1751 indx[2] = indx[3] + 1;
1752 indx[0] = indx[3] + nx + 1;
1753 indx[1] = indx[0] + 1;
1754 indx[4] = indx[0] + (nx + 1) * (ny + 1);
1755 indx[5] = indx[1] + (nx + 1) * (ny + 1);
1756 indx[6] = indx[2] + (nx + 1) * (ny + 1);
1757 indx[7] = indx[3] + (nx + 1) * (ny + 1);
1759 indices[cnt + 0] = Vec4i(indx[0], indx[2], indx[3], indx[6]);
1760 indices[cnt + 1] = Vec4i(indx[0], indx[3], indx[7], indx[6]);
1761 indices[cnt + 2] = Vec4i(indx[0], indx[7], indx[4], indx[6]);
1762 indices[cnt + 3] = Vec4i(indx[0], indx[5], indx[6], indx[4]);
1763 indices[cnt + 4] = Vec4i(indx[1], indx[5], indx[6], indx[0]);
1764 indices[cnt + 5] = Vec4i(indx[1], indx[6], indx[2], indx[0]);
1770 auto mesh = std::make_shared<TetrahedralMesh>();
1771 mesh->initialize(coords, indicesPtr);
1775 std::shared_ptr<TetrahedralMesh>
1781 Vec3d aabbMin, aabbMax;
1784 surfMesh->computeBoundingBox(aabbMin, aabbMax, 1. );
1789 std::vector<bool> insideSurfMesh;
1790 markPointsInsideAndOut(insideSurfMesh, *surfMesh.get(), coords, nx + 1, ny + 1, nz + 1);
1793 std::vector<bool> validTet(uniformMesh->getNumCells(),
false);
1794 std::vector<bool> validVtx(uniformMesh->getNumVertices(),
false);
1797 const Vec3d h = { (aabbMax[0] - aabbMin[0]) / nx,
1798 (aabbMax[1] - aabbMin[1]) / ny,
1799 (aabbMax[2] - aabbMin[2]) / nz };
1803 auto labelEnclosingTet = [&aabbMin, &h, nx, ny, nz, &uniformMesh, &validTet](
const Vec3d& xyz)
1805 const int idX = (xyz[0] - aabbMin[0]) / h[0];
1806 const int idY = (xyz[1] - aabbMin[1]) / h[1];
1807 const int idZ = (xyz[2] - aabbMin[2]) / h[2];
1808 const int hexId = idX + idY * nx + idZ * nx * ny;
1811 const int numDiv = 6;
1812 const int tetId0 = numDiv * hexId;
1813 const int tetId1 = tetId0 + numDiv;
1815 static Vec4d weights = Vec4d::Zero();
1818 for (
int id = tetId0;
id < tetId1; ++id)
1824 weights = uniformMesh->computeBarycentricWeights(
id, xyz);
1826 if ((weights[0] >= 0) && (weights[1] >= 0) && (weights[2] >= 0) && (weights[3] >= 0))
1828 validTet[id] =
true;
1834 auto labelEnclosingTetOfVertices = [&surfMesh, &uniformMesh, &aabbMin, &h, nx, ny, nz, &labelEnclosingTet, &validTet](
const int i)
1836 const auto& xyz = surfMesh->getVertexPosition(i);
1837 labelEnclosingTet(xyz);
1840 for (
size_t i = 0; i < validTet.size(); ++i)
1842 const Vec4i& verts = (*uniformMesh->getCells())[i];
1843 if (insideSurfMesh[verts[0]]
1844 || insideSurfMesh[verts[1]]
1845 || insideSurfMesh[verts[2]]
1846 || insideSurfMesh[verts[3]])
1854 auto labelEnclosingTetOfInteriorPnt = [&](
const int fid)
1856 auto verts = indices[fid];
1857 const auto& vtx0 = surfMesh->getVertexPosition(verts[0]);
1858 const auto& vtx1 = surfMesh->getVertexPosition(verts[1]);
1859 const auto& vtx2 = surfMesh->getVertexPosition(verts[2]);
1860 std::vector<Vec3d> pnts(12);
1862 pnts[0] = 0.75 * vtx0 + 0.25 * vtx1;
1863 pnts[1] = 0.50 * vtx0 + 0.50 * vtx1;
1864 pnts[2] = 0.25 * vtx0 + 0.75 * vtx1;
1865 pnts[3] = 0.75 * vtx1 + 0.25 * vtx2;
1866 pnts[4] = 0.50 * vtx1 + 0.50 * vtx2;
1867 pnts[5] = 0.25 * vtx1 + 0.75 * vtx2;
1868 pnts[6] = 0.75 * vtx2 + 0.25 * vtx0;
1869 pnts[7] = 0.50 * vtx2 + 0.50 * vtx0;
1870 pnts[8] = 0.25 * vtx2 + 0.75 * vtx0;
1871 pnts[9] = 2.0 / 3.0 * pnts[0] + 1.0 / 3.0 * pnts[5];
1872 pnts[10] = 0.5 * (pnts[1] + pnts[4]);
1873 pnts[11] = 0.5 * (pnts[4] + pnts[7]);
1875 for (
size_t i = 0; i < pnts.size(); ++i)
1877 labelEnclosingTet(pnts[i]);
1882 for (
int i = 0; i < surfMesh->getNumVertices(); ++i)
1884 labelEnclosingTetOfVertices(i);
1888 for (
int i = 0; i < surfMesh->getNumCells(); ++i)
1890 labelEnclosingTetOfInteriorPnt(i);
1894 for (
size_t i = 0; i < validTet.size(); ++i)
1896 const Vec4i& verts = (*uniformMesh->getCells())[i];
1899 validVtx[verts[0]] =
true;
1900 validVtx[verts[1]] =
true;
1901 validVtx[verts[2]] =
true;
1902 validVtx[verts[3]] =
true;
1908 size_t numVerts = 0;
1909 for (
auto b : validVtx)
1917 std::shared_ptr<VecDataArray<double, 3>> newCoords = std::make_shared<VecDataArray<double, 3>>(
static_cast<int>(numVerts));
1919 std::vector<int> oldToNew(coords.size(), std::numeric_limits<int>::max());
1922 for (
size_t i = 0; i < validVtx.size(); ++i)
1926 vertices[cnt] = coords[i];
1933 std::shared_ptr<VecDataArray<int, 4>> newIndicesPtr = std::make_shared<VecDataArray<int, 4>>(numElems);
1936 for (
int i = 0; i < uniformMesh->getNumCells(); ++i)
1940 const Vec4i& oldIndices = (*uniformMesh->getCells())[i];
1942 newIndices[cnt][0] = oldToNew[oldIndices[0]];
1943 newIndices[cnt][1] = oldToNew[oldIndices[1]];
1944 newIndices[cnt][2] = oldToNew[oldIndices[2]];
1945 newIndices[cnt][3] = oldToNew[oldIndices[3]];
1952 auto mesh = std::make_shared<TetrahedralMesh>();
1953 mesh->initialize(newCoords, newIndicesPtr);
1958 template<
typename NeighborContainer>
1964 case (MeshNodeRenumberingStrategy::ReverseCuthillMckee):
1965 return RCM(neighbors);
1967 LOG(WARNING) <<
"Unrecognized reorder method; using RCM instead";
1968 return RCM(neighbors);
1972 template<
typename ElemConn>
1978 case (MeshNodeRenumberingStrategy::ReverseCuthillMckee):
1979 return RCM(conn, numVerts);
1981 LOG(WARNING) <<
"Unrecognized reorder method; using Reverse Cuthill-Mckee strategy instead";
1982 return RCM(conn, numVerts);
1989 template std::vector<size_t> imstk::GeometryUtils::reorderConnectivity<std::array<size_t, 4>>(
const std::vector<std::array<size_t, 4>>&,
const size_t,
const MeshNodeRenumberingStrategy&);
vtkSmartPointer< vtkUnstructuredGrid > copyToVtkUnstructuredGrid(std::shared_ptr< TetrahedralMesh > imstkMesh)
Converts imstk tetrahedral mesh into a vtk unstructured grid.
std::shared_ptr< SurfaceMesh > toTriangleGrid(const Vec3d ¢er, const Vec2d &size, const Vec2i &dim, const Quatd orientation=Quatd::Identity(), const double uvScale=1.0)
Produces a triangle grid on a plane given the imstkPlane.
vtkSmartPointer< vtkDataArray > coupleVtkDataArray(std::shared_ptr< AbstractDataArray > imstkArray)
Coupling functions, these create vtk data objects that point to our data objects thus no copying is d...
std::shared_ptr< LineMesh > copyToLineMesh(vtkSmartPointer< vtkPolyData > vtkMesh)
Converts vtk polydata into a imstk surface mesh.
vtkSmartPointer< vtkPolyData > copyToVtkPolyData(std::shared_ptr< LineMesh > imstkMesh)
Converts imstk line mesh into a vtk polydata.
int getOpenEdgeCount(std::shared_ptr< SurfaceMesh > surfMesh)
Returns the number of open edges, use to tell if manifold (==0)
vtkSmartPointer< vtkPoints > copyToVtkPoints(std::shared_ptr< VecDataArray< double, 3 >> vertices)
Copies vertices from imstk structure to VTK one.
std::shared_ptr< TetrahedralMesh > toTetGrid(const Vec3d ¢er, const Vec3d &size, const Vec3i &divisions, const Quatd orientation=Quatd::Identity())
Produces a tetrahedral grid given the OrientedBox with the given divisions.
void resize(const int size) override
Resize data array to hold exactly size number of values.
void push_back(const ValueType &val)
Append the data array to hold the new value, resizes if neccesary.
std::shared_ptr< AbstractCellMesh > copyToCellMesh(vtkSmartPointer< vtkUnstructuredGrid > vtkMesh)
Get imstk cell mesh given vtkUnstructuredGrid as input iMSTK only supports homogenous cells...
virtual void computeBoundingBox(Vec3d &lowerCorner, Vec3d &upperCorner, const double paddingPercent=0.0) override
Compute the bounding box for the entire mesh.
int getNumCells() const override
Returns the number of cells.
std::shared_ptr< LineMesh > toLineGrid(const Vec3d &start, const Vec3d &dir, const double length, const int dim)
Creates a set of connected lines.
const Vec3d & getVertexPosition(const size_t vertNum, DataType type=DataType::PostTransform) const
Returns the position of a vertex given its index.
vtkSmartPointer< vtkPointSet > copyToVtkPointSet(std::shared_ptr< PointSet > imstkMesh)
Converts imstk point set into a vtk polydata.
std::shared_ptr< VecDataArray< double, 3 > > getVertexPositions(DataType type=DataType::PostTransform) const
Returns the vector of current positions of the mesh vertices.
void copyToDataMap(vtkDataSetAttributes *pointData, std::unordered_map< std::string, std::shared_ptr< AbstractDataArray >> &dataMap)
Copy vtkPointData to a data map.
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
std::shared_ptr< TetrahedralMesh > createUniformMesh(const Vec3d &aabbMin, const Vec3d &aabbMax, const int nx, const int ny, const int nz)
Create a tetrahedral mesh based on a uniform Cartesian mesh.
VecDataArray< U, N > cast()
Templated copy the current array with a new internal data type, does not change the number of compone...
std::shared_ptr< SurfaceMesh > toUVSphereSurfaceMesh(std::shared_ptr< Sphere > sphere, const unsigned int phiDivisions, const unsigned int thetaDivisions)
UV sphere from imstkSphere.
std::shared_ptr< SurfaceMesh > copyToSurfaceMesh(vtkSmartPointer< vtkPolyData > vtkMesh)
Converts vtk polydata into a imstk surface mesh.
std::shared_ptr< TetrahedralMesh > createTetrahedralMeshCover(std::shared_ptr< SurfaceMesh > surfMesh, const int nx, const int ny, int nz)
Create a tetrahedral mesh cover.
double getVolume(std::shared_ptr< SurfaceMesh > surfMesh)
Returns volume estimate of closed SurfaceMesh.
vtkSmartPointer< vtkCellArray > copyToVtkCellArray(std::shared_ptr< VecDataArray< int, dim >> cells)
Copies cells of the given dimension from imstk structure to VTK one.
void copyToVtkDataAttributes(vtkDataSetAttributes *pointData, const std::unordered_map< std::string, std::shared_ptr< AbstractDataArray >> &dataMap)
Copy from a data map to vtkDataAttributes (used for vtkCellData and vtkPointData) warning: Components...
std::shared_ptr< PointSet > copyToPointSet(vtkSmartPointer< vtkPointSet > vtkMesh)
Converts vtk polydata into a imstk point set.
vtkSmartPointer< vtkDataArray > copyToVtkDataArray(std::shared_ptr< AbstractDataArray > imstkArray)
Copy functions, these copy to/from vtk data objects.
std::shared_ptr< SurfaceMesh > toSurfaceMesh(std::shared_ptr< AnalyticalGeometry > geom)
Produces SurfaceMesh from an analytical geometry.
MeshNodeRenumberingStrategy
Enumeration for reordering method.
std::shared_ptr< VecDataArray< double, 3 > > copyToVecDataArray(vtkSmartPointer< vtkPoints > points)
Copy from vtk points to a imstk vertices array.
std::vector< size_t > reorderConnectivity(const std::vector< NeighborContainer > &neighbors, const MeshNodeRenumberingStrategy &method=MeshNodeRenumberingStrategy::ReverseCuthillMckee)
Reorder indices in a connectivity to reduce bandwidth.