LCOV - code coverage report
Current view: top level - src/utils - RayTracing.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 58 60 96.7 %
Date: 2025-07-17 01:28:37 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      25             : /**
      26             :  * Figure out which (if any) side of an Elem is intersected by a line.
      27             :  *
      28             :  * @param elem The elem to search
      29             :  * @param not_side Sides to _not_ search (Use -1 if you want to search all sides)
      30             :  * @param intersection_point If an intersection is found this will be filled with the x,y,z position
      31             :  * of that intersection
      32             :  * @return The side that is intersected by the line.  Will return -1 if it doesn't intersect any
      33             :  * side
      34             :  */
      35             : int
      36         498 : sideIntersectedByLine(const Elem * elem,
      37             :                       std::vector<int> & not_side,
      38             :                       const LineSegment & line_segment,
      39             :                       Point & intersection_point)
      40             : {
      41         498 :   unsigned int n_sides = elem->n_sides();
      42             : 
      43             :   // Whether or not they intersect
      44         498 :   bool intersect = false;
      45             : 
      46         498 :   unsigned int dim = elem->dim();
      47             : 
      48        1661 :   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        1575 :     if (std::find(not_side.begin(), not_side.end(), static_cast<int>(i)) != not_side.end())
      53         405 :       continue;
      54             : 
      55             :     // Get a simplified side element
      56        1170 :     std::unique_ptr<const Elem> side_elem = elem->side_ptr(i);
      57             : 
      58        1170 :     if (dim == 3)
      59             :     {
      60             :       // Make a plane out of the first three nodes on the side
      61         572 :       Plane plane(side_elem->point(0), side_elem->point(1), side_elem->point(2));
      62             : 
      63             :       // See if they intersect
      64         572 :       intersect = line_segment.intersect(plane, intersection_point);
      65         572 :     }
      66         598 :     else if (dim == 2)
      67             :     {
      68             :       // Make a Line Segment out of the first two nodes on the side
      69         345 :       LineSegment side_segment(side_elem->point(0), side_elem->point(1));
      70             : 
      71             :       // See if they intersect
      72         345 :       intersect = line_segment.intersect(side_segment, intersection_point);
      73         345 :     }
      74             :     else // 1D
      75             :     {
      76             :       // See if the line segment contains the point
      77         253 :       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         253 :       if (intersect)
      81         209 :         intersection_point = side_elem->point(0);
      82             :     }
      83             : 
      84        1170 :     if (intersect)
      85             :     {
      86         412 :       if (side_elem->contains_point(intersection_point))
      87             :       {
      88         412 :         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         412 :         if (!neighbor)
      93             :         {
      94          22 :           not_side.push_back(i); // Make sure we don't find this side again
      95             : 
      96          22 :           int better_side = sideIntersectedByLine(elem, not_side, line_segment, intersection_point);
      97             : 
      98          22 :           if (better_side != -1)
      99          11 :             return better_side;
     100             :         }
     101             : 
     102         401 :         return i;
     103             :       }
     104             :     }
     105        1170 :   }
     106             : 
     107             :   // Didn't find one
     108          86 :   return -1;
     109             : }
     110             : 
     111             : /**
     112             :  * Returns the side number for elem that neighbor is on
     113             :  *
     114             :  * Returns -1 if the neighbor can't be found to be a neighbor
     115             :  */
     116             : int
     117         390 : sideNeighborIsOn(const Elem * elem, const Elem * neighbor)
     118             : {
     119         390 :   unsigned int n_sides = elem->n_sides();
     120             : 
     121         471 :   for (unsigned int i = 0; i < n_sides; i++)
     122             :   {
     123         471 :     if (elem->neighbor_ptr(i) == neighbor)
     124         390 :       return i;
     125             :   }
     126             : 
     127           0 :   return -1;
     128             : }
     129             : 
     130             : /**
     131             :  * Recursively find all elements intersected by a line segment
     132             :  *
     133             :  * Works by moving from one element to the next _through_ the side of the current element.
     134             :  * This means that (other than for the first element) there is always an incoming_side
     135             :  * that is the reason we ended up in this element in the first place.  Search all the _other_
     136             :  * sides to see if there is a next element...
     137             :  *
     138             :  * @param line_segment the LineSegment to intersect
     139             :  * @param current_elem The current element that needs to be searched
     140             :  * @param incoming_side The side of the current element that was intersected by the LineSegment that
     141             :  * brought us here
     142             :  * @param intersected_elems The output
     143             :  * @param segments Line segments for the path across each element
     144             :  */
     145             : void
     146         476 : recursivelyFindElementsIntersectedByLine(const LineSegment & line_segment,
     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         476 :   Point intersection_point;
     154             : 
     155         476 :   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         476 :       sideIntersectedByLine(current_elem, not_side, line_segment, intersection_point);
     161             : 
     162         476 :   if (intersected_side != -1) // -1 means that we didn't find any side
     163             :   {
     164             :     // Get the neighbor on that side
     165         401 :     const Elem * neighbor = current_elem->neighbor_ptr(intersected_side);
     166             : 
     167         401 :     if (neighbor)
     168             :     {
     169             :       // Add it to the list
     170         390 :       intersected_elems.push_back(const_cast<Elem *>(neighbor));
     171             : 
     172             :       // Add the line segment across the element to the segments list
     173         390 :       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         390 :       int incoming_side = sideNeighborIsOn(neighbor, current_elem);
     178             : 
     179             :       // Recurse
     180         390 :       recursivelyFindElementsIntersectedByLine(
     181             :           line_segment, neighbor, incoming_side, intersection_point, intersected_elems, segments);
     182             :     }
     183             :     else // Add the final segment
     184          11 :       segments.push_back(LineSegment(incoming_point, line_segment.end()));
     185             :   }
     186             :   else // Add the final segment
     187          75 :     segments.push_back(LineSegment(incoming_point, line_segment.end()));
     188             : 
     189             :   // Finished... return out!
     190         952 :   return;
     191         476 : }
     192             : 
     193             : void
     194          86 : elementsIntersectedByLine(const Point & p0,
     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          86 :   intersected_elems.clear();
     203             : 
     204             :   // Find the starting element
     205          86 :   const Elem * first_elem = point_locator(p0);
     206             : 
     207             :   // Quick return if can't even locate the first element.
     208          86 :   if (!first_elem)
     209           0 :     return;
     210             : 
     211          86 :   intersected_elems.push_back(const_cast<Elem *>(first_elem));
     212             : 
     213             :   // Make a LineSegment object out of our two points for ease:
     214          86 :   LineSegment line_segment = LineSegment(p0, p1);
     215             : 
     216             :   // Find 'em!
     217          86 :   recursivelyFindElementsIntersectedByLine(
     218             :       line_segment, first_elem, -1, p0, intersected_elems, segments);
     219          86 : }
     220             : }

Generated by: LCOV version 1.14