Untitled Diff

Created Diff never expires
539 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
582 lines
432 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
508 lines
/*
/*
* Software License Agreement (BSD License)
* Software License Agreement (BSD License)
*
*
* Point Cloud Library (PCL) - www.pointclouds.org
* Point Cloud Library (PCL) - www.pointclouds.org
* Copyright (c) 2010-2011, Willow Garage, Inc.
* Copyright (c) 2010-2011, Willow Garage, Inc.
*
*
* All rights reserved.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* modification, are permitted provided that the following conditions
* are met:
* are met:
*
*
* * Redistributions of source code must retain the above copyright
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* with the distribution.
* * Neither the name of the copyright holder(s) nor the names of its
* * Neither the name of the copyright holder(s) nor the names of its
* contributors may be used to endorse or promote products derived
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* POSSIBILITY OF SUCH DAMAGE.
*
*
* $Id$
* $Id$
*
*
*/
*/


#pragma once
#ifndef PCL18_BACKPORTS_VOXEL_GRID_H
#define PCL18_BACKPORTS_VOXEL_GRID_H

#ifndef BACKPORT_PCL_VOXEL_GRID

#include <pcl/filters/voxel_grid.h>

namespace pcl
{
template <typename PointT>
using VoxelGrid18 = VoxelGrid<PointT>;
}

#else

// System has old PCL; backport VoxelGrid from pcl-1.8

#include <algorithm>
#include <cmath>
#include <functional>
#include <limits>
#include <string>
#include <utility>
#include <vector>


#include <pcl/common/centroid.h>
#include <pcl/filters/boost.h>
#include <pcl/filters/boost.h>
#include <pcl/filters/filter.h>
#include <pcl/filters/filter.h>
#include <map>


