10 #include <unordered_set>
15 #include <Eigen/Geometry>
24 #include <range/v3/view/zip.hpp>
33 const std::optional<Mask>& mask,
37 sceneBounds(sceneBounds),
38 parameters(parameters),
39 global_T_costmap(origin)
45 Costmap::validateSizes()
const
59 Eigen::Vector2f posLocal;
72 return global_T_costmap * costmap_P_pos;
84 if (
index.x() >= grid.rows() ||
index.y() >= grid.cols())
105 const auto localPosition = global_T_costmap.inverse() * globalPosition;
107 const float vX = (localPosition.x() - parameters.
cellSize / 2 - sceneBounds.
min.x()) /
109 const float vY = (localPosition.y() - parameters.
cellSize / 2 - sceneBounds.
min.y()) /
112 const int iX = std::round(vX - 0.01);
113 const int iY = std::round(vY - 0.01);
115 const int iXSan = std::clamp<int>(iX, 0, grid.rows() - 1);
116 const int iYSan = std::clamp<int>(iY, 0, grid.cols() - 1);
140 if (mask.has_value())
143 <<
"At least one element has to be valid. Here, all elements are masked out!";
153 for (
int r = 0; r < grid.rows(); r++)
155 for (
int c = 0;
c < grid.cols();
c++)
157 if (mask.has_value())
159 if (not mask.value()(r,
c))
164 const float currentVal = grid(r,
c);
165 if (currentVal < minVal)
175 return {.value = minVal, .index = {row, col}, .position =
toPositionGlobal({row, col})};
185 if (mask.has_value())
188 <<
"At least one element has to be valid. Here, all elements are masked out!";
191 Grid newGrid(grid.rows(), grid.cols());
192 const double max = grid.maxCoeff();
193 newGrid.setConstant(
max);
194 for (
int r = 0; r < grid.rows(); r++)
196 for (
int c = 0;
c < grid.cols();
c++)
198 if (mask.has_value())
200 if (not mask.value()(r,
c))
205 Eigen::MatrixXf valueMatrix(
filter.matrix.rows(),
filter.matrix.cols());
206 const int radius_r = (
filter.matrix.rows() - 1) / 2;
207 const int radius_c = (
filter.matrix.cols() - 1) / 2;
208 valueMatrix.setConstant(
max);
209 for (
int i = -radius_r; i <= radius_r; i++)
211 for (
int j = -radius_c; j <= radius_c; j++)
213 const int ri = r + i;
214 const int cj =
c + j;
215 if (ri > 0 and ri < grid.rows() and cj > 0 and cj < grid.cols() and
216 mask.value()(ri, cj))
218 valueMatrix(radius_r + i, radius_c + j) = grid(ri, cj);
222 const double sum =
filter.matrix.sum();
225 const float filteredValue =
226 (valueMatrix.cwiseProduct(
filter.matrix)).sum() / sum;
228 filter.useMinimum ?
std::min(grid(r,
c), filteredValue) : filteredValue;
252 return grid(
v.index.x(),
v.index.y()) == 0.F;
262 other.validateSizes();
264 const auto startIdx =
toVertex(other.sceneBounds.
min);
270 const int rows =
std::min(other.grid.rows(), grid.rows() - startIdx.index.x());
271 const int cols =
std::min(other.grid.cols(), grid.cols() - startIdx.index.y());
273 ARMARX_VERBOSE <<
"Adding other grid to region (" << startIdx.index.x() <<
", "
274 << startIdx.index.y() <<
"), "
275 <<
" (" << startIdx.index.x() + rows <<
", " << startIdx.index.y() + cols
281 grid.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array() +=
282 weight * other.grid.block(0, 0, rows, cols).array();
284 if (not mask.has_value())
286 mask =
Mask(grid.rows(), grid.cols());
291 << mask->array().cast<
float>().sum() / mask->size();
293 Mask otherMask(grid.rows(), grid.cols());
295 otherMask.block(startIdx.index.x(), startIdx.index.y(), rows, cols).setOnes();
297 if (other.mask.has_value())
303 otherMask.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array() *=
304 other.mask->block(0, 0, rows, cols).array();
308 mask->array() *= otherMask.array();
311 << mask->array().cast<
float>().sum() / mask->size();
315 grid.array() *= mask->cast<
float>().array();
326 other.validateSizes();
328 const auto startIdx =
toVertex(other.sceneBounds.
min);
334 const int rows =
std::min(other.grid.rows(), grid.rows() - startIdx.index.x());
335 const int cols =
std::min(other.grid.cols(), grid.cols() - startIdx.index.y());
337 ARMARX_VERBOSE <<
"Adding other grid to region (" << startIdx.index.x() <<
", "
338 << startIdx.index.y() <<
"), "
339 <<
" (" << startIdx.index.x() + rows <<
", " << startIdx.index.y() + cols
348 grid.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array() =
349 other.grid.block(0, 0, rows, cols)
352 grid.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array());
356 grid.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array() =
357 other.grid.block(0, 0, rows, cols)
360 grid.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array());
365 if (not mask.has_value())
367 mask =
Mask(grid.rows(), grid.cols());
371 Mask otherMask(grid.rows(), grid.cols());
373 otherMask.block(startIdx.index.x(), startIdx.index.y(), rows, cols).setOnes();
375 if (other.mask.has_value())
381 otherMask.block(startIdx.index.x(), startIdx.index.y(), rows, cols).array() *=
382 other.mask->block(0, 0, rows, cols).array();
386 mask->array() *= otherMask.array();
389 << mask->array().cast<
float>().sum() / mask->size();
393 grid.array() *= mask->cast<
float>().array();
398 const std::optional<Costmap::Mask>&
404 std::optional<Costmap::Mask>&
440 .
min = sceneBounds.
min + parameters.
cellSize * Eigen::Vector2f{
min.cast<
float>()},
441 .max = sceneBounds.
min + parameters.
cellSize * Eigen::Vector2f{
max.cast<
float>()}};
449 if (mask.has_value())
459 sceneBounds.
min = newSceneBounds.min;
460 sceneBounds.
max = newSceneBounds.max;
474 const std::vector<float>& weights)
const
478 const std::vector<float> costmapWeights(weights.begin(), weights.end() - 1);
487 for (
int x = 0; x < mergedCostmap.
getGrid().rows(); x++)
489 for (
int y = 0; y < mergedCostmap.
getGrid().cols(); y++)
495 for (
const auto& costmap : costmaps)
498 mergedCostmap.mask.value()(x, y) &=
499 costmap.isValid(costmap.toVertex(position).index);
505 for (
const auto& [weight, costmap] :
506 ranges::views::zip(costmapWeights, costmaps))
508 const auto otherCostmapVal = costmap.value(position);
511 newVal += weight * otherCostmapVal.value();
514 newVal += weights.back() * mergedCostmap.grid(x, y);
515 mergedCostmap.grid(x, y) = newVal;
519 mergedCostmap.grid(x, y) = 0;
524 return mergedCostmap;
531 Filter gaussianFilter{.
matrix = Eigen::MatrixXf::Zero(radius * 2 + 1, radius * 2 + 1)};
532 for (
int i = -radius; i <= radius; i++)
534 for (
int j = -radius; j <= radius; j++)
536 gaussianFilter.matrix(radius + i, radius + j) =
537 std::exp(-0.5 * (std::pow(i / sigma, 2.0) + std::pow(j / sigma, 2.0))) /
538 (2 *
M_PI * sigma * sigma);
541 return gaussianFilter;
547 if (not mask.has_value())
549 return grid.cols() * grid.rows();
552 return mask->array().cast<
int>().sum();
565 const auto x =
index.x();
566 const auto y =
index.y();
569 for (
int r = 1; r < 10; r++)
571 for (
int i = -r; i <= r; i++)
573 for (
int j = -r; j <= r; j++)
588 std::pair<Costmap::Index, Costmap::Index>
591 if (not mask.has_value())
593 return {
Index{0, 0},
Index{grid.rows() - 1, grid.cols() - 1}};
597 << mask->cast<
float>().sum() / mask->size();
604 for (
int x = 0; x < grid.rows(); x++)
606 for (
int y = 0; y < grid.cols(); y++)
608 if (mask.value()(x, y))
631 auto startIdx =
v.index;
635 startIdx.x() =
std::max(startIdx.x(), aabbMin.x());
636 startIdx.y() =
std::max(startIdx.y(), aabbMin.y());
637 startIdx.x() =
std::min(startIdx.x(), aabbMax.x());
638 startIdx.y() =
std::min(startIdx.y(), aabbMax.y());
640 startIdx = findClosestValidIndex(startIdx);
649 grid.array() *= mask->cast<
float>().array();
650 auto newMask = mask.value();
656 operator()(
const std::pair<int, int>&
v)
const
658 return v.first * 31 +
v.second;
662 std::unordered_set<std::pair<int, int>,
pair_hash> stack;
663 auto visited = newMask;
664 stack.emplace(startIdx.x(), startIdx.y());
666 while (not stack.empty())
670 ARMARX_INFO <<
"After 1000 iterations, current element is " << stack.begin()->first
671 <<
", " << stack.begin()->second;
674 const auto it = stack.begin();
675 const auto idx =
Index{it->first, it->second};
684 visited(idx.x(), idx.y()) = 1;
693 if (grid(idx.x(), idx.y()) == 0.F)
700 newMask.array()(idx.x(), idx.y()) = 1;
702 if (
const std::pair<int, int> element = {idx.x() + 1, idx.y()};
703 element.first < visited.rows() && not visited(element.first, element.second))
705 stack.emplace(element);
707 if (
const std::pair<int, int> element = {idx.x() - 1, idx.y()};
708 element.first > 0 && not visited(element.first, element.second))
710 stack.emplace(element);
712 if (
const std::pair<int, int> element = {idx.x(), idx.y() + 1};
713 element.second < visited.cols() && not visited(element.first, element.second))
715 stack.emplace(element);
717 if (
const std::pair<int, int> element = {idx.x(), idx.y() - 1};
718 element.second > 0 && not visited(element.first, element.second))
720 stack.emplace(element);
724 mask.emplace(newMask);