17#include "libmesh/cell_hex8.h"
18#include "libmesh/cell_hex20.h"
19#include "libmesh/cell_hex27.h"
20#include "libmesh/cell_prism6.h"
21#include "libmesh/cell_prism15.h"
22#include "libmesh/cell_prism18.h"
23#include "libmesh/cell_pyramid5.h"
24#include "libmesh/cell_pyramid13.h"
25#include "libmesh/cell_pyramid14.h"
26#include "libmesh/cell_tet4.h"
27#include "libmesh/cell_tet10.h"
28#include "libmesh/cell_tet14.h"
29#include "libmesh/edge_edge2.h"
30#include "libmesh/enum_to_string.h"
31#include "libmesh/face_quad4.h"
32#include "libmesh/face_tri3.h"
33#include "libmesh/mesh.h"
34#include "libmesh/remote_elem.h"
35#include "libmesh/tensor_value.h"
43 HEX8,
HEX20,
HEX27,
QUAD4,
QUAD8,
QUAD9,
TET4,
TET10,
TET14,
TRI3,
TRI6,
49 const Point & direction,
53 Point & intersection_point,
54 Real & intersection_distance,
56#ifdef DEBUG_RAY_INTERSECTIONS
65 debugRaySimple(
"Called lineLineIntersect2D()");
66 debugRaySimple(
" start = ", start);
67 debugRaySimple(
" direction = ", direction);
68 debugRaySimple(
" length = ", length);
69 debugRaySimple(
" v0 = ", v0);
70 debugRaySimple(
" v1 = ", v1);
72 const auto r = direction * length;
73 const auto s = v1 - v0;
75 const auto rxs = r(0) * s(1) - r(1) * s(0);
76 debugRaySimple(
" rxs = ", rxs);
82 const auto v0mu0 = v0 - start;
84 const auto t = (v0mu0(0) * s(1) - v0mu0(1) * s(0)) / rxs;
85 debugRaySimple(
" t = ", t);
88 debugRaySimple(
"lineLineIntersect2D did not intersect: t out of range");
92 const auto u = (v0mu0(0) * r(1) - v0mu0(1) * r(0)) / rxs;
93 debugRaySimple(
" u = ", u);
96 intersection_point = start + r * t;
97 intersection_distance = t * length;
104 debugRaySimple(
"lineLineIntersect2D intersected with:");
105 debugRaySimple(
" intersection_distance = ", intersection_point);
106 debugRaySimple(
" intersection_distance = ", intersection_distance);
113 debugRaySimple(
"lineLineIntersect2d() did not intersect: u out of range");
119 const Elem *
const elem,
124 std::vector<const Elem *> active_neighbor_children,
125 std::vector<NeighborInfo> & info)
127 mooseAssert(elem->
contains_point(point),
"Doesn't contain point");
132 std::unique_ptr<const Elem> side_helper;
134 auto contains_point = [&point, &info, &side_helper, &elem](
const Elem *
const candidate)
136 if (candidate->contains_point(point))
138 std::vector<unsigned short>
sides;
139 for (
const auto s : candidate->side_index_range())
141 candidate->build_side_ptr(side_helper, s);
142 if (side_helper->contains_point(point))
147 if (!
sides.empty() && candidate != elem)
149 info.emplace_back(candidate, std::move(
sides));
158 contains_point(elem);
164 active_neighbor_children,
170 std::set<const Elem *> point_neighbors;
172 for (
const auto & point_neighbor : point_neighbors)
173 if (!neighbor_set.
contains(point_neighbor) && point_neighbor != elem)
180 const Elem *
const elem,
181 const Node *
const node,
185 std::vector<const Elem *> active_neighbor_children,
186 std::vector<NeighborInfo> & info)
193 std::unique_ptr<const Elem> side_helper;
195 auto contains_node = [&node, &elem, &info, &side_helper](
const Elem *
const candidate)
198 const auto n = candidate->get_node_index(node);
201 std::vector<unsigned short>
sides;
202 for (
const auto s : candidate->side_index_range())
203 if (candidate->is_node_on_side(n, s))
207 mooseError(
"Failed to find a side containing node");
209 info.emplace_back(candidate, std::move(
sides));
214 if (candidate->level() < elem->
level() && candidate->contains_point(*node))
216 std::vector<unsigned short>
sides;
217 for (
const auto s : candidate->side_index_range())
219 candidate->build_side_ptr(side_helper, s);
220 if (side_helper->contains_point(*node))
226 info.emplace_back(candidate, std::move(
sides));
238 elem, neighbor_set, untested_set, next_untested_set, active_neighbor_children, contains_node);
243 std::set<const Elem *> point_neighbors;
245 for (
const auto & point_neighbor : point_neighbors)
246 for (
const auto & neighbor_node : point_neighbor->node_ref_range())
247 if (node == &neighbor_node && !neighbor_set.
contains(point_neighbor) &&
248 point_neighbor != elem)
255 const Elem *
const elem,
256 const Node *
const node1,
257 const Node *
const node2,
261 std::vector<const Elem *> active_neighbor_children,
262 std::vector<NeighborInfo> & info)
274 auto within_edge = [&elem, &node1, &node2, &edge_length, &info](
const Elem *
const candidate)
276 switch (candidate->type())
279 return findEdgeNeighborsWithinEdgeInternal<Hex8>(
280 candidate, elem, node1, node2, edge_length, info);
282 return findEdgeNeighborsWithinEdgeInternal<Tet4>(
283 candidate, elem, node1, node2, edge_length, info);
285 return findEdgeNeighborsWithinEdgeInternal<Pyramid5>(
286 candidate, elem, node1, node2, edge_length, info);
288 return findEdgeNeighborsWithinEdgeInternal<Prism6>(
289 candidate, elem, node1, node2, edge_length, info);
291 return findEdgeNeighborsWithinEdgeInternal<Hex20>(
292 candidate, elem, node1, node2, edge_length, info);
294 return findEdgeNeighborsWithinEdgeInternal<Hex27>(
295 candidate, elem, node1, node2, edge_length, info);
297 return findEdgeNeighborsWithinEdgeInternal<Tet10>(
298 candidate, elem, node1, node2, edge_length, info);
300 return findEdgeNeighborsWithinEdgeInternal<Tet14>(
301 candidate, elem, node1, node2, edge_length, info);
303 return findEdgeNeighborsWithinEdgeInternal<Pyramid13>(
304 candidate, elem, node1, node2, edge_length, info);
306 return findEdgeNeighborsWithinEdgeInternal<Pyramid14>(
307 candidate, elem, node1, node2, edge_length, info);
309 return findEdgeNeighborsWithinEdgeInternal<Prism15>(
310 candidate, elem, node1, node2, edge_length, info);
312 return findEdgeNeighborsWithinEdgeInternal<Prism18>(
313 candidate, elem, node1, node2, edge_length, info);
317 " not supported in TraceRayTools::findEdgeNeighbors()");
325 elem, neighbor_set, untested_set, next_untested_set, active_neighbor_children, within_edge);
331 mooseAssert(!elem->
active(),
"Should be inactive");
332 mooseAssert(elem->
side_ptr(side)->contains_point(point),
"Side should contain point");
342 if (child->close_to_point(point, 5.e-5))
351 mooseError(
"Failed to find child containing point on side");
358 if (!neighbor || neighbor->active())
368 const Point & direction,
369 const Elem *
const elem,
370 const unsigned short v0,
371 const unsigned short v1,
372 const unsigned short v2,
373 Real & intersection_distance,
376#ifdef DEBUG_RAY_INTERSECTIONS
382 debugRaySimple(
"intersectTriangle() called:");
383 debugRaySimple(
" start = ", start);
384 debugRaySimple(
" direction = ", direction);
385 debugRaySimple(
" elem->id() = ", elem->
id());
386 debugRaySimple(
" v0 = ", v0,
" at ", elem->
point(v0));
387 debugRaySimple(
" v1 = ", v1,
" at ", elem->
point(v1));
388 debugRaySimple(
" v2 = ", v2,
" at ", elem->
point(v2));
389 debugRaySimple(
" hmax = ", hmax);
390 mooseAssert(elem->
is_vertex(v0),
"Not a vertex");
391 mooseAssert(elem->
is_vertex(v1),
"Not a vertex");
392 mooseAssert(elem->
is_vertex(v2),
"Not a vertex");
397 const auto inv_hmax = 1.0 / hmax;
399 const auto & v0_point = elem->
point(v0);
401 const auto edge1 = (elem->
point(v1) - v0_point) * inv_hmax;
402 const auto edge2 = (elem->
point(v2) - v0_point) * inv_hmax;
404 const auto pvec = direction.
cross(edge2);
406 auto det = edge1 * pvec;
407 debugRaySimple(
" det = ", det);
410 debugRaySimple(
"intersectTriangle() did not intersect: det < tol");
414 const auto tvec = (start - v0_point) * inv_hmax;
415 const auto u = tvec * pvec;
416 debugRaySimple(
" u = ", u);
417 debugRaySimple(
" u / det = ", u / det);
420 debugRaySimple(
"intersectTriangle() did not intersect: u out of range");
424 const auto qvec = tvec.cross(edge1);
425 const auto v = direction * qvec;
426 debugRaySimple(
" v = ",
v);
427 debugRaySimple(
" v / det = ",
v / det);
428 debugRaySimple(
" (u + v) / det = ", (u +
v) / det);
431 debugRaySimple(
"intersectTriangle() did not intersect: v out of range");
435 const auto possible_distance = (edge2 * qvec) / det;
436 debugRaySimple(
" possible_distance = ", possible_distance);
439 debugRaySimple(
"intersectTriangle() did not intersect: distance too small");
445 intersection_distance = possible_distance * hmax;
456 intersected_extrema.
setEdge(v0, v2);
463 intersected_extrema.
setEdge(v0, v1);
466 intersected_extrema.
setEdge(v1, v2);
468 debugRaySimple(
"intersectTriangle() intersected with:");
469 debugRaySimple(
" intersection_distance = ", intersection_distance);
470 debugRaySimple(
" intersected_extrema = ", intersected_extrema);
477 const Point & direction,
478 const Elem *
const elem,
479 const unsigned short v00,
480 const unsigned short v10,
481 const unsigned short v11,
482 const unsigned short v01,
483 Real & intersection_distance,
486#ifdef DEBUG_RAY_INTERSECTIONS
492 mooseAssert(intersected_extrema.
isInvalid(),
"Should be invalid");
493 debugRaySimple(
"intersectQuad() called:");
494 debugRaySimple(
" start = ", start);
495 debugRaySimple(
" direction = ", direction);
496 debugRaySimple(
" elem->id() = ", elem->
id());
497 debugRaySimple(
" v00 = ", v00,
" at ", elem->
point(v00));
498 debugRaySimple(
" v10 = ", v10,
" at ", elem->
point(v10));
499 debugRaySimple(
" v11 = ", v11,
" at ", elem->
point(v11));
500 debugRaySimple(
" v01 = ", v01,
" at ", elem->
point(v01));
516 intersection_distance,
519#ifdef DEBUG_RAY_INTERSECTIONS
532 intersection_distance,
535#ifdef DEBUG_RAY_INTERSECTIONS
544 if (intersects && intersected_extrema.
atEdge(v00, v11))
577 const Real tolerance )
579 mooseAssert(extrema.
isInvalid(),
"Should be invalid");
581 for (
int e = 0; e < T::num_edges; ++e)
583 elem->
point(T::edge_nodes_map[e][1]),
587 extrema.
setEdge(T::edge_nodes_map[e][0], T::edge_nodes_map[e][1]);
598 const Real tolerance )
600 switch (elem->
type())
605 return withinEdgeTempl<Hex8>(elem, point, extrema, tolerance);
609 return withinEdgeTempl<Tet4>(elem, point, extrema, tolerance);
613 return withinEdgeTempl<Pyramid5>(elem, point, extrema, tolerance);
617 return withinEdgeTempl<Prism6>(elem, point, extrema, tolerance);
621 " not supported in TraceRayTools::withinEdge()");
630 switch (elem->
type())
635 return atVertexOnSideTempl<Hex8>(elem, point, side);
639 return atVertexOnSideTempl<Quad4>(elem, point, side);
643 return atVertexOnSideTempl<Tri3>(elem, point, side);
647 return atVertexOnSideTempl<Tet4>(elem, point, side);
651 return atVertexOnSideTempl<Pyramid5>(elem, point, side);
655 return atVertexOnSideTempl<Prism6>(elem, point, side);
659 return atVertexOnSideTempl<Edge2>(elem, point, side);
663 " not supported in TraceRayTools::atVertexOnSide()");
670typename std::enable_if<!std::is_base_of<Edge, T>::value,
unsigned short>::type
673 mooseAssert(side < elem->n_sides(),
"Invalid side");
675 "Side does not contain point");
677 for (
int i = 0; i < nodesPerSide<T>(side); ++i)
679 return T::side_nodes_map[side][i];
685typename std::enable_if<std::is_base_of<Edge, T>::value,
unsigned short>::type
688 mooseAssert(side < elem->n_sides(),
"Invalid side");
690 "Side does not contain point");
701 const unsigned short side,
704 switch (elem->
type())
709 return withinEdgeOnSideTempl<Hex8>(elem, point, side, extrema);
713 return withinEdgeOnSideTempl<Tet4>(elem, point, side, extrema);
717 return withinEdgeOnSideTempl<Pyramid5>(elem, point, side, extrema);
721 return withinEdgeOnSideTempl<Prism6>(elem, point, side, extrema);
725 " not supported in TraceRayTools::withinEdgeOnSide()");
732typename std::enable_if<std::is_base_of<Cell, T>::value,
bool>::type
735 const unsigned short side,
738 mooseAssert(side < elem->n_sides(),
"Invalid side");
740 "Side does not contain point");
741 mooseAssert(extrema.
isInvalid(),
"Should be invalid");
743 int last_n = T::side_nodes_map[side][nodesPerSide<T>(side) - 1];
745 for (
int side_v = 0; side_v < nodesPerSide<T>(side); ++side_v)
748 extrema.
setEdge(last_n, T::side_nodes_map[side][side_v]);
750 "Edge doesn't contain point");
754 last_n = T::side_nodes_map[side][side_v];
762 const unsigned short side,
763 const unsigned int dim,
766 mooseAssert(extrema.
isInvalid(),
"Extrema should be invalid");
767 mooseAssert(
dim == elem->
dim(),
"Incorrect dim");
780 const Point & segment2,
782 const Real tolerance )
786 const auto segment_length = (segment1 - segment2).norm();
787 return isWithinSegment(segment1, segment2, segment_length, point, tolerance);
792 const Point & segment2,
793 const Real segment_length,
795 const Real tolerance )
798 mooseAssert(MooseUtils::absoluteFuzzyEqual((segment1 - segment2).norm(), segment_length),
799 "Invalid segment length");
801 const auto diff1 = point - segment1;
802 const auto diff2 = point - segment2;
804 if (diff1 * diff2 > tolerance * segment_length)
807 return std::abs(diff1.norm() + diff2.norm() - segment_length) < tolerance * segment_length;
813 const unsigned int dim,
814 const Real tolerance)
816 for (
unsigned int d = 0;
d <
dim; ++
d)
817 if (MooseUtils::absoluteFuzzyEqual(point(
d), bbox.
min()(
d), tolerance) ||
818 MooseUtils::absoluteFuzzyEqual(point(
d), bbox.
max()(
d), tolerance))
void mooseError(Args &&... args)
bool contains(const T &value) const
const Point & max() const
const Point & min() const
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const=0
virtual unsigned int n_vertices() const=0
const Point & point(const unsigned int i) const
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
const Elem * child_ptr(unsigned int i) const
unsigned int which_neighbor_am_i(const Elem *e) const
void find_point_neighbors(const Point &p, std::set< const Elem * > &neighbor_set) const
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
virtual unsigned short dim() const=0
unsigned int level() const
virtual bool is_vertex(const unsigned int i) const=0
virtual unsigned int n_children() const=0
unsigned int get_node_index(const Node *node_ptr) const
virtual ElemType type() const=0
const Elem * neighbor_ptr(unsigned int i) const
bool absolute_fuzzy_equals(const TypeVector< Real > &rhs, Real tol=TOLERANCE) const
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
static const unsigned short invalid_vertex
Identifier for an invalid vertex index.
std::string enum_to_string(const T e)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
const unsigned int invalid_uint
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Helper for defining if at an element's edge, vertex, or neither.
std::unique_ptr< const libMesh::Elem > buildEdge(const Elem *elem) const
void invalidate()
Invalidates the current state.
void setVertex(const unsigned short vertex)
Sets the "at vertex" state.
void setEdge(const unsigned short v1, const unsigned short v2)
Sets the "at edge" state.