8using namespace viennacore;
10template <
class NumericType,
int D>
14 using hrleIndex = viennahrle::Index<D>;
30 SmartPointer<MaterialMap> materialMap =
nullptr;
33 struct SharpCornerNode {
35 Vec3D<NumericType> position;
40 static int findNearestLowerCorner(
41 unsigned l,
const Vec3D<NumericType> &pos,
42 const std::unordered_map<
unsigned, std::vector<SharpCornerNode>>
46 for (
unsigned m = 0; m < l; ++m) {
47 auto it = sharpCornerNodes.find(m);
48 if (it == sharpCornerNodes.end())
50 for (
const auto &scn : it->second) {
52 for (
int i = 0; i <
D; ++i) {
56 if (dist2 < minDist2) {
67 void splitPreviousMaterialEdge(
unsigned l,
unsigned cornerNodeId,
68 const Vec3D<NumericType> &cornerPos,
69 size_t meshSizeBefore) {
75 for (
size_t lineIdx = 0; lineIdx <
mesh->lines.size(); ++lineIdx) {
80 auto &line =
mesh->lines[lineIdx];
81 unsigned node0 = line[0];
82 unsigned node1 = line[1];
84 auto const &pos0 =
mesh->nodes[node0];
85 auto const &pos1 =
mesh->nodes[node1];
86 auto lineVec = pos1 - pos0;
90 for (
int i = 0; i <
D; ++i) {
91 lineLen2 += lineVec[i] * lineVec[i];
92 dot += (cornerPos[i] - pos0[i]) * lineVec[i];
104 for (
int i = 0; i <
D; ++i) {
105 NumericType d = cornerPos[i] - (pos0[i] + t * lineVec[i]);
113 auto reassignSegment = [&](
int idx,
unsigned a,
unsigned b) {
115 mesh->lines[idx] = {a, b};
121 for (
size_t k = meshSizeBefore; k <
mesh->lines.size(); ++k) {
122 const auto &rl =
mesh->lines[k];
123 if ((rl[0] == node0 && rl[1] == cornerNodeId) ||
124 (rl[0] == cornerNodeId && rl[1] == node0))
126 if ((rl[0] == cornerNodeId && rl[1] == node1) ||
127 (rl[0] == node1 && rl[1] == cornerNodeId))
131 if (seg1Idx != -1 && seg2Idx != -1) {
132 reassignSegment(seg1Idx, node0, cornerNodeId);
133 reassignSegment(seg2Idx, cornerNodeId, node1);
134 mesh->lines.erase(
mesh->lines.begin() + lineIdx);
137 }
else if (seg1Idx != -1) {
138 reassignSegment(seg1Idx, node0, cornerNodeId);
139 line[0] = cornerNodeId;
141 }
else if (seg2Idx != -1) {
142 reassignSegment(seg2Idx, cornerNodeId, node1);
143 line[1] = cornerNodeId;
145 line[1] = cornerNodeId;
146 mesh->lines.push_back({cornerNodeId, node1});
157 snapSharpCorners(
unsigned l,
size_t meshSizeBefore,
158 std::unordered_map<
unsigned, std::vector<SharpCornerNode>>
161 unsigned cornerNodeId = cornerPair.first;
162 Vec3D<NumericType> cornerPos = cornerPair.second;
165 (l > 0) ? findNearestLowerCorner(l, cornerPos, sharpCornerNodes) : -1;
167 if (snapToNodeId >= 0) {
169 if constexpr (
D == 2) {
171 for (
size_t i =
mesh->lines.size(); i-- > meshSizeBefore;) {
172 for (
int j = 0; j < 2; ++j) {
173 if (
mesh->lines[i][j] == cornerNodeId)
174 mesh->lines[i][j] = snapToNodeId;
177 unsigned n0 =
mesh->lines[i][0];
178 unsigned n1 =
mesh->lines[i][1];
182 if (n0 == n1 || isDuplicate) {
183 mesh->lines.erase(
mesh->lines.begin() + i);
191 sharpCornerNodes[l].push_back(
192 {
static_cast<unsigned>(snapToNodeId), cornerPos});
195 sharpCornerNodes[l].push_back({cornerNodeId, cornerPos});
196 splitPreviousMaterialEdge(l, cornerNodeId, cornerPos, meshSizeBefore);
207 double minNodeDistFactor = 0.05,
double eps = 1e-12)
209 minNodeDistFactor, eps) {}
212 std::vector<SmartPointer<lsDomainType>>
const &passedLevelSets,
214 double minNodeDistFactor = 0.05,
double eps = 1e-12)
221 double minNodeDistFactor = 0.05,
double eps = 1e-12)
233 materialMap = passedMaterialMap;
238 Logger::getInstance()
239 .addError(
"No level set was passed to ToMultiSurfaceMesh.")
243 if (
mesh ==
nullptr) {
244 Logger::getInstance()
245 .addError(
"No mesh was passed to ToMultiSurfaceMesh.")
252 for (
unsigned i = 0; i <
D; ++i) {
253 mesh->minimumExtent[i] = std::numeric_limits<NumericType>::max();
254 mesh->maximumExtent[i] = std::numeric_limits<NumericType>::lowest();
257 using nodeContainerType = std::map<viennahrle::Index<D>,
unsigned>;
259 nodeContainerType nodes[
D];
260 nodeContainerType faceNodes[
D];
261 nodeContainerType cornerNodes;
268 const bool useMaterialMap = materialMap !=
nullptr;
271 if (sharpCorners &&
D == 3) {
272 Logger::getInstance()
273 .addWarning(
"Sharp corner generation in 3D is experimental and may "
274 "produce suboptimal meshes. Use with caution.")
279 std::vector<viennahrle::ConstSparseCellIterator<hrleDomainType>> cellIts;
281 cellIts.emplace_back(
ls->getDomain());
284 std::unordered_map<unsigned, std::vector<SharpCornerNode>> sharpCornerNodes;
286 for (
unsigned l = 0; l <
levelSets.size(); l++) {
288 if (useMaterialMap) {
300 normalCalculator.
setMaxValue(std::numeric_limits<NumericType>::max());
301 normalCalculator.
apply();
306 viennahrle::ConstSparseIterator<hrleDomainType> valueIt(
310 for (
auto cellIt = cellIts[l]; !cellIt.isFinished(); cellIt.next()) {
311 for (
int u = 0; u <
D; u++) {
312 while (!nodes[u].empty() &&
313 nodes[u].begin()->first <
314 viennahrle::Index<D>(cellIt.getIndices()))
315 nodes[u].erase(nodes[u].begin());
317 if constexpr (
D == 3) {
318 while (!faceNodes[u].empty() &&
319 faceNodes[u].begin()->first <
320 viennahrle::Index<D>(cellIt.getIndices()))
321 faceNodes[u].erase(faceNodes[u].begin());
324 while (!cornerNodes.empty() &&
325 cornerNodes.begin()->first <
326 viennahrle::Index<D>(cellIt.getIndices()))
327 cornerNodes.erase(cornerNodes.begin());
333 for (
int i = 0; i < (1 <<
D); i++) {
334 if (cellIt.getCorner(i).getValue() >=
NumericType(0))
341 if (signs == (1 << (1 <<
D)) - 1)
346 bool atMaterialBoundary =
false;
347 unsigned touchingMaterial = 0;
348 if (sharpCorners && l > 0) {
349 touchingMaterial = l - 1;
350 viennahrle::ConstSparseIterator<hrleDomainType> prevIt(
351 levelSets[touchingMaterial]->getDomain());
352 for (
int i = 0; i < (1 <<
D); ++i) {
353 hrleIndex cornerIdx =
354 cellIt.getIndices() + viennahrle::BitMaskToIndex<D>(i);
355 prevIt.goToIndices(cornerIdx);
356 if (prevIt.getValue() <= 0) {
357 atMaterialBoundary =
true;
364 bool perfectCornerFound =
false;
370 for (
int i = 0; i < (1 <<
D); ++i) {
393 size_t meshSizeBefore = 0;
394 if constexpr (
D == 2) {
395 meshSizeBefore =
mesh->lines.size();
398 posMask, nodes,
nullptr, valueIt);
399 }
else if constexpr (
D == 3) {
400 if (countNeg == 2 || countPos == 2) {
402 cellIt, countNeg, countPos, negMask, posMask, nodes,
403 faceNodes,
nullptr, valueIt);
404 }
else if (countNeg == 1 || countPos == 1) {
406 cellIt, countNeg, countPos, negMask, posMask, nodes,
407 cornerNodes, faceNodes,
nullptr, valueIt);
408 }
else if (countNeg == 3 || countPos == 3) {
410 cellIt, countNeg, countPos, negMask, posMask, nodes,
411 faceNodes,
nullptr, valueIt);
418 snapSharpCorners(l, meshSizeBefore, sharpCornerNodes);
422 if (perfectCornerFound)
425 if constexpr (
D == 3) {
427 for (
int axis = 0; axis < 3; ++axis) {
428 for (
int d = 0; d < 2; ++d) {
429 viennahrle::Index<D> faceKey(cellIt.getIndices());
433 auto it = faceNodes[axis].find(faceKey);
434 if (it != faceNodes[axis].end()) {
435 const unsigned faceNodeId = it->second;
436 const int *Triangles =
439 for (; Triangles[0] != -1; Triangles += 3) {
440 std::vector<unsigned> face_edge_nodes;
441 for (
int i = 0; i < 3; ++i) {
442 int edge = Triangles[i];
446 (((c0 >> axis) & 1) == d) && (((c1 >> axis) & 1) == d);
448 face_edge_nodes.push_back(
449 this->
getNode(cellIt, edge, nodes,
nullptr));
452 if (face_edge_nodes.size() == 2) {
454 face_edge_nodes[0], face_edge_nodes[1], faceNodeId});
463 const int *Triangles;
464 if constexpr (
D == 2) {
470 for (; Triangles[0] != -1; Triangles +=
D) {
471 std::array<unsigned, D> nodeNumbers;
474 for (
int n = 0; n <
D; n++) {
475 const int edge = Triangles[n];
477 unsigned p0 = this->
corner0[edge];
483 viennahrle::Index<D> d(cellIt.getIndices());
484 auto p0B = viennahrle::BitMaskToIndex<D>(p0);
487 auto nodeIt = nodes[dir].find(d);
488 if (nodeIt != nodes[dir].end()) {
489 nodeNumbers[n] = nodeIt->second;
493 if (sharpCorners && l > 0 && atMaterialBoundary) {
494 unsigned cachedNodeId = nodeIt->second;
496 auto it = sharpCornerNodes.find(touchingMaterial);
497 if (it != sharpCornerNodes.end()) {
498 for (
const auto &scn : it->second) {
499 if (scn.nodeId == cachedNodeId) {
501 auto &lCorners = sharpCornerNodes[l];
502 bool alreadyInherited =
false;
503 for (
const auto &existing : lCorners) {
504 if (existing.nodeId == cachedNodeId) {
505 alreadyInherited =
true;
509 if (!alreadyInherited)
510 lCorners.push_back({cachedNodeId, scn.position});
520 Vec3D<NumericType> snapPos{};
521 if (sharpCorners && l > 0 && atMaterialBoundary) {
522 auto tmIt = sharpCornerNodes.find(touchingMaterial);
523 if (tmIt != sharpCornerNodes.end() && !tmIt->second.empty()) {
524 Vec3D<NumericType> nodePos =
528 for (
const auto &scn : tmIt->second) {
530 for (
int i = 0; i <
D; ++i) {
534 if (dist2 < minDist2) {
536 snapNodeId = scn.nodeId;
537 snapPos = scn.position;
543 if (snapNodeId >= 0) {
544 nodeNumbers[n] = snapNodeId;
545 nodes[dir][d] = snapNodeId;
547 sharpCornerNodes[l].push_back(
548 {
static_cast<unsigned>(snapNodeId), snapPos});
550 nodeNumbers[n] = this->
getNode(cellIt, edge, nodes,
nullptr);
556 bool isDuplicate =
false;
557 if constexpr (
D == 2) {
559 if (
uniqueElements.find({(int)nodeNumbers[1], (int)nodeNumbers[0],
575 mesh->triangles.shrink_to_fit();
576 mesh->nodes.shrink_to_fit();
float NumericType
Definition AirGapDeposition.cpp:24
constexpr int D
Definition Epitaxy.cpp:11
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
This algorithm is used to compute the normal vectors for all points with level set values <= maxValue...
Definition lsCalculateNormalVectors.hpp:40
static constexpr char normalVectorsLabel[]
Definition lsCalculateNormalVectors.hpp:52
void apply()
Definition lsCalculateNormalVectors.hpp:95
void setMethod(NormalCalculationMethodEnum passedMethod)
Definition lsCalculateNormalVectors.hpp:79
void setMaxValue(const T passedMaxValue)
Definition lsCalculateNormalVectors.hpp:67
Class containing all information about the level set, including the dimensions of the domain,...
Definition lsDomain.hpp:28
viennahrle::Domain< NumericType, D > DomainType
Definition lsDomain.hpp:33
This class holds an explicit mesh, which is always given in 3 dimensions. If it describes a 2D mesh,...
Definition lsMesh.hpp:22
ToMultiSurfaceMesh(SmartPointer< lsDomainType > passedLevelSet, SmartPointer< viennals::Mesh< NumericType > > passedMesh, double minNodeDistFactor=0.05, double eps=1e-12)
Definition lsToMultiSurfaceMesh.hpp:205
ToMultiSurfaceMesh(SmartPointer< viennals::Mesh< NumericType > > passedMesh, double minNodeDistFactor=0.05, double eps=1e-12)
Definition lsToMultiSurfaceMesh.hpp:220
ToMultiSurfaceMesh(double minNodeDistFactor=0.05, double eps=1e-12)
Definition lsToMultiSurfaceMesh.hpp:202
void apply() override
Definition lsToMultiSurfaceMesh.hpp:236
ToMultiSurfaceMesh(std::vector< SmartPointer< lsDomainType > > const &passedLevelSets, SmartPointer< viennals::Mesh< NumericType > > passedMesh, double minNodeDistFactor=0.05, double eps=1e-12)
Definition lsToMultiSurfaceMesh.hpp:211
void setMaterialMap(SmartPointer< MaterialMap > passedMaterialMap)
Definition lsToMultiSurfaceMesh.hpp:232
void clearLevelSets()
Definition lsToMultiSurfaceMesh.hpp:230
void insertNextLevelSet(SmartPointer< lsDomainType > passedLevelSet)
Definition lsToMultiSurfaceMesh.hpp:226
SmartPointer< Mesh< NumericType > > mesh
Definition lsToSurfaceMesh.hpp:33
static constexpr unsigned int direction[12]
Definition lsToSurfaceMesh.hpp:77
bool generateSharpEdge3D(viennahrle::ConstSparseCellIterator< hrleDomainType > &cellIt, int countNeg, int countPos, int negMask, int posMask, std::map< hrleIndex, unsigned > *nodes, std::map< hrleIndex, unsigned > *faceNodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:1209
SmartPointer< lsDomainType > currentLevelSet
Definition lsToSurfaceMesh.hpp:67
bool generateSharpCorner2D(viennahrle::ConstSparseCellIterator< hrleDomainType > &cellIt, int countNeg, int countPos, int negMask, int posMask, std::map< hrleIndex, unsigned > *nodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:552
bool generateSharpCorners
Definition lsToSurfaceMesh.hpp:38
std::vector< SmartPointer< lsDomainType > > levelSets
Definition lsToSurfaceMesh.hpp:32
std::unordered_map< I3, unsigned, I3Hash > nodeIdByBin
Definition lsToSurfaceMesh.hpp:61
const NumericType epsilon
Definition lsToSurfaceMesh.hpp:35
Vec3D< NumericType > computeNodePosition(viennahrle::ConstSparseCellIterator< hrleDomainType > &cellIt, int edge)
Definition lsToSurfaceMesh.hpp:356
bool generateSharpCorner3D(viennahrle::ConstSparseCellIterator< hrleDomainType > &cellIt, int countNeg, int countPos, int negMask, int posMask, std::map< hrleIndex, unsigned > *nodes, std::map< hrleIndex, unsigned > &cornerNodes, std::map< hrleIndex, unsigned > *faceNodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:1374
std::unordered_set< I3, I3Hash > uniqueElements
Definition lsToSurfaceMesh.hpp:62
std::vector< std::pair< unsigned, Vec3D< NumericType > > > matSharpCornerNodes
Definition lsToSurfaceMesh.hpp:71
static constexpr unsigned int corner1[12]
Definition lsToSurfaceMesh.hpp:75
void insertElement(const std::array< unsigned, D > &nodeNumbers)
Definition lsToSurfaceMesh.hpp:1647
ToSurfaceMesh(double mnd=0.05, double eps=1e-12)
Definition lsToSurfaceMesh.hpp:81
double currentGridDelta
Definition lsToSurfaceMesh.hpp:65
bool generateSharpL3D(viennahrle::ConstSparseCellIterator< hrleDomainType > &cellIt, int countNeg, int countPos, int negMask, int posMask, std::map< hrleIndex, unsigned > *nodes, std::map< hrleIndex, unsigned > *faceNodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:671
PointData< NumericType >::VectorDataType * normalVectorData
Definition lsToSurfaceMesh.hpp:68
std::vector< Vec3D< NumericType > > currentNormals
Definition lsToSurfaceMesh.hpp:63
void scaleMesh()
Definition lsToSurfaceMesh.hpp:342
std::vector< NumericType > currentMaterials
Definition lsToSurfaceMesh.hpp:64
NumericType currentMaterialId
Definition lsToSurfaceMesh.hpp:66
unsigned getNode(viennahrle::ConstSparseCellIterator< hrleDomainType > &cellIt, int edge, std::map< hrleIndex, unsigned > *nodes, std::vector< unsigned > *newDataSourceIds)
Definition lsToSurfaceMesh.hpp:386
static constexpr unsigned int corner0[12]
Definition lsToSurfaceMesh.hpp:73
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:41
@ ONE_SIDED_MIN_MOD
Definition lsCalculateNormalVectors.hpp:22
Definition lsToSurfaceMesh.hpp:40