https://mooseframework.inl.gov
RayTracing.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 // Moose includes
11 #include "RayTracing.h"
12 #include "LineSegment.h"
13 #include "MooseError.h"
14 
15 #include "libmesh/plane.h"
16 #include "libmesh/point.h"
17 #include "libmesh/mesh.h"
18 #include "libmesh/elem.h"
19 
20 using namespace libMesh;
21 
22 namespace Moose
23 {
24 
35 int
37  std::vector<int> & not_side,
38  const LineSegment & line_segment,
39  Point & intersection_point)
40 {
41  unsigned int n_sides = elem->n_sides();
42 
43  // Whether or not they intersect
44  bool intersect = false;
45 
46  unsigned int dim = elem->dim();
47 
48  for (unsigned int i = 0; i < n_sides; i++)
49  {
50  // Don't search the "not_side"
51  // Note: A linear search is fine here because this vector is going to be < n_sides
52  if (std::find(not_side.begin(), not_side.end(), static_cast<int>(i)) != not_side.end())
53  continue;
54 
55  // Get a simplified side element
56  std::unique_ptr<const Elem> side_elem = elem->side_ptr(i);
57 
58  if (dim == 3)
59  {
60  // Make a plane out of the first three nodes on the side
61  Plane plane(side_elem->point(0), side_elem->point(1), side_elem->point(2));
62 
63  // See if they intersect
64  intersect = line_segment.intersect(plane, intersection_point);
65  }
66  else if (dim == 2)
67  {
68  // Make a Line Segment out of the first two nodes on the side
69  LineSegment side_segment(side_elem->point(0), side_elem->point(1));
70 
71  // See if they intersect
72  intersect = line_segment.intersect(side_segment, intersection_point);
73  }
74  else // 1D
75  {
76  // See if the line segment contains the point
77  intersect = line_segment.contains_point(side_elem->point(0));
78 
79  // If it does then save off that one point as the intersection point
80  if (intersect)
81  intersection_point = side_elem->point(0);
82  }
83 
84  if (intersect)
85  {
86  if (side_elem->contains_point(intersection_point))
87  {
88  const Elem * neighbor = elem->neighbor_ptr(i);
89 
90  // If this side is on a boundary, let's do another search and see if we can find a better
91  // candidate
92  if (!neighbor)
93  {
94  not_side.push_back(i); // Make sure we don't find this side again
95 
96  int better_side = sideIntersectedByLine(elem, not_side, line_segment, intersection_point);
97 
98  if (better_side != -1)
99  return better_side;
100  }
101 
102  return i;
103  }
104  }
105  }
106 
107  // Didn't find one
108  return -1;
109 }
110 
116 int
117 sideNeighborIsOn(const Elem * elem, const Elem * neighbor)
118 {
119  unsigned int n_sides = elem->n_sides();
120 
121  for (unsigned int i = 0; i < n_sides; i++)
122  {
123  if (elem->neighbor_ptr(i) == neighbor)
124  return i;
125  }
126 
127  return -1;
128 }
129 
145 void
147  const Elem * current_elem,
148  int incoming_side,
149  const Point & incoming_point,
150  std::vector<Elem *> & intersected_elems,
151  std::vector<LineSegment> & segments)
152 {
153  Point intersection_point;
154 
155  std::vector<int> not_side(1, incoming_side);
156 
157  // Find the side of this element that the LineSegment intersects... while ignoring the incoming
158  // side (we don't want to move backward!)
159  int intersected_side =
160  sideIntersectedByLine(current_elem, not_side, line_segment, intersection_point);
161 
162  if (intersected_side != -1) // -1 means that we didn't find any side
163  {
164  // Get the neighbor on that side
165  const Elem * neighbor = current_elem->neighbor_ptr(intersected_side);
166 
167  if (neighbor)
168  {
169  // Add it to the list
170  intersected_elems.push_back(const_cast<Elem *>(neighbor));
171 
172  // Add the line segment across the element to the segments list
173  segments.push_back(LineSegment(incoming_point, intersection_point));
174 
175  // Note: This is finding the side the current_elem is on for the neighbor. That's the
176  // "incoming_side" for the neighbor
177  int incoming_side = sideNeighborIsOn(neighbor, current_elem);
178 
179  // Recurse
181  line_segment, neighbor, incoming_side, intersection_point, intersected_elems, segments);
182  }
183  else // Add the final segment
184  segments.push_back(LineSegment(incoming_point, line_segment.end()));
185  }
186  else // Add the final segment
187  segments.push_back(LineSegment(incoming_point, line_segment.end()));
188 
189  // Finished... return out!
190  return;
191 }
192 
193 void
195  const Point & p1,
196  const MeshBase & /*mesh*/,
197  const PointLocatorBase & point_locator,
198  std::vector<Elem *> & intersected_elems,
199  std::vector<LineSegment> & segments)
200 {
201  // Make sure our list is clear
202  intersected_elems.clear();
203 
204  // Find the starting element
205  const Elem * first_elem = point_locator(p0);
206 
207  // Quick return if can't even locate the first element.
208  if (!first_elem)
209  return;
210 
211  intersected_elems.push_back(const_cast<Elem *>(first_elem));
212 
213  // Make a LineSegment object out of our two points for ease:
214  LineSegment line_segment = LineSegment(p0, p1);
215 
216  // Find 'em!
218  line_segment, first_elem, -1, p0, intersected_elems, segments);
219 }
220 }
const Point & end() const
Ending of the line segment.
Definition: LineSegment.h:67
void elementsIntersectedByLine(const Point &p0, const Point &p1, const MeshBase &, const PointLocatorBase &point_locator, std::vector< Elem *> &intersected_elems, std::vector< LineSegment > &segments)
Definition: RayTracing.C:194
int sideNeighborIsOn(const Elem *elem, const Elem *neighbor)
Returns the side number for elem that neighbor is on.
Definition: RayTracing.C:117
The LineSegment class is used by the LineMaterialSamplerBase class and for some ray tracing stuff...
Definition: LineSegment.h:28
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:153
void recursivelyFindElementsIntersectedByLine(const LineSegment &line_segment, const Elem *current_elem, int incoming_side, const Point &incoming_point, std::vector< Elem *> &intersected_elems, std::vector< LineSegment > &segments)
Recursively find all elements intersected by a line segment.
Definition: RayTracing.C:146
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
bool intersect(const libMesh::Plane &pl, Point &intersect_p) const
Definition: LineSegment.C:66
bool first_elem
Definition: InfixIterator.h:35
bool contains_point(const Point &p) const
Determines whether a point is in a line segment or not.
Definition: LineSegment.C:59
virtual unsigned int n_sides() const=0
const Elem * neighbor_ptr(unsigned int i) const
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
virtual unsigned short dim() const=0
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
int sideIntersectedByLine(const Elem *elem, std::vector< int > &not_side, const LineSegment &line_segment, Point &intersection_point)
Figure out which (if any) side of an Elem is intersected by a line.
Definition: RayTracing.C:36