86 if (levelSets.empty()) {
88 .addError(
"No level set was passed to ToMultiSurfaceMesh.")
92 if (mesh ==
nullptr) {
94 .addError(
"No mesh was passed to ToMultiSurfaceMesh.")
100 const auto gridDelta = levelSets.front()->getGrid().getGridDelta();
101 for (
unsigned i = 0; i <
D; ++i) {
102 mesh->minimumExtent[i] = std::numeric_limits<NumericType>::max();
103 mesh->maximumExtent[i] = std::numeric_limits<NumericType>::lowest();
106 constexpr unsigned int corner0[12] = {0, 1, 2, 0, 4, 5, 6, 4, 0, 1, 3, 2};
107 constexpr unsigned int corner1[12] = {1, 3, 3, 2, 5, 7, 7, 6, 4, 5, 7, 6};
108 constexpr unsigned int direction[12] = {0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2};
110 typedef std::map<viennahrle::Index<D>,
unsigned> nodeContainerType;
112 nodeContainerType nodes[
D];
113 const double minNodeDistance = gridDelta * minNodeDistanceFactor;
114 std::unordered_map<I3, unsigned, I3Hash> nodeIdByBin;
115 std::unordered_set<I3, I3Hash> uniqueElements;
117 typename nodeContainerType::iterator nodeIt;
119 std::vector<Vec3D<T>> normals;
120 std::vector<T> materials;
122 const bool checkNodeFlag = minNodeDistanceFactor > 0;
123 const bool useMaterialMap = materialMap !=
nullptr;
125 auto quantize = [&](
const Vec3D<T> &p) -> I3 {
126 const T inv =
T(1) / minNodeDistance;
127 return {(int)std::llround(p[0] * inv), (int)std::llround(p[1] * inv),
128 (int)std::llround(p[2] * inv)};
131 auto elementI3 = [&](
const std::array<unsigned, D> &element) -> I3 {
132 if constexpr (
D == 2)
133 return {(int)element[0], (
int)element[1], 0};
135 return {(int)element[0], (
int)element[1], (int)element[2]};
139 std::vector<viennahrle::ConstSparseCellIterator<hrleDomainType>> cellIts;
140 for (
const auto &
ls : levelSets)
141 cellIts.emplace_back(
ls->getDomain());
143 for (
unsigned l = 0; l < levelSets.size(); l++) {
145 for (
auto cellIt = cellIts[l]; !cellIt.isFinished(); cellIt.next()) {
146 for (
int u = 0; u <
D; u++) {
147 while (!nodes[u].empty() &&
148 nodes[u].begin()->first <
149 viennahrle::Index<D>(cellIt.getIndices()))
150 nodes[u].erase(nodes[u].begin());
154 for (
int i = 0; i < (1 <<
D); i++) {
155 if (cellIt.getCorner(i).getValue() >=
NumericType(0))
162 if (signs == (1 << (1 <<
D)) - 1)
166 const int *Triangles;
167 if constexpr (
D == 2) {
173 for (; Triangles[0] != -1; Triangles +=
D) {
174 std::array<unsigned, D> nod_numbers;
177 for (
int n = 0; n <
D; n++) {
178 const int edge = Triangles[n];
180 unsigned p0 = corner0[edge];
181 unsigned p1 = corner1[edge];
184 unsigned dir = direction[edge];
187 viennahrle::Index<D> d(cellIt.getIndices());
188 auto p0B = viennahrle::BitMaskToIndex<D>(p0);
191 nodeIt = nodes[dir].find(d);
192 if (nodeIt != nodes[dir].end()) {
193 nod_numbers[n] = nodeIt->second;
198 for (
int z = 0; z <
D; z++) {
202 cc[z] =
static_cast<T>(cellIt.getIndices(z) + p0B[z]);
204 auto d0 =
static_cast<T>(cellIt.getCorner(p0).getValue());
205 auto d1 =
static_cast<T>(cellIt.getCorner(p1).getValue());
209 cc[z] =
static_cast<T>(cellIt.getIndices(z)) + 0.5;
211 if (std::abs(d0) <= std::abs(d1)) {
212 cc[z] =
static_cast<T>(cellIt.getIndices(z)) +
215 cc[z] =
static_cast<T>(cellIt.getIndices(z) + 1) -
220 cc[z],
static_cast<T>(cellIt.getIndices(z) + epsilon));
223 static_cast<T>((cellIt.getIndices(z) + 1) - epsilon));
230 auto q = quantize(cc);
231 auto it = nodeIdByBin.find(q);
232 if (it != nodeIdByBin.end())
233 nodeIdx = it->second;
236 nod_numbers[n] = nodeIdx;
240 mesh->insertNextNode(cc);
241 nodes[dir][d] = nod_numbers[n];
243 nodeIdByBin.emplace(quantize(cc), nod_numbers[n]);
245 for (
int a = 0; a <
D; a++) {
246 if (cc[a] < mesh->minimumExtent[a])
247 mesh->minimumExtent[a] = cc[a];
248 if (cc[a] > mesh->maximumExtent[a])
249 mesh->maximumExtent[a] = cc[a];
256 if (!triangleMisformed(nod_numbers)) {
259 if (uniqueElements.insert(elementI3(nod_numbers)).second) {
261 if constexpr (
D == 2) {
262 normal = Vec3D<T>{-(mesh->nodes[nod_numbers[1]][1] -
263 mesh->nodes[nod_numbers[0]][1]),
264 mesh->nodes[nod_numbers[1]][0] -
265 mesh->nodes[nod_numbers[0]][0],
268 normal = calculateNormal(mesh->nodes[nod_numbers[0]],
269 mesh->nodes[nod_numbers[1]],
270 mesh->nodes[nod_numbers[2]]);
273 double n2 = normal[0] * normal[0] + normal[1] * normal[1] +
274 normal[2] * normal[2];
277 mesh->insertNextElement(nod_numbers);
280 T invn =
static_cast<T>(1.) / std::sqrt(
static_cast<T>(n2));
281 for (
int d = 0; d <
D; d++) {
284 normals.push_back(normal);
287 if (useMaterialMap) {
288 materials.push_back(materialMap->getMaterialId(l));
290 materials.push_back(
static_cast<T>(l));
299 mesh->cellData.insertNextScalarData(materials,
"MaterialIds");
300 mesh->cellData.insertNextVectorData(normals,
"Normals");
301 mesh->triangles.shrink_to_fit();
302 mesh->nodes.shrink_to_fit();