Skip to content

feat(crop_box_filter): simplify validation logic for input point cloud#875

Merged
interimadd merged 16 commits intoautowarefoundation:mainfrom
interimadd:refactor-simplify-crop-box-filter-validation-logic
Mar 2, 2026
Merged

feat(crop_box_filter): simplify validation logic for input point cloud#875
interimadd merged 16 commits intoautowarefoundation:mainfrom
interimadd:refactor-simplify-crop-box-filter-validation-logic

Conversation

@interimadd
Copy link
Contributor

Description

Simplify the validation criteria for input point clouds and extract the validation logic into crop_box_filter.cpp.

Background

The original is_valid() method in CropBoxFilter checked whether the input PointCloud2 matched specific Autoware point type layouts (e.g., PointXYZIRCAEDT, PointXYZIRC). This was overly strict; the crop box filter only requires x, y, z as FLOAT32 fields and a consistent data size to function correctly.

Changes

  • src/crop_box_filter.hpp / crop_box_filter.cpp: Newly added.
    • Extracted the validate_pointcloud2() logic.
  • crop_box_filter_node.cpp: Removed ~230 lines.
    • Deleted is_valid() and all four is_data_layout_compatible_with_point_*() methods.
    • Updated pointcloud_callback() to call validate_pointcloud2().
  • test/test_crop_box_filter.cpp: Added new unit tests for validate_pointcloud2().

Related links

Parent Issue:

How was this PR tested?

  • Clean build with colcon build --packages-select autoware_crop_box_filter succeeded.
  • All unit tests passed:
    • test_crop_box_filter (new): 3/3 cases passed — accepts xyz-only, accepts XYZIRC, and rejects missing 'z'.
    • test_crop_box_filter_node (existing): No regressions.

Notes for reviewers

  • The validation criteria are intentionally relaxed compared to the original. The previous code rejected any cloud whose layout did not exactly match specific types like PointXYZIRC. The new code only requires x, y, z as FLOAT32 fields, which is the minimum the filter needs. This makes the node compatible with a broader range of point cloud types.
  • There is only one function in crop_box_filter.hpp for now, but I plan to extract more crop box filter logic into it in a future pull request.

Interface changes

None.

Takahisa.Ishikawa added 9 commits March 2, 2026 14:54
…ve redundant functions

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…ation logic

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…improve clarity

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…emoving redundant lambda function

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…stamp handling in validation logic

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…nt ownership

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
… xyz field and data size checks

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
@interimadd interimadd added the run:build-and-test-differential Mark to enable build-and-test-differential workflow. (used-by-ci) label Mar 2, 2026
@github-actions
Copy link

github-actions bot commented Mar 2, 2026

Thank you for contributing to the Autoware project!

🚧 If your pull request is in progress, switch it to draft mode.

Please ensure:

@codecov
Copy link

codecov bot commented Mar 2, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.34%. Comparing base (e232aec) to head (a977c76).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...g/autoware_crop_box_filter/src/crop_box_filter.cpp 53.84% 7 Missing and 5 partials ⚠️
...oware_crop_box_filter/src/crop_box_filter_node.cpp 33.33% 1 Missing and 1 partial ⚠️
...g/autoware_crop_box_filter/src/crop_box_filter.hpp 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #875      +/-   ##
==========================================
+ Coverage   50.16%   50.34%   +0.18%     
==========================================
  Files         356      358       +2     
  Lines       22892    22780     -112     
  Branches    10139    10120      -19     
==========================================
- Hits        11483    11468      -15     
+ Misses      10305    10205     -100     
- Partials     1104     1107       +3     
Flag Coverage Δ *Carryforward flag
daily-humble 50.69% <ø> (+0.18%) ⬆️ Carriedforward from b1a37e9
daily-jazzy 50.18% <ø> (+0.18%) ⬆️ Carriedforward from b1a37e9
differential-humble 50.24% <50.00%> (?)
total 50.38% <ø> (+0.19%) ⬆️ Carriedforward from b1a37e9
total-humble 50.73% <ø> (+0.18%) ⬆️ Carriedforward from b1a37e9
total-jazzy 50.21% <ø> (+0.18%) ⬆️ Carriedforward from b1a37e9

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sasakisasaki sasakisasaki self-assigned this Mar 2, 2026
Copy link

@mojomex mojomex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some small nit-picky comments, but feel free to leave some un-addressed. Merge at your convenience.

