40 #include <range/v3/algorithm/reverse.hpp>
48 ravel(std::size_t row, std::size_t col, std::size_t num_cols)
50 return (row * num_cols) + col;
54 unravel(
const std::size_t pos,
const std::size_t numCols)
60 p.x() =
static_cast<int>(pos) / numCols;
61 p.y() =
static_cast<int>(pos) % numCols;
70 costmap(grid), params(params)
73 << grid.
getGrid().cols() <<
").";
78 const Eigen::Vector2f& goal,
79 const bool checkStartForCollision)
const
85 const auto goalVertex = Eigen::Vector2i{costmap.
toVertex(goal).
index};
89 if ((startVertex.
index.array() == goalVertex.array()).all())
92 return {.path = {}, .success =
true};
95 auto costmapWithValidStart = costmap.
getGrid();
98 costmapWithValidStart(startVertex.
index.x(), startVertex.
index.y()) = 0.1;
102 spfa(costmapWithValidStart, Eigen::Vector2i{startVertex.
index}, checkStartForCollision);
104 const auto isStart = [&startVertex](
const Eigen::Vector2i&
v) ->
bool
105 {
return (
v.array() == startVertex.
index.array()).
all(); };
107 const auto isInvalid = [](
const Eigen::Vector2i&
v) ->
bool
108 {
return (
v.x() == -1) and (
v.y() == -1); };
111 std::vector<Eigen::Vector2f> path;
112 path.push_back(goal);
114 const Eigen::Vector2i* pt = &goalVertex;
121 ARMARX_WARNING <<
"No path found from (" << start <<
") to (" << goal <<
").";
125 const Eigen::Vector2i& parent = result.
parents.at(pt->x()).at(pt->y());
139 path.push_back(start);
145 return {.path = path, .success =
true};
150 const bool checkStartForCollision)
const
157 const Eigen::Vector2i&
source,
158 const bool checkStartForCollision)
const
160 if (checkStartForCollision)
163 <<
"Start must not be in collision";
166 constexpr
float eps = 1e-6;
167 constexpr std::size_t numDirs = 8;
169 const std::array<std::array<std::int64_t, 2>, numDirs> dirs{
170 std::array<std::int64_t, 2>{-1, -1},
171 std::array<std::int64_t, 2>{-1, 0},
172 std::array<std::int64_t, 2>{-1, 1},
173 std::array<std::int64_t, 2>{0, 1},
174 std::array<std::int64_t, 2>{1, 1},
175 std::array<std::int64_t, 2>{1, 0},
176 std::array<std::int64_t, 2>{1, -1},
177 std::array<std::int64_t, 2>{0, -1}};
179 const std::array<float, numDirs> dirLengths{
184 const std::size_t numRows = inputMap.rows();
185 const std::size_t numCols = inputMap.cols();
188 const int source_i =
source.x();
189 const int source_j =
source.y();
191 const std::size_t maxNumVerts = numRows * numCols;
192 constexpr std::size_t maxEdgesPerVert = numDirs;
194 const float inf = 2 * maxNumVerts;
195 const std::size_t queueSize = numDirs * numRows * numCols;
198 std::vector<std::size_t> edges(maxNumVerts * maxEdgesPerVert);
199 std::vector<std::size_t> edge_counts(maxNumVerts);
200 std::vector<std::size_t> queue(queueSize);
201 std::vector<bool> in_queue(maxNumVerts);
202 std::vector<float> weights(maxNumVerts * maxEdgesPerVert);
203 std::vector<float> dists(maxNumVerts, inf);
205 const auto& verify = [](std::int64_t
index, std::size_t maxIndex,
const std::string&
str)
207 if (
index >=
static_cast<std::int64_t
>(maxIndex) ||
index < 0)
217 for (std::size_t row = 0; row < numRows; ++row)
219 for (std::size_t col = 0; col < numCols; ++col)
221 const std::size_t
v = ravel(row, col, numCols);
222 if (inputMap(
static_cast<int>(row),
static_cast<int>(col)) <= 0.
F)
227 for (std::size_t k = 0; k < numDirs; ++k)
229 const std::int64_t ip =
static_cast<std::int64_t
>(row) +
231 const std::int64_t jp =
static_cast<std::int64_t
>(col) + dirs[k][1];
233 if (ip < 0 || jp < 0 || ip >=
static_cast<std::int64_t
>(numRows) ||
234 jp >=
static_cast<std::int64_t
>(numCols))
239 const std::size_t vp = ravel(ip, jp, numCols);
240 if (inputMap(ip, jp) <= 0.
F)
245 const float clippedObstacleDistance =
248 const float travelCost = dirLengths[k];
250 const float targetDistanceCost =
256 ? travelCost * (1 + targetDistanceCost)
259 const std::size_t e = ravel(
v, edge_counts.at(
v), maxEdgesPerVert);
261 verify(e, maxNumVerts * maxEdgesPerVert,
"edges");
262 weights.at(e) = edgeCost;
263 verify(e, maxNumVerts * maxEdgesPerVert,
"weights");
265 verify(
v, maxNumVerts,
"edges_counts");
273 std::size_t head = 0;
274 std::size_t tail = 0;
276 const std::size_t
s = ravel(source_i, source_j, numCols);
278 verify(
s, maxNumVerts,
"dists");
280 verify(tail, queueSize,
"queue");
282 verify(
s, maxNumVerts,
"in_queue");
284 std::vector<std::int64_t> parents(maxNumVerts, -1);
287 const std::size_t u = queue[++head];
289 verify(u, maxNumVerts,
"in_queue");
290 for (std::size_t j = 0; j < edge_counts[u]; ++j)
292 const std::size_t e = ravel(u, j, maxEdgesPerVert);
293 const std::size_t
v = edges[e];
294 const float newDist = dists[u] + weights[e];
295 if (newDist < dists[
v])
298 verify(
v, maxNumVerts,
"parents");
300 verify(
v, maxNumVerts,
"dists");
305 verify(tail, queueSize,
"queue!");
307 verify(
v, maxNumVerts,
"in_queue");
309 if (dists[queue[tail]] < dists[queue[head + 1]])
321 Eigen::MatrixXf output_dists(numRows, numCols);
325 std::vector<std::vector<Eigen::Vector2i>> output_parents(
326 numRows, std::vector<Eigen::Vector2i>(numCols, Eigen::Vector2i{-1, -1}));
328 std::size_t invalids = 0;
330 for (std::size_t row = 0; row < numRows; ++row)
332 for (std::size_t col = 0; col < numCols; ++col)
334 const std::size_t u = ravel(row, col, numCols);
335 output_dists(row, col) = (dists[u] < inf - eps) * dists[u];
337 if (parents[u] == -1)
340 reachable(row, col) =
false;
344 output_parents.at(row).at(col) = unravel(parents[u], numCols);
351 ARMARX_VERBOSE <<
"Fraction of invalid cells: (" << invalids <<
"/" << parents.size()
359 .parents = output_parents,
360 .reachable = reachable};