183 const Eigen::Vector2i& source,
184 const bool checkStartForCollision)
const
186 if (checkStartForCollision)
189 <<
"Start must not be in collision";
192 constexpr float eps = 1e-6;
193 constexpr std::size_t numDirs = 8;
195 const std::array<std::array<std::int64_t, 2>, numDirs> dirs{
196 std::array<std::int64_t, 2>{-1, -1},
197 std::array<std::int64_t, 2>{-1, 0},
198 std::array<std::int64_t, 2>{-1, 1},
199 std::array<std::int64_t, 2>{0, 1},
200 std::array<std::int64_t, 2>{1, 1},
201 std::array<std::int64_t, 2>{1, 0},
202 std::array<std::int64_t, 2>{1, -1},
203 std::array<std::int64_t, 2>{0, -1}};
205 const std::array<float, numDirs> dirLengths{
206 std::sqrt(2.0f), 1, std::sqrt(2.0f), 1, std::sqrt(2.0f), 1, std::sqrt(2.0f), 1};
210 const std::size_t numRows = inputMap.rows();
211 const std::size_t numCols = inputMap.cols();
214 const int source_i = source.x();
215 const int source_j = source.y();
217 const std::size_t maxNumVerts = numRows * numCols;
218 constexpr std::size_t maxEdgesPerVert = numDirs;
220 const float inf = 2 * maxNumVerts;
221 const std::size_t queueSize = maxNumVerts + 1;
224 std::vector<std::size_t> edges(maxNumVerts * maxEdgesPerVert);
225 std::vector<std::size_t> edge_counts(maxNumVerts);
226 std::vector<std::size_t> queue(queueSize);
227 std::vector<bool> in_queue(maxNumVerts);
228 std::vector<float> weights(maxNumVerts * maxEdgesPerVert);
229 std::vector<float> dists(maxNumVerts, inf);
231 const auto& verify = [](std::int64_t
index, std::size_t maxIndex,
const std::string&
str)
233 if (
index >=
static_cast<std::int64_t
>(maxIndex) ||
index < 0)
243 for (std::size_t row = 0; row < numRows; ++row)
245 for (std::size_t col = 0; col < numCols; ++col)
247 const std::size_t v = ravel(row, col, numCols);
248 if (inputMap(
static_cast<int>(row),
static_cast<int>(col)) <= 0.F)
253 for (std::size_t k = 0; k < numDirs; ++k)
255 const std::int64_t ip =
static_cast<std::int64_t
>(row) +
257 const std::int64_t jp =
static_cast<std::int64_t
>(col) + dirs[k][1];
259 if (ip < 0 || jp < 0 || ip >=
static_cast<std::int64_t
>(numRows) ||
260 jp >=
static_cast<std::int64_t
>(numCols))
265 const std::size_t vp = ravel(ip, jp, numCols);
266 if (inputMap(ip, jp) <= 0.F)
271 const float clippedObstacleDistance =
272 std::min(inputMap(ip, jp), params.obstacleMaxDistance);
274 const float travelCost = dirLengths[k];
276 const float targetDistanceCost =
277 params.obstacleDistanceWeight *
278 std::pow(1.F - clippedObstacleDistance / params.obstacleMaxDistance,
279 params.obstacleCostExponent);
281 const float edgeCost = params.obstacleDistanceCosts
282 ? travelCost * (1 + targetDistanceCost)
285 const std::size_t e = ravel(v, edge_counts.at(v), maxEdgesPerVert);
287 verify(e, maxNumVerts * maxEdgesPerVert,
"edges");
288 weights.at(e) = edgeCost;
289 verify(e, maxNumVerts * maxEdgesPerVert,
"weights");
291 verify(v, maxNumVerts,
"edges_counts");
305 std::size_t head = 0;
306 std::size_t tail = 0;
307 const auto next = [queueSize](std::size_t i) {
return (i + 1) % queueSize; };
309 const std::size_t s = ravel(source_i, source_j, numCols);
311 verify(s, maxNumVerts,
"dists");
315 verify(s, maxNumVerts,
"in_queue");
317 std::vector<std::int64_t> parents(maxNumVerts, -1);
321 const std::size_t u = queue[head];
323 verify(u, maxNumVerts,
"in_queue");
324 for (std::size_t j = 0; j < edge_counts[u]; ++j)
326 const std::size_t e = ravel(u, j, maxEdgesPerVert);
327 const std::size_t v = edges[e];
328 const float newDist = dists[u] + weights[e];
329 if (newDist < dists[v])
332 verify(v, maxNumVerts,
"parents");
334 verify(v, maxNumVerts,
"dists");
343 verify(v, maxNumVerts,
"in_queue");
347 const std::size_t front = next(head);
348 if (dists[queue[tail]] < dists[queue[front]])
350 std::swap(queue[tail], queue[front]);
360 Eigen::MatrixXf output_dists(numRows, numCols);
364 std::vector<std::vector<Eigen::Vector2i>> output_parents(
365 numRows, std::vector<Eigen::Vector2i>(numCols, Eigen::Vector2i{-1, -1}));
367 std::size_t invalids = 0;
369 for (std::size_t row = 0; row < numRows; ++row)
371 for (std::size_t col = 0; col < numCols; ++col)
373 const std::size_t u = ravel(row, col, numCols);
374 output_dists(row, col) = (dists[u] < inf - eps) * dists[u];
376 if (parents[u] == -1)
379 reachable(row, col) =
false;
383 output_parents.at(row).at(col) = unravel(parents[u], numCols);
388 reachable(source.x(), source.y()) =
true;
390 ARMARX_VERBOSE <<
"Fraction of invalid cells: (" << invalids <<
"/" << parents.size()
397 return Result{.distances = costmap.params().cellSize * output_dists,
398 .parents = output_parents,
399 .reachable = reachable};