Skip to content

Refactor PointcloudColorHandlerGenericField to deal with any field type#6309

Merged
mvieth merged 11 commits into
PointCloudLibrary:masterfrom
themightyoarfish:colorhandler-field-types
Sep 24, 2025
Merged

Refactor PointcloudColorHandlerGenericField to deal with any field type#6309
mvieth merged 11 commits into
PointCloudLibrary:masterfrom
themightyoarfish:colorhandler-field-types

Conversation

@themightyoarfish

@themightyoarfish themightyoarfish commented Jul 14, 2025

Copy link
Copy Markdown
Contributor

Resolves #6306
Partially resolves #6186

@themightyoarfish

Copy link
Copy Markdown
Contributor Author

I ran the formatter to put my changes in these files, but unfortunately this has resulted in a large diff, as they seemed to not have followed the clang-format style file before.

@mvieth

mvieth commented Jul 15, 2025

Copy link
Copy Markdown
Member

I ran the formatter to put my changes in these files, but unfortunately this has resulted in a large diff, as they seemed to not have followed the clang-format style file before.

The style file has only been added a few years ago, and most of the code is not yet formatted according to it. We are slowly formatting more and more files, but we cannot format any files that are changed in any open pull request (otherwise the pull request would have merge conflicts and basically be lost).

Unfortunately, with the formatting changes mixed in, this pull request is very difficult to review, as it is very time consuming to look for the changes you wanted to make originally. Is there any way you can revert the formatting changes in this pull request?

It has a branch inside the getColor() function which skips points with non-finite x/y/z coordinates, unless the cloud has no x channel, in which case it checks the target field for finiteness. What exactly is the purpose of this and should I keep this? How does one display clouds without an X channel?

To be honest, I am not sure, but it is probably there for a reason so I would like to keep it. However, instead of the current structure (if-condition, then two for-loops, one for each case), you could probably merge the for-loops into one, then check something like x_idx != -1 && !pcl::isXYZFinite((*cloud_)[cp]) inside (similar for PCLPointCloud2 case). That would reduce code duplication, and the performance difference should be negligible.

@themightyoarfish themightyoarfish force-pushed the colorhandler-field-types branch from 88d0563 to 2556e89 Compare July 15, 2025 13:25
@themightyoarfish

Copy link
Copy Markdown
Contributor Author

I have recommitted without formatting changes outside of the affected class.

also added the handling of non-xyz data as suggested, but have not tested it yet.

@themightyoarfish themightyoarfish force-pushed the colorhandler-field-types branch from b5bfae2 to 7e7f343 Compare July 21, 2025 15:43
@themightyoarfish themightyoarfish marked this pull request as ready for review July 30, 2025 10:40
@themightyoarfish

Copy link
Copy Markdown
Contributor Author

CI seems to pass, i guess i should add some kind of test?

@mvieth

mvieth commented Jul 30, 2025

Copy link
Copy Markdown
Member

CI seems to pass, i guess i should add some kind of test?

That would be great. My suggestion: create a small cloud with maybe 4-5 points (manually), pass to color handler, then check if the array returned by getColor contains sensible values. Then convert the cloud to pcl::PCLPointCloud2 and repeat.

@themightyoarfish

Copy link
Copy Markdown
Contributor Author

Added a test which passes for me locally, but I don't think CI builds the visualization tests.