namespace autoware::crop_box_filter
{

static ValidationResult validate_xyz_fields(const PointCloud2ConstPtr & cloud)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) More idiomatic would be to pass a const& PointCloud2 or const PointCloud2 * const since the function does not care about ownership.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you pointed out, shared_ptr was unnecessary.
I've updated the functions to use raw pointers instead.
81a0a30

This change also simplified the unit tests.
afabdda


static ValidationResult validate_data_size(const PointCloud2ConstPtr & cloud)
{
if (cloud->width * cloud->height * cloud->point_step != cloud->data.size()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(optional / discussion) Not sure what PointCloud2 best practice is here. Technically, <= would be enough here. Foxglove still processes pointclouds where width*height*point_step < data.size() and shows a warning icon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the insightful feedback.
As long as data.size() exceeds cloud->width * cloud->height * cloud->point_step, the crop box filter should process the data without any issues. Thus, I think it's reasonable to allow such point clouds.
Fixed in: 2c225e2

{
if (cloud->width * cloud->height * cloud->point_step != cloud->data.size()) {
std::ostringstream oss;
oss << "Invalid PointCloud (data = " << cloud->data.size() << ", width = " << cloud->width
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
oss << "Invalid PointCloud (data = " << cloud->data.size() << ", width = " << cloud->width
oss << "Invalid PointCloud (data.size = " << cloud->data.size() << ", width = " << cloud->width

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks more concrete.
addressed e48e8b9

namespace autoware::crop_box_filter
{

struct ValidationResult
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Not sure if tl is easily accessible in autoware_crop_box_filter, but parts of Autoware already use tl::expected<T, E> as a backport of std::expected from C++23, which is more idiomatic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion.
I didn't know about tl::expected, so I'm glad to learn about it.
In this case, to keep the implementation simple, I would like to keep the current implementation. However, I will keep the concept of tl::expected in mind.


int main(int argc, char ** argv)
{
rclcpp::init(0, nullptr);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rclcpp should not be needed here - message types work without rclcpp.
Once removed, the main function shouldn't be needed altogether since GTest usually auto-discovers tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing that out!
I totally overlooked it.
It's addressed in: be22678

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
Copy link
Contributor

@sasakisasaki sasakisasaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Readability is now much higher now. Thank you!

I left some minor comments 👍

namespace autoware::crop_box_filter
{

static ValidationResult validate_xyz_fields(const PointCloud2ConstPtr & cloud)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For making the role explicit 👍

Suggested change
static ValidationResult validate_xyz_fields(const PointCloud2ConstPtr & cloud)
static ValidationResult contains_xyz_fields(const PointCloud2ConstPtr & cloud)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the return value is ValidationResult, not the bool expected from a function called contains_..., I'm not sure on this one 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comments!
In this case, validate_xyz_fields() checks if its fields have a data type of sensor_msgs::msg::PointField::FLOAT32. So I believe validate is more appropriate in this case.


ValidationResult validate_pointcloud2(const PointCloud2ConstPtr & cloud)
{
const ValidationResult xyz_validation_result = validate_xyz_fields(cloud);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If above my proposal is accepted.

Suggested change
const ValidationResult xyz_validation_result = validate_xyz_fields(cloud);
const ValidationResult xyz_validation_result = contains_xyz_fields(cloud);

Comment on lines +39 to +41
else if (field.name == "z")
has_z = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the number of loops is not huge $\mathcal{O}(n_{fields})$, I guess early return would make sense 👍

Suggested change
else if (field.name == "z")
has_z = true;
}
else if (field.name == "z")
has_z = true;
if (has_x && has_y && has_z) break;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for suggestion!
It looks better in the perspective of this loop's objective.
Addressed in b1a37e9

Takahisa.Ishikawa added 2 commits March 2, 2026 19:34
…tCloud2

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
Takahisa.Ishikawa added 3 commits March 2, 2026 19:46
…g shared_ptr usage

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…er than comparison

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
…elds in PointCloud2

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
@interimadd interimadd enabled auto-merge (squash) March 2, 2026 11:26
@interimadd interimadd disabled auto-merge March 2, 2026 11:27
…filter.cpp

Signed-off-by: Takahisa.Ishikawa <takahisa.ishikawa@tier4.jp>
@interimadd interimadd enabled auto-merge (squash) March 2, 2026 11:28
@interimadd interimadd merged commit d091381 into autowarefoundation:main Mar 2, 2026
42 of 43 checks passed
@interimadd interimadd deleted the refactor-simplify-crop-box-filter-validation-logic branch March 2, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run:build-and-test-differential Mark to enable build-and-test-differential workflow. (used-by-ci)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants