15#include "libmesh/mesh_tools.h"
16#include "libmesh/mesh_tet_interface.h"
17#include "libmesh/unstructured_mesh.h"
27packCell(
const std::size_t y_index,
const std::size_t z_index)
30 return (
static_cast<std::uint64_t
>(y_index) << 32) |
static_cast<std::uint64_t
>(z_index);
34cellIndex(
const Real value,
const Real min_value,
const Real cell_size,
const std::size_t num_cells)
40 const auto index =
static_cast<long long>(std::floor((value - min_value) / cell_size));
43 if (index >=
static_cast<long long>(num_cells))
45 return static_cast<std::size_t
>(index);
59 _surface_tolerance(surface_tolerance),
60 _bounding_box(
MeshTools::create_bounding_box(_mesh)),
61 _point_locator(_mesh.sub_point_locator())
64 mooseAssert(
mesh.is_serial(),
"Input manifold mesh must be serialized.");
65 mooseAssert(
mesh.mesh_dimension() == 2,
"Manifold mesh must be a surface.");
99 unsigned int num_hits = 0;
101 for (
const auto triangle_index : candidates)
103 const auto tri =
_mesh.elem_ptr(triangle_index);
132 auto umesh =
dynamic_cast<UnstructuredMesh *
>(&
_mesh);
134 mooseError(
"TriangleManifold requires an UnstructuredMesh to validate the surface manifold.");
139 "The inputted surface mesh cannot be treated as manifold for the following reasons:\n",
150 const auto extent_y =
152 const auto extent_z =
156 const auto target_cells =
157 std::max<dof_id_type>(1,
static_cast<dof_id_type
>(std::sqrt(
numTriangles())));
158 const auto aspect = std::sqrt(extent_y / extent_z);
161 1,
static_cast<dof_id_type
>(std::lround(std::sqrt(target_cells) * aspect)));
163 1,
static_cast<std::size_t
>(std::ceil(
static_cast<Real
>(target_cells) /
_num_y_cells)));
170 for (
const auto elem :
_mesh.active_element_ptr_range())
172 const auto triangle_index = elem->id();
173 const auto bbox = elem->loose_bounding_box();
185 for (
const auto iy : make_range(y_start, y_stop + 1))
186 for (
const auto iz : make_range(z_start, z_stop + 1))
213 static const Point direction(1.0, 0.0, 0.0);
217 const Point h = direction.
cross(edge2);
218 const Real determinant = edge1 * h;
219 const Real characteristic_length = std::max(edge1.norm(), edge2.norm());
225 const Real inv_determinant = 1.0 / determinant;
226 const Point s = point - tri.
node_ref(0);
227 const Real u = inv_determinant * (s * h);
228 if (u < 0.0 || u > 1.0)
231 const Point q = s.cross(edge1);
232 const Real v = inv_determinant * (direction * q);
233 if (v < 0.0 || u + v > 1.0)
236 const Real t = inv_determinant * (edge2 * q);
244 const Point intersection = point + t * direction;
263 Real total_angle = 0.0;
264 for (
const auto elem :
_mesh.active_element_ptr_range())
271std::vector<dof_id_type>
302 std::ostringstream err_msg;
304 err_msg <<
"- At least one non-Tri3 element was found.\n" << std::endl;
306 err_msg <<
"- At least one triangle without three neighbors was found.\n" << std::endl;
308 err_msg <<
"- The surface mesh was empty\n" << std::endl;
310 err_msg <<
"- At least one triangle neighbor without a return neighbor link was found.\n";
312 err_msg <<
"- At least one triangle neighbor without expected node links was found.\n";
314 err_msg <<
"- At least one triangle neighbor with an inconsistent orientation was found.\n";
316 err_msg <<
"- At least one triangle neighbor with inconsistent node and neighbor links was "
319 err_msg <<
"- At least one input triangle is degenerate, with near-zero area relative to the "
322 err_msg <<
"- Mesh is degenerate, with zero thickness in at least one direction.\n";
323 return err_msg.str();
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
std::string improveAndValidate()
SurfaceChecker(UnstructuredMesh &mesh)
void triangulate() override
std::size_t _num_y_cells
Number of yz-grid bins in the y direction.
bool contains(const Point &point) const
const Real _surface_tolerance
Absolute tolerance used throughout validation and geometric classification.
std::size_t _num_z_cells
Number of yz-grid bins in the z direction.
std::size_t numTriangles() const
bool pointInsideBoundingBox(const Point &point) const
Cheap global bounding-box rejection for containment queries.
SurfaceGeometry::SurfaceSide sideness(const Point &point) const
Classify a query point relative to the manifold surface.
Real _y_cell_size
Width of one yz-grid cell in the y direction.
Real _z_min
Minimum global z coordinate used to map query points into yz-grid bins.
RayIntersection rayIntersectsTriangle(const Point &point, const libMesh::Elem &tri) const
Intersect a positive x-direction ray with a single triangle.
TriangleManifold(MeshBase &mesh, const Real surface_tolerance)
Build a manifold classifier from a prepared surface mesh.
void buildCandidateGrid()
Build the yz-plane lookup grid used to accelerate +x ray queries.
Real _z_cell_size
Width of one yz-grid cell in the z direction.
bool containsBySolidAngle(const Point &point) const
Robust fallback containment query based on accumulated solid angle.
std::unordered_map< std::uint64_t, std::vector< dof_id_type > > _ray_grid
Lookup from packed yz-grid cell index to triangles that could intersect the +x query ray.
Real _y_min
Minimum global y coordinate used to map query points into yz-grid bins.
SurfaceGeometry::SurfaceSide classifyByParity(const Point &point) const
Resolve INSIDE vs OUTSIDE via the fixed +x ray parity test (with solid-angle fallback for ambiguous g...
bool pointOnSurface(const Point &point) const
Detect whether a query point lies on or extremely near the manifold surface.
std::vector< dof_id_type > rayCandidates(const Point &point) const
Get the subset of triangles whose yz extents may intersect the query ray.
const libMesh::BoundingBox & boundingBox() const
void finalize()
Complete post-parse validation and acceleration-structure setup.
const std::unique_ptr< libMesh::PointLocatorBase > _point_locator
Pre-built point locator for fast proximity-to-surface detection.
RayIntersection
Result of intersecting the positive x-direction ray with a triangle.
const Point & max() const
const Point & min() const
const Node & node_ref(const unsigned int i) const
MeshTetInterface(UnstructuredMesh &mesh)
std::set< SurfaceIntegrity > improve_hull_integrity()
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
SurfaceSide
The side of a closed surface where a query point is located.
@ INSIDE
The point lies strictly in the interior of the closed surface.
@ ON
The point lies on the surface itself, within tolerance.
@ OUTSIDE
The point lies strictly in the exterior of the closed surface.
std::uint64_t packCell(const std::size_t y_index, const std::size_t z_index)
std::size_t cellIndex(const Real value, const Real min_value, const Real cell_size, const std::size_t num_cells)
Real pointSegmentDistanceSq(const Point &point, const Point &a, const Point &b)
Compute the squared distance from a point to a 3-D line segment.
Real solidAngle(const Point &point, const Point &v0, const Point &v1, const Point &v2)
Compute the signed solid angle subtended by one oriented triangle at the query point.
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...