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