34 #include "range/v3/algorithm/reverse.hpp"
40 ravel(
int row,
int col,
int num_cols)
42 return row * num_cols + col;
52 p.x() = pos / num_cols;
53 p.y() = pos % num_cols;
60 costmap(grid), params(params)
63 << grid.
getGrid().cols() <<
").";
68 const Eigen::Vector2f& goal,
69 const bool checkStartForCollision)
const
75 const auto goalVertex = Eigen::Vector2i{costmap.
toVertex(goal).
index};
79 if ((startVertex.
index.array() == goalVertex.array()).all())
82 return {.path = {}, .success =
true};
85 auto costmapWithValidStart = costmap.
getGrid();
88 costmapWithValidStart(startVertex.
index.x(), startVertex.
index.y()) = 0.1;
92 spfa(costmapWithValidStart, Eigen::Vector2i{startVertex.
index}, checkStartForCollision);
94 const auto isStart = [&startVertex](
const Eigen::Vector2i&
v) ->
bool
95 {
return (
v.array() == startVertex.
index.array()).
all(); };
97 const auto isInvalid = [](
const Eigen::Vector2i&
v) ->
bool
98 {
return (
v.x() == -1) and (
v.y() == -1); };
101 std::vector<Eigen::Vector2f> path;
102 path.push_back(goal);
104 const Eigen::Vector2i* pt = &goalVertex;
111 ARMARX_WARNING <<
"No path found from (" << start <<
") to (" << goal <<
").";
115 const Eigen::Vector2i& parent = result.
parents.at(pt->x()).at(pt->y());
129 path.push_back(start);
135 return {.path = path, .success =
true};
140 const bool checkStartForCollision)
const
147 const Eigen::Vector2i&
source,
148 const bool checkStartForCollision)
const
150 if (checkStartForCollision)
153 <<
"Start must not be in collision";
156 const float eps = 1e-6;
157 const int num_dirs = 8;
159 const int dirs[num_dirs][2] = {
160 {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}};
162 const float dir_lengths[num_dirs] = {
167 int num_rows = inputMap.rows();
168 int num_cols = inputMap.cols();
171 int source_i =
source.x();
172 int source_j =
source.y();
174 int max_num_verts = num_rows * num_cols;
175 int max_edges_per_vert = num_dirs;
176 const float inf = 2 * max_num_verts;
177 int queue_size = num_dirs * num_rows * num_cols;
180 int* edges =
new int[max_num_verts * max_edges_per_vert]();
181 int* edge_counts =
new int[max_num_verts]();
182 int* queue =
new int[queue_size]();
183 bool* in_queue =
new bool[max_num_verts]();
184 float* weights =
new float[max_num_verts * max_edges_per_vert]();
185 float* dists =
new float[max_num_verts];
186 for (
int i = 0; i < max_num_verts; ++i)
189 std::vector<int> parents(max_num_verts, -1);
193 for (
int row = 0; row < num_rows; ++row)
195 for (
int col = 0; col < num_cols; ++col)
197 int v =
ravel(row, col, num_cols);
198 if (inputMap(row, col) == 0.
F)
201 for (
int k = 0; k < num_dirs; ++k)
203 int ip = row + dirs[k][0], jp = col + dirs[k][1];
204 if (ip < 0 || jp < 0 || ip >= num_rows || jp >= num_cols)
207 int vp =
ravel(ip, jp, num_cols);
208 if (inputMap(ip, jp) == 0.
F)
212 const float clippedObstacleDistance =
215 const float travelCost = dir_lengths[k];
217 const float targetDistanceCost =
223 ? travelCost * (1 + targetDistanceCost)
226 int e =
ravel(
v, edge_counts[
v], max_edges_per_vert);
228 weights[e] = edgeCost;
236 int s =
ravel(source_i, source_j, num_cols);
237 int head = 0, tail = 0;
243 int u = queue[++head];
245 for (
int j = 0; j < edge_counts[u]; ++j)
247 int e =
ravel(u, j, max_edges_per_vert);
249 float new_dist = dists[u] + weights[e];
250 if (new_dist < dists[
v])
256 assert(tail < queue_size);
259 if (dists[queue[tail]] < dists[queue[head + 1]])
269 Eigen::MatrixXf output_dists(num_rows, num_cols);
275 std::vector<std::vector<Eigen::Vector2i>> output_parents;
277 for (
int row = 0; row < num_rows; row++)
279 output_parents.push_back(std::vector<Eigen::Vector2i>(
static_cast<size_t>(num_cols),
280 Eigen::Vector2i{-1, -1}));
285 for (
int row = 0; row < num_rows; ++row)
287 for (
int col = 0; col < num_cols; ++col)
289 int u =
ravel(row, col, num_cols);
290 output_dists(row, col) = (dists[u] < inf - eps) * dists[u];
292 if (parents[u] == -1)
295 reachable(row, col) =
false;
299 output_parents.at(row).at(col) =
unravel(parents[u], num_cols);
306 ARMARX_VERBOSE <<
"Fraction of invalid cells: (" << invalids <<
"/" << parents.size()
311 delete[] edge_counts;
322 .parents = output_parents,
323 .reachable = reachable};