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>
29#include <unordered_map>
33#ifdef LS_TO_VISUALIZATION_DEBUG
34#include <vtkXMLRectilinearGridWriter.h>
39using namespace viennacore;
47template <
class T,
int D>
class WriteVisualizationMesh {
48 typedef typename Domain<T, D>::DomainType hrleDomainType;
49 using LevelSetsType = std::vector<SmartPointer<Domain<T, D>>>;
50 LevelSetsType levelSets;
51 SmartPointer<MaterialMap> materialMap =
nullptr;
53 bool extractVolumeMesh =
true;
54 bool extractHullMesh =
false;
55 bool bottomRemoved =
false;
56 bool writeToFile =
true;
57 double LSEpsilon = 1e-2;
58 std::unordered_map<std::string, std::vector<double>> metaData;
60 vtkSmartPointer<vtkUnstructuredGrid> volumeVTK;
61 vtkSmartPointer<vtkPolyData> hullVTK;
66 static void removeDuplicatePoints(vtkSmartPointer<vtkPolyData> &polyData,
67 const double tolerance) {
69 vtkSmartPointer<vtkPolyData> newPolyData =
70 vtkSmartPointer<vtkPolyData>::New();
71 vtkSmartPointer<vtkIncrementalOctreePointLocator> ptInserter =
72 vtkSmartPointer<vtkIncrementalOctreePointLocator>::New();
73 ptInserter->SetTolerance(tolerance);
75 vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
79 polyData->GetBounds(gridBounds);
82 std::vector<vtkIdType> newPointIds;
83 newPointIds.reserve(polyData->GetNumberOfPoints());
84 ptInserter->InitPointInsertion(newPoints, gridBounds);
87 for (vtkIdType pointId = 0; pointId < polyData->GetNumberOfPoints();
89 vtkIdType globalPtId = 0;
90 ptInserter->InsertUniquePoint(polyData->GetPoint(pointId), globalPtId);
91 newPointIds.push_back(globalPtId);
95 newPolyData->SetPoints(newPoints);
98 vtkSmartPointer<vtkCellArray> oldCells = polyData->GetPolys();
99 vtkSmartPointer<vtkCellArray> newCells =
100 vtkSmartPointer<vtkCellArray>::New();
102 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
103 oldCells->InitTraversal();
104 while (oldCells->GetNextCell(cellPoints)) {
105 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
107 cellPoints->SetId(pointId, newPointIds[cellPoints->GetId(pointId)]);
110 newCells->InsertNextCell(cellPoints);
113 newPolyData->SetPolys(newCells);
119 newPolyData->GetCellData()->ShallowCopy(polyData->GetCellData());
122 polyData = newPolyData;
127 static void removeDuplicatePoints(vtkSmartPointer<vtkUnstructuredGrid> &ugrid,
128 const double tolerance) {
130 vtkSmartPointer<vtkUnstructuredGrid> newGrid =
131 vtkSmartPointer<vtkUnstructuredGrid>::New();
132 vtkSmartPointer<vtkIncrementalOctreePointLocator> ptInserter =
133 vtkSmartPointer<vtkIncrementalOctreePointLocator>::New();
134 ptInserter->SetTolerance(tolerance);
136 vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
139 double gridBounds[6];
140 ugrid->GetBounds(gridBounds);
143 std::vector<vtkIdType> newPointIds;
144 newPointIds.reserve(ugrid->GetNumberOfPoints());
145 ptInserter->InitPointInsertion(newPoints, gridBounds);
148 for (vtkIdType pointId = 0; pointId < ugrid->GetNumberOfPoints();
150 vtkIdType globalPtId = 0;
151 ptInserter->InsertUniquePoint(ugrid->GetPoint(pointId), globalPtId);
152 newPointIds.push_back(globalPtId);
156 newGrid->SetPoints(newPoints);
159 for (vtkIdType cellId = 0; cellId < ugrid->GetNumberOfCells(); ++cellId) {
160 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
161 ugrid->GetCellPoints(cellId, cellPoints);
162 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
164 cellPoints->SetId(pointId, newPointIds[cellPoints->GetId(pointId)]);
167 newGrid->InsertNextCell(ugrid->GetCell(cellId)->GetCellType(),
175 newGrid->GetCellData()->ShallowCopy(ugrid->GetCellData());
183 removeDegenerateTetras(vtkSmartPointer<vtkUnstructuredGrid> &ugrid) {
184 vtkSmartPointer<vtkUnstructuredGrid> newGrid =
185 vtkSmartPointer<vtkUnstructuredGrid>::New();
188 vtkSmartPointer<vtkIntArray> materialNumberArray =
189 vtkSmartPointer<vtkIntArray>::New();
190 materialNumberArray->SetNumberOfComponents(1);
191 materialNumberArray->SetName(
"Material");
195 vtkDataArray *matArray =
196 ugrid->GetCellData()->GetArray(
"Material", arrayIndex);
197 const int &materialArrayIndex = arrayIndex;
200 for (vtkIdType cellId = 0; cellId < ugrid->GetNumberOfCells(); ++cellId) {
201 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
202 ugrid->GetCellPoints(cellId, cellPoints);
203 bool isDuplicate =
false;
204 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
206 for (vtkIdType nextId = pointId + 1;
207 nextId < cellPoints->GetNumberOfIds(); ++nextId) {
209 if (cellPoints->GetId(pointId) == cellPoints->GetId(nextId))
215 newGrid->InsertNextCell(ugrid->GetCell(cellId)->GetCellType(),
218 if (materialArrayIndex >= 0)
219 materialNumberArray->InsertNextValue(matArray->GetTuple1(cellId));
224 newGrid->SetPoints(ugrid->GetPoints());
225 newGrid->GetPointData()->ShallowCopy(ugrid->GetPointData());
227 newGrid->GetCellData()->SetScalars(materialNumberArray);
236 template <
int gr
idExtraPo
ints = 0>
237 vtkSmartPointer<vtkRectilinearGrid>
238 LS2RectiLinearGrid(SmartPointer<Domain<T, D>> levelSet,
const double LSOffset,
239 int infiniteMinimum = std::numeric_limits<int>::max(),
240 int infiniteMaximum = -std::numeric_limits<int>::max()) {
242 auto &grid = levelSet->getGrid();
243 auto &domain = levelSet->getDomain();
245 int numLayers = levelSet->getLevelSetWidth();
247 vtkSmartPointer<vtkFloatArray>
249 int gridMin = 0, gridMax = 0;
254 for (
unsigned i = 0; i <
D; ++i) {
255 coords[i] = vtkSmartPointer<vtkFloatArray>::New();
257 if (grid.getBoundaryConditions(i) ==
258 Domain<T, D>::BoundaryType::INFINITE_BOUNDARY) {
260 gridMin = std::min(domain.getMinRunBreak(i), infiniteMinimum) -
263 gridMax = std::max(domain.getMaxRunBreak(i), infiniteMaximum) + 1;
267 gridMin = grid.getMinGridPoint(i) - gridExtraPoints;
268 gridMax = grid.getMaxGridPoint(i) + gridExtraPoints;
271 for (
int x = gridMin; x <= gridMax; ++x) {
272 coords[i]->InsertNextValue(x *
gridDelta);
278 coords[2] = vtkSmartPointer<vtkFloatArray>::New();
279 coords[2]->InsertNextValue(0);
282 vtkSmartPointer<vtkRectilinearGrid> rgrid =
283 vtkSmartPointer<vtkRectilinearGrid>::New();
285 rgrid->SetDimensions(coords[0]->GetNumberOfTuples(),
286 coords[1]->GetNumberOfTuples(),
287 coords[2]->GetNumberOfTuples());
288 rgrid->SetXCoordinates(coords[0]);
289 rgrid->SetYCoordinates(coords[1]);
290 rgrid->SetZCoordinates(coords[2]);
302 auto const numGridPoints = rgrid->GetNumberOfPoints();
303 vtkSmartPointer<vtkFloatArray> signedDistances =
304 vtkSmartPointer<vtkFloatArray>::New();
305 signedDistances->SetNumberOfComponents(1);
306 signedDistances->SetNumberOfTuples(numGridPoints);
307 signedDistances->SetName(
"SignedDistances");
312 viennahrle::ConstDenseIterator<typename Domain<T, D>::DomainType> it(
313 levelSet->getDomain());
316 for (vtkIdType pointId = 0; pointId < numGridPoints; ++pointId) {
320 rgrid->GetPoint(pointId, p);
322 viennahrle::Index<D> indices(grid.globalCoordinates2GlobalIndices(p));
328 if (grid.isOutsideOfDomain(indices)) {
329 indices = grid.globalIndices2LocalIndices(indices);
335 it.goToIndices(indices);
336 if (it.getValue() == Domain<T, D>::POS_VALUE) {
338 }
else if (it.getValue() == Domain<T, D>::NEG_VALUE) {
341 value = it.getValue() + LSOffset;
355 signedDistances->SetValue(pointId, value *
gridDelta);
412 rgrid->GetPointData()->SetScalars(signedDistances);
417 void addMetaDataToVTK(vtkDataSet *data)
const {
418 if (metaData.empty()) {
423 vtkSmartPointer<vtkFieldData> fieldData = data->GetFieldData();
424 for (
const auto &meta : metaData) {
425 if (meta.second.empty())
428 vtkSmartPointer<vtkFloatArray> metaDataArray =
429 vtkSmartPointer<vtkFloatArray>::New();
430 metaDataArray->SetName(meta.first.c_str());
431 metaDataArray->SetNumberOfValues(meta.second.size());
432 for (
size_t i = 0; i < meta.second.size(); ++i) {
433 metaDataArray->SetValue(i, meta.second[i]);
435 fieldData->AddArray(metaDataArray);
440 WriteVisualizationMesh() =
default;
442 WriteVisualizationMesh(SmartPointer<Domain<T, D>> levelSet) {
443 levelSets.push_back(levelSet);
447 void insertNextLevelSet(SmartPointer<Domain<T, D>> levelSet) {
448 levelSets.push_back(levelSet);
451 void clearLevelSets() { levelSets.clear(); }
455 void setFileName(std::string passedFileName) {
456 fileName = std::move(passedFileName);
460 void setExtractHullMesh(
bool passedExtractHullMesh) {
461 extractHullMesh = passedExtractHullMesh;
465 void setExtractVolumeMesh(
bool passedExtractVolumeMesh) {
466 extractVolumeMesh = passedExtractVolumeMesh;
469 void setWriteToFile(
bool passedWriteToFile) {
470 writeToFile = passedWriteToFile;
473 void setMaterialMap(SmartPointer<MaterialMap> passedMaterialMap) {
474 materialMap = passedMaterialMap;
477 void setWrappingLayerEpsilon(
double epsilon) { LSEpsilon = epsilon; }
479 void setMetaData(
const std::unordered_map<std::string, std::vector<double>>
481 metaData = passedMetaData;
484 void addMetaData(
const std::string &key,
double value) {
485 metaData[key] = std::vector<double>{value};
488 void addMetaData(
const std::string &key,
const std::vector<double> &values) {
489 metaData[key] = values;
493 const std::unordered_map<std::string, std::vector<double>> &newMetaData) {
494 for (
const auto &pair : newMetaData) {
495 metaData[pair.first] = pair.second;
499 auto getVolumeMesh()
const {
return volumeVTK; }
501 auto getHullMesh()
const {
return hullVTK; }
505 for (
unsigned i = 0; i < levelSets.size(); ++i) {
506 if (levelSets[i]->getLevelSetWidth() < 2) {
507 VIENNACORE_LOG_WARNING(
508 "WriteVisualizationMesh: Level Set " + std::to_string(i) +
509 " should have a width greater than 1! Conversion might fail!");
528 if (levelSets.size() > 1) {
529 LevelSetsType nested;
530 nested.reserve(levelSets.size());
531 for (
auto &ls : levelSets) {
532 auto merged = SmartPointer<Domain<T, D>>::New(ls);
534 BooleanOperation<T, D>(merged, nested.back(),
535 BooleanOperationEnum::UNION)
537 nested.push_back(merged);
539 levelSets = std::move(nested);
542 const double gridDelta = levelSets[0]->getGrid().getGridDelta();
545 std::vector<vtkSmartPointer<vtkUnstructuredGrid>> materialMeshes;
546 std::vector<unsigned> materialIds;
548 int totalMinimum = std::numeric_limits<int>::max();
549 int totalMaximum = -std::numeric_limits<int>::max();
550 for (
auto &it : levelSets) {
551 if (it->getNumberOfPoints() == 0) {
554 auto &grid = it->getGrid();
555 auto &domain = it->getDomain();
556 for (
unsigned i = 0; i <
D; ++i) {
557 if (grid.getBoundaryConditions(i) ==
558 Domain<T, D>::BoundaryType::INFINITE_BOUNDARY) {
559 totalMinimum = std::min(totalMinimum, domain.getMinRunBreak(i));
560 totalMaximum = std::max(totalMaximum, domain.getMaxRunBreak(i));
567 vtkSmartPointer<vtkTableBasedClipDataSet> clipper =
568 vtkSmartPointer<vtkTableBasedClipDataSet>::New();
569 auto topGrid = vtkSmartPointer<vtkRectilinearGrid>::New();
572 LS2RectiLinearGrid(levelSets.back(), 0, totalMinimum, totalMaximum);
578#ifdef LS_TO_VISUALIZATION_DEBUG
580 auto gwriter = vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
581 gwriter->SetFileName(
"./grid_0.vtr");
582 gwriter->SetInputData(topGrid);
584 std::cout <<
"Wrote grid 0" << std::endl;
587 clipper->SetInputData(topGrid);
588 clipper->InsideOutOn();
589 clipper->SetValue(0.0);
590 clipper->GenerateClippedOutputOn();
593#ifdef LS_TO_VISUALIZATION_DEBUG
595 auto gwriter = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
596 gwriter->SetFileName(
"./clipped.vtu");
597 gwriter->SetInputData(clipper->GetClippedOutput());
599 std::cout <<
"Wrote clipped" << std::endl;
603 const bool useMaterialMap = materialMap !=
nullptr;
604 materialMeshes.emplace_back(clipper->GetOutput());
605 materialIds.push_back(useMaterialMap ? materialMap->getMaterialId(0) : 0);
607#ifdef LS_TO_VISUALIZATION_DEBUG
609 auto gwriter = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
610 gwriter->SetFileName(
"./probed_0.vtu");
611 gwriter->SetInputData(materialMeshes.front());
619 for (
typename LevelSetsType::const_reverse_iterator it =
620 ++levelSets.rbegin();
621 it != levelSets.rend(); ++it) {
622 if (it->get()->getNumberOfPoints() == 0)
627 vtkSmartPointer<vtkRectilinearGrid> rgrid =
628 vtkSmartPointer<vtkRectilinearGrid>::New();
630 rgrid = LS2RectiLinearGrid<1>(*it, -LSEpsilon * counter, totalMinimum,
637#ifdef LS_TO_VISUALIZATION_DEBUG
639 vtkSmartPointer<vtkXMLRectilinearGridWriter> gwriter =
640 vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
641 gwriter->SetFileName(
642 (
"./grid_" + std::to_string(counter) +
".vtr").c_str());
643 gwriter->SetInputData(rgrid);
645 std::cout <<
"Wrote grid " <<
counter << std::endl;
650 vtkSmartPointer<vtkProbeFilter> probeFilter =
651 vtkSmartPointer<vtkProbeFilter>::New();
652 probeFilter->SetInputData(materialMeshes.back());
653 probeFilter->SetSourceData(rgrid);
654 probeFilter->Update();
656#ifdef LS_TO_VISUALIZATION_DEBUG
658 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
659 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
660 gwriter->SetFileName(
661 (
"./probed_" + std::to_string(counter) +
".vtu").c_str());
662 gwriter->SetInputData(probeFilter->GetOutput());
664 std::cout <<
"Wrote unstructured grid " <<
counter << std::endl;
671 vtkSmartPointer<vtkTableBasedClipDataSet> insideClipper =
672 vtkSmartPointer<vtkTableBasedClipDataSet>::New();
673 insideClipper->SetInputConnection(probeFilter->GetOutputPort());
674 insideClipper->GenerateClippedOutputOn();
675 insideClipper->Update();
677 materialMeshes.back() = insideClipper->GetOutput();
678 materialMeshes.emplace_back(insideClipper->GetClippedOutput());
681 material = materialMap->getMaterialId(counter);
682 materialIds.push_back(material);
687 vtkSmartPointer<vtkAppendFilter> appendFilter =
688 vtkSmartPointer<vtkAppendFilter>::New();
690 vtkSmartPointer<vtkAppendPolyData> hullAppendFilter =
691 vtkSmartPointer<vtkAppendPolyData>::New();
693 for (
unsigned i = 0; i < materialMeshes.size(); ++i) {
696 vtkSmartPointer<vtkIntArray> materialNumberArray =
697 vtkSmartPointer<vtkIntArray>::New();
698 materialNumberArray->SetNumberOfComponents(1);
699 materialNumberArray->SetName(
"Material");
702 materialMeshes[materialMeshes.size() - 1 - i]->GetNumberOfCells();
704 materialNumberArray->InsertNextValue(materialIds[i]);
706 materialMeshes[materialMeshes.size() - 1 - i]->GetCellData()->SetScalars(
707 materialNumberArray);
713 vtkSmartPointer<vtkPointData> pointData =
714 materialMeshes[materialMeshes.size() - 1 - i]->GetPointData();
715 const int numberOfArrays = pointData->GetNumberOfArrays();
716 for (
int j = 0; j < numberOfArrays; ++j) {
717 pointData->RemoveArray(0);
722 if (extractHullMesh) {
723 vtkSmartPointer<vtkGeometryFilter> geoFilter =
724 vtkSmartPointer<vtkGeometryFilter>::New();
725 geoFilter->SetInputData(materialMeshes[materialMeshes.size() - 1 - i]);
727 hullAppendFilter->AddInputData(geoFilter->GetOutput());
730 appendFilter->AddInputData(materialMeshes[materialMeshes.size() - 1 - i]);
734 volumeVTK = vtkSmartPointer<vtkUnstructuredGrid>::New();
735 hullVTK = vtkSmartPointer<vtkPolyData>::New();
736 if (extractVolumeMesh) {
737 appendFilter->Update();
741 volumeVTK = appendFilter->GetOutput();
742#ifdef LS_TO_VISUALIZATION_DEBUG
744 std::cout <<
"Before duplicate removal: " << std::endl;
745 std::cout <<
"Points: " << volumeVTK->GetNumberOfPoints() << std::endl;
746 std::cout <<
"Cells: " << volumeVTK->GetNumberOfCells() << std::endl;
747 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
748 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
749 gwriter->SetFileName(
"before_removal.vtu");
750 gwriter->SetInputData(appendFilter->GetOutput());
757 removeDuplicatePoints(volumeVTK, 1e-3 *
gridDelta);
759#ifdef LS_TO_VISUALIZATION_DEBUG
761 std::cout <<
"After duplicate removal: " << std::endl;
762 std::cout <<
"Points: " << volumeVTK->GetNumberOfPoints() << std::endl;
763 std::cout <<
"Cells: " << volumeVTK->GetNumberOfCells() << std::endl;
764 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
765 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
766 gwriter->SetFileName(
"after_removal.vtu");
767 gwriter->SetInputData(volumeVTK);
773 vtkSmartPointer<vtkDataSetTriangleFilter> triangleFilter =
774 vtkSmartPointer<vtkDataSetTriangleFilter>::New();
775 triangleFilter->SetInputData(volumeVTK);
776 triangleFilter->Update();
777 volumeVTK = triangleFilter->GetOutput();
780 removeDegenerateTetras(volumeVTK);
783 addMetaDataToVTK(volumeVTK);
786 auto writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
787 writer->SetFileName((fileName +
"_volume.vtu").c_str());
795 writer->SetDataModeToBinary();
796 writer->SetInputData(volumeVTK);
802 if (extractHullMesh) {
803 hullAppendFilter->Update();
804 hullVTK = hullAppendFilter->GetOutput();
806 removeDuplicatePoints(hullVTK, 1e-3 *
gridDelta);
808 vtkSmartPointer<vtkTriangleFilter> hullTriangleFilter =
809 vtkSmartPointer<vtkTriangleFilter>::New();
810 hullTriangleFilter->SetInputData(hullVTK);
811 hullTriangleFilter->Update();
813 hullVTK = hullTriangleFilter->GetOutput();
816 addMetaDataToVTK(hullVTK);
819 auto writer = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
820 writer->SetFileName((fileName +
"_hull.vtp").c_str());
823 writer->SetDataModeToBinary();
824 writer->SetInputData(hullVTK);
827 hullTriangleFilter->Update();
constexpr int D
Definition Epitaxy.cpp:12
double T
Definition Epitaxy.cpp:13
constexpr T gridDelta
Definition OxidationNitride.cpp:35
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
writer
Definition AirGapDeposition.py:173
int counter
Definition Deposition.py:75
Definition lsAdvect.hpp:41