DHART
Loading...
Searching...
No Matches
graph_generator.cpp
Go to the documentation of this file.
1
6
7#define NOMINMAX
8#include <graph_generator.h>
9#include <Constants.h>
10#include <node.h>
11#include <Edge.h>
12#include <graph.h>
13#include <robin_hood.h>
14#include <omp.h>
15
16#include <unique_queue.h>
17
18#include <iostream>
19#include <thread>
20
26
27using std::vector;
29
35 inline void SetupCoreCount(int cores = -1) {
36 if (cores > 1) omp_set_num_threads(cores);
37 else omp_set_num_threads(std::thread::hardware_concurrency());
38 }
39
49 template <typename raytracer_type>
50 inline void setupRT(GraphGenerator* gg, raytracer_type & rt, const std::vector<int> & obs_ids, const std::vector<int> & walk_ids ) {
52 gg->params.geom_ids.SetGeometryIds(obs_ids, walk_ids);
53 }
54
55 GraphGenerator::GraphGenerator(HF::RayTracer::EmbreeRayTracer & rt, const vector<int> & obstacle_ids, const vector<int> & walkable_ids){
56 setupRT<HF::RayTracer::EmbreeRayTracer> (this, rt, obstacle_ids, walkable_ids);
57 }
58
59 GraphGenerator::GraphGenerator(HF::RayTracer::NanoRTRayTracer & rt, const vector<int> & obstacle_ids, const vector<int> & walkable_ids) {
60 setupRT<HF::RayTracer::NanoRTRayTracer> (this, rt, obstacle_ids, walkable_ids);
61 }
62
63 GraphGenerator::GraphGenerator(HF::RayTracer::MultiRT & ray_tracer, const vector<int> & obstacle_ids, const vector<int> & walkable_ids)
64 {
65 this->ray_tracer = ray_tracer;
66 this->params.geom_ids.SetGeometryIds(obstacle_ids, walkable_ids);
67 }
68
70 const real3& start_point,
71 const real3& Spacing,
72 int MaxNodes,
73 real_t UpStep,
74 real_t UpSlope,
75 real_t DownStep,
76 real_t DownSlope,
77 int max_step_connections,
78 int min_connections,
79 int cores,
80 real_t node_z_precision,
81 real_t node_spacing_precision,
82 real_t ground_offset)
83 {
84 if (ground_offset < node_z_precision)
85 {
86 std::cerr << "Ground offset is less than z-precision. Setting node offset to Z-Precision." << std::endl;
87 ground_offset = node_z_precision;
88 //std::logic_error("Ground offset is less than Z-Precision");
89 }
90
91 // Store parameters in params
92 params.down_step = DownStep; params.up_step = UpStep;
93 params.up_slope = UpSlope; params.down_slope = DownSlope;
94
95 params.precision.node_z = node_z_precision;
96 params.precision.node_spacing = node_spacing_precision;
97 params.precision.ground_offset = ground_offset;
98
99 // Store class members
100 this->max_nodes = MaxNodes;
101 this->spacing = Spacing;
102 this->core_count = cores;
103 this->max_step_connection = max_step_connections;
104 this->min_connections = min_connections;
105
106 // Take the user defined start point and round it to the precision
107 // that the dhart package can handle.
108 real3 start = real3{
109 roundhf_tmp<real_t>(start_point[0], params.precision.node_spacing),
110 roundhf_tmp<real_t>(start_point[1], params.precision.node_spacing),
111 roundhf_tmp<real_t>(start_point[2], params.precision.node_z)
112 };
113
114 // Define a queue to use for determining what nodes need to be checked
115 UniqueQueue to_do_list;
116 optional_real3 checked_start = ValidateStartPoint(ray_tracer, start, this->params);
117
118 // Check if the start raycast connected.
119 if (checked_start)
120 {
121 // Overwrite start with the checked start point
122 start = *checked_start;
123
124 // add it to the to-do list
125 to_do_list.PushAny(start);
126
127 // If no connection was found, return an empty graph
128 if (this->core_count != 0 && this->core_count != 1)
129 {
131 return CrawlGeomParallel(to_do_list);
132 }
133 // Run the single core version of the graph generator
134 else
135 return CrawlGeom(to_do_list);
136 }
137 else
138 return Graph();
139 }
140
142 {
143 // Generate the set of directions to use for each set of possible children
144 // Uses the maximum connection defined by the user
145 const auto directions = CreateDirecs(max_step_connection);
146
147 // Initialize a tracker for the number of nodes that can be compared to the max nodes limit
148 int num_nodes = 0;
149
150 RayTracer & rt_ref = this->ray_tracer;
151
152 Graph G;
153 // Iterate through every node int the todo-list while it does not reach the maximum number of nodes limit
154 while (!todo.empty() && (num_nodes < max_nodes || max_nodes < 0))
155 {
156 // Pop nodes from the todo list (If max_nodes will be exceeded, then
157 // only pop as many as are left in max_nodes.)
158 int to_do_count = todo.size();
159 if (max_nodes > 0)
160 to_do_count = std::min(todo.size(), max_nodes - num_nodes);
161
162 // Get as many nodes as possible out of the queue
163 auto to_be_done = todo.popMany(to_do_count);
164
165 // If this happens, that means something is wrong with the algorithm
166 // since to_be_done with a size of zero would just cause the outer
167 // while loop to not run anymore.
168 assert(to_be_done.size() > 0);
169
170 // Create array arrays of edges that will be used to store results
171 vector<vector<Edge>> OutEdges(to_do_count);
172
173 // Compute valid children for every node in parallel.
174 #pragma omp parallel for schedule(dynamic) if (to_be_done.size() > 100)
175 for (int i = 0; i < to_do_count; i++)
176 {
177 // Get the parent node from the todo list at index i
178 // and cast it to a real3
179 const Node& n = to_be_done[i];
180 const auto real_parent = CastToReal3(n);
181
182 // Generate children around this parent
183 const std::vector<real3> children = GeneratePotentialChildren(
184 real_parent,
185 directions,
186 spacing,
187 params
188 );
189
190 // Calculate valid edges for this parent and store them in
191 // the edges array at it's index
192 OutEdges[i] = GetChildren(
193 real_parent,
194 children,
195 rt_ref,
196 params
197 );
198 }
199
200 // Go through each edge array we just calculated, then
201 // add the edges to the graph and todo list in sequence
202 for (int i = 0; i < to_do_count; i++) {
203
204 // Only continue if there are edges for this node and the number of edges is the minimum desired
205 if (!OutEdges[i].empty() && OutEdges[i].size() >= this->min_connections) {
206
207 // Iterate through each edge and add it to the graph / todolist
208 for (const auto& e : OutEdges[i]) {
209 todo.push(e.child);
210 G.addEdge(to_be_done[i], e.child, e.score);
211 }
212
213 // Increment max nodes
214 num_nodes++;
215 }
216 }
217 }
218
219 return G;
220 }
221
223 {
224 // Create directions
225 const auto directions = CreateDirecs(this->max_step_connection);
226
227 // Cast this to a reference to avoid dereferencing every time
228 RayTracer& rt_ref = this->ray_tracer;
229
230 int num_nodes = 0;
231 Graph G;
232 while (!todo.empty() && (num_nodes < this->max_nodes || this->max_nodes < 0)) {
233
234 // Get the parent node from the todo list
235 const auto parent = todo.pop();
236
237 // To maintain our precision standards, we'll convert this node to a real3.
238 const auto real_parent = CastToReal3(parent);
239
240 // Generate children from parent
241 const std::vector<real3> children = GeneratePotentialChildren(
242 real_parent,
243 directions,
244 spacing,
245 params
246 );
247
248 // Create edges
249 std::vector<graph_edge> OutEdges = GetChildren(
250 real_parent,
251 children,
252 rt_ref,
253 params
254 );
255
256 // Make
257 if (!OutEdges.empty() && OutEdges.size() >= this->min_connections)
258 {
259
260 // Add new nodes to the queue. It'll drop them if they
261 // already were evaluated, or already existed on the queue
262 for (auto edge : OutEdges)
263 todo.PushAny(edge.child);
264
265 // Add new edges to the graph
266 if (!OutEdges.empty())
267 for (const auto& edge : OutEdges)
268 G.addEdge(parent, edge.child, edge.score);
269
270 // Increment node count
271 num_nodes++;
272 }
273 }
274 return G;
275 }
276}
Contains declarations for all functions related to the graph generator.
Contains definitions for the UniqueQueue class.
Contains definitions for the HF::SpatialStructures namespace.
Contains definitions for the Edge structure.
Contains definitions for the Graph class.
Contains definitions for the Node structure.
Generate a graph of accessible space from a given start point.
real_t up_step
Maximum height of a step the graph can traverse.Any steps higher this will be considered inaccessible...
void setupRT(GraphGenerator *gg, raytracer_type &rt, const std::vector< int > &obs_ids, const std::vector< int > &walk_ids)
Converts the raytracer to a multiRT if required, then map geometry ids to hitflags.
std::vector< real3 > GeneratePotentialChildren(const real3 &parent, const std::vector< pair > &direcs, const real3 &spacing, const GraphParams &gp)
Populare out_children with a potential child position for every direction in directions.
real_t ground_offset
Distance to offset nodes from the ground before checking line of sight.
real3 CastToReal3(real_3_type t)
Cast an array of 3 values to the graph_generator's real_3 type.
GeometryFlagMap geom_ids
Stores a map of geometry IDs to their HIT_FLAGS and the current filter mode of the graph.
real_t node_z
Precision to round the z-component of nodes after a raycast is performed.
real_t down_slope
The maximum downward slope the graph can traverse. Any slopes steeper than this will be considered in...
std::array< real_t, 3 > real3
Type used for the standard coordinate set of the graph generator.
optional_real3 ValidateStartPoint(RayTracer &RT, const real3 &start_point, const GraphParams &Params)
Determine if the start point of the graph is over valid ground.
std::vector< graph_edge > GetChildren(const real3 &parent, const std::vector< real3 > &possible_children, RayTracer &rt, const GraphParams &GP)
Calculate all possible edges between parent and possible_children.
real_t node_spacing
Precision to round nodes after spacing is calculated.
real_t down_step
Maximum step down the graph can traverse.Any steps steeper than this will be considered inaccessible.
real_t up_slope
Maximum upward slope the graph can traverse in degrees.Any slopes steeper than this will be considere...
std::vector< pair > CreateDirecs(int max_step_connections)
Create a set of directions based on max_step_connections.
Precision precision
Tolerances for the graph.
void SetupCoreCount(int cores=-1)
Sets the core count of OpenMP.
constexpr numeric_type roundhf_tmp(numeric_type f, numeric_type p, numeric_type r)
round a number to the nearest precision defined globally. The global values can be overridden with op...
Definition: Constants.h:114
constexpr numeric_type trunchf_tmp(numeric_type f, numeric_type p, numeric_type r)
truncate a number to the nearest precision defined globally. The global values can be overridden with...
Definition: Constants.h:170
Manages rules and ids for different types of geometry in the graph generator.
void SetGeometryIds(const std::vector< int > &obstacle_geometry, const std::vector< int > &walkable_geometry)
Set geometry ids as being walkable or obstacles.
A simple wrapper for real3 that is able to determine whether or not it's defined.
Generate a graph of accessible space from a given start point.
int core_count
Number of cores to use for graph generation.
SpatialStructures::Graph IMPL_BuildNetwork(const real3 &start_point, const real3 &Spacing, int MaxNodes, real_t UpStep, real_t UpSlope, real_t DownStep, real_t DownSlope, int max_step_connections, int min_connections, int cores=-1, real_t node_z_precision=default_z_precision, real_t node_spacing_precision=default_spacing_precision, real_t ground_offset=default_ground_offset)
Generate a graph of accessible space.
RayTracer ray_tracer
A pointer to the raytracer to use for ray intersections.
int max_nodes
Maximum number of nodes to generate. If less than zero, generate nodes without a limit.
GraphParams params
Parameters to run the graph generator.
int max_step_connection
Multiplier for number of children to generate. The higher this is, the more directions there will be.
SpatialStructures::Graph CrawlGeomParallel(UniqueQueue &todo)
Perform breadth first search to populate the graph with nodes and edges using multiple cores.
real3 spacing
Spacing between nodes. New nodes will be generated with atleast this much distance between them.
int min_connections
Minimum number of step connections for a node to be valid (minimum out degree of node)
SpatialStructures::Graph CrawlGeom(UniqueQueue &todo)
Perform breadth first search to populate the graph with with nodes and edges.
A queue that remembers every object inserted, and prevents the addition of nodes that have already be...
Definition: unique_queue.h:29
bool PushAny(const arr_type &node)
Call push with any type of object.
Definition: unique_queue.h:118
HF::SpatialStructures::Node pop()
Remove the topmost node from the queue and return it.
int size() const
Determine how many nodes are currently in the queue.
bool empty() const
Tell if the queue is empty.
bool push(const HF::SpatialStructures::Node &p)
Add a node to the queue if it has never previously been in the queue.
std::vector< SpatialStructures::Node > popMany(int max=-1)
Pop a set amount of nodes from the queue, and return them as a vector.
A wrapper for Intel's Embree Library.
A connection to a child node.
Definition: Edge.h:29
A Graph of nodes connected by edges that supports both integers and HF::SpatialStructures::Node.
Definition: graph.h:486
void addEdge(const Node &parent, const Node &child, float score=1.0f, const std::string &cost_type="")
Add a new edge to the graph from parent to child.
A point in space with an ID.
Definition: node.h:38