12#include <Eigen/Geometry>
14#include <range/v3/view/zip.hpp>
30 const std::optional<Mask>& mask,
34 sceneBounds(sceneBounds),
35 parameters(parameters),
42 Costmap3D::validateSizes()
const
49 auto columns = size.y();
54 columns = mask->cols();
57 for (
const auto& g : grid)
70 Eigen::Vector2f posLocal;
72 sceneBounds.min.x() +
index.x() * parameters.cellSize + parameters.cellSize / 2;
74 sceneBounds.min.y() +
index.y() * parameters.cellSize + parameters.cellSize / 2;
83 return global_T_Costmap3D * Costmap3D_P_pos;
126 if (mask.has_value())
132 return not mask.value()(
index.x(),
index.y());
140 const auto localPosition = global_T_Costmap3D.inverse() * globalPosition;
142 const float vX = (localPosition.x() - parameters.cellSize / 2 - sceneBounds.min.x()) /
144 const float vY = (localPosition.y() - parameters.cellSize / 2 - sceneBounds.min.y()) /
147 const int iX = std::round(vX - 0.01);
148 const int iY = std::round(vY - 0.01);
151 const int iXSan = std::clamp<int>(iX, 0, size.x() - 1);
152 const int iYSan = std::clamp<int>(iY, 0, size.y() - 1);
162 return Vertex{.index =
Index{iXSan, iYSan}, .position = globalPosition};
168 const float degrees = (360.F / parameters.orientations) *
index;
169 return {.index =
index, .degrees = degrees};
175 float deg = std::fmod(degrees, 360.F);
188 const float tmp = (degrees + (180.F / parameters.orientations)) /
189 (360.F / parameters.orientations);
191 index = std::min(
index, parameters.orientations - 1);
192 return {.index =
index, .degrees = degrees};
206 if (mask.has_value())
209 <<
"At least one element has to be valid. Here, all elements are masked out!";
213 Grid::value_type::Index row = 0;
214 Grid::value_type::Index col = 0;
218 float minVal = std::numeric_limits<float>::max();
220 for (
int r = 0; r < size.x(); r++)
222 for (
int c = 0;
c < size.y();
c++)
224 if (mask.has_value())
226 if (not mask.value()(r,
c))
233 for (
const auto& g : grid)
236 const float currentVal = g(r,
c);
237 if (currentVal < minVal)
247 const auto& g = grid[rotation.
index];
249 const float currentVal = g(r,
c);
250 if (currentVal < minVal)
261 return {.value = minVal, .index = {row, col}, .position =
toPositionGlobal({row, col})};
280 if (rotation.has_value())
282 return grid.at(rotation->index)(v.index.x(), v.index.y()) <= 0.F;
287 return std::any_of(grid.begin(),
289 [&v](
const auto& grid2d)
290 { return grid2d(v.index.x(), v.index.y()) <= 0.F; });
293 const std::optional<Costmap3D::Mask>&
299 std::optional<Costmap3D::Mask>&
308 return grid.at(rot_index)(
index.x(),
index.y());
319 if (rot_index < 0 || rot_index > this->grid.size() - 1)
322 <<
" but it is not within allowed range (0 .. "
323 << this->grid.size() - 1 <<
")";
327 return grid.at(rot_index)(
index.x(),
index.y());
338 return value(v.index, r.index);
350 .min = sceneBounds.min + parameters.cellSize * Eigen::Vector2f{
min.cast<
float>()},
351 .max = sceneBounds.min + parameters.cellSize * Eigen::Vector2f{
max.cast<
float>()}};
356 for (
auto& grid2d : grid)
364 if (mask.has_value())
374 sceneBounds.min = newSceneBounds.min;
375 sceneBounds.max = newSceneBounds.max;
377 ARMARX_VERBOSE <<
"New scene bounds: " << sceneBounds.min <<
" and " << sceneBounds.max;
383 if (not mask.has_value())
386 return size.y() * size.x();
389 return mask->array().cast<
int>().sum();
403 const auto y =
index.y();
406 for (
int r = 1; r < 10; r++)
408 for (
int i = -r; i <= r; i++)
410 for (
int j = -r; j <= r; j++)
425 std::pair<Costmap3D::Index, Costmap3D::Index>
428 if (not mask.has_value())
434 << mask->cast<
float>().sum() / mask->size();
442 for (
int x = 0;
x < size.x();
x++)
444 for (
int y = 0; y < size.y(); y++)
446 if (mask.value()(
x, y))
448 min.x() = std::min(
min.x(),
x);
449 min.y() = std::min(
min.y(), y);
450 max.x() = std::max(
max.x(),
x);
451 max.y() = std::max(
max.y(), y);
462 return {grid[0].rows(), grid[0].cols()};
471 .cellSize = parameters.cellSize,
473 .sceneBoundsMargin = parameters.sceneBoundsMargin,
479 c.getMutableMask() =
c.getGrid().array() > 0.0F;
487 const std::optional<Mask>& mask)
495 for (
int rotIdx = 0; rotIdx < parameters.orientations; rotIdx++)
497 ARMARX_INFO <<
"Converting to pseudo SDF for rotation index " << rotIdx;
512 if (not mask.has_value())
514 ARMARX_INFO <<
"Costmap3D::convertToPseudoSDF: No mask present, nothing to do.";
521 std::vector<Costmap3D::Index> borderingIndices;
522 std::vector<Costmap3D::Index> nextBorderingIndices;
537 for (
int y = 0; y <
getSize().y(); y++)
542 workingMask(
x, y) =
false;
545 const std::vector<Costmap3D::Index> neighbors = {
546 {
x + 1, y}, {
x - 1, y}, {
x, y + 1}, {
x, y - 1}};
547 for (
const auto& nIdx : neighbors)
551 borderingIndices.push_back(idx);
560 <<
" bordering indices to start flood-fill.";
561 const float cellSize = parameters.cellSize;
564 while (not borderingIndices.empty())
567 <<
", current border size: " << borderingIndices.size();
568 for (
const auto& idx : borderingIndices)
570 if (workingMask(idx.x(), idx.y()))
576 float minNeighborValue = std::numeric_limits<float>::min();
578 const std::vector<Costmap3D::Index> neighbors = {{idx.x() + 1, idx.y()},
579 {idx.x() - 1, idx.y()},
580 {idx.x(), idx.y() + 1},
581 {idx.x(), idx.y() - 1}};
582 for (
const auto& nIdx : neighbors)
587 if (neighborValue != 0.0 && neighborValue > minNeighborValue)
589 minNeighborValue = neighborValue;
595 const float newValue = -1.0F * iteration * cellSize;
596 grid[rotationIndex](idx.x(), idx.y()) = newValue;
598 workingMask(idx.x(), idx.y()) =
true;
600 for (
const auto& nIdx : neighbors)
602 if (
isWithinRange(nIdx) && not workingMask(nIdx.x(), nIdx.y()))
604 nextBorderingIndices.push_back(nIdx);
608 borderingIndices = nextBorderingIndices;
609 nextBorderingIndices.clear();
614 if (workingMask.array().cast<
int>().sum(),
getSize().
x() *
getSize().y())
void convertToPseudoSDF()
Costmap costmapForOrientation(RotationIndex rotationIndex, bool initializeMask=false) const
bool isWithinRange(const Index &index) const noexcept
const core::Pose2D & origin() const
const SceneBounds & getLocalSceneBounds() const noexcept
Position toPositionGlobal(const Index &index) const
void cutToValidBoundingBox()
const Grid & getGrid() const
static Costmap3D WithSameDimsAs(const Costmap3D &other, const Grid &grid, const std::optional< Mask > &mask=std::nullopt)
Create a Costmap3D with the same dimensions and parameters as the given one.
Costmap3D(const Grid &grid, const Parameters ¶meters, const SceneBounds &sceneBounds, const std::optional< Mask > &mask=std::nullopt, const core::Pose2D &origin=core::Pose2D::Identity())
static constexpr Rotation ALL_ORIENTATIONS
bool isInCollision(const Position &p, std::optional< Rotation > rotation=std::nullopt) const
const std::optional< Mask > & getMask() const noexcept
std::size_t numberOfValidElements() const
bool isMaskedOut(const Index &index) const noexcept
Eigen::Matrix< bool, Eigen::Dynamic, Eigen::Dynamic > Mask
Rotation rotationFromIndex(RotationIndex index) const
Rotation closestRotationFromDegrees(RotationDegrees degrees) const
Position toPositionLocal(const Index &index) const
std::optional< Costmap3D::Mask > & getMutableMask() noexcept
void convertToPseudoSDFForRotation(RotationIndex rot_index)
std::vector< Eigen::MatrixXf > Grid
std::optional< float > value(const Index &index, const RotationIndex rot_index) const
std::pair< Index, Index > getValidBoundingBox() const
Vertex toVertex(const Position &globalPosition) const
bool isValid(const Index &index) const noexcept
checks whether the cell is masked out
Optimum optimum(Rotation rotation=ALL_ORIENTATIONS) const
const Parameters & params() const noexcept
float value_ignore_mask(const Index &index, const RotationIndex rot_index) const
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
This file is part of ArmarX.
float rotationFrom0To360(float degrees)
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)