(they are also disabled on macos, because the code only checks for UNIX + DISPLAY set, which doesn't exist on macos)

@larshg

larshg commented Aug 1, 2025

Copy link
Copy Markdown
Contributor

Added a test which passes for me locally, but I don't think CI builds the visualization tests.

(they are also disabled on macos, because the code only checks for UNIX + DISPLAY set, which doesn't exist on macos)

Its run on the ubuntu CI's using xvfb - so should be good 👍

@themightyoarfish

Copy link
Copy Markdown
Contributor Author

Can I get a review?

Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated
Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated
Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated


// Get point step. Does not directly exist in pcl::PointCloud
template <typename CloudT> inline int getPointStep(const CloudT&)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would add these getters to their respective classes - even though they currently only a used here, I don't see why it shouldn't belong to the point_cloud/PCLPointCloud2 classes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would rather not add these as getters, I don't think they would be used that often

Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated

@mvieth mvieth left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry for the delay

Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated


// Get point step. Does not directly exist in pcl::PointCloud
template <typename CloudT> inline int getPointStep(const CloudT&)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would rather not add these as getters, I don't think they would be used that often

Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated
Comment thread visualization/include/pcl/visualization/point_cloud_color_handlers.h Outdated
@themightyoarfish

Copy link
Copy Markdown
Contributor Author

I've moved some functions to io.h/hpp, but not kept some where they are since there are differing opinions it seems.

I'm a bit annoyed that due to the new getFields() specialization we now get many of these warnings for all code that uses it with PointCloud as the type, which does not need a value to determine the fields. Can we silence them somehow?

[260/578] Building CXX object tools/CMakeFiles/pcl_generate.dir/generate.cpp.o
In file included from /Users/rasmus/Downloads/source_builds/pcl/tools/generate.cpp:42:
In file included from /Users/rasmus/Downloads/source_builds/pcl/io/include/pcl/io/pcd_io.h:801:
In file included from /Users/rasmus/Downloads/source_builds/pcl/io/include/pcl/io/impl/pcd_io.hpp:48:
In file included from /Users/rasmus/Downloads/source_builds/pcl/common/include/pcl/common/io.h:593:
/Users/rasmus/Downloads/source_builds/pcl/common/include/pcl/common/impl/io.hpp:106:26: warning: unused parameter 'cloud' [-Wunused-parameter]
  106 | getFields (const CloudT& cloud)

Comment thread common/include/pcl/common/impl/io.hpp Outdated
virtual std::string
getName () const { return ("PointCloudColorHandlerGenericField"); }
/** \brief Name of the field used to create the color handler. */
std::string field_name_;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could this be private, like before?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

Co-authored-by: Markus Vieth <39675748+mvieth@users.noreply.github.com>
return std::distance(fields.begin(), result);
}

// Cloud type agnostic isXYZFinite wrappers to check if pointcloud or PCLPointCloud2 at

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm, maybe not, since one of the methods require getFieldIndex, which would give circular dependency.

@larshg

larshg commented Sep 17, 2025

Copy link
Copy Markdown
Contributor

Resolve conflict and its 👍 from here.

@larshg larshg added this to the pcl-1.16.0 milestone Sep 17, 2025
@larshg larshg added the changelog: enhancement Meta-information for changelog generation label Sep 17, 2025
Comment thread visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp Outdated
@themightyoarfish

Copy link
Copy Markdown
Contributor Author

Conflict resolved

}
}

const size_t point_offset = this->fields_[this->field_idx_].offset;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
const size_t point_offset = this->fields_[this->field_idx_].offset;
size_t point_offset = this->fields_[this->field_idx_].offset;

const does not work here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

god dammit, i was surprised to learn executing the tests does not recompile the modules they depend on.

fixed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How do you execute the tests? If you run the CMake target tests (e.g. like cmake --build . -- tests), then it should recompile the modules (if it doesn't, something may be broken?). If you just run the executable file (e.g. test_visualization), then it will of course not rebuild anything.

@mvieth mvieth left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@mvieth mvieth changed the title Wip: refactor PointcloudColorHandlerGenericField to deal with any field type Refactor PointcloudColorHandlerGenericField to deal with any field type Sep 24, 2025
@mvieth mvieth merged commit eec1d53 into PointCloudLibrary:master Sep 24, 2025
13 checks passed
Comment on lines +146 to +157
switch (type) {
case pcl::PCLPointField::PointFieldTypes::FLOAT32:
return reinterpret_and_cast<float, T>(data);
break;
case pcl::PCLPointField::PointFieldTypes::UINT8:
return reinterpret_and_cast<std::uint8_t, T>(data);
break;
case pcl::PCLPointField::PointFieldTypes::UINT16:
return reinterpret_and_cast<std::uint16_t, T>(data);
break;
case pcl::PCLPointField::PointFieldTypes::UINT32:
return reinterpret_and_cast<std::uint32_t, T>(data);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i noticed today in other code doing this, that UBSAN complains here about misaligned loads on some types. i.e. if the PCLPointCloud2 point data has first a uint8 field, then a uint16 field, the latter will start at an odd address, which apparently is not allowed for this type. so for everything larger than 8 bits, one would have to memcpy the data instead of just reinterpreting it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: enhancement Meta-information for changelog generation module: visualization

Projects

None yet

3 participants