182 const Eigen::Vector2i& source,
183 const bool checkStartForCollision)
const
185 if (checkStartForCollision)
188 <<
"Start must not be in collision";
191 constexpr float eps = 1e-6;
192 constexpr std::size_t numDirs = 8;
194 const std::array<std::array<std::int64_t, 2>, numDirs> dirs{
195 std::array<std::int64_t, 2>{-1, -1},
196 std::array<std::int64_t, 2>{-1, 0},
197 std::array<std::int64_t, 2>{-1, 1},
198 std::array<std::int64_t, 2>{0, 1},
199 std::array<std::int64_t, 2>{1, 1},
200 std::array<std::int64_t, 2>{1, 0},
201 std::array<std::int64_t, 2>{1, -1},
202 std::array<std::int64_t, 2>{0, -1}};
204 const std::array<float, numDirs> dirLengths{
205 std::sqrt(2.0f), 1, std::sqrt(2.0f), 1, std::sqrt(2.0f), 1, std::sqrt(2.0f), 1};
209 const std::size_t numRows = inputMap.rows();
210 const std::size_t numCols = inputMap.cols();
213 const int source_i = source.x();
214 const int source_j = source.y();
216 const std::size_t maxNumVerts = numRows * numCols;
217 constexpr std::size_t maxEdgesPerVert = numDirs;
219 const float inf = 2 * maxNumVerts;
220 const std::size_t queueSize = numDirs * numRows * numCols;
223 std::vector<std::size_t> edges(maxNumVerts * maxEdgesPerVert);
224 std::vector<std::size_t> edge_counts(maxNumVerts);
225 std::vector<std::size_t> queue(queueSize);
226 std::vector<bool> in_queue(maxNumVerts);
227 std::vector<float> weights(maxNumVerts * maxEdgesPerVert);
228 std::vector<float> dists(maxNumVerts, inf);
230 const auto& verify = [](std::int64_t
index, std::size_t maxIndex,
const std::string&
str)
232 if (
index >=
static_cast<std::int64_t
>(maxIndex) ||
index < 0)
242 for (std::size_t row = 0; row < numRows; ++row)
244 for (std::size_t col = 0; col < numCols; ++col)
246 const std::size_t v = ravel(row, col, numCols);
247 if (inputMap(
static_cast<int>(row),
static_cast<int>(col)) <= 0.F)
252 for (std::size_t k = 0; k < numDirs; ++k)
254 const std::int64_t ip =
static_cast<std::int64_t
>(row) +
256 const std::int64_t jp =
static_cast<std::int64_t
>(col) + dirs[k][1];
258 if (ip < 0 || jp < 0 || ip >=
static_cast<std::int64_t
>(numRows) ||
259 jp >=
static_cast<std::int64_t
>(numCols))
264 const std::size_t vp = ravel(ip, jp, numCols);
265 if (inputMap(ip, jp) <= 0.F)
270 const float clippedObstacleDistance =
271 std::min(inputMap(ip, jp), params.obstacleMaxDistance);
273 const float travelCost = dirLengths[k];
275 const float targetDistanceCost =
276 params.obstacleDistanceWeight *
277 std::pow(1.F - clippedObstacleDistance / params.obstacleMaxDistance,
278 params.obstacleCostExponent);
280 const float edgeCost = params.obstacleDistanceCosts
281 ? travelCost * (1 + targetDistanceCost)
284 const std::size_t e = ravel(v, edge_counts.at(v), maxEdgesPerVert);
286 verify(e, maxNumVerts * maxEdgesPerVert,
"edges");
287 weights.at(e) = edgeCost;
288 verify(e, maxNumVerts * maxEdgesPerVert,
"weights");
290 verify(v, maxNumVerts,
"edges_counts");
298 std::size_t head = 0;
299 std::size_t tail = 0;
301 const std::size_t s = ravel(source_i, source_j, numCols);
303 verify(s, maxNumVerts,
"dists");
305 verify(tail, queueSize,
"queue");
307 verify(s, maxNumVerts,
"in_queue");
309 std::vector<std::int64_t> parents(maxNumVerts, -1);
312 const std::size_t u = queue[++head];
314 verify(u, maxNumVerts,
"in_queue");
315 for (std::size_t j = 0; j < edge_counts[u]; ++j)
317 const std::size_t e = ravel(u, j, maxEdgesPerVert);
318 const std::size_t v = edges[e];
319 const float newDist = dists[u] + weights[e];
320 if (newDist < dists[v])
323 verify(v, maxNumVerts,
"parents");
325 verify(v, maxNumVerts,
"dists");
330 verify(tail, queueSize,
"queue!");
332 verify(v, maxNumVerts,
"in_queue");
334 if (dists[queue[tail]] < dists[queue[head + 1]])
336 std::swap(queue[tail], queue[head + 1]);
346 Eigen::MatrixXf output_dists(numRows, numCols);
350 std::vector<std::vector<Eigen::Vector2i>> output_parents(
351 numRows, std::vector<Eigen::Vector2i>(numCols, Eigen::Vector2i{-1, -1}));
353 std::size_t invalids = 0;
355 for (std::size_t row = 0; row < numRows; ++row)
357 for (std::size_t col = 0; col < numCols; ++col)
359 const std::size_t u = ravel(row, col, numCols);
360 output_dists(row, col) = (dists[u] < inf - eps) * dists[u];
362 if (parents[u] == -1)
365 reachable(row, col) =
false;
369 output_parents.at(row).at(col) = unravel(parents[u], numCols);
374 reachable(source.x(), source.y()) =
true;
376 ARMARX_VERBOSE <<
"Fraction of invalid cells: (" << invalids <<
"/" << parents.size()
383 return Result{.distances = costmap.params().cellSize * output_dists,
384 .parents = output_parents,
385 .reachable = reachable};