5#include <vtkAppendFilter.h>
6#include <vtkAppendPolyData.h>
7#include <vtkCellData.h>
8#include <vtkDataSetTriangleFilter.h>
9#include <vtkFloatArray.h>
10#include <vtkGeometryFilter.h>
11#include <vtkIncrementalOctreePointLocator.h>
12#include <vtkIntArray.h>
13#include <vtkPointData.h>
14#include <vtkProbeFilter.h>
15#include <vtkRectilinearGrid.h>
16#include <vtkSmartPointer.h>
17#include <vtkTableBasedClipDataSet.h>
18#include <vtkTriangleFilter.h>
19#include <vtkUnstructuredGrid.h>
20#include <vtkXMLPolyDataWriter.h>
21#include <vtkXMLUnstructuredGridWriter.h>
23#include <hrleDenseIterator.hpp>
30#ifdef LS_TO_VISUALIZATION_DEBUG
31#include <vtkXMLRectilinearGridWriter.h>
36using namespace viennacore;
44template <
class T,
int D>
class WriteVisualizationMesh {
45 typedef typename Domain<T, D>::DomainType hrleDomainType;
46 using LevelSetsType = std::vector<SmartPointer<Domain<T, D>>>;
47 LevelSetsType levelSets;
48 SmartPointer<MaterialMap> materialMap =
nullptr;
50 bool extractVolumeMesh =
true;
51 bool extractHullMesh =
false;
52 bool bottomRemoved =
false;
53 static constexpr double LSEpsilon = 1e-2;
58 void removeDuplicatePoints(vtkSmartPointer<vtkPolyData> &polyData,
59 const double tolerance) {
61 vtkSmartPointer<vtkPolyData> newPolyData =
62 vtkSmartPointer<vtkPolyData>::New();
63 vtkSmartPointer<vtkIncrementalOctreePointLocator> ptInserter =
64 vtkSmartPointer<vtkIncrementalOctreePointLocator>::New();
65 ptInserter->SetTolerance(tolerance);
67 vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
71 polyData->GetBounds(gridBounds);
74 std::vector<vtkIdType> newPointIds;
75 newPointIds.reserve(polyData->GetNumberOfPoints());
76 ptInserter->InitPointInsertion(newPoints, gridBounds);
79 for (vtkIdType pointId = 0; pointId < polyData->GetNumberOfPoints();
81 vtkIdType globalPtId = 0;
82 ptInserter->InsertUniquePoint(polyData->GetPoint(pointId), globalPtId);
83 newPointIds.push_back(globalPtId);
87 newPolyData->SetPoints(newPoints);
90 vtkSmartPointer<vtkCellArray> oldCells = polyData->GetPolys();
91 vtkSmartPointer<vtkCellArray> newCells =
92 vtkSmartPointer<vtkCellArray>::New();
94 vtkSmartPointer<vtkIdList> cellPoints = vtkIdList::New();
95 oldCells->InitTraversal();
96 while (oldCells->GetNextCell(cellPoints)) {
97 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
99 cellPoints->SetId(pointId, newPointIds[cellPoints->GetId(pointId)]);
102 newCells->InsertNextCell(cellPoints);
105 newPolyData->SetPolys(newCells);
111 newPolyData->GetCellData()->ShallowCopy(polyData->GetCellData());
114 polyData = newPolyData;
119 void removeDuplicatePoints(vtkSmartPointer<vtkUnstructuredGrid> &ugrid,
120 const double tolerance) {
122 vtkSmartPointer<vtkUnstructuredGrid> newGrid =
123 vtkSmartPointer<vtkUnstructuredGrid>::New();
124 vtkSmartPointer<vtkIncrementalOctreePointLocator> ptInserter =
125 vtkSmartPointer<vtkIncrementalOctreePointLocator>::New();
126 ptInserter->SetTolerance(tolerance);
128 vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
131 double gridBounds[6];
132 ugrid->GetBounds(gridBounds);
135 std::vector<vtkIdType> newPointIds;
136 newPointIds.reserve(ugrid->GetNumberOfPoints());
137 ptInserter->InitPointInsertion(newPoints, gridBounds);
140 for (vtkIdType pointId = 0; pointId < ugrid->GetNumberOfPoints();
142 vtkIdType globalPtId = 0;
143 ptInserter->InsertUniquePoint(ugrid->GetPoint(pointId), globalPtId);
144 newPointIds.push_back(globalPtId);
148 newGrid->SetPoints(newPoints);
151 for (vtkIdType cellId = 0; cellId < ugrid->GetNumberOfCells(); ++cellId) {
152 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
153 ugrid->GetCellPoints(cellId, cellPoints);
154 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
156 cellPoints->SetId(pointId, newPointIds[cellPoints->GetId(pointId)]);
159 newGrid->InsertNextCell(ugrid->GetCell(cellId)->GetCellType(),
167 newGrid->GetCellData()->ShallowCopy(ugrid->GetCellData());
174 void removeDegenerateTetras(vtkSmartPointer<vtkUnstructuredGrid> &ugrid) {
175 vtkSmartPointer<vtkUnstructuredGrid> newGrid =
176 vtkSmartPointer<vtkUnstructuredGrid>::New();
179 vtkSmartPointer<vtkIntArray> materialNumberArray =
180 vtkSmartPointer<vtkIntArray>::New();
181 materialNumberArray->SetNumberOfComponents(1);
182 materialNumberArray->SetName(
"Material");
186 vtkDataArray *matArray =
187 ugrid->GetCellData()->GetArray(
"Material", arrayIndex);
188 const int &materialArrayIndex = arrayIndex;
191 for (vtkIdType cellId = 0; cellId < ugrid->GetNumberOfCells(); ++cellId) {
192 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
193 ugrid->GetCellPoints(cellId, cellPoints);
194 bool isDuplicate =
false;
195 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
197 for (vtkIdType nextId = pointId + 1;
198 nextId < cellPoints->GetNumberOfIds(); ++nextId) {
200 if (cellPoints->GetId(pointId) == cellPoints->GetId(nextId))
206 newGrid->InsertNextCell(ugrid->GetCell(cellId)->GetCellType(),
209 if (materialArrayIndex >= 0)
210 materialNumberArray->InsertNextValue(matArray->GetTuple1(cellId));
215 newGrid->SetPoints(ugrid->GetPoints());
216 newGrid->GetPointData()->ShallowCopy(ugrid->GetPointData());
218 newGrid->GetCellData()->SetScalars(materialNumberArray);
227 template <
bool removeBottom = false,
int gr
idExtraPo
ints = 0>
228 vtkSmartPointer<vtkRectilinearGrid>
229 LS2RectiLinearGrid(SmartPointer<Domain<T, D>> levelSet,
230 const double LSOffset = 0.,
231 int infiniteMinimum = std::numeric_limits<int>::max(),
232 int infiniteMaximum = -std::numeric_limits<int>::max()) {
234 auto &grid = levelSet->getGrid();
235 auto &domain = levelSet->getDomain();
237 int numLayers = levelSet->getLevelSetWidth();
239 vtkSmartPointer<vtkFloatArray>
241 int gridMin = 0, gridMax = 0;
242 int openJumpDirection = -1;
245 for (
unsigned i = 0; i <
D; ++i) {
246 coords[i] = vtkSmartPointer<vtkFloatArray>::New();
248 if (grid.getBoundaryConditions(i) ==
249 Domain<T, D>::BoundaryType::INFINITE_BOUNDARY) {
251 gridMin = std::min(domain.getMinRunBreak(i), infiniteMinimum) -
254 gridMax = std::max(domain.getMaxRunBreak(i), infiniteMaximum) + 1;
256 openJumpDirection = i + 1;
259 gridMin = grid.getMinGridPoint(i) - gridExtraPoints;
260 gridMax = grid.getMaxGridPoint(i) + gridExtraPoints;
263 for (
int x = gridMin; x <= gridMax; ++x) {
264 coords[i]->InsertNextValue(x * gridDelta);
270 coords[2] = vtkSmartPointer<vtkFloatArray>::New();
271 coords[2]->InsertNextValue(0);
274 vtkSmartPointer<vtkRectilinearGrid> rgrid =
275 vtkSmartPointer<vtkRectilinearGrid>::New();
277 rgrid->SetDimensions(coords[0]->GetNumberOfTuples(),
278 coords[1]->GetNumberOfTuples(),
279 coords[2]->GetNumberOfTuples());
280 rgrid->SetXCoordinates(coords[0]);
281 rgrid->SetYCoordinates(coords[1]);
282 rgrid->SetZCoordinates(coords[2]);
286 vtkIdType pointId = 0;
287 bool fixBorderPoints = (gridExtraPoints != 0);
291 hrleConstDenseIterator<typename Domain<T, D>::DomainType> it(
292 levelSet->getDomain());
298 int currentOpenIndex =
299 it.getIndices()[(openJumpDirection <
D) ? openJumpDirection : 0];
302 vtkSmartPointer<vtkFloatArray> signedDistances =
303 vtkSmartPointer<vtkFloatArray>::New();
304 signedDistances->SetNumberOfComponents(1);
305 signedDistances->SetName(
"SignedDistances");
308 while ((pointId < rgrid->GetNumberOfPoints())) {
310 rgrid->GetPoint(pointId, p);
312 hrleVectorType<hrleIndexType, D> indices(
313 grid.globalCoordinates2GlobalIndices(p));
319 if (grid.isOutsideOfDomain(indices)) {
320 fixBorderPoints =
true;
321 signedDistances->InsertNextValue(
322 signedDistances->GetDataTypeValueMax());
325 if (it.getValue() == Domain<T, D>::POS_VALUE || it.isFinished()) {
327 }
else if (it.getValue() == Domain<T, D>::NEG_VALUE) {
330 value = it.getValue() + LSOffset;
336 if (currentOpenIndex != indices[openJumpDirection]) {
337 currentOpenIndex = indices[openJumpDirection];
338 if (indices >= it.getIndices()) {
344 signedDistances->InsertNextValue(value * gridDelta);
348 if (it.isFinished()) {
352 while (it.getIndices() <= indices) {
377 if (fixBorderPoints) {
379 while ((pointId < rgrid->GetNumberOfPoints())) {
380 if (signedDistances->GetValue(pointId) ==
381 signedDistances->GetDataTypeValueMax()) {
383 rgrid->GetPoint(pointId, p);
386 hrleVectorType<hrleIndexType, D> indices(
387 grid.globalCoordinates2GlobalIndices(p));
390 hrleVectorType<hrleIndexType, D> localIndices =
391 grid.globalIndices2LocalIndices(indices);
394 int originalPointId = 0;
395 for (
int i =
D - 1; i >= 0; --i) {
397 coords[i]->GetNumberOfTuples();
398 originalPointId += localIndices[i] - indices[i];
400 originalPointId += pointId;
403 signedDistances->SetValue(pointId,
404 signedDistances->GetValue(originalPointId));
411 rgrid->GetPointData()->SetScalars(signedDistances);
417 WriteVisualizationMesh() {}
419 WriteVisualizationMesh(SmartPointer<Domain<T, D>> levelSet) {
420 levelSets.push_back(levelSet);
424 void insertNextLevelSet(SmartPointer<Domain<T, D>> levelSet) {
425 levelSets.push_back(levelSet);
430 void setFileName(std::string passedFileName) { fileName = passedFileName; }
433 void setExtractHullMesh(
bool passedExtractHullMesh) {
434 extractHullMesh = passedExtractHullMesh;
438 void setExtractVolumeMesh(
bool passedExtractVolumeMesh) {
439 extractVolumeMesh = passedExtractVolumeMesh;
442 void setMaterialMap(SmartPointer<MaterialMap> passedMaterialMap) {
443 materialMap = passedMaterialMap;
448 for (
unsigned i = 0; i < levelSets.size(); ++i) {
449 if (levelSets[i]->getLevelSetWidth() < 2) {
450 Logger::getInstance()
452 "WriteVisualizationMesh: Level Set " + std::to_string(i) +
453 " should have a width greater than 1! Conversion might fail!")
458 const double gridDelta = levelSets[0]->getGrid().getGridDelta();
461 std::vector<vtkSmartPointer<vtkUnstructuredGrid>> materialMeshes;
462 std::vector<unsigned> materialIds;
464 int totalMinimum = std::numeric_limits<int>::max();
465 int totalMaximum = -std::numeric_limits<int>::max();
466 for (
auto &it : levelSets) {
467 if (it->getNumberOfPoints() == 0) {
470 auto &grid = it->getGrid();
471 auto &domain = it->getDomain();
472 for (
unsigned i = 0; i <
D; ++i) {
473 if (grid.getBoundaryConditions(i) ==
474 Domain<T, D>::BoundaryType::INFINITE_BOUNDARY) {
475 totalMinimum = std::min(totalMinimum, domain.getMinRunBreak(i));
476 totalMaximum = std::max(totalMaximum, domain.getMaxRunBreak(i));
483 vtkSmartPointer<vtkTableBasedClipDataSet> clipper =
484 vtkSmartPointer<vtkTableBasedClipDataSet>::New();
485 auto topGrid = vtkSmartPointer<vtkRectilinearGrid>::New();
487 topGrid = LS2RectiLinearGrid<true>(levelSets.back(), 0, totalMinimum,
490 topGrid = LS2RectiLinearGrid<false>(levelSets.back(), 0, totalMinimum,
493#ifdef LS_TO_VISUALIZATION_DEBUG
495 auto gwriter = vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
496 gwriter->SetFileName(
"./grid_0.vtr");
497 gwriter->SetInputData(topGrid);
499 std::cout <<
"Wrote grid 0" << std::endl;
502 clipper->SetInputData(topGrid);
503 clipper->InsideOutOn();
504 clipper->SetValue(0.0);
505 clipper->GenerateClippedOutputOn();
508#ifdef LS_TO_VISUALIZATION_DEBUG
510 auto gwriter = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
511 gwriter->SetFileName(
"./clipped.vtu");
512 gwriter->SetInputData(clipper->GetClippedOutput());
514 std::cout <<
"Wrote clipped" << std::endl;
518 const bool useMaterialMap = materialMap !=
nullptr;
519 materialMeshes.push_back(clipper->GetOutput());
520 materialIds.push_back(useMaterialMap ? materialMap->getMaterialId(0) : 0);
522#ifdef LS_TO_VISUALIZATION_DEBUG
524 auto gwriter = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
525 gwriter->SetFileName(
"./probed_0.vtu");
526 gwriter->SetInputData(materialMeshes.front());
534 for (
typename LevelSetsType::const_reverse_iterator it =
535 ++levelSets.rbegin();
536 it != levelSets.rend(); ++it) {
537 if (it->get()->getNumberOfPoints() == 0)
541 vtkSmartPointer<vtkRectilinearGrid> rgrid =
542 vtkSmartPointer<vtkRectilinearGrid>::New();
544 rgrid = LS2RectiLinearGrid<true, 1>(*it, -LSEpsilon * counter,
545 totalMinimum, totalMaximum);
547 rgrid = LS2RectiLinearGrid<false, 1>(*it, -LSEpsilon * counter,
548 totalMinimum, totalMaximum);
551#ifdef LS_TO_VISUALIZATION_DEBUG
553 vtkSmartPointer<vtkXMLRectilinearGridWriter> gwriter =
554 vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
555 gwriter->SetFileName(
556 (
"./grid_" + std::to_string(counter) +
".vtr").c_str());
557 gwriter->SetInputData(rgrid);
559 std::cout <<
"Wrote grid " <<
counter << std::endl;
564 vtkSmartPointer<vtkProbeFilter> probeFilter =
565 vtkSmartPointer<vtkProbeFilter>::New();
566 probeFilter->SetInputData(materialMeshes.back());
567 probeFilter->SetSourceData(rgrid);
568 probeFilter->Update();
570#ifdef LS_TO_VISUALIZATION_DEBUG
572 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
573 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
574 gwriter->SetFileName(
575 (
"./probed_" + std::to_string(counter) +
".vtu").c_str());
576 gwriter->SetInputData(probeFilter->GetOutput());
578 std::cout <<
"Wrote unstructured grid " <<
counter << std::endl;
585 vtkSmartPointer<vtkTableBasedClipDataSet> insideClipper =
586 vtkSmartPointer<vtkTableBasedClipDataSet>::New();
587 insideClipper->SetInputConnection(probeFilter->GetOutputPort());
588 insideClipper->GenerateClippedOutputOn();
589 insideClipper->Update();
591 materialMeshes.rbegin()[0] = insideClipper->GetOutput();
592 materialMeshes.push_back(insideClipper->GetClippedOutput());
595 material = materialMap->getMaterialId(counter);
596 materialIds.push_back(material);
601 vtkSmartPointer<vtkAppendFilter> appendFilter =
602 vtkSmartPointer<vtkAppendFilter>::New();
604 vtkSmartPointer<vtkAppendPolyData> hullAppendFilter =
605 vtkSmartPointer<vtkAppendPolyData>::New();
607 for (
unsigned i = 0; i < materialMeshes.size(); ++i) {
610 vtkSmartPointer<vtkIntArray> materialNumberArray =
611 vtkSmartPointer<vtkIntArray>::New();
612 materialNumberArray->SetNumberOfComponents(1);
613 materialNumberArray->SetName(
"Material");
616 materialMeshes[materialMeshes.size() - 1 - i]->GetNumberOfCells();
618 materialNumberArray->InsertNextValue(materialIds[i]);
620 materialMeshes[materialMeshes.size() - 1 - i]->GetCellData()->SetScalars(
621 materialNumberArray);
627 vtkSmartPointer<vtkPointData> pointData =
628 materialMeshes[materialMeshes.size() - 1 - i]->GetPointData();
629 const int numberOfArrays = pointData->GetNumberOfArrays();
630 for (
int j = 0; j < numberOfArrays; ++j) {
631 pointData->RemoveArray(0);
636 if (extractHullMesh) {
637 vtkSmartPointer<vtkGeometryFilter> geoFilter =
638 vtkSmartPointer<vtkGeometryFilter>::New();
639 geoFilter->SetInputData(materialMeshes[materialMeshes.size() - 1 - i]);
641 hullAppendFilter->AddInputData(geoFilter->GetOutput());
644 appendFilter->AddInputData(materialMeshes[materialMeshes.size() - 1 - i]);
648 auto volumeVTK = vtkSmartPointer<vtkUnstructuredGrid>::New();
649 auto hullVTK = vtkSmartPointer<vtkPolyData>::New();
650 if (extractVolumeMesh) {
651 appendFilter->Update();
655 volumeVTK = appendFilter->GetOutput();
656#ifdef LS_TO_VISUALIZATION_DEBUG
658 std::cout <<
"Before duplicate removal: " << std::endl;
659 std::cout <<
"Points: " << volumeVTK->GetNumberOfPoints() << std::endl;
660 std::cout <<
"Cells: " << volumeVTK->GetNumberOfCells() << std::endl;
661 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
662 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
663 gwriter->SetFileName(
"before_removal.vtu");
664 gwriter->SetInputData(appendFilter->GetOutput());
671 removeDuplicatePoints(volumeVTK, 1e-3 * gridDelta);
673#ifdef LS_TO_VISUALIZATION_DEBUG
675 std::cout <<
"After duplicate removal: " << std::endl;
676 std::cout <<
"Points: " << volumeVTK->GetNumberOfPoints() << std::endl;
677 std::cout <<
"Cells: " << volumeVTK->GetNumberOfCells() << std::endl;
678 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
679 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
680 gwriter->SetFileName(
"after_removal.vtu");
681 gwriter->SetInputData(volumeVTK);
687 vtkSmartPointer<vtkDataSetTriangleFilter> triangleFilter =
688 vtkSmartPointer<vtkDataSetTriangleFilter>::New();
689 triangleFilter->SetInputData(volumeVTK);
690 triangleFilter->Update();
691 volumeVTK = triangleFilter->GetOutput();
694 removeDegenerateTetras(volumeVTK);
696 auto writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
697 writer->SetFileName((fileName +
"_volume.vtu").c_str());
698 writer->SetInputData(volumeVTK);
703 if (extractHullMesh) {
704 hullAppendFilter->Update();
705 hullVTK = hullAppendFilter->GetOutput();
707 removeDuplicatePoints(hullVTK, 1e-3 * gridDelta);
709 vtkSmartPointer<vtkTriangleFilter> hullTriangleFilter =
710 vtkSmartPointer<vtkTriangleFilter>::New();
711 hullTriangleFilter->SetInputData(hullVTK);
712 hullTriangleFilter->Update();
714 hullVTK = hullTriangleFilter->GetOutput();
716 auto writer = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
717 writer->SetFileName((fileName +
"_hull.vtp").c_str());
718 writer->SetInputData(hullVTK);
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
float gridDelta
Definition AirGapDeposition.py:21
int counter
Definition Deposition.py:71
Definition lsAdvect.hpp:46
constexpr int D
Definition pyWrap.cpp:65
double T
Definition pyWrap.cpp:63