27 using node_t = std::uint32_t;
28 using edge_t = std::uint32_t;
30 static constexpr node_t
const NULL_NODE = std::numeric_limits<node_t>::max();
31 static constexpr edge_t
const NULL_EDGE = std::numeric_limits<edge_t>::max();
32 static constexpr float const NULL_COST = std::numeric_limits<float>::infinity();
33 static constexpr float const NULL_DISTANCE = std::numeric_limits<float>::infinity();
36 struct Node :
public Coord {
42 constexpr Node() =
default;
44 constexpr Node(
Coord const& coord,
float cost) :
Coord(coord), cost(cost) {}
48 node_t node = NULL_NODE;
50 float cost = NULL_COST;
53 constexpr Edge() =
default;
55 constexpr Edge(node_t node,
float cost,
float distance)
63 std::vector<node_t> nodes;
72 [[nodiscard]]
Path plan(node_t start, node_t goal,
float distance_weight = 1.0f,
73 float edge_cost_weight = 1.0f,
float node_cost_weight = 1.0f,
74 float heuristic_weight = 1.0f)
const
76 std::vector<node_t> starts{start};
77 return plan(starts, goal, distance_weight, edge_cost_weight, node_cost_weight,
81 [[nodiscard]] Path plan(std::vector<node_t>
const& starts, node_t goal,
82 float distance_weight = 1.0f,
float edge_cost_weight = 1.0f,
83 float node_cost_weight = 1.0f,
84 float heuristic_weight = 1.0f)
const
86 auto cost_f = [
this, distance_weight, edge_cost_weight,
87 node_cost_weight](edge_t edge) {
88 auto const& e = edges_[edge];
89 auto const& n = nodes_[e.node];
90 return distance_weight * e.distance + edge_cost_weight * e.cost +
91 node_cost_weight * n.cost;
94 return plan(starts, goal, cost_f, heuristic_weight);
97 template <
class CostFun>
98 [[nodiscard]] Path plan(node_t start, node_t goal, CostFun cost_f,
99 float heuristic_weight = 1.0f)
const
101 std::vector<node_t> starts{start};
102 return plan(starts, goal, cost_f, heuristic_weight);
105 template <
class CostFun>
106 [[nodiscard]] Path plan(std::vector<node_t>
const& starts, node_t goal, CostFun cost_f,
107 float heuristic_weight = 1.0f)
const
109 auto heuristic_f = [
this, heuristic_weight](node_t cur, node_t goal) {
110 return heuristic_weight *
ufo::distance(coord(cur), coord(goal));
113 return plan(starts, goal, cost_f, heuristic_f);
116 template <
class CostFun,
class HeuristicFun>
117 [[nodiscard]] Path plan(node_t start, node_t goal, CostFun cost_f,
118 HeuristicFun heuristic_f)
const
120 std::vector<node_t> starts{start};
121 return plan(starts, goal, cost_f, heuristic_f);
124 template <
class CostFun,
class HeuristicFun>
125 [[nodiscard]] Path plan(std::vector<node_t>
const& starts, node_t
const& goal,
126 CostFun cost_f, HeuristicFun heuristic_f)
const
128 assert(!starts.empty());
129 assert(std::all_of(starts.begin(), starts.end(),
130 [
this](node_t n) { return NULL_NODE != n && nodes_.size() > n; }));
131 assert(NULL_NODE != goal && nodes_.size() > goal);
133 auto comp = [](
auto const&
a,
auto const&
b) {
return a.second >
b.second; };
136 std::priority_queue<std::pair<node_t, float>,
137 std::vector<std::pair<node_t, float>>,
decltype(comp)>;
138 using ClosedSet = std::unordered_set<node_t>;
139 using CameFrom = std::unordered_map<node_t, node_t>;
140 using GScore = std::unordered_map<node_t, float>;
147 for (node_t start : starts) {
148 g_score[start] = 0.0f;
149 float f_score = heuristic_f(start, goal);
150 open.emplace(start, f_score);
153 node_t cur = NULL_NODE;
154 while (!open.empty() && goal != (cur = open.top().first)) {
157 if (!closed.insert(cur).second) {
162 Node
const& n = nodes_[cur];
163 float gs = g_score[cur];
164 for (edge_t e = n.first_edge; n.last_edge > e; ++e) {
165 node_t neighbor = edges_[e].node;
167 if (NULL_DISTANCE == edges_[e].distance || 0 < closed.count(neighbor)) {
171 float tentative_g_score = gs + cost_f(e);
172 if (
auto [it, inserted] = g_score.try_emplace(neighbor, tentative_g_score);
173 inserted || tentative_g_score < it->second) {
174 came_from[neighbor] = cur;
175 it->second = tentative_g_score;
176 float f_score = tentative_g_score + heuristic_f(neighbor, goal);
177 open.emplace(neighbor, f_score);
186 path.distance = -1.0f;
190 path.cost = g_score[goal];
193 path.nodes.push_back(goal);
194 for (
auto it = came_from.find(goal); came_from.end() != it;
195 it = came_from.find(path.nodes.back())) {
196 path.nodes.push_back(it->second);
199 std::reverse(path.nodes.begin(), path.nodes.end());
201 for (std::size_t i = 1; path.nodes.size() > i; ++i) {
202 Edge
const& e = edges_[edge(path.nodes[i - 1], path.nodes[i])];
203 path.distance += e.distance;
210 void update(
Map const& map,
float robot_radius)
212 unsigned min_depth{};
213 for (; map.numDepthLevels() > min_depth; ++min_depth) {
214 if (
min(map.length(min_depth)) > robot_radius) {
219 std::vector<TreeIndex> candidate_nodes;
220 auto pred = pred::Free() && pred::Depth() >= min_depth;
221 for (
auto node : map.query(pred)) {
222 candidate_nodes.push_back(node);
225 std::vector<TreeCoord<Dim>> nodes;
226 nodes.reserve(candidate_nodes.size());
227 for (
auto node : candidate_nodes) {
228 auto bb = map.boundingBox(node) + robot_radius;
229 auto p = !pred::Free() && pred::Intersects(bb);
230 for (
auto n : map.query(p)) {
235 map_.clear(map.length(min_depth), map.resolution(min_depth));
237 for (
auto node : nodes) {
238 Coord coord = map.center(node);
239 auto p = !pred::Free() && pred::Intersects(Sphere(coord, robot_radius));
240 for (
auto n : map.query(p)) {
251 void updateModified(
Map const& map)
267 [[nodiscard]] std::size_t numNeighbors(node_t node)
const
269 Node
const& n = nodes_[node];
271 for (edge_t e = n.first_edge; n.last_edge > e; ++e) {
272 if (NULL_DISTANCE != edges_[e].distance) {
279 [[nodiscard]] std::vector<node_t> neighbors(node_t node)
const
281 assert(NULL_NODE != node && nodes_.size() > node);
282 auto const& n = nodes_[node];
283 std::vector<node_t> res;
284 res.reserve(n.last_edge - n.first_edge);
285 for (edge_t e = n.first_edge; n.last_edge > e; ++e) {
286 if (NULL_DISTANCE != edges_[e].distance) {
287 res.push_back(edges_[e].node);
293 [[nodiscard]] Coord
const& coord(node_t node)
const
295 assert(NULL_NODE != node && nodes_.size() > node);
296 return static_cast<Coord const&
>(nodes_[node]);
299 [[nodiscard]]
float& cost(node_t node)
301 assert(NULL_NODE != node && nodes_.size() > node);
302 return nodes_[node].cost;
305 [[nodiscard]]
float cost(node_t node)
const
307 assert(NULL_NODE != node && nodes_.size() > node);
308 return nodes_[node].cost;
311 [[nodiscard]]
float& cost(node_t node, node_t neighbor)
313 auto e = edge(node, neighbor);
314 assert(NULL_EDGE != e);
315 return edges_[e].cost;
318 [[nodiscard]]
float cost(node_t node, node_t neighbor)
const
320 auto e = edge(node, neighbor);
321 assert(NULL_EDGE != e);
322 return edges_[e].cost;
325 [[nodiscard]]
float& distance(node_t node, node_t neighbor)
327 auto e = edge(node, neighbor);
328 assert(NULL_EDGE != e);
329 return edges_[e].distance;
332 [[nodiscard]]
float distance(node_t node, node_t neighbor)
const
334 auto e = edge(node, neighbor);
335 assert(NULL_EDGE != e);
336 return edges_[e].distance;
339 node_t addNode(Coord
const& position,
float cost)
341 node_t node = nodes_.size();
342 nodes_.emplace_back(position, cost);
343 map_.emplace(position, node);
348 bool eraseNode(node_t
const& node)
350 assert(validNode(node));
354 for (
auto it = map_.beginNearest(coord), last = map_.endNearest(); last != it; ++it) {
355 if (it->second == node) {
358 }
else if (it->first != coord) {
380 free_nodes_.push_back(node);
385 bool addEdge(node_t start, node_t end,
float cost = 0.0f)
387 assert(validNode(start));
388 assert(validNode(end));
389 return addEdge(start, end, cost,
ufo::distance(coord(start), coord(end)));
392 bool addEdge(node_t start, node_t end,
float cost,
float distance)
394 assert(validNode(start));
395 assert(validNode(end));
397 edge_t e = edge(end, start);
398 float cost_2 = NULL_EDGE == e ? NULL_COST : edges_[e].cost;
399 float distance_2 = NULL_EDGE == e ? NULL_DISTANCE : edges_[e].distance;
401 return 0 != addBiEdge(start, end, cost, cost_2, distance, distance_2);
404 int addBiEdge(node_t node_1, node_t node_2,
float cost = 0.0f)
406 assert(validNode(node_1));
407 assert(validNode(node_2));
408 return addBiEdge(node_1, node_2, cost,
ufo::distance(coord(node_1), coord(node_2)));
411 int addBiEdge(node_t node_1, node_t node_2,
float cost,
float distance)
413 assert(validNode(node_1));
414 assert(validNode(node_2));
415 return addBiEdge(node_1, node_2, cost, cost, distance, distance);
418 int addBiEdge(node_t node_1, node_t node_2,
float cost_1,
float cost_2,
419 float distance_1,
float distance_2)
421 assert(validNode(node_1));
422 assert(validNode(node_2));
425 num_added += NULL_DISTANCE == distance_1 ? 0 : 1;
426 num_added += NULL_DISTANCE == distance_2 ? 0 : 1;
428 if (
auto e_1 = edge(node_1, node_2); NULL_EDGE != e_1) {
430 edge_t e_2 = edge(node_2, node_1);
431 assert(validEdge(e_2));
433 num_added -= NULL_DISTANCE == edges_[e_1].distance ? 0 : 1;
434 num_added -= NULL_DISTANCE == edges_[e_2].distance ? 0 : 1;
436 edges_[e_1].cost = cost_1;
437 edges_[e_2].cost = cost_2;
438 edges_[e_1].distance = distance_1;
439 edges_[e_2].distance = distance_2;
444 Node& n_1 = nodes_[node_1];
445 Node& n_2 = nodes_[node_2];
447 std::size_t
const s = edges_.size();
448 std::size_t
const s_1 = numEdges(node_1);
449 std::size_t
const s_2 = numEdges(node_2);
451 std::size_t
const a_1 = numAllocatedEdges(node_1);
452 std::size_t
const a_2 = numAllocatedEdges(node_2);
454 std::size_t n_a_1 = a_1;
455 std::size_t n_a_2 = a_2;
457 edge_t e_1_first = n_1.first_edge;
458 edge_t e_2_first = n_2.first_edge;
460 std::size_t num_new_edges{};
465 if (
auto it = free_edges_.find(n_a_1);
466 free_edges_.end() != it && !it->second.empty()) {
467 e_1_first = it->second.back();
468 it->second.pop_back();
471 num_new_edges += n_a_1;
477 if (
auto it = free_edges_.find(n_a_2);
478 free_edges_.end() != it && !it->second.empty()) {
479 e_2_first = it->second.back();
480 it->second.pop_back();
482 e_2_first = e_1_first == s ? s + n_a_1 : s;
483 num_new_edges += n_a_2;
487 if (0 != num_new_edges) {
488 edges_.resize(edges_.size() + num_new_edges);
491 if (e_1_first != n_1.first_edge) {
492 std::copy(edges_.begin() + n_1.first_edge, edges_.begin() + n_1.last_edge,
493 edges_.begin() + e_1_first);
495 free_edges_[a_1].push_back(n_1.first_edge);
497 n_1.first_edge = e_1_first;
499 if (e_2_first != n_2.first_edge) {
500 std::copy(edges_.begin() + n_2.first_edge, edges_.begin() + n_2.last_edge,
501 edges_.begin() + e_2_first);
503 free_edges_[a_2].push_back(n_2.first_edge);
505 n_2.first_edge = e_2_first;
508 n_1.last_edge = e_1_first + s_1 + 1;
509 n_2.last_edge = e_2_first + s_2 + 1;
511 edges_[n_1.last_edge - 1] = Edge{node_2, cost_1, distance_1};
512 edges_[n_2.last_edge - 1] = Edge{node_1, cost_2, distance_2};
517 bool eraseEdge(node_t start, node_t end)
519 assert(validNode(start));
520 assert(validNode(end));
522 if (!isNeighbor(start, end)) {
526 if (isNeighbor(end, start)) {
528 edge_t e = edge(start, end);
529 edges_[e] = Edge{end, NULL_COST, NULL_DISTANCE};
540 int eraseBiEdge(node_t node_1, node_t node_2)
543 num_erased += eraseEdge(node_1, node_2) ? 1 : 0;
544 num_erased += eraseEdge(node_2, node_1) ? 1 : 0;
548 [[nodiscard]] node_t nearestNode(node_t node)
const
550 assert(validNode(node));
551 for (
auto const& [_, n] : map_.nearest(coord(node))) {
560 template <
class Geometry>
561 [[nodiscard]] node_t nearestNode(Geometry
const& geometry)
const
563 for (
auto const& [_, node] : map_.nearest(geometry)) {
569 [[nodiscard]] std::vector<node_t> kNearestNodes(node_t node,
unsigned k)
const
571 assert(validNode(node));
572 std::vector<node_t> res;
574 for (
auto const& [_, n] : map_.nearest(coord(node))) {
587 template <
class Geometry>
588 [[nodiscard]] std::vector<node_t> kNearestNodes(Geometry
const& geometry,
591 std::vector<node_t> res;
593 for (
auto const& [_, node] : map_.nearest(geometry)) {
603 template <
class Geometry>
604 [[nodiscard]] std::vector<node_t> intersectingNodes(Geometry
const& geometry)
const
606 std::vector<node_t> res;
607 for (
auto const& [_, node] : map_.query(pred::Intersects(geometry))) {
613 iterator begin() {
return map_.begin(); }
615 iterator end() {
return map_.end(); }
617 const_iterator begin()
const {
return map_.cbegin(); }
619 const_iterator end()
const {
return map_.cend(); }
621 const_iterator cbegin()
const {
return begin(); }
623 const_iterator cend()
const {
return end(); }
625 [[nodiscard]]
bool validNode(node_t node)
const
627 return NULL_NODE != node && nodes_.size() > node;
630 [[nodiscard]]
bool isNeighbor(node_t node, node_t neighbor)
const
632 edge_t e = edge(node, neighbor);
633 return NULL_EDGE != e && NULL_DISTANCE != edges_[e].distance;
636 [[nodiscard]] std::size_t numNodes()
const {
return num_nodes_; }
638 [[nodiscard]] std::size_t numEdges()
const {
return num_edges_; }
641 [[nodiscard]] edge_t edge(node_t node, node_t neighbor)
const
643 assert(validNode(node));
644 assert(validNode(neighbor));
645 auto const& n = nodes_[node];
646 for (edge_t e = n.first_edge; n.last_edge > e; ++e) {
647 if (edges_[e].node == neighbor) {
654 [[nodiscard]]
bool validEdge(edge_t edge)
const
656 return NULL_EDGE != edge && edges_.size() > edge;
659 [[nodiscard]] std::size_t numEdges(node_t node)
const
661 assert(validNode(node));
662 Node
const& n = nodes_[node];
663 return n.last_edge - n.first_edge;
666 [[nodiscard]] std::size_t numAllocatedEdges(node_t node)
const
668 std::size_t
const s = numEdges(node);
669 return edges_mul_ * ((s + (edges_mul_ - 1)) / edges_mul_);
673 TreeMap<Dim, node_t> map_;
675 std::vector<Node> nodes_;
676 std::vector<Edge> edges_;
678 std::size_t edges_mul_ = 10;
680 std::vector<node_t> free_nodes_;
681 std::map<std::size_t, std::vector<node_t>> free_edges_;
683 std::size_t num_nodes_{};
684 std::size_t num_edges_{};