93 if (levelSets.empty()) {
95 .addError(
"No level set was passed to ToMultiSurfaceMesh.")
99 if (mesh ==
nullptr) {
100 Logger::getInstance()
101 .addError(
"No mesh was passed to ToMultiSurfaceMesh.")
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();
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};
117 typedef std::map<viennahrle::Index<D>,
unsigned> nodeContainerType;
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;
124 typename nodeContainerType::iterator nodeIt;
126 std::vector<Vec3D<T>> normals;
127 std::vector<T> materials;
129 const bool checkNodeFlag = minNodeDistanceFactor > 0;
130 const bool useMaterialMap = materialMap !=
nullptr;
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)};
138 auto elementI3 = [&](
const std::array<unsigned, D> &element) -> I3 {
139 if constexpr (
D == 2)
140 return {(int)element[0], (
int)element[1], 0};
142 return {(int)element[0], (
int)element[1], (int)element[2]};
146 std::vector<viennahrle::ConstSparseCellIterator<hrleDomainType>> cellIts;
147 for (
const auto &
ls : levelSets)
148 cellIts.emplace_back(
ls->getDomain());
150 for (
unsigned l = 0; l < levelSets.size(); l++) {
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());
161 for (
int i = 0; i < (1 <<
D); i++) {
162 if (cellIt.getCorner(i).getValue() >=
NumericType(0))
169 if (signs == (1 << (1 <<
D)) - 1)
173 const int *Triangles;
174 if constexpr (
D == 2) {
180 for (; Triangles[0] != -1; Triangles +=
D) {
181 std::array<unsigned, D> nod_numbers;
184 for (
int n = 0; n <
D; n++) {
185 const int edge = Triangles[n];
187 unsigned p0 = corner0[edge];
188 unsigned p1 = corner1[edge];
191 unsigned dir = direction[edge];
194 viennahrle::Index<D> d(cellIt.getIndices());
195 auto p0B = viennahrle::BitMaskToIndex<D>(p0);
198 nodeIt = nodes[dir].find(d);
199 if (nodeIt != nodes[dir].end()) {
200 nod_numbers[n] = nodeIt->second;
205 for (
int z = 0; z <
D; z++) {
209 cc[z] =
static_cast<T>(cellIt.getIndices(z) + p0B[z]);
211 auto d0 =
static_cast<T>(cellIt.getCorner(p0).getValue());
212 auto d1 =
static_cast<T>(cellIt.getCorner(p1).getValue());
216 cc[z] =
static_cast<T>(cellIt.getIndices(z)) + 0.5;
218 if (std::abs(d0) <= std::abs(d1)) {
219 cc[z] =
static_cast<T>(cellIt.getIndices(z)) +
222 cc[z] =
static_cast<T>(cellIt.getIndices(z) + 1) -
227 cc[z],
static_cast<T>(cellIt.getIndices(z) + epsilon));
230 static_cast<T>((cellIt.getIndices(z) + 1) - epsilon));
237 auto q = quantize(cc);
238 auto it = nodeIdByBin.find(q);
239 if (it != nodeIdByBin.end())
240 nodeIdx = it->second;
243 nod_numbers[n] = nodeIdx;
247 mesh->insertNextNode(cc);
248 nodes[dir][d] = nod_numbers[n];
250 nodeIdByBin.emplace(quantize(cc), nod_numbers[n]);
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];
263 if (!triangleMisformed(nod_numbers)) {
266 if (uniqueElements.insert(elementI3(nod_numbers)).second) {
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],
275 normal = calculateNormal(mesh->nodes[nod_numbers[0]],
276 mesh->nodes[nod_numbers[1]],
277 mesh->nodes[nod_numbers[2]]);
280 double n2 = normal[0] * normal[0] + normal[1] * normal[1] +
281 normal[2] * normal[2];
284 mesh->insertNextElement(nod_numbers);
287 T invn =
static_cast<T>(1.) / std::sqrt(
static_cast<T>(n2));
288 for (
int d = 0; d <
D; d++) {
291 normals.push_back(normal);
294 if (useMaterialMap) {
295 materials.push_back(materialMap->getMaterialId(l));
297 materials.push_back(
static_cast<T>(l));
306 mesh->cellData.insertNextScalarData(materials,
"MaterialIds");
307 mesh->cellData.insertNextVectorData(normals,
"Normals");
308 mesh->triangles.shrink_to_fit();
309 mesh->nodes.shrink_to_fit();