OGS
findElementsWithinRadius.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <set>
7#include <unordered_set>
8#include <vector>
9
10#include "Elements/Element.h"
11#include "MathLib/MathTools.h"
12#include "Node.h"
13
14namespace MeshLib
15{
16std::vector<std::size_t> findElementsWithinRadius(Element const& start_element,
17 double const radius_squared)
18{
19 // Special case for 0 radius. All other radii will include at least one
20 // neighbor of the start element.
21 if (radius_squared == 0.)
22 {
23 return {start_element.getID()};
24 }
25
26 // Collect start element node coordinates into local contigiuos memory.
27 std::vector<MathLib::Point3d> start_element_nodes;
28 {
29 auto const start_element_n_nodes = start_element.getNumberOfNodes();
30 start_element_nodes.reserve(start_element_n_nodes);
31 for (unsigned n = 0; n < start_element_n_nodes; ++n)
32 {
33 start_element_nodes.push_back(*start_element.getNode(n));
34 }
35 }
36
37 // Returns true if the test node is inside the radius of any of the
38 // element's nodes.
39 auto node_inside_radius =
40 [&start_element_nodes, radius_squared](Node const* test_node)
41 {
42 return std::any_of(
43 start_element_nodes.begin(), start_element_nodes.end(),
44 [test_node, &radius_squared](auto const node)
45 { return MathLib::sqrDist(*test_node, node) <= radius_squared; });
46 };
47
48 // Returns true if any of the test element's nodes is inside the start
49 // element's radius.
50 auto element_in_radius = [&node_inside_radius](Element const& element)
51 {
52 auto const n_nodes = element.getNumberOfNodes();
53 for (unsigned i = 0; i < n_nodes; ++i)
54 {
55 if (node_inside_radius(element.getNode(i)))
56 {
57 return true;
58 }
59 }
60 return false;
61 };
62
63 std::set<std::size_t> found_elements;
64 std::vector<Element const*> neighbors_to_visit;
65 std::unordered_set<std::size_t> visited_elements;
66
67 auto mark_visited_and_add_neighbors =
68 [&found_elements, &neighbors_to_visit, &visited_elements](
69 Element const& element)
70 {
71 found_elements.insert(element.getID());
72 visited_elements.insert(element.getID());
73 auto const n_neighbors = element.getNumberOfNeighbors();
74 for (unsigned n = 0; n < n_neighbors; ++n)
75 {
76 auto neighbor = element.getNeighbor(n);
77 if (neighbor == nullptr)
78 {
79 continue;
80 }
81 auto x = visited_elements.find(neighbor->getID());
82 if (x != visited_elements.end())
83 {
84 continue;
85 }
86
87 neighbors_to_visit.push_back(neighbor);
88
89 visited_elements.insert(neighbor->getID());
90 }
91 };
92
93 // The result always contains the starting element.
94 mark_visited_and_add_neighbors(start_element);
95
96 while (!neighbors_to_visit.empty())
97 {
98 auto const& current_element = *neighbors_to_visit.back();
99 neighbors_to_visit.pop_back();
100
101 // If any node is inside the radius, all neighbors are visited.
102 if (element_in_radius(current_element))
103 {
104 mark_visited_and_add_neighbors(current_element);
105 }
106 }
107
108 return {std::begin(found_elements), std::end(found_elements)};
109}
110} // namespace MeshLib
virtual unsigned getNumberOfNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
std::size_t getID() const
Returns the ID of the element.
Definition Element.h:80
std::vector< std::size_t > findElementsWithinRadius(Element const &start_element, double const radius_squared)