Refactor VoxelGrid#4813
Conversation
* Implement a base class GridFilter * Implement the basic functionality of VoxelGrid * Implement basic unit tests
* Pass grid_ to setUp as an input
a858b54 to
9fedb4f
Compare
kunaltyagi
left a comment
There was a problem hiding this comment.
Can we split this into 2 PRs?
- Just grid-filter + tests
- voxel-grid + eqivalency tests
| template <typename T> | ||
| using get_grid_type = typename T::Grid; | ||
|
|
||
| template <typename GridStruct, |
There was a problem hiding this comment.
Thoughts on splitting this class into 2 parts?
- minimal wrt API, like FunctionFilter, and call it something like TransformAndFilter
- GridFilterBase which implements the common API for VoxelFilter, etc.
Rationale:
- easy to review the functionality and the API as 2 different things
- Users can use TransformAndFilter class when they don't need the API. Eg:
setDownsampleAllData
There was a problem hiding this comment.
Do you mean some counterpart like FilterIndices? But do some transform (e.g. random sampling) instead of binary removal? But then this kind of transform filters don't have common logic/method basically
There was a problem hiding this comment.
But then this kind of transform filters don't have common logic/method basically
No common logic/method needed. Just bare bone functionality. The common API will be provided by GridFilterBase
There was a problem hiding this comment.
What would be included in TransformAndFilter? Like the logic inside applyFilter?
There was a problem hiding this comment.
applyFilter and the absolute minimum required stuff
There was a problem hiding this comment.
I would prefer not splitting for now.
- The API in
GridFilternow is already quite minimum IMO - We have to also consider other non binary removal filters, since in principle they also belong to
TransformAndFilter
We can come back to this after finishing the grid filters
|
VoxelGrid looks busy, but appears to have a solid implementation. Good work :) |
It's also good for me, but does that mean I have to develop them in separate branches simultaneously? @kunaltyagi (I'll separate the two unit testing to two |
* Use numeric_limits instead of cfloat * Upgrade unsigned int to size_t * Add const to input of setters * Remove duplicate function * Remove clearing output if empty input * Move grid_to GridStruct * Reformat the documentation
f03bd7e to
0306e1b
Compare
|
Yes, if the code is split in 2 PRs, you'll have to develop them independently. But you can simply make the branch for VoxelFilter derive from GridFilter and then you'll only have to develop the features once. You can use the rebase functionality (or merge functionality) to continually get the latest work from the GridFilter branch into the VoxelFilter branch. |
Then I'll close this draft PR and open 2 new ones after I finish the WIP code to here, since the commits here already mixed up the implementation of the two classes |
* Reduce O(N^2) output points test to O(NlogN) * Implement test for VoxelGrid protected methods
afd5da2 to
1813946
Compare
| /** \brief Set to true if all fields need to be downsampled, or false if just XYZ. | ||
| * \param[in] downsample the new value (true/false) | ||
| */ | ||
| inline void | ||
| setDownsampleAllData(const bool downsample) | ||
| { | ||
| downsample_all_data_ = downsample; | ||
| } | ||
|
|
||
| /** \brief Get the state of the internal downsampling parameter (true if all fields | ||
| * need to be downsampled, false if just XYZ). | ||
| */ | ||
| inline bool | ||
| getDownsampleAllData() const | ||
| { | ||
| return downsample_all_data_; | ||
| } | ||
|
|
||
| /** \brief Set the minimum number of points required for a voxel to be used. | ||
| * \param[in] min_points_per_voxel the minimum number of points for required for a | ||
| * voxel to be used | ||
| */ | ||
| inline void | ||
| setMinimumPointsNumberPerVoxel(const std::size_t min_points_per_voxel) | ||
| { | ||
| min_points_per_voxel_ = min_points_per_voxel; | ||
| } | ||
|
|
||
| /** \brief Return the minimum number of points required for a voxel to be used. | ||
| */ | ||
| inline std::size_t | ||
| getMinimumPointsNumberPerVoxel() const | ||
| { | ||
| return min_points_per_voxel_; | ||
| } | ||
|
|
||
| /** \brief Set to true if leaf layout information needs to be saved for later access. | ||
| * \param[in] save_leaf_layout the new value (true/false) | ||
| */ | ||
| inline void | ||
| setSaveLeafLayout(const bool save_leaf_layout) | ||
| { | ||
| save_leaf_layout_ = save_leaf_layout; | ||
| } | ||
|
|
||
| /** \brief Returns true if leaf layout information will to be saved for later access. | ||
| */ | ||
| inline bool | ||
| getSaveLeafLayout() const | ||
| { | ||
| return save_leaf_layout_; | ||
| } | ||
|
|
||
| /** \brief Provide the name of the field to be used for filtering data. In conjunction | ||
| * with \a setFilterLimits, points having values outside this interval will be | ||
| * discarded. | ||
| * \param[in] field_name the name of the field that contains values used for filtering | ||
| */ | ||
| inline void | ||
| setFilterFieldName(const std::string& field_name) | ||
| { | ||
| filter_field_name_ = field_name; | ||
| } | ||
|
|
||
| /** \brief Get the name of the field used for filtering. */ | ||
| inline std::string const | ||
| getFilterFieldName() const | ||
| { | ||
| return filter_field_name_; | ||
| } | ||
|
|
||
| /** \brief Get the field filter limits (min/max) set by the user. The default values | ||
| * are numeric_limits<double>::min(), numeric_limits<double>::max(). | ||
| * \param[out] limit_min the minimum allowed field value | ||
| * \param[out] limit_max the maximum allowed field value | ||
| */ | ||
| inline void | ||
| getFilterLimits(double& limit_min, double& limit_max) const | ||
| { | ||
| limit_min = filter_limit_min_; | ||
| limit_max = filter_limit_max_; | ||
| } | ||
|
|
||
| /** \brief Set to true if we want to return the data outside the interval specified by | ||
| * setFilterLimits (min, max). | ||
| * Default: false. | ||
| * \param[in] limit_negative return data inside the interval (false) or outside (true) | ||
| */ | ||
| inline void | ||
| setFilterLimitsNegative(const bool limit_negative) | ||
| { | ||
| filter_limit_negative_ = limit_negative; | ||
| } | ||
|
|
||
| /** \brief Get whether the data outside the interval (min/max) is to be returned | ||
| * (true) or inside (false). | ||
| * \param[out] limit_negative true if data \b outside the interval [min; max] is to be | ||
| * returned, false otherwise | ||
| */ | ||
| inline void | ||
| getFilterLimitsNegative(bool& limit_negative) const | ||
| { | ||
| limit_negative = filter_limit_negative_; | ||
| } | ||
|
|
||
| /** \brief Get whether the data outside the interval (min/max) is to be returned | ||
| * (true) or inside (false). | ||
| * \return true if data \b outside the interval [min; max] is to be returned, false | ||
| * otherwise | ||
| */ | ||
| inline bool | ||
| getFilterLimitsNegative() const | ||
| { | ||
| return filter_limit_negative_; | ||
| } | ||
|
|
||
| protected: | ||
| /** \brief Set to true if all fields need to be downsampled, or false if just XYZ. */ | ||
| bool downsample_all_data_; | ||
|
|
||
| /** \brief Set to true if leaf layout information needs to be saved in \a | ||
| * leaf_layout_. */ | ||
| bool save_leaf_layout_; | ||
|
|
||
| /** \brief The desired user filter field name. */ | ||
| std::string filter_field_name_; | ||
|
|
||
| /** \brief The minimum allowed filter value a point will be considered from. */ | ||
| double filter_limit_min_; | ||
|
|
||
| /** \brief The maximum allowed filter value a point will be considered from. */ | ||
| double filter_limit_max_; | ||
|
|
||
| /** \brief Set to true if we want to return the data outside (\a filter_limit_min_;\a | ||
| * filter_limit_max_). | ||
| * Default: false. */ | ||
| bool filter_limit_negative_; | ||
|
|
||
| /** \brief Minimum number of points per voxel for the centroid to be computed */ | ||
| std::size_t min_points_per_voxel_; |
There was a problem hiding this comment.
This is the API that makes GridFilter non-minimalistic. By keeping this in GridFilter and moving the applyFilter and friends out into TransforAndFilter, reasoning about the required API for the filter becomes easier
There was a problem hiding this comment.
I see, I can try that out
5344891 to
ce88853
Compare
ce88853 to
064fd26
Compare
877c686 to
4e9db59
Compare
|
Close and split into two new PRs |
| const size_t max_size = std::numeric_limits<size_t>::max(); | ||
|
|
||
| // check unsigned int overflow/wrap-around | ||
| if (dy > max_size / dx || dx * dy > max_size / dz) { |
There was a problem hiding this comment.
By doing this, we now can use the full range of size_t
Goals of this PR:
GridFilterapplyFilterApproximateVoxelGrid,GridMinimum,VoxelGridLabel,UniformSamplingstd::unordered_mapinstead of sorting to gather points into voxel