32 enum struct GeometryEnum :
unsigned {
40 SmartPointer<Domain<T, D>> levelSet;
41 GeometryEnum geometry = GeometryEnum::SPHERE;
42 SmartPointer<Sphere<T, D>> sphere;
43 SmartPointer<Plane<T, D>> plane;
44 SmartPointer<Box<T, D>> box;
45 SmartPointer<Cylinder<T, D>> cylinder;
46 SmartPointer<PointCloud<T, D>> pointCloud;
47 const double numericEps = 1e-9;
49 std::array<bool, 3> ignoreBoundaryConditions{
false,
false,
false};
55 : levelSet(passedLevelSet) {}
59 : levelSet(passedLevelSet), sphere(passedSphere) {
60 geometry = GeometryEnum::SPHERE;
65 : levelSet(passedLevelSet), plane(passedPlane) {
66 geometry = GeometryEnum::PLANE;
71 : levelSet(passedLevelSet), box(passedBox) {
72 geometry = GeometryEnum::BOX;
77 : levelSet(passedLevelSet), cylinder(passedCylinder) {
78 geometry = GeometryEnum::CYLINDER;
83 : levelSet(passedLevelSet), pointCloud(passedPointCloud) {
84 geometry = GeometryEnum::CUSTOM;
88 levelSet = passedlsDomain;
93 sphere = passedSphere;
94 geometry = GeometryEnum::SPHERE;
100 geometry = GeometryEnum::PLANE;
106 geometry = GeometryEnum::BOX;
111 cylinder = passedCylinder;
112 geometry = GeometryEnum::CYLINDER;
118 if (passedPointCloud && passedPointCloud->empty()) {
119 VIENNACORE_LOG_WARNING(
"Passing an empty point cloud to MakeGeometry. ");
121 pointCloud = passedPointCloud;
122 geometry = GeometryEnum::CUSTOM;
128 for (
unsigned i = 0; i <
D; ++i) {
129 ignoreBoundaryConditions[i] = passedIgnoreBoundaryConditions;
136 template <std::
size_t N>
138 std::array<bool, N> passedIgnoreBoundaryConditions) {
139 for (
unsigned i = 0; i <
D && i < N; ++i) {
140 ignoreBoundaryConditions[i] = passedIgnoreBoundaryConditions[i];
145 if (levelSet ==
nullptr) {
146 Logger::getInstance()
147 .addError(
"No level set was passed to MakeGeometry.")
153 case GeometryEnum::SPHERE:
154 makeSphere(sphere->origin, sphere->radius);
156 case GeometryEnum::PLANE:
157 makePlane(plane->origin, plane->normal);
159 case GeometryEnum::BOX:
160 makeBox(box->minCorner, box->maxCorner);
162 case GeometryEnum::CYLINDER:
163 makeCylinder(cylinder);
165 case GeometryEnum::CUSTOM:
166 makeCustom(pointCloud);
169 Logger::getInstance()
170 .addError(
"Invalid geometry type was specified for MakeGeometry. "
171 "Not creating geometry.")
177 void makeSphere(VectorType<T, D> origin,
T radius) {
179 auto &grid = levelSet->getGrid();
180 viennahrle::CoordType gridDelta = grid.getGridDelta();
183 viennahrle::Index<D> index;
184 viennahrle::Index<D> endIndex;
186 for (
unsigned i = 0; i <
D; ++i) {
187 index[i] = (origin[i] - radius) / gridDelta - 1;
188 endIndex[i] = (origin[i] + radius) / gridDelta + 1;
191 constexpr double initialWidth = 2.;
192 const T valueLimit = initialWidth * 0.5 * gridDelta + 1e-5;
193 const T radius2 = radius * radius;
195 pointDataType pointData;
196 const viennahrle::Index<D> minIndex = index;
198 while (index < endIndex) {
200 T distance = std::numeric_limits<T>::max();
201 for (
unsigned i = 0; i <
D; ++i) {
202 T y = (index[(i + 1) %
D] * gridDelta) - origin[(i + 1) %
D];
204 if constexpr (
D == 3)
205 z = (index[(i + 2) %
D] * gridDelta) - origin[(i + 2) %
D];
206 T x = radius2 - y * y - z * z;
210 std::abs((index[i] * gridDelta) - origin[i]) - std::sqrt(x);
211 if (std::abs(dirRadius) < std::abs(distance))
212 distance = dirRadius;
215 if (std::abs(distance) <= valueLimit) {
216 pointData.push_back(std::make_pair(index, distance / gridDelta));
219 for (; dim <
D - 1; ++dim) {
220 if (index[dim] < endIndex[dim])
222 index[dim] = minIndex[dim];
229 for (
unsigned i = 0; i < pointData.size(); ++i) {
230 for (
unsigned j = 0; j <
D; ++j) {
231 if (!ignoreBoundaryConditions[j] && grid.isBoundaryPeriodic(j)) {
232 pointData[i].first[j] =
233 grid.globalIndex2LocalIndex(j, pointData[i].first[j]);
238 levelSet->insertPoints(pointData);
239 levelSet->getDomain().segment();
240 levelSet->finalize(initialWidth);
245 void makePlane(VectorType<T, D> origin,
246 VectorType<T, D>
const &passedNormal) {
247 auto &grid = levelSet->getGrid();
248 viennahrle::CoordType
gridDelta = grid.getGridDelta();
252 VectorType<T, D> normal = passedNormal;
253 for (
unsigned i = 0; i <
D; ++i) {
254 modulus += normal[i] * normal[i];
256 modulus = std::sqrt(modulus);
257 for (
unsigned i = 0; i <
D; ++i) {
258 normal[i] /= modulus;
263 bool infDimSet =
false;
264 for (
unsigned n = 0; n <
D; ++n) {
265 if (grid.getBoundaryConditions(n) ==
266 viennahrle::BoundaryType::INFINITE_BOUNDARY) {
271 Logger::getInstance().addError(
272 "Planes can only be created with one Infinite Boundary "
273 "Condition. More than one found!");
278 Logger::getInstance().addError(
"Planes require exactly one Infinite "
279 "Boundary Condition. None found!");
282 if (passedNormal[i] == 0.) {
283 Logger::getInstance().addError(
284 "MakeGeometry: Plane cannot be parallel to Infinite Boundary "
290 std::vector<Vec3D<T>> cornerPoints;
291 cornerPoints.resize(2 * (
D - 1));
294 unsigned j = (i + 1) %
D;
295 unsigned k = (i + 2) %
D;
304 for (
unsigned n = 0; n <
D - 1; ++n) {
305 minCoord[n] =
gridDelta * (grid.getMinIndex((i + n + 1) %
D) - 1);
306 maxCoord[n] =
gridDelta * (grid.getMaxIndex((i + n + 1) %
D) + 1);
310 cornerPoints[0][j] = minCoord[0];
311 cornerPoints[1][j] = maxCoord[0];
313 if constexpr (
D == 3) {
314 cornerPoints[0][k] = minCoord[1];
315 cornerPoints[1][k] = maxCoord[1];
317 cornerPoints[2][j] = minCoord[0];
318 cornerPoints[2][k] = maxCoord[1];
319 cornerPoints[3][j] = maxCoord[0];
320 cornerPoints[3][k] = minCoord[1];
324 auto mesh = SmartPointer<Mesh<T>>::New();
326 for (
unsigned n = 0; n < cornerPoints.size(); ++n) {
327 double numerator = (cornerPoints[n][j] -
origin[j]) * normal[j];
328 if constexpr (
D == 3)
329 numerator += (cornerPoints[n][k] - origin[k]) * normal[k];
331 cornerPoints[n][2] = 0.;
332 cornerPoints[n][i] =
origin[i] - numerator / normal[i];
333 mesh->insertNextNode(cornerPoints[n]);
337 std::array<unsigned, 2> line = {0, 1};
339 std::swap(line[0], line[1]);
340 mesh->insertNextLine(line);
342 std::array<unsigned, 3> triangle = {0, 1, 2};
344 std::swap(triangle[0], triangle[1]);
345 mesh->insertNextTriangle(triangle);
346 triangle = {0, 3, 1};
348 std::swap(triangle[0], triangle[1]);
349 mesh->insertNextTriangle(triangle);
353 static unsigned planeCounter = 0;
354 VTKWriter<T>(mesh,
"plane" + std::to_string(planeCounter++) +
".vtk")
359 FromSurfaceMesh<T, D>(levelSet, mesh).apply();
363 void makeBox(VectorType<T, D> minCorner, VectorType<T, D> maxCorner) {
365 std::vector<Vec3D<T>> corners;
366 corners.resize(std::pow(2,
D), Vec3D<T>{0, 0, 0});
369 for (
unsigned i = 0; i <
D; ++i)
370 corners[0][i] = minCorner[i];
373 for (
unsigned i = 0; i <
D; ++i)
377 corners[1] = corners[0];
378 corners[1][0] = corners.back()[0];
380 corners[2] = corners[0];
381 corners[2][1] = corners.back()[1];
383 if constexpr (
D == 3) {
384 corners[3] = corners.back();
385 corners[3][2] = corners[0][2];
387 corners[4] = corners[0];
388 corners[4][2] = corners.back()[2];
390 corners[5] = corners.back();
391 corners[5][1] = corners[0][1];
393 corners[6] = corners.back();
394 corners[6][0] = corners[0][0];
399 for (
unsigned i = 0; i < corners.size(); ++i) {
400 mesh->insertNextNode(corners[i]);
404 std::array<unsigned, 2> lines[4] = {{0, 2}, {2, 3}, {3, 1}, {1, 0}};
405 for (
auto &line : lines)
406 mesh->insertNextLine(line);
408 std::array<unsigned, 3> triangles[12] = {
409 {0, 3, 1}, {0, 2, 3}, {0, 1, 5}, {0, 5, 4}, {0, 4, 2}, {4, 6, 2},
410 {7, 6, 4}, {7, 4, 5}, {7, 2, 6}, {7, 3, 2}, {1, 3, 5}, {3, 7, 5}};
411 for (
auto &triangle : triangles)
412 mesh->insertNextTriangle(triangle);
416 FromSurfaceMesh<T, D> mesher(levelSet, mesh);
417 mesher.setRemoveBoundaryTriangles(ignoreBoundaryConditions);
421 void makeCylinder(SmartPointer<Cylinder<T, D>> cylinder) {
422 if constexpr (
D == 3) {
426 auto gridDelta = levelSet->getGrid().getGridDelta();
429 const unsigned numPoints =
430 std::ceil(2 * M_PI * cylinder->radius / gridDelta);
431 const double smallAngle = 2.0 * M_PI /
static_cast<double>(numPoints);
435 mesh->insertNextNode(Vec3D<T>{0.0, 0.0, 0.0});
437 constexpr double limit = 2 * M_PI - 1e-6;
438 std::vector<Vec3D<T>> points;
439 if (cylinder->topRadius)
440 std::vector<Vec3D<T>> pointsTop;
443 for (
double angle = 0.; angle < limit; angle += smallAngle) {
445 point[0] = cylinder->radius * std::cos(angle);
446 point[1] = cylinder->radius * std::sin(angle);
447 points.push_back(point);
448 mesh->insertNextNode(point);
452 mesh->insertNextNode(Vec3D<T>{0.0, 0.0, cylinder->height});
455 for (
unsigned i = 0; i < numPoints; ++i) {
457 std::array<unsigned, 3> triangle{};
458 triangle[0] = (i + 1) % numPoints + 1;
461 mesh->insertNextTriangle(triangle);
466 if (cylinder->topRadius) {
467 points[i][0] = cylinder->topRadius * std::cos(angle);
468 points[i][1] = cylinder->topRadius * std::sin(angle);
471 points[i][2] = cylinder->height;
472 mesh->insertNextNode(points[i]);
475 triangle[0] = numPoints + 1;
476 triangle[1] = numPoints + i + 2;
477 triangle[2] = (i + 1) % numPoints + 2 + numPoints;
478 mesh->insertNextTriangle(triangle);
482 for (
unsigned i = 0; i < numPoints; ++i) {
483 std::array<unsigned, 3> triangle{};
485 triangle[1] = (i + 1) % numPoints + 1;
486 triangle[2] = i + numPoints + 2;
487 mesh->insertNextTriangle(triangle);
489 triangle[0] = (i + 1) % numPoints + 1;
490 triangle[1] = (i + 1) % numPoints + 2 + numPoints;
491 triangle[2] = i + numPoints + 2;
492 mesh->insertNextTriangle(triangle);
499 DotProduct(cylinder->axisDirection, cylinder->axisDirection));
500 Vec3D<T> cylinderAxis;
501 for (
int i = 0; i < 3; ++i) {
502 cylinderAxis[i] = cylinder->axisDirection[i] / unit;
505 Vec3D<T> rotAxis = {-cylinderAxis[1], cylinderAxis[0], 0.0};
507 T rotationAngle = std::acos(cylinderAxis[2]);
514 Vec3D<T> translationVector;
515 for (
int i = 0; i < 3; ++i) {
516 translationVector[i] = cylinder->origin[i];
522 FromSurfaceMesh<T, D> mesher(levelSet, mesh);
523 mesher.setRemoveBoundaryTriangles(ignoreBoundaryConditions);
525 }
else if constexpr (
D == 2) {
526 VIENNACORE_LOG_WARNING(
527 "MakeGeometry: Cylinder in 2D creates a box, not a cylinder.");
533 for (
unsigned i = 0; i <
D; ++i)
534 axisLen += cylinder->axisDirection[i] * cylinder->axisDirection[i];
535 axisLen = std::sqrt(axisLen);
539 T axis[2] = {cylinder->axisDirection[0] / axisLen,
540 cylinder->axisDirection[1] / axisLen};
541 T perp[2] = {axis[1], -axis[0]};
544 (cylinder->topRadius != 0.) ? cylinder->topRadius : cylinder->radius;
547 std::array<Vec3D<T>, 4> corners;
550 corners[0][0] = cylinder->origin[0] + cylinder->radius * perp[0];
551 corners[0][1] = cylinder->origin[1] + cylinder->radius * perp[1];
555 corners[1][0] = cylinder->origin[0] + cylinder->height * axis[0] +
557 corners[1][1] = cylinder->origin[1] + cylinder->height * axis[1] +
562 corners[2][0] = cylinder->origin[0] + cylinder->height * axis[0] -
564 corners[2][1] = cylinder->origin[1] + cylinder->height * axis[1] -
569 corners[3][0] = cylinder->origin[0] - cylinder->radius * perp[0];
570 corners[3][1] = cylinder->origin[1] - cylinder->radius * perp[1];
573 for (
const auto &p : corners) {
574 mesh->insertNextNode(p);
577 mesh->insertNextLine({0, 1});
578 mesh->insertNextLine({1, 2});
579 mesh->insertNextLine({2, 3});
580 mesh->insertNextLine({3, 0});
582 FromSurfaceMesh<T, D> mesher(levelSet, mesh);
583 mesher.setRemoveBoundaryTriangles(ignoreBoundaryConditions);
588 void makeCustom(SmartPointer<PointCloud<T, D>> pointCloud) {
591 ConvexHull<T, D>(mesh, pointCloud).apply();
594 FromSurfaceMesh<T, D> mesher(levelSet, mesh);
595 mesher.setRemoveBoundaryTriangles(ignoreBoundaryConditions);