CostmapFilter::worldToMask() does not process correctly some points from world that belonging to mask.
For example, consider an OccupancyGrid mask of size 3x3 with origin in (3.0, 3.0) world point.
Taking resolution = 1.0 m and this mask should cover 9 square meters in the world, starting from (3.0, 3.0) world point up to (6.0, 6.0) world point as shown in the illustration below. The world point (5.9, 5.9) in this case should belong to the mask. However, in current implementation, CostmapFilter::worldToMask(mask, 5.9, 5.9) will return false value indicating that the underlying world point does not belong to the filter mask, which is incorrect.
This appears because of CostmapFilter::worldToMask() incorrectly uses std::round instead of type casting with decimal fraction drop. This leads to CostmapFilter::worldToMask() converts to mask only (3.0, 3.0) ... (5.49999, 5.49999) world coordinates, depicted in blue at the illustration below:

Bug report
Required Info:
- Operating System:
- ROS2 Version:
- ROS2 rolling built from sources
- Version or commit hash:
- DDS implementation:
Steps to reproduce issue
- Create OccupancyGrid filter mask with
3x3 size, (3.0, 3.0) origin and resolution = 1.0
- call
CostmapFilter::worldToMask(filter_mask, 5.9, 5.9, mx, my) with (5.9, 5.9) world coordinate
Expected behavior
CostmapFilter::worldToMask() should return true and (mx, my) = (2, 2)
Actual behavior
CostmapFilter::worldToMask() returns false
Additional information
The problem is being fixed by the following change:
--- a/nav2_costmap_2d/plugins/costmap_filters/costmap_filter.cpp
+++ b/nav2_costmap_2d/plugins/costmap_filters/costmap_filter.cpp
@@ -197,8 +197,8 @@ bool CostmapFilter::worldToMask(
return false;
}
- mx = std::round((wx - origin_x) / resolution);
- my = std::round((wy - origin_y) / resolution);
+ mx = static_cast<unsigned int>((wx - origin_x) / resolution);
+ my = static_cast<unsigned int>((wy - origin_y) / resolution);
if (mx >= size_x || my >= size_y) {
return false;
}
Which is also consistent with current Costmap2D::worldToMap and NavfnPlanner::worldToMap and implementations.
CostmapFilter::worldToMask()does not process correctly some points from world that belonging to mask.For example, consider an OccupancyGrid mask of size
3x3with origin in(3.0, 3.0)world point.Taking
resolution = 1.0 mand this mask should cover9square meters in the world, starting from(3.0, 3.0)world point up to(6.0, 6.0)world point as shown in the illustration below. The world point(5.9, 5.9)in this case should belong to the mask. However, in current implementation,CostmapFilter::worldToMask(mask, 5.9, 5.9)will returnfalsevalue indicating that the underlying world point does not belong to the filter mask, which is incorrect.This appears because of

CostmapFilter::worldToMask()incorrectly usesstd::roundinstead of type casting with decimal fraction drop. This leads toCostmapFilter::worldToMask()converts to mask only(3.0, 3.0) ... (5.49999, 5.49999)world coordinates, depicted in blue at the illustration below:Bug report
Required Info:
Steps to reproduce issue
3x3size,(3.0, 3.0)origin andresolution = 1.0CostmapFilter::worldToMask(filter_mask, 5.9, 5.9, mx, my)with(5.9, 5.9)world coordinateExpected behavior
CostmapFilter::worldToMask()should returntrueand(mx, my) = (2, 2)Actual behavior
CostmapFilter::worldToMask()returnsfalseAdditional information
The problem is being fixed by the following change:
Which is also consistent with current Costmap2D::worldToMap and NavfnPlanner::worldToMap and implementations.