6#include <unordered_map>
7#include <unordered_set>
9#include <hrleSparseCellIterator.hpp>
10#include <hrleSparseStarIterator.hpp>
20using namespace viennacore;
32 viennahrle::ConstSparseCellIterator<hrleDomainType>;
35 SmartPointer<Mesh<T>>
mesh =
nullptr;
45 return x == o.
x &&
y == o.
y &&
z == o.
z;
52 uint64_t a = (uint64_t)(uint32_t)k.
x;
53 uint64_t b = (uint64_t)(uint32_t)k.
y;
54 uint64_t c = (uint64_t)(uint32_t)k.
z;
55 uint64_t h = a * 0x9E3779B185EBCA87ULL;
56 h ^= b + 0xC2B2AE3D27D4EB4FULL + (h << 6) + (h >> 2);
57 h ^= c + 0x165667B19E3779F9ULL + (h << 6) + (h >> 2);
74 static constexpr unsigned int corner0[12] = {0, 1, 2, 0, 4, 5,
76 static constexpr unsigned int corner1[12] = {1, 3, 3, 2, 5, 7,
78 static constexpr unsigned int direction[12] = {0, 1, 0, 1, 0, 1,
86 SmartPointer<
Mesh<T>> passedMesh,
double mnd = 0.05,
105 Logger::getInstance()
106 .addError(
"No level set was passed to ToSurfaceMesh.")
110 if (
mesh ==
nullptr) {
111 Logger::getInstance()
112 .addError(
"No mesh was passed to ToSurfaceMesh.")
118 VIENNACORE_LOG_WARNING(
119 "ToSurfaceMesh: Level set is empty. No mesh will be created.");
126 VIENNACORE_LOG_WARNING(
"Levelset is less than 2 layers wide. Expanding "
127 "levelset to 2 layers.");
134 typedef std::map<hrleIndex, unsigned> nodeContainerType;
136 nodeContainerType nodes[
D];
137 nodeContainerType faceNodes[
D];
138 nodeContainerType cornerNodes;
140 typename nodeContainerType::iterator nodeIt;
144 std::vector<std::vector<unsigned>> newDataSourceIds;
147 newDataSourceIds.resize(1);
155 normalCalculator.
setMaxValue(std::numeric_limits<T>::max());
156 normalCalculator.
apply();
163 !cellIt.isFinished(); cellIt.next()) {
167 for (
int u = 0; u <
D; u++) {
168 while (!nodes[u].empty() &&
169 nodes[u].begin()->first <
hrleIndex(cellIt.getIndices()))
170 nodes[u].erase(nodes[u].begin());
172 while (!faceNodes[u].empty() &&
173 faceNodes[u].begin()->first <
hrleIndex(cellIt.getIndices()))
174 faceNodes[u].erase(faceNodes[u].begin());
177 while (!cornerNodes.empty() &&
178 cornerNodes.begin()->first <
hrleIndex(cellIt.getIndices()))
179 cornerNodes.erase(cornerNodes.begin());
186 bool hasZero =
false;
187 for (
int i = 0; i < (1 <<
D); i++) {
188 T val = cellIt.getCorner(i).getValue();
198 if (signs == (1 << (1 <<
D)) - 1 && !hasZero)
202 bool perfectCornerFound =
false;
208 for (
int i = 0; i < (1 <<
D); ++i) {
209 T val = cellIt.getCorner(i).getValue();
228 if constexpr (
D == 2) {
230 cellIt, countNeg, countPos, negMask, posMask, nodes,
231 &newDataSourceIds[0], valueIt);
232 }
else if constexpr (
D == 3) {
233 if (countNeg == 2 || countPos == 2) {
236 cellIt, countNeg, countPos, negMask, posMask, nodes, faceNodes,
237 &newDataSourceIds[0], valueIt);
238 }
else if (countNeg == 1 || countPos == 1) {
241 cellIt, countNeg, countPos, negMask, posMask, nodes,
242 cornerNodes, faceNodes, &newDataSourceIds[0], valueIt);
243 }
else if (countNeg == 3 || countPos == 3) {
246 cellIt, countNeg, countPos, negMask, posMask, nodes, faceNodes,
247 &newDataSourceIds[0], valueIt);
254 if (perfectCornerFound)
257 if constexpr (
D == 3) {
262 for (
int axis = 0; axis < 3; ++axis) {
263 for (
int d = 0; d < 2; ++d) {
268 auto it = faceNodes[axis].find(faceKey);
269 if (it != faceNodes[axis].end()) {
270 const unsigned faceNodeId = it->second;
271 const int *Triangles =
274 for (; Triangles[0] != -1; Triangles += 3) {
275 std::vector<unsigned> face_edge_nodes;
276 for (
int i = 0; i < 3; ++i) {
277 int edge = Triangles[i];
281 (((c0 >> axis) & 1) == d) && (((c1 >> axis) & 1) == d);
283 face_edge_nodes.push_back(
284 getNode(cellIt, edge, nodes, &newDataSourceIds[0]));
287 if (face_edge_nodes.size() == 2) {
289 {face_edge_nodes[0], face_edge_nodes[1], faceNodeId});
300 const int *Triangles =
304 for (; Triangles[0] != -1; Triangles +=
D) {
305 std::array<unsigned, D> nodeNumbers;
308 for (
int n = 0; n <
D; n++) {
311 getNode(cellIt, Triangles[n], nodes, &newDataSourceIds[0]);
322 mesh->getPointData().translateFromMultiData(
330 for (
auto &node :
mesh->nodes) {
331 node = node * gridDelta;
333 mesh->minimumExtent =
mesh->minimumExtent * gridDelta;
334 mesh->maximumExtent =
mesh->maximumExtent * gridDelta;
337 template <
class OffsetType>
340 const OffsetType &offset)
const {
342 for (
int z = 0; z <
D; z++) {
345 static_cast<T>(offset[z] + viennahrle::BitMaskToIndex<D>(p0)[z]);
348 cc[z] =
static_cast<T>(offset[z]) +
T(0.5);
350 if (std::abs(d0) <= std::abs(d1)) {
351 cc[z] =
static_cast<T>(offset[z]) + (d0 / (d0 - d1));
353 cc[z] =
static_cast<T>(offset[z] + 1) - (d1 / (d1 - d0));
356 cc[z] = std::max(cc[z], offset[z] +
epsilon);
357 cc[z] = std::min(cc[z], (offset[z] + 1) -
epsilon);
366 std::tuple<Vec3D<T>, std::size_t>
368 const unsigned p0 =
corner0[edge];
369 const unsigned p1 =
corner1[edge];
371 const T d0 = cellIt.getCorner(p0).getValue();
372 const T d1 = cellIt.getCorner(p1).getValue();
374 std::size_t pointId = 0;
375 if (std::abs(d0) <= std::abs(d1)) {
376 pointId = cellIt.getCorner(p0).getPointId();
378 pointId = cellIt.getCorner(p1).getPointId();
383 return {cc, pointId};
387 std::map<hrleIndex, unsigned> *nodes,
388 std::vector<unsigned> *newDataSourceIds) {
390 const unsigned p0 =
corner0[edge];
396 d += viennahrle::BitMaskToIndex<D>(p0);
398 if (nodes[dir].find(d) != nodes[dir].end()) {
400 return nodes[dir][d];
406 newDataSourceIds->push_back(lsPointId);
409 nodes[dir][d] = nodeId;
415 template <
int Dim = D>
416 std::enable_if_t<Dim == 3, void>
418 bool isHighFace,
unsigned faceNodeId,
419 std::map<hrleIndex, unsigned> *nodes,
423 hrleIndex neighborIdx = cellIt.getIndices();
429 if (neighborIdx < cellIt.getIndices()) {
432 for (
int i = 0; i < 8; ++i) {
433 hrleIndex cIdx = neighborIdx + viennahrle::BitMaskToIndex<D>(i);
434 if (!grid.isOutsideOfDomain(cIdx)) {
435 valueIt.goToIndices(cIdx);
436 if (valueIt.getValue() >= 0)
441 if (nSigns != 0 && nSigns != 255) {
443 int nFaceD = isHighFace ? 0 : 1;
445 for (; nTriangles[0] != -1; nTriangles += 3) {
446 std::vector<unsigned> face_edge_nodes;
447 for (
int i = 0; i < 3; ++i) {
448 int edge = nTriangles[i];
451 bool onFace = (((c0 >> axis) & 1) == nFaceD) &&
452 (((c1 >> axis) & 1) == nFaceD);
456 hrleIndex d = neighborIdx + viennahrle::BitMaskToIndex<D>(p0);
457 auto itN = nodes[dir].find(d);
458 if (itN != nodes[dir].end()) {
459 face_edge_nodes.push_back(itN->second);
463 if (face_edge_nodes.size() == 2) {
465 face_edge_nodes[0], face_edge_nodes[1], faceNodeId});
473 template <
int Dim = D>
474 std::enable_if_t<Dim == 2, bool>
476 Vec3D<T> &cornerPos)
const {
478 "Normal vector data must be computed for sharp corner generation.");
480 auto getTransformedGradient = [&](
int cornerID) {
481 auto corner = cellIt.getCorner(cornerID ^ transform);
482 if (corner.isDefined()) {
483 auto normal = (*normalVectorData)[corner.getPointId()];
485 if ((transform & 1) != 0)
486 normal[0] = -normal[0];
487 if ((transform & 2) != 0)
488 normal[1] = -normal[1];
494 Vec3D<T> norm1 = getTransformedGradient(1);
495 Vec3D<T> norm2 = getTransformedGradient(2);
497 if (std::abs(DotProduct(norm1, norm2)) >= 0.8) {
501 auto calculateNodePos = [&](
int edge) {
502 const unsigned p0 =
corner0[edge];
503 const unsigned p1 =
corner1[edge];
505 const T d0 = cellIt.getCorner(p0 ^ transform).getValue();
506 const T d1 = cellIt.getCorner(p1 ^ transform).getValue();
511 auto pX = calculateNodePos(0);
512 auto pY = calculateNodePos(3);
514 double d1 = DotProduct(norm1, pX);
515 double d2 = DotProduct(norm2, pY);
516 double det = norm1[0] * norm2[1] - norm1[1] * norm2[0];
518 if (std::abs(det) > 1e-6 && std::isfinite(det)) {
519 cornerPos[0] = (d1 * norm2[1] - d2 * norm1[1]) / det;
520 cornerPos[1] = (d2 * norm1[0] - d1 * norm2[0]) / det;
522 for (
int i = 0; i <
D; ++i)
523 cornerPos[i] = (pX[i] + pY[i]) *
T(0.5);
531 template <
int Dim = D>
534 int posMask, std::map<hrleIndex, unsigned> *nodes,
539 for (
int i = 0; i < 4; ++i)
540 if ((negMask >> i) & 1) {
544 }
else if (countPos == 1) {
545 for (
int i = 0; i < 4; ++i)
546 if ((posMask >> i) & 1) {
552 if (cornerIdx != -1) {
554 bool isSharedCorner =
false;
556 cellIt.getIndices() + viennahrle::BitMaskToIndex<D>(cornerIdx);
557 T pVal = cellIt.getCorner(cornerIdx).getValue();
560 for (
int i = 0; i < (1 <<
D); ++i) {
565 for (
int k = 0; k <
D; ++k)
566 neighborIndices[k] = pIdx[k] - ((i >> k) & 1);
568 bool neighborIsCorner =
true;
571 for (
int k = 0; k <
D; ++k) {
572 int neighborLocal = i ^ (1 << k);
574 neighborIndices + viennahrle::BitMaskToIndex<D>(neighborLocal);
575 if (grid.isOutsideOfDomain(checkIdx)) {
576 checkIdx = grid.globalIndices2LocalIndices(checkIdx);
578 valueIt.goToIndices(checkIdx);
579 T nVal = valueIt.getValue();
580 bool pSign = (pVal >= 0);
581 bool nSign = (nVal >= 0);
582 if (pSign == nSign) {
583 neighborIsCorner =
false;
588 if (neighborIsCorner) {
589 isSharedCorner =
true;
594 if (!isSharedCorner) {
595 Vec3D<T> cornerPos{};
600 if ((cornerIdx & 1) != 0)
601 cornerPos[0] =
T(1.0) - cornerPos[0];
602 if ((cornerIdx & 2) != 0)
603 cornerPos[1] =
T(1.0) - cornerPos[1];
606 for (
int i = 0; i <
D; ++i) {
607 cornerPos[i] = (cornerPos[i] + cellIt.getIndices(i));
611 int edgeX = -1, edgeY = -1;
612 if (cornerIdx == 0) {
615 }
else if (cornerIdx == 1) {
618 }
else if (cornerIdx == 2) {
621 }
else if (cornerIdx == 3) {
626 unsigned nX =
getNode(cellIt, edgeX, nodes, newDataSourceIds);
627 unsigned nY =
getNode(cellIt, edgeY, nodes, newDataSourceIds);
634 assert(!newDataSourceIds->empty());
635 newDataSourceIds->push_back(
636 newDataSourceIds->back());
649 bool inverted)
const {
651 auto corner = cellIt.getCorner(idx);
652 if (corner.isDefined()) {
653 Vec3D<T> n = (*normalVectorData)[corner.getPointId()];
655 for (
int i = 0; i < 3; ++i)
663 template <
int Dim = D>
666 int posMask, std::map<hrleIndex, unsigned> *nodes,
667 std::map<hrleIndex, unsigned> *faceNodes,
670 bool inverted =
false;
675 }
else if (countPos == 3) {
683 int C = -1, A = -1, B = -1;
684 for (
int i = 0; i < 8; ++i) {
685 if ((mask >> i) & 1) {
687 for (
int k = 0; k < 3; ++k) {
688 if ((mask >> (i ^ (1 << k))) & 1)
691 if (neighbors == 2) {
702 for (
int k = 0; k < 3; ++k) {
703 int n = C ^ (1 << k);
704 if ((mask >> n) & 1) {
713 "Normal vector data must be computed for sharp feature generation.");
717 while ((C ^ A) != (1 << axisA))
720 while ((C ^ B) != (1 << axisB))
722 int axisZ = 3 - axisA - axisB;
725 auto calculateFace = [&](
int axis,
int corner,
int n1,
726 int n2) -> std::optional<Vec3D<T>> {
728 if ((corner >> axis) & 1)
731 if (faceNodes[axis].find(faceIdx) != faceNodes[axis].end()) {
732 unsigned nodeId = faceNodes[axis][faceIdx];
733 Vec3D<T> pos =
mesh->nodes[nodeId];
734 for (
int d = 0; d < 3; ++d)
735 pos[d] = pos[d] - cellIt.getIndices(d);
739 Vec3D<T> N1 =
getNormal(n1, cellIt, inverted);
740 Vec3D<T> N2 =
getNormal(n2, cellIt, inverted);
742 if (std::abs(DotProduct(N1, N2)) >= 0.8)
745 int u = (axis + 1) % 3;
746 int v = (axis + 2) % 3;
749 while ((corner ^ n1) != (1 << axis1))
751 T t1 =
getInterp(corner, n1, cellIt, inverted);
754 while ((corner ^ n2) != (1 << axis2))
756 T t2 =
getInterp(corner, n2, cellIt, inverted);
759 P1[0] = ((corner >> 0) & 1);
760 P1[1] = ((corner >> 1) & 1);
761 P1[2] = ((corner >> 2) & 1);
762 P1[axis1] = ((corner >> axis1) & 1) ? (1.0 - t1) : t1;
765 P2[0] = ((corner >> 0) & 1);
766 P2[1] = ((corner >> 1) & 1);
767 P2[2] = ((corner >> 2) & 1);
768 P2[axis2] = ((corner >> axis2) & 1) ? (1.0 - t2) : t2;
770 double det = N1[u] * N2[v] - N1[v] * N2[u];
771 if (std::abs(det) < 1e-6)
774 double c1 = N1[u] * P1[u] + N1[v] * P1[v];
775 double c2 = N2[u] * P2[u] + N2[v] * P2[v];
779 P[u] = (c1 * N2[v] - c2 * N1[v]) / det;
780 P[v] = (c2 * N1[u] - c1 * N2[u]) / det;
782 if (Norm2(P - P1) > 9.0 || Norm2(P - P2) > 9.0)
788 auto commitFace = [&](
int axis,
int corner, Vec3D<T> P) ->
unsigned {
790 if ((corner >> axis) & 1)
793 if (faceNodes[axis].find(faceIdx) != faceNodes[axis].end()) {
794 return faceNodes[axis][faceIdx];
797 Vec3D<T> globalP = P;
798 for (
int d = 0; d < 3; ++d)
799 globalP[d] = (globalP[d] + cellIt.getIndices(d));
801 faceNodes[axis][faceIdx] = nodeId;
803 newDataSourceIds->push_back(cellIt.getCorner(corner).getPointId());
811 int D_corner = A ^ (1 << axisB);
812 int A_z = A ^ (1 << axisZ);
813 int B_z = B ^ (1 << axisZ);
814 int C_z = C ^ (1 << axisZ);
816 auto P_A_opt = calculateFace(axisA, A, D_corner, A_z);
817 auto P_B_opt = calculateFace(axisB, B, D_corner, B_z);
819 if (!P_A_opt.has_value() || !P_B_opt.has_value())
822 auto const &P_A = P_A_opt.value();
823 auto const &P_B = P_B_opt.value();
827 S[axisA] = P_B[axisA];
828 S[axisB] = P_A[axisB];
829 S[axisZ] = (P_A[axisZ] + P_B[axisZ]) * 0.5;
833 for (
int i = 0; i < 3; ++i)
834 gS[i] = (gS[i] + cellIt.getIndices(i));
838 newDataSourceIds->push_back(cellIt.getCorner(C).getPointId());
842 S_Face[axisZ] =
static_cast<T>((C >> axisZ) & 1);
845 auto faceIdxZ = cellIt.getIndices();
846 if ((C >> axisZ) & 1)
849 if (faceNodes[axisZ].find(faceIdxZ) != faceNodes[axisZ].end()) {
850 nS_Face = faceNodes[axisZ][faceIdxZ];
853 Vec3D<T> gS = S_Face;
854 for (
int i = 0; i < 3; ++i)
855 gS[i] = (gS[i] + cellIt.getIndices(i));
858 faceNodes[axisZ][faceIdxZ] = nS_Face;
860 newDataSourceIds->push_back(cellIt.getCorner(C).getPointId());
867 unsigned nNA = commitFace(axisA, A, P_A);
868 unsigned nNB = commitFace(axisB, B, P_B);
871 auto getEdgeNode = [&](
int v1,
int v2) {
873 for (
int e = 0; e < 12; ++e) {
874 if ((
corner0[e] ==
static_cast<unsigned>(v1) &&
875 corner1[e] ==
static_cast<unsigned>(v2)) ||
876 (
corner0[e] ==
static_cast<unsigned>(v2) &&
877 corner1[e] ==
static_cast<unsigned>(v1))) {
882 return this->
getNode(cellIt, edgeIdx, nodes, newDataSourceIds);
885 unsigned nI_AD = getEdgeNode(A, D_corner);
886 unsigned nI_AZ = getEdgeNode(A, A_z);
887 unsigned nI_BD = getEdgeNode(B, D_corner);
888 unsigned nI_BZ = getEdgeNode(B, B_z);
889 unsigned nI_CZ = getEdgeNode(C, C_z);
892 int parity = (C & 1) + ((C >> 1) & 1) + ((C >> 2) & 1);
893 bool flip = (parity % 2 != 0) ^ inverted;
896 while ((A ^ C) != (1 << vA))
899 while ((B ^ C) != (1 << vB))
901 bool is_cyclic = ((vA + 1) % 3 == vB);
904 std::swap(nI_AD, nI_BD);
905 std::swap(nI_AZ, nI_BZ);
933 template <
int Dim = D>
936 std::map<hrleIndex, unsigned> *nodes,
937 std::map<hrleIndex, unsigned> *faceNodes,
940 "Normal vector data must be computed for sharp edge generation.");
943 auto toCanonical = [&](Vec3D<T> v) {
959 res = Vec3D<T>{v[1], v[2], v[0]};
961 res = Vec3D<T>{v[2], v[0], v[1]};
966 auto fromCanonical = [&](Vec3D<T> v) {
972 res = Vec3D<T>{v[2], v[0], v[1]};
974 res = Vec3D<T>{v[1], v[2], v[0]};
977 res[0] =
T(1.0) - res[0];
979 res[1] =
T(1.0) - res[1];
981 res[2] =
T(1.0) - res[2];
987 unsigned faceNodeIds[2];
988 bool nodeExists[2] = {
false,
false};
991 auto mapIdx = [&](
int c) {
994 int x = (c & 1), y = (c >> 1) & 1, z = (c >> 2) & 1;
1000 }
else if (axis == 1) {
1018 return gx | (gy << 1) | (gz << 2);
1022 for (
int k = 0; k < 2; ++k) {
1029 hrleIndex faceIdx = cellIt.getIndices();
1033 bool isHighFace = (k == 1) ^ ((transform >> axis) & 1);
1037 auto it = faceNodes[axis].find(faceIdx);
1038 if (it != faceNodes[axis].end()) {
1039 nodeExists[k] =
true;
1040 faceNodeIds[k] = it->second;
1041 Vec3D<T> relPos =
mesh->nodes[faceNodeIds[k]];
1042 for (
int d = 0; d < 3; ++d) {
1043 relPos[d] -=
static_cast<T>(cellIt.getIndices(d));
1045 P[k] = toCanonical(relPos);
1061 Vec3D<T> n_y = toCanonical(
getNormal(c_y, cellIt, inverted));
1062 Vec3D<T> n_z = toCanonical(
getNormal(c_z, cellIt, inverted));
1064 if (std::abs(DotProduct(n_y, n_z)) >= 0.8) {
1072 T t_y =
getInterp(c0, c_y, cellIt, inverted);
1073 T t_z =
getInterp(c0, c_z, cellIt, inverted);
1083 double det = n_y[1] * n_z[2] - n_y[2] * n_z[1];
1084 if (std::abs(det) < 1e-6)
1087 double d1 = n_y[1] * t_y;
1088 double d2 = n_z[2] * t_z;
1090 double y = (d1 * n_z[2] - d2 * n_y[2]) / det;
1091 double z = (d2 * n_y[1] - d1 * n_z[1]) / det;
1093 P[k] = Vec3D<T>{(
T)k, (
T)y, (
T)z};
1097 if (Norm2(P[k] - Vec3D<T>{(
T)k, t_y, 0}) > 9.0 ||
1098 Norm2(P[k] - Vec3D<T>{(
T)k, 0, t_z}) > 9.0) {
1105 for (
int k = 0; k < 2; ++k) {
1106 if (!nodeExists[k]) {
1108 hrleIndex faceIdx = cellIt.getIndices();
1109 bool isHighFace = (k == 1) ^ ((transform >> axis) & 1);
1113 Vec3D<T> globalP = fromCanonical(P[k]);
1114 for (
int d = 0; d < 3; ++d)
1115 globalP[d] = (globalP[d] + cellIt.getIndices(d));
1118 faceNodes[axis][faceIdx] = faceNodeIds[k];
1120 newDataSourceIds->push_back(
1121 cellIt.getCorner(mapIdx(c0)).getPointId());
1136 auto getEdgeNode = [&](
int c1,
int c2) {
1138 int g1 = mapIdx(c1);
1139 int g2 = mapIdx(c2);
1143 for (
int e = 0; e < 12; ++e) {
1144 if ((
corner0[e] ==
static_cast<unsigned>(g1) &&
1145 corner1[e] ==
static_cast<unsigned>(g2)) ||
1146 (
corner0[e] ==
static_cast<unsigned>(g2) &&
1147 corner1[e] ==
static_cast<unsigned>(g1))) {
1152 return this->
getNode(cellIt, edgeIdx, nodes, newDataSourceIds);
1155 unsigned n02 = getEdgeNode(0, 2);
1156 unsigned n04 = getEdgeNode(0, 4);
1157 unsigned n13 = getEdgeNode(1, 3);
1158 unsigned n15 = getEdgeNode(1, 5);
1176 template <
int Dim = D>
1179 int posMask, std::map<hrleIndex, unsigned> *nodes,
1180 std::map<hrleIndex, unsigned> *faceNodes,
1183 bool inverted =
false;
1185 if (countNeg == 2) {
1188 }
else if (countPos == 2) {
1196 int v1 = -1, v2 = -1;
1197 for (
int i = 0; i < 8; ++i) {
1198 if ((mask >> i) & 1) {
1207 if ((diff & (diff - 1)) != 0)
1211 while ((diff >> (axis + 1)) > 0)
1218 nodes, faceNodes, newDataSourceIds,
1225 int transform,
bool inverted,
1226 std::map<hrleIndex, unsigned> *nodes,
1227 std::map<hrleIndex, unsigned> *faceNodes,
1228 std::vector<unsigned> *newDataSourceIds,
1230 Vec3D<T> &cornerPos) {
1232 "Normal vector data must be available for sharp corner generation");
1235 auto toCanonical = [&](Vec3D<T> v) {
1246 auto fromCanonical = [&](Vec3D<T> v) {
1248 v[0] =
T(1.0) - v[0];
1250 v[1] =
T(1.0) - v[1];
1252 v[2] =
T(1.0) - v[2];
1256 Vec3D<T> norm1, norm2, norm3;
1258 Vec3D<T> P1, P2, P4;
1260 const int g1 = transform ^ 1;
1261 const int g2 = transform ^ 2;
1262 const int g4 = transform ^ 4;
1264 norm1 = toCanonical(
getNormal(g1, cellIt, inverted));
1265 norm2 = toCanonical(
getNormal(g2, cellIt, inverted));
1266 norm3 = toCanonical(
getNormal(g4, cellIt, inverted));
1268 const T t1 =
getInterp(transform, g1, cellIt, inverted);
1269 const T t2 =
getInterp(transform, g2, cellIt, inverted);
1270 const T t4 =
getInterp(transform, g4, cellIt, inverted);
1276 d1 = DotProduct(norm1, P1);
1277 d2 = DotProduct(norm2, P2);
1278 d3 = DotProduct(norm3, P4);
1280 if (std::abs(DotProduct(norm1, norm2)) >= 0.8 ||
1281 std::abs(DotProduct(norm1, norm3)) >= 0.8 ||
1282 std::abs(DotProduct(norm2, norm3)) >= 0.8) {
1295 const Vec3D<T> c23 = CrossProduct(norm2, norm3);
1296 const Vec3D<T> c31 = CrossProduct(norm3, norm1);
1297 const Vec3D<T> c12 = CrossProduct(norm1, norm2);
1299 const double det = DotProduct(norm1, c23);
1304 const T invDet = 1.0 / det;
1306 for (
int i = 0; i < 3; ++i) {
1307 S[i] = (d1 * c23[i] + d2 * c31[i] + d3 * c12[i]) * invDet;
1310 if (Norm2(S - P1) > 9.0 || Norm2(S - P2) > 9.0 || Norm2(S - P4) > 9.0) {
1315 Vec3D<T> globalS = fromCanonical(S);
1316 for (
int d = 0; d < 3; ++d) {
1317 cornerPos[d] = (globalS[d] + cellIt.getIndices(d));
1325 template <
int Dim = D>
1328 int posMask, std::map<hrleIndex, unsigned> *nodes,
1329 std::map<hrleIndex, unsigned> &cornerNodes,
1330 std::map<hrleIndex, unsigned> *faceNodes,
1333 "Normal vector data must be available for sharp corner generation");
1335 bool inverted =
false;
1339 if (countNeg == 1) {
1341 while (!((negMask >> transform) & 1))
1344 }
else if (countPos == 1) {
1346 while (!((posMask >> transform) & 1))
1351 if (transform == -1)
1356 faceNodes, newDataSourceIds, valueIt,
1359 hrleIndex cornerIdx = cellIt.getIndices();
1360 cornerIdx += viennahrle::BitMaskToIndex<D>(transform);
1362 auto it = cornerNodes.find(cornerIdx);
1363 if (it != cornerNodes.end()) {
1364 nCorner = it->second;
1367 cornerNodes[cornerIdx] = nCorner;
1373 newDataSourceIds->push_back(cellIt.getCorner(transform).getPointId());
1377 auto getEdgeNode = [&](
int neighbor) {
1381 for (
int e = 0; e < 12; ++e) {
1382 if ((
corner0[e] ==
static_cast<unsigned>(v1) &&
1383 corner1[e] ==
static_cast<unsigned>(v2)) ||
1384 (
corner0[e] ==
static_cast<unsigned>(v2) &&
1385 corner1[e] ==
static_cast<unsigned>(v1))) {
1390 return this->
getNode(cellIt, edgeIdx, nodes, newDataSourceIds);
1393 unsigned n1 = getEdgeNode(transform ^ 1);
1394 unsigned n2 = getEdgeNode(transform ^ 2);
1395 unsigned n4 = getEdgeNode(transform ^ 4);
1400 auto toCanonical = [&](Vec3D<T> v) {
1410 auto fromCanonical = [&](Vec3D<T> v) {
1412 v[0] =
T(1.0) - v[0];
1414 v[1] =
T(1.0) - v[1];
1416 v[2] =
T(1.0) - v[2];
1420 Vec3D<T> norm1, norm2, norm3;
1424 int n1_idx = -1, n2_idx = -1, n3_idx = -1;
1425 int neighbors[] = {transform ^ 1, transform ^ 2, transform ^ 4};
1427 for (
int n_idx : neighbors) {
1428 T val = cellIt.getCorner(n_idx).getValue();
1430 if (val * cellIt.getCorner(transform).getValue() < 0) {
1441 norm1 = toCanonical(
getNormal(transform ^ 1, cellIt, inverted));
1442 norm2 = toCanonical(
getNormal(transform ^ 2, cellIt, inverted));
1443 norm3 = toCanonical(
getNormal(transform ^ 4, cellIt, inverted));
1445 d1 = norm1[0] *
getInterp(transform, transform ^ 1, cellIt, inverted);
1446 d2 = norm2[1] *
getInterp(transform, transform ^ 2, cellIt, inverted);
1447 d3 = norm3[2] *
getInterp(transform, transform ^ 4, cellIt, inverted);
1449 auto solve2x2 = [](
double a1,
double b1,
double c1,
double a2,
1450 double b2,
double c2,
T &res1,
T &res2) {
1451 double det = a1 * b2 - a2 * b1;
1452 if (std::abs(det) < 1e-6)
1454 res1 = (c1 * b2 - c2 * b1) / det;
1455 res2 = (a1 * c2 - a2 * c1) / det;
1459 Vec3D<T> Fx, Fy, Fz;
1465 valid &= solve2x2(norm2[1], norm2[2], d2 - norm2[0] * Fx[0], norm3[1],
1466 norm3[2], d3 - norm3[0] * Fx[0], Fx[1], Fx[2]);
1467 valid &= solve2x2(norm1[0], norm1[2], d1 - norm1[1] * Fy[1], norm3[0],
1468 norm3[2], d3 - norm3[1] * Fy[1], Fy[0], Fy[2]);
1469 valid &= solve2x2(norm1[0], norm1[1], d1 - norm1[2] * Fz[2], norm2[0],
1470 norm2[1], d2 - norm2[2] * Fz[2], Fz[0], Fz[1]);
1472 auto checkBounds = [](Vec3D<T> p) {
1473 return p[0] >= -1e-4 && p[0] <= 1.0 + 1e-4 && p[1] >= -1e-4 &&
1474 p[1] <= 1.0 + 1e-4 && p[2] >= -1e-4 && p[2] <= 1.0 + 1e-4;
1477 if (valid && checkBounds(Fx) && checkBounds(Fy) && checkBounds(Fz)) {
1478 auto getFaceNode = [&](
int axis, Vec3D<T> pos) {
1479 hrleIndex faceIdx = cellIt.getIndices();
1480 if ((transform >> axis) & 1)
1483 if (faceNodes[axis].find(faceIdx) != faceNodes[axis].end()) {
1484 return faceNodes[axis][faceIdx];
1486 Vec3D<T> globalPos = fromCanonical(pos);
1487 for (
int d = 0; d < 3; ++d)
1488 globalPos[d] = (globalPos[d] + cellIt.getIndices(d));
1490 faceNodes[axis][faceIdx] = nodeId;
1492 newDataSourceIds->push_back(
1493 cellIt.getCorner(transform).getPointId());
1499 unsigned nFx = getFaceNode(0, Fx);
1500 unsigned nFy = getFaceNode(1, Fy);
1501 unsigned nFz = getFaceNode(2, Fz);
1505 (transform & 1) + ((transform >> 1) & 1) + ((transform >> 2) & 1);
1508 bool flip = (parity % 2 != 0) ^ inverted;
1536 (transform & 1) + ((transform >> 1) & 1) + ((transform >> 2) & 1);
1539 bool flip = (parity % 2 != 0) ^ inverted;
1559 if constexpr (
D == 3) {
1560 return nodeNumbers[0] == nodeNumbers[1] ||
1561 nodeNumbers[0] == nodeNumbers[2] ||
1562 nodeNumbers[1] == nodeNumbers[2];
1564 return nodeNumbers[0] == nodeNumbers[1];
1569 if constexpr (
D == 2) {
1571 -(
mesh->nodes[nodeNumbers[1]][1] -
mesh->nodes[nodeNumbers[0]][1]),
1572 mesh->nodes[nodeNumbers[1]][0] -
mesh->nodes[nodeNumbers[0]][0],
1576 mesh->nodes[nodeNumbers[1]],
1577 mesh->nodes[nodeNumbers[2]]);
1582 const Vec3D<T> &nodeB,
1583 const Vec3D<T> &nodeC)
noexcept {
1584 return CrossProduct(nodeB - nodeA, nodeC - nodeA);
1588 bool inverted)
const {
1589 auto getValue = [&](
int idx) {
1590 T val = cellIt.getCorner(idx).getValue();
1591 return inverted ? -val : val;
1593 const T v_a = getValue(p_a);
1594 const T v_b = getValue(p_b);
1595 if (std::abs(v_a - v_b) <
epsilon)
1597 return v_a / (v_a - v_b);
1604 auto elementI3 = [](
const std::array<unsigned, D> &element) ->
I3 {
1605 if constexpr (
D == 2)
1606 return {(int)element[0], (
int)element[1], 0};
1608 return {(int)element[0], (
int)element[1], (int)element[2]};
1614 T n2 = DotProduct(normal, normal);
1616 mesh->insertNextElement(nodeNumbers);
1617 T invn =
T(1) / std::sqrt(n2);
1618 for (
int d = 0; d <
D; d++) {
1632 auto quantize = [
this](
const Vec3D<T> &p) ->
I3 {
1634 return {(int)std::llround(p[0] * inv), (int)std::llround(p[1] * inv),
1635 (int)std::llround(p[2] * inv)};
1641 auto nodeIdx = it->second;
1642 mesh->nodes[nodeIdx] = (
mesh->nodes[nodeIdx] + pos) *
T(0.5);
1648 unsigned newNodeId =
mesh->insertNextNode(pos);
1652 mesh->minimumExtent = Min(
mesh->minimumExtent, pos);
1653 mesh->maximumExtent = Max(
mesh->maximumExtent, pos);
constexpr int D
Definition Epitaxy.cpp:12
double T
Definition Epitaxy.cpp:13
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: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:21
SmartPointer< Mesh< T > > mesh
Definition lsToSurfaceMesh.hpp:35
ToSurfaceMesh(const SmartPointer< lsDomainType > passedLevelSet, SmartPointer< Mesh< T > > passedMesh, double mnd=0.05, double eps=1e-12)
Definition lsToSurfaceMesh.hpp:85
static constexpr unsigned int direction[12]
Definition lsToSurfaceMesh.hpp:78
std::enable_if_t< Dim==3, bool > generateSharpEdge3D(ConstSparseCellIterator &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:1177
unsigned getNode(const ConstSparseCellIterator &cellIt, int edge, std::map< hrleIndex, unsigned > *nodes, std::vector< unsigned > *newDataSourceIds)
Definition lsToSurfaceMesh.hpp:386
void setMesh(SmartPointer< Mesh< T > > passedMesh)
Definition lsToSurfaceMesh.hpp:96
Vec3D< T > interpWithOffset(const unsigned p0, const T d0, const T d1, const unsigned dir, const OffsetType &offset) const
Definition lsToSurfaceMesh.hpp:338
SmartPointer< lsDomainType > currentLevelSet
Definition lsToSurfaceMesh.hpp:68
std::enable_if_t< Dim==3, bool > generateCanonicalSharpEdge3D(ConstSparseCellIterator &cellIt, int transform, int axis, bool inverted, std::map< hrleIndex, unsigned > *nodes, std::map< hrleIndex, unsigned > *faceNodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:934
bool insertElement(const std::array< unsigned, D > &nodeNumbers)
Definition lsToSurfaceMesh.hpp:1600
std::enable_if_t< Dim==3, void > stitchToNeighbor(const ConstSparseCellIterator &cellIt, int axis, bool isHighFace, unsigned faceNodeId, std::map< hrleIndex, unsigned > *nodes, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:417
bool generateSharpCorners
Definition lsToSurfaceMesh.hpp:40
T getInterp(int p_a, int p_b, const ConstSparseCellIterator &cellIt, bool inverted) const
Definition lsToSurfaceMesh.hpp:1587
std::vector< SmartPointer< lsDomainType > > levelSets
Definition lsToSurfaceMesh.hpp:34
typename lsDomainType::DomainType hrleDomainType
Definition lsToSurfaceMesh.hpp:28
static bool triangleMisformed(const std::array< unsigned, D > &nodeNumbers) noexcept
Definition lsToSurfaceMesh.hpp:1558
Vec3D< T > getNormal(int idx, const ConstSparseCellIterator &cellIt, bool inverted) const
Definition lsToSurfaceMesh.hpp:648
std::enable_if_t< Dim==2, bool > generateSharpCorner2D(ConstSparseCellIterator &cellIt, int countNeg, int countPos, int negMask, int posMask, std::map< hrleIndex, unsigned > *nodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt)
Definition lsToSurfaceMesh.hpp:532
std::enable_if_t< Dim==2, bool > generateCanonicalSharpCorner2D(ConstSparseCellIterator &cellIt, int transform, Vec3D< T > &cornerPos) const
Definition lsToSurfaceMesh.hpp:475
std::unordered_map< I3, unsigned, I3Hash > nodeIdByBin
Definition lsToSurfaceMesh.hpp:63
const T epsilon
Definition lsToSurfaceMesh.hpp:37
viennals::Domain< T, D > lsDomainType
Definition lsToSurfaceMesh.hpp:27
viennahrle::ConstSparseIterator< hrleDomainType > ConstSparseIterator
Definition lsToSurfaceMesh.hpp:30
bool generateCanonicalSharpCorner3D(ConstSparseCellIterator &cellIt, int transform, bool inverted, std::map< hrleIndex, unsigned > *nodes, std::map< hrleIndex, unsigned > *faceNodes, std::vector< unsigned > *newDataSourceIds, ConstSparseIterator &valueIt, Vec3D< T > &cornerPos)
Definition lsToSurfaceMesh.hpp:1224
std::enable_if_t< Dim==3, bool > generateSharpL3D(ConstSparseCellIterator &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:664
viennahrle::ConstSparseCellIterator< hrleDomainType > ConstSparseCellIterator
Definition lsToSurfaceMesh.hpp:31
std::unordered_set< I3, I3Hash > uniqueElements
Definition lsToSurfaceMesh.hpp:64
void scaleMesh(const T gridDelta)
Definition lsToSurfaceMesh.hpp:328
std::vector< std::pair< unsigned, Vec3D< T > > > matSharpCornerNodes
Definition lsToSurfaceMesh.hpp:72
static constexpr unsigned int corner1[12]
Definition lsToSurfaceMesh.hpp:76
std::enable_if_t< Dim==3, bool > generateSharpCorner3D(ConstSparseCellIterator &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:1326
static Vec3D< T > calculateNormal(const Vec3D< T > &nodeA, const Vec3D< T > &nodeB, const Vec3D< T > &nodeC) noexcept
Definition lsToSurfaceMesh.hpp:1581
const double minNodeDistanceFactor
Definition lsToSurfaceMesh.hpp:38
void setUpdatePointData(bool update)
Definition lsToSurfaceMesh.hpp:98
ToSurfaceMesh(double mnd=0.05, double eps=1e-12)
Definition lsToSurfaceMesh.hpp:82
unsigned insertNode(Vec3D< T > const &pos)
Definition lsToSurfaceMesh.hpp:1631
viennahrle::Index< D > hrleIndex
Definition lsToSurfaceMesh.hpp:29
bool updatePointData
Definition lsToSurfaceMesh.hpp:39
std::tuple< Vec3D< T >, std::size_t > computeNodePosition(const ConstSparseCellIterator &cellIt, int edge) const
Definition lsToSurfaceMesh.hpp:367
PointData< T >::VectorDataType * normalVectorData
Definition lsToSurfaceMesh.hpp:69
std::vector< Vec3D< T > > currentNormals
Definition lsToSurfaceMesh.hpp:65
std::vector< T > currentMaterials
Definition lsToSurfaceMesh.hpp:66
void setSharpCorners(bool check)
Definition lsToSurfaceMesh.hpp:100
virtual void apply()
Definition lsToSurfaceMesh.hpp:102
T currentMaterialId
Definition lsToSurfaceMesh.hpp:67
void setLevelSet(SmartPointer< lsDomainType > passedlsDomain)
Definition lsToSurfaceMesh.hpp:91
Vec3D< T > calculateNormal(const std::array< unsigned, D > &nodeNumbers) const
Definition lsToSurfaceMesh.hpp:1568
static constexpr unsigned int corner0[12]
Definition lsToSurfaceMesh.hpp:74
#define PRECOMPILE_PRECISION_DIMENSION(className)
Definition lsPreCompileMacros.hpp:24
Definition lsAdvect.hpp:41
@ ONE_SIDED_MIN_MOD
Definition lsCalculateNormalVectors.hpp:22
Definition lsToSurfaceMesh.hpp:49
size_t operator()(const I3 &k) const
Definition lsToSurfaceMesh.hpp:50
Definition lsToSurfaceMesh.hpp:42
bool operator==(const I3 &o) const
Definition lsToSurfaceMesh.hpp:44
int x
Definition lsToSurfaceMesh.hpp:43
int y
Definition lsToSurfaceMesh.hpp:43
int z
Definition lsToSurfaceMesh.hpp:43