namespace pcl
namespace pcl
{
{
/** \brief Obtain the maximum and minimum points in 3D from a given point cloud.
/** \brief VoxelGrid assembles a local 3D grid over a given PointCloud, and downsamples + filters the data.
* \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset
*
* \param[in] x_idx the index of the X channel
* The VoxelGrid class creates a *3D voxel grid* (think about a voxel
* \param[in] y_idx the index of the Y channel
* grid as a set of tiny 3D boxes in space) over the input point cloud data.
* \param[in] z_idx the index of the Z channel
* Then, in each *voxel* (i.e., 3D box), all the points present will be
* \param[out] min_pt the minimum data point
* approximated (i.e., *downsampled*) with their centroid. This approach is
* \param[out] max_pt the maximum data point
* a bit slower than approximating them with the center of the voxel, but it
*/
* represents the underlying surface more accurately.
PCL_EXPORTS void
*
getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx,
* \author Radu B. Rusu, Bastian Steder
Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt);
* \ingroup filters
*/
template <typename PointT>
class VoxelGrid18 : public Filter<PointT>
{
protected:
using Filter<PointT>::filter_name_;
using Filter<PointT>::getClassName;
using Filter<PointT>::input_;
using Filter<PointT>::indices_;


/** \brief Obtain the maximum and minimum points in 3D from a given point cloud.
typedef typename Filter<PointT>::PointCloud PointCloud;
* \note Performs internal data filtering as well.
typedef typename PointCloud::Ptr PointCloudPtr;
* \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset
typedef typename PointCloud::ConstPtr PointCloudConstPtr;
* \param[in] x_idx the index of the X channel
* \param[in] y_idx the index of the Y channel
* \param[in] z_idx the index of the Z channel
* \param[in] distance_field_name the name of the dimension to filter data along to
* \param[in] min_distance the minimum acceptable value in \a distance_field_name data
* \param[in] max_distance the maximum acceptable value in \a distance_field_name data
* \param[out] min_pt the minimum data point
* \param[out] max_pt the maximum data point
* \param[in] limit_negative \b false if data \b inside of the [min_distance; max_distance] interval should be
* considered, \b true otherwise.
*/
PCL_EXPORTS void
getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx,
const std::string &distance_field_name, float min_distance, float max_distance,
Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative = false);


/** \brief Get the relative cell indices of the "upper half" 13 neighbors.
public:
* \note Useful in combination with getNeighborCentroidIndices() from \ref VoxelGrid
typedef boost::shared_ptr<VoxelGrid18<PointT>> Ptr;
* \ingroup filters
typedef boost::shared_ptr<const VoxelGrid18<PointT>> ConstPtr;
*/

inline Eigen::MatrixXi
/** \brief Empty constructor. */
getHalfNeighborCellIndices ()
VoxelGrid18()
: leaf_size_(Eigen::Vector4f::Zero())
, inverse_leaf_size_(Eigen::Array4f::Zero())
, leaf_layout_()
, min_b_(Eigen::Vector4i::Zero())
, max_b_(Eigen::Vector4i::Zero())
, div_b_(Eigen::Vector4i::Zero())
, divb_mul_(Eigen::Vector4i::Zero())
, filter_limit_min_(-std::numeric_limits<float>::max())
, filter_limit_max_(std::numeric_limits<float>::max())
, filter_limit_negative_(false)
, min_points_per_voxel_(0)
{
{
Eigen::MatrixXi relative_coordinates (3, 13);
filter_name_ = "VoxelGrid";
int idx = 0;
}


// 0 - 8
/** \brief Destructor. */
for (int i = -1; i < 2; i++)
virtual ~VoxelGrid18()
{
{
for (int j = -1; j < 2; j++)
}
{
relative_coordinates (0, idx) = i;
relative_coordinates (1, idx) = j;
relative_coordinates (2, idx) = -1;
idx++;
}
}
// 9 - 11
for (int i = -1; i < 2; i++)
{
relative_coordinates (0, idx) = i;
relative_coordinates (1, idx) = -1;
relative_coordinates (2, idx) = 0;
idx++;
}
// 12
relative_coordinates (0, idx) = -1;
relative_coordinates (1, idx) = 0;
relative_coordinates (2, idx) = 0;


return (relative_coordinates);
/** \brief Set the voxel grid leaf size.
* \param[in] leaf_size the voxel grid leaf size
*/
inline void
setLeafSize(const Eigen::Vector4f& leaf_size)
{
leaf_size_ = leaf_size;
// Avoid division errors
if (leaf_size_[3] == 0)
leaf_size_[3] = 1;
// Use multiplications instead of divisions
inverse_leaf_size_ = Eigen::Array4f::Ones() / leaf_size_.array();
}
}


/** \brief Get the relative cell indices of all the 26 neighbors.
/** \brief Set the voxel grid leaf size.
* \note Useful in combination with getNeighborCentroidIndices() from \ref VoxelGrid
* \param[in] lx the leaf size for X
* \ingroup filters
* \param[in] ly the leaf size for Y
*/
* \param[in] lz the leaf size for Z
inline Eigen::MatrixXi
*/
getAllNeighborCellIndices ()
inline void
setLeafSize(float lx, float ly, float lz)
{
{
Eigen::MatrixXi relative_coordinates = getHalfNeighborCellIndices ();
leaf_size_[0] = lx;
Eigen::MatrixXi relative_coordinates_all( 3, 26);
leaf_size_[1] = ly;
relative_coordinates_all.block<3, 13> (0, 0) = relative_coordinates;
leaf_size_[2] = lz;
relative_coordinates_all.block<3, 13> (0, 13) = -relative_coordinates;
// Avoid division errors
return (relative_coordinates_all);
if (leaf_size_[3] == 0)
leaf_size_[3] = 1;
// Use multiplications instead of divisions
inverse_leaf_size_ = Eigen::Array4f::Ones() / leaf_size_.array();
}
}


/** \brief Get the minimum and maximum values on each of the 3 (x-y-z) dimensions
/** \brief Get the voxel grid leaf size. */
* in a given pointcloud, without considering points outside of a distance threshold from the laser origin
inline Eigen::Vector3f
* \param[in] cloud the point cloud data message
getLeafSize() const
* \param[in] distance_field_name the field name that contains the distance values
{
* \param[in] min_distance the minimum distance a point will be considered from
return (leaf_size_.head<3>());
* \param[in] max_distance the maximum distance a point will be considered to
}
* \param[out] min_pt the resultant minimum bounds
* \param[out] max_pt the resultant maximum bounds
* \param[in] limit_negative if set to true, then all points outside of the interval (min_distance;max_distace) are considered
* \ingroup filters
*/
template <typename PointT> void
getMinMax3D (const typename pcl::PointCloud<PointT>::ConstPtr &cloud,
const std::string &distance_field_name, float min_distance, float max_distance,
Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative = false);


/** \brief Get the minimum and maximum values on each of the 3 (x-y-z) dimensions
/** \brief Set the minimum number of points required for a voxel to be used.
* in a given pointcloud, without considering points outside of a distance threshold from the laser origin
* \param[in] min_points_per_voxel the minimum number of points for required for a voxel to be used
* \param[in] cloud the point cloud data message
*/
* \param[in] indices the vector of indices to use
inline void
* \param[in] distance_field_name the field name that contains the distance values
setMinimumPointsNumberPerVoxel(unsigned int min_points_per_voxel)
* \param[in] min_distance the minimum distance a point will be considered from
{
* \param[in] max_distance the maximum distance a point will be considered to
min_points_per_voxel_ = min_points_per_voxel;
* \param[out] min_pt the resultant minimum bounds
}
* \param[out] max_pt the resultant maximum bounds
* \param[in] limit_negative if set to true, then all points outside of the interval (min_distance;max_distace) are considered
* \ingroup filters
*/
template <typename PointT> void
getMinMax3D (const typename pcl::PointCloud<PointT>::ConstPtr &cloud,
const std::vector<int> &indices,
const std::string &distance_field_name, float min_distance, float max_distance,
Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, bool limit_negative = false);


/** \brief VoxelGrid assembles a local 3D grid over a given PointCloud, and downsamples + filters the data.
/** \brief Return the minimum number of points required for a voxel to be used.
*
* The VoxelGrid class creates a *3D voxel grid* (think about a voxel
* grid as a set of tiny 3D boxes in space) over the input point cloud data.
* Then, in each *voxel* (i.e., 3D box), all the points present will be
* approximated (i.e., *downsampled*) with their centroid. This approach is
* a bit slower than approximating them with the center of the voxel, but it
* represents the underlying surface more accurately.
*
* \author Radu B. Rusu, Bastian Steder
* \ingroup filters
*/
*/
template <typename PointT>
inline unsigned int
class VoxelGrid: public Filter<PointT>
getMinimumPointsNumberPerVoxel() const
{
{
protected:
return min_points_per_voxel_;
using Filter<PointT>::filter_name_;
}
using Filter<PointT>::getClassName;
using Filter<PointT>::input_;
using Filter<PointT>::indices_;

using PointCloud = typename Filter<PointT>::PointCloud;
using PointCloudPtr = typename PointCloud::Ptr;
using PointCloudConstPtr = typename PointCloud::ConstPtr;

public:

using Ptr = shared_ptr<VoxelGrid<PointT> >;
using ConstPtr = shared_ptr<const VoxelGrid<PointT> >;

/** \brief Empty constructor. */
VoxelGrid () :
leaf_size_ (Eigen::Vector4f::Zero ()),
inverse_leaf_size_ (Eigen::Array4f::Zero ()),
downsample_all_data_ (true),
save_leaf_layout_ (false),
min_b_ (Eigen::Vector4i::Zero ()),
max_b_ (Eigen::Vector4i::Zero ()),
div_b_ (Eigen::Vector4i::Zero ()),
divb_mul_ (Eigen::Vector4i::Zero ()),
filter_field_name_ (""),
filter_limit_min_ (-FLT_MAX),
filter_limit_max_ (FLT_MAX),
filter_limit_negative_ (false),
min_points_per_voxel_ (0)
{
filter_name_ = "VoxelGrid";
}

/** \brief Destructor. */
~VoxelGrid ()
{
}


/** \brief Set the voxel grid leaf size.
/** \brief Get the minimum coordinates of the bounding box (after
* \param[in] leaf_size the voxel grid leaf size
* filtering is performed).
*/
*/
inline void
inline Eigen::Vector3i
setLeafSize (const Eigen::Vector4f &leaf_size)
getMinBoxCoordinates() const
{
{
leaf_size_ = leaf_size;
return (min_b_.head<3>());
// Avoid division errors
}
if (leaf_size_[3] == 0)
leaf_size_[3] = 1;
// Use multiplications instead of divisions
inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
}


/** \brief Set the voxel grid leaf size.
/** \brief Get the minimum coordinates of the bounding box (after
* \param[in] lx the leaf size for X
* filtering is performed).
* \param[in] ly the leaf size for Y
*/
* \param[in] lz the leaf size for Z
inline Eigen::Vector3i
*/
getMaxBoxCoordinates() const
inline void
{
setLeafSize (float lx, float ly, float lz)
return (max_b_.head<3>());
{
}
leaf_size_[0] = lx; leaf_size_[1] = ly; leaf_size_[2] = lz;
// Avoid division errors
if (leaf_size_[3] == 0)
leaf_size_[3] = 1;
// Use multiplications instead of divisions
inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
}


/** \brief Get the voxel grid leaf size. */
/** \brief Get the number of divisions along all 3 axes (after filtering
inline Eigen::Vector3f
* is performed).
getLeafSize () const { return (leaf_size_.head<3> ()); }
*/
inline Eigen::Vector3i
getNrDivisions() const
{
return (div_b_.head<3>());
}


/** \brief Set to true if all fields need to be downsampled, or false if just XYZ.
/** \brief Get the multipliers to be applied to the grid coordinates in
* \param[in] downsample the new value (true/false)
* order to find the centroid index (after filtering is performed).
*/
*/
inline void
inline Eigen::Vector3i
setDownsampleAllData (bool downsample) { downsample_all_data_ = downsample; }
getDivisionMultiplier() const
{
return (divb_mul_.head<3>());
}


/** \brief Get the state of the internal downsampling parameter (true if
/** \brief Returns the index in the resulting downsampled cloud of the specified point.
* all fields need to be downsampled, false if just XYZ).
*
*/
* \note for efficiency, user must make sure that the saving of the leaf layout is enabled and filtering
inline bool
* performed, and that the point is inside the grid, to avoid invalid access (or use
getDownsampleAllData () const { return (downsample_all_data_); }
* getGridCoordinates+getCentroidIndexAt)
*
* \param[in] p the point to get the index at
*/
inline int
getCentroidIndex(const PointT& p) const
{
return (leaf_layout_.at((Eigen::Vector4i(static_cast<int>(std::floor(p.x * inverse_leaf_size_[0])),
static_cast<int>(std::floor(p.y * inverse_leaf_size_[1])),
static_cast<int>(std::floor(p.z * inverse_leaf_size_[2])), 0) -
min_b_)
.dot(divb_mul_)));
}


/** \brief Set the minimum number of points required for a voxel to be used.
/** \brief Returns the indices in the resulting downsampled cloud of the points at the specified grid coordinates,
* \param[in] min_points_per_voxel the minimum number of points for required for a voxel to be used
* relative to the grid coordinates of the specified point (or -1 if the cell was empty/out of bounds).
*/
* \param[in] reference_point the coordinates of the reference point (corresponding cell is allowed to be empty/out of bounds)
inline void
* \param[in] relative_coordinates matrix with the columns being the coordinates of the requested cells, relative to the reference point's cell
setMinimumPointsNumberPerVoxel (unsigned int min_points_per_voxel) { min_points_per_voxel_ = min_points_per_voxel; }
* \note for efficiency, user must make sure that the saving of the leaf layout is enabled and filtering performed
*/
inline std::vector<int>
getNeighborCentroidIndices(const PointT& reference_point, const Eigen::MatrixXi& relative_coordinates) const
{
Eigen::Vector4i ijk(static_cast<int>(std::floor(reference_point.x * inverse_leaf_size_[0])),
static_cast<int>(std::floor(reference_point.y * inverse_leaf_size_[1])),
static_cast<int>(std::floor(reference_point.z * inverse_leaf_size_[2])), 0);
Eigen::Array4i diff2min = min_b_ - ijk;
Eigen::Array4i diff2max = max_b_ - ijk;
std::vector<int> neighbors(relative_coordinates.cols());
for (int ni = 0; ni < relative_coordinates.cols(); ni++)
{
Eigen::Vector4i displacement = (Eigen::Vector4i() << relative_coordinates.col(ni), 0).finished();
// checking if the specified cell is in the grid
if ((diff2min <= displacement.array()).all() && (diff2max >= displacement.array()).all())
neighbors[ni] = leaf_layout_[((ijk + displacement - min_b_).dot(divb_mul_))]; // .at() can be omitted
else
neighbors[ni] = -1; // cell is out of bounds, consider it empty
}
return (neighbors);
}


/** \brief Return the minimum number of points required for a voxel to be used.
/** \brief Returns the layout of the leafs for fast access to cells relative to current position.
*/
* \note position at (i-min_x) + (j-min_y)*div_x + (k-min_z)*div_x*div_y holds the index of the element at coordinates (i,j,k) in the grid (-1 if empty)
inline unsigned int
*/
getMinimumPointsNumberPerVoxel () const { return min_points_per_voxel_; }
inline std::vector<int>
getLeafLayout() const
{
return (leaf_layout_);
}


/** \brief Set to true if leaf layout information needs to be saved for later access.
/** \brief Returns the corresponding (i,j,k) coordinates in the grid of point (x,y,z).
* \param[in] save_leaf_layout the new value (true/false)
* \param[in] x the X point coordinate to get the (i, j, k) index at
*/
* \param[in] y the Y point coordinate to get the (i, j, k) index at
inline void
* \param[in] z the Z point coordinate to get the (i, j, k) index at
setSaveLeafLayout (bool save_leaf_layout) { save_leaf_layout_ = save_leaf_layout; }
*/
inline Eigen::Vector3i
getGridCoordinates(float x, float y, float z) const
{
return (Eigen::Vector3i(static_cast<int>(std::floor(x * inverse_leaf_size_[0])),
static_cast<int>(std::floor(y * inverse_leaf_size_[1])),
static_cast<int>(std::floor(z * inverse_leaf_size_[2]))));
}


/** \brief Returns true if leaf layout information will to be saved for later access. */
/** \brief Returns the index in the downsampled cloud corresponding to a given set of coordinates.
inline bool
* \param[in] ijk the coordinates (i,j,k) in the grid (-1 if empty)
getSaveLeafLayout () const { return (save_leaf_layout_); }
*/
inline int
getCentroidIndexAt(const Eigen::Vector3i& ijk) const
{
int idx = ((Eigen::Vector4i() << ijk, 0).finished() - min_b_).dot(divb_mul_);
if (idx < 0 || idx >= static_cast<int>(leaf_layout_.size()))
// this checks also if leaf_layout_.size () == 0 i.e. everything was computed as needed
{
return (-1);
}
return (leaf_layout_[idx]);
}


/** \brief Get the minimum coordinates of the bounding box (after
/** \brief Set the field filter limits. All points having field values outside this interval will be discarded.
* filtering is performed).
* \param[in] limit_min the minimum allowed field value
*/
* \param[in] limit_max the maximum allowed field value
inline Eigen::Vector3i
*/
getMinBoxCoordinates () const { return (min_b_.head<3> ()); }
inline void
setFilterLimits(const double& limit_min, const double& limit_max)
{
filter_limit_min_ = limit_min;
filter_limit_max_ = limit_max;
}


/** \brief Get the minimum coordinates of the bounding box (after
/** \brief Get the field filter limits (min/max) set by the user. The default values are -std::numeric_limits<float>::max(), std::numeric_limits<float>::max().
* filtering is performed).
* \param[out] limit_min the minimum allowed field value
*/
* \param[out] limit_max the maximum allowed field value
inline Eigen::Vector3i
*/
getMaxBoxCoordinates () const { return (max_b_.head<3> ()); }
inline void
getFilterLimits(double& limit_min, double& limit_max) const
{
limit_min = filter_limit_min_;
limit_max = filter_limit_max_;
}


/** \brief Get the number of divisions along all 3 axes (after filtering
/** \brief Set to true if we want to return the data outside the interval specified by setFilterLimits (min, max).
* is performed).
* Default: false.
*/
* \param[in] limit_negative return data inside the interval (false) or outside (true)
inline Eigen::Vector3i
*/
getNrDivisions () const { return (div_b_.head<3> ()); }
inline void
setFilterLimitsNegative(const bool limit_negative)
{
filter_limit_negative_ = limit_negative;
}


/** \brief Get the multipliers to be applied to the grid coordinates in
/** \brief Get whether the data outside the interval (min/max) is to be returned (true) or inside (false).
* order to find the centroid index (after filtering is performed).
* \param[out] limit_negative true if data \b outside the interval [min; max] is to be returned, false otherwise
*/
*/
inline Eigen::Vector3i
inline void
getDivisionMultiplier () const { return (divb_mul_.head<3> ()); }
getFilterLimitsNegative(bool& limit_negative) const
{
limit_negative = filter_limit_negative_;
}


/** \brief Returns the index in the resulting downsampled cloud of the specified point.
/** \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
* \note for efficiency, user must make sure that the saving of the leaf layout is enabled and filtering
*/
* performed, and that the point is inside the grid, to avoid invalid access (or use
inline bool
* getGridCoordinates+getCentroidIndexAt)
getFilterLimitsNegative() const
*
{
* \param[in] p the point to get the index at
return (filter_limit_negative_);
*/
}
inline int
getCentroidIndex (const PointT &p) const
{
return (leaf_layout_.at ((Eigen::Vector4i (static_cast<int> (std::floor (p.x * inverse_leaf_size_[0])),
static_cast<int> (std::floor (p.y * inverse_leaf_size_[1])),
static_cast<int> (std::floor (p.z * inverse_leaf_size_[2])), 0) - min_b_).dot (divb_mul_)));
}


/** \brief Returns the indices in the resulting downsampled cloud of the points at the specified grid coordinates,
protected:
* relative to the grid coordinates of the specified point (or -1 if the cell was empty/out of bounds).
/** \brief The size of a leaf. */
* \param[in] reference_point the coordinates of the reference point (corresponding cell is allowed to be empty/out of bounds)
Eigen::Vector4f leaf_size_;
* \param[in] relative_coordinates matrix with the columns being the coordinates of the requested cells, relative to the reference point's cell
* \note for efficiency, user must make sure that the saving of the leaf layout is enabled and filtering performed
*/
inline std::vector<int>
getNeighborCentroidIndices (const PointT &reference_point, const Eigen::MatrixXi &relative_coordinates) const
{
Eigen::Vector4i ijk (static_cast<int> (std::floor (reference_point.x * inverse_leaf_size_[0])),
static_cast<int> (std::floor (reference_point.y * inverse_leaf_size_[1])),
static_cast<int> (std::floor (reference_point.z * inverse_leaf_size_[2])), 0);
Eigen::Array4i diff2min = min_b_ - ijk;
Eigen::Array4i diff2max = max_b_ - ijk;
std::vector<int> neighbors (relative_coordinates.cols());
for (Eigen::Index ni = 0; ni < relative_coordinates.cols (); ni++)
{
Eigen::Vector4i displacement = (Eigen::Vector4i() << relative_coordinates.col(ni), 0).finished();
// checking if the specified cell is in the grid
if ((diff2min <= displacement.array()).all() && (diff2max >= displacement.array()).all())
neighbors[ni] = leaf_layout_[((ijk + displacement - min_b_).dot (divb_mul_))]; // .at() can be omitted
else
neighbors[ni] = -1; // cell is out of bounds, consider it empty
}
return (neighbors);
}


/** \brief Returns the layout of the leafs for fast access to cells relative to current position.
/** \brief Internal leaf sizes stored as 1/leaf_size_ for efficiency reasons. */
* \note position at (i-min_x) + (j-min_y)*div_x + (k-min_z)*div_x*div_y holds the index of the element at coordinates (i,j,k) in the grid (-1 if empty)
Eigen::Array4f inverse_leaf_size_;
*/
inline std::vector<int>
getLeafLayout () const { return (leaf_layout_); }


/** \brief Returns the corresponding (i,j,k) coordinates in the grid of point (x,y,z).
/** \brief The leaf layout information for fast access to cells relative to current position **/
* \param[in] x the X point coordinate to get the (i, j, k) index at
std::vector<int> leaf_layout_;
* \param[in] y the Y point coordinate to get the (i, j, k) index at
* \param[in] z the Z point coordinate to get the (i, j, k) index at
*/
inline Eigen::Vector3i
getGridCoordinates (float x, float y, float z) const
{
return (Eigen::Vector3i (static_cast<int> (std::floor (x * inverse_leaf_size_[0])),
static_cast<int> (std::floor (y * inverse_leaf_size_[1])),
static_cast<int> (std::floor (z * inverse_leaf_size_[2]))));
}


/** \brief Returns the index in the downsampled cloud corresponding to a given set of coordinates.
/** \brief The minimum and maximum bin coordinates, the number of divisions, and the division multiplier. */
* \param[in] ijk the coordinates (i,j,k) in the grid (-1 if empty)
Eigen::Vector4i min_b_, max_b_, div_b_, divb_mul_;
*/
inline int
getCentroidIndexAt (const Eigen::Vector3i &ijk) const
{
int idx = ((Eigen::Vector4i() << ijk, 0).finished() - min_b_).dot (divb_mul_);
if (idx < 0 || idx >= static_cast<int> (leaf_layout_.size ())) // this checks also if leaf_layout_.size () == 0 i.e. everything was computed as needed
{
//if (verbose)
// PCL_ERROR ("[pcl::%s::getCentroidIndexAt] Specified coordinate is outside grid bounds, or leaf layout is not saved, make sure to call setSaveLeafLayout(true) and filter(output) first!\n", getClassName ().c_str ());
return (-1);
}
return (leaf_layout_[idx]);
}


/** \brief Provide the name of the field to be used for filtering data. In conjunction with \a setFilterLimits,
/** \brief The minimum allowed filter value a point will be considered from. */
* points having values outside this interval will be discarded.
double filter_limit_min_;
* \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. */
/** \brief The maximum allowed filter value a point will be considered from. */
inline std::string const
double filter_limit_max_;
getFilterFieldName () const
{
return (filter_field_name_);
}


/** \brief Set the field filter limits. All points having field values outside this interval will be discarded.
/** \brief Set to true if we want to return the data outside
* \param[in] limit_min the minimum allowed field value
(\a filter_limit_min_;\a filter_limit_max_). Default: false. */
* \param[in] limit_max the maximum allowed field value
bool filter_limit_negative_;
*/
inline void
setFilterLimits (const double &limit_min, const double &limit_max)
{
filter_limit_min_ = limit_min;
filter_limit_max_ = limit_max;
}


/** \brief Get the field filter limits (min/max) set by the user. The default values are -FLT_MAX, FLT_MAX.
/** \brief Minimum number of points per voxel for the centroid to be computed */
* \param[out] limit_min the minimum allowed field value
unsigned int min_points_per_voxel_;
* \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).
typedef typename pcl::traits::fieldList<PointT>::type FieldList;
* 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).
/** \brief Downsample a Point Cloud using a voxelized grid approach
* \param[out] limit_negative true if data \b outside the interval [min; max] is to be returned, false otherwise
* \param[out] output the resultant point cloud message
*/
*/
inline void
void
getFilterLimitsNegative (bool &limit_negative) const
applyFilter(PointCloud& output)
{
{
limit_negative = filter_limit_negative_;
// Has the input dataset been set already?
}
if (!input_)
{
PCL_WARN("[pcl::%s::applyFilter] No input dataset given!\n", getClassName().c_str());
output.width = output.height = 0;
output.points.clear();
return;
}


/** \brief Get whether the data outside the interval (min/max) is to be returned (true) or inside (false).
// Copy the header (and thus the frame_id) + allocate enough space for points
* \return true if data \b outside the interval [min; max] is to be returned, false otherwise
output.height = 1; // downsampling breaks the organized structure
*/
output.is_dense = true; // we filter out invalid points
inline bool
getFilterLimitsNegative () const
{
return (filter_limit_negative_);
}


protected:
Eigen::Vector4f min_p, max_p;
/** \brief The size of a leaf. */
getMinMax3D<PointT>(*input_, *indices_, min_p, max_p);
Eigen::Vector4f leaf_size_;


/** \brief Internal leaf sizes stored as 1/leaf_size_ for efficiency reasons. */
// Check that the leaf size is not too small, given the size of the data
Eigen::Array4f inverse_leaf_size_;
int64_t dx = static_cast<int64_t>((max_p[0] - min_p[0]) * inverse_leaf_size_[0]) + 1;
int64_t dy = static_cast<int64_t>((max_p[1] - min_p[1]) * inverse_leaf_size_[1]) + 1;
int64_t dz = static_cast<int64_t>((max_p[2] - min_p[2]) * inverse_leaf_size_[2]) + 1;


/** \brief Set to true if all fields need to be downsampled, or false if just XYZ. */
if ((dx * dy * dz) > static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
bool downsample_all_data_;
{
PCL_WARN("[pcl::%s::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow.",
getClassName().c_str());
output = *input_;
return;
}


/** \brief Set to true if leaf layout information needs to be saved in \a leaf_layout_. */
// Compute the minimum and maximum bounding box values
bool save_leaf_layout_;
min_b_[0] = static_cast<int>(std::floor(min_p[0] * inverse_leaf_size_[0]));
max_b_[0] = static_cast<int>(std::floor(max_p[0] * inverse_leaf_size_[0]));
min_b_[1] = static_cast<int>(std::floor(min_p[1] * inverse_leaf_size_[1]));
max_b_[1] = static_cast<int>(std::floor(max_p[1] * inverse_leaf_size_[1]));
min_b_[2] = static_cast<int>(std::floor(min_p[2] * inverse_leaf_size_[2]));
max_b_[2] = static_cast<int>(std::floor(max_p[2] * inverse_leaf_size_[2]));


/** \brief The leaf layout information for fast access to cells relative to current position **/
// Compute the number of divisions needed along all axis
std::vector<int> leaf_layout_;
div_b_ = max_b_ - min_b_ + Eigen::Vector4i::Ones();
div_b_[3] = 0;


/** \brief The minimum and maximum bin coordinates, the number of divisions, and the division multiplier. */
// Set up the division multiplier
Eigen::Vector4i min_b_, max_b_, div_b_, divb_mul_;
divb_mul_ = Eigen::Vector4i(1, div_b_[0], div_b_[0] * div_b_[1], 0);


/** \brief The desired user filter field name. */
// Storage for mapping leaf and pointcloud indexes
std::string filter_field_name_;
std::vector<cloud_point_index_idx> index_vector;
index_vector.reserve(indices_->size());


/** \brief The minimum allowed filter value a point will be considered from. */
// No distance filtering, process all data
double filter_limit_min_;
// First pass: go over all points and insert them into the index_vector vector
// with calculated idx. Points with the same idx value will contribute to the
// same point of resulting CloudPoint
for (std::vector<int>::const_iterator it = indices_->begin(); it != indices_->end(); ++it)
{
if (!input_->is_dense)
// Check if the point is invalid
if (!pcl_isfinite(input_->points[*it].x) ||
!pcl_isfinite(input_->points[*it].y) ||
!pcl_isfinite(input_->points[*it].z))
continue;


/** \brief The maximum allowed filter value a point will be considered from. */
int ijk0 = static_cast<int>(
double filter_limit_max_;
std::floor(input_->points[*it].x * inverse_leaf_size_[0]) - static_cast<float>(min_b_[0]));
int ijk1 = static_cast<int>(
std::floor(input_->points[*it].y * inverse_leaf_size_[1]) - static_cast<float>(min_b_[1]));
int ijk2 = static_cast<int>(
std::floor(input_->points[*it].z * inverse_leaf_size_[2]) - static_cast<float>(min_b_[2]));


/** \brief Set to true if we want to return the data outside (\a filter_limit_min_;\a filter_limit_max_). Default: false. */
// Compute the centroid leaf index
bool filter_limit_negative_;
int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
index_vector.push_back(cloud_point_index_idx(static_cast<unsigned int>(idx), *it));
}


/** \brief Minimum number of points per voxel for the centroid to be computed */
// Second pass: sort the index_vector vector using value representing target cell as index
unsigned int min_points_per_voxel_;
// in effect all points belonging to the same output cell will be next to each other
std::sort(index_vector.begin(), index_vector.end(), std::less<cloud_point_index_idx>());


using FieldList = typename pcl::traits::fieldList<PointT>::type;
// Third pass: count output cells
// we need to skip all the same, adjacent idx values
unsigned int total = 0;
unsigned int index = 0;
// first_and_last_indices_vector[i] represents the index in index_vector of the first point in
// index_vector belonging to the voxel which corresponds to the i-th output point,
// and of the first point not belonging to.
std::vector<std::pair<unsigned int, unsigned int>> first_and_last_indices_vector;
// Worst case size
first_and_last_indices_vector.reserve(index_vector.size());
while (index < index_vector.size())
{
unsigned int i = index + 1;
while (i < index_vector.size() && index_vector[i].idx == index_vector[index].idx)
++i;
if (i - index >= min_points_per_voxel_)
{
++total;
first_and_last_indices_vector.push_back(std::pair<unsigned int, unsigned int>(index, i));
}
index = i;
}


/** \brief Downsample a Point Cloud using a voxelized grid approach
// Fourth pass: compute centroids, insert them into their final position
* \param[out] output the resultant point cloud message
output.points.resize(total);
*/
void
applyFilter (PointCloud &output) override;
};


/** \brief VoxelGrid assembles a local 3D grid over a given PointCloud, and downsamples + filters the data.
index = 0;
*
for (unsigned int cp = 0; cp < first_and_last_indices_vector.size(); ++cp)
* The VoxelGrid class creates a *3D voxel grid* (think about a voxel
{
* grid as a set of tiny 3D boxes in space) over the input point cloud data.
// calculate centroid - sum values from all input points, that have the same idx value in index_vector array
* Then, in each *voxel* (i.e., 3D box), all the points present will be
unsigned int first_index = first_and_last_indices_vector[cp].first;
* approximated (i.e., *downsampled*) with their centroid. This approach is
unsigned int last_index = first_and_last_indices_vector[cp].second;
* a bit slower than approximating them with the center of the voxel, but it
* represents the underlying surface more accurately.
*
* \author Radu B. Rusu, Bastian Steder, Radoslaw Cybulski
* \ingroup filters
*/
template <>
class PCL_EXPORTS VoxelGrid<pcl::PCLPointCloud2> : public Filter<pcl::PCLPointCloud2>
{
using Filter<pcl::PCLPointCloud2>::filter_name_;
using Filter<pcl::PCLPointCloud2>::getClassName;


using PCLPointCloud2 = pcl::PCLPointCloud2;
CentroidPoint<PointT> centroid;
using PCLPointCloud2Ptr = PCLPointCloud2::Ptr;
using PCLPointCloud2ConstPtr = PCLPointCloud2::ConstPtr;


public:
// fill in the accumulator with leaf points
/** \brief Empty constructor. */
for (unsigned int li = first_index; li < last_index; ++li)
VoxelGrid () :
centroid.add(input_->points[index_vector[li].cloud_point_index]);
leaf_size_ (Eigen::Vector4f::Zero ()),
inverse_leaf_size_ (Eigen::Array4f::Zero ()),
downsample_all_data_ (true),
save_leaf_layout_ (false),
min_b_ (Eigen::Vector4i::Zero ()),
max_b_ (Eigen::Vector4i::Zero ()),
div_b_ (Eigen::Vector4i::Zero ()),
divb_mul_ (Eigen::Vector4i::Zero ()),
filter_field_name_ (""),
filter_limit_min_ (-FLT_MAX),
filter_limit_max_ (FLT_MAX),
filter_limit_negative_ (false),
min_points_per_voxel_ (0)
{
filter_name_ = "VoxelGrid";
}


/** \brief Destructor. */
centroid.get(output.points[index]);
~VoxelGrid ()
{
}


/** \brief Set the voxel grid leaf size.
++index;
* \param[in] leaf_size the voxel grid leaf size
}
*/
output.width = static_cast<uint32_t>(output.points.size());
inline void
}
setLeafSize (const Eigen::Vector4f &leaf_size)
};
{
} // namespace pcl
leaf_size_ = leaf_size;
// Avoid division errors
if (leaf_size_[3] == 0)
leaf_size_[3] = 1;
// Use multiplications instead of divisions
inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
}


/** \brief Set the voxel grid leaf size.
#endif // BACKPORT_PCL_VOXEL_GRID
* \param[in] lx the leaf size for X
* \param[in] ly the leaf size for Y
* \param[in] lz the leaf size for Z
*/
inline void
setLeafSize (float lx, float ly, float lz)
{
leaf_size_[0] = lx; leaf_size_[1] = ly; leaf_size_[2] = lz;
// Avoid division errors
if (leaf_size_[3] == 0)
leaf_size_[3] = 1;
// Use multiplications instead of divisions
inverse_leaf_size_ = Eigen::Array4f::Ones () / leaf_size_.array ();
}


/** \brief Get the voxel grid leaf size. */
#endif // PCL18_BACKPORTS_VOXEL_GRID_H
inline Eigen::Vector3f
getLeafSize () const { return (leaf_size_.head<3> ()); }


/** \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 (bool downsample) { downsample