ViennaLS
Loading...
Searching...
No Matches
lsWriteVisualizationMesh.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifdef VIENNALS_USE_VTK // this class needs vtk support
4
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>
22
23#include <hrleDenseIterator.hpp>
24
25#include <lsDomain.hpp>
26#include <lsMaterialMap.hpp>
28#include <unordered_map>
29#include <utility>
30
31// #define LS_TO_VISUALIZATION_DEBUG
32#ifdef LS_TO_VISUALIZATION_DEBUG
33#include <vtkXMLRectilinearGridWriter.h>
34#endif
35
36namespace viennals {
37
38using namespace viennacore;
39
46template <class T, int D> class WriteVisualizationMesh {
47 typedef typename Domain<T, D>::DomainType hrleDomainType;
48 using LevelSetsType = std::vector<SmartPointer<Domain<T, D>>>;
49 LevelSetsType levelSets;
50 SmartPointer<MaterialMap> materialMap = nullptr;
51 std::string fileName;
52 bool extractVolumeMesh = true;
53 bool extractHullMesh = false;
54 bool bottomRemoved = false;
55 double LSEpsilon = 1e-2;
56 std::unordered_map<std::string, std::vector<double>> metaData;
57
61 static void removeDuplicatePoints(vtkSmartPointer<vtkPolyData> &polyData,
62 const double tolerance) {
63
64 vtkSmartPointer<vtkPolyData> newPolyData =
65 vtkSmartPointer<vtkPolyData>::New();
66 vtkSmartPointer<vtkIncrementalOctreePointLocator> ptInserter =
67 vtkSmartPointer<vtkIncrementalOctreePointLocator>::New();
68 ptInserter->SetTolerance(tolerance);
69
70 vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
71
72 // get bounds
73 double gridBounds[6];
74 polyData->GetBounds(gridBounds);
75
76 // start point insertion from original points
77 std::vector<vtkIdType> newPointIds;
78 newPointIds.reserve(polyData->GetNumberOfPoints());
79 ptInserter->InitPointInsertion(newPoints, gridBounds);
80
81 // make new point list
82 for (vtkIdType pointId = 0; pointId < polyData->GetNumberOfPoints();
83 ++pointId) {
84 vtkIdType globalPtId = 0;
85 ptInserter->InsertUniquePoint(polyData->GetPoint(pointId), globalPtId);
86 newPointIds.push_back(globalPtId);
87 }
88
89 // now set the new points to the unstructured grid
90 newPolyData->SetPoints(newPoints);
91
92 // go through all cells and change point ids to match the new ids
93 vtkSmartPointer<vtkCellArray> oldCells = polyData->GetPolys();
94 vtkSmartPointer<vtkCellArray> newCells =
95 vtkSmartPointer<vtkCellArray>::New();
96
97 vtkSmartPointer<vtkIdList> cellPoints = vtkIdList::New();
98 oldCells->InitTraversal();
99 while (oldCells->GetNextCell(cellPoints)) {
100 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
101 ++pointId) {
102 cellPoints->SetId(pointId, newPointIds[cellPoints->GetId(pointId)]);
103 }
104 // insert same cell with new points
105 newCells->InsertNextCell(cellPoints);
106 }
107
108 newPolyData->SetPolys(newCells);
109
110 // conserve all cell data
111 // TODO transfer point data as well (do with "InsertTuples (vtkIdList
112 // *dstIds, vtkIdList *srcIds, vtkAbstractArray *source) override)" of
113 // vtkDataArray class)
114 newPolyData->GetCellData()->ShallowCopy(polyData->GetCellData());
115
116 // set ugrid to the newly created grid
117 polyData = newPolyData;
118 }
119
122 static void removeDuplicatePoints(vtkSmartPointer<vtkUnstructuredGrid> &ugrid,
123 const double tolerance) {
124
125 vtkSmartPointer<vtkUnstructuredGrid> newGrid =
126 vtkSmartPointer<vtkUnstructuredGrid>::New();
127 vtkSmartPointer<vtkIncrementalOctreePointLocator> ptInserter =
128 vtkSmartPointer<vtkIncrementalOctreePointLocator>::New();
129 ptInserter->SetTolerance(tolerance);
130
131 vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
132
133 // get bounds
134 double gridBounds[6];
135 ugrid->GetBounds(gridBounds);
136
137 // start point insertion from original points
138 std::vector<vtkIdType> newPointIds;
139 newPointIds.reserve(ugrid->GetNumberOfPoints());
140 ptInserter->InitPointInsertion(newPoints, gridBounds);
141
142 // make new point list
143 for (vtkIdType pointId = 0; pointId < ugrid->GetNumberOfPoints();
144 ++pointId) {
145 vtkIdType globalPtId = 0;
146 ptInserter->InsertUniquePoint(ugrid->GetPoint(pointId), globalPtId);
147 newPointIds.push_back(globalPtId);
148 }
149
150 // now set the new points to the unstructured grid
151 newGrid->SetPoints(newPoints);
152
153 // go through all cells and change point ids to match the new ids
154 for (vtkIdType cellId = 0; cellId < ugrid->GetNumberOfCells(); ++cellId) {
155 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
156 ugrid->GetCellPoints(cellId, cellPoints);
157 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
158 ++pointId) {
159 cellPoints->SetId(pointId, newPointIds[cellPoints->GetId(pointId)]);
160 }
161 // insert same cell with new points
162 newGrid->InsertNextCell(ugrid->GetCell(cellId)->GetCellType(),
163 cellPoints);
164 }
165
166 // conserve all cell data
167 // TODO transfer point data as well (do with "InsertTuples (vtkIdList
168 // *dstIds, vtkIdList *srcIds, vtkAbstractArray *source) override)" of
169 // vtkDataArray class)
170 newGrid->GetCellData()->ShallowCopy(ugrid->GetCellData());
171
172 // set ugrid to the newly created grid
173 ugrid = newGrid;
174 }
175
177 static void
178 removeDegenerateTetras(vtkSmartPointer<vtkUnstructuredGrid> &ugrid) {
179 vtkSmartPointer<vtkUnstructuredGrid> newGrid =
180 vtkSmartPointer<vtkUnstructuredGrid>::New();
181
182 // need to copy material numbers
183 vtkSmartPointer<vtkIntArray> materialNumberArray =
184 vtkSmartPointer<vtkIntArray>::New();
185 materialNumberArray->SetNumberOfComponents(1);
186 materialNumberArray->SetName("Material");
187
188 // see if material is defined
189 int arrayIndex;
190 vtkDataArray *matArray =
191 ugrid->GetCellData()->GetArray("Material", arrayIndex);
192 const int &materialArrayIndex = arrayIndex;
193
194 // go through all cells and delete those with duplicate entries
195 for (vtkIdType cellId = 0; cellId < ugrid->GetNumberOfCells(); ++cellId) {
196 vtkSmartPointer<vtkIdList> cellPoints = vtkSmartPointer<vtkIdList>::New();
197 ugrid->GetCellPoints(cellId, cellPoints);
198 bool isDuplicate = false;
199 for (vtkIdType pointId = 0; pointId < cellPoints->GetNumberOfIds();
200 ++pointId) {
201 for (vtkIdType nextId = pointId + 1;
202 nextId < cellPoints->GetNumberOfIds(); ++nextId) {
203 // if they are the same, remove the cell
204 if (cellPoints->GetId(pointId) == cellPoints->GetId(nextId))
205 isDuplicate = true;
206 }
207 }
208 if (!isDuplicate) {
209 // insert same cell if no degenerate points
210 newGrid->InsertNextCell(ugrid->GetCell(cellId)->GetCellType(),
211 cellPoints);
212 // if material was defined before, use it now
213 if (materialArrayIndex >= 0)
214 materialNumberArray->InsertNextValue(matArray->GetTuple1(cellId));
215 }
216 }
217
218 // just take the old points and point data
219 newGrid->SetPoints(ugrid->GetPoints());
220 newGrid->GetPointData()->ShallowCopy(ugrid->GetPointData());
221 // set material cell data
222 newGrid->GetCellData()->SetScalars(materialNumberArray);
223
224 ugrid = newGrid;
225 }
226
227 // This function takes a levelset and converts it to a vtkRectilinearGrid
228 // The full domain contains values, which are capped at numLayers * gridDelta
229 // gridExtraPoints layers of grid points are added to the domain according to
230 // boundary conditions
231 template <int gridExtraPoints = 0>
232 vtkSmartPointer<vtkRectilinearGrid>
233 LS2RectiLinearGrid(SmartPointer<Domain<T, D>> levelSet, const double LSOffset,
234 int infiniteMinimum = std::numeric_limits<int>::max(),
235 int infiniteMaximum = -std::numeric_limits<int>::max()) {
236
237 auto &grid = levelSet->getGrid();
238 auto &domain = levelSet->getDomain();
239 double gridDelta = grid.getGridDelta();
240 int numLayers = levelSet->getLevelSetWidth();
241
242 vtkSmartPointer<vtkFloatArray>
243 coords[3]; // needs to be 3 because vtk only knows 3D
244 int gridMin = 0, gridMax = 0;
245 // int openJumpDirection = -1; // direction above the open boundary
246 // direction
247
248 // fill grid with offset depending on orientation
249 for (unsigned i = 0; i < D; ++i) {
250 coords[i] = vtkSmartPointer<vtkFloatArray>::New();
251
252 if (grid.getBoundaryConditions(i) ==
253 Domain<T, D>::BoundaryType::INFINITE_BOUNDARY) {
254 // add one to gridMin and gridMax for numerical stability
255 gridMin = std::min(domain.getMinRunBreak(i), infiniteMinimum) -
256 1; // choose the smaller number so that for first levelset the
257 // overall minimum can be chosen
258 gridMax = std::max(domain.getMaxRunBreak(i), infiniteMaximum) + 1;
259
260 // openJumpDirection = i + 1;
261 } else {
262 gridMin = grid.getMinGridPoint(i) - gridExtraPoints;
263 gridMax = grid.getMaxGridPoint(i) + gridExtraPoints;
264 }
265
266 for (int x = gridMin; x <= gridMax; ++x) {
267 coords[i]->InsertNextValue(x * gridDelta);
268 }
269 }
270
271 // if we work in 2D, just add 1 grid point at origin
272 if (D == 2) {
273 coords[2] = vtkSmartPointer<vtkFloatArray>::New();
274 coords[2]->InsertNextValue(0);
275 }
276
277 vtkSmartPointer<vtkRectilinearGrid> rgrid =
278 vtkSmartPointer<vtkRectilinearGrid>::New();
279
280 rgrid->SetDimensions(coords[0]->GetNumberOfTuples(),
281 coords[1]->GetNumberOfTuples(),
282 coords[2]->GetNumberOfTuples());
283 rgrid->SetXCoordinates(coords[0]);
284 rgrid->SetYCoordinates(coords[1]);
285 rgrid->SetZCoordinates(coords[2]);
286
287 // bool fixBorderPoints = (gridExtraPoints != 0);
288
289 // need to save the current position one dimension above open boundary
290 // direction, so we can register a jump in the open boundary direction when
291 // it occurs, so we can fix the LS value as follows: if remove_bottom==true,
292 // we need to flip the sign otherwise the sign stays the same
293 // int currentOpenIndex =
294 // it.getIndices()[(openJumpDirection < D) ? openJumpDirection : 0];
295
296 // Make array to store signed distance function
297 auto const numGridPoints = rgrid->GetNumberOfPoints();
298 vtkSmartPointer<vtkFloatArray> signedDistances =
299 vtkSmartPointer<vtkFloatArray>::New();
300 signedDistances->SetNumberOfComponents(1);
301 signedDistances->SetNumberOfTuples(numGridPoints);
302 signedDistances->SetName("SignedDistances");
303
304#pragma omp parallel
305 {
306 // use dense iterator to got to every index location
307 viennahrle::ConstDenseIterator<typename Domain<T, D>::DomainType> it(
308 levelSet->getDomain());
309
310#pragma omp for
311 for (vtkIdType pointId = 0; pointId < numGridPoints; ++pointId) {
312 // iterate until all grid points have a signed distance value
313
314 double p[3];
315 rgrid->GetPoint(pointId, p);
316 // create index vector
317 viennahrle::Index<D> indices(grid.globalCoordinates2GlobalIndices(p));
318
319 // write the corresponding LSValue
320 T value;
321
322 // if indices are outside of domain map to local indices
323 if (grid.isOutsideOfDomain(indices)) {
324 indices = grid.globalIndices2LocalIndices(indices);
325 // fixBorderPoints = true;
326 // signedDistances->InsertNextValue(
327 // signedDistances->GetDataTypeValueMax());
328 }
329
330 it.goToIndices(indices);
331 if (it.getValue() == Domain<T, D>::POS_VALUE) {
332 value = numLayers;
333 } else if (it.getValue() == Domain<T, D>::NEG_VALUE) {
334 value = -numLayers;
335 } else {
336 value = it.getValue() + LSOffset;
337 }
338
339 // if (removeBottom) {
340 // // if we jump from one end of the domain to the other and are not
341 // // already in the new run, we need to fix the sign of the run
342 // if (currentOpenIndex != indices[openJumpDirection]) {
343 // currentOpenIndex = indices[openJumpDirection];
344 // if (indices >= it.getIndices()) {
345 // value = -value;
346 // }
347 // }
348 // }
349
350 signedDistances->SetValue(pointId, value * gridDelta);
351 // signedDistances->InsertNextValue(value * gridDelta);
352 }
353
354 // // advance iterator until it is at correct point
355 // while (compare(it_l.end_indices(), indices) < 0) {
356 // it_l.next();
357 // if (it_l.is_finished())
358 // break;
359 // }
360 // // now move iterator with pointId to get to next point
361 // switch (compare(it_l.end_indices(), indices)) {
362 // case 0:
363 // it_l.next();
364 // default:
365 // ++pointId;
366 // }
367 // }
368 }
369
370 // now need to go through again to fix border points, this is done by
371 // mapping existing points onto the points outside the domain according
372 // to the correct boundary conditions
373 // if (fixBorderPoints) {
374 // vtkIdType pointId = 0;
375 // while ((pointId < rgrid->GetNumberOfPoints())) {
376 // if (signedDistances->GetValue(pointId) ==
377 // signedDistances->GetDataTypeValueMax()) {
378 // double p[3];
379 // rgrid->GetPoint(pointId, p);
380
381 // // create index vector
382 // viennahrle::Index<D> indices(
383 // grid.globalCoordinates2GlobalIndices(p));
384
385 // // vector for mapped point inside domain
386 // viennahrle::Index<D> localIndices =
387 // grid.globalIndices2LocalIndices(indices);
388
389 // // now find ID of point we need to take value from
390 // int originalPointId = 0;
391 // for (int i = D - 1; i >= 0; --i) {
392 // originalPointId *=
393 // coords[i]->GetNumberOfTuples(); // extent in direction
394 // originalPointId += localIndices[i] - indices[i];
395 // }
396 // originalPointId += pointId;
397
398 // // now put value of mapped point in global point
399 // signedDistances->SetValue(pointId,
400 // signedDistances->GetValue(originalPointId));
401 // }
402 // ++pointId;
403 // }
404 // }
405
406 // Add the SignedDistances to the grid
407 rgrid->GetPointData()->SetScalars(signedDistances);
408
409 return rgrid;
410 }
411
412 void addMetaDataToVTK(vtkDataSet *data) const {
413 if (metaData.empty()) {
414 return;
415 }
416
417 // add metadata to field data
418 vtkSmartPointer<vtkFieldData> fieldData = data->GetFieldData();
419 for (const auto &meta : metaData) {
420 if (meta.second.empty())
421 continue; // skip empty metadata
422
423 vtkSmartPointer<vtkFloatArray> metaDataArray =
424 vtkSmartPointer<vtkFloatArray>::New();
425 metaDataArray->SetName(meta.first.c_str());
426 metaDataArray->SetNumberOfValues(meta.second.size());
427 for (size_t i = 0; i < meta.second.size(); ++i) {
428 metaDataArray->SetValue(i, meta.second[i]);
429 }
430 fieldData->AddArray(metaDataArray);
431 }
432 }
433
434public:
435 WriteVisualizationMesh() = default;
436
437 WriteVisualizationMesh(SmartPointer<Domain<T, D>> levelSet) {
438 levelSets.push_back(levelSet);
439 }
440
442 void insertNextLevelSet(SmartPointer<Domain<T, D>> levelSet) {
443 levelSets.push_back(levelSet);
444 }
445
446 void clearLevelSets() { levelSets.clear(); }
447
450 void setFileName(std::string passedFileName) {
451 fileName = std::move(passedFileName);
452 }
453
455 void setExtractHullMesh(bool passedExtractHullMesh) {
456 extractHullMesh = passedExtractHullMesh;
457 }
458
460 void setExtractVolumeMesh(bool passedExtractVolumeMesh) {
461 extractVolumeMesh = passedExtractVolumeMesh;
462 }
463
464 void setMaterialMap(SmartPointer<MaterialMap> passedMaterialMap) {
465 materialMap = passedMaterialMap;
466 }
467
468 void setWrappingLayerEpsilon(double epsilon) { LSEpsilon = epsilon; }
469
470 void setMetaData(const std::unordered_map<std::string, std::vector<double>>
471 &passedMetaData) {
472 metaData = passedMetaData;
473 }
474
475 void addMetaData(const std::string &key, double value) {
476 metaData[key] = std::vector<double>{value};
477 }
478
479 void addMetaData(const std::string &key, const std::vector<double> &values) {
480 metaData[key] = values;
481 }
482
483 void addMetaData(
484 const std::unordered_map<std::string, std::vector<double>> &newMetaData) {
485 for (const auto &pair : newMetaData) {
486 metaData[pair.first] = pair.second;
487 }
488 }
489
490 void apply() {
491 // check if level sets have enough layers
492 for (unsigned i = 0; i < levelSets.size(); ++i) {
493 if (levelSets[i]->getLevelSetWidth() < 2) {
494 Logger::getInstance()
495 .addWarning(
496 "WriteVisualizationMesh: Level Set " + std::to_string(i) +
497 " should have a width greater than 1! Conversion might fail!")
498 .print();
499 }
500 }
501
502 const double gridDelta = levelSets[0]->getGrid().getGridDelta();
503
504 // store volume for each material
505 std::vector<vtkSmartPointer<vtkUnstructuredGrid>> materialMeshes;
506 std::vector<unsigned> materialIds;
507
508 int totalMinimum = std::numeric_limits<int>::max();
509 int totalMaximum = -std::numeric_limits<int>::max();
510 for (auto &it : levelSets) {
511 if (it->getNumberOfPoints() == 0) {
512 continue;
513 }
514 auto &grid = it->getGrid();
515 auto &domain = it->getDomain();
516 for (unsigned i = 0; i < D; ++i) {
517 if (grid.getBoundaryConditions(i) ==
518 Domain<T, D>::BoundaryType::INFINITE_BOUNDARY) {
519 totalMinimum = std::min(totalMinimum, domain.getMinRunBreak(i));
520 totalMaximum = std::max(totalMaximum, domain.getMaxRunBreak(i));
521 }
522 }
523 }
524
525 // create volume mesh for largest LS
526 // Use vtkClipDataSet to slice the grid
527 vtkSmartPointer<vtkTableBasedClipDataSet> clipper =
528 vtkSmartPointer<vtkTableBasedClipDataSet>::New();
529 auto topGrid = vtkSmartPointer<vtkRectilinearGrid>::New();
530 // if (bottomRemoved) {
531 topGrid =
532 LS2RectiLinearGrid(levelSets.back(), 0, totalMinimum, totalMaximum);
533 // } else {
534 // topGrid = LS2RectiLinearGrid<false>(levelSets.back(), 0,
535 // totalMinimum,
536 // totalMaximum);
537 // }
538#ifdef LS_TO_VISUALIZATION_DEBUG
539 {
540 auto gwriter = vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
541 gwriter->SetFileName("./grid_0.vtr");
542 gwriter->SetInputData(topGrid);
543 gwriter->Write();
544 std::cout << "Wrote grid 0" << std::endl;
545 }
546#endif
547 clipper->SetInputData(topGrid);
548 clipper->InsideOutOn();
549 clipper->SetValue(0.0);
550 clipper->GenerateClippedOutputOn(); // TODO remove
551 clipper->Update();
552
553#ifdef LS_TO_VISUALIZATION_DEBUG
554 {
555 auto gwriter = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
556 gwriter->SetFileName("./clipped.vtu");
557 gwriter->SetInputData(clipper->GetClippedOutput());
558 gwriter->Write();
559 std::cout << "Wrote clipped" << std::endl;
560 }
561#endif
562
563 const bool useMaterialMap = materialMap != nullptr;
564 materialMeshes.emplace_back(clipper->GetOutput());
565 materialIds.push_back(useMaterialMap ? materialMap->getMaterialId(0) : 0);
566
567#ifdef LS_TO_VISUALIZATION_DEBUG
568 {
569 auto gwriter = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
570 gwriter->SetFileName("./probed_0.vtu");
571 gwriter->SetInputData(materialMeshes.front());
572 gwriter->Write();
573 }
574#endif
575
576 unsigned counter = 1;
577
578 // now cut large volume mesh with all the smaller ones
579 for (typename LevelSetsType::const_reverse_iterator it =
580 ++levelSets.rbegin();
581 it != levelSets.rend(); ++it) {
582 if (it->get()->getNumberOfPoints() == 0)
583 continue; // ignore empty levelSets
584
585 // create grid of next LS with slight offset and project into current
586 // mesh
587 vtkSmartPointer<vtkRectilinearGrid> rgrid =
588 vtkSmartPointer<vtkRectilinearGrid>::New();
589 // if (bottomRemoved) {
590 rgrid = LS2RectiLinearGrid<1>(*it, -LSEpsilon * counter, totalMinimum,
591 totalMaximum);
592 // } else {
593 // rgrid = LS2RectiLinearGrid<false, 1>(*it, -LSEpsilon * counter,
594 // totalMinimum, totalMaximum);
595 // }
596
597#ifdef LS_TO_VISUALIZATION_DEBUG
598 {
599 vtkSmartPointer<vtkXMLRectilinearGridWriter> gwriter =
600 vtkSmartPointer<vtkXMLRectilinearGridWriter>::New();
601 gwriter->SetFileName(
602 ("./grid_" + std::to_string(counter) + ".vtr").c_str());
603 gwriter->SetInputData(rgrid);
604 gwriter->Write();
605 std::cout << "Wrote grid " << counter << std::endl;
606 }
607#endif
608
609 // now transfer implicit values to mesh points
610 vtkSmartPointer<vtkProbeFilter> probeFilter =
611 vtkSmartPointer<vtkProbeFilter>::New();
612 probeFilter->SetInputData(materialMeshes.back()); // last element
613 probeFilter->SetSourceData(rgrid);
614 probeFilter->Update();
615
616#ifdef LS_TO_VISUALIZATION_DEBUG
617 {
618 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
619 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
620 gwriter->SetFileName(
621 ("./probed_" + std::to_string(counter) + ".vtu").c_str());
622 gwriter->SetInputData(probeFilter->GetOutput());
623 gwriter->Write();
624 std::cout << "Wrote unstructured grid " << counter << std::endl;
625 }
626#endif
627
628 // now clip the mesh and save the clipped as the 1st layer and use the
629 // inverse for the next layer clipping Use vtkTabelBasedClipDataSet to
630 // slice the grid
631 vtkSmartPointer<vtkTableBasedClipDataSet> insideClipper =
632 vtkSmartPointer<vtkTableBasedClipDataSet>::New();
633 insideClipper->SetInputConnection(probeFilter->GetOutputPort());
634 insideClipper->GenerateClippedOutputOn();
635 insideClipper->Update();
636
637 materialMeshes.back() = insideClipper->GetOutput();
638 materialMeshes.emplace_back(insideClipper->GetClippedOutput());
639 auto material = counter;
640 if (useMaterialMap)
641 material = materialMap->getMaterialId(counter);
642 materialIds.push_back(material);
643
644 ++counter;
645 }
646
647 vtkSmartPointer<vtkAppendFilter> appendFilter =
648 vtkSmartPointer<vtkAppendFilter>::New();
649
650 vtkSmartPointer<vtkAppendPolyData> hullAppendFilter =
651 vtkSmartPointer<vtkAppendPolyData>::New();
652
653 for (unsigned i = 0; i < materialMeshes.size(); ++i) {
654
655 // write material number in mesh
656 vtkSmartPointer<vtkIntArray> materialNumberArray =
657 vtkSmartPointer<vtkIntArray>::New();
658 materialNumberArray->SetNumberOfComponents(1);
659 materialNumberArray->SetName("Material");
660 for (unsigned j = 0;
661 j <
662 materialMeshes[materialMeshes.size() - 1 - i]->GetNumberOfCells();
663 ++j) {
664 materialNumberArray->InsertNextValue(materialIds[i]);
665 }
666 materialMeshes[materialMeshes.size() - 1 - i]->GetCellData()->SetScalars(
667 materialNumberArray);
668
669 // delete all point data, so it is not in ouput
670 // TODO this includes signed distance information which could be
671 // conserved for debugging also includes wheter a cell was vaild for
672 // cutting by the grid
673 vtkSmartPointer<vtkPointData> pointData =
674 materialMeshes[materialMeshes.size() - 1 - i]->GetPointData();
675 const int numberOfArrays = pointData->GetNumberOfArrays();
676 for (int j = 0; j < numberOfArrays; ++j) {
677 pointData->RemoveArray(0); // remove first array until none are left
678 }
679
680 // if hull mesh should be exported, create hull for each layer and put
681 // them together
682 if (extractHullMesh) {
683 vtkSmartPointer<vtkGeometryFilter> geoFilter =
684 vtkSmartPointer<vtkGeometryFilter>::New();
685 geoFilter->SetInputData(materialMeshes[materialMeshes.size() - 1 - i]);
686 geoFilter->Update();
687 hullAppendFilter->AddInputData(geoFilter->GetOutput());
688 }
689
690 appendFilter->AddInputData(materialMeshes[materialMeshes.size() - 1 - i]);
691 }
692
693 // do not need tetrahedral volume mesh if we do not print volume
694 auto volumeVTK = vtkSmartPointer<vtkUnstructuredGrid>::New();
695 auto hullVTK = vtkSmartPointer<vtkPolyData>::New();
696 if (extractVolumeMesh) {
697 appendFilter->Update();
698
699 // remove degenerate points and remove cells which collapse to zero
700 // volume then
701 volumeVTK = appendFilter->GetOutput();
702#ifdef LS_TO_VISUALIZATION_DEBUG
703 {
704 std::cout << "Before duplicate removal: " << std::endl;
705 std::cout << "Points: " << volumeVTK->GetNumberOfPoints() << std::endl;
706 std::cout << "Cells: " << volumeVTK->GetNumberOfCells() << std::endl;
707 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
708 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
709 gwriter->SetFileName("before_removal.vtu");
710 gwriter->SetInputData(appendFilter->GetOutput());
711 gwriter->Update();
712 }
713#endif
714
715 // use 1/1000th of grid spacing for contraction of two similar points,
716 // so that tetrahedralisation works correctly
717 removeDuplicatePoints(volumeVTK, 1e-3 * gridDelta);
718
719#ifdef LS_TO_VISUALIZATION_DEBUG
720 {
721 std::cout << "After duplicate removal: " << std::endl;
722 std::cout << "Points: " << volumeVTK->GetNumberOfPoints() << std::endl;
723 std::cout << "Cells: " << volumeVTK->GetNumberOfCells() << std::endl;
724 vtkSmartPointer<vtkXMLUnstructuredGridWriter> gwriter =
725 vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
726 gwriter->SetFileName("after_removal.vtu");
727 gwriter->SetInputData(volumeVTK);
728 gwriter->Update();
729 }
730#endif
731
732 // change all 3D cells into tetras and all 2D cells to triangles
733 vtkSmartPointer<vtkDataSetTriangleFilter> triangleFilter =
734 vtkSmartPointer<vtkDataSetTriangleFilter>::New();
735 triangleFilter->SetInputData(volumeVTK);
736 triangleFilter->Update();
737 volumeVTK = triangleFilter->GetOutput();
738
739 // now that only tetras are left, remove the ones with degenerate points
740 removeDegenerateTetras(volumeVTK);
741
742 // add meta data to volume mesh
743 addMetaDataToVTK(volumeVTK);
744
745 auto writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
746 writer->SetFileName((fileName + "_volume.vtu").c_str());
747 writer->SetInputData(volumeVTK);
748 writer->Write();
749 }
750
751 // Now make hull mesh if necessary
752 if (extractHullMesh) {
753 hullAppendFilter->Update();
754 hullVTK = hullAppendFilter->GetOutput();
755 // use 1/1000th of grid spacing for contraction of two similar points
756 removeDuplicatePoints(hullVTK, 1e-3 * gridDelta);
757
758 vtkSmartPointer<vtkTriangleFilter> hullTriangleFilter =
759 vtkSmartPointer<vtkTriangleFilter>::New();
760 hullTriangleFilter->SetInputData(hullVTK);
761 hullTriangleFilter->Update();
762
763 hullVTK = hullTriangleFilter->GetOutput();
764
765 // add meta data to hull mesh
766 addMetaDataToVTK(hullVTK);
767
768 auto writer = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
769 writer->SetFileName((fileName + "_hull.vtp").c_str());
770 writer->SetInputData(hullVTK);
771 writer->Write();
772 }
773 }
774};
775
776// add all template specialisations for this class
777PRECOMPILE_PRECISION_DIMENSION(WriteVisualizationMesh)
778
779} // namespace viennals
780
781#endif // VIENNALS_USE_VTK
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
float gridDelta
Definition AirGapDeposition.py:21
writer
Definition AirGapDeposition.py:89
int counter
Definition Deposition.py:75
Definition lsAdvect.hpp:36