From 29d8be8035a68b5ce283f47ccdbd706dd3c7cc28 Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Sun, 1 May 2022 20:00:47 +0200 Subject: [PATCH 1/7] Fix if-else formatting --- .clang-format | 2 +- Examples/AMReX_DCEL/main.cpp | 18 ++++++++----- Examples/AMReX_Shapes/main.cpp | 27 ++++++++++++------- Examples/Chombo3_DCEL/main.cpp | 18 ++++++++----- Examples/Chombo3_Shapes/main.cpp | 27 ++++++++++++------- Examples/EBGeometry_DCEL/main.cpp | 3 ++- .../EBGeometry_AnalyticDistanceFunctions.hpp | 11 +++++--- Source/EBGeometry_BVHImplem.hpp | 18 ++++++++----- Source/EBGeometry_DCEL_EdgeImplem.hpp | 6 +++-- Source/EBGeometry_DCEL_FaceImplem.hpp | 11 ++++---- Source/EBGeometry_DCEL_MeshImplem.hpp | 27 ++++++++++++------- Source/EBGeometry_DCEL_Polygon2DImplem.hpp | 3 ++- Source/EBGeometry_DCEL_VertexImplem.hpp | 6 +++-- Source/EBGeometry_ParserImplem.hpp | 3 ++- Source/EBGeometry_Polygon2DImplem.hpp | 3 ++- Source/EBGeometry_VecImplem.hpp | 6 +++-- 16 files changed, 124 insertions(+), 65 deletions(-) diff --git a/.clang-format b/.clang-format index b73290a5..37888105 100644 --- a/.clang-format +++ b/.clang-format @@ -31,7 +31,7 @@ BraceWrapping: AfterStruct: true AfterUnion: false BeforeCatch: false - BeforeElse: false + BeforeElse: true IndentBraces: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom diff --git a/Examples/AMReX_DCEL/main.cpp b/Examples/AMReX_DCEL/main.cpp index 4dbd2c50..17d884b9 100644 --- a/Examples/AMReX_DCEL/main.cpp +++ b/Examples/AMReX_DCEL/main.cpp @@ -131,23 +131,29 @@ main(int argc, char* argv[]) if (which_geom == 0) { // Airfoil case rb = RealBox({-100, -100, -75}, {400, 100, 125}); filename = "../PLY/airfoil.ply"; - } else if (which_geom == 1) { // Sphere case + } + else if (which_geom == 1) { // Sphere case rb = RealBox({-400, -400, -400}, {400, 400, 400}); filename = "../PLY/sphere.ply"; - } else if (which_geom == 2) { // Dodecahedron + } + else if (which_geom == 2) { // Dodecahedron rb = RealBox({-2., -2., -2.}, {2., 2., 2.}); filename = "../PLY/dodecahedron.ply"; - } else if (which_geom == 3) { // Horse + } + else if (which_geom == 3) { // Horse rb = RealBox({-0.12, -0.12, -0.12}, {0.12, 0.12, 0.12}); filename = "../PLY/horse.ply"; - } else if (which_geom == 4) { // Car + } + else if (which_geom == 4) { // Car // rb = RealBox({-20,-20,-20}, {20,20,20}); // Doesn't work. rb = RealBox({-10, -5, -5}, {10, 5, 5}); // Works. filename = "../PLY/porsche.ply"; - } else if (which_geom == 5) { // Orion + } + else if (which_geom == 5) { // Orion rb = RealBox({-10, -5, -10}, {10, 10, 10}); filename = "../PLY/orion.ply"; - } else if (which_geom == 6) { // Armadillo + } + else if (which_geom == 6) { // Armadillo rb = RealBox({-100, -75, -100}, {100, 125, 100}); filename = "../PLY/armadillo.ply"; } diff --git a/Examples/AMReX_Shapes/main.cpp b/Examples/AMReX_Shapes/main.cpp index 1716bb6f..d5ad9bc2 100644 --- a/Examples/AMReX_Shapes/main.cpp +++ b/Examples/AMReX_Shapes/main.cpp @@ -90,40 +90,49 @@ main(int argc, char* argv[]) if (whichGeom == 0) { // Sphere. rb = RealBox({-1, -1, -1}, {1, 1, 1}); func = std::make_shared>(Vec3::zero(), T(0.5), false); - } else if (whichGeom == 1) { // Plane. + } + else if (whichGeom == 1) { // Plane. rb = RealBox({-1, -1, -1}, {1, 1, 1}); func = std::make_shared>(Vec3::zero(), Vec3::one(), false); - } else if (whichGeom == 2) { // Infinite cylinder. + } + else if (whichGeom == 2) { // Infinite cylinder. rb = RealBox({-1, -1, -1}, {1, 1, 1}); func = std::make_shared>(Vec3::zero(), T(0.1), 2, false); - } else if (whichGeom == 3) { // Finite cylinder. + } + else if (whichGeom == 3) { // Finite cylinder. rb = RealBox({-2, -2, -2}, {2, 2, 2}); func = std::make_shared>(-Vec3::one(), Vec3::one(), 0.25, false); - } else if (whichGeom == 4) { // Capsule. + } + else if (whichGeom == 4) { // Capsule. rb = RealBox({-2, -2, -2}, {2, 2, 2}); func = std::make_shared>(-Vec3::one(), Vec3::one(), 0.25, false); - } else if (whichGeom == 5) { // Box. + } + else if (whichGeom == 5) { // Box. rb = RealBox({-2, -2, -2}, {2, 2, 2}); func = std::make_shared>(-Vec3::one(), Vec3::one(), false); - } else if (whichGeom == 6) { // Rounded box. + } + else if (whichGeom == 6) { // Rounded box. rb = RealBox({-2, -2, -2}, {2, 2, 2}); auto box = std::make_shared>(-Vec3::one(), Vec3::one(), false); func = std::make_shared>(box, 0.25); - } else if (whichGeom == 7) { // Torus. + } + else if (whichGeom == 7) { // Torus. rb = RealBox({-2, -2, -2}, {2, 2, 2}); func = std::make_shared>(Vec3::zero(), 1.0, 0.25, false); - } else if (whichGeom == 8) { // Infinite cone. + } + else if (whichGeom == 8) { // Infinite cone. rb = RealBox({-2, -2, -2}, {2, 2, 2}); func = std::make_shared>(Vec3(0.0, 0.0, 1.0), 30.0, false); - } else if (whichGeom == 9) { // Finite cone. + } + else if (whichGeom == 9) { // Finite cone. rb = RealBox({-2, -2, -2}, {2, 2, 2}); func = std::make_shared>(Vec3(0.0, 0.0, 1.0), 2.0, 30, false); diff --git a/Examples/Chombo3_DCEL/main.cpp b/Examples/Chombo3_DCEL/main.cpp index bb6c3582..9c05e00c 100644 --- a/Examples/Chombo3_DCEL/main.cpp +++ b/Examples/Chombo3_DCEL/main.cpp @@ -104,32 +104,38 @@ main(int argc, char* argv[]) hiCorner = 250 * RealVect::Unit; filename = "../PLY/airfoil.ply"; - } else if (whichGeom == 1) { // Sphere + } + else if (whichGeom == 1) { // Sphere loCorner = -400 * RealVect::Unit; hiCorner = 400 * RealVect::Unit; filename = "../PLY/sphere.ply"; - } else if (whichGeom == 2) { // Dodecahedron + } + else if (whichGeom == 2) { // Dodecahedron loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; filename = "../PLY/dodecahedron.ply"; - } else if (whichGeom == 3) { // Horse + } + else if (whichGeom == 3) { // Horse loCorner = -0.12 * RealVect::Unit; hiCorner = 0.12 * RealVect::Unit; filename = "../PLY/horse.ply"; - } else if (whichGeom == 4) { // Porsche + } + else if (whichGeom == 4) { // Porsche loCorner = -10 * RealVect::Unit; hiCorner = 10 * RealVect::Unit; filename = "../PLY/porsche.ply"; - } else if (whichGeom == 5) { // Orion + } + else if (whichGeom == 5) { // Orion loCorner = -10 * RealVect::Unit; hiCorner = 10 * RealVect::Unit; filename = "../PLY/orion.ply"; - } else if (whichGeom == 6) { // Armadillo + } + else if (whichGeom == 6) { // Armadillo loCorner = -125 * RealVect::Unit; hiCorner = 125 * RealVect::Unit; diff --git a/Examples/Chombo3_Shapes/main.cpp b/Examples/Chombo3_Shapes/main.cpp index 38643fd3..e61ceb8a 100644 --- a/Examples/Chombo3_Shapes/main.cpp +++ b/Examples/Chombo3_Shapes/main.cpp @@ -80,48 +80,57 @@ main(int argc, char* argv[]) hiCorner = RealVect::Unit; sdf = std::make_shared>(Vec3::zero(), T(0.5), false); - } else if (whichGeom == 1) { // Plane. + } + else if (whichGeom == 1) { // Plane. loCorner = -RealVect::Unit; hiCorner = RealVect::Unit; sdf = std::make_shared>(Vec3::zero(), Vec3::one(), false); - } else if (whichGeom == 2) { // Infinite cylinder. + } + else if (whichGeom == 2) { // Infinite cylinder. loCorner = -RealVect::Unit; hiCorner = RealVect::Unit; sdf = std::make_shared>(Vec3::zero(), T(0.1), 2, false); - } else if (whichGeom == 3) { // Finite cylinder. + } + else if (whichGeom == 3) { // Finite cylinder. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; sdf = std::make_shared>(-Vec3::one(), Vec3::one(), 0.25, false); - } else if (whichGeom == 4) { // Capsule. + } + else if (whichGeom == 4) { // Capsule. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; sdf = std::make_shared>(-Vec3::one(), Vec3::one(), 0.25, false); - } else if (whichGeom == 5) { // Box. + } + else if (whichGeom == 5) { // Box. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; sdf = std::make_shared>(-Vec3::one(), Vec3::one(), false); - } else if (whichGeom == 6) { // Rounded box. + } + else if (whichGeom == 6) { // Rounded box. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; auto box = std::make_shared>(-Vec3::one(), Vec3::one(), false); sdf = std::make_shared>(box, 0.25); - } else if (whichGeom == 7) { // Torus. + } + else if (whichGeom == 7) { // Torus. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; sdf = std::make_shared>(Vec3::zero(), 1.0, 0.25, false); - } else if (whichGeom == 8) { // Infinite cone. + } + else if (whichGeom == 8) { // Infinite cone. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; sdf = std::make_shared>(Vec3(0.0, 0.0, 1.0), 30.0, false); - } else if (whichGeom == 9) { // Finite cone. + } + else if (whichGeom == 9) { // Finite cone. loCorner = -2 * RealVect::Unit; hiCorner = 2 * RealVect::Unit; diff --git a/Examples/EBGeometry_DCEL/main.cpp b/Examples/EBGeometry_DCEL/main.cpp index 246d0124..504214cb 100644 --- a/Examples/EBGeometry_DCEL/main.cpp +++ b/Examples/EBGeometry_DCEL/main.cpp @@ -28,7 +28,8 @@ main(int argc, char* argv[]) // Read the input file. if (argc == 2) { file = "../PLY/" + std::string(argv[1]); - } else { + } + else { std::cerr << "Missing file name. Use ./a.out 'filename' where 'filename' " "is one of the files in ../PLY\n"; } diff --git a/Source/EBGeometry_AnalyticDistanceFunctions.hpp b/Source/EBGeometry_AnalyticDistanceFunctions.hpp index f3fd7d4b..41e48c72 100644 --- a/Source/EBGeometry_AnalyticDistanceFunctions.hpp +++ b/Source/EBGeometry_AnalyticDistanceFunctions.hpp @@ -687,12 +687,15 @@ class CylinderSDF : public SignedDistanceFunction if (w <= zero && h <= zero) { // Inside cylinder d = (std::abs(w) < std::abs(h)) ? w : h; - } else if (w <= zero && h > zero) { // Above one of the endcaps. + } + else if (w <= zero && h > zero) { // Above one of the endcaps. d = h; - } else if (w > zero && h < zero) { // Outside radius but between the - // endcaps. + } + else if (w > zero && h < zero) { // Outside radius but between the + // endcaps. d = w; - } else { + } + else { d = sqrt(w * w + h * h); } } diff --git a/Source/EBGeometry_BVHImplem.hpp b/Source/EBGeometry_BVHImplem.hpp index c39f889d..3ec50871 100644 --- a/Source/EBGeometry_BVHImplem.hpp +++ b/Source/EBGeometry_BVHImplem.hpp @@ -249,7 +249,8 @@ NodeT::pruneStack(const Vec3& a_point) const noexcept if (std::abs(primDist) < std::abs(minDist)) { minDist = primDist; } - } else { + } + else { // If it's a regular node, sort the child nodes and put them on the // stack. On the next iteration we do the closest node first. This // sorting is critical to the performance of the BVH. @@ -300,7 +301,8 @@ NodeT::pruneOrdered(T& a_shortestDistanceSoFar, const Vec3& a_point if (std::abs(primDist) < std::abs(a_shortestDistanceSoFar)) { a_shortestDistanceSoFar = primDist; } - } else { + } + else { // In this case we need to decide which subtree to move down. First, sort // the children nodes by the distance between a_point and the children // node's bounding volume. Shortest distance goes first. @@ -327,7 +329,8 @@ NodeT::pruneOrdered(T& a_shortestDistanceSoFar, const Vec3& a_point // value here. if (std::abs(curChildNode.first) <= std::abs(a_shortestDistanceSoFar)) { curChildNode.second->pruneOrdered(a_shortestDistanceSoFar, a_point); - } else { // Prune the rest of the children nodes. + } + else { // Prune the rest of the children nodes. break; } } @@ -346,7 +349,8 @@ NodeT::pruneUnordered(T& a_shortestDistanceSoFar, const Vec3& a_poi if (std::abs(curSignedDistance) < std::abs(a_shortestDistanceSoFar)) { a_shortestDistanceSoFar = curSignedDistance; } - } else { + } + else { // Investigate subtrees. Prune subtrees if the distance to their bounding // volumes are longer than the shortest distance we've found so far. for (const auto& child : m_children) { @@ -407,7 +411,8 @@ NodeT::flattenTree( a_linearNodes[curNode]->setPrimitivesOffset(a_sortedPrimitives.size()); a_sortedPrimitives.insert(a_sortedPrimitives.end(), m_primitives.begin(), m_primitives.end()); - } else { + } + else { a_linearNodes[curNode]->setNumPrimitives(0); a_linearNodes[curNode]->setPrimitivesOffset(0UL); @@ -598,7 +603,8 @@ LinearBVH::signedDistance(const Vec3& a_point) const noexcept if (std::abs(primDist) < std::abs(minDist)) { minDist = primDist; } - } else { + } + else { // Compute child indices and their BVH distance to a_point. for (size_t k = 0; k < K; k++) { const size_t& curOff = m_linearNodes[curNode]->getChildOffsets()[k]; diff --git a/Source/EBGeometry_DCEL_EdgeImplem.hpp b/Source/EBGeometry_DCEL_EdgeImplem.hpp index 945801ee..a88f54ad 100644 --- a/Source/EBGeometry_DCEL_EdgeImplem.hpp +++ b/Source/EBGeometry_DCEL_EdgeImplem.hpp @@ -269,9 +269,11 @@ EdgeT::signedDistance(const Vec3& a_x0) const noexcept T retval; if (t <= 0.0) { // Closest point is the starting vertex retval = this->getVertex()->signedDistance(a_x0); - } else if (t >= 1.0) { // Closest point is the end vertex + } + else if (t >= 1.0) { // Closest point is the end vertex retval = this->getOtherVertex()->signedDistance(a_x0); - } else { // Closest point is the edge itself. + } + else { // Closest point is the edge itself. const Vec3 linePoint = m_vertex->getPosition() + t * m_x2x1; const Vec3 delta = a_x0 - linePoint; const T dot = m_normal.dot(delta); diff --git a/Source/EBGeometry_DCEL_FaceImplem.hpp b/Source/EBGeometry_DCEL_FaceImplem.hpp index 889ec188..57cffaa0 100644 --- a/Source/EBGeometry_DCEL_FaceImplem.hpp +++ b/Source/EBGeometry_DCEL_FaceImplem.hpp @@ -147,8 +147,9 @@ FaceT::computeNormal() noexcept m_normal = (x2 - x1).cross(x2 - x0); - if (m_normal.length() > 0.0) + if (m_normal.length() > 0.0) { break; // Found one. + } } this->normalizeNormalVector(); @@ -158,8 +159,6 @@ template inline void FaceT::computePolygon2D() noexcept { - - // See CD_DCELPoly.H to see how the 2D embedding operates. m_poly2 = std::make_shared>(m_normal, this->getAllVertexCoordinates()); } @@ -318,7 +317,8 @@ FaceT::signedDistance(const Vec3& a_x0) const noexcept if (inside) { // Projects to inside so distance and sign are straightforward // to compute. retval = m_normal.dot(a_x0 - m_centroid); - } else { + } + else { for (const auto& e : m_edges) { // Projects to outside so edge/vertex are // closest. Check that distance. const T curDist = e->signedDistance(a_x0); @@ -343,7 +343,8 @@ FaceT::unsignedDistance2(const Vec3& a_x0) const noexcept const T normDist = m_normal.dot(a_x0 - m_centroid); retval = normDist * normDist; - } else { + } + else { for (const auto& e : m_edges) { // Projects to outside so edge/vertex are closest. const T curDist2 = e->unsignedDistance2(a_x0); diff --git a/Source/EBGeometry_DCEL_MeshImplem.hpp b/Source/EBGeometry_DCEL_MeshImplem.hpp index c0cbb612..357cc385 100644 --- a/Source/EBGeometry_DCEL_MeshImplem.hpp +++ b/Source/EBGeometry_DCEL_MeshImplem.hpp @@ -108,7 +108,8 @@ MeshT::sanityCheck() const noexcept if (f == nullptr) { incrementWarning(warnings, f_null); - } else if (halfEdge == nullptr) { + } + else if (halfEdge == nullptr) { incrementWarning(warnings, f_noEdge); } if (!noDuplicates) { @@ -126,24 +127,31 @@ MeshT::sanityCheck() const noexcept // Check basic points for current edge. if (e == nullptr) { incrementWarning(warnings, e_null); - } else if (e->getVertex() == e->getOtherVertex()) { + } + else if (e->getVertex() == e->getOtherVertex()) { incrementWarning(warnings, e_degenerate); - } else if (pairEdge == nullptr) { + } + else if (pairEdge == nullptr) { incrementWarning(warnings, e_noPairEdge); - } else if (nextEdge == nullptr) { + } + else if (nextEdge == nullptr) { incrementWarning(warnings, e_noNextEdge); - } else if (prevEdge == nullptr) { + } + else if (prevEdge == nullptr) { incrementWarning(warnings, e_noPrevEdge); - } else if (curVertex == nullptr) { + } + else if (curVertex == nullptr) { incrementWarning(warnings, e_noOrigVert); - } else if (curFace == nullptr) { + } + else if (curFace == nullptr) { incrementWarning(warnings, e_noFace); } // Check that the next edge's previous edge is this edge. if (prevEdge->getNextEdge() != e) { incrementWarning(warnings, e_noPrevNext); - } else if (nextEdge->getPreviousEdge() != e) { + } + else if (nextEdge->getPreviousEdge() != e) { incrementWarning(warnings, e_noNextPrev); } } @@ -152,7 +160,8 @@ MeshT::sanityCheck() const noexcept for (const auto& v : m_vertices) { if (v == nullptr) { incrementWarning(warnings, v_null); - } else if (v->getOutgoingEdge() == nullptr) { + } + else if (v->getOutgoingEdge() == nullptr) { incrementWarning(warnings, v_noEdge); } } diff --git a/Source/EBGeometry_DCEL_Polygon2DImplem.hpp b/Source/EBGeometry_DCEL_Polygon2DImplem.hpp index 702c815d..47d9c248 100644 --- a/Source/EBGeometry_DCEL_Polygon2DImplem.hpp +++ b/Source/EBGeometry_DCEL_Polygon2DImplem.hpp @@ -115,7 +115,8 @@ Polygon2D::computeWindingNumber(const Vec2& P) const noexcept if (P2.y > P.y) // an upward crossing if (res > 0.) // P left of edge ++wn; // have a valid up intersect - } else { // start y > P.y (no test needed) + } + else { // start y > P.y (no test needed) if (P2.y <= P.y) // a downward crossing if (res < 0.) // P right of edge --wn; // have a valid down intersect diff --git a/Source/EBGeometry_DCEL_VertexImplem.hpp b/Source/EBGeometry_DCEL_VertexImplem.hpp index 7dddf7e2..108d9572 100644 --- a/Source/EBGeometry_DCEL_VertexImplem.hpp +++ b/Source/EBGeometry_DCEL_VertexImplem.hpp @@ -173,9 +173,11 @@ VertexT::computeVertexNormalAngleWeighted(const std::vector& a_faces if (v1 == originVertex || v2 == originVertex) { if (v1 == originVertex) { inoutVertices.emplace_back(v2); - } else if (v2 == originVertex) { + } + else if (v2 == originVertex) { inoutVertices.emplace_back(v1); - } else { + } + else { std::cerr << "In file 'CD_DCELVertexImplem.H' function " "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; } diff --git a/Source/EBGeometry_ParserImplem.hpp b/Source/EBGeometry_ParserImplem.hpp index 753a456f..a66c1b15 100644 --- a/Source/EBGeometry_ParserImplem.hpp +++ b/Source/EBGeometry_ParserImplem.hpp @@ -66,7 +66,8 @@ Parser::PLY::readIntoDCEL(Mesh& a_mesh, const std::string a_filename) filestream.close(); a_mesh.reconcile(EBGeometry::DCEL::MeshT::VertexNormalWeight::Angle); - } else { + } + else { const std::string error = "Parser::PLY::readIntoDCEL - ERROR! Could not open file " + a_filename; std::cerr << error + "\n"; } diff --git a/Source/EBGeometry_Polygon2DImplem.hpp b/Source/EBGeometry_Polygon2DImplem.hpp index e2d11dba..2dd12fa1 100644 --- a/Source/EBGeometry_Polygon2DImplem.hpp +++ b/Source/EBGeometry_Polygon2DImplem.hpp @@ -113,7 +113,8 @@ Polygon2D::computeWindingNumber(const Vec2& P) const noexcept if (P2.y > P.y) // an upward crossing if (res > 0.) // P left of edge ++wn; // have a valid up intersect - } else { // start y > P.y (no test needed) + } + else { // start y > P.y (no test needed) if (P2.y <= P.y) // a downward crossing if (res < 0.) // P right of edge --wn; // have a valid down intersect diff --git a/Source/EBGeometry_VecImplem.hpp b/Source/EBGeometry_VecImplem.hpp index 156652e8..09c711fe 100644 --- a/Source/EBGeometry_VecImplem.hpp +++ b/Source/EBGeometry_VecImplem.hpp @@ -421,7 +421,8 @@ Vec3T::minDir(const bool a_doAbs) const noexcept if (std::abs(X[dir]) < std::abs(X[mDir])) { mDir = dir; } - } else { + } + else { if (X[dir] < X[mDir]) { mDir = dir; } @@ -442,7 +443,8 @@ Vec3T::maxDir(const bool a_doAbs) const noexcept if (std::abs(X[dir]) > std::abs(X[mDir])) { mDir = dir; } - } else { + } + else { if (X[dir] > X[mDir]) { mDir = dir; } From 11dce566df6d7d586f218a64e2c21d644024adca Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Sun, 1 May 2022 20:01:25 +0200 Subject: [PATCH 2/7] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index de2ff886..dfd7991b 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Contributing ``` git checkout main git pull - git checkout -b my_feature + git checkout -b my_branch ``` 2. Develop the feature. @@ -96,7 +96,7 @@ Contributing 5. Push the changes to GitHub ``` - git push --set-upstream my_feature + git push --set-upstream origin my_branch ``` 6. Create a pull request and make sure the GitHub continuous integration tests pass. From 867d11652dcb6a771a9f92fd9d72946073fdd1ba Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Sun, 1 May 2022 20:54:14 +0200 Subject: [PATCH 3/7] Work docs a bit --- Sphinx/source/ImplemBVH.rst | 90 +++++++++++++++++++++++++------- Sphinx/source/Implementation.rst | 2 +- Sphinx/source/Introduction.rst | 24 ++++++--- Sphinx/source/index.rst | 5 +- 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/Sphinx/source/ImplemBVH.rst b/Sphinx/source/ImplemBVH.rst index d3846077..f234796c 100644 --- a/Sphinx/source/ImplemBVH.rst +++ b/Sphinx/source/ImplemBVH.rst @@ -28,11 +28,17 @@ The above template parameters are: Importantly, ``NodeT`` is the BVH builder node, i.e. it is the class through which we recursively build the BVH, see :ref:`Chap:BVHConstruction`. The compact BVH is discussed below in :ref:`Chap:LinearBVH`. -For getting the signed distance, ``NodeT`` has provides the following function: +For getting the signed distance, ``NodeT`` has provide the following functions: -.. literalinclude:: ../../Source/EBGeometry_BVH.hpp - :language: c++ - :lines: 112-115,220-221,330 +.. code-block:: c++ + + inline T + signedDistance(const Vec3T& a_point) const noexcept override; + + inline T + signedDistance(const Vec3T& a_point, const Prune a_pruning) const noexcept; + +The first version simply calls the other version with a stack-based pruning algorithm for the tree traversal. .. _Chap:BVHConstraints: @@ -163,9 +169,31 @@ Although seemingly complicated, the input arguments are simply polymorphic funct The function takes an list of primitives which it partitions into ``K`` new list of primitives, i.e. it encapsulates :eq:`Partition`. As an example, we include a partitioner that is provided for integrating BVH and DCEL functionality. - .. literalinclude:: ../../Source/EBGeometry_DcelBVH.hpp - :language: c++ - :lines: 100-121 + .. code-block:: c++ + + template + EBGeometry::BVH::PartitionerT, BV, K> chunkPartitioner = + [](const PrimitiveList& a_primitives) -> std::array, K> { + Vec3T lo = Vec3T::max(); + Vec3T hi = -Vec3T::max(); + for (const auto& p : a_primitives) { + lo = min(lo, p->getCentroid()); + hi = max(hi, p->getCentroid()); + } + + const size_t splitDir = (hi - lo).maxDir(true); + + // Sort the primitives along the above coordinate direction. + PrimitiveList sortedPrimitives(a_primitives); + + std::sort( + sortedPrimitives.begin(), sortedPrimitives.end(), + [splitDir](const std::shared_ptr>& f1, const std::shared_ptr>& f2) -> bool { + return f1->getCentroid(splitDir) < f2->getCentroid(splitDir); + }); + + return EBGeometry::DCEL::equalCounts(sortedPrimitives); + }; In the above, we are taking a list of DCEL facets in the input argument (``PrimitiveList`` expands to ``std::vector >``). We then compute the centroid locations of each facet and figure out along which coordinate axis we partition the objects (called ``splitDir`` above). @@ -199,9 +227,10 @@ To encapsulate the compact BVH we provide two classes: * ``LinearNodeT`` which encapsulates a node, but rather than storing the primitives and pointers to child nodes it stores offsets along the 1D arrays. Just like ``NodeT`` the class is templated: - .. literalinclude:: ../../Source/EBGeometry_BVH.hpp - :language: c++ - :lines: 352-354, 473 + .. code-block:: c++ + + template + class LinearNodeT ``LinearNodeT`` has a smaller memory footprint and should fit in one CPU word in floating-point precision and two CPU words in double point precision. The performance benefits of further memory alignment have not been investigated. @@ -219,9 +248,18 @@ To encapsulate the compact BVH we provide two classes: * ``LinearBVH`` which stores the compact BVH *and* primitives as class members. That is, ``LinearBVH`` contains the nodes and primitives as class members. - .. literalinclude:: ../../Source/EBGeometry_BVH.hpp - :language: c++ - :lines: 477-480,529-533,537,544 + .. code-block:: c++ + + template + class LinearBVH : public SignedDistanceFunction + { + public: + + protected: + + std::vector>> m_linearNodes; + std::vector> m_primitives; + }; The root node is, of course, found at the front of the ``m_linearNodes`` vector. Note that the list of primitives ``m_primitives`` is stored in the order in which the leaf nodes appear in ``m_linearNodes``. @@ -229,9 +267,16 @@ To encapsulate the compact BVH we provide two classes: Constructing the compact BVH is simply a matter of letting ``NodeT`` aggregate the nodes and primitives into arrays, and return a ``LinearBVH``. This is done by calling the ``NodeT`` member function ``flattenTree()``: -.. literalinclude:: ../../Source/EBGeometry_BVH.hpp - :language: c++ - :lines: 112-114,236-237,329 +.. code-block:: c++ + + template + class NodeT : public SignedDistanceFunction + { + public: + + inline std::shared_ptr> + flattenTree() const noexcept; + }; which returns a pointer to a ``LinearBVH``. For example: @@ -255,9 +300,16 @@ For example: Note that the primitives live in ``LinearBVH`` and not ``LinearNodeT``, and the signed distance function is therefore implemented in the ``LinearBVH`` member function: -.. literalinclude:: ../../Source/EBGeometry_BVH.hpp - :language: c++ - :lines: 477-479, 529-530, 544 +.. code-block:: c++ + + template + class LinearBVH : public SignedDistanceFunction + { + public: + + inline T + signedDistance(const Vec3& a_point) const noexcept override; + }; Signed distance --------------- diff --git a/Sphinx/source/Implementation.rst b/Sphinx/source/Implementation.rst index 90d3e443..8a5958be 100644 --- a/Sphinx/source/Implementation.rst +++ b/Sphinx/source/Implementation.rst @@ -5,7 +5,7 @@ Overview Here, we consider the basic EBGeometry API. EBGeometry is a header-only library, implemented under it's own namespace ``EBGeometry``. -Various major components, like BVHs and DCEL, are implemented under namespaces ``EBGeometry::BVH`` and ``EBGeometry::Dcel``. +Various major components, like BVHs and DCEL, are implemented under namespaces ``EBGeometry::BVH`` and ``EBGeometry::DCEL``. Below, we consider a brief introduction to the API and implementation details of EBGeometry. diff --git a/Sphinx/source/Introduction.rst b/Sphinx/source/Introduction.rst index c925a2f1..572a2062 100644 --- a/Sphinx/source/Introduction.rst +++ b/Sphinx/source/Introduction.rst @@ -7,7 +7,6 @@ Requirements ============ * A C++ compiler which supports C++14. -* An analytic signed distance function, or a watertight and orientable surface grid. Quickstart ========== @@ -18,14 +17,23 @@ To obtained EBGeometry, clone the code from `github `_. - A separate Doxygen-generated API of EBGeometry is available `here `_. + A separate Doxygen-generated API of EBGeometry is `available here `_. .. This is for getting rid of the TOC in html view. .. raw:: html From fd9573659182778030d2a37e1718fd839e6fff2f Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Sun, 1 May 2022 21:18:55 +0200 Subject: [PATCH 4/7] Update documentation --- Examples/AMReX_DCEL/main.cpp | 178 +++++++++++++++--------------- Sphinx/source/Example_AMReX.rst | 14 +-- Sphinx/source/Example_Chombo3.rst | 26 +++-- Sphinx/source/ImplemDCEL.rst | 152 ++++++++++++------------- Sphinx/source/ImplemSDF.rst | 67 +++++------ Sphinx/source/ImplemUnion.rst | 8 +- Sphinx/source/Parsers.rst | 35 ++++++ Sphinx/source/index.rst | 3 +- 8 files changed, 263 insertions(+), 220 deletions(-) create mode 100644 Sphinx/source/Parsers.rst diff --git a/Examples/AMReX_DCEL/main.cpp b/Examples/AMReX_DCEL/main.cpp index 17d884b9..ffc185f0 100644 --- a/Examples/AMReX_DCEL/main.cpp +++ b/Examples/AMReX_DCEL/main.cpp @@ -16,95 +16,95 @@ using namespace amrex; namespace amrex { -namespace EB2 { - -/*! - @brief This is an AMReX-capable version of the EBGeometry BVH accelerator. It - is templated as T, BV, K which indicate the EBGeometry precision, bounding - volume, and tree degree. -*/ -template -class SignedDistanceBVH -{ -public: - /*! -@brief Alias for builder node, for encapsulating a "standard" BVH node - */ - using BuilderNode = EBGeometry::BVH::NodeT, BV, K>; - - /*! -@brief Alias for linearized BVH node - */ - using LinearNode = EBGeometry::BVH::LinearBVH, BV, K>; - - /*! -@brief Alias for always-3D vector - */ - using Vec3 = EBGeometry::Vec3T; - - /*! -@brief Full constructor. -@param[in] a_filename File name. Must be a PLY file and will be parser by the -PLY parser. -@param[in] a_flipSign Hook for swapping inside/outside. - */ - SignedDistanceBVH(const std::string a_filename, const bool a_flipSign) - { - - // 1. Read mesh from file. - auto mesh = EBGeometry::Parser::PLY::readIntoDCEL(a_filename); - - // 2. Create a standard BVH hierarchy. This is not a compact ree. - auto root = std::make_shared(mesh->getFaces()); - root->topDownSortAndPartitionPrimitives( - EBGeometry::DCEL::defaultBVConstructor, EBGeometry::DCEL::defaultPartitioner, - EBGeometry::DCEL::defaultStopFunction); - - // 3. Flatten the tree onto a tighter memory representation. - m_rootNode = root->flattenTree(); - } - - /*! -@brief Copy constructor. -@param[in] a_other Other SDF. - */ - SignedDistanceBVH(const SignedDistanceBVH& a_other) - { - this->m_rootNode = a_other.m_rootNode; - this->m_flipSign = a_other.m_flipSign; - } - - /*! -@brief AMReX's implicit function definition. - */ - Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept - { - const Real sign = (m_flipSign) ? -1.0 : 1.0; - - return sign * m_rootNode->signedDistance(Vec3(x, y, z)); - }; - - /*! -@brief Also an AMReX implicit function implementation - */ - inline Real - operator()(const RealArray& p) const noexcept - { - return this->operator()(AMREX_D_DECL(p[0], p[1], p[2])); - } - -protected: - /*! -@brief Root node of the linearized BVH hierarchy. - */ - std::shared_ptr m_rootNode; - - /*! -@brief Hook for flipping the sign - */ - bool m_flipSign; -}; -} // namespace EB2 + namespace EB2 { + + /*! + @brief This is an AMReX-capable version of the EBGeometry BVH accelerator. It + is templated as T, BV, K which indicate the EBGeometry precision, bounding + volume, and tree degree. + */ + template + class SignedDistanceBVH + { + public: + /*! + @brief Alias for builder node, for encapsulating a "standard" BVH node + */ + using BuilderNode = EBGeometry::BVH::NodeT, BV, K>; + + /*! + @brief Alias for linearized BVH node + */ + using LinearNode = EBGeometry::BVH::LinearBVH, BV, K>; + + /*! + @brief Alias for always-3D vector + */ + using Vec3 = EBGeometry::Vec3T; + + /*! + @brief Full constructor. + @param[in] a_filename File name. Must be a PLY file and will be parser by the + PLY parser. + @param[in] a_flipSign Hook for swapping inside/outside. + */ + SignedDistanceBVH(const std::string a_filename, const bool a_flipSign) + { + + // 1. Read mesh from file. + auto mesh = EBGeometry::Parser::PLY::readIntoDCEL(a_filename); + + // 2. Create a standard BVH hierarchy. This is not a compact ree. + auto root = std::make_shared(mesh->getFaces()); + root->topDownSortAndPartitionPrimitives( + EBGeometry::DCEL::defaultBVConstructor, EBGeometry::DCEL::defaultPartitioner, + EBGeometry::DCEL::defaultStopFunction); + + // 3. Flatten the tree onto a tighter memory representation. + m_rootNode = root->flattenTree(); + } + + /*! + @brief Copy constructor. + @param[in] a_other Other SDF. + */ + SignedDistanceBVH(const SignedDistanceBVH& a_other) + { + this->m_rootNode = a_other.m_rootNode; + this->m_flipSign = a_other.m_flipSign; + } + + /*! + @brief AMReX's implicit function definition. + */ + Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept + { + const Real sign = (m_flipSign) ? -1.0 : 1.0; + + return sign * m_rootNode->signedDistance(Vec3(x, y, z)); + }; + + /*! + @brief Also an AMReX implicit function implementation + */ + inline Real + operator()(const RealArray& p) const noexcept + { + return this->operator()(AMREX_D_DECL(p[0], p[1], p[2])); + } + + protected: + /*! + @brief Root node of the linearized BVH hierarchy. + */ + std::shared_ptr m_rootNode; + + /*! + @brief Hook for flipping the sign + */ + bool m_flipSign; + }; + } // namespace EB2 } // namespace amrex int diff --git a/Sphinx/source/Example_AMReX.rst b/Sphinx/source/Example_AMReX.rst index 51f014bf..80af6db0 100644 --- a/Sphinx/source/Example_AMReX.rst +++ b/Sphinx/source/Example_AMReX.rst @@ -9,17 +9,11 @@ We will focus on the following parts of the code: .. literalinclude:: ../../Examples/AMReX_DCEL/main.cpp :language: c++ - :lines: 18-28, 32,37,42-43,49-63, 76-81, 85-88, 101-102 Constructing the BVH -------------------- -When constructing the signed distance function we use the DCEL and BVH functionality directly in the constructor: - -.. literalinclude:: ../../Examples/AMReX_DCEL/main.cpp - :language: c++ - :lines: 49,52,55,56-58,61-62 - +When constructing the signed distance function we use the DCEL and BVH functionality directly in the constructor. Note that we are performing the following steps: * Using the PLY parser for creating a DCEL mesh. @@ -31,8 +25,8 @@ Exposing signed distance functions Next, we expose the signed distance function to AMReX by implementing the functions -.. literalinclude:: ../../Examples/AMReX_DCEL/main.cpp - :language: c++ - :lines: 76-81, 85-87 +.. code-block:: c++ + + Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept Note that the AMReX ``DECL`` macros expand to ``(Real x, Real y)`` in 2D, but here we assume that the user has compiled for 3D. diff --git a/Sphinx/source/Example_Chombo3.rst b/Sphinx/source/Example_Chombo3.rst index 60557a21..62c4156e 100644 --- a/Sphinx/source/Example_Chombo3.rst +++ b/Sphinx/source/Example_Chombo3.rst @@ -9,17 +9,11 @@ We will focus on the following parts of the code: .. literalinclude:: ../../Examples/Chombo3_DCEL/main.cpp :language: c++ - :lines: 22-25, 29-30, 34-35, 38,40,43-46,49,50, 55-64, 73 Constructing the BVH -------------------- -When constructing the signed distance function we use the DCEL and BVH functionality directly in the constructor: - -.. literalinclude:: ../../Examples/Chombo3_DCEL/main.cpp - :language: c++ - :lines: 38-50 - +When constructing the signed distance function we use the DCEL and BVH functionality directly in the constructor. Note that we are performing the following steps: * Using the PLY parser for creating a DCEL mesh. @@ -31,8 +25,20 @@ Exposing signed distance functions Next, we expose the signed distance function to Chombo3 by implementing the functions -.. literalinclude:: ../../Examples/Chombo3_DCEL/main.cpp - :language: c++ - :lines: 56-64 +.. code-block:: c++ + + Real + value(const RealVect& a_point) const override final + { + #if CH_SPACEDIM == 2 + Vec3 p(a_point[0], a_point[1], 0.0); + #else + Vec3 p(a_point[0], a_point[1], a_point[2]); + #endif + + return Real(m_rootNode->signedDistance(p)); + } + + Note that because Chombo3 can be compiled in either 2D or 3D, we put a Chombo preprocessor flag ``CH_SPACEDIM`` in order to translate the Chombo ``RealVect`` to EBGeometry's inherent 3D vector structure. diff --git a/Sphinx/source/ImplemDCEL.rst b/Sphinx/source/ImplemDCEL.rst index 3e3ae68b..786f970f 100644 --- a/Sphinx/source/ImplemDCEL.rst +++ b/Sphinx/source/ImplemDCEL.rst @@ -3,7 +3,7 @@ DCEL ==== -The DCEL functionality exists under the namespace ``EBGeometry::Dcel`` and contains the following functionality: +The DCEL functionality exists under the namespace ``EBGeometry::DCEL`` and contains the following functionality: * **Fundamental data types** like vertices, half-edges, polygons, and entire surface grids. * **Signed distance functionality** for the above types. @@ -19,33 +19,36 @@ Classes The main DCEL functionality (vertices, edges, faces) is provided by the following classes: -* **Vertices** are implemented as a template ``EBGeometry::Dcel::EdgeT`` +* **Vertices** are implemented as a template ``EBGeometry::DCEL::EdgeT`` - .. literalinclude:: ../../Source/EBGeometry_DcelVertex.hpp - :language: c++ - :lines: 41-43 + .. code-block:: c++ + + template + class VertexT The DCEL vertex class stores the vertex position, normal vector, and the outgoing half-edge from the vertex. Note that the class has member functions for computing the vertex pseudonormal, see :ref:`Chap:NormalDCEL`. - The full API is given in the doxygen documentation `here `__. + The full API is given in the doxygen documentation `here `__. -* **Edges** are implemented as a template ``EBGeometry::Dcel::EdgeT`` +* **Edges** are implemented as a template ``EBGeometry::DCEL::EdgeT`` - .. literalinclude:: ../../Source/EBGeometry_DcelEdge.hpp - :language: c++ - :lines: 43-45 + .. code-block:: c++ + + template + class EdgeT The half-edges store a reference to their face, as well as pointers to the previous edge, next edge, pair edge, and starting vertex. For performance reasons, the edge also stores the length and inverse length of the edge. - The full API is given in the doxygen documentation `here `__. + The full API is given in the doxygen documentation `here `__. -* **Faces** are implemented as a template ``EBGeometry::Dcel::FaceT`` +* **Faces** are implemented as a template ``EBGeometry::DCEL::FaceT`` - .. literalinclude:: ../../Source/EBGeometry_DcelFace.hpp - :language: c++ - :lines: 44-46 + .. code-block:: c++ + + template + class FaceT For performance reasons, a polygon face stores all it's half-edges (to avoid iteration when computing the signed distance). It also stores: @@ -57,19 +60,20 @@ The main DCEL functionality (vertices, edges, faces) is provided by the followin The normal vector and 2D embedding of the facet exist because the signed distance computation requires them. The centroid position exists only because BVH partitioners will use it for partitioning the surface mesh. - The full API is given in the doxygen documentation `here `__. + The full API is given in the doxygen documentation `here `__. -* **Mesh** is implemented as a template ``EBGeometry::Dcel::MeshT`` +* **Mesh** is implemented as a template ``EBGeometry::DCEL::MeshT`` - .. literalinclude:: ../../Source/EBGeometry_DcelMesh.hpp - :language: c++ - :lines: 42-44 + .. code-block:: c++ + + template + class MeshT The Mesh stores all the vertices, half-edges, and faces. - For example, to obtain all the facets one can call ``EBGeometry::Dcel::MeshT::getFaces()`` which will return all the DCEL faces of the surface mesh. + For example, to obtain all the facets one can call ``EBGeometry::DCEL::MeshT::getFaces()`` which will return all the DCEL faces of the surface mesh. Typically, the mesh is not created by the user but automatically created when reading the mesh from an input file. - The full API is given in the doxygen documentation `here `__. + The full API is given in the doxygen documentation `here `__. All of the above DCEL classes have member functions of the type: @@ -81,36 +85,6 @@ All of the above DCEL classes have member functions of the type: Thus, they fulfill the template requirements of the primitive type for the BVH implementation, see :ref:`Chap:BVHConstraints`. See :ref:`Chap:BVHIntegration` for details regarding DCEL integration with BVHs. - -File parsers ------------- - -Routines for parsing surface files from grids into EBGeometry's DCEL grids are given in the namespace ``EBGeometry::Dcel::Parser``. -Currently, this is limited to the following file formats: - -* **PLY** Only ASCII formats currently supported, ``_. - - When reading a PLY file into the DCEL data structures, it is sufficient to call the following static function: - - .. code-block:: - - template - using Mesh = EBGeometry::Dcel::MeshT; - - template - std::shared_ptr EBGeometry::Parser::PLY::readASCII(const std::string a_filename); - - .. warning:: - - Although the parser will do it's best to read files that contains holes or incomplete faces, success will fluctuate. - Moreover, the signed distance function is not well-defined for such cases. - - Calling the ``readASCII`` function will read the input file (which is assumed to be a PLY file) and create the DCEL data structures. - -.. note:: - - If the file format of your surface mesh file is not one of the above, consider either providing a new plugin or convert your file (e.g. to PLY) using MeshLab, Blender, etc. - .. _Chap:BVHIntegration: BVH integration @@ -120,42 +94,70 @@ DCEL functionality can easily be embedded in BVHs. In this case it is the facets that are embedded in the BVHs, and we require that we can create bounding volumes that contain all the vertices in a facet. Moreover, partitioning functions that partition a set of polygon faces into ``K`` new sets of faces are also required. -Construction methods -____________________ - EBGeometry provides some simplistic functions that are needed (see :ref:`Chap:BVHConstruction`) when building BVHs for DCEL geometries . .. note:: - The functions are defined in :file:`Source/EBGeometry_DcelBVH.hpp`. + The functions are defined in :file:`Source/EBGeometry_DCEL_BVH.hpp`. For the bounding volume constructor, we provide a function -.. literalinclude:: ../../Source/EBGeometry_DcelBVH.hpp - :language: c++ - :lines: 40-43 +.. code-block:: c++ + + template + EBGeometry::BVH::BVConstructorT, BV> defaultBVConstructor = + [](const std::shared_ptr>& a_primitive) -> BV { + return BV(a_primitive->getAllVertexCoordinates()); + }; -Note the extra template constraint on the bounding volume type ``BV``, which must be able to construct a bounding volume from a finite point set (the vertex coordinates). +Note the extra template constraint on the bounding volume type ``BV``, which must be able to construct a bounding volume from a finite point set (in this case the vertex coordinates). For the stop function we provide a simple function -.. literalinclude:: ../../Source/EBGeometry_DcelBVH.hpp - :language: c++ - :lines: 52-55 +.. code-block:: c++ + + template + EBGeometry::BVH::StopFunctionT, BV, K> defaultStopFunction = + [](const BVH::NodeT, BV, K>& a_node) -> bool { + return (a_node.getPrimitives()).size() < K; + }; Note that this simply terminates the leaf partitioning if there are not enough primitives (polygon faces) available, or there are fewer than a pre-defined number of primitives. -For the partitioning function we include a simple function that partitions the primites along the longest axis: +For the partitioning function we include a simple function that partitions the primitives along the longest axis: + +.. code-block:: c++ -.. literalinclude:: ../../Source/EBGeometry_DcelBVH.hpp - :language: c++ - :lines: 221-222 + template + EBGeometry::BVH::PartitionerT, BV, K> chunkPartitioner = + [](const PrimitiveList& a_primitives) -> std::array, K> { + Vec3T lo = Vec3T::max(); + Vec3T hi = -Vec3T::max(); + + for (const auto& p : a_primitives) { + lo = min(lo, p->getCentroid()); + hi = max(hi, p->getCentroid()); + } -Note that this function is just an alias for a different partitioner which splits the bounding volumes into equal-sized chunks. -See :file:`Source/EBGeometry_DcelBVH.hpp` for details. + const size_t splitDir = (hi - lo).maxDir(true); + + // Sort the primitives along the above coordinate direction. + PrimitiveList sortedPrimitives(a_primitives); + + std::sort( + sortedPrimitives.begin(), sortedPrimitives.end(), + [splitDir](const std::shared_ptr>& f1, const std::shared_ptr>& f2) -> bool { + return f1->getCentroid(splitDir) < f2->getCentroid(splitDir); + }); + + return EBGeometry::DCEL::equalCounts(sortedPrimitives); + }; + + +For a list of all DCEL partitioner, see :file:`Source/EBGeometry_DCEL_BVH.hpp`. Code example -____________ +------------ Constructing a compact BVH representation of polygon mesh is therefore done as follows: @@ -164,20 +166,20 @@ Constructing a compact BVH representation of polygon mesh is therefore done as f using T = float; using BV = EBGeometry::BoundingVolumes::AABBT; using Vec3 = EBGeometry::Vec3T; - using Face = EBGeometry::Dcel::FaceT; + using Face = EBGeometry::DCEL::FaceT; constexpr int K = 4; // Read the mesh from file and put it in a DCEL format. - std::shared_ptr > mesh = EBGeometry::Dcel::Parser::Ply("MyFile.ply"); + std::shared_ptr > mesh = EBGeometry::Parser::PLY("MyFile.ply"); // Make a BVH node and build the BVH. auto root = std::make_shared >(mesh->getFaces()); // Build the BVH hierarchy - root->topDownSortAndPartitionPrimitives(EBGeometry::Dcel::defaultBVConstructor, - EBGeometry::Dcel::spatialSplitPartitioner, - EBGeometry::Dcel::defaultStopFunction); + root->topDownSortAndPartitionPrimitives(EBGeometry::DCEL::defaultBVConstructor, + EBGeometry::DCEL::spatialSplitPartitioner, + EBGeometry::DCEL::defaultStopFunction); // Flatten the tree onto a tighter representation. Then delete the old tree. auto compactBVH = root->flattenTree(); diff --git a/Sphinx/source/ImplemSDF.rst b/Sphinx/source/ImplemSDF.rst index 3217af79..79dc77cd 100644 --- a/Sphinx/source/ImplemSDF.rst +++ b/Sphinx/source/ImplemSDF.rst @@ -5,12 +5,11 @@ Signed distance function In EBGeometry we have encapsulated the concept of a signed distance function in an abstract class -.. literalinclude:: ../../Source/EBGeometry_SignedDistanceFunction.hpp +.. literalinclude:: ../../Source/EBGeometry_SignedDistanceFunction.hpp :language: c++ - :lines: 28-31, 46-47, 54-56, 61-63, 69-71, 82-84 -We point out that the BVH and DCEL functionalities are fundamentally also signed distance functions, even though they do not inherent from ``EBGeometry::SignedDistanceFunction``. -The ``SignedDistanceFunction`` class exists so that we have a common entry point for performing distance field manipulations like rotations and translations. +We point out that the BVH and DCEL classes are fundamentally also signed distance functions, and they also inherit from ``SignedDistanceFunction``. +The ``SignedDistanceFunction`` class also exists so that we have a common entry point for performing distance field manipulations like rotations and translations. When implementing the ``signedDistance`` function, one can transform the input point by first calling ``transformPoint``. The functions ``translate`` and ``rotate`` will translate or rotate the object. @@ -105,7 +104,7 @@ The rounded SDF is implemented in :file:`Source/EBGeometry_AnalyticDistanceFunct .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp :language: c++ - :lines: 40-43, 54-58, 69-71, 84 + :lines: 45-89 To use it, simply pass an SDF into the constructor and use the new distance function. @@ -125,8 +124,7 @@ The rounded SDF is implemented in :file:`Source/EBGeometry_AnalyticDistanceFunct .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp :language: c++ - :lines: 138-151, 152-155, 168-170, 183 - + :lines: 143-188 .. _Chap:AnalyticSDF: @@ -138,49 +136,56 @@ In addition, the file :file:`Source/EBGeometry_AnalyticSignedDistanceFunctions.h * **Sphere** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 239-240 + .. code-block:: c++ + + template + class SphereSDF : public SignedDistanceFunction * **Box** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 334-335 + .. code-block:: c++ + + template + class BoxSDF : public SignedDistanceFunction * **Torus** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 440-441 + .. code-block:: c++ + + template + class TorusSDF : public SignedDistanceFunction * **Capped cylinder** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 560-561 + .. code-block:: c++ + + template + class CylinderSDF : public SignedDistanceFunction * **Infinite cylinder** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 699-700 + .. code-block:: c++ + + template + class InfiniteCylinderSDF : public SignedDistanceFunction * **Capsule/rounded cylinder** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 762-763 + .. code-block:: c++ + + template + class CapsuleSDF : public SignedDistanceFunction * **Infinite cone** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 827-828 + .. code-block:: c++ + + template + class InfiniteConeSDF : public SignedDistanceFunction * **Cone** - .. literalinclude:: ../../Source/EBGeometry_AnalyticDistanceFunctions.hpp - :language: c++ - :lines: 895-896 + .. code-block:: c++ + template + class ConeSDF : public SignedDistanceFunction diff --git a/Sphinx/source/ImplemUnion.rst b/Sphinx/source/ImplemUnion.rst index 4f9ee26d..b839ea3c 100644 --- a/Sphinx/source/ImplemUnion.rst +++ b/Sphinx/source/ImplemUnion.rst @@ -16,14 +16,14 @@ The standard union is template as .. literalinclude:: ../../Source/EBGeometry_Union.hpp :language: c++ - :lines: 26-29,33-34,45 + :lines: 27-70 Note that ``EBGeometry::Union`` inherits from ``EBGeometry::SignedDistanceFunction`` and thus provides a ``signedDistance(...)`` function. The implementation of the standard union is .. literalinclude:: ../../Source/EBGeometry_UnionImplem.hpp :language: c++ - :lines: 28-43 + :lines: 20-44 That is, it iterates through *all* the objects in order to find the signed distance. @@ -34,7 +34,7 @@ The BVH-enabled union is implemented by ``EBGeometry::UnionBVH`` as follows: .. literalinclude:: ../../Source/EBGeometry_UnionBVH.hpp :language: c++ - :lines: 26-29,33-34,38-39,58-61,77-80, 94-95, 104, 115 + :lines: 27-122 As always, the template parameter ``T`` indicates the precision, ``BV`` the bounding volume type and ``K`` the tree degree. ``UnionBVH`` takes a bounding volume constructor in addition to the list of primitives, see :ref:`Chap:BVHConstruction`. @@ -46,6 +46,6 @@ The implementation of the signed distance function for the BVH-enabled union is .. literalinclude:: ../../Source/EBGeometry_UnionBVHImplem.hpp :language: c++ - :lines: 144-149 + :lines: 163-170 That is, it relies on pruning from the BVH functionality for finding the signed distance to the closest object. diff --git a/Sphinx/source/Parsers.rst b/Sphinx/source/Parsers.rst new file mode 100644 index 00000000..a885beef --- /dev/null +++ b/Sphinx/source/Parsers.rst @@ -0,0 +1,35 @@ +.. _Chap:Parsers: + +File parsers +============ + +Routines for parsing surface files from grids into EBGeometry's DCEL grids are given in the namespace ``EBGeometry::Parser``. +The source code is implemented in :file:`Source/EBGeometry_Parser.hpp`. + +Read into DCEL +-------------- + +Currently, this is limited to the following file formats: + +* **PLY** Only ASCII formats currently supported, ``_. + + When reading a PLY file into the DCEL data structures, it is sufficient to call the following static function: + + .. code-block:: + + template + using Mesh = EBGeometry::DCEL::MeshT; + + template + std::shared_ptr EBGeometry::Parser::PLY::readASCII(const std::string a_filename); + + .. warning:: + + Although the parser will do it's best to read files that contains holes or incomplete faces, success will fluctuate. + Moreover, the signed distance function is not well-defined for such cases. + + Calling the ``readASCII`` function will read the input file (which is assumed to be a PLY file) and create the DCEL data structures. + +.. note:: + + If the file format of your surface mesh file is not one of the above, consider either providing a new plugin or convert your file (e.g. to PLY) using MeshLab, Blender, etc. diff --git a/Sphinx/source/index.rst b/Sphinx/source/index.rst index cf6a32a9..0506c426 100644 --- a/Sphinx/source/index.rst +++ b/Sphinx/source/index.rst @@ -69,7 +69,8 @@ Implementation ImplemBVH.rst ImplemDCEL.rst ImplemSDF.rst - ImplemUnion.rst + ImplemUnion.rst + Parsers.rst Guided examples *************** From 21ea9c801b41b22b39c1b12e58e6939cb5b838a8 Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Mon, 2 May 2022 09:08:35 +0200 Subject: [PATCH 5/7] Better code alignment now --- .clang-format | 16 +- Examples/AMReX_DCEL/main.cpp | 50 +- Examples/AMReX_Shapes/main.cpp | 65 +- Examples/Chombo3_DCEL/main.cpp | 32 +- Examples/Chombo3_Shapes/main.cpp | 22 +- Examples/EBGeometry_DCEL/main.cpp | 36 +- Examples/EBGeometry_Union/main.cpp | 24 +- .../EBGeometry_AnalyticDistanceFunctions.hpp | 108 +- Source/EBGeometry_BVH.hpp | 408 ++++--- Source/EBGeometry_BVHImplem.hpp | 1017 ++++++++--------- Source/EBGeometry_BoundingVolumes.hpp | 298 ++--- Source/EBGeometry_BoundingVolumesImplem.hpp | 808 +++++++------ Source/EBGeometry_DCEL_BVH.hpp | 274 ++--- Source/EBGeometry_DCEL_Edge.hpp | 283 +++-- Source/EBGeometry_DCEL_EdgeImplem.hpp | 532 +++++---- Source/EBGeometry_DCEL_Face.hpp | 276 ++--- Source/EBGeometry_DCEL_FaceImplem.hpp | 565 +++++---- Source/EBGeometry_DCEL_Iterator.hpp | 130 +-- Source/EBGeometry_DCEL_IteratorImplem.hpp | 164 +-- Source/EBGeometry_DCEL_Mesh.hpp | 248 ++-- Source/EBGeometry_DCEL_MeshImplem.hpp | 626 +++++----- Source/EBGeometry_DCEL_Polygon2D.hpp | 118 +- Source/EBGeometry_DCEL_Polygon2DImplem.hpp | 294 ++--- Source/EBGeometry_DCEL_Vertex.hpp | 220 ++-- Source/EBGeometry_DCEL_VertexImplem.hpp | 507 ++++---- Source/EBGeometry_Parser.hpp | 84 +- Source/EBGeometry_ParserImplem.hpp | 44 +- Source/EBGeometry_Polygon2DImplem.hpp | 2 +- Source/EBGeometry_TransformOpsImplem.hpp | 4 +- Source/EBGeometry_UnionBVH.hpp | 7 +- Source/EBGeometry_UnionBVHImplem.hpp | 17 +- Source/EBGeometry_VecImplem.hpp | 2 +- 32 files changed, 3639 insertions(+), 3642 deletions(-) diff --git a/.clang-format b/.clang-format index 37888105..cdc0433e 100644 --- a/.clang-format +++ b/.clang-format @@ -2,9 +2,9 @@ --- Language: Cpp AccessModifierOffset: -2 -AlignAfterOpenBracket: AlwaysBreak -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true AlignEscapedNewlinesLeft: false AlignEscapedNewlines: Left AlignOperands: true @@ -15,11 +15,10 @@ AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: TopLevel AlwaysBreakAfterReturnType: All AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: true -BinPackArguments: true +BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: true @@ -33,10 +32,11 @@ BraceWrapping: BeforeCatch: false BeforeElse: true IndentBraces: false + SplitEmptyFunction: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 120 @@ -65,7 +65,7 @@ KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None +NamespaceIndentation: All ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true @@ -76,7 +76,7 @@ PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left -ReflowComments: true +ReflowComments: false SortIncludes: false SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true diff --git a/Examples/AMReX_DCEL/main.cpp b/Examples/AMReX_DCEL/main.cpp index ffc185f0..b1a37a3a 100644 --- a/Examples/AMReX_DCEL/main.cpp +++ b/Examples/AMReX_DCEL/main.cpp @@ -51,17 +51,17 @@ namespace amrex { SignedDistanceBVH(const std::string a_filename, const bool a_flipSign) { - // 1. Read mesh from file. - auto mesh = EBGeometry::Parser::PLY::readIntoDCEL(a_filename); + // 1. Read mesh from file. + auto mesh = EBGeometry::Parser::PLY::readIntoDCEL(a_filename); - // 2. Create a standard BVH hierarchy. This is not a compact ree. - auto root = std::make_shared(mesh->getFaces()); - root->topDownSortAndPartitionPrimitives( - EBGeometry::DCEL::defaultBVConstructor, EBGeometry::DCEL::defaultPartitioner, - EBGeometry::DCEL::defaultStopFunction); + // 2. Create a standard BVH hierarchy. This is not a compact ree. + auto root = std::make_shared(mesh->getFaces()); + root->topDownSortAndPartitionPrimitives(EBGeometry::DCEL::defaultBVConstructor, + EBGeometry::DCEL::defaultPartitioner, + EBGeometry::DCEL::defaultStopFunction); - // 3. Flatten the tree onto a tighter memory representation. - m_rootNode = root->flattenTree(); + // 3. Flatten the tree onto a tighter memory representation. + m_rootNode = root->flattenTree(); } /*! @@ -70,8 +70,8 @@ namespace amrex { */ SignedDistanceBVH(const SignedDistanceBVH& a_other) { - this->m_rootNode = a_other.m_rootNode; - this->m_flipSign = a_other.m_flipSign; + this->m_rootNode = a_other.m_rootNode; + this->m_flipSign = a_other.m_flipSign; } /*! @@ -79,9 +79,9 @@ namespace amrex { */ Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept { - const Real sign = (m_flipSign) ? -1.0 : 1.0; + const Real sign = (m_flipSign) ? -1.0 : 1.0; - return sign * m_rootNode->signedDistance(Vec3(x, y, z)); + return sign * m_rootNode->signedDistance(Vec3(x, y, z)); }; /*! @@ -90,7 +90,7 @@ namespace amrex { inline Real operator()(const RealArray& p) const noexcept { - return this->operator()(AMREX_D_DECL(p[0], p[1], p[2])); + return this->operator()(AMREX_D_DECL(p[0], p[1], p[2])); } protected: @@ -112,9 +112,9 @@ main(int argc, char* argv[]) { amrex::Initialize(argc, argv); - int n_cell = 128; + int n_cell = 128; int max_grid_size = 32; - int which_geom = 0; + int which_geom = 0; std::string filename; @@ -129,32 +129,32 @@ main(int argc, char* argv[]) RealBox rb; if (which_geom == 0) { // Airfoil case - rb = RealBox({-100, -100, -75}, {400, 100, 125}); + rb = RealBox({-100, -100, -75}, {400, 100, 125}); filename = "../PLY/airfoil.ply"; } else if (which_geom == 1) { // Sphere case - rb = RealBox({-400, -400, -400}, {400, 400, 400}); + rb = RealBox({-400, -400, -400}, {400, 400, 400}); filename = "../PLY/sphere.ply"; } else if (which_geom == 2) { // Dodecahedron - rb = RealBox({-2., -2., -2.}, {2., 2., 2.}); + rb = RealBox({-2., -2., -2.}, {2., 2., 2.}); filename = "../PLY/dodecahedron.ply"; } else if (which_geom == 3) { // Horse - rb = RealBox({-0.12, -0.12, -0.12}, {0.12, 0.12, 0.12}); + rb = RealBox({-0.12, -0.12, -0.12}, {0.12, 0.12, 0.12}); filename = "../PLY/horse.ply"; } else if (which_geom == 4) { // Car // rb = RealBox({-20,-20,-20}, {20,20,20}); // Doesn't work. - rb = RealBox({-10, -5, -5}, {10, 5, 5}); // Works. + rb = RealBox({-10, -5, -5}, {10, 5, 5}); // Works. filename = "../PLY/porsche.ply"; } else if (which_geom == 5) { // Orion - rb = RealBox({-10, -5, -10}, {10, 10, 10}); + rb = RealBox({-10, -5, -10}, {10, 10, 10}); filename = "../PLY/orion.ply"; } else if (which_geom == 6) { // Armadillo - rb = RealBox({-100, -75, -100}, {100, 125, 100}); + rb = RealBox({-100, -75, -100}, {100, 125, 100}); filename = "../PLY/armadillo.ply"; } @@ -168,9 +168,9 @@ main(int argc, char* argv[]) // EBGeometry precision. constexpr int K = 4; - using T = float; + using T = float; using Vec3 = EBGeometry::Vec3T; - using BV = EBGeometry::BoundingVolumes::AABBT; + using BV = EBGeometry::BoundingVolumes::AABBT; EB2::SignedDistanceBVH sdf(filename, false); diff --git a/Examples/AMReX_Shapes/main.cpp b/Examples/AMReX_Shapes/main.cpp index d5ad9bc2..2b8f088b 100644 --- a/Examples/AMReX_Shapes/main.cpp +++ b/Examples/AMReX_Shapes/main.cpp @@ -15,55 +15,58 @@ using namespace amrex; -using T = float; -using SDF = EBGeometry::SignedDistanceFunction; +using T = float; +using SDF = EBGeometry::SignedDistanceFunction; using Vec3 = EBGeometry::Vec3T; namespace amrex { -namespace EB2 { + namespace EB2 { -/*! + /*! @brief This is just an EBGeometry-exposed signed distance field usable with AMReX. */ -class AMReXSDF -{ -public: - /*! + class AMReXSDF + { + public: + /*! @brief Full constructor. @param[in] a_filename File name. Must be a PLY file and will be parser by the PLY parser. @param[in] a_flipSign Hook for swapping inside/outside. */ - AMReXSDF(std::shared_ptr& a_sdf) { m_sdf = a_sdf; } + AMReXSDF(std::shared_ptr& a_sdf) { m_sdf = a_sdf; } - /*! + /*! @brief Copy constructor. @param[in] a_other Other SDF. */ - AMReXSDF(const AMReXSDF& a_other) { this->m_sdf = a_other.m_sdf; } + AMReXSDF(const AMReXSDF& a_other) { this->m_sdf = a_other.m_sdf; } - /*! + /*! @brief AMReX's implicit function definition. */ - Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept { return m_sdf->signedDistance(Vec3(x, y, z)); }; + Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept + { + return m_sdf->signedDistance(Vec3(x, y, z)); + }; - /*! + /*! @brief Also an AMReX implicit function implementation */ - inline Real - operator()(const RealArray& p) const noexcept - { - return this->operator()(AMREX_D_DECL(p[0], p[1], p[2])); - } - -protected: - /*! + inline Real + operator()(const RealArray& p) const noexcept + { + return this->operator()(AMREX_D_DECL(p[0], p[1], p[2])); + } + + protected: + /*! @brief EBGeometry signed distance function. */ - std::shared_ptr m_sdf; -}; -} // namespace EB2 + std::shared_ptr m_sdf; + }; + } // namespace EB2 } // namespace amrex int @@ -71,9 +74,9 @@ main(int argc, char* argv[]) { amrex::Initialize(argc, argv); - int n_cell = 128; + int n_cell = 128; int max_grid_size = 32; - int whichGeom = 0; + int whichGeom = 0; std::string filename; @@ -84,11 +87,11 @@ main(int argc, char* argv[]) pp.query("which_geom", whichGeom); Geometry geom; - RealBox rb; + RealBox rb; std::shared_ptr func; if (whichGeom == 0) { // Sphere. - rb = RealBox({-1, -1, -1}, {1, 1, 1}); + rb = RealBox({-1, -1, -1}, {1, 1, 1}); func = std::make_shared>(Vec3::zero(), T(0.5), false); } else if (whichGeom == 1) { // Plane. @@ -120,7 +123,7 @@ main(int argc, char* argv[]) rb = RealBox({-2, -2, -2}, {2, 2, 2}); auto box = std::make_shared>(-Vec3::one(), Vec3::one(), false); - func = std::make_shared>(box, 0.25); + func = std::make_shared>(box, 0.25); } else if (whichGeom == 7) { // Torus. rb = RealBox({-2, -2, -2}, {2, 2, 2}); @@ -141,7 +144,7 @@ main(int argc, char* argv[]) rb = RealBox({-1, -1, -1}, {1, 1, 1}); auto sphere = std::make_shared>(Vec3::zero(), T(0.5), false); - func = std::make_shared>(sphere, 0.1); + func = std::make_shared>(sphere, 0.1); } Array is_periodic{false, false, false}; diff --git a/Examples/Chombo3_DCEL/main.cpp b/Examples/Chombo3_DCEL/main.cpp index 9c05e00c..1067c1bf 100644 --- a/Examples/Chombo3_DCEL/main.cpp +++ b/Examples/Chombo3_DCEL/main.cpp @@ -13,10 +13,10 @@ // Our includes #include "EBGeometry.hpp" -using T = float; -using SDF = EBGeometry::SignedDistanceFunction; +using T = float; +using SDF = EBGeometry::SignedDistanceFunction; using Vec3 = EBGeometry::Vec3T; -using BV = EBGeometry::BoundingVolumes::AABBT; +using BV = EBGeometry::BoundingVolumes::AABBT; // Binding for exposing EBGeometry's signed distance functions to Chombo template @@ -42,9 +42,9 @@ class ChomboSDF : public BaseIF // 2. Create standard BVH hierarchy. This is not a compact tree. auto root = std::make_shared(mesh->getFaces()); - root->topDownSortAndPartitionPrimitives( - EBGeometry::DCEL::defaultBVConstructor, EBGeometry::DCEL::defaultPartitioner, - EBGeometry::DCEL::defaultStopFunction); + root->topDownSortAndPartitionPrimitives(EBGeometry::DCEL::defaultBVConstructor, + EBGeometry::DCEL::defaultPartitioner, + EBGeometry::DCEL::defaultStopFunction); // 3. Flatten the tree onto a tighter memory representation. m_rootNode = root->flattenTree(); @@ -85,18 +85,18 @@ main(int argc, char* argv[]) // Set up domain. // Parse input file - char* inFile = argv[1]; + char* inFile = argv[1]; ParmParse pp(argc - 2, argv + 2, NULL, inFile); - int nCells = 128; + int nCells = 128; int whichGeom = 0; - int gridSize = 16; + int gridSize = 16; pp.query("which_geom", whichGeom); pp.query("n_cells", nCells); pp.query("grid_size", gridSize); - RealVect loCorner; - RealVect hiCorner; + RealVect loCorner; + RealVect hiCorner; std::string filename; if (whichGeom == 0) { // Airfoil @@ -143,15 +143,15 @@ main(int argc, char* argv[]) } // - constexpr int K = 4; - auto impFunc = (BaseIF*)(new ChomboSDF(filename)); + constexpr int K = 4; + auto impFunc = (BaseIF*)(new ChomboSDF(filename)); // Set up the Chombo EB geometry. ProblemDomain domain(IntVect::Zero, (nCells - 1) * IntVect::Unit); - const Real dx = (hiCorner[0] - loCorner[0]) / nCells; + const Real dx = (hiCorner[0] - loCorner[0]) / nCells; ; - GeometryShop workshop(*impFunc, -1, dx * RealVect::Zero); + GeometryShop workshop(*impFunc, -1, dx * RealVect::Zero); EBIndexSpace* ebisPtr = Chombo_EBIS::instance(); ebisPtr->define(domain, loCorner, dx, workshop, gridSize, -1); @@ -177,7 +177,7 @@ main(int argc, char* argv[]) for (BoxIterator bit(region); bit.ok(); ++bit) { const IntVect iv = bit(); - const RealVect pos = loCorner + (iv + 0.5 * RealVect::Unit) * dx; + const RealVect pos = loCorner + (iv + 0.5 * RealVect::Unit) * dx; fab.getFArrayBox()(iv, 0) = impFunc->value(pos); } } diff --git a/Examples/Chombo3_Shapes/main.cpp b/Examples/Chombo3_Shapes/main.cpp index e61ceb8a..ae8f1f33 100644 --- a/Examples/Chombo3_Shapes/main.cpp +++ b/Examples/Chombo3_Shapes/main.cpp @@ -13,8 +13,8 @@ // Our includes #include "EBGeometry.hpp" -using T = float; -using SDF = EBGeometry::SignedDistanceFunction; +using T = float; +using SDF = EBGeometry::SignedDistanceFunction; using Vec3 = EBGeometry::Vec3T; // Binding for exposing EBGeometry's signed distance functions to Chombo @@ -61,12 +61,12 @@ main(int argc, char* argv[]) // Set up domain. // Parse input file - char* inFile = argv[1]; + char* inFile = argv[1]; ParmParse pp(argc - 2, argv + 2, NULL, inFile); - int nCells = 128; + int nCells = 128; int whichGeom = 0; - int gridSize = 16; + int gridSize = 16; pp.query("which_geom", whichGeom); pp.query("n_cells", nCells); pp.query("grid_size", gridSize); @@ -116,7 +116,7 @@ main(int argc, char* argv[]) hiCorner = 2 * RealVect::Unit; auto box = std::make_shared>(-Vec3::one(), Vec3::one(), false); - sdf = std::make_shared>(box, 0.25); + sdf = std::make_shared>(box, 0.25); } else if (whichGeom == 7) { // Torus. loCorner = -2 * RealVect::Unit; @@ -141,15 +141,15 @@ main(int argc, char* argv[]) hiCorner = RealVect::Unit; auto sphere = std::make_shared>(Vec3::zero(), T(0.5), false); - sdf = std::make_shared>(sphere, 0.1); + sdf = std::make_shared>(sphere, 0.1); } // Set up the Chombo EB geometry. ProblemDomain domain(IntVect::Zero, (nCells - 1) * IntVect::Unit); - const Real dx = (hiCorner[0] - loCorner[0]) / nCells; + const Real dx = (hiCorner[0] - loCorner[0]) / nCells; ; - auto impFunc = (BaseIF*)(new ChomboSDF(sdf)); - GeometryShop workshop(*impFunc, -1, dx * RealVect::Zero); + auto impFunc = (BaseIF*)(new ChomboSDF(sdf)); + GeometryShop workshop(*impFunc, -1, dx * RealVect::Zero); EBIndexSpace* ebisPtr = Chombo_EBIS::instance(); ebisPtr->define(domain, loCorner, dx, workshop, gridSize, -1); @@ -175,7 +175,7 @@ main(int argc, char* argv[]) for (BoxIterator bit(region); bit.ok(); ++bit) { const IntVect iv = bit(); - const RealVect pos = loCorner + (iv + 0.5 * RealVect::Unit) * dx; + const RealVect pos = loCorner + (iv + 0.5 * RealVect::Unit) * dx; fab.getFArrayBox()(iv, 0) = impFunc->value(pos); } } diff --git a/Examples/EBGeometry_DCEL/main.cpp b/Examples/EBGeometry_DCEL/main.cpp index 504214cb..862c16d4 100644 --- a/Examples/EBGeometry_DCEL/main.cpp +++ b/Examples/EBGeometry_DCEL/main.cpp @@ -20,7 +20,7 @@ int main(int argc, char* argv[]) { - std::string current_exec_name = argv[0]; // Name of the current exec program + std::string current_exec_name = argv[0]; // Name of the current exec program std::vector all_args; std::string file; @@ -38,7 +38,7 @@ main(int argc, char* argv[]) using T = float; // Aliases for cutting down on typing. - using BV = BoundingVolumes::AABBT; + using BV = BoundingVolumes::AABBT; using Vec3 = Vec3T; // Parse the mesh from file. One can call the signed distance function @@ -51,9 +51,9 @@ main(int argc, char* argv[]) // bounding volume hierarchy bounds the facets in a binary tree. std::cout << "Partitioning BVH\n"; auto bvhSDF = std::make_shared, BV, K>>(directSDF->getFaces()); - bvhSDF->topDownSortAndPartitionPrimitives( - EBGeometry::DCEL::defaultBVConstructor, EBGeometry::DCEL::defaultPartitioner, - EBGeometry::DCEL::defaultStopFunction); + bvhSDF->topDownSortAndPartitionPrimitives(EBGeometry::DCEL::defaultBVConstructor, + EBGeometry::DCEL::defaultPartitioner, + EBGeometry::DCEL::defaultStopFunction); // Create the linear representation of the conventional BVH SDF above. std::cout << "Flattening BVH tree\n"; @@ -62,27 +62,27 @@ main(int argc, char* argv[]) // Compute signed distance for this position and time all SDF representations. const Vec3 point = Vec3::one(); - const auto t1 = std::chrono::high_resolution_clock::now(); - const T directDist = directSDF->signedDistance(point); - const auto t2 = std::chrono::high_resolution_clock::now(); + const auto t1 = std::chrono::high_resolution_clock::now(); + const T directDist = directSDF->signedDistance(point); + const auto t2 = std::chrono::high_resolution_clock::now(); - const auto t3 = std::chrono::high_resolution_clock::now(); - const T bvhDist = bvhSDF->signedDistance(point); - const auto t4 = std::chrono::high_resolution_clock::now(); + const auto t3 = std::chrono::high_resolution_clock::now(); + const T bvhDist = bvhSDF->signedDistance(point); + const auto t4 = std::chrono::high_resolution_clock::now(); - const auto t5 = std::chrono::high_resolution_clock::now(); - const T linDist = linSDF->signedDistance(point); - const auto t6 = std::chrono::high_resolution_clock::now(); + const auto t5 = std::chrono::high_resolution_clock::now(); + const T linDist = linSDF->signedDistance(point); + const auto t6 = std::chrono::high_resolution_clock::now(); // Kill all the SDF representations. directSDF = nullptr; - bvhSDF = nullptr; - linSDF = nullptr; + bvhSDF = nullptr; + linSDF = nullptr; // Get the timings. const std::chrono::duration directTime = t2 - t1; - const std::chrono::duration bvhTime = t4 - t3; - const std::chrono::duration linTime = t6 - t5; + const std::chrono::duration bvhTime = t4 - t3; + const std::chrono::duration linTime = t6 - t5; std::cout << "Distance and time using direct query = " << directDist << ", which took " << directTime.count() << " us\n"; diff --git a/Examples/EBGeometry_Union/main.cpp b/Examples/EBGeometry_Union/main.cpp index 8e689ccd..17c790d3 100644 --- a/Examples/EBGeometry_Union/main.cpp +++ b/Examples/EBGeometry_Union/main.cpp @@ -14,9 +14,9 @@ using T = double; // Aliases for cutting down on typing. -using AABB = EBGeometry::BoundingVolumes::AABBT; -using Vec3 = EBGeometry::Vec3T; -using SDF = EBGeometry::SignedDistanceFunction; +using AABB = EBGeometry::BoundingVolumes::AABBT; +using Vec3 = EBGeometry::Vec3T; +using SDF = EBGeometry::SignedDistanceFunction; using Sphere = EBGeometry::SphereSDF; using namespace std::chrono_literals; @@ -32,8 +32,8 @@ main() // the spheres is 2*radius std::vector> spheres; - constexpr T radius = 1.0; - constexpr int N = 100; + constexpr T radius = 1.0; + constexpr int N = 100; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { @@ -62,7 +62,7 @@ main() const Sphere& sph = static_cast(*a_prim); const Vec3& c = sph.getCenter(); - const T& r = sph.getRadius(); + const T& r = sph.getRadius(); const Vec3 lo = c - r * Vec3::one(); const Vec3 hi = c + r * Vec3::one(); @@ -77,14 +77,14 @@ main() const Vec3 point = Vec3::zero(); std::cout << "Computing distance with slow union\n"; - const auto t1 = std::chrono::high_resolution_clock::now(); - const T slowDist = slowUnion.signedDistance(point); - const auto t2 = std::chrono::high_resolution_clock::now(); + const auto t1 = std::chrono::high_resolution_clock::now(); + const T slowDist = slowUnion.signedDistance(point); + const auto t2 = std::chrono::high_resolution_clock::now(); std::cout << "Computing distance with fast union\n"; - const auto t3 = std::chrono::high_resolution_clock::now(); - const T fastDist = fastUnion.signedDistance(point); - const auto t4 = std::chrono::high_resolution_clock::now(); + const auto t3 = std::chrono::high_resolution_clock::now(); + const T fastDist = fastUnion.signedDistance(point); + const auto t4 = std::chrono::high_resolution_clock::now(); const std::chrono::duration slowTime = t2 - t1; const std::chrono::duration fastTime = t4 - t3; diff --git a/Source/EBGeometry_AnalyticDistanceFunctions.hpp b/Source/EBGeometry_AnalyticDistanceFunctions.hpp index 41e48c72..f2cdc4f5 100644 --- a/Source/EBGeometry_AnalyticDistanceFunctions.hpp +++ b/Source/EBGeometry_AnalyticDistanceFunctions.hpp @@ -58,7 +58,7 @@ class RoundedSDF : public SignedDistanceFunction */ RoundedSDF(const std::shared_ptr> a_sdf, const T a_curv) { - m_sdf = a_sdf; + m_sdf = a_sdf; m_curv = a_curv; } @@ -107,7 +107,7 @@ class AnnularSDF : public SignedDistanceFunction */ AnnularSDF(const std::shared_ptr> a_sdf, const T a_curv) { - m_sdf = a_sdf; + m_sdf = a_sdf; m_curv = a_curv; } @@ -156,7 +156,7 @@ class ScaledSDF : public SignedDistanceFunction */ ScaledSDF(const std::shared_ptr> a_sdf, const T a_scale) { - m_sdf = a_sdf; + m_sdf = a_sdf; m_scale = a_scale; } @@ -204,8 +204,8 @@ class PlaneSDF : public SignedDistanceFunction */ PlaneSDF(const Vec3T& a_point, const Vec3T& a_normal, const bool a_flipInside) { - m_point = a_point; - m_normal = a_normal; + m_point = a_point; + m_normal = a_normal; m_flipInside = a_flipInside; m_normal /= m_normal.length(); @@ -260,8 +260,8 @@ class SphereSDF : public SignedDistanceFunction */ SphereSDF(const Vec3T& a_center, const T& a_radius, const bool a_flipInside) { - this->m_center = a_center; - this->m_radius = a_radius; + this->m_center = a_center; + this->m_radius = a_radius; this->m_flipInside = a_flipInside; } @@ -270,9 +270,9 @@ class SphereSDF : public SignedDistanceFunction */ SphereSDF(const SphereSDF& a_other) { - this->m_center = a_other.m_center; - this->m_radius = a_other.m_radius; - this->m_flipInside = a_other.m_flipInside; + this->m_center = a_other.m_center; + this->m_radius = a_other.m_radius; + this->m_flipInside = a_other.m_flipInside; this->m_transformOps = a_other.m_transformOps; } @@ -366,8 +366,8 @@ class BoxSDF : public SignedDistanceFunction */ BoxSDF(const Vec3T& a_loCorner, const Vec3T& a_hiCorner, const bool a_flipInside) { - this->m_loCorner = a_loCorner; - this->m_hiCorner = a_hiCorner; + this->m_loCorner = a_loCorner; + this->m_hiCorner = a_hiCorner; this->m_flipInside = a_flipInside; } @@ -427,16 +427,12 @@ class BoxSDF : public SignedDistanceFunction // between xLo and xHi. In this case delta[dir] will be the signed distance // to the closest box face in the dir-direction. Otherwise, if a_point[dir] // is outside the corner we have delta[dir] > 0. - const Vec3T delta( - std::max( - m_loCorner[0] - a_point[0], - a_point[0] - m_hiCorner[0]), // < 0 if point falls between xLo and xHi. - std::max( - m_loCorner[1] - a_point[1], - a_point[1] - m_hiCorner[1]), // < 0 if point falls between yLo and yHi. - std::max( - m_loCorner[2] - a_point[2], - a_point[2] - m_hiCorner[2])); // < 0 if point falls between zLo and zHi. + const Vec3T delta(std::max(m_loCorner[0] - a_point[0], + a_point[0] - m_hiCorner[0]), // < 0 if point falls between xLo and xHi. + std::max(m_loCorner[1] - a_point[1], + a_point[1] - m_hiCorner[1]), // < 0 if point falls between yLo and yHi. + std::max(m_loCorner[2] - a_point[2], + a_point[2] - m_hiCorner[2])); // < 0 if point falls between zLo and zHi. // Note: max is max(Vec3T, Vec3T) and not std::max. It returns a // vector with coordinate-wise largest components. Note that the first part @@ -489,10 +485,10 @@ class TorusSDF : public SignedDistanceFunction */ TorusSDF(const Vec3T& a_center, const T& a_majorRadius, const T& a_minorRadius, const bool a_flipInside) { - this->m_center = a_center; + this->m_center = a_center; this->m_majorRadius = a_majorRadius; this->m_minorRadius = a_minorRadius; - this->m_flipInside = a_flipInside; + this->m_flipInside = a_flipInside; } /*! @@ -566,9 +562,9 @@ class TorusSDF : public SignedDistanceFunction virtual T signedDistance(const Vec3T& a_point) const noexcept override { - const Vec3T p = a_point - m_center; - const T rho = sqrt(p[0] * p[0] + p[1] * p[1]) - m_majorRadius; - const T d = sqrt(rho * rho + p[2] * p[2]) - m_minorRadius; + const Vec3T p = a_point - m_center; + const T rho = sqrt(p[0] * p[0] + p[1] * p[1]) - m_majorRadius; + const T d = sqrt(rho * rho + p[2] * p[2]) - m_minorRadius; const T sign = m_flipInside ? -1.0 : 1.0; @@ -618,15 +614,15 @@ class CylinderSDF : public SignedDistanceFunction */ CylinderSDF(const Vec3T& a_center1, const Vec3T& a_center2, const T& a_radius, const bool a_flipInside) { - this->m_center1 = a_center1; - this->m_center2 = a_center2; - this->m_radius = a_radius; + this->m_center1 = a_center1; + this->m_center2 = a_center2; + this->m_radius = a_radius; this->m_flipInside = a_flipInside; // Some derived quantities that are needed for SDF computations. m_center = (m_center2 + m_center1) * 0.5; m_length = (m_center2 - m_center1).length(); - m_axis = (m_center2 - m_center1) / m_length; + m_axis = (m_center2 - m_center1) / m_length; } /*! @@ -675,7 +671,7 @@ class CylinderSDF : public SignedDistanceFunction if (m_length > 0.0 && m_radius > 0.0) { const Vec3T point = a_point - m_center; - const T para = dot(point, m_axis); + const T para = dot(point, m_axis); const Vec3T ortho = point - para * m_axis; // Distance from cylinder axis. const T w = ortho.length() - m_radius; // Distance from cylinder wall. < 0 @@ -763,9 +759,9 @@ class InfiniteCylinderSDF : public SignedDistanceFunction */ InfiniteCylinderSDF(const Vec3T& a_center, const T& a_radius, const size_t a_axis, const bool a_flipInside) { - m_center = a_center; - m_radius = a_radius; - m_axis = a_axis; + m_center = a_center; + m_radius = a_radius; + m_axis = a_axis; m_flipInside = a_flipInside; } @@ -777,9 +773,9 @@ class InfiniteCylinderSDF : public SignedDistanceFunction signedDistance(const Vec3T& a_point) const noexcept override { Vec3T delta = a_point - m_center; - delta[m_axis] = 0.0; + delta[m_axis] = 0.0; - const T d = delta.length() - m_radius; + const T d = delta.length() - m_radius; const T sign = m_flipInside ? -1.0 : 1.0; return sign * d; @@ -830,10 +826,10 @@ class CapsuleSDF : public SignedDistanceFunction CapsuleSDF(const Vec3T& a_tip1, const Vec3T a_tip2, const T& a_radius, const bool a_flipInside) { const Vec3T axis = (a_tip2 - a_tip1) / length(a_tip2 - a_tip1); - m_center1 = a_tip1 + a_radius * axis; - m_center2 = a_tip2 - a_radius * axis; - m_radius = a_radius; - m_flipInside = a_flipInside; + m_center1 = a_tip1 + a_radius * axis; + m_center2 = a_tip2 - a_radius * axis; + m_radius = a_radius; + m_flipInside = a_flipInside; } /*! @@ -846,8 +842,8 @@ class CapsuleSDF : public SignedDistanceFunction const Vec3T v1 = a_point - m_center1; const Vec3T v2 = m_center2 - m_center1; - const T h = clamp(dot(v1, v2) / dot(v2, v2), T(0.0), T(1.0)); - const T d = length(v1 - h * v2) - m_radius; + const T h = clamp(dot(v1, v2) / dot(v2, v2), T(0.0), T(1.0)); + const T d = length(v1 - h * v2) - m_radius; const T sign = m_flipInside ? -1.0 : 1.0; return sign * d; @@ -897,9 +893,9 @@ class InfiniteConeSDF : public SignedDistanceFunction { constexpr T pi = 3.14159265358979323846; - m_tip = a_tip; - m_c.x = std::sin(0.5 * a_angle * pi / 180.0); - m_c.y = std::cos(0.5 * a_angle * pi / 180.0); + m_tip = a_tip; + m_c.x = std::sin(0.5 * a_angle * pi / 180.0); + m_c.y = std::cos(0.5 * a_angle * pi / 180.0); m_flipInside = a_flipInside; } @@ -966,10 +962,10 @@ class ConeSDF : public SignedDistanceFunction { constexpr T pi = 3.14159265358979323846; - m_tip = a_tip; - m_height = a_height; - m_c.x = std::sin(0.5 * a_angle * pi / 180.0); - m_c.y = std::cos(0.5 * a_angle * pi / 180.0); + m_tip = a_tip; + m_height = a_height; + m_c.x = std::sin(0.5 * a_angle * pi / 180.0); + m_c.y = std::cos(0.5 * a_angle * pi / 180.0); m_flipInside = a_flipInside; } @@ -986,11 +982,11 @@ class ConeSDF : public SignedDistanceFunction signedDistance(const Vec3T& a_point) const noexcept override { const Vec3T delta = a_point - m_tip; - const T dr = sqrt(delta[0] * delta[0] + delta[1] * delta[1]); - const T dz = delta[2]; + const T dr = sqrt(delta[0] * delta[0] + delta[1] * delta[1]); + const T dz = delta[2]; constexpr T zero = T(0.0); - constexpr T one = T(1.0); + constexpr T one = T(1.0); const Vec2T q = m_height * Vec2T(m_c.x / m_c.y, -1.0); const Vec2T w = Vec2T(dr, dz); @@ -999,9 +995,9 @@ class ConeSDF : public SignedDistanceFunction auto sign = [](const T& x) { return (x > zero) - (x < zero); }; - const T k = sign(q.y); - const T d = std::min(dot(a, a), dot(b, b)); - const T s = std::max(k * (w.x * q.y - w.y * q.x), k * (w.y - q.y)); + const T k = sign(q.y); + const T d = std::min(dot(a, a), dot(b, b)); + const T s = std::max(k * (w.x * q.y - w.y * q.x), k * (w.y - q.y)); const T flip = m_flipInside ? -one : one; return flip * sqrt(d) * sign(s); diff --git a/Source/EBGeometry_BVH.hpp b/Source/EBGeometry_BVH.hpp index cc58d3b8..6c01efd1 100644 --- a/Source/EBGeometry_BVH.hpp +++ b/Source/EBGeometry_BVH.hpp @@ -27,39 +27,39 @@ */ namespace BVH { -/*! + /*! @brief Forward declare the BVH node since it is needed for the polymorphic lambdas. @details T is the precision used in the BVH computations, P is the enclosing primitive and BV is the bounding volume used in the BVH. K is the tree degree. */ -template -class NodeT; + template + class NodeT; -/*! + /*! @brief Forward declare linear node class. @details T is the precision used in the BVH computations, P is the enclosing primitive and BV is the bounding volume used in the BVH. K is the tree degree. */ -template -class LinearNodeT; + template + class LinearNodeT; -/*! + /*! @brief Forward declare linear BVH class. @details T is the precision used in the BVH computations, P is the enclosing primitive and BV is the bounding volume used in the BVH. K is the tree degree. */ -template -class LinearBVH; + template + class LinearBVH; -/*! + /*! @brief Alias to cut down on typing. @details P is the primitive bounded by the BVH. */ -template -using PrimitiveListT = std::vector>; + template + using PrimitiveListT = std::vector>; -/*! + /*! @brief Stop function for deciding when a BVH node can't be divided into sub-volumes. @details T is the precision used in the BVH computations, P is the enclosing @@ -67,10 +67,10 @@ using PrimitiveListT = std::vector>; @param[in] a_node BVH node @return True if the node can't be divided into subvolumes and false otherwise. */ -template -using StopFunctionT = std::function& a_node)>; + template + using StopFunctionT = std::function& a_node)>; -/*! + /*! @brief Polymorphic partitioner for splitting a list of primitives into K new lists of primitives @details P is the primitive type bound in the BVH and K is the BVH degree. @@ -79,10 +79,10 @@ using StopFunctionT = std::function& a_node)>; @return Returns a list (std::array) of new primitives which make up the new bounding volumes. */ -template -using PartitionerT = std::function, K>(const PrimitiveListT

& a_primitives)>; + template + using PartitionerT = std::function, K>(const PrimitiveListT

& a_primitives)>; -/*! + /*! @brief Constructor method for creating bounding volumes from a list of primitives @details P is the primitive type bound in the BVH and BV is the bounding @@ -91,24 +91,24 @@ using PartitionerT = std::function, K>(const Primit @return Returns a new bounding volumes which is guaranteed to enclose all the input primitives. */ -template -using BVConstructorT = std::function& a_primitive)>; + template + using BVConstructorT = std::function& a_primitive)>; -/*! + /*! @brief Typename for identifying algorithms various algorithms during tree traversel. @details Stack => Use stack/priority queue (ordered traversal). Ordered => Use recursive ordered traversal. Unordered => Use recursive unordered traversal. */ -enum class Prune -{ - Stack, - Ordered, - Unordered, -}; + enum class Prune + { + Stack, + Ordered, + Unordered, + }; -/*! + /*! @brief Class which encapsulates a node in a bounding volume hierarchy. @details T is the precision, P is the primitive type you want to enclose, BV is the bounding volume type used at the nodes. The parameter K (which must be @@ -121,71 +121,71 @@ enum class Prune Had this been C++20, we would have use concepts to enforce this. */ -template -class NodeT : public SignedDistanceFunction -{ -public: - /*! + template + class NodeT : public SignedDistanceFunction + { + public: + /*! @brief Alias for cutting down on typing. This is a std::vector >. */ - using PrimitiveList = PrimitiveListT

; + using PrimitiveList = PrimitiveListT

; - /*! + /*! @brief Alias for cutting down on typing. */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Alias for cutting down on typing. */ - using Node = NodeT; + using Node = NodeT; - /*! + /*! @brief Alias for cutting down on typing. */ - using NodePtr = std::shared_ptr; + using NodePtr = std::shared_ptr; - /*! + /*! @brief Alias for cutting down on typing. */ - using StopFunction = StopFunctionT; + using StopFunction = StopFunctionT; - /*! + /*! @brief Alias for cutting down on typing */ - using Partitioner = PartitionerT; + using Partitioner = PartitionerT; - /*! + /*! @brief Alias for cutting down on typing. */ - using BVConstructor = BVConstructorT; + using BVConstructor = BVConstructorT; - /*! + /*! @brief Default constructor which sets a regular node. */ - NodeT(); + NodeT(); - /*! + /*! @brief Construct node from a set of primitives. @details This node becomes a leaf node which contains the input primitives. @param[in] a_primitives Input primitives. */ - NodeT(const std::vector>& a_primitives); + NodeT(const std::vector>& a_primitives); - /*! + /*! @brief Construct node from a set of primitives. @details This node becomes a leaf node which contains the input primitives. @param[in] a_primitives Input primitives. */ - NodeT(const std::vector>& a_primitives); + NodeT(const std::vector>& a_primitives); - /*! + /*! @brief Destructor (does nothing) */ - virtual ~NodeT(); + virtual ~NodeT(); - /*! + /*! @brief Function for using top-down construction of the bounding volume hierarchy. @details The rules for terminating the hierarchy construction, how to @@ -198,142 +198,143 @@ class NodeT : public SignedDistanceFunction @param[in] a_stopCrit Termination function which tells us when to stop the recursion. */ - inline void - topDownSortAndPartitionPrimitives( - const BVConstructor& a_bvConstructor, const Partitioner& a_partitioner, const StopFunction& a_stopCrit) noexcept; + inline void + topDownSortAndPartitionPrimitives(const BVConstructor& a_bvConstructor, + const Partitioner& a_partitioner, + const StopFunction& a_stopCrit) noexcept; - /*! + /*! @brief Get node type */ - inline bool - isLeaf() const noexcept; + inline bool + isLeaf() const noexcept; - /*! + /*! @brief Get the primitives stored in this node. @return m_primitives. */ - inline const PrimitiveList& - getPrimitives() const noexcept; + inline const PrimitiveList& + getPrimitives() const noexcept; - /*! + /*! @brief Get bounding volume @return m_bv */ - inline const BV& - getBoundingVolume() const noexcept; + inline const BV& + getBoundingVolume() const noexcept; - /*! + /*! @brief Return this node's children. @return m_children. */ - inline const std::array>, K>& - getChildren() const noexcept; + inline const std::array>, K>& + getChildren() const noexcept; - /*! + /*! @brief Function which computes the signed distance @param[in] a_point 3D point in space @return Signed distance to the input point. */ - inline T - signedDistance(const Vec3T& a_point) const noexcept override; + inline T + signedDistance(const Vec3T& a_point) const noexcept override; - /*! + /*! @brief Function which computes the signed distance. This version allows the user to manually select a traversal algorithm. @param[in] a_point 3D point in space @param[in] a_pruning Pruning algorithm @return Signed distance to the input point. */ - inline T - signedDistance(const Vec3T& a_point, const Prune a_pruning) const noexcept; + inline T + signedDistance(const Vec3T& a_point, const Prune a_pruning) const noexcept; - /*! + /*! @brief Flatten everything beneath this node into a depth-first sorted BVH hierarchy. @details This will compute the flattening of the standard BVH tree and return a pointer to the linear corresponding to the current node. */ - inline std::shared_ptr> - flattenTree() const noexcept; + inline std::shared_ptr> + flattenTree() const noexcept; -protected: - /*! + protected: + /*! @brief Bounding volume object. */ - BV m_boundingVolume; + BV m_boundingVolume; - /*! + /*! @brief Primitives list. This will be empty for regular nodes */ - std::vector> m_primitives; + std::vector> m_primitives; - /*! + /*! @brief Children nodes */ - std::array>, K> m_children; + std::array>, K> m_children; - /*! + /*! @brief Insert nodes with primitives. @param[in] a_primitives Primitives for children. */ - inline void - insertChildren(const std::array& a_primitives) noexcept; + inline void + insertChildren(const std::array& a_primitives) noexcept; - /*! + /*! @brief Set primitives in this node @param[in] a_primitives Primitives */ - inline void - setPrimitives(const PrimitiveList& a_primitives) noexcept; + inline void + setPrimitives(const PrimitiveList& a_primitives) noexcept; - /*! + /*! @brief Get the distance from a 3D point to the bounding volume @param[in] a_point 3D point @return Returns distance to bounding volume. A zero distance implies that the input point is inside the bounding volume. */ - inline T - getDistanceToBoundingVolume(const Vec3& a_point) const noexcept; + inline T + getDistanceToBoundingVolume(const Vec3& a_point) const noexcept; - /*! + /*! @brief Compute the shortest distance to the primitives in this node. @param[in] a_point 3D point @return Returns the signed distance to the primitives. */ - inline T - getDistanceToPrimitives(const Vec3& a_point) const noexcept; + inline T + getDistanceToPrimitives(const Vec3& a_point) const noexcept; - /*! + /*! @brief Get the list of primitives in this node. @return Primitives list */ - inline PrimitiveList& - getPrimitives() noexcept; + inline PrimitiveList& + getPrimitives() noexcept; - /*! + /*! @brief Iterative ordered pruning along the BVH tree. @param[in,out] a_point Input 3D point */ - inline T - pruneStack(const Vec3& a_point) const noexcept; + inline T + pruneStack(const Vec3& a_point) const noexcept; - /*! + /*! @brief Recursively ordered pruning along the BVH tree. @param[in,out] a_closest Shortest distance to primitives so far. @param[in,out] a_point Input 3D point */ - inline void - pruneOrdered(T& a_closest, const Vec3& a_point) const noexcept; + inline void + pruneOrdered(T& a_closest, const Vec3& a_point) const noexcept; - /*! + /*! @brief Recursive unordered pruning along the BVH tree. @param[in,out] a_closest Shortest distance to primitives so far. @param[in,out] a_point Input 3D point */ - inline void - pruneUnordered(T& a_closest, const Vec3& a_point) const noexcept; + inline void + pruneUnordered(T& a_closest, const Vec3& a_point) const noexcept; - /*! + /*! @brief Flatten tree method. @details This function will flatten everything beneath the current node and linearize all the nodes and primitives beneath it to a_linearNodes and @@ -345,14 +346,13 @@ class NodeT : public SignedDistanceFunction @note When called from the root node, a_linearNodes and a_sortedPrimitives should be empty and a_offset=0UL. */ - inline size_t - flattenTree( - std::vector>>& a_linearNodes, - std::vector>& a_sortedPrimitives, - size_t& a_offset) const noexcept; -}; + inline size_t + flattenTree(std::vector>>& a_linearNodes, + std::vector>& a_sortedPrimitives, + size_t& a_offset) const noexcept; + }; -/*! + /*! @brief Node type for linearized (flattened) BVH. This will be constructed from the other (conventional) BVH type. @@ -382,198 +382,196 @@ class NodeT : public SignedDistanceFunction storage, which would mean that a double-precision binary tree only takes up one word of CPU memory. */ -template -class LinearNodeT -{ -public: - /*! + template + class LinearNodeT + { + public: + /*! @brief Alias for cutting down on typing. */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Constructor. */ - inline LinearNodeT() noexcept; + inline LinearNodeT() noexcept; - /*! + /*! @brief Destructor. */ - inline virtual ~LinearNodeT(); + inline virtual ~LinearNodeT(); - /*! + /*! @brief Set the bounding volume @param[in] a_boundingVolume Bounding volume for this node. */ - inline void - setBoundingVolume(const BV& a_boundingVolume) noexcept; + inline void + setBoundingVolume(const BV& a_boundingVolume) noexcept; - /*! + /*! @brief Set the offset into the primitives array. */ - inline void - setPrimitivesOffset(const size_t a_primitivesOffset) noexcept; + inline void + setPrimitivesOffset(const size_t a_primitivesOffset) noexcept; - /*! + /*! @brief Set number of primitives. @param[in] a_numPrimitives Number of primitives. */ - inline void - setNumPrimitives(const size_t a_numPrimitives) noexcept; + inline void + setNumPrimitives(const size_t a_numPrimitives) noexcept; - /*! + /*! @brief Set the child offsets. @param[in] a_childOffset Offset in node array. @param[in] a_whichChild Child index in m_childrenOffsets. Must be [0,K-1] */ - inline void - setChildOffset(const size_t a_childOffset, const size_t a_whichChild) noexcept; + inline void + setChildOffset(const size_t a_childOffset, const size_t a_whichChild) noexcept; - /*! + /*! @brief Get the node bounding volume. return m_boundingVolume */ - inline const BV& - getBoundingVolume() const noexcept; + inline const BV& + getBoundingVolume() const noexcept; - /*! + /*! @brief Get the primitives offset @return Returns m_primitivesOffset */ - inline const size_t& - getPrimitivesOffset() const noexcept; + inline const size_t& + getPrimitivesOffset() const noexcept; - /*! + /*! @brief Get the number of primitives. @return Returns m_numPrimitives */ - inline const size_t& - getNumPrimitives() const noexcept; + inline const size_t& + getNumPrimitives() const noexcept; - /*! + /*! @brief Get the child offsets @return Returns m_childOffsets */ - inline const std::array& - getChildOffsets() const noexcept; + inline const std::array& + getChildOffsets() const noexcept; - /*! + /*! @brief Is leaf or not */ - inline bool - isLeaf() const noexcept; + inline bool + isLeaf() const noexcept; - /*! + /*! @brief Get the distance from a 3D point to the bounding volume @param[in] a_point 3D point @return Returns distance to bounding volume. A zero distance implies that the input point is inside the bounding volume. */ - inline T - getDistanceToBoundingVolume(const Vec3& a_point) const noexcept; + inline T + getDistanceToBoundingVolume(const Vec3& a_point) const noexcept; - /*! + /*! @brief Compute signed distance to primitives. @param[in] a_point Point @param[in] a_primitives List of primitives @note Only call if this is a leaf node. */ - inline T - getDistanceToPrimitives( - const Vec3& a_point, const std::vector>& a_primitives) const noexcept; + inline T + getDistanceToPrimitives(const Vec3& a_point, + const std::vector>& a_primitives) const noexcept; -protected: - /*! + protected: + /*! @brief Bounding volume. */ - BV m_boundingVolume; + BV m_boundingVolume; - /*! + /*! @brief Offset into primitives array */ - size_t m_primitivesOffset; + size_t m_primitivesOffset; - /*! + /*! @brief Number of primitives */ - size_t m_numPrimitives; + size_t m_numPrimitives; - /*! + /*! @brief Offset to child nodes. */ - std::array m_childOffsets; -}; + std::array m_childOffsets; + }; -/*! + /*! @brief Linear root node for BVH hierarchy */ -template -class LinearBVH : public SignedDistanceFunction -{ -public: - /*! + template + class LinearBVH : public SignedDistanceFunction + { + public: + /*! @brief Cut down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Alias for cutting down on typing */ - using LinearNode = LinearNodeT; + using LinearNode = LinearNodeT; - /*! + /*! @brief List of primitives */ - using PrimitiveList = std::vector>; + using PrimitiveList = std::vector>; - /*! + /*! @brief Disallowed. Use the full constructor please. */ - LinearBVH() = delete; + LinearBVH() = delete; - /*! + /*! @brief Full constructor. Associates the nodes and primitives. @param[in] a_linearNodes Linearized BVH nodes. @param[in] a_primitives Primitives. */ - inline LinearBVH( - const std::vector>>& a_linearNodes, - const std::vector>& a_primitives); + inline LinearBVH(const std::vector>>& a_linearNodes, + const std::vector>& a_primitives); - /*! + /*! @brief Full constructor. Associates the nodes and primitives. @param[in] a_linearNodes Linearized BVH nodes. @param[in] a_primitives Primitives. */ - inline LinearBVH( - const std::vector>>& a_linearNodes, - const std::vector>& a_primitives); + inline LinearBVH(const std::vector>>& a_linearNodes, + const std::vector>& a_primitives); - /*! + /*! @brief Destructor. Does nothing */ - inline virtual ~LinearBVH(); + inline virtual ~LinearBVH(); - /*! + /*! @brief Function which computes the signed distance. This calls the other version. @param[in] a_point 3D point in space */ - inline T - signedDistance(const Vec3& a_point) const noexcept override; + inline T + signedDistance(const Vec3& a_point) const noexcept override; -protected: - /*! + protected: + /*! @brief List of linearly stored nodes */ - std::vector>> m_linearNodes; + std::vector>> m_linearNodes; - /*! + /*! @brief Global list of primitives. Note that this is ALL primitives, sorted so that LinearNodeT can interface into it. */ - std::vector> m_primitives; -}; + std::vector> m_primitives; + }; } // namespace BVH #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_BVHImplem.hpp b/Source/EBGeometry_BVHImplem.hpp index 3ec50871..4e78926f 100644 --- a/Source/EBGeometry_BVHImplem.hpp +++ b/Source/EBGeometry_BVHImplem.hpp @@ -21,617 +21,614 @@ namespace BVH { -template -inline NodeT::NodeT() -{ - for (auto& c : m_children) { - c = nullptr; - } - - m_primitives.resize(0); -} - -template -inline NodeT::NodeT(const std::vector>& a_primitives) : NodeT() -{ - for (const auto& p : a_primitives) { - m_primitives.emplace_back(p); - } - - for (auto& c : m_children) { - c = nullptr; - } -} - -template -inline NodeT::NodeT(const std::vector>& a_primitives) : NodeT() -{ - m_primitives = a_primitives; - - for (auto& c : m_children) { - c = nullptr; - } -} - -template -inline NodeT::~NodeT() -{ -} - -template -inline void -NodeT::setPrimitives(const PrimitiveList& a_primitives) noexcept -{ - m_primitives = a_primitives; -} - -template -inline bool -NodeT::isLeaf() const noexcept -{ - return m_primitives.size() > 0; -} - -template -inline PrimitiveListT

& -NodeT::getPrimitives() noexcept -{ - return (m_primitives); -} - -template -inline const PrimitiveListT

& -NodeT::getPrimitives() const noexcept -{ - return (m_primitives); -} - -template -inline const BV& -NodeT::getBoundingVolume() const noexcept -{ - return (m_boundingVolume); -} - -template -inline const std::array>, K>& -NodeT::getChildren() const noexcept -{ - return (m_children); -} - -template -inline void -NodeT::topDownSortAndPartitionPrimitives( - const BVConstructor& a_bvConstructor, const Partitioner& a_partitioner, const StopFunction& a_stopCrit) noexcept -{ - - // Compute the bounding volume for this node. - std::vector boundingVolumes; - for (const auto& p : m_primitives) { - boundingVolumes.emplace_back(a_bvConstructor(p)); - } - - m_boundingVolume = BV(boundingVolumes); - - // Check if we can split this node into sub-bounding volumes. - const bool stopRecursiveSplitting = a_stopCrit(*this); - const bool hasEnoughPrimitives = m_primitives.size() >= K; - - if (!stopRecursiveSplitting && hasEnoughPrimitives) { - - // Divide primitives into new partitions - const auto& newPartitions = a_partitioner(m_primitives); // Divide this node's primitives into K new - // sub-volume primitives - this->insertChildren(newPartitions); // Insert the K new nodes into the tree. - - m_primitives.resize(0); // This node is no longer a leaf node. + template + inline NodeT::NodeT() + { + for (auto& c : m_children) { + c = nullptr; + } + + m_primitives.resize(0); + } + + template + inline NodeT::NodeT(const std::vector>& a_primitives) : NodeT() + { + for (const auto& p : a_primitives) { + m_primitives.emplace_back(p); + } - // Partition children nodes further for (auto& c : m_children) { - c->topDownSortAndPartitionPrimitives(a_bvConstructor, a_partitioner, a_stopCrit); + c = nullptr; } } -} -template -inline void -NodeT::insertChildren(const std::array& a_primitives) noexcept -{ - for (size_t l = 0; l < K; l++) { - m_children[l] = std::make_shared>(); + template + inline NodeT::NodeT(const std::vector>& a_primitives) : NodeT() + { + m_primitives = a_primitives; - m_children[l]->setPrimitives(a_primitives[l]); + for (auto& c : m_children) { + c = nullptr; + } } -} -template -inline T -NodeT::getDistanceToBoundingVolume(const Vec3& a_point) const noexcept -{ - return m_boundingVolume.getDistance(a_point); -} + template + inline NodeT::~NodeT() + {} -template -inline T -NodeT::getDistanceToPrimitives(const Vec3& a_point) const noexcept -{ - T minDist = std::numeric_limits::infinity(); + template + inline void + NodeT::setPrimitives(const PrimitiveList& a_primitives) noexcept + { + m_primitives = a_primitives; + } - for (const auto& p : m_primitives) { - const auto curDist = p->signedDistance(a_point); + template + inline bool + NodeT::isLeaf() const noexcept + { + return m_primitives.size() > 0; + } - if (curDist * curDist < minDist * minDist) { - minDist = curDist; - } + template + inline PrimitiveListT

& + NodeT::getPrimitives() noexcept + { + return (m_primitives); } - return minDist; -} + template + inline const PrimitiveListT

& + NodeT::getPrimitives() const noexcept + { + return (m_primitives); + } + + template + inline const BV& + NodeT::getBoundingVolume() const noexcept + { + return (m_boundingVolume); + } -template -inline T -NodeT::signedDistance(const Vec3& a_point) const noexcept -{ - return this->signedDistance(a_point, Prune::Stack); -} + template + inline const std::array>, K>& + NodeT::getChildren() const noexcept + { + return (m_children); + } + + template + inline void + NodeT::topDownSortAndPartitionPrimitives(const BVConstructor& a_bvConstructor, + const Partitioner& a_partitioner, + const StopFunction& a_stopCrit) noexcept + { + + // Compute the bounding volume for this node. + std::vector boundingVolumes; + for (const auto& p : m_primitives) { + boundingVolumes.emplace_back(a_bvConstructor(p)); + } -template -inline T -NodeT::signedDistance(const Vec3& a_point, const Prune a_pruning) const noexcept -{ - T ret = std::numeric_limits::infinity(); + m_boundingVolume = BV(boundingVolumes); - switch (a_pruning) { - case Prune::Stack: { - ret = this->pruneStack(a_point); + // Check if we can split this node into sub-bounding volumes. + const bool stopRecursiveSplitting = a_stopCrit(*this); + const bool hasEnoughPrimitives = m_primitives.size() >= K; - break; + if (!stopRecursiveSplitting && hasEnoughPrimitives) { + + // Divide primitives into new partitions + const auto& newPartitions = a_partitioner(m_primitives); // Divide this node's primitives into K new + // sub-volume primitives + this->insertChildren(newPartitions); // Insert the K new nodes into the tree. + + m_primitives.resize(0); // This node is no longer a leaf node. + + // Partition children nodes further + for (auto& c : m_children) { + c->topDownSortAndPartitionPrimitives(a_bvConstructor, a_partitioner, a_stopCrit); + } + } } - case Prune::Ordered: { - this->pruneOrdered(ret, a_point); - break; + template + inline void + NodeT::insertChildren(const std::array& a_primitives) noexcept + { + for (size_t l = 0; l < K; l++) { + m_children[l] = std::make_shared>(); + + m_children[l]->setPrimitives(a_primitives[l]); + } } - case Prune::Unordered: { - this->pruneUnordered(ret, a_point); - break; + template + inline T + NodeT::getDistanceToBoundingVolume(const Vec3& a_point) const noexcept + { + return m_boundingVolume.getDistance(a_point); } - default: - std::cerr << "In file EBGeometry_BVHImplem.hpp function NodeT::signedDistance(Vec3, Prune) -- bad input enum for 'Prune'\n"; - }; - return ret; -} + template + inline T + NodeT::getDistanceToPrimitives(const Vec3& a_point) const noexcept + { + T minDist = std::numeric_limits::infinity(); -template -inline T -NodeT::pruneStack(const Vec3& a_point) const noexcept -{ - // TLDR: This routine uses ordered traversal along the branches. Rather than - // calling itself recursively, it uses - // a stack for investigating the branches and nodes. + for (const auto& p : m_primitives) { + const auto curDist = p->signedDistance(a_point); - // Shortest distance. Initialize to something big. - T minDist = std::numeric_limits::infinity(); + if (curDist * curDist < minDist * minDist) { + minDist = curDist; + } + } - // Create temporary storage and and priority queue (our stack). - using RawNode = const NodeT*; - using NodeAndDist = std::pair; + return minDist; + } - std::array childrenAndDistances; - std::stack q; + template + inline T + NodeT::signedDistance(const Vec3& a_point) const noexcept + { + return this->signedDistance(a_point, Prune::Stack); + } - // Initialize the stack with the root node. - q.emplace(this, this->getDistanceToBoundingVolume(a_point)); + template + inline T + NodeT::signedDistance(const Vec3& a_point, const Prune a_pruning) const noexcept + { + T ret = std::numeric_limits::infinity(); - // Stack loop -- always investigate the one at the top. - while (!(q.empty())) { + switch (a_pruning) { + case Prune::Stack: { + ret = this->pruneStack(a_point); - // Pop the top node off the stack. - const auto& curNode = (q.top()).first; - const auto& bvDist = (q.top()).second; + break; + } + case Prune::Ordered: { + this->pruneOrdered(ret, a_point); + + break; + } + case Prune::Unordered: { + this->pruneUnordered(ret, a_point); - q.pop(); + break; + } + default: + std::cerr << "In file EBGeometry_BVHImplem.hpp function NodeT::signedDistance(Vec3, Prune) -- bad input enum for 'Prune'\n"; + }; - // See if we really need to process this node. We only need to do it if its - // BV is closer than the shortest distance we've found so far. Otherwise we - // are guaranteed that the distance to the primitives is larger than the - // shortest distance we've found so far. If the current node is a leaf node - // we just update the shortest distance. Otherwise we fetch the child nodes - // and process them (in a very specific order!). - if (bvDist <= std::abs(minDist)) { - if (curNode->isLeaf()) { - const T primDist = curNode->getDistanceToPrimitives(a_point); + return ret; + } - if (std::abs(primDist) < std::abs(minDist)) { - minDist = primDist; + template + inline T + NodeT::pruneStack(const Vec3& a_point) const noexcept + { + // TLDR: This routine uses ordered traversal along the branches. Rather than + // calling itself recursively, it uses + // a stack for investigating the branches and nodes. + + // Shortest distance. Initialize to something big. + T minDist = std::numeric_limits::infinity(); + + // Create temporary storage and and priority queue (our stack). + using RawNode = const NodeT*; + using NodeAndDist = std::pair; + + std::array childrenAndDistances; + std::stack q; + + // Initialize the stack with the root node. + q.emplace(this, this->getDistanceToBoundingVolume(a_point)); + + // Stack loop -- always investigate the one at the top. + while (!(q.empty())) { + + // Pop the top node off the stack. + const auto& curNode = (q.top()).first; + const auto& bvDist = (q.top()).second; + + q.pop(); + + // See if we really need to process this node. We only need to do it if its + // BV is closer than the shortest distance we've found so far. Otherwise we + // are guaranteed that the distance to the primitives is larger than the + // shortest distance we've found so far. If the current node is a leaf node + // we just update the shortest distance. Otherwise we fetch the child nodes + // and process them (in a very specific order!). + if (bvDist <= std::abs(minDist)) { + if (curNode->isLeaf()) { + const T primDist = curNode->getDistanceToPrimitives(a_point); + + if (std::abs(primDist) < std::abs(minDist)) { + minDist = primDist; + } } - } - else { - // If it's a regular node, sort the child nodes and put them on the - // stack. On the next iteration we do the closest node first. This - // sorting is critical to the performance of the BVH. + else { + // If it's a regular node, sort the child nodes and put them on the + // stack. On the next iteration we do the closest node first. This + // sorting is critical to the performance of the BVH. - // Get the nodes's children. - const std::array& children = curNode->getChildren(); + // Get the nodes's children. + const std::array& children = curNode->getChildren(); - for (size_t k = 0; k < K; k++) { - const RawNode& child = &(*children[k]); + for (size_t k = 0; k < K; k++) { + const RawNode& child = &(*children[k]); - childrenAndDistances[k] = std::make_pair(child, child->getDistanceToBoundingVolume(a_point)); - } + childrenAndDistances[k] = std::make_pair(child, child->getDistanceToBoundingVolume(a_point)); + } - std::sort( - childrenAndDistances.begin(), childrenAndDistances.end(), - [](const NodeAndDist& node1, const NodeAndDist& node2) -> bool { return node1.second > node2.second; }); + std::sort( + childrenAndDistances.begin(), + childrenAndDistances.end(), + [](const NodeAndDist& node1, const NodeAndDist& node2) -> bool { return node1.second > node2.second; }); - // Push the children onto the stack. - for (const auto& child : childrenAndDistances) { - q.push(child); + // Push the children onto the stack. + for (const auto& child : childrenAndDistances) { + q.push(child); + } } } } - } - return minDist; -} - -template -inline void -NodeT::pruneOrdered(T& a_shortestDistanceSoFar, const Vec3& a_point) const noexcept -{ - - // TLDR: Beginning at some node, this routine descends the branches in the - // tree. It always descends the branch with the shortest distance - // to the bounding volume first. The other branch is investigated only - // after the full sub-tree beneath the first branch has completed. Since - // the shortest distance to primitives is updated underway, there is a - // decent chance that the secondary subtree can be pruned. Hence why - // this routine is more efficient than prunedUnordered. - if (this->isLeaf()) { - // Compute the shortest signed distance to the primitives in this leaf node. - // If this is shorter than a_shortestDistanceSoFar, update it. Recall that - // the comparison requires the absolute value since we're doing the SIGNED - // distance. - const T primDist = this->getDistanceToPrimitives(a_point); - - if (std::abs(primDist) < std::abs(a_shortestDistanceSoFar)) { - a_shortestDistanceSoFar = primDist; - } + return minDist; } - else { - // In this case we need to decide which subtree to move down. First, sort - // the children nodes by the distance between a_point and the children - // node's bounding volume. Shortest distance goes first. - std::array, K> distancesAndNodes; - for (size_t i = 0; i < K; i++) { - distancesAndNodes[i] = std::make_pair(m_children[i]->getDistanceToBoundingVolume(a_point), m_children[i]); + + template + inline void + NodeT::pruneOrdered(T& a_shortestDistanceSoFar, const Vec3& a_point) const noexcept + { + + // TLDR: Beginning at some node, this routine descends the branches in the + // tree. It always descends the branch with the shortest distance + // to the bounding volume first. The other branch is investigated only + // after the full sub-tree beneath the first branch has completed. Since + // the shortest distance to primitives is updated underway, there is a + // decent chance that the secondary subtree can be pruned. Hence why + // this routine is more efficient than prunedUnordered. + if (this->isLeaf()) { + // Compute the shortest signed distance to the primitives in this leaf node. + // If this is shorter than a_shortestDistanceSoFar, update it. Recall that + // the comparison requires the absolute value since we're doing the SIGNED + // distance. + const T primDist = this->getDistanceToPrimitives(a_point); + + if (std::abs(primDist) < std::abs(a_shortestDistanceSoFar)) { + a_shortestDistanceSoFar = primDist; + } } + else { + // In this case we need to decide which subtree to move down. First, sort + // the children nodes by the distance between a_point and the children + // node's bounding volume. Shortest distance goes first. + std::array, K> distancesAndNodes; + for (size_t i = 0; i < K; i++) { + distancesAndNodes[i] = std::make_pair(m_children[i]->getDistanceToBoundingVolume(a_point), m_children[i]); + } - // Comparator for sorting -- puts the node with the shortest distance to the - // bounding volume at the front of the vector. - auto comparator = [](const std::pair& a_node1, const std::pair& a_node2) -> bool { - return std::abs(a_node1.first) < std::abs(a_node2.first); - }; + // Comparator for sorting -- puts the node with the shortest distance to the + // bounding volume at the front of the vector. + auto comparator = [](const std::pair& a_node1, const std::pair& a_node2) -> bool { + return std::abs(a_node1.first) < std::abs(a_node2.first); + }; - std::sort(distancesAndNodes.begin(), distancesAndNodes.end(), comparator); + std::sort(distancesAndNodes.begin(), distancesAndNodes.end(), comparator); - // Go through the children nodes -- closest node goes first. We prune - // branches if the distance to the node's bounding volume is longer than the - // shortest distance we've found so far. - for (size_t i = 0; i < K; i++) { - const std::pair& curChildNode = distancesAndNodes[i]; + // Go through the children nodes -- closest node goes first. We prune + // branches if the distance to the node's bounding volume is longer than the + // shortest distance we've found so far. + for (size_t i = 0; i < K; i++) { + const std::pair& curChildNode = distancesAndNodes[i]; + + // a_shortestDistanceSoFar is the SIGNED distance, so we need the absolute + // value here. + if (std::abs(curChildNode.first) <= std::abs(a_shortestDistanceSoFar)) { + curChildNode.second->pruneOrdered(a_shortestDistanceSoFar, a_point); + } + else { // Prune the rest of the children nodes. + break; + } + } + } + } - // a_shortestDistanceSoFar is the SIGNED distance, so we need the absolute - // value here. - if (std::abs(curChildNode.first) <= std::abs(a_shortestDistanceSoFar)) { - curChildNode.second->pruneOrdered(a_shortestDistanceSoFar, a_point); + template + inline void + NodeT::pruneUnordered(T& a_shortestDistanceSoFar, const Vec3& a_point) const noexcept + { + if (this->isLeaf()) { + // Check if the distance to the primitives in this leaf is shorter than + // a_shortestDistanceSoFar. If it is, update the shortest distance. + const T curSignedDistance = this->getDistanceToPrimitives(a_point); + + if (std::abs(curSignedDistance) < std::abs(a_shortestDistanceSoFar)) { + a_shortestDistanceSoFar = curSignedDistance; } - else { // Prune the rest of the children nodes. - break; + } + else { + // Investigate subtrees. Prune subtrees if the distance to their bounding + // volumes are longer than the shortest distance we've found so far. + for (const auto& child : m_children) { + const T distanceToChildBoundingVolume = child->getDistanceToBoundingVolume(a_point); + + if (std::abs(distanceToChildBoundingVolume) < std::abs(a_shortestDistanceSoFar)) { + child->pruneUnordered(a_shortestDistanceSoFar, a_point); + } } } } -} -template -inline void -NodeT::pruneUnordered(T& a_shortestDistanceSoFar, const Vec3& a_point) const noexcept -{ - if (this->isLeaf()) { - // Check if the distance to the primitives in this leaf is shorter than - // a_shortestDistanceSoFar. If it is, update the shortest distance. - const T curSignedDistance = this->getDistanceToPrimitives(a_point); + template + inline std::shared_ptr> + NodeT::flattenTree() const noexcept + { - if (std::abs(curSignedDistance) < std::abs(a_shortestDistanceSoFar)) { - a_shortestDistanceSoFar = curSignedDistance; - } + // Create a list of sorted primitives and nodes. + std::vector> sortedPrimitives; + std::vector>> linearNodes; + + // Track the offset into the linearized node array. + size_t offset = 0; + + // Flatten recursively. + this->flattenTree(linearNodes, sortedPrimitives, offset); + + // Return the root node. + return std::make_shared>(linearNodes, sortedPrimitives); } - else { - // Investigate subtrees. Prune subtrees if the distance to their bounding - // volumes are longer than the shortest distance we've found so far. - for (const auto& child : m_children) { - const T distanceToChildBoundingVolume = child->getDistanceToBoundingVolume(a_point); - if (std::abs(distanceToChildBoundingVolume) < std::abs(a_shortestDistanceSoFar)) { - child->pruneUnordered(a_shortestDistanceSoFar, a_point); + template + inline size_t + NodeT::flattenTree(std::vector>>& a_linearNodes, + std::vector>& a_sortedPrimitives, + size_t& a_offset) const noexcept + { + + // TLDR: This is the main routine for flattening the hierarchy beneath the + // current node. When this is called we insert + // this node into a_linearNodes and associate the array offsets so that + // we can find the children in the linearized array. + + // Current node we are dealing with. + const auto curNode = a_offset; + + // Insert a new node corresponding to this node and provide it with the + // current bounding volume. + a_linearNodes.emplace_back(std::make_shared>()); + a_linearNodes[curNode]->setBoundingVolume(m_boundingVolume); + + a_offset++; + + if (this->isLeaf()) { + // Insert primitives and offsets. + a_linearNodes[curNode]->setNumPrimitives(m_primitives.size()); + a_linearNodes[curNode]->setPrimitivesOffset(a_sortedPrimitives.size()); + + a_sortedPrimitives.insert(a_sortedPrimitives.end(), m_primitives.begin(), m_primitives.end()); + } + else { + a_linearNodes[curNode]->setNumPrimitives(0); + a_linearNodes[curNode]->setPrimitivesOffset(0UL); + + // Go through the children nodes and + for (size_t k = 0; k < K; k++) { + const size_t offset = m_children[k]->flattenTree(a_linearNodes, a_sortedPrimitives, a_offset); + + a_linearNodes[curNode]->setChildOffset(offset, k); } } - } -} -template -inline std::shared_ptr> -NodeT::flattenTree() const noexcept -{ + return curNode; + } - // Create a list of sorted primitives and nodes. - std::vector> sortedPrimitives; - std::vector>> linearNodes; + template + inline LinearNodeT::LinearNodeT() noexcept + { - // Track the offset into the linearized node array. - size_t offset = 0; + // Initialize everything. + m_boundingVolume = BV(); + m_primitivesOffset = 0UL; + m_numPrimitives = 0; - // Flatten recursively. - this->flattenTree(linearNodes, sortedPrimitives, offset); + for (auto& offset : m_childOffsets) { + offset = 0UL; + } + } - // Return the root node. - return std::make_shared>(linearNodes, sortedPrimitives); -} + template + inline LinearNodeT::~LinearNodeT() + {} -template -inline size_t -NodeT::flattenTree( - std::vector>>& a_linearNodes, - std::vector>& a_sortedPrimitives, - size_t& a_offset) const noexcept -{ + template + inline void + LinearNodeT::setBoundingVolume(const BV& a_boundingVolume) noexcept + { + m_boundingVolume = a_boundingVolume; + } - // TLDR: This is the main routine for flattening the hierarchy beneath the - // current node. When this is called we insert - // this node into a_linearNodes and associate the array offsets so that - // we can find the children in the linearized array. + template + inline void + LinearNodeT::setPrimitivesOffset(const size_t a_primitivesOffset) noexcept + { + m_primitivesOffset = a_primitivesOffset; + } - // Current node we are dealing with. - const auto curNode = a_offset; + template + inline void + LinearNodeT::setNumPrimitives(const size_t a_numPrimitives) noexcept + { + m_numPrimitives = a_numPrimitives; + } - // Insert a new node corresponding to this node and provide it with the - // current bounding volume. - a_linearNodes.emplace_back(std::make_shared>()); - a_linearNodes[curNode]->setBoundingVolume(m_boundingVolume); + template + inline void + LinearNodeT::setChildOffset(const size_t a_childOffset, const size_t a_whichChild) noexcept + { + m_childOffsets[a_whichChild] = a_childOffset; + } - a_offset++; + template + inline const BV& + LinearNodeT::getBoundingVolume() const noexcept + { + return (m_boundingVolume); + } - if (this->isLeaf()) { - // Insert primitives and offsets. - a_linearNodes[curNode]->setNumPrimitives(m_primitives.size()); - a_linearNodes[curNode]->setPrimitivesOffset(a_sortedPrimitives.size()); + template + inline const size_t& + LinearNodeT::getPrimitivesOffset() const noexcept + { + return (m_primitivesOffset); + } - a_sortedPrimitives.insert(a_sortedPrimitives.end(), m_primitives.begin(), m_primitives.end()); + template + inline const size_t& + LinearNodeT::getNumPrimitives() const noexcept + { + return (m_numPrimitives); } - else { - a_linearNodes[curNode]->setNumPrimitives(0); - a_linearNodes[curNode]->setPrimitivesOffset(0UL); - // Go through the children nodes and - for (size_t k = 0; k < K; k++) { - const size_t offset = m_children[k]->flattenTree(a_linearNodes, a_sortedPrimitives, a_offset); + template + inline const std::array& + LinearNodeT::getChildOffsets() const noexcept + { + return (m_childOffsets); + } - a_linearNodes[curNode]->setChildOffset(offset, k); - } + template + inline bool + LinearNodeT::isLeaf() const noexcept + { + return m_numPrimitives > 0; } - return curNode; -} - -template -inline LinearNodeT::LinearNodeT() noexcept -{ - - // Initialize everything. - m_boundingVolume = BV(); - m_primitivesOffset = 0UL; - m_numPrimitives = 0; - - for (auto& offset : m_childOffsets) { - offset = 0UL; - } -} - -template -inline LinearNodeT::~LinearNodeT() -{ -} - -template -inline void -LinearNodeT::setBoundingVolume(const BV& a_boundingVolume) noexcept -{ - m_boundingVolume = a_boundingVolume; -} - -template -inline void -LinearNodeT::setPrimitivesOffset(const size_t a_primitivesOffset) noexcept -{ - m_primitivesOffset = a_primitivesOffset; -} - -template -inline void -LinearNodeT::setNumPrimitives(const size_t a_numPrimitives) noexcept -{ - m_numPrimitives = a_numPrimitives; -} - -template -inline void -LinearNodeT::setChildOffset(const size_t a_childOffset, const size_t a_whichChild) noexcept -{ - m_childOffsets[a_whichChild] = a_childOffset; -} - -template -inline const BV& -LinearNodeT::getBoundingVolume() const noexcept -{ - return (m_boundingVolume); -} - -template -inline const size_t& -LinearNodeT::getPrimitivesOffset() const noexcept -{ - return (m_primitivesOffset); -} - -template -inline const size_t& -LinearNodeT::getNumPrimitives() const noexcept -{ - return (m_numPrimitives); -} - -template -inline const std::array& -LinearNodeT::getChildOffsets() const noexcept -{ - return (m_childOffsets); -} - -template -inline bool -LinearNodeT::isLeaf() const noexcept -{ - return m_numPrimitives > 0; -} - -template -inline T -LinearNodeT::getDistanceToBoundingVolume(const Vec3& a_point) const noexcept -{ - return m_boundingVolume.getDistance(a_point); -} - -template -inline T -LinearNodeT::getDistanceToPrimitives( - const Vec3T& a_point, const std::vector>& a_primitives) const noexcept -{ - T minDist = std::numeric_limits::infinity(); - - for (size_t i = 0; i < m_numPrimitives; i++) { - const T curDist = a_primitives[m_primitivesOffset + i]->signedDistance(a_point); - - if (std::abs(curDist) < std::abs(minDist)) { - minDist = curDist; - } + template + inline T + LinearNodeT::getDistanceToBoundingVolume(const Vec3& a_point) const noexcept + { + return m_boundingVolume.getDistance(a_point); } - return minDist; -} + template + inline T + LinearNodeT::getDistanceToPrimitives( + const Vec3T& a_point, const std::vector>& a_primitives) const noexcept + { + T minDist = std::numeric_limits::infinity(); + + for (size_t i = 0; i < m_numPrimitives; i++) { + const T curDist = a_primitives[m_primitivesOffset + i]->signedDistance(a_point); -template -inline LinearBVH::LinearBVH( - const std::vector>>& a_linearNodes, - const std::vector>& a_primitives) -{ - m_linearNodes = a_linearNodes; - m_primitives = a_primitives; -} + if (std::abs(curDist) < std::abs(minDist)) { + minDist = curDist; + } + } -template -inline LinearBVH::LinearBVH( - const std::vector>>& a_linearNodes, - const std::vector>& a_primitives) -{ + return minDist; + } - for (const auto& p : a_linearNodes) { - m_linearNodes.emplace_back(p); + template + inline LinearBVH::LinearBVH( + const std::vector>>& a_linearNodes, + const std::vector>& a_primitives) + { + m_linearNodes = a_linearNodes; + m_primitives = a_primitives; } - m_primitives = a_primitives; -} + template + inline LinearBVH::LinearBVH(const std::vector>>& a_linearNodes, + const std::vector>& a_primitives) + { -template -inline LinearBVH::~LinearBVH() -{ -} + for (const auto& p : a_linearNodes) { + m_linearNodes.emplace_back(p); + } -template -inline T -LinearBVH::signedDistance(const Vec3& a_point) const noexcept -{ - // TLDR: This routine uses ordered traversal along the branches. Rather than - // calling itself recursively, it uses - // a stack for investigating the branches and nodes. + m_primitives = a_primitives; + } - // Shortest unsigned square distance. Initialize to something big. - T minDist = std::numeric_limits::infinity(); + template + inline LinearBVH::~LinearBVH() + {} - // Create temporary storage and and priority queue (our stack). - using NodeAndDist = std::pair; + template + inline T + LinearBVH::signedDistance(const Vec3& a_point) const noexcept + { + // TLDR: This routine uses ordered traversal along the branches. Rather than + // calling itself recursively, it uses + // a stack for investigating the branches and nodes. - std::array children; - std::stack q; + // Shortest unsigned square distance. Initialize to something big. + T minDist = std::numeric_limits::infinity(); - // Initialize the stack with the root node. - q.emplace(0, m_linearNodes[0]->getDistanceToBoundingVolume(a_point)); + // Create temporary storage and and priority queue (our stack). + using NodeAndDist = std::pair; - // Stack loop -- always investigate the one at the top. - while (!(q.empty())) { + std::array children; + std::stack q; - // Pop the top node off the stack. - const auto& curNode = (q.top()).first; - const auto& bvDist = (q.top()).second; + // Initialize the stack with the root node. + q.emplace(0, m_linearNodes[0]->getDistanceToBoundingVolume(a_point)); - q.pop(); + // Stack loop -- always investigate the one at the top. + while (!(q.empty())) { - // See if we really need to process this node. We only need to do it if its - // BV is closer than the shortest distance we've found so far. Otherwise we - // are guaranteed that the distance to the primitives is larger than the - // shortest distance we've found so far. - if (bvDist <= std::abs(minDist)) { + // Pop the top node off the stack. + const auto& curNode = (q.top()).first; + const auto& bvDist = (q.top()).second; - // If it's a leaf node, update the shortest distance so far. - if (m_linearNodes[curNode]->isLeaf()) { - const T primDist = m_linearNodes[curNode]->getDistanceToPrimitives(a_point, m_primitives); + q.pop(); - if (std::abs(primDist) < std::abs(minDist)) { - minDist = primDist; - } - } - else { - // Compute child indices and their BVH distance to a_point. - for (size_t k = 0; k < K; k++) { - const size_t& curOff = m_linearNodes[curNode]->getChildOffsets()[k]; - const T distanceToBV = m_linearNodes[curOff]->getDistanceToBoundingVolume(a_point); + // See if we really need to process this node. We only need to do it if its + // BV is closer than the shortest distance we've found so far. Otherwise we + // are guaranteed that the distance to the primitives is larger than the + // shortest distance we've found so far. + if (bvDist <= std::abs(minDist)) { - children[k] = std::make_pair(curOff, distanceToBV); - } + // If it's a leaf node, update the shortest distance so far. + if (m_linearNodes[curNode]->isLeaf()) { + const T primDist = m_linearNodes[curNode]->getDistanceToPrimitives(a_point, m_primitives); - // Sort the child nodes and put them on the stack. On the next iteration - // we do the closest node first. This sorting is critical to the - // performance of the BVH. - std::sort( - children.begin(), children.end(), - [](const std::pair& node1, const std::pair& node2) -> bool { - return node1.second > node2.second; - }); - - // Push onto stack if the BV is closer than minDist. - for (const auto& child : children) { - q.push(child); + if (std::abs(primDist) < std::abs(minDist)) { + minDist = primDist; + } + } + else { + // Compute child indices and their BVH distance to a_point. + for (size_t k = 0; k < K; k++) { + const size_t& curOff = m_linearNodes[curNode]->getChildOffsets()[k]; + const T distanceToBV = m_linearNodes[curOff]->getDistanceToBoundingVolume(a_point); + + children[k] = std::make_pair(curOff, distanceToBV); + } + + // Sort the child nodes and put them on the stack. On the next iteration + // we do the closest node first. This sorting is critical to the + // performance of the BVH. + std::sort(children.begin(), + children.end(), + [](const std::pair& node1, const std::pair& node2) -> bool { + return node1.second > node2.second; + }); + + // Push onto stack if the BV is closer than minDist. + for (const auto& child : children) { + q.push(child); + } } } } - } - return minDist; -} + return minDist; + } } // namespace BVH #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_BoundingVolumes.hpp b/Source/EBGeometry_BoundingVolumes.hpp index da6f2417..faa53b2f 100644 --- a/Source/EBGeometry_BoundingVolumes.hpp +++ b/Source/EBGeometry_BoundingVolumes.hpp @@ -26,55 +26,55 @@ */ namespace BoundingVolumes { -/*! + /*! @brief Class which encloses a set of points using a bounding sphere. @details The template parameter T is the floating-point precision which is used. */ -template -class BoundingSphereT -{ -public: - /*! + template + class BoundingSphereT + { + public: + /*! @brief Typename for possible algorithms that support the computation of a bounding sphere for a set of 3D points. */ - enum class BoundingVolumeAlgorithm - { - Ritter, - }; + enum class BoundingVolumeAlgorithm + { + Ritter, + }; - /*! + /*! @brief Alias to cut down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Default constructor. Leaves object in undefined state. */ - BoundingSphereT(); + BoundingSphereT(); - /*! + /*! @brief Full constructor. Sets the center and radius of the bounding sphere. @param[in] a_center Bounding sphere center @param[in] a_radius Bounding sphere radius */ - BoundingSphereT(const Vec3T& a_center, const T& a_radius); + BoundingSphereT(const Vec3T& a_center, const T& a_radius); - /*! + /*! @brief Full constructor. Constructs a bounding sphere that encloses all the other bounding spheres @param[in] a_otherSpheres Other bounding spheres. */ - BoundingSphereT(const std::vector>& a_otherSpheres); + BoundingSphereT(const std::vector>& a_otherSpheres); - /*! + /*! @brief Copy constructor. Sets the center and radius from the other sphere. @param[in] a_other Other sphere */ - BoundingSphereT(const BoundingSphereT& a_other); + BoundingSphereT(const BoundingSphereT& a_other); - /*! + /*! @brief Template constructor which takes a set of 3D points (mixed precision allowed). @details This computes the bounding sphere using the supplied algorithm. @@ -82,303 +82,303 @@ class BoundingSphereT @param[in] a_alg Bounding sphere algorithm. @note This calls the define(...) function. */ - template - BoundingSphereT( - const std::vector>& a_points, const BoundingVolumeAlgorithm& a_alg = BoundingVolumeAlgorithm::Ritter); + template + BoundingSphereT(const std::vector>& a_points, + const BoundingVolumeAlgorithm& a_alg = BoundingVolumeAlgorithm::Ritter); - /*! + /*! @brief Destructor (does nothing). */ - virtual ~BoundingSphereT(); + virtual ~BoundingSphereT(); - /*! + /*! @brief Copy assignment operator @param[in] a_other Other sphere */ - BoundingSphereT& - operator=(const BoundingSphereT& a_other) = default; + BoundingSphereT& + operator=(const BoundingSphereT& a_other) = default; - /*! + /*! @brief Template define function which takes a set of 3D points (mixed precision allowed). @details This computes the bounding sphere using the supplied algorithm. @param[in] a_points Set of 3D points @param[in] a_alg Bounding sphere algorithm. */ - template - inline void - define(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_alg) noexcept; + template + inline void + define(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_alg) noexcept; - /*! + /*! @brief Check if this bounding sphere intersect another bounding sphere @param[in] a_other Other bounding sphere. @return True if the two sphere intersect. */ - inline bool - intersects(const BoundingSphereT& a_other) const noexcept; + inline bool + intersects(const BoundingSphereT& a_other) const noexcept; - /*! + /*! @brief Get modifiable radius for this sphere */ - inline T& - getRadius() noexcept; + inline T& + getRadius() noexcept; - /*! + /*! @brief Get immutable radius for this sphere */ - inline const T& - getRadius() const noexcept; + inline const T& + getRadius() const noexcept; - /*! + /*! @brief Get modifiable center for this sphere */ - inline Vec3& - getCentroid() noexcept; + inline Vec3& + getCentroid() noexcept; - /*! + /*! @brief Get immutable center for this sphere */ - inline const Vec3& - getCentroid() const noexcept; + inline const Vec3& + getCentroid() const noexcept; - /*! + /*! @brief Compute the overlapping volume between this bounding sphere and another @param[in] a_other Other bounding sphere @return The overlapping volume, computing using standard expressions. */ - inline T - getOverlappingVolume(const BoundingSphereT& a_other) const noexcept; + inline T + getOverlappingVolume(const BoundingSphereT& a_other) const noexcept; - /*! + /*! @brief Get the distance to this bounding sphere (points inside the sphere have a zero distance) @param[in] a_x0 3D point @return Returns the distance to the sphere (a point inside has a zero distance) */ - inline T - getDistance(const Vec3& a_x0) const noexcept; + inline T + getDistance(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Get the sphere volume @return Sphere volume */ - inline T - getVolume() const noexcept; + inline T + getVolume() const noexcept; - /*! + /*! @brief Get the sphere area @return Sphere area. */ - inline T - getArea() const noexcept; + inline T + getArea() const noexcept; -protected: - /*! + protected: + /*! @brief Sphere radius */ - T m_radius; + T m_radius; - /*! + /*! @brief Sphere center */ - Vec3 m_center; + Vec3 m_center; - /*! + /*! @brief Template function which computes the bounding sphere for a set of points (mixed precision allowed) using Ritter's algorithm */ - template - inline void - buildRitter(const std::vector>& a_points) noexcept; -}; + template + inline void + buildRitter(const std::vector>& a_points) noexcept; + }; -/*! + /*! @brief Axis-aligned bounding box as bounding volume @details This class represents a Cartesian box that encloses a set of 3D points. @note The template parameter T is the precision. */ -template -class AABBT -{ -public: - /*! + template + class AABBT + { + public: + /*! @brief Alias which cuts down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Default constructor (does nothing) */ - AABBT(); + AABBT(); - /*! + /*! @brief Full constructor taking the low/high corners of the bounding box @param[in] a_lo Low corner @param[in] a_hi High */ - AABBT(const Vec3T& a_lo, const Vec3T& a_hi); + AABBT(const Vec3T& a_lo, const Vec3T& a_hi); - /*! + /*! @brief Copy constructor of another bounding box @param[in] a_other Other bounding box */ - AABBT(const AABBT& a_other); + AABBT(const AABBT& a_other); - /*! + /*! @brief Constructor which creates an AABB which encloses a set of other AABBs. @param[in] a_others Other bounding boxes */ - AABBT(const std::vector>& a_others); + AABBT(const std::vector>& a_others); - /*! + /*! @brief Template constructor (since mixed precision allowed) which creates an AABB that encloses a set of 3D points @param[in] a_points Set of 3D points @note Calls the define function */ - template - AABBT(const std::vector>& a_points); + template + AABBT(const std::vector>& a_points); - /*! + /*! @brief Destructor (does nothing) */ - virtual ~AABBT(); + virtual ~AABBT(); - /*! + /*! @brief Copy assignment @param[in] a_other Other bounding box */ - AABBT& - operator=(const AABBT& a_other) = default; + AABBT& + operator=(const AABBT& a_other) = default; - /*! + /*! @brief Define function (since mixed precision allowed) which sets this AABB such that it encloses a set of 3D points @param[in] a_points Set of 3D points */ - template - inline void - define(const std::vector>& a_points) noexcept; + template + inline void + define(const std::vector>& a_points) noexcept; - /*! + /*! @brief Check if this AABB intersects another AABB @param[in] a_other The other AABB @return True if they intersect and false otherwise. */ - inline bool - intersects(const AABBT& a_other) const noexcept; + inline bool + intersects(const AABBT& a_other) const noexcept; - /*! + /*! @brief Get the modifiable lower-left corner of the AABB */ - inline Vec3T& - getLowCorner() noexcept; + inline Vec3T& + getLowCorner() noexcept; - /*! + /*! @brief Get the immutable lower-left corner of the AABB */ - inline const Vec3T& - getLowCorner() const noexcept; + inline const Vec3T& + getLowCorner() const noexcept; - /*! + /*! @brief Get the modifiable upper-right corner of the AABB */ - inline Vec3T& - getHighCorner() noexcept; + inline Vec3T& + getHighCorner() noexcept; - /*! + /*! @brief Get the immutable upper-right corner of the AABB */ - inline const Vec3T& - getHighCorner() const noexcept; + inline const Vec3T& + getHighCorner() const noexcept; - /*! + /*! @brief Get bounding volume centroid. */ - inline Vec3 - getCentroid() const noexcept; + inline Vec3 + getCentroid() const noexcept; - /*! + /*! @brief Compute the overlapping volume between this AABB and another AABB. @param[in] a_other The other AABB @return Returns overlapping volume */ - inline T - getOverlappingVolume(const AABBT& a_other) const noexcept; + inline T + getOverlappingVolume(const AABBT& a_other) const noexcept; - /*! + /*! @brief Get the distance to this AABB (points inside the bounding box have a zero distance) @param[in] a_x0 3D point @return Returns the distance to the bounding box (a point inside has a zero distance) */ - inline T - getDistance(const Vec3& a_x0) const noexcept; + inline T + getDistance(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Compute the bounding box volume */ - inline T - getVolume() const noexcept; + inline T + getVolume() const noexcept; - /*! + /*! @brief Compute the bounding box area */ - inline T - getArea() const noexcept; + inline T + getArea() const noexcept; -protected: - /*! + protected: + /*! @brief Lower-left corner of bounding box */ - Vec3 m_loCorner; + Vec3 m_loCorner; - /*! + /*! @brief Upper-right corner of bounding box */ - Vec3 m_hiCorner; -}; + Vec3 m_hiCorner; + }; -/*! + /*! @brief Intersection method for testing if two bounding spheres overlap @param[in] a_u One bounding sphere @param[in] a_v The other bounding sphere */ -template -bool -intersects(const BoundingSphereT& a_u, const BoundingSphereT& a_v) noexcept; + template + bool + intersects(const BoundingSphereT& a_u, const BoundingSphereT& a_v) noexcept; -/*! + /*! @brief Intersection method for testing if two bounding boxes overlap @param[in] a_u One bounding box @param[in] a_v The other bounding box */ -template -bool -intersects(const AABBT& a_u, const AABBT& a_v) noexcept; + template + bool + intersects(const AABBT& a_u, const AABBT& a_v) noexcept; -/*! + /*! @brief Compute the overlapping volume between two bounding spheres @param[in] a_u One bounding sphere @param[in] a_v The other bounding sphere */ -template -T -getOverlappingVolume(const BoundingSphereT& a_u, const BoundingSphereT& a_v) noexcept; + template + T + getOverlappingVolume(const BoundingSphereT& a_u, const BoundingSphereT& a_v) noexcept; -/*! + /*! @brief Compute the overlapping volume between two bounding boxes @param[in] a_u One bounding box @param[in] a_v The other bounding box */ -template -T -getOverlappingVolume(const AABBT& a_u, const AABBT& a_v) noexcept; + template + T + getOverlappingVolume(const AABBT& a_u, const AABBT& a_v) noexcept; } // namespace BoundingVolumes #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_BoundingVolumesImplem.hpp b/Source/EBGeometry_BoundingVolumesImplem.hpp index 8253bd0d..b5ce0a73 100644 --- a/Source/EBGeometry_BoundingVolumesImplem.hpp +++ b/Source/EBGeometry_BoundingVolumesImplem.hpp @@ -21,429 +21,427 @@ namespace BoundingVolumes { -template -inline BoundingSphereT::BoundingSphereT() -{ - m_radius = 0.0; - m_center = Vec3::zero(); -} - -template -inline BoundingSphereT::BoundingSphereT(const Vec3T& a_center, const T& a_radius) -{ - m_center = a_center; - m_radius = a_radius; -} - -template -BoundingSphereT::BoundingSphereT(const BoundingSphereT& a_other) -{ - m_radius = a_other.m_radius; - m_center = a_other.m_center; -} - -template -BoundingSphereT::BoundingSphereT(const std::vector>& a_otherSpheres) -{ - - // TLDR: Spheres enclosing other spheres is a difficult problem, but a sphere - // enclosing a set of points is simpler. For each - // input sphere we create a set of points representing the lo/hicorners - // of an axis-aligned bounding box that encloses the sphere. We then - // compute the bounding sphere from this set of points. - std::vector> points; - for (const auto& sphere : a_otherSpheres) { - const T& radius = sphere.getRadius(); - const Vec3T& center = sphere.getCentroid(); - - points.emplace_back(center + radius * Vec3T::one()); - points.emplace_back(center - radius * Vec3T::one()); - } - - this->define(points, BoundingSphereT::BoundingVolumeAlgorithm::Ritter); -} - -template -template -BoundingSphereT::BoundingSphereT(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_algorithm) -{ - this->define(a_points, a_algorithm); -} - -template -BoundingSphereT::~BoundingSphereT() -{ -} - -template -template -inline void -BoundingSphereT::define(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_algorithm) noexcept -{ - switch (a_algorithm) { - case BoundingVolumeAlgorithm::Ritter: { - this->buildRitter(a_points); - - break; - } - default: { - std::cerr << "BoundingSphereT::define - unsupported algorithm requested\n"; - } - } -} - -template -inline bool -BoundingSphereT::intersects(const BoundingSphereT& a_other) const noexcept -{ - const Vec3 deltaV = m_center - a_other.getCentroid(); - const T sumR = m_radius + a_other.getRadius(); - - return deltaV.dot(deltaV) < sumR * sumR; -} - -template -inline T& -BoundingSphereT::getRadius() noexcept -{ - return (m_radius); -} - -template -inline const T& -BoundingSphereT::getRadius() const noexcept -{ - return (m_radius); -} - -template -inline Vec3T& -BoundingSphereT::getCentroid() noexcept -{ - return (m_center); -} - -template -inline const Vec3T& -BoundingSphereT::getCentroid() const noexcept -{ - return (m_center); -} - -template -template -inline void -BoundingSphereT::buildRitter(const std::vector>& a_points) noexcept -{ - m_radius = 0.0; - m_center = Vec3::zero(); - - constexpr T half = 0.5; - - constexpr size_t DIM = 3; - - // INITIAL PASS - std::vector min_coord(DIM, a_points[0]); // [0] = Minimum x, [1] = Minimum y, [2] = Minimum z - std::vector max_coord(DIM, a_points[0]); - - for (size_t i = 1; i < a_points.size(); i++) { - for (size_t dir = 0; dir < DIM; dir++) { - Vec3& min = min_coord[dir]; - Vec3& max = max_coord[dir]; + template + inline BoundingSphereT::BoundingSphereT() + { + m_radius = 0.0; + m_center = Vec3::zero(); + } + + template + inline BoundingSphereT::BoundingSphereT(const Vec3T& a_center, const T& a_radius) + { + m_center = a_center; + m_radius = a_radius; + } + + template + BoundingSphereT::BoundingSphereT(const BoundingSphereT& a_other) + { + m_radius = a_other.m_radius; + m_center = a_other.m_center; + } + + template + BoundingSphereT::BoundingSphereT(const std::vector>& a_otherSpheres) + { + + // TLDR: Spheres enclosing other spheres is a difficult problem, but a sphere + // enclosing a set of points is simpler. For each + // input sphere we create a set of points representing the lo/hicorners + // of an axis-aligned bounding box that encloses the sphere. We then + // compute the bounding sphere from this set of points. + std::vector> points; + for (const auto& sphere : a_otherSpheres) { + const T& radius = sphere.getRadius(); + const Vec3T& center = sphere.getCentroid(); + + points.emplace_back(center + radius * Vec3T::one()); + points.emplace_back(center - radius * Vec3T::one()); + } + + this->define(points, BoundingSphereT::BoundingVolumeAlgorithm::Ritter); + } + + template + template + BoundingSphereT::BoundingSphereT(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_algorithm) + { + this->define(a_points, a_algorithm); + } + + template + BoundingSphereT::~BoundingSphereT() + {} + + template + template + inline void + BoundingSphereT::define(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_algorithm) noexcept + { + switch (a_algorithm) { + case BoundingVolumeAlgorithm::Ritter: { + this->buildRitter(a_points); - if (a_points[i][dir] < min[dir]) { - min = a_points[i]; + break; + } + default: { + std::cerr << "BoundingSphereT::define - unsupported algorithm requested\n"; + } + } + } + + template + inline bool + BoundingSphereT::intersects(const BoundingSphereT& a_other) const noexcept + { + const Vec3 deltaV = m_center - a_other.getCentroid(); + const T sumR = m_radius + a_other.getRadius(); + + return deltaV.dot(deltaV) < sumR * sumR; + } + + template + inline T& + BoundingSphereT::getRadius() noexcept + { + return (m_radius); + } + + template + inline const T& + BoundingSphereT::getRadius() const noexcept + { + return (m_radius); + } + + template + inline Vec3T& + BoundingSphereT::getCentroid() noexcept + { + return (m_center); + } + + template + inline const Vec3T& + BoundingSphereT::getCentroid() const noexcept + { + return (m_center); + } + + template + template + inline void + BoundingSphereT::buildRitter(const std::vector>& a_points) noexcept + { + m_radius = 0.0; + m_center = Vec3::zero(); + + constexpr T half = 0.5; + + constexpr size_t DIM = 3; + + // INITIAL PASS + std::vector min_coord(DIM, a_points[0]); // [0] = Minimum x, [1] = Minimum y, [2] = Minimum z + std::vector max_coord(DIM, a_points[0]); + + for (size_t i = 1; i < a_points.size(); i++) { + for (size_t dir = 0; dir < DIM; dir++) { + Vec3& min = min_coord[dir]; + Vec3& max = max_coord[dir]; + + if (a_points[i][dir] < min[dir]) { + min = a_points[i]; + } + if (a_points[i][dir] > max[dir]) { + max = a_points[i]; + } } - if (a_points[i][dir] > max[dir]) { - max = a_points[i]; + } + + T dist = -1; + Vec3 v, p1, p2; + for (size_t dir = 0; dir < DIM; dir++) { + const T len = (max_coord[dir] - min_coord[dir]).length(); + if (len > dist) { + dist = len; + p1 = min_coord[dir]; + p2 = max_coord[dir]; } } + + // m_center = half*(p1+p2); + m_center = (p1 + p2) * half; + m_radius = half * (p2 - p1).length(); + + // SECOND PASS + for (size_t i = 0; i < a_points.size(); i++) { + dist = (a_points[i] - m_center).length() - m_radius; + if (dist > 0.0) { // Point lies outside + v = a_points[i] - m_center; + p1 = a_points[i]; + p2 = m_center - m_radius * v / v.length(); + + m_center = half * (p2 + p1); + m_radius = half * (p2 - p1).length(); + } + } + + // Ritter algorithm is very coarse and does not give an exact result anyways. + // Grow the dimension for safety. + m_radius *= (1.0 + 1E-2); + } + + template + inline T + BoundingSphereT::getOverlappingVolume(const BoundingSphereT& a_other) const noexcept + { + constexpr T zero = 0.0; + + T retval = zero; + + if (this->intersects(a_other)) { + const auto& r1 = m_radius; + const auto& r2 = a_other.getRadius(); + + const auto d = (m_center - a_other.getCentroid()).length(); + + retval = + M_PI / (12. * d) * (r1 + r2 - d) * (r1 + r2 - d) * (d * d + 2 * d * (r1 + r2) - 3 * (r1 - r2) * (r1 - r2)); + } + + return retval; + } + + template + inline T + BoundingSphereT::getDistance(const Vec3& a_x0) const noexcept + { + constexpr T zero = 0.0; + + return std::max(zero, (a_x0 - m_center).length() - m_radius); + } + + template + inline T + BoundingSphereT::getVolume() const noexcept + { + return 4. * M_PI * m_radius * m_radius * m_radius / 3.0; + } + + template + inline T + BoundingSphereT::getArea() const noexcept + { + return T(4. * M_PI * m_radius * m_radius); + } + + template + AABBT::AABBT() + { + m_loCorner = Vec3::zero(); + m_hiCorner = Vec3::zero(); + } + + template + AABBT::AABBT(const Vec3T& a_lo, const Vec3T& a_hi) + { + m_loCorner = a_lo; + m_hiCorner = a_hi; + } + + template + AABBT::AABBT(const AABBT& a_other) + { + m_loCorner = a_other.m_loCorner; + m_hiCorner = a_other.m_hiCorner; + } + + template + AABBT::AABBT(const std::vector>& a_others) + { + m_loCorner = a_others.front().getLowCorner(); + m_hiCorner = a_others.front().getHighCorner(); + + for (const auto& other : a_others) { + m_loCorner = min(m_loCorner, other.getLowCorner()); + m_hiCorner = max(m_hiCorner, other.getHighCorner()); + } } - T dist = -1; - Vec3 v, p1, p2; - for (size_t dir = 0; dir < DIM; dir++) { - const T len = (max_coord[dir] - min_coord[dir]).length(); - if (len > dist) { - dist = len; - p1 = min_coord[dir]; - p2 = max_coord[dir]; + template + template + AABBT::AABBT(const std::vector>& a_points) + { + this->define(a_points); + } + + template + AABBT::~AABBT() + {} + + template + template + inline void + AABBT::define(const std::vector>& a_points) noexcept + { + m_loCorner = a_points.front(); + m_hiCorner = a_points.front(); + + for (const auto& p : a_points) { + m_loCorner = min(m_loCorner, p); + m_hiCorner = max(m_hiCorner, p); } } - // m_center = half*(p1+p2); - m_center = (p1 + p2) * half; - m_radius = half * (p2 - p1).length(); + template + inline bool + AABBT::intersects(const AABBT& a_other) const noexcept + { + const Vec3& otherLo = a_other.getLowCorner(); + const Vec3& otherHi = a_other.getHighCorner(); + + return (m_loCorner[0] < otherHi[0] && m_hiCorner[0] > otherLo[0]) && + (m_loCorner[1] < otherHi[1] && m_hiCorner[1] > otherLo[1]) && + (m_loCorner[2] < otherHi[2] && m_hiCorner[2] > otherLo[2]); + } + + template + inline Vec3T& + AABBT::getLowCorner() noexcept + { + return (m_loCorner); + } + + template + inline const Vec3T& + AABBT::getLowCorner() const noexcept + { + return (m_loCorner); + } + + template + inline Vec3T& + AABBT::getHighCorner() noexcept + { + return (m_hiCorner); + } + + template + inline const Vec3T& + AABBT::getHighCorner() const noexcept + { + return (m_hiCorner); + } + + template + inline Vec3T + AABBT::getCentroid() const noexcept + { + constexpr T half = T(0.5); + + return half * (m_loCorner + m_hiCorner); + } + + template + inline T + AABBT::getOverlappingVolume(const AABBT& a_other) const noexcept + { + constexpr T zero = 0.0; - // SECOND PASS - for (size_t i = 0; i < a_points.size(); i++) { - dist = (a_points[i] - m_center).length() - m_radius; - if (dist > 0.0) { // Point lies outside - v = a_points[i] - m_center; - p1 = a_points[i]; - p2 = m_center - m_radius * v / v.length(); + T ret = 1.0; - m_center = half * (p2 + p1); - m_radius = half * (p2 - p1).length(); + for (size_t dir = 0; dir < 3; dir++) { + const auto xL = m_loCorner[dir]; + const auto xH = m_hiCorner[dir]; + + const auto yL = a_other.m_loCorner[dir]; + const auto yH = a_other.m_hiCorner[dir]; + + const auto delta = std::max(zero, std::min(xH, yH) - std::max(xL, yL)); + + ret *= delta; + } + + return ret; + } + + template + inline T + AABBT::getDistance(const Vec3& a_point) const noexcept + { + constexpr T zero = 0.0; + + const Vec3 delta = Vec3(std::max(m_loCorner[0] - a_point[0], a_point[0] - m_hiCorner[0]), + std::max(m_loCorner[1] - a_point[1], a_point[1] - m_hiCorner[1]), + std::max(m_loCorner[2] - a_point[2], a_point[2] - m_hiCorner[2])); + + const T retval = std::max(zero, max(Vec3::zero(), delta).length()); + + return retval; + } + + template + inline T + AABBT::getVolume() const noexcept + { + const auto delta = m_hiCorner - m_loCorner; + + T ret = 1.0; + for (size_t dir = 0; dir < 3; dir++) { + ret *= delta[dir]; } + + return ret; } - // Ritter algorithm is very coarse and does not give an exact result anyways. - // Grow the dimension for safety. - m_radius *= (1.0 + 1E-2); -} - -template -inline T -BoundingSphereT::getOverlappingVolume(const BoundingSphereT& a_other) const noexcept -{ - constexpr T zero = 0.0; - - T retval = zero; - - if (this->intersects(a_other)) { - const auto& r1 = m_radius; - const auto& r2 = a_other.getRadius(); - - const auto d = (m_center - a_other.getCentroid()).length(); - - retval = M_PI / (12. * d) * (r1 + r2 - d) * (r1 + r2 - d) * (d * d + 2 * d * (r1 + r2) - 3 * (r1 - r2) * (r1 - r2)); - } - - return retval; -} - -template -inline T -BoundingSphereT::getDistance(const Vec3& a_x0) const noexcept -{ - constexpr T zero = 0.0; - - return std::max(zero, (a_x0 - m_center).length() - m_radius); -} - -template -inline T -BoundingSphereT::getVolume() const noexcept -{ - return 4. * M_PI * m_radius * m_radius * m_radius / 3.0; -} - -template -inline T -BoundingSphereT::getArea() const noexcept -{ - return T(4. * M_PI * m_radius * m_radius); -} - -template -AABBT::AABBT() -{ - m_loCorner = Vec3::zero(); - m_hiCorner = Vec3::zero(); -} - -template -AABBT::AABBT(const Vec3T& a_lo, const Vec3T& a_hi) -{ - m_loCorner = a_lo; - m_hiCorner = a_hi; -} - -template -AABBT::AABBT(const AABBT& a_other) -{ - m_loCorner = a_other.m_loCorner; - m_hiCorner = a_other.m_hiCorner; -} - -template -AABBT::AABBT(const std::vector>& a_others) -{ - m_loCorner = a_others.front().getLowCorner(); - m_hiCorner = a_others.front().getHighCorner(); - - for (const auto& other : a_others) { - m_loCorner = min(m_loCorner, other.getLowCorner()); - m_hiCorner = max(m_hiCorner, other.getHighCorner()); - } -} - -template -template -AABBT::AABBT(const std::vector>& a_points) -{ - this->define(a_points); -} - -template -AABBT::~AABBT() -{ -} - -template -template -inline void -AABBT::define(const std::vector>& a_points) noexcept -{ - m_loCorner = a_points.front(); - m_hiCorner = a_points.front(); - - for (const auto& p : a_points) { - m_loCorner = min(m_loCorner, p); - m_hiCorner = max(m_hiCorner, p); - } -} - -template -inline bool -AABBT::intersects(const AABBT& a_other) const noexcept -{ - const Vec3& otherLo = a_other.getLowCorner(); - const Vec3& otherHi = a_other.getHighCorner(); - - return (m_loCorner[0] < otherHi[0] && m_hiCorner[0] > otherLo[0]) && - (m_loCorner[1] < otherHi[1] && m_hiCorner[1] > otherLo[1]) && - (m_loCorner[2] < otherHi[2] && m_hiCorner[2] > otherLo[2]); -} - -template -inline Vec3T& -AABBT::getLowCorner() noexcept -{ - return (m_loCorner); -} - -template -inline const Vec3T& -AABBT::getLowCorner() const noexcept -{ - return (m_loCorner); -} - -template -inline Vec3T& -AABBT::getHighCorner() noexcept -{ - return (m_hiCorner); -} - -template -inline const Vec3T& -AABBT::getHighCorner() const noexcept -{ - return (m_hiCorner); -} - -template -inline Vec3T -AABBT::getCentroid() const noexcept -{ - constexpr T half = T(0.5); - - return half * (m_loCorner + m_hiCorner); -} - -template -inline T -AABBT::getOverlappingVolume(const AABBT& a_other) const noexcept -{ - constexpr T zero = 0.0; - - T ret = 1.0; - - for (size_t dir = 0; dir < 3; dir++) { - const auto xL = m_loCorner[dir]; - const auto xH = m_hiCorner[dir]; - - const auto yL = a_other.m_loCorner[dir]; - const auto yH = a_other.m_hiCorner[dir]; - - const auto delta = std::max(zero, std::min(xH, yH) - std::max(xL, yL)); - - ret *= delta; - } - - return ret; -} - -template -inline T -AABBT::getDistance(const Vec3& a_point) const noexcept -{ - constexpr T zero = 0.0; - - const Vec3 delta = Vec3( - std::max(m_loCorner[0] - a_point[0], a_point[0] - m_hiCorner[0]), - std::max(m_loCorner[1] - a_point[1], a_point[1] - m_hiCorner[1]), - std::max(m_loCorner[2] - a_point[2], a_point[2] - m_hiCorner[2])); - - const T retval = std::max(zero, max(Vec3::zero(), delta).length()); - - return retval; -} - -template -inline T -AABBT::getVolume() const noexcept -{ - const auto delta = m_hiCorner - m_loCorner; - - T ret = 1.0; - for (size_t dir = 0; dir < 3; dir++) { - ret *= delta[dir]; - } - - return ret; -} - -template -inline T -AABBT::getArea() const noexcept -{ - constexpr size_t DIM = 3; - - T ret = 0.0; - - const auto delta = m_hiCorner - m_loCorner; - - for (size_t dir = 0; dir < DIM; dir++) { - const size_t otherDir1 = (dir + 1) % DIM; - const size_t otherDir2 = (dir + 2) % DIM; - - ret += 2.0 * delta[otherDir1] * delta[otherDir2]; - } + template + inline T + AABBT::getArea() const noexcept + { + constexpr size_t DIM = 3; + + T ret = 0.0; - return ret; -} - -template -bool -intersects(const BoundingSphereT& u, const BoundingSphereT& v) noexcept -{ - return u.intersects(v); -} + const auto delta = m_hiCorner - m_loCorner; -template -bool -intersects(const AABBT& u, const AABBT& v) noexcept -{ - return u.intersects(v); -} + for (size_t dir = 0; dir < DIM; dir++) { + const size_t otherDir1 = (dir + 1) % DIM; + const size_t otherDir2 = (dir + 2) % DIM; -template -T -getOverlappingVolume(const BoundingSphereT& u, const BoundingSphereT& v) noexcept -{ - return u.getOverlappingVolume(v); -} + ret += 2.0 * delta[otherDir1] * delta[otherDir2]; + } -template -T -getOverlappingVolume(const AABBT& u, const AABBT& v) noexcept -{ - return u.getOverlappingVolume(v); -} + return ret; + } + + template + bool + intersects(const BoundingSphereT& u, const BoundingSphereT& v) noexcept + { + return u.intersects(v); + } + + template + bool + intersects(const AABBT& u, const AABBT& v) noexcept + { + return u.intersects(v); + } + + template + T + getOverlappingVolume(const BoundingSphereT& u, const BoundingSphereT& v) noexcept + { + return u.getOverlappingVolume(v); + } + + template + T + getOverlappingVolume(const AABBT& u, const AABBT& v) noexcept + { + return u.getOverlappingVolume(v); + } } // namespace BoundingVolumes #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_BVH.hpp b/Source/EBGeometry_DCEL_BVH.hpp index 63d93d33..02d9e6c0 100644 --- a/Source/EBGeometry_DCEL_BVH.hpp +++ b/Source/EBGeometry_DCEL_BVH.hpp @@ -25,13 +25,13 @@ namespace DCEL { -/*! + /*! @brief Alias for vector of primitives. */ -template -using PrimitiveList = std::vector>>; + template + using PrimitiveList = std::vector>>; -/*! + /*! @brief Bounding volume constructor for a DCEL face. @details With BVHs and DCEL, the object to be bounded is the polygon face (e.g., triangle). We assume that our BV constructor can enclose points, so we @@ -39,13 +39,13 @@ using PrimitiveList = std::vector -EBGeometry::BVH::BVConstructorT, BV> defaultBVConstructor = - [](const std::shared_ptr>& a_primitive) -> BV { - return BV(a_primitive->getAllVertexCoordinates()); -}; + template + EBGeometry::BVH::BVConstructorT, BV> defaultBVConstructor = + [](const std::shared_ptr>& a_primitive) -> BV { + return BV(a_primitive->getAllVertexCoordinates()); + }; -/*! + /*! @brief Default stop function. This function terminates the division process if a BVH node has only one primitive. @details In this function, BVH::NodeT, BVH > is a BVH node. The @@ -55,55 +55,55 @@ EBGeometry::BVH::BVConstructorT, BV> defaultBVConstru @return Returns true if the bounding volume shouldn't be split more and false otherwise. */ -template -EBGeometry::BVH::StopFunctionT, BV, K> defaultStopFunction = - [](const BVH::NodeT, BV, K>& a_node) -> bool { - return (a_node.getPrimitives()).size() < K; -}; + template + EBGeometry::BVH::StopFunctionT, BV, K> defaultStopFunction = + [](const BVH::NodeT, BV, K>& a_node) -> bool { + return (a_node.getPrimitives()).size() < K; + }; -/*! + /*! @brief Function which checks that all chunks are valid (i.e., contain at least one primitive @param[in] a_chunks Chunks. */ -template -auto validChunks = [](const std::array, K>& a_chunks) -> bool { - for (const auto& chunk : a_chunks) { - if (chunk.empty()) - return false; - } + template + auto validChunks = [](const std::array, K>& a_chunks) -> bool { + for (const auto& chunk : a_chunks) { + if (chunk.empty()) + return false; + } - return true; -}; + return true; + }; -/*! + /*! @brief Function for partitioning an input list into K almost-equal-sized chunks @param[in] a_primitives Primitives to be partitioned. */ -template -auto equalCounts = [](const PrimitiveList& a_primitives) -> std::array, K> { - int length = a_primitives.size() / K; - int remain = a_primitives.size() % K; + template + auto equalCounts = [](const PrimitiveList& a_primitives) -> std::array, K> { + int length = a_primitives.size() / K; + int remain = a_primitives.size() % K; - int begin = 0; - int end = 0; + int begin = 0; + int end = 0; - std::array, K> chunks; + std::array, K> chunks; - for (size_t k = 0; k < K; k++) { - end += (remain > 0) ? length + 1 : length; - remain--; + for (size_t k = 0; k < K; k++) { + end += (remain > 0) ? length + 1 : length; + remain--; - chunks[k] = PrimitiveList(a_primitives.begin() + begin, a_primitives.begin() + end); + chunks[k] = PrimitiveList(a_primitives.begin() + begin, a_primitives.begin() + end); - begin = end; - } + begin = end; + } - return chunks; -}; + return chunks; + }; -/*! + /*! @brief Partitioner function for subdividing into K sub-volumes with approximately the same number of primitives. @details This partitioner splits along one of the axis coordinates and sorts @@ -111,31 +111,31 @@ auto equalCounts = [](const PrimitiveList& a_primitives) -> std::array -EBGeometry::BVH::PartitionerT, BV, K> chunkPartitioner = - [](const PrimitiveList& a_primitives) -> std::array, K> { - Vec3T lo = Vec3T::max(); - Vec3T hi = -Vec3T::max(); - for (const auto& p : a_primitives) { - lo = min(lo, p->getCentroid()); - hi = max(hi, p->getCentroid()); - } - - const size_t splitDir = (hi - lo).maxDir(true); - - // Sort the primitives along the above coordinate direction. - PrimitiveList sortedPrimitives(a_primitives); - - std::sort( - sortedPrimitives.begin(), sortedPrimitives.end(), - [splitDir](const std::shared_ptr>& f1, const std::shared_ptr>& f2) -> bool { - return f1->getCentroid(splitDir) < f2->getCentroid(splitDir); - }); + template + EBGeometry::BVH::PartitionerT, BV, K> chunkPartitioner = + [](const PrimitiveList& a_primitives) -> std::array, K> { + Vec3T lo = Vec3T::max(); + Vec3T hi = -Vec3T::max(); + for (const auto& p : a_primitives) { + lo = min(lo, p->getCentroid()); + hi = max(hi, p->getCentroid()); + } - return EBGeometry::DCEL::equalCounts(sortedPrimitives); -}; + const size_t splitDir = (hi - lo).maxDir(true); -/*! + // Sort the primitives along the above coordinate direction. + PrimitiveList sortedPrimitives(a_primitives); + + std::sort(sortedPrimitives.begin(), + sortedPrimitives.end(), + [splitDir](const std::shared_ptr>& f1, const std::shared_ptr>& f2) -> bool { + return f1->getCentroid(splitDir) < f2->getCentroid(splitDir); + }); + + return EBGeometry::DCEL::equalCounts(sortedPrimitives); + }; + + /*! @brief Partitioner function for subdividing into K sub-volumes with approximately the same number of primitives. @details Basically the same as chunkPartitioner, except that the centroids are @@ -143,105 +143,105 @@ EBGeometry::BVH::PartitionerT, BV, K> chunkPartitione @param[in] a_primitives List of primitives to partition into sub-bounding volumes */ -template -EBGeometry::BVH::PartitionerT, BV, K> bvPartitioner = - [](const PrimitiveList& a_primitives) -> std::array, K> { - Vec3T lo = Vec3T::max(); - Vec3T hi = -Vec3T::max(); + template + EBGeometry::BVH::PartitionerT, BV, K> bvPartitioner = + [](const PrimitiveList& a_primitives) -> std::array, K> { + Vec3T lo = Vec3T::max(); + Vec3T hi = -Vec3T::max(); - // Pack primitives and their bounding volumes together. - using P = std::pair>, BV>; + // Pack primitives and their bounding volumes together. + using P = std::pair>, BV>; - std::vector

primsAndBVs; + std::vector

primsAndBVs; - for (const auto& p : a_primitives) { - const BV bv(p->getAllVertexCoordinates()); + for (const auto& p : a_primitives) { + const BV bv(p->getAllVertexCoordinates()); - primsAndBVs.emplace_back(p, bv); + primsAndBVs.emplace_back(p, bv); - lo = min(lo, bv.getCentroid()); - hi = max(hi, bv.getCentroid()); - } + lo = min(lo, bv.getCentroid()); + hi = max(hi, bv.getCentroid()); + } - const size_t splitDir = (hi - lo).maxDir(true); + const size_t splitDir = (hi - lo).maxDir(true); - // Sort the primitives based on the centroid location of their BVs. - std::sort(primsAndBVs.begin(), primsAndBVs.end(), [splitDir](const P& p1, const P& p2) { - return (p1.second).getCentroid()[splitDir] < (p2.second).getCentroid()[splitDir]; - }); + // Sort the primitives based on the centroid location of their BVs. + std::sort(primsAndBVs.begin(), primsAndBVs.end(), [splitDir](const P& p1, const P& p2) { + return (p1.second).getCentroid()[splitDir] < (p2.second).getCentroid()[splitDir]; + }); - // Unpack the vector and partition into equal counts. - PrimitiveList sortedPrimitives; - for (const auto& p : primsAndBVs) { - sortedPrimitives.emplace_back(p.first); - } + // Unpack the vector and partition into equal counts. + PrimitiveList sortedPrimitives; + for (const auto& p : primsAndBVs) { + sortedPrimitives.emplace_back(p.first); + } - primsAndBVs.resize(0); + primsAndBVs.resize(0); - return EBGeometry::DCEL::equalCounts(sortedPrimitives); -}; + return EBGeometry::DCEL::equalCounts(sortedPrimitives); + }; -/*! + /*! @brief Partitioner function for subdividing into K sub-volumes, partitioning on the primitive centroid midpoint(s). @param[in] a_primitives List of primitives to partition into sub-bounding volumes */ -template -EBGeometry::BVH::PartitionerT, BV, K> centroidPartitioner = - [](const PrimitiveList& a_primitives) -> std::array, K> { - Vec3T lo = Vec3T::max(); - Vec3T hi = -Vec3T::max(); - for (const auto& p : a_primitives) { - lo = min(lo, p->getCentroid()); - hi = max(hi, p->getCentroid()); - } - - const size_t splitDir = (hi - lo).maxDir(true); - const T delta = (hi - lo)[splitDir] / K; - - std::array boundsLo; - std::array boundsHi; - - for (size_t k = 0; k < K; k++) { - boundsLo[k] = lo[splitDir] + delta * k; - boundsHi[k] = lo[splitDir] + delta * (k + 1); - } - - // Given coord, find the bin. - auto getBin = [&](const T& coord) -> size_t { + template + EBGeometry::BVH::PartitionerT, BV, K> centroidPartitioner = + [](const PrimitiveList& a_primitives) -> std::array, K> { + Vec3T lo = Vec3T::max(); + Vec3T hi = -Vec3T::max(); + for (const auto& p : a_primitives) { + lo = min(lo, p->getCentroid()); + hi = max(hi, p->getCentroid()); + } + + const size_t splitDir = (hi - lo).maxDir(true); + const T delta = (hi - lo)[splitDir] / K; + + std::array boundsLo; + std::array boundsHi; + for (size_t k = 0; k < K; k++) { - if (coord >= boundsLo[k] && coord <= boundsHi[k]) { - return k; - } + boundsLo[k] = lo[splitDir] + delta * k; + boundsHi[k] = lo[splitDir] + delta * (k + 1); } - return K - 1; - }; + // Given coord, find the bin. + auto getBin = [&](const T& coord) -> size_t { + for (size_t k = 0; k < K; k++) { + if (coord >= boundsLo[k] && coord <= boundsHi[k]) { + return k; + } + } - // Put primitives in their respective bins. - std::array, K> chunks; + return K - 1; + }; - for (const auto& p : a_primitives) { - const size_t k = getBin(p->getCentroid()[splitDir]); - chunks[k].push_back(p); - } + // Put primitives in their respective bins. + std::array, K> chunks; - // The centroid-based partitioner can end up with no primitives in one of the - // leaves (a rare case). Use a different partitioner in that case. - if (!(EBGeometry::DCEL::validChunks(chunks))) { - chunks = EBGeometry::DCEL::chunkPartitioner(a_primitives); - } + for (const auto& p : a_primitives) { + const size_t k = getBin(p->getCentroid()[splitDir]); + chunks[k].push_back(p); + } - return chunks; -}; + // The centroid-based partitioner can end up with no primitives in one of the + // leaves (a rare case). Use a different partitioner in that case. + if (!(EBGeometry::DCEL::validChunks(chunks))) { + chunks = EBGeometry::DCEL::chunkPartitioner(a_primitives); + } -/*! + return chunks; + }; + + /*! @brief Alias for default partitioner. */ -template -EBGeometry::BVH::PartitionerT, BV, K> defaultPartitioner = - EBGeometry::DCEL::chunkPartitioner; + template + EBGeometry::BVH::PartitionerT, BV, K> defaultPartitioner = + EBGeometry::DCEL::chunkPartitioner; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Edge.hpp b/Source/EBGeometry_DCEL_Edge.hpp index 65a6b9e9..59fdfd1d 100644 --- a/Source/EBGeometry_DCEL_Edge.hpp +++ b/Source/EBGeometry_DCEL_Edge.hpp @@ -24,17 +24,17 @@ namespace DCEL { -// Forward declare classes. -template -class VertexT; -template -class EdgeT; -template -class FaceT; -template -class EdgeIteratorT; + // Forward declare classes. + template + class VertexT; + template + class EdgeT; + template + class FaceT; + template + class EdgeIteratorT; -/*! + /*! @brief Class which represents a half-edge in a double-edge connected list (DCEL). @details This class is used in DCEL functionality which stores polygonal @@ -54,75 +54,75 @@ class EdgeIteratorT; @note The normal vector is outgoing, i.e. a point x is "outside" if the dot product between n and (x - x0) is positive. */ -template -class EdgeT -{ -public: - /*! + template + class EdgeT + { + public: + /*! @brief Alias to cut down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Alias to cut down on typing */ - using Vertex = VertexT; + using Vertex = VertexT; - /*! + /*! @brief Alias to cut down on typing */ - using Edge = EdgeT; + using Edge = EdgeT; - /*! + /*! @brief Alias to cut down on typing */ - using Face = FaceT; + using Face = FaceT; - /*! + /*! @brief Alias to cut down on typing */ - using VertexPtr = std::shared_ptr; + using VertexPtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using EdgePtr = std::shared_ptr; + using EdgePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using FacePtr = std::shared_ptr; + using FacePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using EdgeIterator = EdgeIteratorT; + using EdgeIterator = EdgeIteratorT; - /*! + /*! @brief Default constructor. Sets all pointers to zero and vectors to zero vectors */ - EdgeT(); + EdgeT(); - /*! + /*! @brief Copy constructor. Copies all information from the other half-edge. @param[in] a_otherEdge Other edge */ - EdgeT(const Edge& a_otherEdge); + EdgeT(const Edge& a_otherEdge); - /*! + /*! @brief Partial constructor. Calls the default constructor but sets the starting vertex. @param[in] a_vertex Starting vertex. */ - EdgeT(const VertexPtr& a_vertex); + EdgeT(const VertexPtr& a_vertex); - /*! + /*! @brief Destructor (does nothing) */ - ~EdgeT(); + ~EdgeT(); - /*! + /*! @brief Define function. Sets the starting vertex, edges, and normal vectors @param[in] a_vertex Starting vertex @param[in] a_pairEdge Pair half-edge @@ -130,159 +130,158 @@ class EdgeT @param[in] a_previousEdge Previous half-edge @param[in] a_normal Edge normal vector */ - inline void - define( - const VertexPtr& a_vertex, - const EdgePtr& a_pairEdge, - const EdgePtr& a_nextEdge, - const EdgePtr& a_previousEdge, - const Vec3 a_normal) noexcept; + inline void + define(const VertexPtr& a_vertex, + const EdgePtr& a_pairEdge, + const EdgePtr& a_nextEdge, + const EdgePtr& a_previousEdge, + const Vec3 a_normal) noexcept; - /*! + /*! @brief Set the starting vertex @param[in] a_vertex Starting vertex */ - inline void - setVertex(const VertexPtr& a_vertex) noexcept; + inline void + setVertex(const VertexPtr& a_vertex) noexcept; - /*! + /*! @brief Set the pair edge @param[in] a_pairEdge Pair edge */ - inline void - setPairEdge(const EdgePtr& a_pairEdge) noexcept; + inline void + setPairEdge(const EdgePtr& a_pairEdge) noexcept; - /*! + /*! @brief Set the next edge @param[in] a_nextEdge Next edge */ - inline void - setNextEdge(const EdgePtr& a_nextEdge) noexcept; + inline void + setNextEdge(const EdgePtr& a_nextEdge) noexcept; - /*! + /*! @brief Set the previous edge @param[in] a_previousEdge Previous edge */ - inline void - setPreviousEdge(const EdgePtr& a_previousEdge) noexcept; + inline void + setPreviousEdge(const EdgePtr& a_previousEdge) noexcept; - /*! + /*! @brief Set the pointer to this half-edge's face. */ - inline void - setFace(const FacePtr& a_face) noexcept; + inline void + setFace(const FacePtr& a_face) noexcept; - /*! + /*! @brief Compute edge normal and edge length (for performance reasons) */ - inline void - reconcile() noexcept; + inline void + reconcile() noexcept; - /*! + /*! @brief Get modifiable starting vertex @return Returns m_vertex */ - inline VertexPtr& - getVertex() noexcept; + inline VertexPtr& + getVertex() noexcept; - /*! + /*! @brief Get immutable starting vertex @return Returns m_vertex */ - inline const VertexPtr& - getVertex() const noexcept; + inline const VertexPtr& + getVertex() const noexcept; - /*! + /*! @brief Get modifiable end vertex @return Returns the next half-edge's starting vertex */ - inline VertexPtr& - getOtherVertex() noexcept; + inline VertexPtr& + getOtherVertex() noexcept; - /*! + /*! @brief Get immutable end vertex @return Returns the next half-edge's starting vertex */ - inline const VertexPtr& - getOtherVertex() const noexcept; + inline const VertexPtr& + getOtherVertex() const noexcept; - /*! + /*! @brief Get modifiable pair edge @return Returns the pair edge */ - inline EdgePtr& - getPairEdge() noexcept; + inline EdgePtr& + getPairEdge() noexcept; - /*! + /*! @brief Get immutable pair edge @return Returns the pair edge */ - inline const EdgePtr& - getPairEdge() const noexcept; + inline const EdgePtr& + getPairEdge() const noexcept; - /*! + /*! @brief Get modifiable previous edge @return Returns the previous edge */ - inline EdgePtr& - getPreviousEdge() noexcept; + inline EdgePtr& + getPreviousEdge() noexcept; - /*! + /*! @brief Get immutable previous edge @return Returns the previous edge */ - inline const EdgePtr& - getPreviousEdge() const noexcept; + inline const EdgePtr& + getPreviousEdge() const noexcept; - /*! + /*! @brief Get modifiable next edge @return Returns the next edge */ - inline EdgePtr& - getNextEdge() noexcept; + inline EdgePtr& + getNextEdge() noexcept; - /*! + /*! @brief Get immutable next edge @return Returns the next edge */ - inline const EdgePtr& - getNextEdge() const noexcept; + inline const EdgePtr& + getNextEdge() const noexcept; - /*! + /*! @brief Get modifiable half-edge normal vector */ - inline Vec3T& - getNormal() noexcept; + inline Vec3T& + getNormal() noexcept; - /*! + /*! @brief Get immutable half-edge normal vector */ - inline const Vec3T& - getNormal() const noexcept; + inline const Vec3T& + getNormal() const noexcept; - /*! + /*! @brief Get modifiable half-edge face */ - inline FacePtr& - getFace() noexcept; + inline FacePtr& + getFace() noexcept; - /*! + /*! @brief Get immutable half-edge face */ - inline const FacePtr& - getFace() const noexcept; + inline const FacePtr& + getFace() const noexcept; - /*! + /*! @brief Get the signed distance to this half edge @details This routine will check if the input point projects to the edge or one of the vertices. If it projectes to one of the vertices we compute the signed distance to the corresponding vertex. Otherwise we compute the projection to the edge and compute the sign from the normal vector. */ - inline T - signedDistance(const Vec3& a_x0) const noexcept; + inline T + signedDistance(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Get the signed distance to this half edge @details This routine will check if the input point projects to the edge or one of the vertices. If it projectes to one of the vertices we compute the @@ -290,82 +289,82 @@ class EdgeT squared distance of the projection to the edge. This is faster than signedDistance() */ - inline T - unsignedDistance2(const Vec3& a_x0) const noexcept; + inline T + unsignedDistance2(const Vec3& a_x0) const noexcept; -protected: - /*! + protected: + /*! @brief Half-edge normal vector @details Computed in computeNormal which sets the normal vector to be the average of the normal vector of the connected faces */ - Vec3 m_normal; + Vec3 m_normal; - /*! + /*! @brief Vector from the starting vertex to the end vertex. Exists for performance reasons. */ - Vec3 m_x2x1; + Vec3 m_x2x1; - /*! + /*! @brief Squared inverse edge length. Exists for performance reasons. */ - T m_invLen2; + T m_invLen2; - /*! + /*! @brief Starting vertex */ - VertexPtr m_vertex; + VertexPtr m_vertex; - /*! + /*! @brief Pair edge */ - EdgePtr m_pairEdge; + EdgePtr m_pairEdge; - /*! + /*! @brief Previous edge */ - EdgePtr m_previousEdge; + EdgePtr m_previousEdge; - /*! + /*! @brief Next edge */ - EdgePtr m_nextEdge; + EdgePtr m_nextEdge; - /*! + /*! @brief Enclosing polygon face */ - FacePtr m_face; + FacePtr m_face; - /*! + /*! @brief Returns the "projection" of a point to an edge. @details This function parametrizes the edge as x(t) = x0 + (x1-x0)*t and returns where on the this edge the point a_x0 projects. If projects onto the edge if t = [0,1] and to one of the start/end vertices otherwise. */ - inline T - projectPointToEdge(const Vec3& a_x0) const noexcept; + inline T + projectPointToEdge(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Normalize the normal vector, ensuring it has length 1 */ - inline void - normalizeNormalVector() noexcept; + inline void + normalizeNormalVector() noexcept; - /*! + /*! @brief Compute the edge length. @details This computes the vector m_x2x1 (vector from starting vertex to end vertex) and the inverse length squared. */ - inline void - computeEdgeLength() noexcept; + inline void + computeEdgeLength() noexcept; - /*! + /*! @brief Compute normal vector as average of face normals */ - inline void - computeNormal() noexcept; -}; + inline void + computeNormal() noexcept; + }; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_EdgeImplem.hpp b/Source/EBGeometry_DCEL_EdgeImplem.hpp index a88f54ad..66777b15 100644 --- a/Source/EBGeometry_DCEL_EdgeImplem.hpp +++ b/Source/EBGeometry_DCEL_EdgeImplem.hpp @@ -22,286 +22,284 @@ namespace DCEL { -template -inline EdgeT::EdgeT() -{ - m_face = nullptr; - m_vertex = nullptr; - m_pairEdge = nullptr; - m_nextEdge = nullptr; - m_previousEdge = nullptr; - m_normal = Vec3::zero(); - m_x2x1 = Vec3::zero(); - m_invLen2 = 0.0; -} - -template -inline EdgeT::EdgeT(const VertexPtr& a_vertex) : EdgeT() -{ - m_vertex = a_vertex; -} - -template -inline EdgeT::EdgeT(const Edge& a_otherEdge) : EdgeT() -{ - m_face = a_otherEdge.m_face; - m_vertex = a_otherEdge.m_vertex; - m_pairEdge = a_otherEdge.m_pairEdge; - m_nextEdge = a_otherEdge.m_nextEdge; - m_previousEdge = a_otherEdge.m_previousEdge; - m_normal = a_otherEdge.m_normal; - m_x2x1 = a_otherEdge.m_x2x1; - m_invLen2 = a_otherEdge.m_invLen2; -} - -template -inline EdgeT::~EdgeT() -{ -} - -template -inline void -EdgeT::define( - const VertexPtr& a_vertex, - const EdgePtr& a_pairEdge, - const EdgePtr& a_nextEdge, - const EdgePtr& a_previousEdge, - const Vec3 a_normal) noexcept -{ - m_vertex = a_vertex; - m_pairEdge = a_pairEdge; - m_nextEdge = a_nextEdge; - m_previousEdge = a_previousEdge; - m_normal = a_normal; -} - -template -inline void -EdgeT::setVertex(const VertexPtr& a_vertex) noexcept -{ - m_vertex = a_vertex; -} - -template -inline void -EdgeT::setPairEdge(const EdgePtr& a_pairEdge) noexcept -{ - m_pairEdge = a_pairEdge; -} - -template -inline void -EdgeT::setNextEdge(const EdgePtr& a_nextEdge) noexcept -{ - m_nextEdge = a_nextEdge; -} - -template -inline void -EdgeT::setPreviousEdge(const EdgePtr& a_previousEdge) noexcept -{ - m_previousEdge = a_previousEdge; -} - -template -inline void -EdgeT::setFace(const FacePtr& a_face) noexcept -{ - m_face = a_face; -} - -template -inline void -EdgeT::normalizeNormalVector() noexcept -{ - m_normal = m_normal / m_normal.length(); -} - -template -inline void -EdgeT::computeEdgeLength() noexcept -{ - const auto& x1 = this->getVertex()->getPosition(); - const auto& x2 = this->getOtherVertex()->getPosition(); - - m_x2x1 = x2 - x1; - - const auto len2 = m_x2x1.dot(m_x2x1); - - m_invLen2 = 1. / len2; -} - -template -inline void -EdgeT::computeNormal() noexcept -{ - - m_normal = m_face->getNormal(); - - if (m_pairEdge) { - m_normal += m_pairEdge->getFace()->getNormal(); + template + inline EdgeT::EdgeT() + { + m_face = nullptr; + m_vertex = nullptr; + m_pairEdge = nullptr; + m_nextEdge = nullptr; + m_previousEdge = nullptr; + m_normal = Vec3::zero(); + m_x2x1 = Vec3::zero(); + m_invLen2 = 0.0; } - this->normalizeNormalVector(); -} - -template -inline void -EdgeT::reconcile() noexcept -{ - this->computeNormal(); - this->computeEdgeLength(); -} - -template -inline std::shared_ptr>& -EdgeT::getVertex() noexcept -{ - return (m_vertex); -} - -template -inline const std::shared_ptr>& -EdgeT::getVertex() const noexcept -{ - return (m_vertex); -} - -template -inline std::shared_ptr>& -EdgeT::getOtherVertex() noexcept -{ - return (m_nextEdge->getVertex()); -} - -template -inline const std::shared_ptr>& -EdgeT::getOtherVertex() const noexcept -{ - return (m_nextEdge->getVertex()); -} - -template -inline std::shared_ptr>& -EdgeT::getPairEdge() noexcept -{ - return (m_pairEdge); -} - -template -inline const std::shared_ptr>& -EdgeT::getPairEdge() const noexcept -{ - return (m_pairEdge); -} - -template -inline std::shared_ptr>& -EdgeT::getPreviousEdge() noexcept -{ - return (m_previousEdge); -} - -template -inline const std::shared_ptr>& -EdgeT::getPreviousEdge() const noexcept -{ - return (m_previousEdge); -} - -template -inline std::shared_ptr>& -EdgeT::getNextEdge() noexcept -{ - return (m_nextEdge); -} - -template -inline const std::shared_ptr>& -EdgeT::getNextEdge() const noexcept -{ - return (m_nextEdge); -} - -template -inline Vec3T& -EdgeT::getNormal() noexcept -{ - return (m_normal); -} - -template -inline const Vec3T& -EdgeT::getNormal() const noexcept -{ - return (m_normal); -} - -template -inline std::shared_ptr>& -EdgeT::getFace() noexcept -{ - return (m_face); -} - -template -inline const std::shared_ptr>& -EdgeT::getFace() const noexcept -{ - return (m_face); -} - -template -inline T -EdgeT::projectPointToEdge(const Vec3& a_x0) const noexcept -{ - const auto p = a_x0 - m_vertex->getPosition(); - - return p.dot(m_x2x1) * m_invLen2; -} - -template -inline T -EdgeT::signedDistance(const Vec3& a_x0) const noexcept -{ - const T t = this->projectPointToEdge(a_x0); - - T retval; - if (t <= 0.0) { // Closest point is the starting vertex - retval = this->getVertex()->signedDistance(a_x0); + template + inline EdgeT::EdgeT(const VertexPtr& a_vertex) : EdgeT() + { + m_vertex = a_vertex; } - else if (t >= 1.0) { // Closest point is the end vertex - retval = this->getOtherVertex()->signedDistance(a_x0); + + template + inline EdgeT::EdgeT(const Edge& a_otherEdge) : EdgeT() + { + m_face = a_otherEdge.m_face; + m_vertex = a_otherEdge.m_vertex; + m_pairEdge = a_otherEdge.m_pairEdge; + m_nextEdge = a_otherEdge.m_nextEdge; + m_previousEdge = a_otherEdge.m_previousEdge; + m_normal = a_otherEdge.m_normal; + m_x2x1 = a_otherEdge.m_x2x1; + m_invLen2 = a_otherEdge.m_invLen2; + } + + template + inline EdgeT::~EdgeT() + {} + + template + inline void + EdgeT::define(const VertexPtr& a_vertex, + const EdgePtr& a_pairEdge, + const EdgePtr& a_nextEdge, + const EdgePtr& a_previousEdge, + const Vec3 a_normal) noexcept + { + m_vertex = a_vertex; + m_pairEdge = a_pairEdge; + m_nextEdge = a_nextEdge; + m_previousEdge = a_previousEdge; + m_normal = a_normal; + } + + template + inline void + EdgeT::setVertex(const VertexPtr& a_vertex) noexcept + { + m_vertex = a_vertex; } - else { // Closest point is the edge itself. - const Vec3 linePoint = m_vertex->getPosition() + t * m_x2x1; - const Vec3 delta = a_x0 - linePoint; - const T dot = m_normal.dot(delta); - const int sgn = (dot > 0.0) ? 1 : -1; + template + inline void + EdgeT::setPairEdge(const EdgePtr& a_pairEdge) noexcept + { + m_pairEdge = a_pairEdge; + } - retval = sgn * delta.length(); + template + inline void + EdgeT::setNextEdge(const EdgePtr& a_nextEdge) noexcept + { + m_nextEdge = a_nextEdge; } - return retval; -} + template + inline void + EdgeT::setPreviousEdge(const EdgePtr& a_previousEdge) noexcept + { + m_previousEdge = a_previousEdge; + } -template -inline T -EdgeT::unsignedDistance2(const Vec3& a_x0) const noexcept -{ - T t = this->projectPointToEdge(a_x0); + template + inline void + EdgeT::setFace(const FacePtr& a_face) noexcept + { + m_face = a_face; + } + + template + inline void + EdgeT::normalizeNormalVector() noexcept + { + m_normal = m_normal / m_normal.length(); + } + + template + inline void + EdgeT::computeEdgeLength() noexcept + { + const auto& x1 = this->getVertex()->getPosition(); + const auto& x2 = this->getOtherVertex()->getPosition(); + + m_x2x1 = x2 - x1; + + const auto len2 = m_x2x1.dot(m_x2x1); + + m_invLen2 = 1. / len2; + } - constexpr T zero = 0.0; - constexpr T one = 1.0; + template + inline void + EdgeT::computeNormal() noexcept + { - t = std::min(std::max(zero, t), one); // Edge is on t=[0,1]. + m_normal = m_face->getNormal(); - const Vec3T linePoint = m_vertex->getPosition() + t * m_x2x1; - const Vec3T delta = a_x0 - linePoint; + if (m_pairEdge) { + m_normal += m_pairEdge->getFace()->getNormal(); + } + + this->normalizeNormalVector(); + } + + template + inline void + EdgeT::reconcile() noexcept + { + this->computeNormal(); + this->computeEdgeLength(); + } + + template + inline std::shared_ptr>& + EdgeT::getVertex() noexcept + { + return (m_vertex); + } + + template + inline const std::shared_ptr>& + EdgeT::getVertex() const noexcept + { + return (m_vertex); + } + + template + inline std::shared_ptr>& + EdgeT::getOtherVertex() noexcept + { + return (m_nextEdge->getVertex()); + } + + template + inline const std::shared_ptr>& + EdgeT::getOtherVertex() const noexcept + { + return (m_nextEdge->getVertex()); + } + + template + inline std::shared_ptr>& + EdgeT::getPairEdge() noexcept + { + return (m_pairEdge); + } - return delta.dot(delta); -} + template + inline const std::shared_ptr>& + EdgeT::getPairEdge() const noexcept + { + return (m_pairEdge); + } + + template + inline std::shared_ptr>& + EdgeT::getPreviousEdge() noexcept + { + return (m_previousEdge); + } + + template + inline const std::shared_ptr>& + EdgeT::getPreviousEdge() const noexcept + { + return (m_previousEdge); + } + + template + inline std::shared_ptr>& + EdgeT::getNextEdge() noexcept + { + return (m_nextEdge); + } + + template + inline const std::shared_ptr>& + EdgeT::getNextEdge() const noexcept + { + return (m_nextEdge); + } + + template + inline Vec3T& + EdgeT::getNormal() noexcept + { + return (m_normal); + } + + template + inline const Vec3T& + EdgeT::getNormal() const noexcept + { + return (m_normal); + } + + template + inline std::shared_ptr>& + EdgeT::getFace() noexcept + { + return (m_face); + } + + template + inline const std::shared_ptr>& + EdgeT::getFace() const noexcept + { + return (m_face); + } + + template + inline T + EdgeT::projectPointToEdge(const Vec3& a_x0) const noexcept + { + const auto p = a_x0 - m_vertex->getPosition(); + + return p.dot(m_x2x1) * m_invLen2; + } + + template + inline T + EdgeT::signedDistance(const Vec3& a_x0) const noexcept + { + const T t = this->projectPointToEdge(a_x0); + + T retval; + if (t <= 0.0) { // Closest point is the starting vertex + retval = this->getVertex()->signedDistance(a_x0); + } + else if (t >= 1.0) { // Closest point is the end vertex + retval = this->getOtherVertex()->signedDistance(a_x0); + } + else { // Closest point is the edge itself. + const Vec3 linePoint = m_vertex->getPosition() + t * m_x2x1; + const Vec3 delta = a_x0 - linePoint; + const T dot = m_normal.dot(delta); + + const int sgn = (dot > 0.0) ? 1 : -1; + + retval = sgn * delta.length(); + } + + return retval; + } + + template + inline T + EdgeT::unsignedDistance2(const Vec3& a_x0) const noexcept + { + T t = this->projectPointToEdge(a_x0); + + constexpr T zero = 0.0; + constexpr T one = 1.0; + + t = std::min(std::max(zero, t), one); // Edge is on t=[0,1]. + + const Vec3T linePoint = m_vertex->getPosition() + t * m_x2x1; + const Vec3T delta = a_x0 - linePoint; + + return delta.dot(delta); + } } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Face.hpp b/Source/EBGeometry_DCEL_Face.hpp index 672dccc1..ec179990 100644 --- a/Source/EBGeometry_DCEL_Face.hpp +++ b/Source/EBGeometry_DCEL_Face.hpp @@ -26,17 +26,17 @@ namespace DCEL { -// Forward declarations of other DCEL functionality. -template -class VertexT; -template -class EdgeT; -template -class FaceT; -template -class EdgeIteratorT; + // Forward declarations of other DCEL functionality. + template + class VertexT; + template + class EdgeT; + template + class FaceT; + template + class EdgeIteratorT; -/*! + /*! @brief Class which represents a polygon face in a double-edge connected list (DCEL). @details This class is a polygon face in a DCEL mesh. It contains pointer @@ -55,160 +55,160 @@ class EdgeIteratorT; algorithm. Other algorithms can be set in setInsideOutsideAlgorithm (see CD_DCELAlgorithms.H) */ -template -class FaceT -{ -public: - /*! + template + class FaceT + { + public: + /*! @brief Alias to cut down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Alias to cut down on typing */ - using Vertex = VertexT; + using Vertex = VertexT; - /*! + /*! @brief Alias to cut down on typing */ - using Edge = EdgeT; + using Edge = EdgeT; - /*! + /*! @brief Alias to cut down on typing */ - using Face = FaceT; + using Face = FaceT; - /*! + /*! @brief Alias to cut down on typing */ - using VertexPtr = std::shared_ptr; + using VertexPtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using EdgePtr = std::shared_ptr; + using EdgePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using FacePtr = std::shared_ptr; + using FacePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using EdgeIterator = EdgeIteratorT; + using EdgeIterator = EdgeIteratorT; - /*! + /*! @brief Default constructor. Sets the half-edge to zero and the inside/outside algorithm to crossing number algorithm */ - FaceT(); + FaceT(); - /*! + /*! @brief Partial constructor. Calls default constructor but associates a half-edge @param[in] a_edge Half-edge */ - FaceT(const EdgePtr& a_edge); + FaceT(const EdgePtr& a_edge); - /*! + /*! @brief Partial constructor. @details Calls default constructor but sets the normal vector and half-edge equal to the other face's (rest is undefined) */ - FaceT(const Face& a_otherFace); + FaceT(const Face& a_otherFace); - /*! + /*! @brief Destructor (does nothing) */ - ~FaceT(); + ~FaceT(); - /*! + /*! @brief Define function which sets the normal vector and half-edge @param[in] a_normal Normal vector @param[in] a_edge Half edge */ - inline void - define(const Vec3& a_normal, const EdgePtr& a_edge) noexcept; + inline void + define(const Vec3& a_normal, const EdgePtr& a_edge) noexcept; - /*! + /*! @brief Reconcile face. This will compute the normal vector, area, centroid, and the 2D embedding of the polygon @note "Everything" must be set before doing this, i.e. the face must be complete with half edges and there can be no dangling edges. */ - inline void - reconcile() noexcept; + inline void + reconcile() noexcept; - /*! + /*! @brief Set the half edge @param[in] a_halfEdge Half edge */ - inline void - setHalfEdge(const EdgePtr& a_halfEdge) noexcept; + inline void + setHalfEdge(const EdgePtr& a_halfEdge) noexcept; - /*! + /*! @brief Set the inside/outside algorithm when determining if a point projects to the inside or outside of the polygon. @param[in] a_algorithm Desired algorithm @note See CD_DCELAlgorithms.H for options (and CD_DCELPolyImplem.H for how the algorithms operate). */ - inline void - setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm& a_algorithm) noexcept; + inline void + setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm& a_algorithm) noexcept; - /*! + /*! @brief Get modifiable half-edge */ - inline EdgePtr& - getHalfEdge() noexcept; + inline EdgePtr& + getHalfEdge() noexcept; - /*! + /*! @brief Get immutable half-edge */ - inline const EdgePtr& - getHalfEdge() const noexcept; + inline const EdgePtr& + getHalfEdge() const noexcept; - /*! + /*! @brief Get modifiable centroid */ - inline Vec3T& - getCentroid() noexcept; + inline Vec3T& + getCentroid() noexcept; - /*! + /*! @brief Get immutable centroid */ - inline const Vec3T& - getCentroid() const noexcept; + inline const Vec3T& + getCentroid() const noexcept; - /*! + /*! @brief Get modifiable centroid position in specified coordinate direction @param[in] a_dir Coordinate direction */ - inline T& - getCentroid(const size_t a_dir) noexcept; + inline T& + getCentroid(const size_t a_dir) noexcept; - /*! + /*! @brief Get immutable centroid position in specified coordinate direction @param[in] a_dir Coordinate direction */ - inline const T& - getCentroid(const size_t a_dir) const noexcept; + inline const T& + getCentroid(const size_t a_dir) const noexcept; - /*! + /*! @brief Get modifiable normal vector */ - inline Vec3T& - getNormal() noexcept; + inline Vec3T& + getNormal() noexcept; - /*! + /*! @brief Get immutable normal vector */ - inline const Vec3T& - getNormal() const noexcept; + inline const Vec3T& + getNormal() const noexcept; - /*! + /*! @brief Compute the signed distance to a point. @param[in] a_x0 Point in space @details This algorithm operates by checking if the input point projects to @@ -216,10 +216,10 @@ class FaceT projected distance onto the polygon plane and the sign is well-defined. Otherwise, we check the distance to the edges of the polygon. */ - inline T - signedDistance(const Vec3& a_x0) const noexcept; + inline T + signedDistance(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Compute the unsigned squared distance to a point. @param[in] a_x0 Point in space @details This algorithm operates by checking if the input point projects to @@ -227,137 +227,137 @@ class FaceT projected distance onto the polygon plane. Otherwise, we check the distance to the edges of the polygon. */ - inline T - unsignedDistance2(const Vec3& a_x0) const noexcept; + inline T + unsignedDistance2(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Return the coordinates of all the vertices on this polygon. @details This builds a list of all the vertex coordinates and returns it. */ - inline std::vector> - getAllVertexCoordinates() const noexcept; + inline std::vector> + getAllVertexCoordinates() const noexcept; - /*! + /*! @brief Return all the vertices on this polygon @details This builds a list of all the vertices and returns it. */ - inline std::vector - gatherVertices() const noexcept; + inline std::vector + gatherVertices() const noexcept; - /*! + /*! @brief Get the lower-left-most coordinate of this polygon face */ - inline Vec3T - getSmallestCoordinate() const noexcept; + inline Vec3T + getSmallestCoordinate() const noexcept; - /*! + /*! @brief Get the upper-right-most coordinate of this polygon face */ - inline Vec3T - getHighestCoordinate() const noexcept; + inline Vec3T + getHighestCoordinate() const noexcept; -protected: - /*! + protected: + /*! @brief This polygon's half-edge. A valid face will always have != nullptr */ - EdgePtr m_halfEdge; + EdgePtr m_halfEdge; - /*! + /*! @brief Pointers to all the half-edges of this face. Exists for performance reasons (in signedDistance(...)) */ - std::vector m_edges; // Exists because of performance reasons. + std::vector m_edges; // Exists because of performance reasons. - /*! + /*! @brief Polygon face area */ - T m_area; + T m_area; - /*! + /*! @brief Polygon face normal vector */ - Vec3 m_normal; + Vec3 m_normal; - /*! + /*! @brief Polygon face centroid position */ - Vec3 m_centroid; + Vec3 m_centroid; - /*! + /*! @brief 2D embedding of this polygon. This is the 2D view of the current object projected along its normal vector cardinal. */ - std::shared_ptr> m_poly2; + std::shared_ptr> m_poly2; - /*! + /*! @brief Algorithm for inside/outside tests */ - typename Polygon2D::InsideOutsideAlgorithm m_poly2Algorithm; + typename Polygon2D::InsideOutsideAlgorithm m_poly2Algorithm; - /*! + /*! @brief Compute the area of this polygon */ - inline void - computeArea() noexcept; + inline void + computeArea() noexcept; - /*! + /*! @brief Compute the centroid position of this polygon */ - inline void - computeCentroid() noexcept; + inline void + computeCentroid() noexcept; - /*! + /*! @brief Compute the normal position of this polygon */ - inline void - computeNormal() noexcept; + inline void + computeNormal() noexcept; - /*! + /*! @brief Compute the 2D embedding of this polygon */ - inline void - computePolygon2D() noexcept; + inline void + computePolygon2D() noexcept; - /*! + /*! @brief Normalize the normal vector, ensuring it has a length of 1 */ - inline void - normalizeNormalVector() noexcept; + inline void + normalizeNormalVector() noexcept; - /*! + /*! @brief Get the area of this polygon face */ - inline T - getArea() noexcept; + inline T + getArea() noexcept; - /*! + /*! @brief Get the area of this polygon face */ - inline T - getArea() const noexcept; + inline T + getArea() const noexcept; - /*! + /*! @brief Compute and store all the half-edges around this polygon face */ - inline void - computeAndStoreEdges() noexcept; + inline void + computeAndStoreEdges() noexcept; - /*! + /*! @brief Compute the projection of a point onto the polygon face plane @param[in] a_p Point in space */ - inline Vec3T - projectPointIntoFacePlane(const Vec3& a_p) const noexcept; + inline Vec3T + projectPointIntoFacePlane(const Vec3& a_p) const noexcept; - /*! + /*! @brief Check if a point projects to inside or outside the polygon face @param[in] a_p Point in space @return Returns true if a_p projects to inside the polygon and false otherwise. */ - inline bool - isPointInsideFace(const Vec3& a_p) const noexcept; -}; + inline bool + isPointInsideFace(const Vec3& a_p) const noexcept; + }; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_FaceImplem.hpp b/Source/EBGeometry_DCEL_FaceImplem.hpp index 57cffaa0..25ddd61f 100644 --- a/Source/EBGeometry_DCEL_FaceImplem.hpp +++ b/Source/EBGeometry_DCEL_FaceImplem.hpp @@ -19,341 +19,340 @@ namespace DCEL { -template -inline FaceT::FaceT() -{ - m_halfEdge = nullptr; - m_normal = Vec3::zero(); - m_poly2Algorithm = Polygon2D::InsideOutsideAlgorithm::CrossingNumber; -} - -template -inline FaceT::FaceT(const EdgePtr& a_edge) : Face() -{ - m_halfEdge = a_edge; -} - -template -inline FaceT::FaceT(const Face& a_otherFace) : Face() -{ - m_normal = a_otherFace.getNormal(); - m_halfEdge = a_otherFace.getHalfEdge(); -} - -template -inline FaceT::~FaceT() -{ -} - -template -inline void -FaceT::define(const Vec3& a_normal, const EdgePtr& a_edge) noexcept -{ - m_normal = a_normal; - m_halfEdge = a_edge; -} - -template -inline void -FaceT::reconcile() noexcept -{ - this->computeNormal(); - this->normalizeNormalVector(); - this->computeCentroid(); - this->computeArea(); - this->computePolygon2D(); - this->computeAndStoreEdges(); -} - -template -inline void -FaceT::computeAndStoreEdges() noexcept -{ - m_edges.resize(0); - - for (EdgeIterator edgeIt(*this); edgeIt.ok(); ++edgeIt) { - m_edges.emplace_back(edgeIt()); + template + inline FaceT::FaceT() + { + m_halfEdge = nullptr; + m_normal = Vec3::zero(); + m_poly2Algorithm = Polygon2D::InsideOutsideAlgorithm::CrossingNumber; } -} - -template -inline void -FaceT::setHalfEdge(const EdgePtr& a_halfEdge) noexcept -{ - m_halfEdge = a_halfEdge; -} - -template -inline void -FaceT::normalizeNormalVector() noexcept -{ - m_normal = m_normal / m_normal.length(); -} - -template -inline void -FaceT::setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm& a_algorithm) noexcept -{ - m_poly2Algorithm = a_algorithm; -} - -template -inline void -FaceT::computeArea() noexcept -{ - m_area = 0.0; - - // This computes the area of any N-side polygon. - const auto vertices = this->gatherVertices(); - - for (size_t i = 0; i < vertices.size() - 1; i++) { - const auto& v1 = vertices[i]->getPosition(); - const auto& v2 = vertices[i + 1]->getPosition(); - m_area += m_normal.dot(v2.cross(v1)); + + template + inline FaceT::FaceT(const EdgePtr& a_edge) : Face() + { + m_halfEdge = a_edge; } - m_area = 0.5 * std::abs(m_area); -} + template + inline FaceT::FaceT(const Face& a_otherFace) : Face() + { + m_normal = a_otherFace.getNormal(); + m_halfEdge = a_otherFace.getHalfEdge(); + } -template -inline void -FaceT::computeCentroid() noexcept -{ - m_centroid = Vec3::zero(); + template + inline FaceT::~FaceT() + {} - const auto vertices = this->gatherVertices(); + template + inline void + FaceT::define(const Vec3& a_normal, const EdgePtr& a_edge) noexcept + { + m_normal = a_normal; + m_halfEdge = a_edge; + } - for (const auto& v : vertices) { - m_centroid += v->getPosition(); + template + inline void + FaceT::reconcile() noexcept + { + this->computeNormal(); + this->normalizeNormalVector(); + this->computeCentroid(); + this->computeArea(); + this->computePolygon2D(); + this->computeAndStoreEdges(); + } + + template + inline void + FaceT::computeAndStoreEdges() noexcept + { + m_edges.resize(0); + + for (EdgeIterator edgeIt(*this); edgeIt.ok(); ++edgeIt) { + m_edges.emplace_back(edgeIt()); + } } - m_centroid = m_centroid / vertices.size(); -} + template + inline void + FaceT::setHalfEdge(const EdgePtr& a_halfEdge) noexcept + { + m_halfEdge = a_halfEdge; + } -template -inline void -FaceT::computeNormal() noexcept -{ - const auto vertices = this->gatherVertices(); + template + inline void + FaceT::normalizeNormalVector() noexcept + { + m_normal = m_normal / m_normal.length(); + } - const size_t N = vertices.size(); + template + inline void + FaceT::setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm& a_algorithm) noexcept + { + m_poly2Algorithm = a_algorithm; + } - // To compute the normal vector we find three vertices in this polygon face. - // They span a plane, and we just compute the normal vector of that plane. - for (size_t i = 0; i < N; i++) { - const auto& x0 = vertices[i]->getPosition(); - const auto& x1 = vertices[(i + 1) % N]->getPosition(); - const auto& x2 = vertices[(i + 2) % N]->getPosition(); + template + inline void + FaceT::computeArea() noexcept + { + m_area = 0.0; - m_normal = (x2 - x1).cross(x2 - x0); + // This computes the area of any N-side polygon. + const auto vertices = this->gatherVertices(); - if (m_normal.length() > 0.0) { - break; // Found one. + for (size_t i = 0; i < vertices.size() - 1; i++) { + const auto& v1 = vertices[i]->getPosition(); + const auto& v2 = vertices[i + 1]->getPosition(); + m_area += m_normal.dot(v2.cross(v1)); } + + m_area = 0.5 * std::abs(m_area); } - this->normalizeNormalVector(); -} - -template -inline void -FaceT::computePolygon2D() noexcept -{ - m_poly2 = std::make_shared>(m_normal, this->getAllVertexCoordinates()); -} - -template -inline T& -FaceT::getCentroid(const size_t a_dir) noexcept -{ - return m_centroid[a_dir]; -} - -template -inline const T& -FaceT::getCentroid(const size_t a_dir) const noexcept -{ - return m_centroid[a_dir]; -} - -template -inline Vec3T& -FaceT::getCentroid() noexcept -{ - return (m_centroid); -} - -template -inline const Vec3T& -FaceT::getCentroid() const noexcept -{ - return (m_centroid); -} - -template -inline Vec3T& -FaceT::getNormal() noexcept -{ - return (m_normal); -} - -template -inline const Vec3T& -FaceT::getNormal() const noexcept -{ - return (m_normal); -} - -template -inline T -FaceT::getArea() noexcept -{ - return (m_area); -} - -template -inline T -FaceT::getArea() const noexcept -{ - return (m_area); -} - -template -inline std::shared_ptr>& -FaceT::getHalfEdge() noexcept -{ - return (m_halfEdge); -} - -template -inline const std::shared_ptr>& -FaceT::getHalfEdge() const noexcept -{ - return (m_halfEdge); -} - -template -inline std::vector>> -FaceT::gatherVertices() const noexcept -{ - std::vector vertices; - - for (EdgeIterator iter(*this); iter.ok(); ++iter) { - EdgePtr& edge = iter(); - vertices.emplace_back(edge->getVertex()); + template + inline void + FaceT::computeCentroid() noexcept + { + m_centroid = Vec3::zero(); + + const auto vertices = this->gatherVertices(); + + for (const auto& v : vertices) { + m_centroid += v->getPosition(); + } + + m_centroid = m_centroid / vertices.size(); } - return vertices; -} + template + inline void + FaceT::computeNormal() noexcept + { + const auto vertices = this->gatherVertices(); + + const size_t N = vertices.size(); -template -inline std::vector> -FaceT::getAllVertexCoordinates() const noexcept -{ - std::vector ret; + // To compute the normal vector we find three vertices in this polygon face. + // They span a plane, and we just compute the normal vector of that plane. + for (size_t i = 0; i < N; i++) { + const auto& x0 = vertices[i]->getPosition(); + const auto& x1 = vertices[(i + 1) % N]->getPosition(); + const auto& x2 = vertices[(i + 2) % N]->getPosition(); - for (EdgeIterator iter(*this); iter.ok(); ++iter) { - EdgePtr& edge = iter(); - ret.emplace_back(edge->getVertex()->getPosition()); + m_normal = (x2 - x1).cross(x2 - x0); + + if (m_normal.length() > 0.0) { + break; // Found one. + } + } + + this->normalizeNormalVector(); } - return ret; -} + template + inline void + FaceT::computePolygon2D() noexcept + { + m_poly2 = std::make_shared>(m_normal, this->getAllVertexCoordinates()); + } -template -inline Vec3T -FaceT::getSmallestCoordinate() const noexcept -{ - const auto coords = this->getAllVertexCoordinates(); + template + inline T& + FaceT::getCentroid(const size_t a_dir) noexcept + { + return m_centroid[a_dir]; + } - auto minCoord = coords.front(); + template + inline const T& + FaceT::getCentroid(const size_t a_dir) const noexcept + { + return m_centroid[a_dir]; + } + + template + inline Vec3T& + FaceT::getCentroid() noexcept + { + return (m_centroid); + } - for (const auto& c : coords) { - minCoord = min(minCoord, c); + template + inline const Vec3T& + FaceT::getCentroid() const noexcept + { + return (m_centroid); } - return minCoord; -} + template + inline Vec3T& + FaceT::getNormal() noexcept + { + return (m_normal); + } + + template + inline const Vec3T& + FaceT::getNormal() const noexcept + { + return (m_normal); + } -template -inline Vec3T -FaceT::getHighestCoordinate() const noexcept -{ - const auto coords = this->getAllVertexCoordinates(); + template + inline T + FaceT::getArea() noexcept + { + return (m_area); + } - auto maxCoord = coords.front(); + template + inline T + FaceT::getArea() const noexcept + { + return (m_area); + } - for (const auto& c : coords) { - maxCoord = max(maxCoord, c); + template + inline std::shared_ptr>& + FaceT::getHalfEdge() noexcept + { + return (m_halfEdge); } - return maxCoord; -} + template + inline const std::shared_ptr>& + FaceT::getHalfEdge() const noexcept + { + return (m_halfEdge); + } -template -inline Vec3T -FaceT::projectPointIntoFacePlane(const Vec3& a_p) const noexcept -{ - return a_p - m_normal * (m_normal.dot(a_p - m_centroid)); -} + template + inline std::vector>> + FaceT::gatherVertices() const noexcept + { + std::vector vertices; -template -inline bool -FaceT::isPointInsideFace(const Vec3& a_p) const noexcept -{ - const Vec3 p = this->projectPointIntoFacePlane(a_p); + for (EdgeIterator iter(*this); iter.ok(); ++iter) { + EdgePtr& edge = iter(); + vertices.emplace_back(edge->getVertex()); + } - return m_poly2->isPointInside(p, m_poly2Algorithm); -} + return vertices; + } -template -inline T -FaceT::signedDistance(const Vec3& a_x0) const noexcept -{ - T retval = std::numeric_limits::infinity(); + template + inline std::vector> + FaceT::getAllVertexCoordinates() const noexcept + { + std::vector ret; - const bool inside = this->isPointInsideFace(a_x0); + for (EdgeIterator iter(*this); iter.ok(); ++iter) { + EdgePtr& edge = iter(); + ret.emplace_back(edge->getVertex()->getPosition()); + } - if (inside) { // Projects to inside so distance and sign are straightforward - // to compute. - retval = m_normal.dot(a_x0 - m_centroid); + return ret; } - else { - for (const auto& e : m_edges) { // Projects to outside so edge/vertex are - // closest. Check that distance. - const T curDist = e->signedDistance(a_x0); - retval = (std::abs(curDist) < std::abs(retval)) ? curDist : retval; + template + inline Vec3T + FaceT::getSmallestCoordinate() const noexcept + { + const auto coords = this->getAllVertexCoordinates(); + + auto minCoord = coords.front(); + + for (const auto& c : coords) { + minCoord = min(minCoord, c); } + + return minCoord; } - return retval; -} + template + inline Vec3T + FaceT::getHighestCoordinate() const noexcept + { + const auto coords = this->getAllVertexCoordinates(); -template -inline T -FaceT::unsignedDistance2(const Vec3& a_x0) const noexcept -{ - T retval = std::numeric_limits::infinity(); + auto maxCoord = coords.front(); + + for (const auto& c : coords) { + maxCoord = max(maxCoord, c); + } - const bool inside = this->isPointInsideFace(a_x0); + return maxCoord; + } + + template + inline Vec3T + FaceT::projectPointIntoFacePlane(const Vec3& a_p) const noexcept + { + return a_p - m_normal * (m_normal.dot(a_p - m_centroid)); + } - if (inside) { // Projects to inside the polygon face so distance is - // straightforward. - const T normDist = m_normal.dot(a_x0 - m_centroid); + template + inline bool + FaceT::isPointInsideFace(const Vec3& a_p) const noexcept + { + const Vec3 p = this->projectPointIntoFacePlane(a_p); - retval = normDist * normDist; + return m_poly2->isPointInside(p, m_poly2Algorithm); } - else { - for (const auto& e : m_edges) { // Projects to outside so edge/vertex are closest. - const T curDist2 = e->unsignedDistance2(a_x0); - retval = (curDist2 < retval) ? curDist2 : retval; + template + inline T + FaceT::signedDistance(const Vec3& a_x0) const noexcept + { + T retval = std::numeric_limits::infinity(); + + const bool inside = this->isPointInsideFace(a_x0); + + if (inside) { // Projects to inside so distance and sign are straightforward + // to compute. + retval = m_normal.dot(a_x0 - m_centroid); + } + else { + for (const auto& e : m_edges) { // Projects to outside so edge/vertex are + // closest. Check that distance. + const T curDist = e->signedDistance(a_x0); + + retval = (std::abs(curDist) < std::abs(retval)) ? curDist : retval; + } } + + return retval; } - return retval; -} + template + inline T + FaceT::unsignedDistance2(const Vec3& a_x0) const noexcept + { + T retval = std::numeric_limits::infinity(); + + const bool inside = this->isPointInsideFace(a_x0); + + if (inside) { // Projects to inside the polygon face so distance is + // straightforward. + const T normDist = m_normal.dot(a_x0 - m_centroid); + + retval = normDist * normDist; + } + else { + for (const auto& e : m_edges) { // Projects to outside so edge/vertex are closest. + const T curDist2 = e->unsignedDistance2(a_x0); + + retval = (curDist2 < retval) ? curDist2 : retval; + } + } + + return retval; + } } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Iterator.hpp b/Source/EBGeometry_DCEL_Iterator.hpp index f50e125e..8818d617 100644 --- a/Source/EBGeometry_DCEL_Iterator.hpp +++ b/Source/EBGeometry_DCEL_Iterator.hpp @@ -20,160 +20,160 @@ namespace DCEL { -// Forward declare classes. -template -class VertexT; -template -class EdgeT; -template -class FaceT; + // Forward declare classes. + template + class VertexT; + template + class EdgeT; + template + class FaceT; -/*! + /*! @brief Class which can iterate through edges and vertices around a DCEL polygon face. @details This class can be used so that it either visits all the half-edges in a face, or all the outgoing half-edges from a vertex. */ -template -class EdgeIteratorT -{ -public: - /*! + template + class EdgeIteratorT + { + public: + /*! @brief Alias to cut down on typing */ - using Vertex = VertexT; + using Vertex = VertexT; - /*! + /*! @brief Alias to cut down on typing */ - using Edge = EdgeT; + using Edge = EdgeT; - /*! + /*! @brief Alias to cut down on typing */ - using Face = FaceT; + using Face = FaceT; - /*! + /*! @brief Alias to cut down on typing */ - using VertexPtr = std::shared_ptr; + using VertexPtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using EdgePtr = std::shared_ptr; + using EdgePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing */ - using FacePtr = std::shared_ptr; + using FacePtr = std::shared_ptr; - /*! + /*! @brief Default construction is not allowed. Use one of the full constructors */ - EdgeIteratorT() = delete; + EdgeIteratorT() = delete; - /*! + /*! @brief Constructor, taking a face as argument. The iterator begins at the half-edge pointer contained in the face @param[in] a_face DCEL polygon face @note This constructor will will iterate through the half-edges in the polygon face. */ - EdgeIteratorT(Face& a_face); + EdgeIteratorT(Face& a_face); - /*! + /*! @brief Constructor, taking a face as argument. The iterator begins at the half-edge pointer contained in the face @param[in] a_face DCEL polygon face @note This constructor will will iterate through the half-edges in the polygon face. */ - EdgeIteratorT(const Face& a_face); + EdgeIteratorT(const Face& a_face); - /*! + /*! @brief Constructor, taking a vertex as argument. The iterator begins at the outgoing half-edge from the vertex @param[in] a_vertex DCEL vertex @note This constructor will will iterate through the outgoing half-edges from a vertex. */ - EdgeIteratorT(Vertex& a_vertex); + EdgeIteratorT(Vertex& a_vertex); - /*! + /*! @brief Constructor, taking a vertex as argument. The iterator begins at the outgoing half-edge from the vertex @param[in] a_vertex DCEL vertex @note This constructor will will iterate through the outgoing half-edges from a vertex. */ - EdgeIteratorT(const Vertex& a_vertex); + EdgeIteratorT(const Vertex& a_vertex); - /*! + /*! @brief Operator returning a pointer to the current half-edge */ - inline EdgePtr& - operator()() noexcept; + inline EdgePtr& + operator()() noexcept; - /*! + /*! @brief Operator returning a pointer to the current half-edge */ - inline const EdgePtr& - operator()() const noexcept; + inline const EdgePtr& + operator()() const noexcept; - /*! + /*! @brief Reset function for the iterator. This resets the iterator so that it begins from the starting half-edge */ - inline void - reset() noexcept; + inline void + reset() noexcept; - /*! + /*! @brief Incrementation operator, bringing the iterator to the next half-edge */ - inline void - operator++() noexcept; + inline void + operator++() noexcept; - /*! + /*! @brief Function which checks if the iteration can be continued. @return Returns true unless the current half-edge is a nullptr (i.e., a broken polygon face) OR a full loop has been made around the polygon face (i.e. all half-edges have been visited) */ - inline bool - ok() const noexcept; + inline bool + ok() const noexcept; -protected: - /*! + protected: + /*! @brief Iteration mode, used to distinguish between the two constructors (face- or vertex-based iteration) */ - enum class IterationMode - { - Vertices, - Faces - }; + enum class IterationMode + { + Vertices, + Faces + }; - /*! + /*! @brief If true, a full loop has been made around the polygon face */ - bool m_fullLoop; + bool m_fullLoop; - /*! + /*! @brief Iteration mode. Set in constructor */ - IterationMode m_iterMode; + IterationMode m_iterMode; - /*! + /*! @brief Starting half-edge */ - std::shared_ptr m_startEdge; + std::shared_ptr m_startEdge; - /*! + /*! @brief Current half-edge */ - std::shared_ptr m_curEdge; -}; + std::shared_ptr m_curEdge; + }; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_IteratorImplem.hpp b/Source/EBGeometry_DCEL_IteratorImplem.hpp index 939961a5..b1b8cb89 100644 --- a/Source/EBGeometry_DCEL_IteratorImplem.hpp +++ b/Source/EBGeometry_DCEL_IteratorImplem.hpp @@ -21,95 +21,95 @@ namespace DCEL { -template -inline EdgeIteratorT::EdgeIteratorT(Face& a_face) -{ - m_startEdge = a_face.getHalfEdge(); - m_curEdge = m_startEdge; - m_fullLoop = false; - m_iterMode = IterationMode::Faces; -} - -template -inline EdgeIteratorT::EdgeIteratorT(const Face& a_face) -{ - m_startEdge = a_face.getHalfEdge(); - m_curEdge = m_startEdge; - m_fullLoop = false; - m_iterMode = IterationMode::Faces; -} - -template -inline EdgeIteratorT::EdgeIteratorT(Vertex& a_vert) -{ - m_startEdge = a_vert.getOutgoingEdge(); - m_curEdge = m_startEdge; - m_fullLoop = false; - m_iterMode = IterationMode::Vertices; -} - -template -inline EdgeIteratorT::EdgeIteratorT(const Vertex& a_vert) -{ - m_startEdge = a_vert.getOutgoingEdge(); - m_curEdge = m_startEdge; - m_fullLoop = false; - m_iterMode = IterationMode::Vertices; -} - -template -inline std::shared_ptr>& -EdgeIteratorT::operator()() noexcept -{ - return (m_curEdge); -} - -template -inline const std::shared_ptr>& -EdgeIteratorT::operator()() const noexcept -{ - return (m_curEdge); -} - -template -inline void -EdgeIteratorT::reset() noexcept -{ - m_curEdge = m_startEdge; - m_fullLoop = false; -} - -template -inline void -EdgeIteratorT::operator++() noexcept -{ - switch (m_iterMode) { - case IterationMode::Faces: { - m_curEdge = m_curEdge->getNextEdge(); - - break; + template + inline EdgeIteratorT::EdgeIteratorT(Face& a_face) + { + m_startEdge = a_face.getHalfEdge(); + m_curEdge = m_startEdge; + m_fullLoop = false; + m_iterMode = IterationMode::Faces; } - case IterationMode::Vertices: { - // For vertices, we want to compute the - m_curEdge = m_curEdge->getPreviousEdge()->getPairEdge(); - break; + template + inline EdgeIteratorT::EdgeIteratorT(const Face& a_face) + { + m_startEdge = a_face.getHalfEdge(); + m_curEdge = m_startEdge; + m_fullLoop = false; + m_iterMode = IterationMode::Faces; } - default: { - std::cerr << "In file 'EBGeometry_DCEL_IteratorImplem.hpp function " - "EdgeIteratorT::operator++ - logic bust\n"; + + template + inline EdgeIteratorT::EdgeIteratorT(Vertex& a_vert) + { + m_startEdge = a_vert.getOutgoingEdge(); + m_curEdge = m_startEdge; + m_fullLoop = false; + m_iterMode = IterationMode::Vertices; + } + + template + inline EdgeIteratorT::EdgeIteratorT(const Vertex& a_vert) + { + m_startEdge = a_vert.getOutgoingEdge(); + m_curEdge = m_startEdge; + m_fullLoop = false; + m_iterMode = IterationMode::Vertices; + } + + template + inline std::shared_ptr>& + EdgeIteratorT::operator()() noexcept + { + return (m_curEdge); } + + template + inline const std::shared_ptr>& + EdgeIteratorT::operator()() const noexcept + { + return (m_curEdge); } - m_fullLoop = (m_curEdge == m_startEdge); -} + template + inline void + EdgeIteratorT::reset() noexcept + { + m_curEdge = m_startEdge; + m_fullLoop = false; + } -template -inline bool -EdgeIteratorT::ok() const noexcept -{ - return !m_fullLoop && m_curEdge; -} + template + inline void + EdgeIteratorT::operator++() noexcept + { + switch (m_iterMode) { + case IterationMode::Faces: { + m_curEdge = m_curEdge->getNextEdge(); + + break; + } + case IterationMode::Vertices: { + // For vertices, we want to compute the + m_curEdge = m_curEdge->getPreviousEdge()->getPairEdge(); + + break; + } + default: { + std::cerr << "In file 'EBGeometry_DCEL_IteratorImplem.hpp function " + "EdgeIteratorT::operator++ - logic bust\n"; + } + } + + m_fullLoop = (m_curEdge == m_startEdge); + } + + template + inline bool + EdgeIteratorT::ok() const noexcept + { + return !m_fullLoop && m_curEdge; + } } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Mesh.hpp b/Source/EBGeometry_DCEL_Mesh.hpp index 2afcfee6..f9b92f3b 100644 --- a/Source/EBGeometry_DCEL_Mesh.hpp +++ b/Source/EBGeometry_DCEL_Mesh.hpp @@ -28,15 +28,15 @@ class Polygon2D; namespace DCEL { -// Forward declare classes. -template -class VertexT; -template -class EdgeT; -template -class FaceT; + // Forward declare classes. + template + class VertexT; + template + class EdgeT; + template + class FaceT; -/*! + /*! @brief Mesh class which stores a full DCEL mesh (with signed distance functions) @details This encapsulates a full DCEL mesh, and also includes DIRECT signed @@ -51,82 +51,82 @@ class FaceT; and builds the mesh from that. Do not try to build a MeshT object yourself, use file parsers! */ -template -class MeshT : public SignedDistanceFunction -{ -public: - /*! + template + class MeshT : public SignedDistanceFunction + { + public: + /*! @brief Possible search algorithms for DCEL::MeshT @details Direct means compute the signed distance for all primitives, Direct2 means compute the squared signed distance for all primitives. */ - enum class SearchAlgorithm - { - Direct, - Direct2, - }; + enum class SearchAlgorithm + { + Direct, + Direct2, + }; - /*! + /*! @brief How to weight vertex normal */ - enum class VertexNormalWeight - { - None, - Angle, - }; + enum class VertexNormalWeight + { + None, + Angle, + }; - /*! + /*! @brief Alias to cut down on the typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Alias to cut down on the typing */ - using Vertex = VertexT; + using Vertex = VertexT; - /*! + /*! @brief Alias to cut down on the typing */ - using Edge = EdgeT; + using Edge = EdgeT; - /*! + /*! @brief Alias to cut down on the typing */ - using Face = FaceT; + using Face = FaceT; - /*! + /*! @brief Alias to cut down on the typing */ - using VertexPtr = std::shared_ptr; + using VertexPtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on the typing */ - using EdgePtr = std::shared_ptr; + using EdgePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on the typing */ - using FacePtr = std::shared_ptr; + using FacePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on the typing */ - using Mesh = MeshT; + using Mesh = MeshT; - /*! + /*! @brief Default constructor. Leaves unobject in an unusable state */ - MeshT(); + MeshT(); - /*! + /*! @brief Disallowed copy construction @param[in] a_otherMesh Other mesh */ - MeshT(const Mesh& a_otherMesh) = delete; + MeshT(const Mesh& a_otherMesh) = delete; - /*! + /*! @brief Full constructor. This provides the faces, edges, and vertices to the mesh. @details Calls define(a_faces, a_edges, a_vertices) @@ -137,14 +137,14 @@ class MeshT : public SignedDistanceFunction description. This is usually done through a file parser which reads a mesh file format and creates the DCEL mesh structure */ - MeshT(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices); + MeshT(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices); - /*! + /*! @brief Destructor (does nothing) */ - ~MeshT(); + ~MeshT(); - /*! + /*! @brief Define function. Puts Mesh in usable state. @param[in] a_faces Polygon faces @param[in] a_edges Half-edges @@ -155,27 +155,27 @@ class MeshT : public SignedDistanceFunction involves associating pointer structures through the mesh. Internal parameters like face area and normal is computed in MeshT::reconcile. */ - inline void - define(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices) noexcept; + inline void + define(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices) noexcept; - /*! + /*! @brief Perform a sanity check. @details This will provide error messages if vertices are badly linked, faces are nullptr, and so on. These messages are logged by calling incrementWarning() which identifies types of errors that can occur, and how many of those errors have occurred. */ - inline void - sanityCheck() const noexcept; + inline void + sanityCheck() const noexcept; - /*! + /*! @brief Search algorithm for direct signed distance computations @param[in] a_algorithm Algorithm to use */ - inline void - setSearchAlgorithm(const SearchAlgorithm a_algorithm) noexcept; + inline void + setSearchAlgorithm(const SearchAlgorithm a_algorithm) noexcept; - /*! + /*! @brief Set the inside/outside algorithm to use when computing the signed distance to polygon faces. @details Computing the signed distance to faces requires testing if a point @@ -183,10 +183,10 @@ class MeshT : public SignedDistanceFunction There are multiple algorithms to use here. @param[in] a_algorithm Algorithm to use */ - inline void - setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm a_algorithm) noexcept; + inline void + setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm a_algorithm) noexcept; - /*! + /*! @brief Reconcile function which computes the internal parameters in vertices, edges, and faces for use with signed distance functionality @param[in] a_weight Vertex angle weighting function. Either @@ -195,46 +195,46 @@ class MeshT : public SignedDistanceFunction @details This will reconcile faces, edges, and vertices, e.g. computing the area and normal vector for faces */ - inline void - reconcile(typename DCEL::MeshT::VertexNormalWeight a_weight = VertexNormalWeight::Angle) noexcept; + inline void + reconcile(typename DCEL::MeshT::VertexNormalWeight a_weight = VertexNormalWeight::Angle) noexcept; - /*! + /*! @brief Get modifiable vertices in this mesh */ - inline std::vector& - getVertices() noexcept; + inline std::vector& + getVertices() noexcept; - /*! + /*! @brief Get immutable vertices in this mesh */ - inline const std::vector& - getVertices() const noexcept; + inline const std::vector& + getVertices() const noexcept; - /*! + /*! @brief Get modifiable half-edges in this mesh */ - inline std::vector& - getEdges() noexcept; + inline std::vector& + getEdges() noexcept; - /*! + /*! @brief Get immutable half-edges in this mesh */ - inline const std::vector& - getEdges() const noexcept; + inline const std::vector& + getEdges() const noexcept; - /*! + /*! @brief Get modifiable faces in this mesh */ - inline std::vector& - getFaces() noexcept; + inline std::vector& + getFaces() noexcept; - /*! + /*! @brief Get immutable faces in this mesh */ - inline const std::vector& - getFaces() const noexcept; + inline const std::vector& + getFaces() const noexcept; - /*! + /*! @brief Compute the signed distance from a point to this mesh @param[in] a_x0 3D point in space. @details This function will iterate through ALL faces in the mesh and return @@ -243,10 +243,10 @@ class MeshT : public SignedDistanceFunction in a bounding volume hierarchy for faster access. @note This will call the other version with the object's search algorithm. */ - inline T - signedDistance(const Vec3& a_x0) const noexcept override; + inline T + signedDistance(const Vec3& a_x0) const noexcept override; - /*! + /*! @brief Compute the signed distance from a point to this mesh @param[in] a_x0 3D point in space. @param[in] a_algorithm Search algorithm @@ -255,10 +255,10 @@ class MeshT : public SignedDistanceFunction why this function is almost never called. Rather, MeshT can be embedded in a bounding volume hierarchy for faster access. */ - inline T - signedDistance(const Vec3& a_x0, SearchAlgorithm a_algorithm) const noexcept; + inline T + signedDistance(const Vec3& a_x0, SearchAlgorithm a_algorithm) const noexcept; - /*! + /*! @brief Compute the unsigned square distance from a point to this mesh @param[in] a_x0 3D point in space. @details This function will iterate through ALL faces in the mesh and return @@ -267,68 +267,68 @@ class MeshT : public SignedDistanceFunction in a bounding volume hierarchy for faster access. @note This will call the other version with the object's search algorithm. */ - inline T - unsignedDistance2(const Vec3& a_x0) const noexcept; + inline T + unsignedDistance2(const Vec3& a_x0) const noexcept; -protected: - /*! + protected: + /*! @brief Search algorithm. Only used in signed distance functions. */ - SearchAlgorithm m_algorithm; + SearchAlgorithm m_algorithm; - /*! + /*! @brief Mesh vertices */ - std::vector m_vertices; + std::vector m_vertices; - /*! + /*! @brief Mesh half-edges */ - std::vector m_edges; + std::vector m_edges; - /*! + /*! @brief Mesh faces */ - std::vector m_faces; + std::vector m_faces; - /*! + /*! @brief Return all vertex coordinates in the mesh. */ - inline std::vector> - getAllVertexCoordinates() const noexcept; + inline std::vector> + getAllVertexCoordinates() const noexcept; - /*! + /*! @brief Function which computes internal things for the polygon faces. @note This calls DCEL::FaceT::reconcile() */ - inline void - reconcileFaces() noexcept; + inline void + reconcileFaces() noexcept; - /*! + /*! @brief Function which computes internal things for the half-edges @note This calls DCEL::EdgeT::reconcile() */ - inline void - reconcileEdges() noexcept; + inline void + reconcileEdges() noexcept; - /*! + /*! @brief Function which computes internal things for the vertices @param[in] a_weight Vertex angle weighting @note This calls DCEL::VertexT::computeVertexNormalAverage() or DCEL::VertexT::computeVertexNormalAngleWeighted() */ - inline void - reconcileVertices(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept; + inline void + reconcileVertices(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept; - /*! + /*! @brief Implementation of signed distance function which iterates through all faces @param[in] a_point 3D point */ - inline T - DirectSignedDistance(const Vec3& a_point) const noexcept; + inline T + DirectSignedDistance(const Vec3& a_point) const noexcept; - /*! + /*! @brief Implementation of squared signed distance function which iterates through all faces. @details This first find the face with the smallest unsigned square @@ -336,24 +336,24 @@ class MeshT : public SignedDistanceFunction than the other version). @param[in] a_point 3D point */ - inline T - DirectSignedDistance2(const Vec3& a_point) const noexcept; + inline T + DirectSignedDistance2(const Vec3& a_point) const noexcept; - /*! + /*! @brief Increment a warning. This is used in sanityCheck() for locating holes or bad inputs in the mesh. @param[in] a_warnings Map of all registered warnings @param[in] a_warn Current warning to increment by */ - inline void - incrementWarning(std::map& a_warnings, const std::string& a_warn) const noexcept; + inline void + incrementWarning(std::map& a_warnings, const std::string& a_warn) const noexcept; - /*! + /*! @brief Print all warnings to std::cerr */ - inline void - printWarnings(const std::map& a_warnings) const noexcept; -}; + inline void + printWarnings(const std::map& a_warnings) const noexcept; + }; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_MeshImplem.hpp b/Source/EBGeometry_DCEL_MeshImplem.hpp index 357cc385..37d50487 100644 --- a/Source/EBGeometry_DCEL_MeshImplem.hpp +++ b/Source/EBGeometry_DCEL_MeshImplem.hpp @@ -22,358 +22,370 @@ namespace DCEL { -template -inline MeshT::MeshT() -{ - m_algorithm = SearchAlgorithm::Direct2; -} - -template -inline MeshT::MeshT(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices) - : MeshT() -{ - this->define(a_faces, a_edges, a_vertices); -} - -template -inline MeshT::~MeshT() -{ -} - -template -inline void -MeshT::define( - std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices) noexcept -{ - m_faces = a_faces; - m_edges = a_edges; - m_vertices = a_vertices; -} - -template -inline void -MeshT::incrementWarning(std::map& a_warnings, const std::string& a_warn) const noexcept -{ - a_warnings.at(a_warn) += 1; -} - -template -inline void -MeshT::printWarnings(const std::map& a_warnings) const noexcept -{ - for (const auto& warn : a_warnings) { - if (warn.second > 0) { - std::cerr << "In file 'CD_DCELMeshImplem.H' function " - "MeshT::sanityCheck() - warnings about error '" - << warn.first << "' = " << warn.second << "\n"; - } + template + inline MeshT::MeshT() + { + m_algorithm = SearchAlgorithm::Direct2; } -} - -template -inline void -MeshT::sanityCheck() const noexcept -{ - - const std::string f_null = "nullptr face"; - const std::string f_noEdge = "face with no edge"; - const std::string f_degenerate = "degenerate face"; - - const std::string e_null = "nullptr edges"; - const std::string e_degenerate = "degenerate edge"; - const std::string e_noPairEdge = "no pair edge (not watertight)"; - const std::string e_noNextEdge = "no next edge (badly linked dcel)"; - const std::string e_noPrevEdge = "no previous edge (badly linked dcel)"; - const std::string e_noOrigVert = "no origin vertex found for half edge (badly linked dcel)"; - const std::string e_noFace = "no face found for half edge (badly linked dcel)"; - const std::string e_noPrevNext = "previous edge's next edge is not this edge (badly linked dcel)"; - const std::string e_noNextPrev = "next edge's previous edge is not this edge (badly linked dcel)"; - - const std::string v_null = "nullptr vertex"; - const std::string v_noEdge = "no referenced edge for vertex (unreferenced vertex)"; - - std::map warnings = {{f_null, 0}, {f_noEdge, 0}, {f_degenerate, 0}, {e_null, 0}, - {e_degenerate, 0}, {e_noPairEdge, 0}, {e_noNextEdge, 0}, {e_noPrevEdge, 0}, - {e_noOrigVert, 0}, {e_noFace, 0}, {e_noPrevNext, 0}, {e_noNextPrev, 0}, - {v_null, 0}, {v_noEdge, 0}}; - - for (const auto& f : m_faces) { - const auto& halfEdge = f->getHalfEdge(); - - // Check for duplicate vertices - auto vertices = f->gatherVertices(); - std::sort(vertices.begin(), vertices.end()); - auto it = std::unique(vertices.begin(), vertices.end()); - const bool noDuplicates = (it == vertices.end()); - - if (f == nullptr) { - incrementWarning(warnings, f_null); - } - else if (halfEdge == nullptr) { - incrementWarning(warnings, f_noEdge); - } - if (!noDuplicates) { - incrementWarning(warnings, f_degenerate); - } + + template + inline MeshT::MeshT(std::vector& a_faces, + std::vector& a_edges, + std::vector& a_vertices) + : MeshT() + { + this->define(a_faces, a_edges, a_vertices); } - for (const auto& e : m_edges) { - const auto& nextEdge = e->getNextEdge(); - const auto& prevEdge = e->getPreviousEdge(); - const auto& pairEdge = e->getPairEdge(); - const auto& curVertex = e->getVertex(); - const auto& curFace = e->getFace(); + template + inline MeshT::~MeshT() + {} + + template + inline void + MeshT::define(std::vector& a_faces, + std::vector& a_edges, + std::vector& a_vertices) noexcept + { + m_faces = a_faces; + m_edges = a_edges; + m_vertices = a_vertices; + } - // Check basic points for current edge. - if (e == nullptr) { - incrementWarning(warnings, e_null); - } - else if (e->getVertex() == e->getOtherVertex()) { - incrementWarning(warnings, e_degenerate); - } - else if (pairEdge == nullptr) { - incrementWarning(warnings, e_noPairEdge); - } - else if (nextEdge == nullptr) { - incrementWarning(warnings, e_noNextEdge); - } - else if (prevEdge == nullptr) { - incrementWarning(warnings, e_noPrevEdge); - } - else if (curVertex == nullptr) { - incrementWarning(warnings, e_noOrigVert); - } - else if (curFace == nullptr) { - incrementWarning(warnings, e_noFace); - } + template + inline void + MeshT::incrementWarning(std::map& a_warnings, const std::string& a_warn) const noexcept + { + a_warnings.at(a_warn) += 1; + } - // Check that the next edge's previous edge is this edge. - if (prevEdge->getNextEdge() != e) { - incrementWarning(warnings, e_noPrevNext); - } - else if (nextEdge->getPreviousEdge() != e) { - incrementWarning(warnings, e_noNextPrev); + template + inline void + MeshT::printWarnings(const std::map& a_warnings) const noexcept + { + for (const auto& warn : a_warnings) { + if (warn.second > 0) { + std::cerr << "In file 'CD_DCELMeshImplem.H' function " + "MeshT::sanityCheck() - warnings about error '" + << warn.first << "' = " << warn.second << "\n"; + } } } - // Vertex check - for (const auto& v : m_vertices) { - if (v == nullptr) { - incrementWarning(warnings, v_null); + template + inline void + MeshT::sanityCheck() const noexcept + { + + const std::string f_null = "nullptr face"; + const std::string f_noEdge = "face with no edge"; + const std::string f_degenerate = "degenerate face"; + + const std::string e_null = "nullptr edges"; + const std::string e_degenerate = "degenerate edge"; + const std::string e_noPairEdge = "no pair edge (not watertight)"; + const std::string e_noNextEdge = "no next edge (badly linked dcel)"; + const std::string e_noPrevEdge = "no previous edge (badly linked dcel)"; + const std::string e_noOrigVert = "no origin vertex found for half edge (badly linked dcel)"; + const std::string e_noFace = "no face found for half edge (badly linked dcel)"; + const std::string e_noPrevNext = "previous edge's next edge is not this edge (badly linked dcel)"; + const std::string e_noNextPrev = "next edge's previous edge is not this edge (badly linked dcel)"; + + const std::string v_null = "nullptr vertex"; + const std::string v_noEdge = "no referenced edge for vertex (unreferenced vertex)"; + + std::map warnings = {{f_null, 0}, + {f_noEdge, 0}, + {f_degenerate, 0}, + {e_null, 0}, + {e_degenerate, 0}, + {e_noPairEdge, 0}, + {e_noNextEdge, 0}, + {e_noPrevEdge, 0}, + {e_noOrigVert, 0}, + {e_noFace, 0}, + {e_noPrevNext, 0}, + {e_noNextPrev, 0}, + {v_null, 0}, + {v_noEdge, 0}}; + + for (const auto& f : m_faces) { + const auto& halfEdge = f->getHalfEdge(); + + // Check for duplicate vertices + auto vertices = f->gatherVertices(); + std::sort(vertices.begin(), vertices.end()); + auto it = std::unique(vertices.begin(), vertices.end()); + const bool noDuplicates = (it == vertices.end()); + + if (f == nullptr) { + incrementWarning(warnings, f_null); + } + else if (halfEdge == nullptr) { + incrementWarning(warnings, f_noEdge); + } + if (!noDuplicates) { + incrementWarning(warnings, f_degenerate); + } + } + + for (const auto& e : m_edges) { + const auto& nextEdge = e->getNextEdge(); + const auto& prevEdge = e->getPreviousEdge(); + const auto& pairEdge = e->getPairEdge(); + const auto& curVertex = e->getVertex(); + const auto& curFace = e->getFace(); + + // Check basic points for current edge. + if (e == nullptr) { + incrementWarning(warnings, e_null); + } + else if (e->getVertex() == e->getOtherVertex()) { + incrementWarning(warnings, e_degenerate); + } + else if (pairEdge == nullptr) { + incrementWarning(warnings, e_noPairEdge); + } + else if (nextEdge == nullptr) { + incrementWarning(warnings, e_noNextEdge); + } + else if (prevEdge == nullptr) { + incrementWarning(warnings, e_noPrevEdge); + } + else if (curVertex == nullptr) { + incrementWarning(warnings, e_noOrigVert); + } + else if (curFace == nullptr) { + incrementWarning(warnings, e_noFace); + } + + // Check that the next edge's previous edge is this edge. + if (prevEdge->getNextEdge() != e) { + incrementWarning(warnings, e_noPrevNext); + } + else if (nextEdge->getPreviousEdge() != e) { + incrementWarning(warnings, e_noNextPrev); + } } - else if (v->getOutgoingEdge() == nullptr) { - incrementWarning(warnings, v_noEdge); + + // Vertex check + for (const auto& v : m_vertices) { + if (v == nullptr) { + incrementWarning(warnings, v_null); + } + else if (v->getOutgoingEdge() == nullptr) { + incrementWarning(warnings, v_noEdge); + } } + + this->printWarnings(warnings); } - this->printWarnings(warnings); -} - -template -inline void -MeshT::setSearchAlgorithm(const SearchAlgorithm a_algorithm) noexcept -{ - m_algorithm = a_algorithm; -} - -template -inline void -MeshT::setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm a_algorithm) noexcept -{ - for (auto& f : m_faces) { - f->setInsideOutsideAlgorithm(a_algorithm); + template + inline void + MeshT::setSearchAlgorithm(const SearchAlgorithm a_algorithm) noexcept + { + m_algorithm = a_algorithm; } -} - -template -inline void -MeshT::reconcile(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept -{ - this->reconcileFaces(); - this->reconcileEdges(); - this->reconcileVertices(a_weight); -} - -template -inline void -MeshT::reconcileFaces() noexcept -{ - for (auto& f : m_faces) { - f->reconcile(); + + template + inline void + MeshT::setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm a_algorithm) noexcept + { + for (auto& f : m_faces) { + f->setInsideOutsideAlgorithm(a_algorithm); + } } -} - -template -inline void -MeshT::reconcileEdges() noexcept -{ - for (auto& e : m_edges) { - e->reconcile(); + + template + inline void + MeshT::reconcile(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept + { + this->reconcileFaces(); + this->reconcileEdges(); + this->reconcileVertices(a_weight); } -} - -template -inline void -MeshT::reconcileVertices(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept -{ - for (auto& v : m_vertices) { - switch (a_weight) { - case VertexNormalWeight::None: - v->computeVertexNormalAverage(); - break; - case VertexNormalWeight::Angle: - v->computeVertexNormalAngleWeighted(); - break; - default: - std::cerr << "In file 'CD_DCELMeshImplem.H' function " - "DCEL::MeshT::reconcileVertices(VertexNormalWeighting) - " - "unsupported algorithm requested\n"; + + template + inline void + MeshT::reconcileFaces() noexcept + { + for (auto& f : m_faces) { + f->reconcile(); } } -} - -template -inline std::vector>>& -MeshT::getVertices() noexcept -{ - return (m_vertices); -} - -template -inline const std::vector>>& -MeshT::getVertices() const noexcept -{ - return (m_vertices); -} - -template -inline std::vector>>& -MeshT::getEdges() noexcept -{ - return (m_edges); -} - -template -inline const std::vector>>& -MeshT::getEdges() const noexcept -{ - return (m_edges); -} - -template -inline std::vector>>& -MeshT::getFaces() noexcept -{ - return (m_faces); -} - -template -inline const std::vector>>& -MeshT::getFaces() const noexcept -{ - return (m_faces); -} - -template -inline std::vector> -MeshT::getAllVertexCoordinates() const noexcept -{ - std::vector vertexCoordinates; - for (const auto& v : m_vertices) { - vertexCoordinates.emplace_back(v->getPosition()); + + template + inline void + MeshT::reconcileEdges() noexcept + { + for (auto& e : m_edges) { + e->reconcile(); + } } - return vertexCoordinates; -} + template + inline void + MeshT::reconcileVertices(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept + { + for (auto& v : m_vertices) { + switch (a_weight) { + case VertexNormalWeight::None: + v->computeVertexNormalAverage(); + break; + case VertexNormalWeight::Angle: + v->computeVertexNormalAngleWeighted(); + break; + default: + std::cerr << "In file 'CD_DCELMeshImplem.H' function " + "DCEL::MeshT::reconcileVertices(VertexNormalWeighting) - " + "unsupported algorithm requested\n"; + } + } + } -template -inline T -MeshT::signedDistance(const Vec3& a_point) const noexcept -{ - return this->signedDistance(a_point, m_algorithm); -} + template + inline std::vector>>& + MeshT::getVertices() noexcept + { + return (m_vertices); + } -template -inline T -MeshT::unsignedDistance2(const Vec3& a_point) const noexcept -{ - T minDist2 = std::numeric_limits::max(); + template + inline const std::vector>>& + MeshT::getVertices() const noexcept + { + return (m_vertices); + } - for (const auto& f : m_faces) { - const T curDist2 = f->unsignedDistance2(a_point); + template + inline std::vector>>& + MeshT::getEdges() noexcept + { + return (m_edges); + } - minDist2 = std::min(minDist2, curDist2); + template + inline const std::vector>>& + MeshT::getEdges() const noexcept + { + return (m_edges); } - return minDist2; -} + template + inline std::vector>>& + MeshT::getFaces() noexcept + { + return (m_faces); + } -template -inline T -MeshT::signedDistance(const Vec3& a_point, SearchAlgorithm a_algorithm) const noexcept -{ - T minDist = std::numeric_limits::max(); + template + inline const std::vector>>& + MeshT::getFaces() const noexcept + { + return (m_faces); + } - switch (a_algorithm) { - case SearchAlgorithm::Direct: { - minDist = this->DirectSignedDistance(a_point); + template + inline std::vector> + MeshT::getAllVertexCoordinates() const noexcept + { + std::vector vertexCoordinates; + for (const auto& v : m_vertices) { + vertexCoordinates.emplace_back(v->getPosition()); + } - break; + return vertexCoordinates; } - case SearchAlgorithm::Direct2: { - minDist = this->DirectSignedDistance2(a_point); - break; + template + inline T + MeshT::signedDistance(const Vec3& a_point) const noexcept + { + return this->signedDistance(a_point, m_algorithm); } - default: { - std::cerr << "Error in file 'CD_DCELMeshImplem.H' MeshT::signedDistance " - "unsupported algorithm requested\n"; - break; - } + template + inline T + MeshT::unsignedDistance2(const Vec3& a_point) const noexcept + { + T minDist2 = std::numeric_limits::max(); + + for (const auto& f : m_faces) { + const T curDist2 = f->unsignedDistance2(a_point); + + minDist2 = std::min(minDist2, curDist2); + } + + return minDist2; } - return minDist; -} + template + inline T + MeshT::signedDistance(const Vec3& a_point, SearchAlgorithm a_algorithm) const noexcept + { + T minDist = std::numeric_limits::max(); -template -inline T -MeshT::DirectSignedDistance(const Vec3& a_point) const noexcept -{ - T minDist = m_faces.front()->signedDistance(a_point); - T minDist2 = minDist * minDist; + switch (a_algorithm) { + case SearchAlgorithm::Direct: { + minDist = this->DirectSignedDistance(a_point); - for (const auto& f : m_faces) { - const T curDist = f->signedDistance(a_point); - const T curDist2 = curDist * curDist; + break; + } + case SearchAlgorithm::Direct2: { + minDist = this->DirectSignedDistance2(a_point); - if (curDist2 < minDist2) { - minDist = curDist; - minDist2 = curDist2; + break; + } + default: { + std::cerr << "Error in file 'CD_DCELMeshImplem.H' MeshT::signedDistance " + "unsupported algorithm requested\n"; + + break; + } } + + return minDist; } - return minDist; -} + template + inline T + MeshT::DirectSignedDistance(const Vec3& a_point) const noexcept + { + T minDist = m_faces.front()->signedDistance(a_point); + T minDist2 = minDist * minDist; + + for (const auto& f : m_faces) { + const T curDist = f->signedDistance(a_point); + const T curDist2 = curDist * curDist; + + if (curDist2 < minDist2) { + minDist = curDist; + minDist2 = curDist2; + } + } + + return minDist; + } -template -inline T -MeshT::DirectSignedDistance2(const Vec3& a_point) const noexcept -{ - FacePtr closest = m_faces.front(); - T minDist2 = closest->unsignedDistance2(a_point); + template + inline T + MeshT::DirectSignedDistance2(const Vec3& a_point) const noexcept + { + FacePtr closest = m_faces.front(); + T minDist2 = closest->unsignedDistance2(a_point); - for (const auto& f : m_faces) { - const T curDist2 = f->unsignedDistance2(a_point); + for (const auto& f : m_faces) { + const T curDist2 = f->unsignedDistance2(a_point); - if (curDist2 < minDist2) { - closest = f; - minDist2 = curDist2; + if (curDist2 < minDist2) { + closest = f; + minDist2 = curDist2; + } } - } - return closest->signedDistance(a_point); -} + return closest->signedDistance(a_point); + } } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Polygon2D.hpp b/Source/EBGeometry_DCEL_Polygon2D.hpp index 27d8e882..e9e60e79 100644 --- a/Source/EBGeometry_DCEL_Polygon2D.hpp +++ b/Source/EBGeometry_DCEL_Polygon2D.hpp @@ -22,7 +22,7 @@ namespace DCEL { -/*! + /*! @brief Class for embedding a DCEL polygon face into 2D. @details This class is required for determining whether or not a 3D point projected to the plane of an N-sided polygon lies inside or outside the @@ -40,149 +40,149 @@ namespace DCEL { which checks how many times a ray cast from the point crosses the edges of the polygon. */ -template -class Polygon2D -{ -public: - /*! + template + class Polygon2D + { + public: + /*! @brief Supported algorithms for performing inside/outside tests when checking if a point projects to the inside or outside of a polygon face. */ - enum class InsideOutsideAlgorithm - { - SubtendedAngle, - CrossingNumber, - WindingNumber - }; + enum class InsideOutsideAlgorithm + { + SubtendedAngle, + CrossingNumber, + WindingNumber + }; - /*! + /*! @brief Alias to cut down on typing */ - using Vec2 = Vec2T; + using Vec2 = Vec2T; - /*! + /*! @brief Alias to cut down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Disallowed constructor, use the one with the normal vector and points */ - Polygon2D() = delete; + Polygon2D() = delete; - /*! + /*! @brief Full constructor @param[in] a_normal Normal vector of the 3D polygon face @param[in] a_points Vertex coordinates of the 3D polygon face */ - Polygon2D(const Vec3& a_normal, const std::vector& a_points); + Polygon2D(const Vec3& a_normal, const std::vector& a_points); - /*! + /*! @brief Destructor (does nothing */ - ~Polygon2D() = default; + ~Polygon2D() = default; - /*! + /*! @brief Check if a point is inside or outside the 2D polygon @param[in] a_point 3D point coordinates @param[in] a_algorithm Inside/outside algorithm @details This will call the function corresponding to a_algorithm. */ - inline bool - isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_algorithm) const noexcept; + inline bool + isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_algorithm) const noexcept; - /*! + /*! @brief Check if a point is inside a 2D polygon, using the winding number algorithm @param[in] a_point 3D point coordinates @return Returns true if the 3D point projects to the inside of the 2D polygon */ - inline bool - isPointInsidePolygonWindingNumber(const Vec3& a_point) const noexcept; + inline bool + isPointInsidePolygonWindingNumber(const Vec3& a_point) const noexcept; - /*! + /*! @brief Check if a point is inside a 2D polygon, using the subtended angles @param[in] a_point 3D point coordinates @return Returns true if the 3D point projects to the inside of the 2D polygon */ - inline bool - isPointInsidePolygonSubtend(const Vec3& a_point) const noexcept; + inline bool + isPointInsidePolygonSubtend(const Vec3& a_point) const noexcept; - /*! + /*! @brief Check if a point is inside a 2D polygon, by computing the number of times a ray crosses the polygon edges. @param[in] a_point 3D point coordinates @return Returns true if the 3D point projects to the inside of the 2D polygon */ - inline bool - isPointInsidePolygonCrossingNumber(const Vec3& a_point) const noexcept; + inline bool + isPointInsidePolygonCrossingNumber(const Vec3& a_point) const noexcept; -private: - /*! + private: + /*! @brief 3D coordinate direction to ignore */ - size_t m_ignoreDir; + size_t m_ignoreDir; - /*! + /*! @brief The corresponding 2D x-direction. */ - size_t m_xDir; + size_t m_xDir; - /*! + /*! @brief The corresponding 2D y-direction. */ - size_t m_yDir; + size_t m_yDir; - /*! + /*! @brief Projected set of points in 2D */ - std::vector m_points; + std::vector m_points; - /*! + /*! @brief Project a 3D point onto the 2D polygon plane (this ignores one of the vector components) @param[in] a_poitn 3D point @return 2D point, ignoring one of the coordinate directions. */ - inline Vec2 - projectPoint(const Vec3& a_point) const noexcept; + inline Vec2 + projectPoint(const Vec3& a_point) const noexcept; - /*! + /*! @brief Define function. This find the direction to ignore and then computes the 2D points. @param[in] a_normal Normal vector for polygon face @param[in] a_points Vertex coordinates for polygon face. */ - inline void - define(const Vec3& a_normal, const std::vector& a_points); + inline void + define(const Vec3& a_normal, const std::vector& a_points); - /*! + /*! @brief Compute the winding number for a point P with the 2D polygon @param[in] P 2D point @return Returns winding number. */ - inline int - computeWindingNumber(const Vec2& P) const noexcept; + inline int + computeWindingNumber(const Vec2& P) const noexcept; - /*! + /*! @brief Compute the crossing number for a point P with the 2D polygon @param[in] P 2D point @return Returns crossing number. */ - inline size_t - computeCrossingNumber(const Vec2& P) const noexcept; + inline size_t + computeCrossingNumber(const Vec2& P) const noexcept; - /*! + /*! @brief Compute the subtended angle for a point P with the 2D polygon @param[in] P 2D point @return Returns subtended angle. */ - inline T - computeSubtendedAngle(const Vec2& P) const noexcept; -}; + inline T + computeSubtendedAngle(const Vec2& P) const noexcept; + }; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Polygon2DImplem.hpp b/Source/EBGeometry_DCEL_Polygon2DImplem.hpp index 47d9c248..bca50308 100644 --- a/Source/EBGeometry_DCEL_Polygon2DImplem.hpp +++ b/Source/EBGeometry_DCEL_Polygon2DImplem.hpp @@ -21,204 +21,204 @@ namespace DCEL { -template -inline Polygon2D::Polygon2D(const Vec3& a_normal, const std::vector& a_points) -{ - this->define(a_normal, a_points); -} - -template -inline bool -Polygon2D::isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_algorithm) const noexcept -{ - bool ret = false; - - switch (a_algorithm) { - case InsideOutsideAlgorithm::SubtendedAngle: { - ret = this->isPointInsidePolygonSubtend(a_point); - - break; + template + inline Polygon2D::Polygon2D(const Vec3& a_normal, const std::vector& a_points) + { + this->define(a_normal, a_points); } - case InsideOutsideAlgorithm::CrossingNumber: { - ret = this->isPointInsidePolygonCrossingNumber(a_point); - break; - } - case InsideOutsideAlgorithm::WindingNumber: { - ret = this->isPointInsidePolygonWindingNumber(a_point); + template + inline bool + Polygon2D::isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_algorithm) const noexcept + { + bool ret = false; + + switch (a_algorithm) { + case InsideOutsideAlgorithm::SubtendedAngle: { + ret = this->isPointInsidePolygonSubtend(a_point); + + break; + } + case InsideOutsideAlgorithm::CrossingNumber: { + ret = this->isPointInsidePolygonCrossingNumber(a_point); + + break; + } + case InsideOutsideAlgorithm::WindingNumber: { + ret = this->isPointInsidePolygonWindingNumber(a_point); + + break; + } + default: + std::cerr << "In file 'CD_DCELPolygon2DImplem.H' function " + "Polygon2D::isPointInside - logic bust.\n"; + } - break; + return ret; } - default: - std::cerr << "In file 'CD_DCELPolygon2DImplem.H' function " - "Polygon2D::isPointInside - logic bust.\n"; + + template + inline Vec2T + Polygon2D::projectPoint(const Vec3& a_point) const noexcept + { + return Vec2(a_point[m_xDir], a_point[m_yDir]); } - return ret; -} - -template -inline Vec2T -Polygon2D::projectPoint(const Vec3& a_point) const noexcept -{ - return Vec2(a_point[m_xDir], a_point[m_yDir]); -} - -template -inline void -Polygon2D::define(const Vec3& a_normal, const std::vector& a_points) -{ - m_ignoreDir = 0; - - for (size_t dir = 1; dir < 3; dir++) { - if (std::abs(a_normal[dir]) > std::abs(a_normal[m_ignoreDir])) { - m_ignoreDir = dir; + template + inline void + Polygon2D::define(const Vec3& a_normal, const std::vector& a_points) + { + m_ignoreDir = 0; + + for (size_t dir = 1; dir < 3; dir++) { + if (std::abs(a_normal[dir]) > std::abs(a_normal[m_ignoreDir])) { + m_ignoreDir = dir; + } } - } - m_xDir = 3; - m_yDir = 0; + m_xDir = 3; + m_yDir = 0; - for (size_t dir = 0; dir < 3; dir++) { - if (dir != m_ignoreDir) { - m_xDir = std::min(m_xDir, dir); - m_yDir = std::max(m_yDir, dir); + for (size_t dir = 0; dir < 3; dir++) { + if (dir != m_ignoreDir) { + m_xDir = std::min(m_xDir, dir); + m_yDir = std::max(m_yDir, dir); + } } - } - for (const auto& p3 : a_points) { - m_points.emplace_back(this->projectPoint(p3)); + for (const auto& p3 : a_points) { + m_points.emplace_back(this->projectPoint(p3)); + } } -} -template -inline int -Polygon2D::computeWindingNumber(const Vec2& P) const noexcept -{ - int wn = 0; // the winding number counter + template + inline int + Polygon2D::computeWindingNumber(const Vec2& P) const noexcept + { + int wn = 0; // the winding number counter - const size_t N = m_points.size(); + const size_t N = m_points.size(); - auto isLeft = [](const Vec2& P0, const Vec2& P1, const Vec2& P2) { - return (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y); - }; + auto isLeft = [](const Vec2& P0, const Vec2& P1, const Vec2& P2) { + return (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y); + }; - // loop through all edges of the polygon - for (size_t i = 0; i < N; i++) { // edge from V[i] to V[i+1] + // loop through all edges of the polygon + for (size_t i = 0; i < N; i++) { // edge from V[i] to V[i+1] - const Vec2& P1 = m_points[i]; - const Vec2& P2 = m_points[(i + 1) % N]; + const Vec2& P1 = m_points[i]; + const Vec2& P2 = m_points[(i + 1) % N]; - const T res = isLeft(P1, P2, P); + const T res = isLeft(P1, P2, P); - if (P1.y <= P.y) { // start y <= P.y - if (P2.y > P.y) // an upward crossing - if (res > 0.) // P left of edge - ++wn; // have a valid up intersect - } - else { // start y > P.y (no test needed) - if (P2.y <= P.y) // a downward crossing - if (res < 0.) // P right of edge - --wn; // have a valid down intersect + if (P1.y <= P.y) { // start y <= P.y + if (P2.y > P.y) // an upward crossing + if (res > 0.) // P left of edge + ++wn; // have a valid up intersect + } + else { // start y > P.y (no test needed) + if (P2.y <= P.y) // a downward crossing + if (res < 0.) // P right of edge + --wn; // have a valid down intersect + } } - } - return wn; -} + return wn; + } -template -inline size_t -Polygon2D::computeCrossingNumber(const Vec2& P) const noexcept -{ - size_t cn = 0; + template + inline size_t + Polygon2D::computeCrossingNumber(const Vec2& P) const noexcept + { + size_t cn = 0; - const size_t N = m_points.size(); + const size_t N = m_points.size(); - for (size_t i = 0; i < N; i++) { // edge from V[i] to V[i+1] - const Vec2& P1 = m_points[i]; - const Vec2& P2 = m_points[(i + 1) % N]; + for (size_t i = 0; i < N; i++) { // edge from V[i] to V[i+1] + const Vec2& P1 = m_points[i]; + const Vec2& P2 = m_points[(i + 1) % N]; - const bool upwardCrossing = (P1.y <= P.y) && (P2.y > P.y); - const bool downwardCrossing = (P1.y > P.y) && (P2.y <= P.y); + const bool upwardCrossing = (P1.y <= P.y) && (P2.y > P.y); + const bool downwardCrossing = (P1.y > P.y) && (P2.y <= P.y); - if (upwardCrossing || downwardCrossing) { - const T t = (P.y - P1.y) / (P2.y - P1.y); + if (upwardCrossing || downwardCrossing) { + const T t = (P.y - P1.y) / (P2.y - P1.y); - if (P.x < P1.x + t * (P2.x - P1.x)) { // P.x < intersect - cn += 1; // a valid crossing of y=P.y right of P.x + if (P.x < P1.x + t * (P2.x - P1.x)) { // P.x < intersect + cn += 1; // a valid crossing of y=P.y right of P.x + } } } + + return cn; } - return cn; -} + template + inline T + Polygon2D::computeSubtendedAngle(const Vec2& p) const noexcept + { + T sumTheta = 0.0; -template -inline T -Polygon2D::computeSubtendedAngle(const Vec2& p) const noexcept -{ - T sumTheta = 0.0; + const size_t N = m_points.size(); - const size_t N = m_points.size(); + for (size_t i = 0; i < N; i++) { + const Vec2 p1 = m_points[i] - p; + const Vec2 p2 = m_points[(i + 1) % N] - p; - for (size_t i = 0; i < N; i++) { - const Vec2 p1 = m_points[i] - p; - const Vec2 p2 = m_points[(i + 1) % N] - p; + const T theta1 = atan2(p1.y, p1.x); + const T theta2 = atan2(p2.y, p2.x); - const T theta1 = atan2(p1.y, p1.x); - const T theta2 = atan2(p2.y, p2.x); + T dTheta = theta2 - theta1; - T dTheta = theta2 - theta1; + while (dTheta > M_PI) + dTheta -= 2.0 * M_PI; + while (dTheta < -M_PI) + dTheta += 2.0 * M_PI; - while (dTheta > M_PI) - dTheta -= 2.0 * M_PI; - while (dTheta < -M_PI) - dTheta += 2.0 * M_PI; + sumTheta += dTheta; + } - sumTheta += dTheta; + return sumTheta; } - return sumTheta; -} - -template -inline bool -Polygon2D::isPointInsidePolygonWindingNumber(const Vec3& a_point) const noexcept -{ - const Vec2 p = this->projectPoint(a_point); + template + inline bool + Polygon2D::isPointInsidePolygonWindingNumber(const Vec3& a_point) const noexcept + { + const Vec2 p = this->projectPoint(a_point); - const int wn = this->computeWindingNumber(p); + const int wn = this->computeWindingNumber(p); - return wn != 0; -} + return wn != 0; + } -template -inline bool -Polygon2D::isPointInsidePolygonCrossingNumber(const Vec3& a_point) const noexcept -{ - const Vec2 p = this->projectPoint(a_point); + template + inline bool + Polygon2D::isPointInsidePolygonCrossingNumber(const Vec3& a_point) const noexcept + { + const Vec2 p = this->projectPoint(a_point); - const size_t cn = this->computeCrossingNumber(p); + const size_t cn = this->computeCrossingNumber(p); - const bool ret = (cn & 1); + const bool ret = (cn & 1); - return ret; -} + return ret; + } -template -inline bool -Polygon2D::isPointInsidePolygonSubtend(const Vec3& a_point) const noexcept -{ - const Vec2 p = this->projectPoint(a_point); + template + inline bool + Polygon2D::isPointInsidePolygonSubtend(const Vec3& a_point) const noexcept + { + const Vec2 p = this->projectPoint(a_point); - T sumTheta = this->computeSubtendedAngle(p); // Should be = 2pi if point is inside. + T sumTheta = this->computeSubtendedAngle(p); // Should be = 2pi if point is inside. - sumTheta = std::abs(sumTheta) / (2. * M_PI); + sumTheta = std::abs(sumTheta) / (2. * M_PI); - const bool ret = (round(sumTheta) == 1); // 2PI if the polygon is inside. + const bool ret = (round(sumTheta) == 1); // 2PI if the polygon is inside. - return ret; -} + return ret; + } } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_Vertex.hpp b/Source/EBGeometry_DCEL_Vertex.hpp index 0b95ec63..81245e67 100644 --- a/Source/EBGeometry_DCEL_Vertex.hpp +++ b/Source/EBGeometry_DCEL_Vertex.hpp @@ -25,17 +25,17 @@ namespace DCEL { -// Forward declare classes. -template -class VertexT; -template -class EdgeT; -template -class FaceT; -template -class EdgeIteratorT; + // Forward declare classes. + template + class VertexT; + template + class EdgeT; + template + class FaceT; + template + class EdgeIteratorT; -/*! + /*! @brief Class which represents a vertex node in a double-edge connected list (DCEL). @details This class is used in DCEL functionality which stores polygonal @@ -45,152 +45,152 @@ class EdgeIteratorT; @note The normal vector is outgoing, i.e. a point x is "outside" the vertex if the dot product between n and (x - x0) is positive. */ -template -class VertexT -{ -public: - /*! + template + class VertexT + { + public: + /*! @brief Alias to cut down on typing */ - using Vec3 = Vec3T; + using Vec3 = Vec3T; - /*! + /*! @brief Alias to cut down on typing */ - using Vertex = VertexT; + using Vertex = VertexT; - /*! + /*! @brief Alias to cut down on typing */ - using Edge = EdgeT; + using Edge = EdgeT; - /*! + /*! @brief Alias to cut down on typing */ - using Face = FaceT; + using Face = FaceT; - /*! + /*! @brief Alias to cut down on typing. Note that this is std::shared_ptr > */ - using VertexPtr = std::shared_ptr; + using VertexPtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing. Note that this is std::shared_ptr > */ - using EdgePtr = std::shared_ptr; + using EdgePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing. Note that this is std::shared_ptr > */ - using FacePtr = std::shared_ptr; + using FacePtr = std::shared_ptr; - /*! + /*! @brief Alias to cut down on typing. Note that this is std::shared_ptr > */ - using EdgeIterator = EdgeIteratorT; + using EdgeIterator = EdgeIteratorT; - /*! + /*! @brief Default constructor. @details This initializes the position and the normal vector to zero vectors, and the polygon face list is empty */ - VertexT(); + VertexT(); - /*! + /*! @brief Partial constructor. @param[in] a_position Vertex position @details This initializes the position to a_position and the normal vector to the zero vector. The polygon face list is empty. */ - VertexT(const Vec3& a_position); + VertexT(const Vec3& a_position); - /*! + /*! @brief Constructor. @param[in] a_position Vertex position @param[in] a_normal Vertex normal vector @details This initializes the position to a_position and the normal vector to a_normal. The polygon face list is empty. */ - VertexT(const Vec3& a_position, const Vec3& a_normal); + VertexT(const Vec3& a_position, const Vec3& a_normal); - /*! + /*! @brief Full copy constructor @param[in] a_otherVertex Other vertex @details This copies the position, normal vector, and outgoing edge pointer from the other vertex. The polygon face list. */ - VertexT(const Vertex& a_otherVertex); + VertexT(const Vertex& a_otherVertex); - /*! + /*! @brief Destructor (does nothing) */ - ~VertexT(); + ~VertexT(); - /*! + /*! @brief Define function @param[in] a_position Vertex position @param[in] a_edge Pointer to outgoing edge @param[in] a_normal Vertex normal vector @details This sets the position, normal vector, and edge pointer. */ - inline void - define(const Vec3& a_position, const EdgePtr& a_edge, const Vec3& a_normal) noexcept; + inline void + define(const Vec3& a_position, const EdgePtr& a_edge, const Vec3& a_normal) noexcept; - /*! + /*! @brief Set the vertex position @param[in] a_position Vertex position */ - inline void - setPosition(const Vec3& a_position) noexcept; + inline void + setPosition(const Vec3& a_position) noexcept; - /*! + /*! @brief Set the vertex normal vector @param[in] a_normal Vertex normal vector */ - inline void - setNormal(const Vec3& a_normal) noexcept; + inline void + setNormal(const Vec3& a_normal) noexcept; - /*! + /*! @brief Set the reference to the outgoing edge @param[in] a_edge Pointer to an outgoing edge */ - inline void - setEdge(const EdgePtr& a_edge) noexcept; + inline void + setEdge(const EdgePtr& a_edge) noexcept; - /*! + /*! @brief Add a face to the polygon face list. @param[in] a_face Pointer to face. */ - inline void - addFace(const FacePtr& a_face) noexcept; + inline void + addFace(const FacePtr& a_face) noexcept; - /*! + /*! @brief Normalize the normal vector, ensuring its length is 1 */ - inline void - normalizeNormalVector() noexcept; + inline void + normalizeNormalVector() noexcept; - /*! + /*! @brief Compute the vertex normal, using an average the normal vector in this vertex's face list (m_faces) */ - inline void - computeVertexNormalAverage() noexcept; + inline void + computeVertexNormalAverage() noexcept; - /*! + /*! @brief Compute the vertex normal, using an average of the normal vectors in the input face list @param[in] a_faces Faces @note This computes the vertex normal as n = sum(normal(face))/num(faces) */ - inline void - computeVertexNormalAverage(const std::vector& a_faces) noexcept; + inline void + computeVertexNormalAverage(const std::vector& a_faces) noexcept; - /*! + /*! @brief Compute the vertex normal, using the pseudonormal algorithm which weights the normal with the subtended angle to each connected face. @details This calls the other version with a_faces = m_faces @@ -198,10 +198,10 @@ class VertexT Baerentzen and Aanes in "Signed distance computation using the angle weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49) */ - inline void - computeVertexNormalAngleWeighted() noexcept; + inline void + computeVertexNormalAngleWeighted() noexcept; - /*! + /*! @brief Compute the vertex normal, using the pseudonormal algorithm which weights the normal with the subtended angle to each connected face. @param[in] a_faces Faces to use for computation. @@ -209,97 +209,97 @@ class VertexT Baerentzen and Aanes in "Signed distance computation using the angle weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49) */ - inline void - computeVertexNormalAngleWeighted(const std::vector& a_faces) noexcept; + inline void + computeVertexNormalAngleWeighted(const std::vector& a_faces) noexcept; - /*! + /*! @brief Return modifiable vertex position. */ - inline Vec3T& - getPosition() noexcept; + inline Vec3T& + getPosition() noexcept; - /*! + /*! @brief Return immutable vertex position. */ - inline const Vec3T& - getPosition() const noexcept; + inline const Vec3T& + getPosition() const noexcept; - /*! + /*! @brief Return modifiable vertex normal vector. */ - inline Vec3T& - getNormal() noexcept; + inline Vec3T& + getNormal() noexcept; - /*! + /*! @brief Return immutable vertex normal vector. */ - inline const Vec3T& - getNormal() const noexcept; + inline const Vec3T& + getNormal() const noexcept; - /*! + /*! @brief Return modifiable pointer to outgoing edge. */ - inline EdgePtr& - getOutgoingEdge() noexcept; + inline EdgePtr& + getOutgoingEdge() noexcept; - /*! + /*! @brief Return immutable pointer to outgoing edge. */ - inline const EdgePtr& - getOutgoingEdge() const noexcept; + inline const EdgePtr& + getOutgoingEdge() const noexcept; - /*! + /*! @brief Get modifiable polygon face list for this vertex. */ - inline std::vector& - getFaces() noexcept; + inline std::vector& + getFaces() noexcept; - /*! + /*! @brief Get immutable polygon face list for this vertex. */ - inline const std::vector& - getFaces() const noexcept; + inline const std::vector& + getFaces() const noexcept; - /*! + /*! @brief Get the signed distance to this vertex @param[in] a_x0 Position in space. @return The returned distance is |a_x0 - m_position| and the sign is given by the sign of m_normal * |a_x0 - m_position|. */ - inline T - signedDistance(const Vec3& a_x0) const noexcept; + inline T + signedDistance(const Vec3& a_x0) const noexcept; - /*! + /*! @brief Get the squared unsigned distance to this vertex @details This is faster to compute than signedDistance, and might be preferred for some algorithms. @return Returns the vector length of (a_x - m_position) */ - inline T - unsignedDistance2(const Vec3& a_x0) const noexcept; + inline T + unsignedDistance2(const Vec3& a_x0) const noexcept; -protected: - /*! + protected: + /*! @brief Pointer to an outgoing edge from this vertex. */ - EdgePtr m_outgoingEdge; + EdgePtr m_outgoingEdge; - /*! + /*! @brief Vertex position */ - Vec3 m_position; + Vec3 m_position; - /*! + /*! @brief Vertex normal vector */ - Vec3 m_normal; + Vec3 m_normal; - /*! + /*! @brief List of faces connected to this vertex (these must be "manually" added) */ - std::vector m_faces; -}; + std::vector m_faces; + }; } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_DCEL_VertexImplem.hpp b/Source/EBGeometry_DCEL_VertexImplem.hpp index 108d9572..2477822b 100644 --- a/Source/EBGeometry_DCEL_VertexImplem.hpp +++ b/Source/EBGeometry_DCEL_VertexImplem.hpp @@ -21,275 +21,274 @@ namespace DCEL { -template -inline VertexT::VertexT() -{ - m_position = Vec3::zero(); - m_normal = Vec3::zero(); - - m_faces.resize(0); -} - -template -inline VertexT::VertexT(const Vec3& a_position) : VertexT() -{ - m_position = a_position; -} - -template -inline VertexT::VertexT(const Vec3& a_position, const Vec3& a_normal) : VertexT() -{ - m_position = a_position; - m_normal = a_normal; -} - -template -inline VertexT::VertexT(const VertexT& a_otherVertex) -{ - m_position = a_otherVertex.m_position; - m_normal = a_otherVertex.m_m_normal; - m_outgoingEdge = a_otherVertex.m_outgoingEdge; -} - -template -inline VertexT::~VertexT() -{ -} - -template -inline void -VertexT::define(const Vec3& a_position, const EdgePtr& a_edge, const Vec3& a_normal) noexcept -{ - m_position = a_position; - m_outgoingEdge = a_edge; - m_normal = a_normal; -} - -template -inline void -VertexT::setPosition(const Vec3& a_position) noexcept -{ - m_position = a_position; -} - -template -inline void -VertexT::setEdge(const EdgePtr& a_edge) noexcept -{ - m_outgoingEdge = a_edge; -} - -template -inline void -VertexT::setNormal(const Vec3& a_normal) noexcept -{ - m_normal = a_normal; -} - -template -inline void -VertexT::addFace(const FacePtr& a_face) noexcept -{ - m_faces.emplace_back(a_face); -} - -template -inline void -VertexT::normalizeNormalVector() noexcept -{ - m_normal = m_normal / m_normal.length(); -} - -template -inline void -VertexT::computeVertexNormalAverage() noexcept -{ - this->computeVertexNormalAverage(m_faces); -} - -template -inline void -VertexT::computeVertexNormalAverage(const std::vector& a_faces) noexcept -{ - m_normal = Vec3::zero(); - - // TLDR: We simply compute the sum of the normal vectors for each face in - // a_faces and then normalize. This - // will yield an "average" of the normal vectors of the faces - // circulating this vertex. - for (const auto& f : a_faces) { - m_normal += f->getNormal(); + template + inline VertexT::VertexT() + { + m_position = Vec3::zero(); + m_normal = Vec3::zero(); + + m_faces.resize(0); } - this->normalizeNormalVector(); -} - -template -inline void -VertexT::computeVertexNormalAngleWeighted() noexcept -{ - this->computeVertexNormalAngleWeighted(m_faces); -} - -template -inline void -VertexT::computeVertexNormalAngleWeighted(const std::vector& a_faces) noexcept -{ - m_normal = Vec3::zero(); - - // This routine computes the pseudonormal from pseudnormal algorithm from - // Baerentzen and Aanes in "Signed distance computation using the angle - // weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49). This algorithm computes - // an average normal vector using the normal vectors of each face connected to - // this vertex, i.e. in the form - // - // n = sum(w * n(face))/sum(w) - // - // where w are weights for each face. This weight is given by the subtended - // angle of the face, which means the angle spanned by the incoming/outgoing - // edges of the face that pass through this vertex. - // - // - // The below code is more complicated than it looks. It happens because we - // want the two half edges that has the current vertex as a mutual vertex - // (i.e. the "incoming" and "outgoing" edges into this vertex). Normally we'd - // just iterate through edges, but if it happens that an input face is - // flipped, this will result in infinite iteration. Instead, we have stored - // the pointers to each face connected to this vertex. We look through each - // face to find the endpoints of the edges the have the current vertex as the - // common vertex, and then compute the subtended angle between those. Sigh... - - const VertexPtr& originVertex = m_outgoingEdge->getVertex(); // AKA 'this' - - for (const auto& f : a_faces) { - - std::vector inoutVertices(0); - for (EdgeIterator edgeIt(f->getHalfEdge()); edgeIt.ok(); ++edgeIt) { - const auto& e = edgeIt(); - - const auto& v1 = e->getVertex(); - const auto& v2 = e->getOtherVertex(); - - if (v1 == originVertex || v2 == originVertex) { - if (v1 == originVertex) { - inoutVertices.emplace_back(v2); - } - else if (v2 == originVertex) { - inoutVertices.emplace_back(v1); - } - else { - std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; + template + inline VertexT::VertexT(const Vec3& a_position) : VertexT() + { + m_position = a_position; + } + + template + inline VertexT::VertexT(const Vec3& a_position, const Vec3& a_normal) : VertexT() + { + m_position = a_position; + m_normal = a_normal; + } + + template + inline VertexT::VertexT(const VertexT& a_otherVertex) + { + m_position = a_otherVertex.m_position; + m_normal = a_otherVertex.m_m_normal; + m_outgoingEdge = a_otherVertex.m_outgoingEdge; + } + + template + inline VertexT::~VertexT() + {} + + template + inline void + VertexT::define(const Vec3& a_position, const EdgePtr& a_edge, const Vec3& a_normal) noexcept + { + m_position = a_position; + m_outgoingEdge = a_edge; + m_normal = a_normal; + } + + template + inline void + VertexT::setPosition(const Vec3& a_position) noexcept + { + m_position = a_position; + } + + template + inline void + VertexT::setEdge(const EdgePtr& a_edge) noexcept + { + m_outgoingEdge = a_edge; + } + + template + inline void + VertexT::setNormal(const Vec3& a_normal) noexcept + { + m_normal = a_normal; + } + + template + inline void + VertexT::addFace(const FacePtr& a_face) noexcept + { + m_faces.emplace_back(a_face); + } + + template + inline void + VertexT::normalizeNormalVector() noexcept + { + m_normal = m_normal / m_normal.length(); + } + + template + inline void + VertexT::computeVertexNormalAverage() noexcept + { + this->computeVertexNormalAverage(m_faces); + } + + template + inline void + VertexT::computeVertexNormalAverage(const std::vector& a_faces) noexcept + { + m_normal = Vec3::zero(); + + // TLDR: We simply compute the sum of the normal vectors for each face in + // a_faces and then normalize. This + // will yield an "average" of the normal vectors of the faces + // circulating this vertex. + for (const auto& f : a_faces) { + m_normal += f->getNormal(); + } + + this->normalizeNormalVector(); + } + + template + inline void + VertexT::computeVertexNormalAngleWeighted() noexcept + { + this->computeVertexNormalAngleWeighted(m_faces); + } + + template + inline void + VertexT::computeVertexNormalAngleWeighted(const std::vector& a_faces) noexcept + { + m_normal = Vec3::zero(); + + // This routine computes the pseudonormal from pseudnormal algorithm from + // Baerentzen and Aanes in "Signed distance computation using the angle + // weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49). This algorithm computes + // an average normal vector using the normal vectors of each face connected to + // this vertex, i.e. in the form + // + // n = sum(w * n(face))/sum(w) + // + // where w are weights for each face. This weight is given by the subtended + // angle of the face, which means the angle spanned by the incoming/outgoing + // edges of the face that pass through this vertex. + // + // + // The below code is more complicated than it looks. It happens because we + // want the two half edges that has the current vertex as a mutual vertex + // (i.e. the "incoming" and "outgoing" edges into this vertex). Normally we'd + // just iterate through edges, but if it happens that an input face is + // flipped, this will result in infinite iteration. Instead, we have stored + // the pointers to each face connected to this vertex. We look through each + // face to find the endpoints of the edges the have the current vertex as the + // common vertex, and then compute the subtended angle between those. Sigh... + + const VertexPtr& originVertex = m_outgoingEdge->getVertex(); // AKA 'this' + + for (const auto& f : a_faces) { + + std::vector inoutVertices(0); + for (EdgeIterator edgeIt(f->getHalfEdge()); edgeIt.ok(); ++edgeIt) { + const auto& e = edgeIt(); + + const auto& v1 = e->getVertex(); + const auto& v2 = e->getOtherVertex(); + + if (v1 == originVertex || v2 == originVertex) { + if (v1 == originVertex) { + inoutVertices.emplace_back(v2); + } + else if (v2 == originVertex) { + inoutVertices.emplace_back(v1); + } + else { + std::cerr << "In file 'CD_DCELVertexImplem.H' function " + "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; + } } } - } - if (inoutVertices.size() != 2) { - std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust 2.\n"; - } + if (inoutVertices.size() != 2) { + std::cerr << "In file 'CD_DCELVertexImplem.H' function " + "vertexT::computeVertexNormalAngleWeighted() - logic bust 2.\n"; + } + + const Vec3& x0 = originVertex->getPosition(); + const Vec3& x1 = inoutVertices[0]->getPosition(); + const Vec3& x2 = inoutVertices[1]->getPosition(); + + if (x0 == x1 || x0 == x2 || x1 == x2) { + std::cerr << "In file 'CD_DCELVertexImplem.H' function " + "vertexT::computeVertexNormalAngleWeighted() - logic bust 3.\n"; + } - const Vec3& x0 = originVertex->getPosition(); - const Vec3& x1 = inoutVertices[0]->getPosition(); - const Vec3& x2 = inoutVertices[1]->getPosition(); + Vec3 v1 = x1 - x0; + Vec3 v2 = x2 - x0; - if (x0 == x1 || x0 == x2 || x1 == x2) { - std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust 3.\n"; + v1 = v1 / v1.length(); + v2 = v2 / v2.length(); + + const Vec3& norm = f->getNormal(); + + const T alpha = acos(v1.dot(v2)); + + m_normal += alpha * norm; } - Vec3 v1 = x1 - x0; - Vec3 v2 = x2 - x0; + this->normalizeNormalVector(); + } - v1 = v1 / v1.length(); - v2 = v2 / v2.length(); + template + inline Vec3T& + VertexT::getPosition() noexcept + { + return (m_position); + } - const Vec3& norm = f->getNormal(); + template + inline const Vec3T& + VertexT::getPosition() const noexcept + { + return (m_position); + } - const T alpha = acos(v1.dot(v2)); + template + inline Vec3T& + VertexT::getNormal() noexcept + { + return (m_normal); + } - m_normal += alpha * norm; + template + inline const Vec3T& + VertexT::getNormal() const noexcept + { + return (m_normal); } - this->normalizeNormalVector(); -} - -template -inline Vec3T& -VertexT::getPosition() noexcept -{ - return (m_position); -} - -template -inline const Vec3T& -VertexT::getPosition() const noexcept -{ - return (m_position); -} - -template -inline Vec3T& -VertexT::getNormal() noexcept -{ - return (m_normal); -} - -template -inline const Vec3T& -VertexT::getNormal() const noexcept -{ - return (m_normal); -} - -template -inline std::shared_ptr>& -VertexT::getOutgoingEdge() noexcept -{ - return (m_outgoingEdge); -} - -template -inline const std::shared_ptr>& -VertexT::getOutgoingEdge() const noexcept -{ - return (m_outgoingEdge); -} - -template -inline std::vector>>& -VertexT::getFaces() noexcept -{ - return (m_faces); -} - -template -inline const std::vector>>& -VertexT::getFaces() const noexcept -{ - return (m_faces); -} - -template -inline T -VertexT::signedDistance(const Vec3& a_x0) const noexcept -{ - const auto delta = a_x0 - m_position; - const T dist = delta.length(); - const T dot = m_normal.dot(delta); - const int sign = (dot > 0.) ? 1 : -1; - - return dist * sign; -} - -template -inline T -VertexT::unsignedDistance2(const Vec3& a_x0) const noexcept -{ - const auto d = a_x0 - m_position; - - return d.dot(d); -} + template + inline std::shared_ptr>& + VertexT::getOutgoingEdge() noexcept + { + return (m_outgoingEdge); + } + + template + inline const std::shared_ptr>& + VertexT::getOutgoingEdge() const noexcept + { + return (m_outgoingEdge); + } + + template + inline std::vector>>& + VertexT::getFaces() noexcept + { + return (m_faces); + } + + template + inline const std::vector>>& + VertexT::getFaces() const noexcept + { + return (m_faces); + } + + template + inline T + VertexT::signedDistance(const Vec3& a_x0) const noexcept + { + const auto delta = a_x0 - m_position; + const T dist = delta.length(); + const T dot = m_normal.dot(delta); + const int sign = (dot > 0.) ? 1 : -1; + + return dist * sign; + } + + template + inline T + VertexT::unsignedDistance2(const Vec3& a_x0) const noexcept + { + const auto d = a_x0 - m_position; + + return d.dot(d); + } } // namespace DCEL #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_Parser.hpp b/Source/EBGeometry_Parser.hpp index 0340b5c9..ad2027c5 100644 --- a/Source/EBGeometry_Parser.hpp +++ b/Source/EBGeometry_Parser.hpp @@ -31,57 +31,57 @@ */ namespace Parser { -/*! + /*! @brief Class for reading Stanford PLY files. @note T is the precision used for storing the mesh. */ -template -class PLY -{ -public: - /*! + template + class PLY + { + public: + /*! @brief Alias for cutting down on typing */ - using Vertex = DCEL::VertexT; + using Vertex = DCEL::VertexT; - /*! + /*! @brief Alias for cutting down on typing */ - using Edge = DCEL::EdgeT; + using Edge = DCEL::EdgeT; - /*! + /*! @brief Alias for cutting down on typing */ - using Face = DCEL::FaceT; + using Face = DCEL::FaceT; - /*! + /*! @brief Alias for cutting down on typing */ - using Mesh = DCEL::MeshT; + using Mesh = DCEL::MeshT; - /*! + /*! @brief Alias for cutting down on typing */ - using EdgeIterator = DCEL::EdgeIteratorT; + using EdgeIterator = DCEL::EdgeIteratorT; - /*! + /*! @brief Static function which reads an ASCII .ply file and returns a DCEL mesh. @param[in] a_filename File name */ - inline static std::shared_ptr - readIntoDCEL(const std::string a_filename); + inline static std::shared_ptr + readIntoDCEL(const std::string a_filename); - /*! + /*! @brief Static function which reads an ASCII .ply file and puts it in a mesh. @param[out] a_mesh DCEL mesh @param[in] a_filename File name */ - inline static void - readIntoDCEL(Mesh& a_mesh, const std::string a_filename); + inline static void + readIntoDCEL(Mesh& a_mesh, const std::string a_filename); -protected: - /*! + protected: + /*! @brief Read an ASCII header @details This reads the number of vertices and faces in the PLY file. Note that it only reads the header. @@ -90,10 +90,10 @@ class PLY @param[in,out] a_inputStream File stream. On output, the filestream is at the end of the PLY header. */ - inline static void - readHeaderASCII(size_t& a_numVertices, size_t& a_numFaces, std::ifstream& a_inputStream); + inline static void + readHeaderASCII(size_t& a_numVertices, size_t& a_numFaces, std::ifstream& a_inputStream); - /*! + /*! @brief Read ASCII vertices. @param[out] a_vertices DCEL vertices. These are constructed in this routine. @param[in] a_numVertices Number of vertices to read @@ -101,11 +101,12 @@ class PLY @note The next getline() from a_inputStream must read the first vertex (i.e. don't rewind the stream before entering this routine) */ - inline static void - readVerticesIntoDCEL( - std::vector>& a_vertices, const size_t a_numVertices, std::ifstream& a_inputStream); + inline static void + readVerticesIntoDCEL(std::vector>& a_vertices, + const size_t a_numVertices, + std::ifstream& a_inputStream); - /*! + /*! @brief Read ASCII faces and create mesh connectivity. @param[out] a_faces DCEL faces. Constructured in this routine. @param[out] a_edges DCEL edges. Constructured in this routine. @@ -117,22 +118,21 @@ class PLY assume that read_ascii_vertices was called IMMEDIATELY before this function. That function will center the fstream on the correct line in the input file. */ - inline static void - readFacesIntoDCEL( - std::vector>& a_faces, - std::vector>& a_edges, - const std::vector>& a_vertices, - const size_t a_numFaces, - std::ifstream& a_inputStream); - - /*! + inline static void + readFacesIntoDCEL(std::vector>& a_faces, + std::vector>& a_edges, + const std::vector>& a_vertices, + const size_t a_numFaces, + std::ifstream& a_inputStream); + + /*! @brief Reconcile pair edges, i.e. find the pair edge for every constructed half-edge @param[in,out] a_edges Half edges. */ - inline static void - reconcilePairEdgesDCEL(std::vector>& a_edges); -}; + inline static void + reconcilePairEdgesDCEL(std::vector>& a_edges); + }; } // namespace Parser #include "EBGeometry_NamespaceFooter.hpp" diff --git a/Source/EBGeometry_ParserImplem.hpp b/Source/EBGeometry_ParserImplem.hpp index a66c1b15..48c146c3 100644 --- a/Source/EBGeometry_ParserImplem.hpp +++ b/Source/EBGeometry_ParserImplem.hpp @@ -46,8 +46,8 @@ Parser::PLY::readIntoDCEL(Mesh& a_mesh, const std::string a_filename) if (filestream.is_open()) { std::vector>& vertices = a_mesh.getVertices(); - std::vector>& edges = a_mesh.getEdges(); - std::vector>& faces = a_mesh.getFaces(); + std::vector>& edges = a_mesh.getEdges(); + std::vector>& faces = a_mesh.getFaces(); vertices.resize(0); edges.resize(0); @@ -118,19 +118,20 @@ Parser::PLY::readHeaderASCII(size_t& a_numVertices, size_t& a_numFaces, std:: template inline void -Parser::PLY::readVerticesIntoDCEL( - std::vector>& a_vertices, const size_t a_numVertices, std::ifstream& a_inputStream) +Parser::PLY::readVerticesIntoDCEL(std::vector>& a_vertices, + const size_t a_numVertices, + std::ifstream& a_inputStream) { Vec3T pos; - T& x = pos[0]; - T& y = pos[1]; - T& z = pos[2]; + T& x = pos[0]; + T& y = pos[1]; + T& z = pos[2]; Vec3T norm; - T& nx = norm[0]; - T& ny = norm[1]; - T& nz = norm[2]; + T& nx = norm[0]; + T& ny = norm[1]; + T& nz = norm[2]; size_t num = 0; @@ -151,18 +152,17 @@ Parser::PLY::readVerticesIntoDCEL( template inline void -Parser::PLY::readFacesIntoDCEL( - std::vector>& a_faces, - std::vector>& a_edges, - const std::vector>& a_vertices, - const size_t a_numFaces, - std::ifstream& a_inputStream) +Parser::PLY::readFacesIntoDCEL(std::vector>& a_faces, + std::vector>& a_edges, + const std::vector>& a_vertices, + const size_t a_numFaces, + std::ifstream& a_inputStream) { - size_t numVertices; + size_t numVertices; std::vector vertexIndices; std::string line; - size_t counter = 0; + size_t counter = 0; while (std::getline(a_inputStream, line)) { counter++; @@ -199,7 +199,7 @@ Parser::PLY::readFacesIntoDCEL( // Associate next/previous for the half edges inside the current face. Wish // we had a circular iterator but this will have to do. for (size_t i = 0; i < halfEdges.size(); i++) { - auto& curEdge = halfEdges[i]; + auto& curEdge = halfEdges[i]; auto& nextEdge = halfEdges[(i + 1) % halfEdges.size()]; curEdge->setNextEdge(nextEdge); @@ -234,15 +234,15 @@ Parser::PLY::reconcilePairEdgesDCEL(std::vector>& a_edg const auto& nextEdge = curEdge->getNextEdge(); const auto& vertexStart = curEdge->getVertex(); - const auto& vertexEnd = nextEdge->getVertex(); + const auto& vertexEnd = nextEdge->getVertex(); for (const auto& p : vertexStart->getFaces()) { for (EdgeIterator edgeIt(*p); edgeIt.ok(); ++edgeIt) { - const auto& polyCurEdge = edgeIt(); + const auto& polyCurEdge = edgeIt(); const auto& polyNextEdge = polyCurEdge->getNextEdge(); const auto& polyVertexStart = polyCurEdge->getVertex(); - const auto& polyVertexEnd = polyNextEdge->getVertex(); + const auto& polyVertexEnd = polyNextEdge->getVertex(); if (vertexStart == polyVertexEnd && polyVertexStart == vertexEnd) { // Found the pair edge curEdge->setPairEdge(polyCurEdge); diff --git a/Source/EBGeometry_Polygon2DImplem.hpp b/Source/EBGeometry_Polygon2DImplem.hpp index 2dd12fa1..f97aec3e 100644 --- a/Source/EBGeometry_Polygon2DImplem.hpp +++ b/Source/EBGeometry_Polygon2DImplem.hpp @@ -136,7 +136,7 @@ Polygon2D::computeCrossingNumber(const Vec2& P) const noexcept const Vec2& P1 = m_points[i]; const Vec2& P2 = m_points[(i + 1) % N]; - const bool upwardCrossing = (P1.y <= P.y) && (P2.y > P.y); + const bool upwardCrossing = (P1.y <= P.y) && (P2.y > P.y); const bool downwardCrossing = (P1.y > P.y) && (P2.y <= P.y); if (upwardCrossing || downwardCrossing) { diff --git a/Source/EBGeometry_TransformOpsImplem.hpp b/Source/EBGeometry_TransformOpsImplem.hpp index 5c2a424c..5dda8132 100644 --- a/Source/EBGeometry_TransformOpsImplem.hpp +++ b/Source/EBGeometry_TransformOpsImplem.hpp @@ -38,7 +38,7 @@ TranslateOp::transform(const Vec3T& a_inputPoint) const noexcept template RotateOp::RotateOp() { - m_axis = Vec3T::unit(); + m_axis = Vec3T::unit(); m_cosAngle = std::cos(T(0.0)); m_sinAngle = std::sin(T(0.0)); } @@ -46,7 +46,7 @@ RotateOp::RotateOp() template RotateOp::RotateOp(const T a_angle, const size_t a_axis) noexcept { - m_axis = a_axis; + m_axis = a_axis; m_cosAngle = std::cos(a_angle); m_sinAngle = std::sin(a_angle); } diff --git a/Source/EBGeometry_UnionBVH.hpp b/Source/EBGeometry_UnionBVH.hpp index 48ff0f15..f60f8917 100644 --- a/Source/EBGeometry_UnionBVH.hpp +++ b/Source/EBGeometry_UnionBVH.hpp @@ -58,10 +58,9 @@ class UnionBVH : public SignedDistanceFunction @param[in] a_flipSign Hook for turning inside to outside @param[in] a_bvConstructor Bounding volume constructor. */ - UnionBVH( - const std::vector>& a_distanceFunctions, - const bool a_flipSign, - const BVConstructor& a_bvConstructor); + UnionBVH(const std::vector>& a_distanceFunctions, + const bool a_flipSign, + const BVConstructor& a_bvConstructor); /*! @brief Build BVH tree for the input objects. User must supply a partitioner diff --git a/Source/EBGeometry_UnionBVHImplem.hpp b/Source/EBGeometry_UnionBVHImplem.hpp index f4aeb7e4..c0e571dd 100644 --- a/Source/EBGeometry_UnionBVHImplem.hpp +++ b/Source/EBGeometry_UnionBVHImplem.hpp @@ -24,14 +24,13 @@ UnionBVH::UnionBVH(const std::vector>& a_distance } m_flipSign = a_flipSign; - m_isGood = false; + m_isGood = false; } template -UnionBVH::UnionBVH( - const std::vector>& a_distanceFunctions, - const bool a_flipSign, - const BVConstructor& a_bvConstructor) +UnionBVH::UnionBVH(const std::vector>& a_distanceFunctions, + const bool a_flipSign, + const BVConstructor& a_bvConstructor) : UnionBVH(a_distanceFunctions, a_flipSign) { @@ -80,8 +79,8 @@ UnionBVH::buildTree(const BVConstructor& a_bvConstructor) // volumes. We do this by packing the SDFs and their BV centroids // in a vector which we sort (I love C++). using Primitive = std::shared_ptr; - using Centroid = Vec3T; - using PC = std::pair; + using Centroid = Vec3T; + using PC = std::pair; // Vector pack. std::vector primsAndCentroids; @@ -104,12 +103,12 @@ UnionBVH::buildTree(const BVConstructor& a_bvConstructor) // 4. Figure out where along the PC vector we should do our spatial splits. // We try to balance the chunks. const size_t almostEqualChunkSize = numPrimitives / K; - size_t remainder = numPrimitives % K; + size_t remainder = numPrimitives % K; std::array startIndices; std::array endIndices; - startIndices[0] = 0; + startIndices[0] = 0; endIndices[K - 1] = numPrimitives; for (size_t i = 1; i < K; i++) { diff --git a/Source/EBGeometry_VecImplem.hpp b/Source/EBGeometry_VecImplem.hpp index 09c711fe..ddbd683d 100644 --- a/Source/EBGeometry_VecImplem.hpp +++ b/Source/EBGeometry_VecImplem.hpp @@ -239,7 +239,7 @@ inline constexpr Vec3T Vec3T::unit(const size_t a_dir) noexcept { Vec3T v = Vec3T::zero(); - v[a_dir] = 1.0; + v[a_dir] = 1.0; return v; } From 7381e7d4861ef635ad8a6634698e75fb31c2f5ed Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Mon, 2 May 2022 09:23:35 +0200 Subject: [PATCH 6/7] Comments align --- Examples/AMReX_Shapes/main.cpp | 34 +- Examples/EBGeometry_DCEL/main.cpp | 2 +- Source/EBGeometry_BVH.hpp | 558 ++++++++++---------- Source/EBGeometry_BVHImplem.hpp | 14 +- Source/EBGeometry_BoundingVolumes.hpp | 322 +++++------ Source/EBGeometry_BoundingVolumesImplem.hpp | 4 +- Source/EBGeometry_DCEL_BVH.hpp | 98 ++-- Source/EBGeometry_DCEL_Edge.hpp | 306 +++++------ Source/EBGeometry_DCEL_Face.hpp | 294 +++++------ Source/EBGeometry_DCEL_Iterator.hpp | 144 ++--- Source/EBGeometry_DCEL_IteratorImplem.hpp | 2 +- Source/EBGeometry_DCEL_Mesh.hpp | 340 ++++++------ Source/EBGeometry_DCEL_MeshImplem.hpp | 8 +- Source/EBGeometry_DCEL_Polygon2D.hpp | 192 ------- Source/EBGeometry_DCEL_Polygon2DImplem.hpp | 226 -------- Source/EBGeometry_DCEL_Vertex.hpp | 256 ++++----- Source/EBGeometry_DCEL_VertexImplem.hpp | 6 +- Source/EBGeometry_Parser.hpp | 102 ++-- Source/EBGeometry_ParserImplem.hpp | 2 +- Source/EBGeometry_Polygon2D.hpp | 10 +- Source/EBGeometry_Polygon2DImplem.hpp | 2 +- Source/EBGeometry_UnionBVHImplem.hpp | 6 +- Source/EBGeometry_Vec.hpp | 4 +- Source/EBGeometry_VecImplem.hpp | 2 +- 24 files changed, 1258 insertions(+), 1676 deletions(-) delete mode 100644 Source/EBGeometry_DCEL_Polygon2D.hpp delete mode 100644 Source/EBGeometry_DCEL_Polygon2DImplem.hpp diff --git a/Examples/AMReX_Shapes/main.cpp b/Examples/AMReX_Shapes/main.cpp index 2b8f088b..5311c91a 100644 --- a/Examples/AMReX_Shapes/main.cpp +++ b/Examples/AMReX_Shapes/main.cpp @@ -23,37 +23,37 @@ namespace amrex { namespace EB2 { /*! - @brief This is just an EBGeometry-exposed signed distance field usable with - AMReX. -*/ + @brief This is just an EBGeometry-exposed signed distance field usable with + AMReX. + */ class AMReXSDF { public: /*! -@brief Full constructor. -@param[in] a_filename File name. Must be a PLY file and will be parser by the -PLY parser. -@param[in] a_flipSign Hook for swapping inside/outside. - */ + @brief Full constructor. + @param[in] a_filename File name. Must be a PLY file and will be parser by the + PLY parser. + @param[in] a_flipSign Hook for swapping inside/outside. + */ AMReXSDF(std::shared_ptr& a_sdf) { m_sdf = a_sdf; } /*! -@brief Copy constructor. -@param[in] a_other Other SDF. - */ + @brief Copy constructor. + @param[in] a_other Other SDF. + */ AMReXSDF(const AMReXSDF& a_other) { this->m_sdf = a_other.m_sdf; } /*! -@brief AMReX's implicit function definition. - */ + @brief AMReX's implicit function definition. + */ Real operator()(AMREX_D_DECL(Real x, Real y, Real z)) const noexcept { return m_sdf->signedDistance(Vec3(x, y, z)); }; /*! -@brief Also an AMReX implicit function implementation - */ + @brief Also an AMReX implicit function implementation + */ inline Real operator()(const RealArray& p) const noexcept { @@ -62,8 +62,8 @@ PLY parser. protected: /*! -@brief EBGeometry signed distance function. - */ + @brief EBGeometry signed distance function. + */ std::shared_ptr m_sdf; }; } // namespace EB2 diff --git a/Examples/EBGeometry_DCEL/main.cpp b/Examples/EBGeometry_DCEL/main.cpp index 862c16d4..0cc4d2b3 100644 --- a/Examples/EBGeometry_DCEL/main.cpp +++ b/Examples/EBGeometry_DCEL/main.cpp @@ -31,7 +31,7 @@ main(int argc, char* argv[]) } else { std::cerr << "Missing file name. Use ./a.out 'filename' where 'filename' " - "is one of the files in ../PLY\n"; + "is one of the files in ../PLY\n"; } // Declare the precision T as float. diff --git a/Source/EBGeometry_BVH.hpp b/Source/EBGeometry_BVH.hpp index 6c01efd1..277af38e 100644 --- a/Source/EBGeometry_BVH.hpp +++ b/Source/EBGeometry_BVH.hpp @@ -28,324 +28,324 @@ namespace BVH { /*! - @brief Forward declare the BVH node since it is needed for the polymorphic - lambdas. - @details T is the precision used in the BVH computations, P is the enclosing - primitive and BV is the bounding volume used in the BVH. K is the tree degree. -*/ + @brief Forward declare the BVH node since it is needed for the polymorphic + lambdas. + @details T is the precision used in the BVH computations, P is the enclosing + primitive and BV is the bounding volume used in the BVH. K is the tree degree. + */ template class NodeT; /*! - @brief Forward declare linear node class. - @details T is the precision used in the BVH computations, P is the enclosing - primitive and BV is the bounding volume used in the BVH. K is the tree degree. -*/ + @brief Forward declare linear node class. + @details T is the precision used in the BVH computations, P is the enclosing + primitive and BV is the bounding volume used in the BVH. K is the tree degree. + */ template class LinearNodeT; /*! - @brief Forward declare linear BVH class. - @details T is the precision used in the BVH computations, P is the enclosing - primitive and BV is the bounding volume used in the BVH. K is the tree degree. -*/ + @brief Forward declare linear BVH class. + @details T is the precision used in the BVH computations, P is the enclosing + primitive and BV is the bounding volume used in the BVH. K is the tree degree. + */ template class LinearBVH; /*! - @brief Alias to cut down on typing. - @details P is the primitive bounded by the BVH. -*/ + @brief Alias to cut down on typing. + @details P is the primitive bounded by the BVH. + */ template using PrimitiveListT = std::vector>; /*! - @brief Stop function for deciding when a BVH node can't be divided into - sub-volumes. - @details T is the precision used in the BVH computations, P is the enclosing - primitive and BV is the bounding volume used in the BVH. K is the tree degree. - @param[in] a_node BVH node - @return True if the node can't be divided into subvolumes and false otherwise. -*/ + @brief Stop function for deciding when a BVH node can't be divided into + sub-volumes. + @details T is the precision used in the BVH computations, P is the enclosing + primitive and BV is the bounding volume used in the BVH. K is the tree degree. + @param[in] a_node BVH node + @return True if the node can't be divided into subvolumes and false otherwise. + */ template using StopFunctionT = std::function& a_node)>; /*! - @brief Polymorphic partitioner for splitting a list of primitives into K new - lists of primitives - @details P is the primitive type bound in the BVH and K is the BVH degree. - @param[in] a_primitives List of primitives to be subdivided into sub-bounding - volumes. - @return Returns a list (std::array) of new primitives which make up the new - bounding volumes. -*/ + @brief Polymorphic partitioner for splitting a list of primitives into K new + lists of primitives + @details P is the primitive type bound in the BVH and K is the BVH degree. + @param[in] a_primitives List of primitives to be subdivided into sub-bounding + volumes. + @return Returns a list (std::array) of new primitives which make up the new + bounding volumes. + */ template using PartitionerT = std::function, K>(const PrimitiveListT

& a_primitives)>; /*! - @brief Constructor method for creating bounding volumes from a list of - primitives - @details P is the primitive type bound in the BVH and BV is the bounding - volume type. - @param[in] a_primitives List of primitives. - @return Returns a new bounding volumes which is guaranteed to enclose all the - input primitives. -*/ + @brief Constructor method for creating bounding volumes from a list of + primitives + @details P is the primitive type bound in the BVH and BV is the bounding + volume type. + @param[in] a_primitives List of primitives. + @return Returns a new bounding volumes which is guaranteed to enclose all the + input primitives. + */ template using BVConstructorT = std::function& a_primitive)>; /*! - @brief Typename for identifying algorithms various algorithms during tree - traversel. - @details Stack => Use stack/priority queue (ordered traversal). - Ordered => Use recursive ordered traversal. - Unordered => Use recursive unordered traversal. -*/ + @brief Typename for identifying algorithms various algorithms during tree + traversel. + @details Stack => Use stack/priority queue (ordered traversal). + Ordered => Use recursive ordered traversal. + Unordered => Use recursive unordered traversal. + */ enum class Prune - { - Stack, - Ordered, - Unordered, - }; + { + Stack, + Ordered, + Unordered, + }; /*! - @brief Class which encapsulates a node in a bounding volume hierarchy. - @details T is the precision, P is the primitive type you want to enclose, BV - is the bounding volume type used at the nodes. The parameter K (which must be - > 1) is the tree degree. K=2 is a binary tree, K=3 is a tertiary tree and so - on. - @note Template constraints are as following: + @brief Class which encapsulates a node in a bounding volume hierarchy. + @details T is the precision, P is the primitive type you want to enclose, BV + is the bounding volume type used at the nodes. The parameter K (which must be + > 1) is the tree degree. K=2 is a binary tree, K=3 is a tertiary tree and so + on. + @note Template constraints are as following: - P MUST supply function signedDistance(...) . - BV MUST supply a function getDistance + P MUST supply function signedDistance(...) . + BV MUST supply a function getDistance - Had this been C++20, we would have use concepts to enforce this. -*/ + Had this been C++20, we would have use concepts to enforce this. + */ template class NodeT : public SignedDistanceFunction { public: /*! - @brief Alias for cutting down on typing. This is a - std::vector >. - */ + @brief Alias for cutting down on typing. This is a + std::vector >. + */ using PrimitiveList = PrimitiveListT

; /*! - @brief Alias for cutting down on typing. - */ + @brief Alias for cutting down on typing. + */ using Vec3 = Vec3T; /*! - @brief Alias for cutting down on typing. - */ + @brief Alias for cutting down on typing. + */ using Node = NodeT; /*! - @brief Alias for cutting down on typing. - */ + @brief Alias for cutting down on typing. + */ using NodePtr = std::shared_ptr; /*! - @brief Alias for cutting down on typing. - */ + @brief Alias for cutting down on typing. + */ using StopFunction = StopFunctionT; /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using Partitioner = PartitionerT; /*! - @brief Alias for cutting down on typing. - */ + @brief Alias for cutting down on typing. + */ using BVConstructor = BVConstructorT; /*! - @brief Default constructor which sets a regular node. - */ + @brief Default constructor which sets a regular node. + */ NodeT(); /*! - @brief Construct node from a set of primitives. - @details This node becomes a leaf node which contains the input primitives. - @param[in] a_primitives Input primitives. - */ + @brief Construct node from a set of primitives. + @details This node becomes a leaf node which contains the input primitives. + @param[in] a_primitives Input primitives. + */ NodeT(const std::vector>& a_primitives); /*! - @brief Construct node from a set of primitives. - @details This node becomes a leaf node which contains the input primitives. - @param[in] a_primitives Input primitives. - */ + @brief Construct node from a set of primitives. + @details This node becomes a leaf node which contains the input primitives. + @param[in] a_primitives Input primitives. + */ NodeT(const std::vector>& a_primitives); /*! - @brief Destructor (does nothing) - */ + @brief Destructor (does nothing) + */ virtual ~NodeT(); /*! - @brief Function for using top-down construction of the bounding volume - hierarchy. - @details The rules for terminating the hierarchy construction, how to - partition sets of primitives, and how to enclose them by bounding volumes - are given in the input arguments (a_stopFunc, a_partFunc, a_bvFunc) - @param[in] a_bvConstructor Polymorphic function which builds a bounding - volume from a set of primitives. - @param[in] a_partitioner Partitioning function. This is a polymorphic - function which divides a set of primitives into two lists. - @param[in] a_stopCrit Termination function which tells us when to stop - the recursion. - */ + @brief Function for using top-down construction of the bounding volume + hierarchy. + @details The rules for terminating the hierarchy construction, how to + partition sets of primitives, and how to enclose them by bounding volumes + are given in the input arguments (a_stopFunc, a_partFunc, a_bvFunc) + @param[in] a_bvConstructor Polymorphic function which builds a bounding + volume from a set of primitives. + @param[in] a_partitioner Partitioning function. This is a polymorphic + function which divides a set of primitives into two lists. + @param[in] a_stopCrit Termination function which tells us when to stop + the recursion. + */ inline void topDownSortAndPartitionPrimitives(const BVConstructor& a_bvConstructor, const Partitioner& a_partitioner, const StopFunction& a_stopCrit) noexcept; /*! - @brief Get node type - */ + @brief Get node type + */ inline bool isLeaf() const noexcept; /*! - @brief Get the primitives stored in this node. - @return m_primitives. - */ + @brief Get the primitives stored in this node. + @return m_primitives. + */ inline const PrimitiveList& getPrimitives() const noexcept; /*! - @brief Get bounding volume - @return m_bv - */ + @brief Get bounding volume + @return m_bv + */ inline const BV& getBoundingVolume() const noexcept; /*! - @brief Return this node's children. - @return m_children. - */ + @brief Return this node's children. + @return m_children. + */ inline const std::array>, K>& getChildren() const noexcept; /*! - @brief Function which computes the signed distance - @param[in] a_point 3D point in space - @return Signed distance to the input point. - */ + @brief Function which computes the signed distance + @param[in] a_point 3D point in space + @return Signed distance to the input point. + */ inline T signedDistance(const Vec3T& a_point) const noexcept override; /*! - @brief Function which computes the signed distance. This version allows the - user to manually select a traversal algorithm. - @param[in] a_point 3D point in space - @param[in] a_pruning Pruning algorithm - @return Signed distance to the input point. - */ + @brief Function which computes the signed distance. This version allows the + user to manually select a traversal algorithm. + @param[in] a_point 3D point in space + @param[in] a_pruning Pruning algorithm + @return Signed distance to the input point. + */ inline T signedDistance(const Vec3T& a_point, const Prune a_pruning) const noexcept; /*! - @brief Flatten everything beneath this node into a depth-first sorted BVH - hierarchy. - @details This will compute the flattening of the standard BVH tree and - return a pointer to the linear corresponding to the current node. - */ + @brief Flatten everything beneath this node into a depth-first sorted BVH + hierarchy. + @details This will compute the flattening of the standard BVH tree and + return a pointer to the linear corresponding to the current node. + */ inline std::shared_ptr> flattenTree() const noexcept; protected: /*! - @brief Bounding volume object. - */ + @brief Bounding volume object. + */ BV m_boundingVolume; /*! - @brief Primitives list. This will be empty for regular nodes - */ + @brief Primitives list. This will be empty for regular nodes + */ std::vector> m_primitives; /*! - @brief Children nodes - */ + @brief Children nodes + */ std::array>, K> m_children; /*! - @brief Insert nodes with primitives. - @param[in] a_primitives Primitives for children. - */ + @brief Insert nodes with primitives. + @param[in] a_primitives Primitives for children. + */ inline void insertChildren(const std::array& a_primitives) noexcept; /*! - @brief Set primitives in this node - @param[in] a_primitives Primitives - */ + @brief Set primitives in this node + @param[in] a_primitives Primitives + */ inline void setPrimitives(const PrimitiveList& a_primitives) noexcept; /*! - @brief Get the distance from a 3D point to the bounding volume - @param[in] a_point 3D point - @return Returns distance to bounding volume. A zero distance implies that - the input point is inside the bounding volume. - */ + @brief Get the distance from a 3D point to the bounding volume + @param[in] a_point 3D point + @return Returns distance to bounding volume. A zero distance implies that + the input point is inside the bounding volume. + */ inline T getDistanceToBoundingVolume(const Vec3& a_point) const noexcept; /*! - @brief Compute the shortest distance to the primitives in this node. - @param[in] a_point 3D point - @return Returns the signed distance to the primitives. - */ + @brief Compute the shortest distance to the primitives in this node. + @param[in] a_point 3D point + @return Returns the signed distance to the primitives. + */ inline T getDistanceToPrimitives(const Vec3& a_point) const noexcept; /*! - @brief Get the list of primitives in this node. - @return Primitives list - */ + @brief Get the list of primitives in this node. + @return Primitives list + */ inline PrimitiveList& getPrimitives() noexcept; /*! - @brief Iterative ordered pruning along the BVH tree. - @param[in,out] a_point Input 3D point - */ + @brief Iterative ordered pruning along the BVH tree. + @param[in,out] a_point Input 3D point + */ inline T pruneStack(const Vec3& a_point) const noexcept; /*! - @brief Recursively ordered pruning along the BVH tree. - @param[in,out] a_closest Shortest distance to primitives so far. - @param[in,out] a_point Input 3D point - */ + @brief Recursively ordered pruning along the BVH tree. + @param[in,out] a_closest Shortest distance to primitives so far. + @param[in,out] a_point Input 3D point + */ inline void pruneOrdered(T& a_closest, const Vec3& a_point) const noexcept; /*! - @brief Recursive unordered pruning along the BVH tree. - @param[in,out] a_closest Shortest distance to primitives so far. - @param[in,out] a_point Input 3D point - */ + @brief Recursive unordered pruning along the BVH tree. + @param[in,out] a_closest Shortest distance to primitives so far. + @param[in,out] a_point Input 3D point + */ inline void pruneUnordered(T& a_closest, const Vec3& a_point) const noexcept; /*! - @brief Flatten tree method. - @details This function will flatten everything beneath the current node and - linearize all the nodes and primitives beneath it to a_linearNodes and - a_sortedPrimitives. This function is called recursively. - @param[in,out] a_linearNodes BVH nodes, linearized onto a vector. - @param[in,out] a_sortedPrimitives Sorted primitives (in leaf node order). - @param[in,out] a_offset Supporting integer for figuring out where - in the tree we are. - @note When called from the root node, a_linearNodes and a_sortedPrimitives - should be empty and a_offset=0UL. - */ + @brief Flatten tree method. + @details This function will flatten everything beneath the current node and + linearize all the nodes and primitives beneath it to a_linearNodes and + a_sortedPrimitives. This function is called recursively. + @param[in,out] a_linearNodes BVH nodes, linearized onto a vector. + @param[in,out] a_sortedPrimitives Sorted primitives (in leaf node order). + @param[in,out] a_offset Supporting integer for figuring out where + in the tree we are. + @note When called from the root node, a_linearNodes and a_sortedPrimitives + should be empty and a_offset=0UL. + */ inline size_t flattenTree(std::vector>>& a_linearNodes, std::vector>& a_sortedPrimitives, @@ -353,223 +353,223 @@ namespace BVH { }; /*! - @brief Node type for linearized (flattened) BVH. This will be constructed from - the other (conventional) BVH type. - - @details T is the precision for Vec3, P is the primitive type you want to - enclose, BV is the bounding volume you use for it. - - @note P MUST supply function signedDistance(...) BV must supply a function - getDistance (had this been C++20, we would have use concepts to enforce this). - Note that LinearNode is the result of a flattened BVH hierarchy where nodes - are stored with depth-first ordering for improved cache-location in the - downward traversal. - - @note This class exists so that we can fit the nodes with a smaller memory - footprint. The standard BVH node (NodeT) is very useful when building the tree - but less useful when traversing it since it stores references to the - primitives in the node itself. It will span multiple cache lines. This node - exists so that we can fit all the BVH info onto fewer cache lines. The number - of cache lines will depend on the tree degree, precision, and bounding volume - that is chosen. - - @todo There's a minor optimization that can be made to the memory alignment, - which is as follows: For a leaf node we never really need the m_childOffsets - array, and for a regular node we never really need the m_primitivesOffset - member. Moreover, m_childOffsets could be made into a K-1 sized array because - we happen to know that the linearized hierarchy will store the first child - node immediately after the regular node. We could shave off 16 bytes of - storage, which would mean that a double-precision binary tree only takes up - one word of CPU memory. -*/ + @brief Node type for linearized (flattened) BVH. This will be constructed from + the other (conventional) BVH type. + + @details T is the precision for Vec3, P is the primitive type you want to + enclose, BV is the bounding volume you use for it. + + @note P MUST supply function signedDistance(...) BV must supply a function + getDistance (had this been C++20, we would have use concepts to enforce this). + Note that LinearNode is the result of a flattened BVH hierarchy where nodes + are stored with depth-first ordering for improved cache-location in the + downward traversal. + + @note This class exists so that we can fit the nodes with a smaller memory + footprint. The standard BVH node (NodeT) is very useful when building the tree + but less useful when traversing it since it stores references to the + primitives in the node itself. It will span multiple cache lines. This node + exists so that we can fit all the BVH info onto fewer cache lines. The number + of cache lines will depend on the tree degree, precision, and bounding volume + that is chosen. + + @todo There's a minor optimization that can be made to the memory alignment, + which is as follows: For a leaf node we never really need the m_childOffsets + array, and for a regular node we never really need the m_primitivesOffset + member. Moreover, m_childOffsets could be made into a K-1 sized array because + we happen to know that the linearized hierarchy will store the first child + node immediately after the regular node. We could shave off 16 bytes of + storage, which would mean that a double-precision binary tree only takes up + one word of CPU memory. + */ template class LinearNodeT { public: /*! - @brief Alias for cutting down on typing. - */ + @brief Alias for cutting down on typing. + */ using Vec3 = Vec3T; /*! - @brief Constructor. - */ + @brief Constructor. + */ inline LinearNodeT() noexcept; /*! - @brief Destructor. - */ + @brief Destructor. + */ inline virtual ~LinearNodeT(); /*! - @brief Set the bounding volume - @param[in] a_boundingVolume Bounding volume for this node. - */ + @brief Set the bounding volume + @param[in] a_boundingVolume Bounding volume for this node. + */ inline void setBoundingVolume(const BV& a_boundingVolume) noexcept; /*! - @brief Set the offset into the primitives array. - */ + @brief Set the offset into the primitives array. + */ inline void setPrimitivesOffset(const size_t a_primitivesOffset) noexcept; /*! - @brief Set number of primitives. - @param[in] a_numPrimitives Number of primitives. - */ + @brief Set number of primitives. + @param[in] a_numPrimitives Number of primitives. + */ inline void setNumPrimitives(const size_t a_numPrimitives) noexcept; /*! - @brief Set the child offsets. - @param[in] a_childOffset Offset in node array. - @param[in] a_whichChild Child index in m_childrenOffsets. Must be [0,K-1] - */ + @brief Set the child offsets. + @param[in] a_childOffset Offset in node array. + @param[in] a_whichChild Child index in m_childrenOffsets. Must be [0,K-1] + */ inline void setChildOffset(const size_t a_childOffset, const size_t a_whichChild) noexcept; /*! - @brief Get the node bounding volume. - return m_boundingVolume - */ + @brief Get the node bounding volume. + return m_boundingVolume + */ inline const BV& getBoundingVolume() const noexcept; /*! - @brief Get the primitives offset - @return Returns m_primitivesOffset - */ + @brief Get the primitives offset + @return Returns m_primitivesOffset + */ inline const size_t& getPrimitivesOffset() const noexcept; /*! - @brief Get the number of primitives. - @return Returns m_numPrimitives - */ + @brief Get the number of primitives. + @return Returns m_numPrimitives + */ inline const size_t& getNumPrimitives() const noexcept; /*! - @brief Get the child offsets - @return Returns m_childOffsets - */ + @brief Get the child offsets + @return Returns m_childOffsets + */ inline const std::array& getChildOffsets() const noexcept; /*! - @brief Is leaf or not - */ + @brief Is leaf or not + */ inline bool isLeaf() const noexcept; /*! - @brief Get the distance from a 3D point to the bounding volume - @param[in] a_point 3D point - @return Returns distance to bounding volume. A zero distance implies that - the input point is inside the bounding volume. - */ + @brief Get the distance from a 3D point to the bounding volume + @param[in] a_point 3D point + @return Returns distance to bounding volume. A zero distance implies that + the input point is inside the bounding volume. + */ inline T getDistanceToBoundingVolume(const Vec3& a_point) const noexcept; /*! - @brief Compute signed distance to primitives. - @param[in] a_point Point - @param[in] a_primitives List of primitives - @note Only call if this is a leaf node. - */ + @brief Compute signed distance to primitives. + @param[in] a_point Point + @param[in] a_primitives List of primitives + @note Only call if this is a leaf node. + */ inline T getDistanceToPrimitives(const Vec3& a_point, const std::vector>& a_primitives) const noexcept; protected: /*! - @brief Bounding volume. - */ + @brief Bounding volume. + */ BV m_boundingVolume; /*! - @brief Offset into primitives array - */ + @brief Offset into primitives array + */ size_t m_primitivesOffset; /*! - @brief Number of primitives - */ + @brief Number of primitives + */ size_t m_numPrimitives; /*! - @brief Offset to child nodes. - */ + @brief Offset to child nodes. + */ std::array m_childOffsets; }; /*! - @brief Linear root node for BVH hierarchy -*/ + @brief Linear root node for BVH hierarchy + */ template class LinearBVH : public SignedDistanceFunction { public: /*! - @brief Cut down on typing - */ + @brief Cut down on typing + */ using Vec3 = Vec3T; /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using LinearNode = LinearNodeT; /*! - @brief List of primitives - */ + @brief List of primitives + */ using PrimitiveList = std::vector>; /*! - @brief Disallowed. Use the full constructor please. - */ + @brief Disallowed. Use the full constructor please. + */ LinearBVH() = delete; /*! - @brief Full constructor. Associates the nodes and primitives. - @param[in] a_linearNodes Linearized BVH nodes. - @param[in] a_primitives Primitives. - */ + @brief Full constructor. Associates the nodes and primitives. + @param[in] a_linearNodes Linearized BVH nodes. + @param[in] a_primitives Primitives. + */ inline LinearBVH(const std::vector>>& a_linearNodes, const std::vector>& a_primitives); /*! - @brief Full constructor. Associates the nodes and primitives. - @param[in] a_linearNodes Linearized BVH nodes. - @param[in] a_primitives Primitives. - */ + @brief Full constructor. Associates the nodes and primitives. + @param[in] a_linearNodes Linearized BVH nodes. + @param[in] a_primitives Primitives. + */ inline LinearBVH(const std::vector>>& a_linearNodes, const std::vector>& a_primitives); /*! - @brief Destructor. Does nothing - */ + @brief Destructor. Does nothing + */ inline virtual ~LinearBVH(); /*! - @brief Function which computes the signed distance. This calls the other - version. - @param[in] a_point 3D point in space - */ + @brief Function which computes the signed distance. This calls the other + version. + @param[in] a_point 3D point in space + */ inline T signedDistance(const Vec3& a_point) const noexcept override; protected: /*! - @brief List of linearly stored nodes - */ + @brief List of linearly stored nodes + */ std::vector>> m_linearNodes; /*! - @brief Global list of primitives. Note that this is ALL primitives, sorted - so that LinearNodeT can interface into it. - */ + @brief Global list of primitives. Note that this is ALL primitives, sorted + so that LinearNodeT can interface into it. + */ std::vector> m_primitives; }; } // namespace BVH diff --git a/Source/EBGeometry_BVHImplem.hpp b/Source/EBGeometry_BVHImplem.hpp index 4e78926f..b55e58a4 100644 --- a/Source/EBGeometry_BVHImplem.hpp +++ b/Source/EBGeometry_BVHImplem.hpp @@ -200,7 +200,7 @@ namespace BVH { } default: std::cerr << "In file EBGeometry_BVHImplem.hpp function NodeT::signedDistance(Vec3, Prune) -- bad input enum for 'Prune'\n"; + "K>::signedDistance(Vec3, Prune) -- bad input enum for 'Prune'\n"; }; return ret; @@ -265,9 +265,9 @@ namespace BVH { } std::sort( - childrenAndDistances.begin(), - childrenAndDistances.end(), - [](const NodeAndDist& node1, const NodeAndDist& node2) -> bool { return node1.second > node2.second; }); + childrenAndDistances.begin(), + childrenAndDistances.end(), + [](const NodeAndDist& node1, const NodeAndDist& node2) -> bool { return node1.second > node2.second; }); // Push the children onto the stack. for (const auto& child : childrenAndDistances) { @@ -518,7 +518,7 @@ namespace BVH { template inline T LinearNodeT::getDistanceToPrimitives( - const Vec3T& a_point, const std::vector>& a_primitives) const noexcept + const Vec3T& a_point, const std::vector>& a_primitives) const noexcept { T minDist = std::numeric_limits::infinity(); @@ -535,8 +535,8 @@ namespace BVH { template inline LinearBVH::LinearBVH( - const std::vector>>& a_linearNodes, - const std::vector>& a_primitives) + const std::vector>>& a_linearNodes, + const std::vector>& a_primitives) { m_linearNodes = a_linearNodes; m_primitives = a_primitives; diff --git a/Source/EBGeometry_BoundingVolumes.hpp b/Source/EBGeometry_BoundingVolumes.hpp index faa53b2f..64daa0db 100644 --- a/Source/EBGeometry_BoundingVolumes.hpp +++ b/Source/EBGeometry_BoundingVolumes.hpp @@ -27,355 +27,355 @@ namespace BoundingVolumes { /*! - @brief Class which encloses a set of points using a bounding sphere. - @details The template parameter T is the floating-point precision which is - used. -*/ + @brief Class which encloses a set of points using a bounding sphere. + @details The template parameter T is the floating-point precision which is + used. + */ template class BoundingSphereT { public: /*! - @brief Typename for possible algorithms that support the computation of a - bounding sphere for a set of 3D points. - */ + @brief Typename for possible algorithms that support the computation of a + bounding sphere for a set of 3D points. + */ enum class BoundingVolumeAlgorithm - { - Ritter, - }; + { + Ritter, + }; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vec3 = Vec3T; /*! - @brief Default constructor. Leaves object in undefined state. - */ + @brief Default constructor. Leaves object in undefined state. + */ BoundingSphereT(); /*! - @brief Full constructor. Sets the center and radius of the bounding sphere. - @param[in] a_center Bounding sphere center - @param[in] a_radius Bounding sphere radius - */ + @brief Full constructor. Sets the center and radius of the bounding sphere. + @param[in] a_center Bounding sphere center + @param[in] a_radius Bounding sphere radius + */ BoundingSphereT(const Vec3T& a_center, const T& a_radius); /*! - @brief Full constructor. Constructs a bounding sphere that encloses all the - other bounding spheres - @param[in] a_otherSpheres Other bounding spheres. - */ + @brief Full constructor. Constructs a bounding sphere that encloses all the + other bounding spheres + @param[in] a_otherSpheres Other bounding spheres. + */ BoundingSphereT(const std::vector>& a_otherSpheres); /*! - @brief Copy constructor. Sets the center and radius from the other sphere. - @param[in] a_other Other sphere - */ + @brief Copy constructor. Sets the center and radius from the other sphere. + @param[in] a_other Other sphere + */ BoundingSphereT(const BoundingSphereT& a_other); /*! - @brief Template constructor which takes a set of 3D points (mixed precision - allowed). - @details This computes the bounding sphere using the supplied algorithm. - @param[in] a_points Set of 3D points - @param[in] a_alg Bounding sphere algorithm. - @note This calls the define(...) function. - */ + @brief Template constructor which takes a set of 3D points (mixed precision + allowed). + @details This computes the bounding sphere using the supplied algorithm. + @param[in] a_points Set of 3D points + @param[in] a_alg Bounding sphere algorithm. + @note This calls the define(...) function. + */ template BoundingSphereT(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_alg = BoundingVolumeAlgorithm::Ritter); /*! - @brief Destructor (does nothing). - */ + @brief Destructor (does nothing). + */ virtual ~BoundingSphereT(); /*! - @brief Copy assignment operator - @param[in] a_other Other sphere - */ + @brief Copy assignment operator + @param[in] a_other Other sphere + */ BoundingSphereT& operator=(const BoundingSphereT& a_other) = default; /*! - @brief Template define function which takes a set of 3D points (mixed - precision allowed). - @details This computes the bounding sphere using the supplied algorithm. - @param[in] a_points Set of 3D points - @param[in] a_alg Bounding sphere algorithm. - */ + @brief Template define function which takes a set of 3D points (mixed + precision allowed). + @details This computes the bounding sphere using the supplied algorithm. + @param[in] a_points Set of 3D points + @param[in] a_alg Bounding sphere algorithm. + */ template inline void define(const std::vector>& a_points, const BoundingVolumeAlgorithm& a_alg) noexcept; /*! - @brief Check if this bounding sphere intersect another bounding sphere - @param[in] a_other Other bounding sphere. - @return True if the two sphere intersect. - */ + @brief Check if this bounding sphere intersect another bounding sphere + @param[in] a_other Other bounding sphere. + @return True if the two sphere intersect. + */ inline bool intersects(const BoundingSphereT& a_other) const noexcept; /*! - @brief Get modifiable radius for this sphere - */ + @brief Get modifiable radius for this sphere + */ inline T& getRadius() noexcept; /*! - @brief Get immutable radius for this sphere - */ + @brief Get immutable radius for this sphere + */ inline const T& getRadius() const noexcept; /*! - @brief Get modifiable center for this sphere - */ + @brief Get modifiable center for this sphere + */ inline Vec3& getCentroid() noexcept; /*! - @brief Get immutable center for this sphere - */ + @brief Get immutable center for this sphere + */ inline const Vec3& getCentroid() const noexcept; /*! - @brief Compute the overlapping volume between this bounding sphere and - another - @param[in] a_other Other bounding sphere - @return The overlapping volume, computing using standard expressions. - */ + @brief Compute the overlapping volume between this bounding sphere and + another + @param[in] a_other Other bounding sphere + @return The overlapping volume, computing using standard expressions. + */ inline T getOverlappingVolume(const BoundingSphereT& a_other) const noexcept; /*! - @brief Get the distance to this bounding sphere (points inside the sphere - have a zero distance) - @param[in] a_x0 3D point - @return Returns the distance to the sphere (a point inside has a zero - distance) - */ + @brief Get the distance to this bounding sphere (points inside the sphere + have a zero distance) + @param[in] a_x0 3D point + @return Returns the distance to the sphere (a point inside has a zero + distance) + */ inline T getDistance(const Vec3& a_x0) const noexcept; /*! - @brief Get the sphere volume - @return Sphere volume - */ + @brief Get the sphere volume + @return Sphere volume + */ inline T getVolume() const noexcept; /*! - @brief Get the sphere area - @return Sphere area. - */ + @brief Get the sphere area + @return Sphere area. + */ inline T getArea() const noexcept; protected: /*! - @brief Sphere radius - */ + @brief Sphere radius + */ T m_radius; /*! - @brief Sphere center - */ + @brief Sphere center + */ Vec3 m_center; /*! - @brief Template function which computes the bounding sphere for a set of - points (mixed precision allowed) using Ritter's algorithm - */ + @brief Template function which computes the bounding sphere for a set of + points (mixed precision allowed) using Ritter's algorithm + */ template inline void buildRitter(const std::vector>& a_points) noexcept; }; /*! - @brief Axis-aligned bounding box as bounding volume - @details This class represents a Cartesian box that encloses a set of 3D - points. - @note The template parameter T is the precision. -*/ + @brief Axis-aligned bounding box as bounding volume + @details This class represents a Cartesian box that encloses a set of 3D + points. + @note The template parameter T is the precision. + */ template class AABBT { public: /*! - @brief Alias which cuts down on typing - */ + @brief Alias which cuts down on typing + */ using Vec3 = Vec3T; /*! - @brief Default constructor (does nothing) - */ + @brief Default constructor (does nothing) + */ AABBT(); /*! - @brief Full constructor taking the low/high corners of the bounding box - @param[in] a_lo Low corner - @param[in] a_hi High - */ + @brief Full constructor taking the low/high corners of the bounding box + @param[in] a_lo Low corner + @param[in] a_hi High + */ AABBT(const Vec3T& a_lo, const Vec3T& a_hi); /*! - @brief Copy constructor of another bounding box - @param[in] a_other Other bounding box - */ + @brief Copy constructor of another bounding box + @param[in] a_other Other bounding box + */ AABBT(const AABBT& a_other); /*! - @brief Constructor which creates an AABB which encloses a set of other - AABBs. - @param[in] a_others Other bounding boxes - */ + @brief Constructor which creates an AABB which encloses a set of other + AABBs. + @param[in] a_others Other bounding boxes + */ AABBT(const std::vector>& a_others); /*! - @brief Template constructor (since mixed precision allowed) which creates an - AABB that encloses a set of 3D points - @param[in] a_points Set of 3D points - @note Calls the define function - */ + @brief Template constructor (since mixed precision allowed) which creates an + AABB that encloses a set of 3D points + @param[in] a_points Set of 3D points + @note Calls the define function + */ template AABBT(const std::vector>& a_points); /*! - @brief Destructor (does nothing) - */ + @brief Destructor (does nothing) + */ virtual ~AABBT(); /*! - @brief Copy assignment - @param[in] a_other Other bounding box - */ + @brief Copy assignment + @param[in] a_other Other bounding box + */ AABBT& operator=(const AABBT& a_other) = default; /*! - @brief Define function (since mixed precision allowed) which sets this AABB - such that it encloses a set of 3D points - @param[in] a_points Set of 3D points - */ + @brief Define function (since mixed precision allowed) which sets this AABB + such that it encloses a set of 3D points + @param[in] a_points Set of 3D points + */ template inline void define(const std::vector>& a_points) noexcept; /*! - @brief Check if this AABB intersects another AABB - @param[in] a_other The other AABB - @return True if they intersect and false otherwise. - */ + @brief Check if this AABB intersects another AABB + @param[in] a_other The other AABB + @return True if they intersect and false otherwise. + */ inline bool intersects(const AABBT& a_other) const noexcept; /*! - @brief Get the modifiable lower-left corner of the AABB - */ + @brief Get the modifiable lower-left corner of the AABB + */ inline Vec3T& getLowCorner() noexcept; /*! - @brief Get the immutable lower-left corner of the AABB - */ + @brief Get the immutable lower-left corner of the AABB + */ inline const Vec3T& getLowCorner() const noexcept; /*! - @brief Get the modifiable upper-right corner of the AABB - */ + @brief Get the modifiable upper-right corner of the AABB + */ inline Vec3T& getHighCorner() noexcept; /*! - @brief Get the immutable upper-right corner of the AABB - */ + @brief Get the immutable upper-right corner of the AABB + */ inline const Vec3T& getHighCorner() const noexcept; /*! - @brief Get bounding volume centroid. - */ + @brief Get bounding volume centroid. + */ inline Vec3 getCentroid() const noexcept; /*! - @brief Compute the overlapping volume between this AABB and another AABB. - @param[in] a_other The other AABB - @return Returns overlapping volume - */ + @brief Compute the overlapping volume between this AABB and another AABB. + @param[in] a_other The other AABB + @return Returns overlapping volume + */ inline T getOverlappingVolume(const AABBT& a_other) const noexcept; /*! - @brief Get the distance to this AABB (points inside the bounding box have a - zero distance) - @param[in] a_x0 3D point - @return Returns the distance to the bounding box (a point inside has a zero - distance) - */ + @brief Get the distance to this AABB (points inside the bounding box have a + zero distance) + @param[in] a_x0 3D point + @return Returns the distance to the bounding box (a point inside has a zero + distance) + */ inline T getDistance(const Vec3& a_x0) const noexcept; /*! - @brief Compute the bounding box volume - */ + @brief Compute the bounding box volume + */ inline T getVolume() const noexcept; /*! - @brief Compute the bounding box area - */ + @brief Compute the bounding box area + */ inline T getArea() const noexcept; protected: /*! - @brief Lower-left corner of bounding box - */ + @brief Lower-left corner of bounding box + */ Vec3 m_loCorner; /*! - @brief Upper-right corner of bounding box - */ + @brief Upper-right corner of bounding box + */ Vec3 m_hiCorner; }; /*! - @brief Intersection method for testing if two bounding spheres overlap - @param[in] a_u One bounding sphere - @param[in] a_v The other bounding sphere -*/ + @brief Intersection method for testing if two bounding spheres overlap + @param[in] a_u One bounding sphere + @param[in] a_v The other bounding sphere + */ template bool intersects(const BoundingSphereT& a_u, const BoundingSphereT& a_v) noexcept; /*! - @brief Intersection method for testing if two bounding boxes overlap - @param[in] a_u One bounding box - @param[in] a_v The other bounding box -*/ + @brief Intersection method for testing if two bounding boxes overlap + @param[in] a_u One bounding box + @param[in] a_v The other bounding box + */ template bool intersects(const AABBT& a_u, const AABBT& a_v) noexcept; /*! - @brief Compute the overlapping volume between two bounding spheres - @param[in] a_u One bounding sphere - @param[in] a_v The other bounding sphere -*/ + @brief Compute the overlapping volume between two bounding spheres + @param[in] a_u One bounding sphere + @param[in] a_v The other bounding sphere + */ template T getOverlappingVolume(const BoundingSphereT& a_u, const BoundingSphereT& a_v) noexcept; /*! - @brief Compute the overlapping volume between two bounding boxes - @param[in] a_u One bounding box - @param[in] a_v The other bounding box -*/ + @brief Compute the overlapping volume between two bounding boxes + @param[in] a_u One bounding box + @param[in] a_v The other bounding box + */ template T getOverlappingVolume(const AABBT& a_u, const AABBT& a_v) noexcept; diff --git a/Source/EBGeometry_BoundingVolumesImplem.hpp b/Source/EBGeometry_BoundingVolumesImplem.hpp index b5ce0a73..5b08560f 100644 --- a/Source/EBGeometry_BoundingVolumesImplem.hpp +++ b/Source/EBGeometry_BoundingVolumesImplem.hpp @@ -302,8 +302,8 @@ namespace BoundingVolumes { const Vec3& otherHi = a_other.getHighCorner(); return (m_loCorner[0] < otherHi[0] && m_hiCorner[0] > otherLo[0]) && - (m_loCorner[1] < otherHi[1] && m_hiCorner[1] > otherLo[1]) && - (m_loCorner[2] < otherHi[2] && m_hiCorner[2] > otherLo[2]); + (m_loCorner[1] < otherHi[1] && m_hiCorner[1] > otherLo[1]) && + (m_loCorner[2] < otherHi[2] && m_hiCorner[2] > otherLo[2]); } template diff --git a/Source/EBGeometry_DCEL_BVH.hpp b/Source/EBGeometry_DCEL_BVH.hpp index 02d9e6c0..f1bcb5b2 100644 --- a/Source/EBGeometry_DCEL_BVH.hpp +++ b/Source/EBGeometry_DCEL_BVH.hpp @@ -26,19 +26,19 @@ namespace DCEL { /*! - @brief Alias for vector of primitives. -*/ + @brief Alias for vector of primitives. + */ template using PrimitiveList = std::vector>>; /*! - @brief Bounding volume constructor for a DCEL face. - @details With BVHs and DCEL, the object to be bounded is the polygon face - (e.g., triangle). We assume that our BV constructor can enclose points, so we - return an object that encloses all the vertices of the polygon. - @param[in] a_primitive Primitive (facet) to be bounded. - @return Returns a bounding volume which encloses the input face. -*/ + @brief Bounding volume constructor for a DCEL face. + @details With BVHs and DCEL, the object to be bounded is the polygon face + (e.g., triangle). We assume that our BV constructor can enclose points, so we + return an object that encloses all the vertices of the polygon. + @param[in] a_primitive Primitive (facet) to be bounded. + @return Returns a bounding volume which encloses the input face. + */ template EBGeometry::BVH::BVConstructorT, BV> defaultBVConstructor = [](const std::shared_ptr>& a_primitive) -> BV { @@ -46,15 +46,15 @@ namespace DCEL { }; /*! - @brief Default stop function. This function terminates the division process if - a BVH node has only one primitive. - @details In this function, BVH::NodeT, BVH > is a BVH node. The - interpretation of the parameters are: T is the precision, FaceT is the - primitive type in the BVH tree, and BV is the bounding volume type. - @param[in] a_node Bounding volume hierarchy node. - @return Returns true if the bounding volume shouldn't be split more and false - otherwise. -*/ + @brief Default stop function. This function terminates the division process if + a BVH node has only one primitive. + @details In this function, BVH::NodeT, BVH > is a BVH node. The + interpretation of the parameters are: T is the precision, FaceT is the + primitive type in the BVH tree, and BV is the bounding volume type. + @param[in] a_node Bounding volume hierarchy node. + @return Returns true if the bounding volume shouldn't be split more and false + otherwise. + */ template EBGeometry::BVH::StopFunctionT, BV, K> defaultStopFunction = [](const BVH::NodeT, BV, K>& a_node) -> bool { @@ -62,10 +62,10 @@ namespace DCEL { }; /*! - @brief Function which checks that all chunks are valid (i.e., contain at least - one primitive - @param[in] a_chunks Chunks. -*/ + @brief Function which checks that all chunks are valid (i.e., contain at least + one primitive + @param[in] a_chunks Chunks. + */ template auto validChunks = [](const std::array, K>& a_chunks) -> bool { for (const auto& chunk : a_chunks) { @@ -77,10 +77,10 @@ namespace DCEL { }; /*! - @brief Function for partitioning an input list into K almost-equal-sized - chunks - @param[in] a_primitives Primitives to be partitioned. -*/ + @brief Function for partitioning an input list into K almost-equal-sized + chunks + @param[in] a_primitives Primitives to be partitioned. + */ template auto equalCounts = [](const PrimitiveList& a_primitives) -> std::array, K> { int length = a_primitives.size() / K; @@ -104,13 +104,13 @@ namespace DCEL { }; /*! - @brief Partitioner function for subdividing into K sub-volumes with - approximately the same number of primitives. - @details This partitioner splits along one of the axis coordinates and sorts - the primitives along the centroid. - @param[in] a_primitives List of primitives to partition into sub-bounding - volumes -*/ + @brief Partitioner function for subdividing into K sub-volumes with + approximately the same number of primitives. + @details This partitioner splits along one of the axis coordinates and sorts + the primitives along the centroid. + @param[in] a_primitives List of primitives to partition into sub-bounding + volumes + */ template EBGeometry::BVH::PartitionerT, BV, K> chunkPartitioner = [](const PrimitiveList& a_primitives) -> std::array, K> { @@ -136,13 +136,13 @@ namespace DCEL { }; /*! - @brief Partitioner function for subdividing into K sub-volumes with - approximately the same number of primitives. - @details Basically the same as chunkPartitioner, except that the centroids are - based on the bounding volumes' centroids. - @param[in] a_primitives List of primitives to partition into sub-bounding - volumes -*/ + @brief Partitioner function for subdividing into K sub-volumes with + approximately the same number of primitives. + @details Basically the same as chunkPartitioner, except that the centroids are + based on the bounding volumes' centroids. + @param[in] a_primitives List of primitives to partition into sub-bounding + volumes + */ template EBGeometry::BVH::PartitionerT, BV, K> bvPartitioner = [](const PrimitiveList& a_primitives) -> std::array, K> { @@ -167,8 +167,8 @@ namespace DCEL { // Sort the primitives based on the centroid location of their BVs. std::sort(primsAndBVs.begin(), primsAndBVs.end(), [splitDir](const P& p1, const P& p2) { - return (p1.second).getCentroid()[splitDir] < (p2.second).getCentroid()[splitDir]; - }); + return (p1.second).getCentroid()[splitDir] < (p2.second).getCentroid()[splitDir]; + }); // Unpack the vector and partition into equal counts. PrimitiveList sortedPrimitives; @@ -182,11 +182,11 @@ namespace DCEL { }; /*! - @brief Partitioner function for subdividing into K sub-volumes, partitioning - on the primitive centroid midpoint(s). - @param[in] a_primitives List of primitives to partition into sub-bounding - volumes -*/ + @brief Partitioner function for subdividing into K sub-volumes, partitioning + on the primitive centroid midpoint(s). + @param[in] a_primitives List of primitives to partition into sub-bounding + volumes + */ template EBGeometry::BVH::PartitionerT, BV, K> centroidPartitioner = [](const PrimitiveList& a_primitives) -> std::array, K> { @@ -237,8 +237,8 @@ namespace DCEL { }; /*! - @brief Alias for default partitioner. -*/ + @brief Alias for default partitioner. + */ template EBGeometry::BVH::PartitionerT, BV, K> defaultPartitioner = EBGeometry::DCEL::chunkPartitioner; diff --git a/Source/EBGeometry_DCEL_Edge.hpp b/Source/EBGeometry_DCEL_Edge.hpp index 59fdfd1d..47687448 100644 --- a/Source/EBGeometry_DCEL_Edge.hpp +++ b/Source/EBGeometry_DCEL_Edge.hpp @@ -35,101 +35,101 @@ namespace DCEL { class EdgeIteratorT; /*! - @brief Class which represents a half-edge in a double-edge connected list - (DCEL). - @details This class is used in DCEL functionality which stores polygonal - surfaces in a mesh. The information contain in an EdgeT object contains the - necessary object for logically circulating the inside of a polygon face. This - means that a polygon face has a double-connected list of half-edges which - circulate the interior of the face. The EdgeT object is such a half-edge; it - represents the outgoing half-edge from a vertex, located such that it can be - logically represented as a half edge on the "inside" of a polygon face. It - contains pointers to the polygon face, next half edge, and the previous half - edge. It also contains a pointer to the "pair" half edge, i.e. the - corresponding half-edge on the other face that shares this edge. Since this - class is used with DCEL functionality and signed distance fields, this class - also has a signed distance function and thus a "normal vector". For numericaly - efficiency, some extra storage is also allocated (such as the vector between - the starting vertex and the end vertex). - @note The normal vector is outgoing, i.e. a point x is "outside" if the dot - product between n and (x - x0) is positive. -*/ + @brief Class which represents a half-edge in a double-edge connected list + (DCEL). + @details This class is used in DCEL functionality which stores polygonal + surfaces in a mesh. The information contain in an EdgeT object contains the + necessary object for logically circulating the inside of a polygon face. This + means that a polygon face has a double-connected list of half-edges which + circulate the interior of the face. The EdgeT object is such a half-edge; it + represents the outgoing half-edge from a vertex, located such that it can be + logically represented as a half edge on the "inside" of a polygon face. It + contains pointers to the polygon face, next half edge, and the previous half + edge. It also contains a pointer to the "pair" half edge, i.e. the + corresponding half-edge on the other face that shares this edge. Since this + class is used with DCEL functionality and signed distance fields, this class + also has a signed distance function and thus a "normal vector". For numericaly + efficiency, some extra storage is also allocated (such as the vector between + the starting vertex and the end vertex). + @note The normal vector is outgoing, i.e. a point x is "outside" if the dot + product between n and (x - x0) is positive. + */ template class EdgeT { public: /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vec3 = Vec3T; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vertex = VertexT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Edge = EdgeT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Face = FaceT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using VertexPtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using EdgePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using FacePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using EdgeIterator = EdgeIteratorT; /*! - @brief Default constructor. Sets all pointers to zero and vectors to zero - vectors - */ + @brief Default constructor. Sets all pointers to zero and vectors to zero + vectors + */ EdgeT(); /*! - @brief Copy constructor. Copies all information from the other half-edge. - @param[in] a_otherEdge Other edge - */ + @brief Copy constructor. Copies all information from the other half-edge. + @param[in] a_otherEdge Other edge + */ EdgeT(const Edge& a_otherEdge); /*! - @brief Partial constructor. Calls the default constructor but sets the - starting vertex. - @param[in] a_vertex Starting vertex. - */ + @brief Partial constructor. Calls the default constructor but sets the + starting vertex. + @param[in] a_vertex Starting vertex. + */ EdgeT(const VertexPtr& a_vertex); /*! - @brief Destructor (does nothing) - */ + @brief Destructor (does nothing) + */ ~EdgeT(); /*! - @brief Define function. Sets the starting vertex, edges, and normal vectors - @param[in] a_vertex Starting vertex - @param[in] a_pairEdge Pair half-edge - @param[in] a_nextEdge Next half-edge - @param[in] a_previousEdge Previous half-edge - @param[in] a_normal Edge normal vector - */ + @brief Define function. Sets the starting vertex, edges, and normal vectors + @param[in] a_vertex Starting vertex + @param[in] a_pairEdge Pair half-edge + @param[in] a_nextEdge Next half-edge + @param[in] a_previousEdge Previous half-edge + @param[in] a_normal Edge normal vector + */ inline void define(const VertexPtr& a_vertex, const EdgePtr& a_pairEdge, @@ -138,230 +138,230 @@ namespace DCEL { const Vec3 a_normal) noexcept; /*! - @brief Set the starting vertex - @param[in] a_vertex Starting vertex - */ + @brief Set the starting vertex + @param[in] a_vertex Starting vertex + */ inline void setVertex(const VertexPtr& a_vertex) noexcept; /*! - @brief Set the pair edge - @param[in] a_pairEdge Pair edge - */ + @brief Set the pair edge + @param[in] a_pairEdge Pair edge + */ inline void setPairEdge(const EdgePtr& a_pairEdge) noexcept; /*! - @brief Set the next edge - @param[in] a_nextEdge Next edge - */ + @brief Set the next edge + @param[in] a_nextEdge Next edge + */ inline void setNextEdge(const EdgePtr& a_nextEdge) noexcept; /*! - @brief Set the previous edge - @param[in] a_previousEdge Previous edge - */ + @brief Set the previous edge + @param[in] a_previousEdge Previous edge + */ inline void setPreviousEdge(const EdgePtr& a_previousEdge) noexcept; /*! - @brief Set the pointer to this half-edge's face. - */ + @brief Set the pointer to this half-edge's face. + */ inline void setFace(const FacePtr& a_face) noexcept; /*! - @brief Compute edge normal and edge length (for performance reasons) - */ + @brief Compute edge normal and edge length (for performance reasons) + */ inline void reconcile() noexcept; /*! - @brief Get modifiable starting vertex - @return Returns m_vertex - */ + @brief Get modifiable starting vertex + @return Returns m_vertex + */ inline VertexPtr& getVertex() noexcept; /*! - @brief Get immutable starting vertex - @return Returns m_vertex - */ + @brief Get immutable starting vertex + @return Returns m_vertex + */ inline const VertexPtr& getVertex() const noexcept; /*! - @brief Get modifiable end vertex - @return Returns the next half-edge's starting vertex - */ + @brief Get modifiable end vertex + @return Returns the next half-edge's starting vertex + */ inline VertexPtr& getOtherVertex() noexcept; /*! - @brief Get immutable end vertex - @return Returns the next half-edge's starting vertex - */ + @brief Get immutable end vertex + @return Returns the next half-edge's starting vertex + */ inline const VertexPtr& getOtherVertex() const noexcept; /*! - @brief Get modifiable pair edge - @return Returns the pair edge - */ + @brief Get modifiable pair edge + @return Returns the pair edge + */ inline EdgePtr& getPairEdge() noexcept; /*! - @brief Get immutable pair edge - @return Returns the pair edge - */ + @brief Get immutable pair edge + @return Returns the pair edge + */ inline const EdgePtr& getPairEdge() const noexcept; /*! - @brief Get modifiable previous edge - @return Returns the previous edge - */ + @brief Get modifiable previous edge + @return Returns the previous edge + */ inline EdgePtr& getPreviousEdge() noexcept; /*! - @brief Get immutable previous edge - @return Returns the previous edge - */ + @brief Get immutable previous edge + @return Returns the previous edge + */ inline const EdgePtr& getPreviousEdge() const noexcept; /*! - @brief Get modifiable next edge - @return Returns the next edge - */ + @brief Get modifiable next edge + @return Returns the next edge + */ inline EdgePtr& getNextEdge() noexcept; /*! - @brief Get immutable next edge - @return Returns the next edge - */ + @brief Get immutable next edge + @return Returns the next edge + */ inline const EdgePtr& getNextEdge() const noexcept; /*! - @brief Get modifiable half-edge normal vector - */ + @brief Get modifiable half-edge normal vector + */ inline Vec3T& getNormal() noexcept; /*! - @brief Get immutable half-edge normal vector - */ + @brief Get immutable half-edge normal vector + */ inline const Vec3T& getNormal() const noexcept; /*! - @brief Get modifiable half-edge face - */ + @brief Get modifiable half-edge face + */ inline FacePtr& getFace() noexcept; /*! - @brief Get immutable half-edge face - */ + @brief Get immutable half-edge face + */ inline const FacePtr& getFace() const noexcept; /*! - @brief Get the signed distance to this half edge - @details This routine will check if the input point projects to the edge or - one of the vertices. If it projectes to one of the vertices we compute the - signed distance to the corresponding vertex. Otherwise we compute the - projection to the edge and compute the sign from the normal vector. - */ + @brief Get the signed distance to this half edge + @details This routine will check if the input point projects to the edge or + one of the vertices. If it projectes to one of the vertices we compute the + signed distance to the corresponding vertex. Otherwise we compute the + projection to the edge and compute the sign from the normal vector. + */ inline T signedDistance(const Vec3& a_x0) const noexcept; /*! - @brief Get the signed distance to this half edge - @details This routine will check if the input point projects to the edge or - one of the vertices. If it projectes to one of the vertices we compute the - squared distance to the corresponding vertex. Otherwise we compute the - squared distance of the projection to the edge. This is faster than - signedDistance() - */ + @brief Get the signed distance to this half edge + @details This routine will check if the input point projects to the edge or + one of the vertices. If it projectes to one of the vertices we compute the + squared distance to the corresponding vertex. Otherwise we compute the + squared distance of the projection to the edge. This is faster than + signedDistance() + */ inline T unsignedDistance2(const Vec3& a_x0) const noexcept; protected: /*! - @brief Half-edge normal vector - @details Computed in computeNormal which sets the normal vector to be the - average of the normal vector of the connected faces - */ + @brief Half-edge normal vector + @details Computed in computeNormal which sets the normal vector to be the + average of the normal vector of the connected faces + */ Vec3 m_normal; /*! - @brief Vector from the starting vertex to the end vertex. Exists for - performance reasons. - */ + @brief Vector from the starting vertex to the end vertex. Exists for + performance reasons. + */ Vec3 m_x2x1; /*! - @brief Squared inverse edge length. Exists for performance reasons. - */ + @brief Squared inverse edge length. Exists for performance reasons. + */ T m_invLen2; /*! - @brief Starting vertex - */ + @brief Starting vertex + */ VertexPtr m_vertex; /*! - @brief Pair edge - */ + @brief Pair edge + */ EdgePtr m_pairEdge; /*! - @brief Previous edge - */ + @brief Previous edge + */ EdgePtr m_previousEdge; /*! - @brief Next edge - */ + @brief Next edge + */ EdgePtr m_nextEdge; /*! - @brief Enclosing polygon face - */ + @brief Enclosing polygon face + */ FacePtr m_face; /*! - @brief Returns the "projection" of a point to an edge. - @details This function parametrizes the edge as x(t) = x0 + (x1-x0)*t and - returns where on the this edge the point a_x0 projects. If projects onto the - edge if t = [0,1] and to one of the start/end vertices otherwise. - */ + @brief Returns the "projection" of a point to an edge. + @details This function parametrizes the edge as x(t) = x0 + (x1-x0)*t and + returns where on the this edge the point a_x0 projects. If projects onto the + edge if t = [0,1] and to one of the start/end vertices otherwise. + */ inline T projectPointToEdge(const Vec3& a_x0) const noexcept; /*! - @brief Normalize the normal vector, ensuring it has length 1 - */ + @brief Normalize the normal vector, ensuring it has length 1 + */ inline void normalizeNormalVector() noexcept; /*! - @brief Compute the edge length. - @details This computes the vector m_x2x1 (vector from starting vertex to end - vertex) and the inverse length squared. - */ + @brief Compute the edge length. + @details This computes the vector m_x2x1 (vector from starting vertex to end + vertex) and the inverse length squared. + */ inline void computeEdgeLength() noexcept; /*! - @brief Compute normal vector as average of face normals - */ + @brief Compute normal vector as average of face normals + */ inline void computeNormal() noexcept; }; diff --git a/Source/EBGeometry_DCEL_Face.hpp b/Source/EBGeometry_DCEL_Face.hpp index ec179990..6c910045 100644 --- a/Source/EBGeometry_DCEL_Face.hpp +++ b/Source/EBGeometry_DCEL_Face.hpp @@ -37,324 +37,324 @@ namespace DCEL { class EdgeIteratorT; /*! - @brief Class which represents a polygon face in a double-edge connected list - (DCEL). - @details This class is a polygon face in a DCEL mesh. It contains pointer - storage to one of the half-edges that circulate the inside of the polygon - face, as well as having a normal vector, a centroid, and an area. This class - supports signed distance computations. These computations require algorithms - that compute e.g. the winding number of the polygon, or the number of times a - ray cast passes through it. Thus, one of its central features is that it can - be embedded in 2D by projecting it along the cardinal direction of its normal - vector. To be fully consistent with a DCEL structure the class stores a - reference to one of its half edges, but for performance reasons it also stores - references to the other half edges. - @note To compute the distance from a point to the face one must determine if - the point projects "inside" or "outside" the polygon. There are several - algorithms for this, and by default this class uses a crossing number - algorithm. Other algorithms can be set in setInsideOutsideAlgorithm (see - CD_DCELAlgorithms.H) -*/ + @brief Class which represents a polygon face in a double-edge connected list + (DCEL). + @details This class is a polygon face in a DCEL mesh. It contains pointer + storage to one of the half-edges that circulate the inside of the polygon + face, as well as having a normal vector, a centroid, and an area. This class + supports signed distance computations. These computations require algorithms + that compute e.g. the winding number of the polygon, or the number of times a + ray cast passes through it. Thus, one of its central features is that it can + be embedded in 2D by projecting it along the cardinal direction of its normal + vector. To be fully consistent with a DCEL structure the class stores a + reference to one of its half edges, but for performance reasons it also stores + references to the other half edges. + @note To compute the distance from a point to the face one must determine if + the point projects "inside" or "outside" the polygon. There are several + algorithms for this, and by default this class uses a crossing number + algorithm. Other algorithms can be set in setInsideOutsideAlgorithm (see + CD_DCELAlgorithms.H) + */ template class FaceT { public: /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vec3 = Vec3T; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vertex = VertexT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Edge = EdgeT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Face = FaceT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using VertexPtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using EdgePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using FacePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using EdgeIterator = EdgeIteratorT; /*! - @brief Default constructor. Sets the half-edge to zero and the - inside/outside algorithm to crossing number algorithm - */ + @brief Default constructor. Sets the half-edge to zero and the + inside/outside algorithm to crossing number algorithm + */ FaceT(); /*! - @brief Partial constructor. Calls default constructor but associates a - half-edge - @param[in] a_edge Half-edge - */ + @brief Partial constructor. Calls default constructor but associates a + half-edge + @param[in] a_edge Half-edge + */ FaceT(const EdgePtr& a_edge); /*! - @brief Partial constructor. - @details Calls default constructor but sets the normal vector and half-edge - equal to the other face's (rest is undefined) - */ + @brief Partial constructor. + @details Calls default constructor but sets the normal vector and half-edge + equal to the other face's (rest is undefined) + */ FaceT(const Face& a_otherFace); /*! - @brief Destructor (does nothing) - */ + @brief Destructor (does nothing) + */ ~FaceT(); /*! - @brief Define function which sets the normal vector and half-edge - @param[in] a_normal Normal vector - @param[in] a_edge Half edge - */ + @brief Define function which sets the normal vector and half-edge + @param[in] a_normal Normal vector + @param[in] a_edge Half edge + */ inline void define(const Vec3& a_normal, const EdgePtr& a_edge) noexcept; /*! - @brief Reconcile face. This will compute the normal vector, area, centroid, - and the 2D embedding of the polygon - @note "Everything" must be set before doing this, i.e. the face must be - complete with half edges and there can be no dangling edges. - */ + @brief Reconcile face. This will compute the normal vector, area, centroid, + and the 2D embedding of the polygon + @note "Everything" must be set before doing this, i.e. the face must be + complete with half edges and there can be no dangling edges. + */ inline void reconcile() noexcept; /*! - @brief Set the half edge - @param[in] a_halfEdge Half edge - */ + @brief Set the half edge + @param[in] a_halfEdge Half edge + */ inline void setHalfEdge(const EdgePtr& a_halfEdge) noexcept; /*! - @brief Set the inside/outside algorithm when determining if a point projects - to the inside or outside of the polygon. - @param[in] a_algorithm Desired algorithm - @note See CD_DCELAlgorithms.H for options (and CD_DCELPolyImplem.H for how - the algorithms operate). - */ + @brief Set the inside/outside algorithm when determining if a point projects + to the inside or outside of the polygon. + @param[in] a_algorithm Desired algorithm + @note See CD_DCELAlgorithms.H for options (and CD_DCELPolyImplem.H for how + the algorithms operate). + */ inline void setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm& a_algorithm) noexcept; /*! - @brief Get modifiable half-edge - */ + @brief Get modifiable half-edge + */ inline EdgePtr& getHalfEdge() noexcept; /*! - @brief Get immutable half-edge - */ + @brief Get immutable half-edge + */ inline const EdgePtr& getHalfEdge() const noexcept; /*! - @brief Get modifiable centroid - */ + @brief Get modifiable centroid + */ inline Vec3T& getCentroid() noexcept; /*! - @brief Get immutable centroid - */ + @brief Get immutable centroid + */ inline const Vec3T& getCentroid() const noexcept; /*! - @brief Get modifiable centroid position in specified coordinate direction - @param[in] a_dir Coordinate direction - */ + @brief Get modifiable centroid position in specified coordinate direction + @param[in] a_dir Coordinate direction + */ inline T& getCentroid(const size_t a_dir) noexcept; /*! - @brief Get immutable centroid position in specified coordinate direction - @param[in] a_dir Coordinate direction - */ + @brief Get immutable centroid position in specified coordinate direction + @param[in] a_dir Coordinate direction + */ inline const T& getCentroid(const size_t a_dir) const noexcept; /*! - @brief Get modifiable normal vector - */ + @brief Get modifiable normal vector + */ inline Vec3T& getNormal() noexcept; /*! - @brief Get immutable normal vector - */ + @brief Get immutable normal vector + */ inline const Vec3T& getNormal() const noexcept; /*! - @brief Compute the signed distance to a point. - @param[in] a_x0 Point in space - @details This algorithm operates by checking if the input point projects to - the inside of the polygon. If it does then the distance is just the - projected distance onto the polygon plane and the sign is well-defined. - Otherwise, we check the distance to the edges of the polygon. - */ + @brief Compute the signed distance to a point. + @param[in] a_x0 Point in space + @details This algorithm operates by checking if the input point projects to + the inside of the polygon. If it does then the distance is just the + projected distance onto the polygon plane and the sign is well-defined. + Otherwise, we check the distance to the edges of the polygon. + */ inline T signedDistance(const Vec3& a_x0) const noexcept; /*! - @brief Compute the unsigned squared distance to a point. - @param[in] a_x0 Point in space - @details This algorithm operates by checking if the input point projects to - the inside of the polygon. If it does then the distance is just the - projected distance onto the polygon plane. Otherwise, we check the distance - to the edges of the polygon. - */ + @brief Compute the unsigned squared distance to a point. + @param[in] a_x0 Point in space + @details This algorithm operates by checking if the input point projects to + the inside of the polygon. If it does then the distance is just the + projected distance onto the polygon plane. Otherwise, we check the distance + to the edges of the polygon. + */ inline T unsignedDistance2(const Vec3& a_x0) const noexcept; /*! - @brief Return the coordinates of all the vertices on this polygon. - @details This builds a list of all the vertex coordinates and returns it. - */ + @brief Return the coordinates of all the vertices on this polygon. + @details This builds a list of all the vertex coordinates and returns it. + */ inline std::vector> getAllVertexCoordinates() const noexcept; /*! - @brief Return all the vertices on this polygon - @details This builds a list of all the vertices and returns it. - */ + @brief Return all the vertices on this polygon + @details This builds a list of all the vertices and returns it. + */ inline std::vector gatherVertices() const noexcept; /*! - @brief Get the lower-left-most coordinate of this polygon face - */ + @brief Get the lower-left-most coordinate of this polygon face + */ inline Vec3T getSmallestCoordinate() const noexcept; /*! - @brief Get the upper-right-most coordinate of this polygon face - */ + @brief Get the upper-right-most coordinate of this polygon face + */ inline Vec3T getHighestCoordinate() const noexcept; protected: /*! - @brief This polygon's half-edge. A valid face will always have != nullptr - */ + @brief This polygon's half-edge. A valid face will always have != nullptr + */ EdgePtr m_halfEdge; /*! - @brief Pointers to all the half-edges of this face. Exists for performance - reasons (in signedDistance(...)) - */ + @brief Pointers to all the half-edges of this face. Exists for performance + reasons (in signedDistance(...)) + */ std::vector m_edges; // Exists because of performance reasons. /*! - @brief Polygon face area - */ + @brief Polygon face area + */ T m_area; /*! - @brief Polygon face normal vector - */ + @brief Polygon face normal vector + */ Vec3 m_normal; /*! - @brief Polygon face centroid position - */ + @brief Polygon face centroid position + */ Vec3 m_centroid; /*! - @brief 2D embedding of this polygon. This is the 2D view of the current - object projected along its normal vector cardinal. - */ + @brief 2D embedding of this polygon. This is the 2D view of the current + object projected along its normal vector cardinal. + */ std::shared_ptr> m_poly2; /*! - @brief Algorithm for inside/outside tests - */ + @brief Algorithm for inside/outside tests + */ typename Polygon2D::InsideOutsideAlgorithm m_poly2Algorithm; /*! - @brief Compute the area of this polygon - */ + @brief Compute the area of this polygon + */ inline void computeArea() noexcept; /*! - @brief Compute the centroid position of this polygon - */ + @brief Compute the centroid position of this polygon + */ inline void computeCentroid() noexcept; /*! - @brief Compute the normal position of this polygon - */ + @brief Compute the normal position of this polygon + */ inline void computeNormal() noexcept; /*! - @brief Compute the 2D embedding of this polygon - */ + @brief Compute the 2D embedding of this polygon + */ inline void computePolygon2D() noexcept; /*! - @brief Normalize the normal vector, ensuring it has a length of 1 - */ + @brief Normalize the normal vector, ensuring it has a length of 1 + */ inline void normalizeNormalVector() noexcept; /*! - @brief Get the area of this polygon face - */ + @brief Get the area of this polygon face + */ inline T getArea() noexcept; /*! - @brief Get the area of this polygon face - */ + @brief Get the area of this polygon face + */ inline T getArea() const noexcept; /*! - @brief Compute and store all the half-edges around this polygon face - */ + @brief Compute and store all the half-edges around this polygon face + */ inline void computeAndStoreEdges() noexcept; /*! - @brief Compute the projection of a point onto the polygon face plane - @param[in] a_p Point in space - */ + @brief Compute the projection of a point onto the polygon face plane + @param[in] a_p Point in space + */ inline Vec3T projectPointIntoFacePlane(const Vec3& a_p) const noexcept; /*! - @brief Check if a point projects to inside or outside the polygon face - @param[in] a_p Point in space - @return Returns true if a_p projects to inside the polygon and false - otherwise. - */ + @brief Check if a point projects to inside or outside the polygon face + @param[in] a_p Point in space + @return Returns true if a_p projects to inside the polygon and false + otherwise. + */ inline bool isPointInsideFace(const Vec3& a_p) const noexcept; }; diff --git a/Source/EBGeometry_DCEL_Iterator.hpp b/Source/EBGeometry_DCEL_Iterator.hpp index 8818d617..67183f95 100644 --- a/Source/EBGeometry_DCEL_Iterator.hpp +++ b/Source/EBGeometry_DCEL_Iterator.hpp @@ -29,149 +29,149 @@ namespace DCEL { class FaceT; /*! - @brief Class which can iterate through edges and vertices around a DCEL - polygon face. - @details This class can be used so that it either visits all the half-edges in - a face, or all the outgoing half-edges from a vertex. -*/ + @brief Class which can iterate through edges and vertices around a DCEL + polygon face. + @details This class can be used so that it either visits all the half-edges in + a face, or all the outgoing half-edges from a vertex. + */ template class EdgeIteratorT { public: /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vertex = VertexT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Edge = EdgeT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Face = FaceT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using VertexPtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using EdgePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using FacePtr = std::shared_ptr; /*! - @brief Default construction is not allowed. Use one of the full constructors - */ + @brief Default construction is not allowed. Use one of the full constructors + */ EdgeIteratorT() = delete; /*! - @brief Constructor, taking a face as argument. The iterator begins at the - half-edge pointer contained in the face - @param[in] a_face DCEL polygon face - @note This constructor will will iterate through the half-edges in the - polygon face. - */ + @brief Constructor, taking a face as argument. The iterator begins at the + half-edge pointer contained in the face + @param[in] a_face DCEL polygon face + @note This constructor will will iterate through the half-edges in the + polygon face. + */ EdgeIteratorT(Face& a_face); /*! - @brief Constructor, taking a face as argument. The iterator begins at the - half-edge pointer contained in the face - @param[in] a_face DCEL polygon face - @note This constructor will will iterate through the half-edges in the - polygon face. - */ + @brief Constructor, taking a face as argument. The iterator begins at the + half-edge pointer contained in the face + @param[in] a_face DCEL polygon face + @note This constructor will will iterate through the half-edges in the + polygon face. + */ EdgeIteratorT(const Face& a_face); /*! - @brief Constructor, taking a vertex as argument. The iterator begins at the - outgoing half-edge from the vertex - @param[in] a_vertex DCEL vertex - @note This constructor will will iterate through the outgoing half-edges - from a vertex. - */ + @brief Constructor, taking a vertex as argument. The iterator begins at the + outgoing half-edge from the vertex + @param[in] a_vertex DCEL vertex + @note This constructor will will iterate through the outgoing half-edges + from a vertex. + */ EdgeIteratorT(Vertex& a_vertex); /*! - @brief Constructor, taking a vertex as argument. The iterator begins at the - outgoing half-edge from the vertex - @param[in] a_vertex DCEL vertex - @note This constructor will will iterate through the outgoing half-edges - from a vertex. - */ + @brief Constructor, taking a vertex as argument. The iterator begins at the + outgoing half-edge from the vertex + @param[in] a_vertex DCEL vertex + @note This constructor will will iterate through the outgoing half-edges + from a vertex. + */ EdgeIteratorT(const Vertex& a_vertex); /*! - @brief Operator returning a pointer to the current half-edge - */ + @brief Operator returning a pointer to the current half-edge + */ inline EdgePtr& operator()() noexcept; /*! - @brief Operator returning a pointer to the current half-edge - */ + @brief Operator returning a pointer to the current half-edge + */ inline const EdgePtr& operator()() const noexcept; /*! - @brief Reset function for the iterator. This resets the iterator so that it - begins from the starting half-edge - */ + @brief Reset function for the iterator. This resets the iterator so that it + begins from the starting half-edge + */ inline void reset() noexcept; /*! - @brief Incrementation operator, bringing the iterator to the next half-edge - */ + @brief Incrementation operator, bringing the iterator to the next half-edge + */ inline void operator++() noexcept; /*! - @brief Function which checks if the iteration can be continued. - @return Returns true unless the current half-edge is a nullptr (i.e., a - broken polygon face) OR a full loop has been made around the polygon face - (i.e. all half-edges have been visited) - */ + @brief Function which checks if the iteration can be continued. + @return Returns true unless the current half-edge is a nullptr (i.e., a + broken polygon face) OR a full loop has been made around the polygon face + (i.e. all half-edges have been visited) + */ inline bool ok() const noexcept; protected: /*! - @brief Iteration mode, used to distinguish between the two constructors - (face- or vertex-based iteration) - */ + @brief Iteration mode, used to distinguish between the two constructors + (face- or vertex-based iteration) + */ enum class IterationMode - { - Vertices, - Faces - }; + { + Vertices, + Faces + }; /*! - @brief If true, a full loop has been made around the polygon face - */ + @brief If true, a full loop has been made around the polygon face + */ bool m_fullLoop; /*! - @brief Iteration mode. Set in constructor - */ + @brief Iteration mode. Set in constructor + */ IterationMode m_iterMode; /*! - @brief Starting half-edge - */ + @brief Starting half-edge + */ std::shared_ptr m_startEdge; /*! - @brief Current half-edge - */ + @brief Current half-edge + */ std::shared_ptr m_curEdge; }; } // namespace DCEL diff --git a/Source/EBGeometry_DCEL_IteratorImplem.hpp b/Source/EBGeometry_DCEL_IteratorImplem.hpp index b1b8cb89..389fc60e 100644 --- a/Source/EBGeometry_DCEL_IteratorImplem.hpp +++ b/Source/EBGeometry_DCEL_IteratorImplem.hpp @@ -97,7 +97,7 @@ namespace DCEL { } default: { std::cerr << "In file 'EBGeometry_DCEL_IteratorImplem.hpp function " - "EdgeIteratorT::operator++ - logic bust\n"; + "EdgeIteratorT::operator++ - logic bust\n"; } } diff --git a/Source/EBGeometry_DCEL_Mesh.hpp b/Source/EBGeometry_DCEL_Mesh.hpp index f9b92f3b..8fde1fba 100644 --- a/Source/EBGeometry_DCEL_Mesh.hpp +++ b/Source/EBGeometry_DCEL_Mesh.hpp @@ -37,320 +37,320 @@ namespace DCEL { class FaceT; /*! - @brief Mesh class which stores a full DCEL mesh (with signed distance - functions) - @details This encapsulates a full DCEL mesh, and also includes DIRECT signed - distance functions. The mesh consists of a set of vertices, half-edges, and - polygon faces who each have references to other vertices, half-edges, and - polygon faces. The signed distance functions DIRECT, which means that they go - through ALL of the polygon faces and compute the signed distance to them. This - is extremely inefficient, which is why this class is almost always embedded - into a bounding volume hierarchy. - @note This class is not for the light of heart -- it will almost always be - instantiated through a file parser which reads vertices and edges from file - and builds the mesh from that. Do not try to build a MeshT object yourself, - use file parsers! -*/ + @brief Mesh class which stores a full DCEL mesh (with signed distance + functions) + @details This encapsulates a full DCEL mesh, and also includes DIRECT signed + distance functions. The mesh consists of a set of vertices, half-edges, and + polygon faces who each have references to other vertices, half-edges, and + polygon faces. The signed distance functions DIRECT, which means that they go + through ALL of the polygon faces and compute the signed distance to them. This + is extremely inefficient, which is why this class is almost always embedded + into a bounding volume hierarchy. + @note This class is not for the light of heart -- it will almost always be + instantiated through a file parser which reads vertices and edges from file + and builds the mesh from that. Do not try to build a MeshT object yourself, + use file parsers! + */ template class MeshT : public SignedDistanceFunction { public: /*! - @brief Possible search algorithms for DCEL::MeshT - @details Direct means compute the signed distance for all primitives, - Direct2 means compute the squared signed distance for all primitives. - */ + @brief Possible search algorithms for DCEL::MeshT + @details Direct means compute the signed distance for all primitives, + Direct2 means compute the squared signed distance for all primitives. + */ enum class SearchAlgorithm - { - Direct, - Direct2, - }; + { + Direct, + Direct2, + }; /*! - @brief How to weight vertex normal - */ + @brief How to weight vertex normal + */ enum class VertexNormalWeight - { - None, - Angle, - }; + { + None, + Angle, + }; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using Vec3 = Vec3T; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using Vertex = VertexT; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using Edge = EdgeT; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using Face = FaceT; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using VertexPtr = std::shared_ptr; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using EdgePtr = std::shared_ptr; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using FacePtr = std::shared_ptr; /*! - @brief Alias to cut down on the typing - */ + @brief Alias to cut down on the typing + */ using Mesh = MeshT; /*! - @brief Default constructor. Leaves unobject in an unusable state - */ + @brief Default constructor. Leaves unobject in an unusable state + */ MeshT(); /*! - @brief Disallowed copy construction - @param[in] a_otherMesh Other mesh - */ + @brief Disallowed copy construction + @param[in] a_otherMesh Other mesh + */ MeshT(const Mesh& a_otherMesh) = delete; /*! - @brief Full constructor. This provides the faces, edges, and vertices to the - mesh. - @details Calls define(a_faces, a_edges, a_vertices) - @param[in] a_faces Polygon faces - @param[in] a_edges Half-edges - @param[in] a_vertices Vertices - @note The constructor arguments should provide a complete DCEL mesh - description. This is usually done through a file parser which reads a mesh - file format and creates the DCEL mesh structure - */ + @brief Full constructor. This provides the faces, edges, and vertices to the + mesh. + @details Calls define(a_faces, a_edges, a_vertices) + @param[in] a_faces Polygon faces + @param[in] a_edges Half-edges + @param[in] a_vertices Vertices + @note The constructor arguments should provide a complete DCEL mesh + description. This is usually done through a file parser which reads a mesh + file format and creates the DCEL mesh structure + */ MeshT(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices); /*! - @brief Destructor (does nothing) - */ + @brief Destructor (does nothing) + */ ~MeshT(); /*! - @brief Define function. Puts Mesh in usable state. - @param[in] a_faces Polygon faces - @param[in] a_edges Half-edges - @param[in] a_vertices Vertices - @note The function arguments should provide a complete DCEL mesh - description. This is usually done through a file parser which reads a mesh - file format and creates the DCEL mesh structure. Note that this only - involves associating pointer structures through the mesh. Internal - parameters like face area and normal is computed in MeshT::reconcile. - */ + @brief Define function. Puts Mesh in usable state. + @param[in] a_faces Polygon faces + @param[in] a_edges Half-edges + @param[in] a_vertices Vertices + @note The function arguments should provide a complete DCEL mesh + description. This is usually done through a file parser which reads a mesh + file format and creates the DCEL mesh structure. Note that this only + involves associating pointer structures through the mesh. Internal + parameters like face area and normal is computed in MeshT::reconcile. + */ inline void define(std::vector& a_faces, std::vector& a_edges, std::vector& a_vertices) noexcept; /*! - @brief Perform a sanity check. - @details This will provide error messages if vertices are badly linked, - faces are nullptr, and so on. These messages are logged by calling - incrementWarning() which identifies types of errors that can occur, and how - many of those errors have occurred. - */ + @brief Perform a sanity check. + @details This will provide error messages if vertices are badly linked, + faces are nullptr, and so on. These messages are logged by calling + incrementWarning() which identifies types of errors that can occur, and how + many of those errors have occurred. + */ inline void sanityCheck() const noexcept; /*! - @brief Search algorithm for direct signed distance computations - @param[in] a_algorithm Algorithm to use - */ + @brief Search algorithm for direct signed distance computations + @param[in] a_algorithm Algorithm to use + */ inline void setSearchAlgorithm(const SearchAlgorithm a_algorithm) noexcept; /*! - @brief Set the inside/outside algorithm to use when computing the signed - distance to polygon faces. - @details Computing the signed distance to faces requires testing if a point - projected to a polygo face plane falls inside or outside the polygon face. - There are multiple algorithms to use here. - @param[in] a_algorithm Algorithm to use - */ + @brief Set the inside/outside algorithm to use when computing the signed + distance to polygon faces. + @details Computing the signed distance to faces requires testing if a point + projected to a polygo face plane falls inside or outside the polygon face. + There are multiple algorithms to use here. + @param[in] a_algorithm Algorithm to use + */ inline void setInsideOutsideAlgorithm(typename Polygon2D::InsideOutsideAlgorithm a_algorithm) noexcept; /*! - @brief Reconcile function which computes the internal parameters in - vertices, edges, and faces for use with signed distance functionality - @param[in] a_weight Vertex angle weighting function. Either - VertexNormalWeight::None for unweighted vertex normals or - VertexNormalWeight::Angle for the pseudonormal - @details This will reconcile faces, edges, and vertices, e.g. computing the - area and normal vector for faces - */ + @brief Reconcile function which computes the internal parameters in + vertices, edges, and faces for use with signed distance functionality + @param[in] a_weight Vertex angle weighting function. Either + VertexNormalWeight::None for unweighted vertex normals or + VertexNormalWeight::Angle for the pseudonormal + @details This will reconcile faces, edges, and vertices, e.g. computing the + area and normal vector for faces + */ inline void reconcile(typename DCEL::MeshT::VertexNormalWeight a_weight = VertexNormalWeight::Angle) noexcept; /*! - @brief Get modifiable vertices in this mesh - */ + @brief Get modifiable vertices in this mesh + */ inline std::vector& getVertices() noexcept; /*! - @brief Get immutable vertices in this mesh - */ + @brief Get immutable vertices in this mesh + */ inline const std::vector& getVertices() const noexcept; /*! - @brief Get modifiable half-edges in this mesh - */ + @brief Get modifiable half-edges in this mesh + */ inline std::vector& getEdges() noexcept; /*! - @brief Get immutable half-edges in this mesh - */ + @brief Get immutable half-edges in this mesh + */ inline const std::vector& getEdges() const noexcept; /*! - @brief Get modifiable faces in this mesh - */ + @brief Get modifiable faces in this mesh + */ inline std::vector& getFaces() noexcept; /*! - @brief Get immutable faces in this mesh - */ + @brief Get immutable faces in this mesh + */ inline const std::vector& getFaces() const noexcept; /*! - @brief Compute the signed distance from a point to this mesh - @param[in] a_x0 3D point in space. - @details This function will iterate through ALL faces in the mesh and return - the value with the smallest magnitude. This is horrendously slow, which is - why this function is almost never called. Rather, MeshT can be embedded - in a bounding volume hierarchy for faster access. - @note This will call the other version with the object's search algorithm. - */ + @brief Compute the signed distance from a point to this mesh + @param[in] a_x0 3D point in space. + @details This function will iterate through ALL faces in the mesh and return + the value with the smallest magnitude. This is horrendously slow, which is + why this function is almost never called. Rather, MeshT can be embedded + in a bounding volume hierarchy for faster access. + @note This will call the other version with the object's search algorithm. + */ inline T signedDistance(const Vec3& a_x0) const noexcept override; /*! - @brief Compute the signed distance from a point to this mesh - @param[in] a_x0 3D point in space. - @param[in] a_algorithm Search algorithm - @details This function will iterate through ALL faces in the mesh and return - the value with the smallest magnitude. This is horrendously slow, which is - why this function is almost never called. Rather, MeshT can be embedded - in a bounding volume hierarchy for faster access. - */ + @brief Compute the signed distance from a point to this mesh + @param[in] a_x0 3D point in space. + @param[in] a_algorithm Search algorithm + @details This function will iterate through ALL faces in the mesh and return + the value with the smallest magnitude. This is horrendously slow, which is + why this function is almost never called. Rather, MeshT can be embedded + in a bounding volume hierarchy for faster access. + */ inline T signedDistance(const Vec3& a_x0, SearchAlgorithm a_algorithm) const noexcept; /*! - @brief Compute the unsigned square distance from a point to this mesh - @param[in] a_x0 3D point in space. - @details This function will iterate through ALL faces in the mesh and return - the value with the smallest magnitude. This is horrendously slow, which is - why this function is almost never called. Rather, MeshT can be embedded - in a bounding volume hierarchy for faster access. - @note This will call the other version with the object's search algorithm. - */ + @brief Compute the unsigned square distance from a point to this mesh + @param[in] a_x0 3D point in space. + @details This function will iterate through ALL faces in the mesh and return + the value with the smallest magnitude. This is horrendously slow, which is + why this function is almost never called. Rather, MeshT can be embedded + in a bounding volume hierarchy for faster access. + @note This will call the other version with the object's search algorithm. + */ inline T unsignedDistance2(const Vec3& a_x0) const noexcept; protected: /*! - @brief Search algorithm. Only used in signed distance functions. - */ + @brief Search algorithm. Only used in signed distance functions. + */ SearchAlgorithm m_algorithm; /*! - @brief Mesh vertices - */ + @brief Mesh vertices + */ std::vector m_vertices; /*! - @brief Mesh half-edges - */ + @brief Mesh half-edges + */ std::vector m_edges; /*! - @brief Mesh faces - */ + @brief Mesh faces + */ std::vector m_faces; /*! - @brief Return all vertex coordinates in the mesh. - */ + @brief Return all vertex coordinates in the mesh. + */ inline std::vector> getAllVertexCoordinates() const noexcept; /*! - @brief Function which computes internal things for the polygon faces. - @note This calls DCEL::FaceT::reconcile() - */ + @brief Function which computes internal things for the polygon faces. + @note This calls DCEL::FaceT::reconcile() + */ inline void reconcileFaces() noexcept; /*! - @brief Function which computes internal things for the half-edges - @note This calls DCEL::EdgeT::reconcile() - */ + @brief Function which computes internal things for the half-edges + @note This calls DCEL::EdgeT::reconcile() + */ inline void reconcileEdges() noexcept; /*! - @brief Function which computes internal things for the vertices - @param[in] a_weight Vertex angle weighting - @note This calls DCEL::VertexT::computeVertexNormalAverage() or - DCEL::VertexT::computeVertexNormalAngleWeighted() - */ + @brief Function which computes internal things for the vertices + @param[in] a_weight Vertex angle weighting + @note This calls DCEL::VertexT::computeVertexNormalAverage() or + DCEL::VertexT::computeVertexNormalAngleWeighted() + */ inline void reconcileVertices(typename DCEL::MeshT::VertexNormalWeight a_weight) noexcept; /*! - @brief Implementation of signed distance function which iterates through all - faces - @param[in] a_point 3D point - */ + @brief Implementation of signed distance function which iterates through all + faces + @param[in] a_point 3D point + */ inline T DirectSignedDistance(const Vec3& a_point) const noexcept; /*! - @brief Implementation of squared signed distance function which iterates - through all faces. - @details This first find the face with the smallest unsigned square - distance, and the returns the signed distance to that face (more efficient - than the other version). - @param[in] a_point 3D point - */ + @brief Implementation of squared signed distance function which iterates + through all faces. + @details This first find the face with the smallest unsigned square + distance, and the returns the signed distance to that face (more efficient + than the other version). + @param[in] a_point 3D point + */ inline T DirectSignedDistance2(const Vec3& a_point) const noexcept; /*! - @brief Increment a warning. This is used in sanityCheck() for locating holes - or bad inputs in the mesh. - @param[in] a_warnings Map of all registered warnings - @param[in] a_warn Current warning to increment by - */ + @brief Increment a warning. This is used in sanityCheck() for locating holes + or bad inputs in the mesh. + @param[in] a_warnings Map of all registered warnings + @param[in] a_warn Current warning to increment by + */ inline void incrementWarning(std::map& a_warnings, const std::string& a_warn) const noexcept; /*! - @brief Print all warnings to std::cerr - */ + @brief Print all warnings to std::cerr + */ inline void printWarnings(const std::map& a_warnings) const noexcept; }; diff --git a/Source/EBGeometry_DCEL_MeshImplem.hpp b/Source/EBGeometry_DCEL_MeshImplem.hpp index 37d50487..a4d1e58f 100644 --- a/Source/EBGeometry_DCEL_MeshImplem.hpp +++ b/Source/EBGeometry_DCEL_MeshImplem.hpp @@ -66,7 +66,7 @@ namespace DCEL { for (const auto& warn : a_warnings) { if (warn.second > 0) { std::cerr << "In file 'CD_DCELMeshImplem.H' function " - "MeshT::sanityCheck() - warnings about error '" + "MeshT::sanityCheck() - warnings about error '" << warn.first << "' = " << warn.second << "\n"; } } @@ -238,8 +238,8 @@ namespace DCEL { break; default: std::cerr << "In file 'CD_DCELMeshImplem.H' function " - "DCEL::MeshT::reconcileVertices(VertexNormalWeighting) - " - "unsupported algorithm requested\n"; + "DCEL::MeshT::reconcileVertices(VertexNormalWeighting) - " + "unsupported algorithm requested\n"; } } } @@ -339,7 +339,7 @@ namespace DCEL { } default: { std::cerr << "Error in file 'CD_DCELMeshImplem.H' MeshT::signedDistance " - "unsupported algorithm requested\n"; + "unsupported algorithm requested\n"; break; } diff --git a/Source/EBGeometry_DCEL_Polygon2D.hpp b/Source/EBGeometry_DCEL_Polygon2D.hpp deleted file mode 100644 index e9e60e79..00000000 --- a/Source/EBGeometry_DCEL_Polygon2D.hpp +++ /dev/null @@ -1,192 +0,0 @@ -/* EBGeometry - * Copyright © 2022 Robert Marskar - * Please refer to Copyright.txt and LICENSE in the EBGeometry root directory. - */ -/*! - @file EBGeometry_Polygon2D.hpp - @brief Declaration of a two-dimensional polygon class for embedding 3D - polygon faces - @author Robert Marskar -*/ - -#ifndef EBGeometry_Polygon2D -#define EBGeometry_Polygon2D - -// Std includes -#include -#include - -// Our includes -#include "EBGeometry_Vec.hpp" -#include "EBGeometry_NamespaceHeader.hpp" - -namespace DCEL { - - /*! - @brief Class for embedding a DCEL polygon face into 2D. - @details This class is required for determining whether or not a 3D point - projected to the plane of an N-sided polygon lies inside or outside the - polygon face. To do this we compute the 2D embedding of the polygon face, - reducing the problem to a tractable dimension where we can use well-tested - algorithm. The 2D embedding of a polygon occurs by taking a set of 3D points - and a corresponding normal vector, and projecting those points along one of - the 3D Cartesian axes such that the polygon has the largest area. In essence, - we simply find the direction with the smallest normal vector component and - ignore that. Once the 2D embedding is computed, we can use well-known - algorithms for checking if a point lies inside or outside. The supported - algorithms are 1) The winding number algorithm (computing the winding number), - 2) Computing the subtended angle of the point with the edges of the polygon - (sums to 360 degrees if the point is inside), or computing the crossing number - which checks how many times a ray cast from the point crosses the edges of the - polygon. -*/ - template - class Polygon2D - { - public: - /*! - @brief Supported algorithms for performing inside/outside tests when - checking if a point projects to the inside or outside of a polygon face. - */ - enum class InsideOutsideAlgorithm - { - SubtendedAngle, - CrossingNumber, - WindingNumber - }; - - /*! - @brief Alias to cut down on typing - */ - using Vec2 = Vec2T; - - /*! - @brief Alias to cut down on typing - */ - using Vec3 = Vec3T; - - /*! - @brief Disallowed constructor, use the one with the normal vector and points - */ - Polygon2D() = delete; - - /*! - @brief Full constructor - @param[in] a_normal Normal vector of the 3D polygon face - @param[in] a_points Vertex coordinates of the 3D polygon face - */ - Polygon2D(const Vec3& a_normal, const std::vector& a_points); - - /*! - @brief Destructor (does nothing - */ - ~Polygon2D() = default; - - /*! - @brief Check if a point is inside or outside the 2D polygon - @param[in] a_point 3D point coordinates - @param[in] a_algorithm Inside/outside algorithm - @details This will call the function corresponding to a_algorithm. - */ - inline bool - isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_algorithm) const noexcept; - - /*! - @brief Check if a point is inside a 2D polygon, using the winding number - algorithm - @param[in] a_point 3D point coordinates - @return Returns true if the 3D point projects to the inside of the 2D - polygon - */ - inline bool - isPointInsidePolygonWindingNumber(const Vec3& a_point) const noexcept; - - /*! - @brief Check if a point is inside a 2D polygon, using the subtended angles - @param[in] a_point 3D point coordinates - @return Returns true if the 3D point projects to the inside of the 2D - polygon - */ - inline bool - isPointInsidePolygonSubtend(const Vec3& a_point) const noexcept; - - /*! - @brief Check if a point is inside a 2D polygon, by computing the number of - times a ray crosses the polygon edges. - @param[in] a_point 3D point coordinates - @return Returns true if the 3D point projects to the inside of the 2D - polygon - */ - inline bool - isPointInsidePolygonCrossingNumber(const Vec3& a_point) const noexcept; - - private: - /*! - @brief 3D coordinate direction to ignore - */ - size_t m_ignoreDir; - - /*! - @brief The corresponding 2D x-direction. - */ - size_t m_xDir; - - /*! - @brief The corresponding 2D y-direction. - */ - size_t m_yDir; - - /*! - @brief Projected set of points in 2D - */ - std::vector m_points; - - /*! - @brief Project a 3D point onto the 2D polygon plane (this ignores one of the - vector components) - @param[in] a_poitn 3D point - @return 2D point, ignoring one of the coordinate directions. - */ - inline Vec2 - projectPoint(const Vec3& a_point) const noexcept; - - /*! - @brief Define function. This find the direction to ignore and then computes - the 2D points. - @param[in] a_normal Normal vector for polygon face - @param[in] a_points Vertex coordinates for polygon face. - */ - inline void - define(const Vec3& a_normal, const std::vector& a_points); - - /*! - @brief Compute the winding number for a point P with the 2D polygon - @param[in] P 2D point - @return Returns winding number. - */ - inline int - computeWindingNumber(const Vec2& P) const noexcept; - - /*! - @brief Compute the crossing number for a point P with the 2D polygon - @param[in] P 2D point - @return Returns crossing number. - */ - inline size_t - computeCrossingNumber(const Vec2& P) const noexcept; - - /*! - @brief Compute the subtended angle for a point P with the 2D polygon - @param[in] P 2D point - @return Returns subtended angle. - */ - inline T - computeSubtendedAngle(const Vec2& P) const noexcept; - }; -} // namespace DCEL - -#include "EBGeometry_NamespaceFooter.hpp" - -#include "EBGeometry_Polygon2DImplem.hpp" - -#endif diff --git a/Source/EBGeometry_DCEL_Polygon2DImplem.hpp b/Source/EBGeometry_DCEL_Polygon2DImplem.hpp deleted file mode 100644 index bca50308..00000000 --- a/Source/EBGeometry_DCEL_Polygon2DImplem.hpp +++ /dev/null @@ -1,226 +0,0 @@ -/* EBGeometry - * Copyright © 2022 Robert Marskar - * Please refer to Copyright.txt and LICENSE in the EBGeometry root directory. - */ - -/*! - @file EBGeometry_Polygon2DImplem.hpp - @brief Implementation of DCELPolygon.hpp - @author Robert Marskar -*/ - -#ifndef EBGeometry_Polygon2DImplem -#define EBGeometry_Polygon2DImplem - -// Std includes -#include - -// Our includes -#include "EBGeometry_Polygon2D.hpp" -#include "EBGeometry_NamespaceHeader.hpp" - -namespace DCEL { - - template - inline Polygon2D::Polygon2D(const Vec3& a_normal, const std::vector& a_points) - { - this->define(a_normal, a_points); - } - - template - inline bool - Polygon2D::isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_algorithm) const noexcept - { - bool ret = false; - - switch (a_algorithm) { - case InsideOutsideAlgorithm::SubtendedAngle: { - ret = this->isPointInsidePolygonSubtend(a_point); - - break; - } - case InsideOutsideAlgorithm::CrossingNumber: { - ret = this->isPointInsidePolygonCrossingNumber(a_point); - - break; - } - case InsideOutsideAlgorithm::WindingNumber: { - ret = this->isPointInsidePolygonWindingNumber(a_point); - - break; - } - default: - std::cerr << "In file 'CD_DCELPolygon2DImplem.H' function " - "Polygon2D::isPointInside - logic bust.\n"; - } - - return ret; - } - - template - inline Vec2T - Polygon2D::projectPoint(const Vec3& a_point) const noexcept - { - return Vec2(a_point[m_xDir], a_point[m_yDir]); - } - - template - inline void - Polygon2D::define(const Vec3& a_normal, const std::vector& a_points) - { - m_ignoreDir = 0; - - for (size_t dir = 1; dir < 3; dir++) { - if (std::abs(a_normal[dir]) > std::abs(a_normal[m_ignoreDir])) { - m_ignoreDir = dir; - } - } - - m_xDir = 3; - m_yDir = 0; - - for (size_t dir = 0; dir < 3; dir++) { - if (dir != m_ignoreDir) { - m_xDir = std::min(m_xDir, dir); - m_yDir = std::max(m_yDir, dir); - } - } - - for (const auto& p3 : a_points) { - m_points.emplace_back(this->projectPoint(p3)); - } - } - - template - inline int - Polygon2D::computeWindingNumber(const Vec2& P) const noexcept - { - int wn = 0; // the winding number counter - - const size_t N = m_points.size(); - - auto isLeft = [](const Vec2& P0, const Vec2& P1, const Vec2& P2) { - return (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y); - }; - - // loop through all edges of the polygon - for (size_t i = 0; i < N; i++) { // edge from V[i] to V[i+1] - - const Vec2& P1 = m_points[i]; - const Vec2& P2 = m_points[(i + 1) % N]; - - const T res = isLeft(P1, P2, P); - - if (P1.y <= P.y) { // start y <= P.y - if (P2.y > P.y) // an upward crossing - if (res > 0.) // P left of edge - ++wn; // have a valid up intersect - } - else { // start y > P.y (no test needed) - if (P2.y <= P.y) // a downward crossing - if (res < 0.) // P right of edge - --wn; // have a valid down intersect - } - } - - return wn; - } - - template - inline size_t - Polygon2D::computeCrossingNumber(const Vec2& P) const noexcept - { - size_t cn = 0; - - const size_t N = m_points.size(); - - for (size_t i = 0; i < N; i++) { // edge from V[i] to V[i+1] - const Vec2& P1 = m_points[i]; - const Vec2& P2 = m_points[(i + 1) % N]; - - const bool upwardCrossing = (P1.y <= P.y) && (P2.y > P.y); - const bool downwardCrossing = (P1.y > P.y) && (P2.y <= P.y); - - if (upwardCrossing || downwardCrossing) { - const T t = (P.y - P1.y) / (P2.y - P1.y); - - if (P.x < P1.x + t * (P2.x - P1.x)) { // P.x < intersect - cn += 1; // a valid crossing of y=P.y right of P.x - } - } - } - - return cn; - } - - template - inline T - Polygon2D::computeSubtendedAngle(const Vec2& p) const noexcept - { - T sumTheta = 0.0; - - const size_t N = m_points.size(); - - for (size_t i = 0; i < N; i++) { - const Vec2 p1 = m_points[i] - p; - const Vec2 p2 = m_points[(i + 1) % N] - p; - - const T theta1 = atan2(p1.y, p1.x); - const T theta2 = atan2(p2.y, p2.x); - - T dTheta = theta2 - theta1; - - while (dTheta > M_PI) - dTheta -= 2.0 * M_PI; - while (dTheta < -M_PI) - dTheta += 2.0 * M_PI; - - sumTheta += dTheta; - } - - return sumTheta; - } - - template - inline bool - Polygon2D::isPointInsidePolygonWindingNumber(const Vec3& a_point) const noexcept - { - const Vec2 p = this->projectPoint(a_point); - - const int wn = this->computeWindingNumber(p); - - return wn != 0; - } - - template - inline bool - Polygon2D::isPointInsidePolygonCrossingNumber(const Vec3& a_point) const noexcept - { - const Vec2 p = this->projectPoint(a_point); - - const size_t cn = this->computeCrossingNumber(p); - - const bool ret = (cn & 1); - - return ret; - } - - template - inline bool - Polygon2D::isPointInsidePolygonSubtend(const Vec3& a_point) const noexcept - { - const Vec2 p = this->projectPoint(a_point); - - T sumTheta = this->computeSubtendedAngle(p); // Should be = 2pi if point is inside. - - sumTheta = std::abs(sumTheta) / (2. * M_PI); - - const bool ret = (round(sumTheta) == 1); // 2PI if the polygon is inside. - - return ret; - } -} // namespace DCEL - -#include "EBGeometry_NamespaceFooter.hpp" - -#endif diff --git a/Source/EBGeometry_DCEL_Vertex.hpp b/Source/EBGeometry_DCEL_Vertex.hpp index 81245e67..1c829f47 100644 --- a/Source/EBGeometry_DCEL_Vertex.hpp +++ b/Source/EBGeometry_DCEL_Vertex.hpp @@ -36,268 +36,268 @@ namespace DCEL { class EdgeIteratorT; /*! - @brief Class which represents a vertex node in a double-edge connected list - (DCEL). - @details This class is used in DCEL functionality which stores polygonal - surfaces in a mesh. The VertexT class has a position, a normal vector, and a - pointer to one of the outgoing edges from the vertex. For performance reasons - we also include pointers to all the polygon faces that share this vertex. - @note The normal vector is outgoing, i.e. a point x is "outside" the vertex if - the dot product between n and (x - x0) is positive. -*/ + @brief Class which represents a vertex node in a double-edge connected list + (DCEL). + @details This class is used in DCEL functionality which stores polygonal + surfaces in a mesh. The VertexT class has a position, a normal vector, and a + pointer to one of the outgoing edges from the vertex. For performance reasons + we also include pointers to all the polygon faces that share this vertex. + @note The normal vector is outgoing, i.e. a point x is "outside" the vertex if + the dot product between n and (x - x0) is positive. + */ template class VertexT { public: /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vec3 = Vec3T; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Vertex = VertexT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Edge = EdgeT; /*! - @brief Alias to cut down on typing - */ + @brief Alias to cut down on typing + */ using Face = FaceT; /*! - @brief Alias to cut down on typing. Note that this is - std::shared_ptr > - */ + @brief Alias to cut down on typing. Note that this is + std::shared_ptr > + */ using VertexPtr = std::shared_ptr; /*! - @brief Alias to cut down on typing. Note that this is - std::shared_ptr > - */ + @brief Alias to cut down on typing. Note that this is + std::shared_ptr > + */ using EdgePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing. Note that this is - std::shared_ptr > - */ + @brief Alias to cut down on typing. Note that this is + std::shared_ptr > + */ using FacePtr = std::shared_ptr; /*! - @brief Alias to cut down on typing. Note that this is - std::shared_ptr > - */ + @brief Alias to cut down on typing. Note that this is + std::shared_ptr > + */ using EdgeIterator = EdgeIteratorT; /*! - @brief Default constructor. - @details This initializes the position and the normal vector to zero - vectors, and the polygon face list is empty - */ + @brief Default constructor. + @details This initializes the position and the normal vector to zero + vectors, and the polygon face list is empty + */ VertexT(); /*! - @brief Partial constructor. - @param[in] a_position Vertex position - @details This initializes the position to a_position and the normal vector - to the zero vector. The polygon face list is empty. - */ + @brief Partial constructor. + @param[in] a_position Vertex position + @details This initializes the position to a_position and the normal vector + to the zero vector. The polygon face list is empty. + */ VertexT(const Vec3& a_position); /*! - @brief Constructor. - @param[in] a_position Vertex position - @param[in] a_normal Vertex normal vector - @details This initializes the position to a_position and the normal vector - to a_normal. The polygon face list is empty. - */ + @brief Constructor. + @param[in] a_position Vertex position + @param[in] a_normal Vertex normal vector + @details This initializes the position to a_position and the normal vector + to a_normal. The polygon face list is empty. + */ VertexT(const Vec3& a_position, const Vec3& a_normal); /*! - @brief Full copy constructor - @param[in] a_otherVertex Other vertex - @details This copies the position, normal vector, and outgoing edge pointer - from the other vertex. The polygon face list. - */ + @brief Full copy constructor + @param[in] a_otherVertex Other vertex + @details This copies the position, normal vector, and outgoing edge pointer + from the other vertex. The polygon face list. + */ VertexT(const Vertex& a_otherVertex); /*! - @brief Destructor (does nothing) - */ + @brief Destructor (does nothing) + */ ~VertexT(); /*! - @brief Define function - @param[in] a_position Vertex position - @param[in] a_edge Pointer to outgoing edge - @param[in] a_normal Vertex normal vector - @details This sets the position, normal vector, and edge pointer. - */ + @brief Define function + @param[in] a_position Vertex position + @param[in] a_edge Pointer to outgoing edge + @param[in] a_normal Vertex normal vector + @details This sets the position, normal vector, and edge pointer. + */ inline void define(const Vec3& a_position, const EdgePtr& a_edge, const Vec3& a_normal) noexcept; /*! - @brief Set the vertex position - @param[in] a_position Vertex position - */ + @brief Set the vertex position + @param[in] a_position Vertex position + */ inline void setPosition(const Vec3& a_position) noexcept; /*! - @brief Set the vertex normal vector - @param[in] a_normal Vertex normal vector - */ + @brief Set the vertex normal vector + @param[in] a_normal Vertex normal vector + */ inline void setNormal(const Vec3& a_normal) noexcept; /*! - @brief Set the reference to the outgoing edge - @param[in] a_edge Pointer to an outgoing edge - */ + @brief Set the reference to the outgoing edge + @param[in] a_edge Pointer to an outgoing edge + */ inline void setEdge(const EdgePtr& a_edge) noexcept; /*! - @brief Add a face to the polygon face list. - @param[in] a_face Pointer to face. - */ + @brief Add a face to the polygon face list. + @param[in] a_face Pointer to face. + */ inline void addFace(const FacePtr& a_face) noexcept; /*! - @brief Normalize the normal vector, ensuring its length is 1 - */ + @brief Normalize the normal vector, ensuring its length is 1 + */ inline void normalizeNormalVector() noexcept; /*! - @brief Compute the vertex normal, using an average the normal vector in this - vertex's face list (m_faces) - */ + @brief Compute the vertex normal, using an average the normal vector in this + vertex's face list (m_faces) + */ inline void computeVertexNormalAverage() noexcept; /*! - @brief Compute the vertex normal, using an average of the normal vectors in - the input face list - @param[in] a_faces Faces - @note This computes the vertex normal as n = sum(normal(face))/num(faces) - */ + @brief Compute the vertex normal, using an average of the normal vectors in + the input face list + @param[in] a_faces Faces + @note This computes the vertex normal as n = sum(normal(face))/num(faces) + */ inline void computeVertexNormalAverage(const std::vector& a_faces) noexcept; /*! - @brief Compute the vertex normal, using the pseudonormal algorithm which - weights the normal with the subtended angle to each connected face. - @details This calls the other version with a_faces = m_faces - @note This computes the normal vector using the pseudnormal algorithm from - Baerentzen and Aanes in "Signed distance computation using the angle - weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49) - */ + @brief Compute the vertex normal, using the pseudonormal algorithm which + weights the normal with the subtended angle to each connected face. + @details This calls the other version with a_faces = m_faces + @note This computes the normal vector using the pseudnormal algorithm from + Baerentzen and Aanes in "Signed distance computation using the angle + weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49) + */ inline void computeVertexNormalAngleWeighted() noexcept; /*! - @brief Compute the vertex normal, using the pseudonormal algorithm which - weights the normal with the subtended angle to each connected face. - @param[in] a_faces Faces to use for computation. - @note This computes the normal vector using the pseudnormal algorithm from - Baerentzen and Aanes in "Signed distance computation using the angle - weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49) - */ + @brief Compute the vertex normal, using the pseudonormal algorithm which + weights the normal with the subtended angle to each connected face. + @param[in] a_faces Faces to use for computation. + @note This computes the normal vector using the pseudnormal algorithm from + Baerentzen and Aanes in "Signed distance computation using the angle + weighted pseudonormal" (DOI: 10.1109/TVCG.2005.49) + */ inline void computeVertexNormalAngleWeighted(const std::vector& a_faces) noexcept; /*! - @brief Return modifiable vertex position. - */ + @brief Return modifiable vertex position. + */ inline Vec3T& getPosition() noexcept; /*! - @brief Return immutable vertex position. - */ + @brief Return immutable vertex position. + */ inline const Vec3T& getPosition() const noexcept; /*! - @brief Return modifiable vertex normal vector. - */ + @brief Return modifiable vertex normal vector. + */ inline Vec3T& getNormal() noexcept; /*! - @brief Return immutable vertex normal vector. - */ + @brief Return immutable vertex normal vector. + */ inline const Vec3T& getNormal() const noexcept; /*! - @brief Return modifiable pointer to outgoing edge. - */ + @brief Return modifiable pointer to outgoing edge. + */ inline EdgePtr& getOutgoingEdge() noexcept; /*! - @brief Return immutable pointer to outgoing edge. - */ + @brief Return immutable pointer to outgoing edge. + */ inline const EdgePtr& getOutgoingEdge() const noexcept; /*! - @brief Get modifiable polygon face list for this vertex. - */ + @brief Get modifiable polygon face list for this vertex. + */ inline std::vector& getFaces() noexcept; /*! - @brief Get immutable polygon face list for this vertex. - */ + @brief Get immutable polygon face list for this vertex. + */ inline const std::vector& getFaces() const noexcept; /*! - @brief Get the signed distance to this vertex - @param[in] a_x0 Position in space. - @return The returned distance is |a_x0 - m_position| and the sign is given - by the sign of m_normal * |a_x0 - m_position|. - */ + @brief Get the signed distance to this vertex + @param[in] a_x0 Position in space. + @return The returned distance is |a_x0 - m_position| and the sign is given + by the sign of m_normal * |a_x0 - m_position|. + */ inline T signedDistance(const Vec3& a_x0) const noexcept; /*! - @brief Get the squared unsigned distance to this vertex - @details This is faster to compute than signedDistance, and might be - preferred for some algorithms. - @return Returns the vector length of (a_x - m_position) - */ + @brief Get the squared unsigned distance to this vertex + @details This is faster to compute than signedDistance, and might be + preferred for some algorithms. + @return Returns the vector length of (a_x - m_position) + */ inline T unsignedDistance2(const Vec3& a_x0) const noexcept; protected: /*! - @brief Pointer to an outgoing edge from this vertex. - */ + @brief Pointer to an outgoing edge from this vertex. + */ EdgePtr m_outgoingEdge; /*! - @brief Vertex position - */ + @brief Vertex position + */ Vec3 m_position; /*! - @brief Vertex normal vector - */ + @brief Vertex normal vector + */ Vec3 m_normal; /*! - @brief List of faces connected to this vertex (these must be "manually" - added) - */ + @brief List of faces connected to this vertex (these must be "manually" + added) + */ std::vector m_faces; }; } // namespace DCEL diff --git a/Source/EBGeometry_DCEL_VertexImplem.hpp b/Source/EBGeometry_DCEL_VertexImplem.hpp index 2477822b..c15b8c55 100644 --- a/Source/EBGeometry_DCEL_VertexImplem.hpp +++ b/Source/EBGeometry_DCEL_VertexImplem.hpp @@ -178,14 +178,14 @@ namespace DCEL { } else { std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; + "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; } } } if (inoutVertices.size() != 2) { std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust 2.\n"; + "vertexT::computeVertexNormalAngleWeighted() - logic bust 2.\n"; } const Vec3& x0 = originVertex->getPosition(); @@ -194,7 +194,7 @@ namespace DCEL { if (x0 == x1 || x0 == x2 || x1 == x2) { std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust 3.\n"; + "vertexT::computeVertexNormalAngleWeighted() - logic bust 3.\n"; } Vec3 v1 = x1 - x0; diff --git a/Source/EBGeometry_Parser.hpp b/Source/EBGeometry_Parser.hpp index ad2027c5..4ca3ce2b 100644 --- a/Source/EBGeometry_Parser.hpp +++ b/Source/EBGeometry_Parser.hpp @@ -32,92 +32,92 @@ namespace Parser { /*! - @brief Class for reading Stanford PLY files. - @note T is the precision used for storing the mesh. -*/ + @brief Class for reading Stanford PLY files. + @note T is the precision used for storing the mesh. + */ template class PLY { public: /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using Vertex = DCEL::VertexT; /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using Edge = DCEL::EdgeT; /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using Face = DCEL::FaceT; /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using Mesh = DCEL::MeshT; /*! - @brief Alias for cutting down on typing - */ + @brief Alias for cutting down on typing + */ using EdgeIterator = DCEL::EdgeIteratorT; /*! - @brief Static function which reads an ASCII .ply file and returns a DCEL - mesh. - @param[in] a_filename File name - */ + @brief Static function which reads an ASCII .ply file and returns a DCEL + mesh. + @param[in] a_filename File name + */ inline static std::shared_ptr readIntoDCEL(const std::string a_filename); /*! - @brief Static function which reads an ASCII .ply file and puts it in a mesh. - @param[out] a_mesh DCEL mesh - @param[in] a_filename File name - */ + @brief Static function which reads an ASCII .ply file and puts it in a mesh. + @param[out] a_mesh DCEL mesh + @param[in] a_filename File name + */ inline static void readIntoDCEL(Mesh& a_mesh, const std::string a_filename); protected: /*! - @brief Read an ASCII header - @details This reads the number of vertices and faces in the PLY file. Note - that it only reads the header. - @param[out] a_numVertices Number of vertices - @param[out] a_numFaces Number of faces - @param[in,out] a_inputStream File stream. On output, the filestream is at the - end of the PLY header. - */ + @brief Read an ASCII header + @details This reads the number of vertices and faces in the PLY file. Note + that it only reads the header. + @param[out] a_numVertices Number of vertices + @param[out] a_numFaces Number of faces + @param[in,out] a_inputStream File stream. On output, the filestream is at the + end of the PLY header. + */ inline static void readHeaderASCII(size_t& a_numVertices, size_t& a_numFaces, std::ifstream& a_inputStream); /*! - @brief Read ASCII vertices. - @param[out] a_vertices DCEL vertices. These are constructed in this routine. - @param[in] a_numVertices Number of vertices to read - @param[in] a_inputStream Input file stream. - @note The next getline() from a_inputStream must read the first vertex (i.e. - don't rewind the stream before entering this routine) - */ + @brief Read ASCII vertices. + @param[out] a_vertices DCEL vertices. These are constructed in this routine. + @param[in] a_numVertices Number of vertices to read + @param[in] a_inputStream Input file stream. + @note The next getline() from a_inputStream must read the first vertex (i.e. + don't rewind the stream before entering this routine) + */ inline static void readVerticesIntoDCEL(std::vector>& a_vertices, const size_t a_numVertices, std::ifstream& a_inputStream); /*! - @brief Read ASCII faces and create mesh connectivity. - @param[out] a_faces DCEL faces. Constructured in this routine. - @param[out] a_edges DCEL edges. Constructured in this routine. - @param[out] a_vertices DCEL edges. Constructured in - readVerticesIntoDCEL. - @param[in] a_numFaces Total number of faces in mesh. - @param[in,out] a_inputStream Input stream - @note The next getline() from inputStream must read the first face, i.e. we - assume that read_ascii_vertices was called IMMEDIATELY before this function. - That function will center the fstream on the correct line in the input file. - */ + @brief Read ASCII faces and create mesh connectivity. + @param[out] a_faces DCEL faces. Constructured in this routine. + @param[out] a_edges DCEL edges. Constructured in this routine. + @param[out] a_vertices DCEL edges. Constructured in + readVerticesIntoDCEL. + @param[in] a_numFaces Total number of faces in mesh. + @param[in,out] a_inputStream Input stream + @note The next getline() from inputStream must read the first face, i.e. we + assume that read_ascii_vertices was called IMMEDIATELY before this function. + That function will center the fstream on the correct line in the input file. + */ inline static void readFacesIntoDCEL(std::vector>& a_faces, std::vector>& a_edges, @@ -126,10 +126,10 @@ namespace Parser { std::ifstream& a_inputStream); /*! - @brief Reconcile pair edges, i.e. find the pair edge for every constructed - half-edge - @param[in,out] a_edges Half edges. - */ + @brief Reconcile pair edges, i.e. find the pair edge for every constructed + half-edge + @param[in,out] a_edges Half edges. + */ inline static void reconcilePairEdgesDCEL(std::vector>& a_edges); }; diff --git a/Source/EBGeometry_ParserImplem.hpp b/Source/EBGeometry_ParserImplem.hpp index 48c146c3..a92fbb9c 100644 --- a/Source/EBGeometry_ParserImplem.hpp +++ b/Source/EBGeometry_ParserImplem.hpp @@ -176,7 +176,7 @@ Parser::PLY::readFacesIntoDCEL(std::vector>& a_ if (numVertices < 3) std::cerr << "Parser::PLY::readFacesIntoDCEL - a face must have at least " - "three vertices!\n"; + "three vertices!\n"; // Get the vertices that make up this face. std::vector> curVertices; diff --git a/Source/EBGeometry_Polygon2D.hpp b/Source/EBGeometry_Polygon2D.hpp index 6e9f12dc..61f11aea 100644 --- a/Source/EBGeometry_Polygon2D.hpp +++ b/Source/EBGeometry_Polygon2D.hpp @@ -47,11 +47,11 @@ class Polygon2D checking if a point projects to the inside or outside of a polygon face. */ enum class InsideOutsideAlgorithm - { - SubtendedAngle, - CrossingNumber, - WindingNumber - }; + { + SubtendedAngle, + CrossingNumber, + WindingNumber + }; /*! @brief Alias to cut down on typing diff --git a/Source/EBGeometry_Polygon2DImplem.hpp b/Source/EBGeometry_Polygon2DImplem.hpp index f97aec3e..86589964 100644 --- a/Source/EBGeometry_Polygon2DImplem.hpp +++ b/Source/EBGeometry_Polygon2DImplem.hpp @@ -49,7 +49,7 @@ Polygon2D::isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_ } default: std::cerr << "In file 'EBGeometry_Polygon2DImplem.hpp' function " - "Polygon2D::isPointInside - logic bust.\n"; + "Polygon2D::isPointInside - logic bust.\n"; } return ret; diff --git a/Source/EBGeometry_UnionBVHImplem.hpp b/Source/EBGeometry_UnionBVHImplem.hpp index c0e571dd..830ebddf 100644 --- a/Source/EBGeometry_UnionBVHImplem.hpp +++ b/Source/EBGeometry_UnionBVHImplem.hpp @@ -54,7 +54,7 @@ UnionBVH::buildTree(const BVConstructor& a_bvConstructor) if (numPrimitives < K) { std::cerr << "UnionBVH::buildTree -- not enough primitives to " - "partition into K new nodes\n"; + "partition into K new nodes\n"; } // 1. Compute the bounding volume centroids for each input SDF. @@ -90,8 +90,8 @@ UnionBVH::buildTree(const BVConstructor& a_bvConstructor) // Vector sort. std::sort(primsAndCentroids.begin(), primsAndCentroids.end(), [splitDir](const PC& sdf1, const PC& sdf2) -> bool { - return sdf1.second[splitDir] < sdf2.second[splitDir]; - }); + return sdf1.second[splitDir] < sdf2.second[splitDir]; + }); // Vector unpack. The input SDFs are not sorted based on their bounding // volume centroids. diff --git a/Source/EBGeometry_Vec.hpp b/Source/EBGeometry_Vec.hpp index 9245ff48..e316c67d 100644 --- a/Source/EBGeometry_Vec.hpp +++ b/Source/EBGeometry_Vec.hpp @@ -235,8 +235,8 @@ class Vec3T { public: /*! - @brief Default constructor. Sets the vector to the zero vector. -*/ + @brief Default constructor. Sets the vector to the zero vector. + */ Vec3T(); /*! diff --git a/Source/EBGeometry_VecImplem.hpp b/Source/EBGeometry_VecImplem.hpp index ddbd683d..6e1fc620 100644 --- a/Source/EBGeometry_VecImplem.hpp +++ b/Source/EBGeometry_VecImplem.hpp @@ -263,7 +263,7 @@ inline constexpr Vec3T Vec3T::infinity() noexcept { return Vec3T( - std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); + std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); } template From 4b529c1d19e71dff124acd2b2bb9ddd476956743 Mon Sep 17 00:00:00 2001 From: Robert Marskar Date: Mon, 2 May 2022 09:35:31 +0200 Subject: [PATCH 7/7] Format files again --- .clang-format | 2 +- Examples/EBGeometry_DCEL/main.cpp | 2 +- Source/EBGeometry_BVH.hpp | 10 +++++----- Source/EBGeometry_BVHImplem.hpp | 14 +++++++------- Source/EBGeometry_BoundingVolumes.hpp | 6 +++--- Source/EBGeometry_BoundingVolumesImplem.hpp | 4 ++-- Source/EBGeometry_DCEL_BVH.hpp | 4 ++-- Source/EBGeometry_DCEL_Iterator.hpp | 8 ++++---- Source/EBGeometry_DCEL_IteratorImplem.hpp | 2 +- Source/EBGeometry_DCEL_Mesh.hpp | 16 ++++++++-------- Source/EBGeometry_DCEL_MeshImplem.hpp | 8 ++++---- Source/EBGeometry_DCEL_VertexImplem.hpp | 6 +++--- Source/EBGeometry_ParserImplem.hpp | 2 +- Source/EBGeometry_Polygon2D.hpp | 10 +++++----- Source/EBGeometry_Polygon2DImplem.hpp | 2 +- Source/EBGeometry_UnionBVHImplem.hpp | 6 +++--- Source/EBGeometry_VecImplem.hpp | 2 +- 17 files changed, 52 insertions(+), 52 deletions(-) diff --git a/.clang-format b/.clang-format index cdc0433e..d513fa49 100644 --- a/.clang-format +++ b/.clang-format @@ -38,7 +38,7 @@ BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true +BreakStringLiterals: false ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: true diff --git a/Examples/EBGeometry_DCEL/main.cpp b/Examples/EBGeometry_DCEL/main.cpp index 0cc4d2b3..862c16d4 100644 --- a/Examples/EBGeometry_DCEL/main.cpp +++ b/Examples/EBGeometry_DCEL/main.cpp @@ -31,7 +31,7 @@ main(int argc, char* argv[]) } else { std::cerr << "Missing file name. Use ./a.out 'filename' where 'filename' " - "is one of the files in ../PLY\n"; + "is one of the files in ../PLY\n"; } // Declare the precision T as float. diff --git a/Source/EBGeometry_BVH.hpp b/Source/EBGeometry_BVH.hpp index 277af38e..c9fad17e 100644 --- a/Source/EBGeometry_BVH.hpp +++ b/Source/EBGeometry_BVH.hpp @@ -102,11 +102,11 @@ namespace BVH { Unordered => Use recursive unordered traversal. */ enum class Prune - { - Stack, - Ordered, - Unordered, - }; + { + Stack, + Ordered, + Unordered, + }; /*! @brief Class which encapsulates a node in a bounding volume hierarchy. diff --git a/Source/EBGeometry_BVHImplem.hpp b/Source/EBGeometry_BVHImplem.hpp index b55e58a4..4e78926f 100644 --- a/Source/EBGeometry_BVHImplem.hpp +++ b/Source/EBGeometry_BVHImplem.hpp @@ -200,7 +200,7 @@ namespace BVH { } default: std::cerr << "In file EBGeometry_BVHImplem.hpp function NodeT::signedDistance(Vec3, Prune) -- bad input enum for 'Prune'\n"; + "K>::signedDistance(Vec3, Prune) -- bad input enum for 'Prune'\n"; }; return ret; @@ -265,9 +265,9 @@ namespace BVH { } std::sort( - childrenAndDistances.begin(), - childrenAndDistances.end(), - [](const NodeAndDist& node1, const NodeAndDist& node2) -> bool { return node1.second > node2.second; }); + childrenAndDistances.begin(), + childrenAndDistances.end(), + [](const NodeAndDist& node1, const NodeAndDist& node2) -> bool { return node1.second > node2.second; }); // Push the children onto the stack. for (const auto& child : childrenAndDistances) { @@ -518,7 +518,7 @@ namespace BVH { template inline T LinearNodeT::getDistanceToPrimitives( - const Vec3T& a_point, const std::vector>& a_primitives) const noexcept + const Vec3T& a_point, const std::vector>& a_primitives) const noexcept { T minDist = std::numeric_limits::infinity(); @@ -535,8 +535,8 @@ namespace BVH { template inline LinearBVH::LinearBVH( - const std::vector>>& a_linearNodes, - const std::vector>& a_primitives) + const std::vector>>& a_linearNodes, + const std::vector>& a_primitives) { m_linearNodes = a_linearNodes; m_primitives = a_primitives; diff --git a/Source/EBGeometry_BoundingVolumes.hpp b/Source/EBGeometry_BoundingVolumes.hpp index 64daa0db..07bc285d 100644 --- a/Source/EBGeometry_BoundingVolumes.hpp +++ b/Source/EBGeometry_BoundingVolumes.hpp @@ -40,9 +40,9 @@ namespace BoundingVolumes { bounding sphere for a set of 3D points. */ enum class BoundingVolumeAlgorithm - { - Ritter, - }; + { + Ritter, + }; /*! @brief Alias to cut down on typing diff --git a/Source/EBGeometry_BoundingVolumesImplem.hpp b/Source/EBGeometry_BoundingVolumesImplem.hpp index 5b08560f..b5ce0a73 100644 --- a/Source/EBGeometry_BoundingVolumesImplem.hpp +++ b/Source/EBGeometry_BoundingVolumesImplem.hpp @@ -302,8 +302,8 @@ namespace BoundingVolumes { const Vec3& otherHi = a_other.getHighCorner(); return (m_loCorner[0] < otherHi[0] && m_hiCorner[0] > otherLo[0]) && - (m_loCorner[1] < otherHi[1] && m_hiCorner[1] > otherLo[1]) && - (m_loCorner[2] < otherHi[2] && m_hiCorner[2] > otherLo[2]); + (m_loCorner[1] < otherHi[1] && m_hiCorner[1] > otherLo[1]) && + (m_loCorner[2] < otherHi[2] && m_hiCorner[2] > otherLo[2]); } template diff --git a/Source/EBGeometry_DCEL_BVH.hpp b/Source/EBGeometry_DCEL_BVH.hpp index f1bcb5b2..60316d25 100644 --- a/Source/EBGeometry_DCEL_BVH.hpp +++ b/Source/EBGeometry_DCEL_BVH.hpp @@ -167,8 +167,8 @@ namespace DCEL { // Sort the primitives based on the centroid location of their BVs. std::sort(primsAndBVs.begin(), primsAndBVs.end(), [splitDir](const P& p1, const P& p2) { - return (p1.second).getCentroid()[splitDir] < (p2.second).getCentroid()[splitDir]; - }); + return (p1.second).getCentroid()[splitDir] < (p2.second).getCentroid()[splitDir]; + }); // Unpack the vector and partition into equal counts. PrimitiveList sortedPrimitives; diff --git a/Source/EBGeometry_DCEL_Iterator.hpp b/Source/EBGeometry_DCEL_Iterator.hpp index 67183f95..d31e34f9 100644 --- a/Source/EBGeometry_DCEL_Iterator.hpp +++ b/Source/EBGeometry_DCEL_Iterator.hpp @@ -149,10 +149,10 @@ namespace DCEL { (face- or vertex-based iteration) */ enum class IterationMode - { - Vertices, - Faces - }; + { + Vertices, + Faces + }; /*! @brief If true, a full loop has been made around the polygon face diff --git a/Source/EBGeometry_DCEL_IteratorImplem.hpp b/Source/EBGeometry_DCEL_IteratorImplem.hpp index 389fc60e..b1b8cb89 100644 --- a/Source/EBGeometry_DCEL_IteratorImplem.hpp +++ b/Source/EBGeometry_DCEL_IteratorImplem.hpp @@ -97,7 +97,7 @@ namespace DCEL { } default: { std::cerr << "In file 'EBGeometry_DCEL_IteratorImplem.hpp function " - "EdgeIteratorT::operator++ - logic bust\n"; + "EdgeIteratorT::operator++ - logic bust\n"; } } diff --git a/Source/EBGeometry_DCEL_Mesh.hpp b/Source/EBGeometry_DCEL_Mesh.hpp index 8fde1fba..3e43e856 100644 --- a/Source/EBGeometry_DCEL_Mesh.hpp +++ b/Source/EBGeometry_DCEL_Mesh.hpp @@ -61,19 +61,19 @@ namespace DCEL { Direct2 means compute the squared signed distance for all primitives. */ enum class SearchAlgorithm - { - Direct, - Direct2, - }; + { + Direct, + Direct2, + }; /*! @brief How to weight vertex normal */ enum class VertexNormalWeight - { - None, - Angle, - }; + { + None, + Angle, + }; /*! @brief Alias to cut down on the typing diff --git a/Source/EBGeometry_DCEL_MeshImplem.hpp b/Source/EBGeometry_DCEL_MeshImplem.hpp index a4d1e58f..37d50487 100644 --- a/Source/EBGeometry_DCEL_MeshImplem.hpp +++ b/Source/EBGeometry_DCEL_MeshImplem.hpp @@ -66,7 +66,7 @@ namespace DCEL { for (const auto& warn : a_warnings) { if (warn.second > 0) { std::cerr << "In file 'CD_DCELMeshImplem.H' function " - "MeshT::sanityCheck() - warnings about error '" + "MeshT::sanityCheck() - warnings about error '" << warn.first << "' = " << warn.second << "\n"; } } @@ -238,8 +238,8 @@ namespace DCEL { break; default: std::cerr << "In file 'CD_DCELMeshImplem.H' function " - "DCEL::MeshT::reconcileVertices(VertexNormalWeighting) - " - "unsupported algorithm requested\n"; + "DCEL::MeshT::reconcileVertices(VertexNormalWeighting) - " + "unsupported algorithm requested\n"; } } } @@ -339,7 +339,7 @@ namespace DCEL { } default: { std::cerr << "Error in file 'CD_DCELMeshImplem.H' MeshT::signedDistance " - "unsupported algorithm requested\n"; + "unsupported algorithm requested\n"; break; } diff --git a/Source/EBGeometry_DCEL_VertexImplem.hpp b/Source/EBGeometry_DCEL_VertexImplem.hpp index c15b8c55..2477822b 100644 --- a/Source/EBGeometry_DCEL_VertexImplem.hpp +++ b/Source/EBGeometry_DCEL_VertexImplem.hpp @@ -178,14 +178,14 @@ namespace DCEL { } else { std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; + "vertexT::computeVertexNormalAngleWeighted() - logic bust.\n"; } } } if (inoutVertices.size() != 2) { std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust 2.\n"; + "vertexT::computeVertexNormalAngleWeighted() - logic bust 2.\n"; } const Vec3& x0 = originVertex->getPosition(); @@ -194,7 +194,7 @@ namespace DCEL { if (x0 == x1 || x0 == x2 || x1 == x2) { std::cerr << "In file 'CD_DCELVertexImplem.H' function " - "vertexT::computeVertexNormalAngleWeighted() - logic bust 3.\n"; + "vertexT::computeVertexNormalAngleWeighted() - logic bust 3.\n"; } Vec3 v1 = x1 - x0; diff --git a/Source/EBGeometry_ParserImplem.hpp b/Source/EBGeometry_ParserImplem.hpp index a92fbb9c..48c146c3 100644 --- a/Source/EBGeometry_ParserImplem.hpp +++ b/Source/EBGeometry_ParserImplem.hpp @@ -176,7 +176,7 @@ Parser::PLY::readFacesIntoDCEL(std::vector>& a_ if (numVertices < 3) std::cerr << "Parser::PLY::readFacesIntoDCEL - a face must have at least " - "three vertices!\n"; + "three vertices!\n"; // Get the vertices that make up this face. std::vector> curVertices; diff --git a/Source/EBGeometry_Polygon2D.hpp b/Source/EBGeometry_Polygon2D.hpp index 61f11aea..6e9f12dc 100644 --- a/Source/EBGeometry_Polygon2D.hpp +++ b/Source/EBGeometry_Polygon2D.hpp @@ -47,11 +47,11 @@ class Polygon2D checking if a point projects to the inside or outside of a polygon face. */ enum class InsideOutsideAlgorithm - { - SubtendedAngle, - CrossingNumber, - WindingNumber - }; + { + SubtendedAngle, + CrossingNumber, + WindingNumber + }; /*! @brief Alias to cut down on typing diff --git a/Source/EBGeometry_Polygon2DImplem.hpp b/Source/EBGeometry_Polygon2DImplem.hpp index 86589964..f97aec3e 100644 --- a/Source/EBGeometry_Polygon2DImplem.hpp +++ b/Source/EBGeometry_Polygon2DImplem.hpp @@ -49,7 +49,7 @@ Polygon2D::isPointInside(const Vec3& a_point, const InsideOutsideAlgorithm a_ } default: std::cerr << "In file 'EBGeometry_Polygon2DImplem.hpp' function " - "Polygon2D::isPointInside - logic bust.\n"; + "Polygon2D::isPointInside - logic bust.\n"; } return ret; diff --git a/Source/EBGeometry_UnionBVHImplem.hpp b/Source/EBGeometry_UnionBVHImplem.hpp index 830ebddf..c0e571dd 100644 --- a/Source/EBGeometry_UnionBVHImplem.hpp +++ b/Source/EBGeometry_UnionBVHImplem.hpp @@ -54,7 +54,7 @@ UnionBVH::buildTree(const BVConstructor& a_bvConstructor) if (numPrimitives < K) { std::cerr << "UnionBVH::buildTree -- not enough primitives to " - "partition into K new nodes\n"; + "partition into K new nodes\n"; } // 1. Compute the bounding volume centroids for each input SDF. @@ -90,8 +90,8 @@ UnionBVH::buildTree(const BVConstructor& a_bvConstructor) // Vector sort. std::sort(primsAndCentroids.begin(), primsAndCentroids.end(), [splitDir](const PC& sdf1, const PC& sdf2) -> bool { - return sdf1.second[splitDir] < sdf2.second[splitDir]; - }); + return sdf1.second[splitDir] < sdf2.second[splitDir]; + }); // Vector unpack. The input SDFs are not sorted based on their bounding // volume centroids. diff --git a/Source/EBGeometry_VecImplem.hpp b/Source/EBGeometry_VecImplem.hpp index 6e1fc620..ddbd683d 100644 --- a/Source/EBGeometry_VecImplem.hpp +++ b/Source/EBGeometry_VecImplem.hpp @@ -263,7 +263,7 @@ inline constexpr Vec3T Vec3T::infinity() noexcept { return Vec3T( - std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); + std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()); } template