ViennaLS
Loading...
Searching...
No Matches
lsToSurfaceMesh.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <iostream>
6#include <map>
7
8#include <hrleSparseCellIterator.hpp>
9#include <lsDomain.hpp>
10#include <lsExpand.hpp>
11#include <lsMarchingCubes.hpp>
12#include <lsMesh.hpp>
13
14namespace viennals {
15
16using namespace viennacore;
17
21template <class T, int D> class ToSurfaceMesh {
22 typedef typename Domain<T, D>::DomainType hrleDomainType;
23
24 SmartPointer<Domain<T, D>> levelSet = nullptr;
25 SmartPointer<Mesh<T>> mesh = nullptr;
26 // std::vector<hrleIndexType> meshNodeToPointIdMapping;
27 const T epsilon;
28 bool updatePointData = true;
29
30public:
31 explicit ToSurfaceMesh(double eps = 1e-12) : epsilon(eps) {}
32
33 ToSurfaceMesh(const SmartPointer<Domain<T, D>> passedLevelSet,
34 SmartPointer<Mesh<T>> passedMesh, double eps = 1e-12)
35 : levelSet(passedLevelSet), mesh(passedMesh), epsilon(eps) {}
36
37 void setLevelSet(SmartPointer<Domain<T, D>> passedlsDomain) {
38 levelSet = passedlsDomain;
39 }
40
41 void setMesh(SmartPointer<Mesh<T>> passedMesh) { mesh = passedMesh; }
42
43 void setUpdatePointData(bool update) { updatePointData = update; }
44
45 void apply() {
46 if (levelSet == nullptr) {
47 Logger::getInstance()
48 .addError("No level set was passed to ToSurfaceMesh.")
49 .print();
50 return;
51 }
52 if (mesh == nullptr) {
53 Logger::getInstance()
54 .addError("No mesh was passed to ToSurfaceMesh.")
55 .print();
56 return;
57 }
58
59 if (levelSet->getNumberOfPoints() == 0) {
60 Logger::getInstance()
61 .addWarning(
62 "ToSurfaceMesh: Level set is empty. No mesh will be created.")
63 .print();
64 return;
65 }
66
67 mesh->clear();
68 const unsigned int corner0[12] = {0, 1, 2, 0, 4, 5, 6, 4, 0, 1, 3, 2};
69 const unsigned int corner1[12] = {1, 3, 3, 2, 5, 7, 7, 6, 4, 5, 7, 6};
70 const unsigned int direction[12] = {0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2};
71
72 // test if level set function consists of at least 2 layers of
73 // defined grid points
74 if (levelSet->getLevelSetWidth() < 2) {
75 Logger::getInstance()
76 .addWarning("Levelset is less than 2 layers wide. Expanding levelset "
77 "to 2 layers.")
78 .print();
79 Expand<T, D>(levelSet, 2).apply();
80 }
81
82 typedef std::map<viennahrle::Index<D>, unsigned> nodeContainerType;
83
84 nodeContainerType nodes[D];
85 typename nodeContainerType::iterator nodeIt;
86 const bool updateData = updatePointData;
87
88 // save how data should be transferred to new level set
89 // list of indices into the old pointData vector
90 std::vector<std::vector<unsigned>> newDataSourceIds;
91 // there is no multithreading here, so just use 1
92 if (updateData)
93 newDataSourceIds.resize(1);
94
95 // iterate over all active points
96 for (viennahrle::ConstSparseCellIterator<hrleDomainType> cellIt(
97 levelSet->getDomain());
98 !cellIt.isFinished(); cellIt.next()) {
99
100 for (int u = 0; u < D; u++) {
101 while (!nodes[u].empty() &&
102 nodes[u].begin()->first <
103 viennahrle::Index<D>(cellIt.getIndices()))
104 nodes[u].erase(nodes[u].begin());
105 }
106
107 unsigned signs = 0;
108 for (int i = 0; i < (1 << D); i++) {
109 if (cellIt.getCorner(i).getValue() >= T(0))
110 signs |= (1 << i);
111 }
112
113 // all corners have the same sign, so no surface here
114 if (signs == 0)
115 continue;
116 if (signs == (1 << (1 << D)) - 1)
117 continue;
118
119 // for each element
120 const int *Triangles =
123
124 for (; Triangles[0] != -1; Triangles += D) {
125 std::array<unsigned, D> nod_numbers;
126
127 // for each node
128 for (int n = 0; n < D; n++) {
129 const int edge = Triangles[n];
130
131 unsigned p0 = corner0[edge];
132 unsigned p1 = corner1[edge];
133
134 // determine direction of edge
135 auto dir = direction[edge];
136
137 // look for existing surface node
138 viennahrle::Index<D> d(cellIt.getIndices());
139 d += viennahrle::BitMaskToIndex<D>(p0);
140
141 nodeIt = nodes[dir].find(d);
142 if (nodeIt != nodes[dir].end()) {
143 nod_numbers[n] = nodeIt->second;
144 } else { // if node does not exist yet
145
146 // calculate coordinate of new node
147 Vec3D<T> cc = {0., 0., 0.}; // initialise with zeros
148 std::size_t currentPointId = 0;
149 for (int z = 0; z < D; z++) {
150 if (z != dir) {
151 // TODO might not need BitMaskToVector here, just check if z bit
152 // is set
153 cc[z] =
154 static_cast<double>(cellIt.getIndices(z) +
155 viennahrle::BitMaskToIndex<D>(p0)[z]);
156 } else {
157 T d0, d1;
158
159 d0 = cellIt.getCorner(p0).getValue();
160 d1 = cellIt.getCorner(p1).getValue();
161
162 // calculate the surface-grid intersection point
163 if (d0 == -d1) { // includes case where d0=d1=0
164 currentPointId = cellIt.getCorner(p0).getPointId();
165 cc[z] = static_cast<T>(cellIt.getIndices(z)) + 0.5;
166 } else {
167 if (std::abs(d0) <= std::abs(d1)) {
168 currentPointId = cellIt.getCorner(p0).getPointId();
169 cc[z] =
170 static_cast<T>(cellIt.getIndices(z)) + (d0 / (d0 - d1));
171 } else {
172 currentPointId = cellIt.getCorner(p1).getPointId();
173 cc[z] = static_cast<T>(cellIt.getIndices(z) + 1) -
174 (d1 / (d1 - d0));
175 }
176 }
177 cc[z] = std::max(cc[z], cellIt.getIndices(z) + epsilon);
178 cc[z] = std::min(cc[z], (cellIt.getIndices(z) + 1) - epsilon);
179 }
180 cc[z] = levelSet->getGrid().getGridDelta() * cc[z];
181 }
182
183 // insert new node
184 nod_numbers[n] =
185 mesh->insertNextNode(cc); // insert new surface node
186 nodes[dir][d] = nod_numbers[n];
187
188 if (updateData)
189 newDataSourceIds[0].push_back(currentPointId);
190 }
191 }
192
193 if (!triangleMisformed(nod_numbers))
194 mesh->insertNextElement(nod_numbers); // insert new surface element
195 }
196 }
197
198 // now copy old data into new level set
199 if (updateData) {
200 mesh->getPointData().translateFromMultiData(levelSet->getPointData(),
201 newDataSourceIds);
202 }
203 }
204
205private:
206 static bool triangleMisformed(const std::array<unsigned, D> &nodeNumbers) {
207 if constexpr (D == 3) {
208 return nodeNumbers[0] == nodeNumbers[1] ||
209 nodeNumbers[0] == nodeNumbers[2] ||
210 nodeNumbers[1] == nodeNumbers[2];
211 } else {
212 return nodeNumbers[0] == nodeNumbers[1];
213 }
214 }
215};
216
217// add all template specialisations for this class
219
220} // namespace viennals
constexpr int D
Definition Epitaxy.cpp:9
double T
Definition Epitaxy.cpp:10
static const int * polygonize2d(unsigned int signs)
signs = signs of the corners in lexicographic order (1bit per corner)
Definition lsMarchingCubes.hpp:312
static const int * polygonize3d(unsigned int signs)
signs = signs of the corners in lexicographic order (1bit per corner)
Definition lsMarchingCubes.hpp:324
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:27
viennahrle::Domain< T, D > DomainType
Definition lsDomain.hpp:32
Expands the levelSet to the specified number of layers. The largest value in the levelset is thus wid...
Definition lsExpand.hpp:17
void apply()
Apply the expansion to the specified width.
Definition lsExpand.hpp:44
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:22
Extract an explicit Mesh<> instance from an lsDomain. The interface is then described by explicit sur...
Definition lsToSurfaceMesh.hpp:21
void setMesh(SmartPointer< Mesh< T > > passedMesh)
Definition lsToSurfaceMesh.hpp:41
ToSurfaceMesh(const SmartPointer< Domain< T, D > > passedLevelSet, SmartPointer< Mesh< T > > passedMesh, double eps=1e-12)
Definition lsToSurfaceMesh.hpp:33
void apply()
Definition lsToSurfaceMesh.hpp:45
void setUpdatePointData(bool update)
Definition lsToSurfaceMesh.hpp:43
void setLevelSet(SmartPointer< Domain< T, D > > passedlsDomain)
Definition lsToSurfaceMesh.hpp:37
ToSurfaceMesh(double eps=1e-12)
Definition lsToSurfaceMesh.hpp:31
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:36