ViennaLS
Loading...
Searching...
No Matches
lsToMultiSurfaceMesh.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <iostream>
6#include <map>
7#include <unordered_map>
8#include <unordered_set>
9
10#include <hrleSparseCellIterator.hpp>
11#include <lsDomain.hpp>
12#include <lsExpand.hpp>
13#include <lsMarchingCubes.hpp>
14#include <lsMaterialMap.hpp>
15#include <lsMesh.hpp>
16
17namespace viennals {
18
19using namespace viennacore;
20
21template <class NumericType, int D, class T = NumericType>
23
24 typedef viennals::Domain<NumericType, D> lsDomainType;
25 typedef typename viennals::Domain<NumericType, D>::DomainType hrleDomainType;
26
27 std::vector<SmartPointer<lsDomainType>> levelSets;
28 SmartPointer<viennals::Mesh<T>> mesh = nullptr;
29 SmartPointer<MaterialMap> materialMap = nullptr;
30
31 const double epsilon;
32 const double minNodeDistanceFactor;
33
34 struct I3 {
35 int x, y, z;
36 bool operator==(const I3 &o) const {
37 return x == o.x && y == o.y && z == o.z;
38 }
39 };
40
41 struct I3Hash {
42 size_t operator()(const I3 &k) const {
43 // 64-bit mix
44 uint64_t a = (uint64_t)(uint32_t)k.x;
45 uint64_t b = (uint64_t)(uint32_t)k.y;
46 uint64_t c = (uint64_t)(uint32_t)k.z;
47 uint64_t h = a * 0x9E3779B185EBCA87ULL;
48 h ^= b + 0xC2B2AE3D27D4EB4FULL + (h << 6) + (h >> 2);
49 h ^= c + 0x165667B19E3779F9ULL + (h << 6) + (h >> 2);
50 return (size_t)h;
51 }
52 };
53
54public:
55 ToMultiSurfaceMesh(double eps = 1e-12, double minNodeDistFactor = 0.05)
56 : epsilon(eps), minNodeDistanceFactor(minNodeDistFactor) {}
57
58 ToMultiSurfaceMesh(SmartPointer<lsDomainType> passedLevelSet,
59 SmartPointer<viennals::Mesh<T>> passedMesh,
60 double eps = 1e-12, double minNodeDistFactor = 0.05)
61 : mesh(passedMesh), epsilon(eps),
62 minNodeDistanceFactor(minNodeDistFactor) {
63 levelSets.push_back(passedLevelSet);
64 }
65
67 std::vector<SmartPointer<lsDomainType>> const &passedLevelSets,
68 SmartPointer<viennals::Mesh<T>> passedMesh, double eps = 1e-12,
69 double minNodeDistFactor = 0.05)
70 : levelSets(passedLevelSets), mesh(passedMesh), epsilon(eps),
71 minNodeDistanceFactor(minNodeDistFactor) {}
72
73 ToMultiSurfaceMesh(SmartPointer<viennals::Mesh<T>> passedMesh,
74 double eps = 1e-12, double minNodeDistFactor = 0.05)
75 : mesh(passedMesh), epsilon(eps),
76 minNodeDistanceFactor(minNodeDistFactor) {}
77
78 void setMesh(SmartPointer<viennals::Mesh<T>> passedMesh) {
79 mesh = passedMesh;
80 }
81
82 void insertNextLevelSet(SmartPointer<lsDomainType> passedLevelSet) {
83 levelSets.push_back(passedLevelSet);
84 }
85
86 void clearLevelSets() { levelSets.clear(); }
87
88 void setMaterialMap(SmartPointer<MaterialMap> passedMaterialMap) {
89 materialMap = passedMaterialMap;
90 }
91
92 void apply() {
93 if (levelSets.empty()) {
94 Logger::getInstance()
95 .addError("No level set was passed to ToMultiSurfaceMesh.")
96 .print();
97 return;
98 }
99 if (mesh == nullptr) {
100 Logger::getInstance()
101 .addError("No mesh was passed to ToMultiSurfaceMesh.")
102 .print();
103 return;
104 }
105
106 mesh->clear();
107 const auto gridDelta = levelSets.front()->getGrid().getGridDelta();
108 for (unsigned i = 0; i < D; ++i) {
109 mesh->minimumExtent[i] = std::numeric_limits<NumericType>::max();
110 mesh->maximumExtent[i] = std::numeric_limits<NumericType>::lowest();
111 }
112
113 constexpr unsigned int corner0[12] = {0, 1, 2, 0, 4, 5, 6, 4, 0, 1, 3, 2};
114 constexpr unsigned int corner1[12] = {1, 3, 3, 2, 5, 7, 7, 6, 4, 5, 7, 6};
115 constexpr unsigned int direction[12] = {0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2};
116
117 typedef std::map<viennahrle::Index<D>, unsigned> nodeContainerType;
118
119 nodeContainerType nodes[D];
120 const double minNodeDistance = gridDelta * minNodeDistanceFactor;
121 std::unordered_map<I3, unsigned, I3Hash> nodeIdByBin;
122 std::unordered_set<I3, I3Hash> uniqueElements;
123
124 typename nodeContainerType::iterator nodeIt;
125
126 std::vector<Vec3D<T>> normals;
127 std::vector<T> materials;
128
129 const bool checkNodeFlag = minNodeDistanceFactor > 0;
130 const bool useMaterialMap = materialMap != nullptr;
131
132 auto quantize = [&minNodeDistance](const Vec3D<T> &p) -> I3 {
133 const T inv = T(1) / minNodeDistance;
134 return {(int)std::llround(p[0] * inv), (int)std::llround(p[1] * inv),
135 (int)std::llround(p[2] * inv)};
136 };
137
138 auto elementI3 = [&](const std::array<unsigned, D> &element) -> I3 {
139 if constexpr (D == 2)
140 return {(int)element[0], (int)element[1], 0};
141 else
142 return {(int)element[0], (int)element[1], (int)element[2]};
143 };
144
145 // an iterator for each level set
146 std::vector<viennahrle::ConstSparseCellIterator<hrleDomainType>> cellIts;
147 for (const auto &ls : levelSets)
148 cellIts.emplace_back(ls->getDomain());
149
150 for (unsigned l = 0; l < levelSets.size(); l++) {
151 // iterate over all active surface points
152 for (auto cellIt = cellIts[l]; !cellIt.isFinished(); cellIt.next()) {
153 for (int u = 0; u < D; u++) {
154 while (!nodes[u].empty() &&
155 nodes[u].begin()->first <
156 viennahrle::Index<D>(cellIt.getIndices()))
157 nodes[u].erase(nodes[u].begin());
158 }
159
160 unsigned signs = 0;
161 for (int i = 0; i < (1 << D); i++) {
162 if (cellIt.getCorner(i).getValue() >= NumericType(0))
163 signs |= (1 << i);
164 }
165
166 // all corners have the same sign, so no surface here
167 if (signs == 0)
168 continue;
169 if (signs == (1 << (1 << D)) - 1)
170 continue;
171
172 // for each element
173 const int *Triangles;
174 if constexpr (D == 2) {
176 } else {
178 }
179
180 for (; Triangles[0] != -1; Triangles += D) {
181 std::array<unsigned, D> nod_numbers;
182
183 // for each node
184 for (int n = 0; n < D; n++) {
185 const int edge = Triangles[n];
186
187 unsigned p0 = corner0[edge];
188 unsigned p1 = corner1[edge];
189
190 // determine direction of edge
191 unsigned dir = direction[edge];
192
193 // look for existing surface node
194 viennahrle::Index<D> d(cellIt.getIndices());
195 auto p0B = viennahrle::BitMaskToIndex<D>(p0);
196 d += p0B;
197
198 nodeIt = nodes[dir].find(d);
199 if (nodeIt != nodes[dir].end()) {
200 nod_numbers[n] = nodeIt->second;
201 } else {
202 // if node does not exist yet
203 // calculate coordinate of new node
204 Vec3D<T> cc{}; // initialise with zeros
205 for (int z = 0; z < D; z++) {
206 if (z != dir) {
207 // TODO might not need BitMaskToVector here, just check if z
208 // bit is set
209 cc[z] = static_cast<T>(cellIt.getIndices(z) + p0B[z]);
210 } else {
211 auto d0 = static_cast<T>(cellIt.getCorner(p0).getValue());
212 auto d1 = static_cast<T>(cellIt.getCorner(p1).getValue());
213
214 // calculate the surface-grid intersection point
215 if (d0 == -d1) { // includes case where d0=d1=0
216 cc[z] = static_cast<T>(cellIt.getIndices(z)) + 0.5;
217 } else {
218 if (std::abs(d0) <= std::abs(d1)) {
219 cc[z] = static_cast<T>(cellIt.getIndices(z)) +
220 (d0 / (d0 - d1));
221 } else {
222 cc[z] = static_cast<T>(cellIt.getIndices(z) + 1) -
223 (d1 / (d1 - d0));
224 }
225 }
226 cc[z] = std::max(
227 cc[z], static_cast<T>(cellIt.getIndices(z) + epsilon));
228 cc[z] = std::min(
229 cc[z],
230 static_cast<T>((cellIt.getIndices(z) + 1) - epsilon));
231 }
232 cc[z] *= gridDelta;
233 }
234
235 int nodeIdx = -1;
236 if (checkNodeFlag) {
237 auto q = quantize(cc);
238 auto it = nodeIdByBin.find(q);
239 if (it != nodeIdByBin.end())
240 nodeIdx = it->second;
241 }
242 if (nodeIdx >= 0) {
243 nod_numbers[n] = nodeIdx;
244 } else {
245 // insert new node
246 nod_numbers[n] =
247 mesh->insertNextNode(cc); // insert new surface node
248 nodes[dir][d] = nod_numbers[n];
249 if (checkNodeFlag)
250 nodeIdByBin.emplace(quantize(cc), nod_numbers[n]);
251
252 for (int a = 0; a < D; a++) {
253 if (cc[a] < mesh->minimumExtent[a])
254 mesh->minimumExtent[a] = cc[a];
255 if (cc[a] > mesh->maximumExtent[a])
256 mesh->maximumExtent[a] = cc[a];
257 }
258 }
259 }
260 }
261
262 // check for degenerate triangles
263 if (!triangleMisformed(nod_numbers)) {
264
265 // only insert if not already present
266 if (uniqueElements.insert(elementI3(nod_numbers)).second) {
267 Vec3D<T> normal;
268 if constexpr (D == 2) {
269 normal = Vec3D<T>{-(mesh->nodes[nod_numbers[1]][1] -
270 mesh->nodes[nod_numbers[0]][1]),
271 mesh->nodes[nod_numbers[1]][0] -
272 mesh->nodes[nod_numbers[0]][0],
273 T(0)};
274 } else {
275 normal = calculateNormal(mesh->nodes[nod_numbers[0]],
276 mesh->nodes[nod_numbers[1]],
277 mesh->nodes[nod_numbers[2]]);
278 }
279
280 double n2 = normal[0] * normal[0] + normal[1] * normal[1] +
281 normal[2] * normal[2];
282 if (n2 > epsilon) {
283 // insert new element
284 mesh->insertNextElement(nod_numbers);
285
286 // insert normal
287 T invn = static_cast<T>(1.) / std::sqrt(static_cast<T>(n2));
288 for (int d = 0; d < D; d++) {
289 normal[d] *= invn;
290 }
291 normals.push_back(normal);
292
293 // insert material
294 if (useMaterialMap) {
295 materials.push_back(materialMap->getMaterialId(l));
296 } else {
297 materials.push_back(static_cast<T>(l));
298 }
299 }
300 }
301 }
302 }
303 }
304 }
305
306 mesh->cellData.insertNextScalarData(materials, "MaterialIds");
307 mesh->cellData.insertNextVectorData(normals, "Normals");
308 mesh->triangles.shrink_to_fit();
309 mesh->nodes.shrink_to_fit();
310 }
311
312private:
313 static inline bool
314 triangleMisformed(const std::array<unsigned, D> &nod_numbers) noexcept {
315 if constexpr (D == 3) {
316 return nod_numbers[0] == nod_numbers[1] ||
317 nod_numbers[0] == nod_numbers[2] ||
318 nod_numbers[1] == nod_numbers[2];
319 } else {
320 return nod_numbers[0] == nod_numbers[1];
321 }
322 }
323
324 static inline Vec3D<NumericType>
325 calculateNormal(const Vec3D<NumericType> &nodeA,
326 const Vec3D<NumericType> &nodeB,
327 const Vec3D<NumericType> &nodeC) noexcept {
328 return CrossProduct(nodeB - nodeA, nodeC - nodeA);
329 }
330};
331
333
334} // namespace viennals
float NumericType
Definition AirGapDeposition.cpp:24
constexpr int D
Definition Epitaxy.cpp:11
double T
Definition Epitaxy.cpp:12
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
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:22
Definition lsToMultiSurfaceMesh.hpp:22
void setMaterialMap(SmartPointer< MaterialMap > passedMaterialMap)
Definition lsToMultiSurfaceMesh.hpp:88
void setMesh(SmartPointer< viennals::Mesh< T > > passedMesh)
Definition lsToMultiSurfaceMesh.hpp:78
void apply()
Definition lsToMultiSurfaceMesh.hpp:92
void clearLevelSets()
Definition lsToMultiSurfaceMesh.hpp:86
ToMultiSurfaceMesh(double eps=1e-12, double minNodeDistFactor=0.05)
Definition lsToMultiSurfaceMesh.hpp:55
ToMultiSurfaceMesh(SmartPointer< lsDomainType > passedLevelSet, SmartPointer< viennals::Mesh< T > > passedMesh, double eps=1e-12, double minNodeDistFactor=0.05)
Definition lsToMultiSurfaceMesh.hpp:58
ToMultiSurfaceMesh(std::vector< SmartPointer< lsDomainType > > const &passedLevelSets, SmartPointer< viennals::Mesh< T > > passedMesh, double eps=1e-12, double minNodeDistFactor=0.05)
Definition lsToMultiSurfaceMesh.hpp:66
void insertNextLevelSet(SmartPointer< lsDomainType > passedLevelSet)
Definition lsToMultiSurfaceMesh.hpp:82
ToMultiSurfaceMesh(SmartPointer< viennals::Mesh< T > > passedMesh, double eps=1e-12, double minNodeDistFactor=0.05)
Definition lsToMultiSurfaceMesh.hpp:73
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:37