diff --git a/filters/include/pcl/filters/impl/voxel_grid.hpp b/filters/include/pcl/filters/impl/voxel_grid.hpp index 5297a49dc2a..4b30282ddd6 100644 --- a/filters/include/pcl/filters/impl/voxel_grid.hpp +++ b/filters/include/pcl/filters/impl/voxel_grid.hpp @@ -46,6 +46,421 @@ #include #include +/////////////////////////////////////////////////////////////////////////////////////////// +template void +pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, Eigen::Matrix &min_pt, Eigen::Matrix &max_pt) +{ + if (pcl::traits::asEnum_v != cloud->fields[x_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[y_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[z_idx].datatype) + { + PCL_ERROR("[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n"); + return; + } + + T min_x = std::numeric_limits::max(); + T min_y = std::numeric_limits::max(); + T min_z = std::numeric_limits::max(); + T max_x = std::numeric_limits::lowest(); + T max_y = std::numeric_limits::lowest(); + T max_z = std::numeric_limits::lowest(); + + const std::uint32_t x_off = cloud->fields[x_idx].offset; + const std::uint32_t y_off = cloud->fields[y_idx].offset; + const std::uint32_t z_off = cloud->fields[z_idx].offset; + const std::uint32_t pt_step = cloud->point_step; + const std::size_t nr_points = cloud->width * cloud->height; + + const std::uint8_t* data_ptr = cloud->data.data(); + + T x, y, z; + + auto update_min_max = [&](const T& x, const T& y, const T& z) { + if (x < min_x) + min_x = x; + if (y < min_y) + min_y = y; + if (z < min_z) + min_z = z; + if (x > max_x) + max_x = x; + if (y > max_y) + max_y = y; + if (z > max_z) + max_z = z; + }; + + // If dense, no need to check for NaNs + if (cloud->is_dense) + { + for (std::size_t i = 0; i < nr_points; ++i) + { + std::memcpy(&x, data_ptr + x_off, sizeof(T)); + std::memcpy(&y, data_ptr + y_off, sizeof(T)); + std::memcpy(&z, data_ptr + z_off, sizeof(T)); + + data_ptr += pt_step; + + update_min_max(x, y, z); + } + } + else + { + for (std::size_t i = 0; i < nr_points; ++i) + { + std::memcpy(&x, data_ptr + x_off, sizeof(T)); + std::memcpy(&y, data_ptr + y_off, sizeof(T)); + std::memcpy(&z, data_ptr + z_off, sizeof(T)); + + data_ptr += pt_step; + + // Check if the point is invalid + if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) + continue; + + update_min_max(x, y, z); + } + } + + min_pt << min_x, min_y, min_z, 0; + max_pt << max_x, max_y, max_z, 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +template void +pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const pcl::Indices &indices, int x_idx, int y_idx, int z_idx, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt) +{ + if (pcl::traits::asEnum_v != cloud->fields[x_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[y_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[z_idx].datatype) + { + PCL_ERROR("[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n"); + return; + } + + T min_x = std::numeric_limits::max(); + T min_y = std::numeric_limits::max(); + T min_z = std::numeric_limits::max(); + T max_x = std::numeric_limits::lowest(); + T max_y = std::numeric_limits::lowest(); + T max_z = std::numeric_limits::lowest(); + + const std::uint32_t x_off = cloud->fields[x_idx].offset; + const std::uint32_t y_off = cloud->fields[y_idx].offset; + const std::uint32_t z_off = cloud->fields[z_idx].offset; + const std::uint32_t pt_step = cloud->point_step; + const std::uint8_t* data_ptr = cloud->data.data(); + + T x, y, z; + + auto update_min_max = [&](const T& x, const T& y, const T& z) { + if (x < min_x) + min_x = x; + if (y < min_y) + min_y = y; + if (z < min_z) + min_z = z; + if (x > max_x) + max_x = x; + if (y > max_y) + max_y = y; + if (z > max_z) + max_z = z; + }; + + // If dense, no need to check for NaNs + if (cloud->is_dense) + { + for (const auto& index : indices) + { + const std::uint8_t* pt_data = data_ptr + (index * pt_step); + + std::memcpy(&x, pt_data + x_off, sizeof(T)); + std::memcpy(&y, pt_data + y_off, sizeof(T)); + std::memcpy(&z, pt_data + z_off, sizeof(T)); + + update_min_max(x, y, z); + } + } + else + { + for (const auto& index : indices) + { + const std::uint8_t* pt_data = data_ptr + (index * pt_step); + + std::memcpy(&x, pt_data + x_off, sizeof(T)); + std::memcpy(&y, pt_data + y_off, sizeof(T)); + std::memcpy(&z, pt_data + z_off, sizeof(T)); + + // Check if the point is invalid + if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) + continue; + + update_min_max(x, y, z); + } + } + + min_pt << min_x, min_y, min_z, 0; + max_pt << max_x, max_y, max_z, 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +template void +pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, + const std::string &distance_field_name, D min_distance, D max_distance, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt, bool limit_negative) +{ + if (pcl::traits::asEnum_v != cloud->fields[x_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[y_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[z_idx].datatype) + { + PCL_ERROR("[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n"); + return; + } + + int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name); + + if (distance_idx < 0) + { + PCL_ERROR("[pcl::getMinMax3D] The specified distance field name is not found in the cloud!\n"); + return; + } + + if (cloud->fields[distance_idx].datatype != pcl::traits::asEnum_v) + { + PCL_ERROR ("[pcl::getMinMax3D] min_distance/max_distance are incorrect type!\n"); + return; + } + + T min_x = std::numeric_limits::max(); + T min_y = std::numeric_limits::max(); + T min_z = std::numeric_limits::max(); + T max_x = std::numeric_limits::lowest(); + T max_y = std::numeric_limits::lowest(); + T max_z = std::numeric_limits::lowest(); + + const std::uint32_t x_off = cloud->fields[x_idx].offset; + const std::uint32_t y_off = cloud->fields[y_idx].offset; + const std::uint32_t z_off = cloud->fields[z_idx].offset; + const std::uint32_t pt_step = cloud->point_step; + const std::uint8_t* data_ptr = cloud->data.data(); + const std::size_t nr_points = cloud->width * cloud->height; + + const std::uint32_t distance_off = cloud->fields[distance_idx].offset; + + T x, y, z; + D distance_value; + + auto update_min_max = [&](const T& x, const T& y, const T& z) { + if (x < min_x) + min_x = x; + if (y < min_y) + min_y = y; + if (z < min_z) + min_z = z; + if (x > max_x) + max_x = x; + if (y > max_y) + max_y = y; + if (z > max_z) + max_z = z; + }; + + // If dense, no need to check for NaNs + if (cloud->is_dense) + { + for (std::size_t cp = 0; cp < nr_points; ++cp) + { + std::memcpy(&distance_value, data_ptr + distance_off, sizeof(D)); + + if (limit_negative) + { + if ((distance_value < max_distance) && (distance_value > min_distance)) + { + data_ptr += pt_step; + continue; + } + } + else + { + if ((distance_value > max_distance) || (distance_value < min_distance)) + { + data_ptr += pt_step; + continue; + } + } + + std::memcpy(&x, data_ptr + x_off, sizeof(T)); + std::memcpy(&y, data_ptr + y_off, sizeof(T)); + std::memcpy(&z, data_ptr + z_off, sizeof(T)); + + data_ptr += pt_step; + + update_min_max(x, y, z); + } + } + else + { + for (std::size_t cp = 0; cp < nr_points; ++cp) + { + std::memcpy(&distance_value, data_ptr + distance_off, sizeof(D)); + + if (limit_negative) + { + if ((distance_value < max_distance) && (distance_value > min_distance)) + { + data_ptr += pt_step; + continue; + } + } + else + { + if ((distance_value > max_distance) || (distance_value < min_distance)) + { + data_ptr += pt_step; + continue; + } + } + + std::memcpy(&x, data_ptr + x_off, sizeof(T)); + std::memcpy(&y, data_ptr + y_off, sizeof(T)); + std::memcpy(&z, data_ptr + z_off, sizeof(T)); + + data_ptr += pt_step; + + // Check if the point is invalid + if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) + continue; + + update_min_max(x, y, z); + } + } + + min_pt << min_x, min_y, min_z, 0; + max_pt << max_x, max_y, max_z, 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +template void +pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const pcl::Indices &indices, int x_idx, int y_idx, int z_idx, const std::string &distance_field_name, D min_distance, D max_distance, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt, bool limit_negative) +{ + if (pcl::traits::asEnum_v != cloud->fields[x_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[y_idx].datatype || + pcl::traits::asEnum_v != cloud->fields[z_idx].datatype) + { + PCL_ERROR("[pcl::getMinMax3D] Type of max_pt/min_pt does not match cloud type!\n"); + return; + } + + int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name); + + if (distance_idx < 0) + { + PCL_ERROR("[pcl::getMinMax3D] The specified distance field name is not found in the cloud!\n"); + return; + } + + if (cloud->fields[distance_idx].datatype != pcl::traits::asEnum_v) + { + PCL_ERROR ("[pcl::getMinMax3D] min_distance/max_distance are incorrect type!\n"); + return; + } + + T min_x = std::numeric_limits::max(); + T min_y = std::numeric_limits::max(); + T min_z = std::numeric_limits::max(); + T max_x = std::numeric_limits::lowest(); + T max_y = std::numeric_limits::lowest(); + T max_z = std::numeric_limits::lowest(); + + const std::uint32_t x_off = cloud->fields[x_idx].offset; + const std::uint32_t y_off = cloud->fields[y_idx].offset; + const std::uint32_t z_off = cloud->fields[z_idx].offset; + const std::uint32_t pt_step = cloud->point_step; + const std::uint8_t* data_ptr = cloud->data.data(); + + const std::uint32_t distance_off = cloud->fields[distance_idx].offset; + + T x, y, z; + D distance_value; + + auto update_min_max = [&](const T& x, const T& y, const T& z) { + if (x < min_x) + min_x = x; + if (y < min_y) + min_y = y; + if (z < min_z) + min_z = z; + if (x > max_x) + max_x = x; + if (y > max_y) + max_y = y; + if (z > max_z) + max_z = z; + }; + + // If dense, no need to check for NaNs + if(cloud->is_dense) + { + for (const auto& index : indices) + { + const std::uint8_t* pt_data = data_ptr + (index * pt_step); + + std::memcpy(&distance_value, pt_data + distance_off, sizeof(D)); + + if (limit_negative) + { + if ((distance_value < max_distance) && (distance_value > min_distance)) + continue; + } + else + { + if ((distance_value > max_distance) || (distance_value < min_distance)) + continue; + } + + std::memcpy(&x, pt_data + x_off, sizeof(T)); + std::memcpy(&y, pt_data + y_off, sizeof(T)); + std::memcpy(&z, pt_data + z_off, sizeof(T)); + + update_min_max(x, y, z); + } + } + else + { + for (const auto& index : indices) + { + const std::uint8_t* pt_data = data_ptr + (index * pt_step); + + std::memcpy(&distance_value, pt_data + distance_off, sizeof(D)); + + if (limit_negative) + { + if ((distance_value < max_distance) && (distance_value > min_distance)) + continue; + } + else + { + if ((distance_value > max_distance) || (distance_value < min_distance)) + continue; + } + + std::memcpy(&x, pt_data + x_off, sizeof(T)); + std::memcpy(&y, pt_data + y_off, sizeof(T)); + std::memcpy(&z, pt_data + z_off, sizeof(T)); + + if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) + continue; + + update_min_max(x, y, z); + } + } + min_pt << min_x, min_y, min_z, 0; + max_pt << max_x, max_y, max_z, 0; +} + /////////////////////////////////////////////////////////////////////////////////////////// template void pcl::getMinMax3D (const typename pcl::PointCloud::ConstPtr &cloud, @@ -197,8 +612,8 @@ pcl::getMinMax3D (const typename pcl::PointCloud::ConstPtr &cloud, } // Check if the point is invalid - if (!std::isfinite ((*cloud)[index].x) || - !std::isfinite ((*cloud)[index].y) || + if (!std::isfinite ((*cloud)[index].x) || + !std::isfinite ((*cloud)[index].y) || !std::isfinite ((*cloud)[index].z)) continue; // Create the point structure and get the min/max @@ -305,7 +720,7 @@ pcl::VoxelGrid::applyFilter (PointCloud &output) if ((distance_value > filter_limit_max_) || (distance_value < filter_limit_min_)) continue; } - + int ijk0 = static_cast (std::floor ((*input_)[index].x * inverse_leaf_size_[0]) - static_cast (min_b_[0])); int ijk1 = static_cast (std::floor ((*input_)[index].y * inverse_leaf_size_[1]) - static_cast (min_b_[1])); int ijk2 = static_cast (std::floor ((*input_)[index].z * inverse_leaf_size_[2]) - static_cast (min_b_[2])); @@ -342,7 +757,7 @@ pcl::VoxelGrid::applyFilter (PointCloud &output) // in effect all points belonging to the same output cell will be next to each other auto rightshift_func = [](const internal::cloud_point_index_idx &x, const unsigned offset) { return x.idx >> offset; }; boost::sort::spreadsort::integer_sort(index_vector.begin(), index_vector.end(), rightshift_func); - + // Third pass: count output cells // we need to skip all the same, adjacent idx values unsigned int total = 0; @@ -353,10 +768,10 @@ pcl::VoxelGrid::applyFilter (PointCloud &output) std::vector > first_and_last_indices_vector; // Worst case size first_and_last_indices_vector.reserve (index_vector.size ()); - while (index < 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) + while (i < index_vector.size () && index_vector[i].idx == index_vector[index].idx) ++i; if (i - index >= min_points_per_voxel_) { @@ -371,7 +786,7 @@ pcl::VoxelGrid::applyFilter (PointCloud &output) if (save_leaf_layout_) { try - { + { // Resizing won't reset old elements to -1. If leaf_layout_ has been used previously, it needs to be re-initialized to -1 std::uint32_t new_layout_size = div_b_[0]*div_b_[1]*div_b_[2]; //This is the number of elements that need to be re-initialized to -1 @@ -379,21 +794,21 @@ pcl::VoxelGrid::applyFilter (PointCloud &output) for (std::uint32_t i = 0; i < reinit_size; i++) { leaf_layout_[i] = -1; - } - leaf_layout_.resize (new_layout_size, -1); + } + leaf_layout_.resize (new_layout_size, -1); } catch (std::bad_alloc&) { - throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout", - "voxel_grid.hpp", "applyFilter"); + throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout", + "voxel_grid.hpp", "applyFilter"); } catch (std::length_error&) { - throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout", - "voxel_grid.hpp", "applyFilter"); + throw PCLException("VoxelGrid bin size is too low; impossible to allocate memory for layout", + "voxel_grid.hpp", "applyFilter"); } } - + index = 0; for (const auto &cp : first_and_last_indices_vector) { @@ -422,11 +837,11 @@ pcl::VoxelGrid::applyFilter (PointCloud &output) // fill in the accumulator with leaf points for (unsigned int li = first_index; li < last_index; ++li) - centroid.add ((*input_)[index_vector[li].cloud_point_index]); + centroid.add ((*input_)[index_vector[li].cloud_point_index]); centroid.get (output[index]); } - + ++index; } output.width = output.size (); diff --git a/filters/include/pcl/filters/voxel_grid.h b/filters/include/pcl/filters/voxel_grid.h index 00bdcf50c42..94b1512fae3 100644 --- a/filters/include/pcl/filters/voxel_grid.h +++ b/filters/include/pcl/filters/voxel_grid.h @@ -44,70 +44,6 @@ namespace pcl { - /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. - * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset - * \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[out] min_pt the minimum data point - * \param[out] max_pt the maximum data point - */ - PCL_EXPORTS void - getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, - Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt); - - /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. - * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset - * \param[in] indices the point cloud indices that need to be considered - * \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[out] min_pt the minimum data point - * \param[out] max_pt the maximum data point - */ - PCL_EXPORTS void - getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const Indices &indices, int x_idx, int y_idx, int z_idx, - Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt); - - /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. - * \note Performs internal data filtering as well. - * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset - * \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 Obtain the maximum and minimum points in 3D from a given point cloud. - * \note Performs internal data filtering as well. - * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset - * \param[in] indices the point cloud indices that need to be considered - * \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, const Indices &indices, 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. * \note Useful in combination with getNeighborCentroidIndices() from \ref VoxelGrid * \ingroup filters @@ -159,6 +95,82 @@ namespace pcl return (relative_coordinates_all); } + /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. + * \tparam T the coordinate type + * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset + * \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[out] min_pt the minimum data point + * \param[out] max_pt the maximum data point + * \ingroup filters + */ + template void + getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt); + + /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. + * \tparam T the coordinate type + * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset + * \param[in] indices the point cloud indices that need to be considered + * \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[out] min_pt the minimum data point + * \param[out] max_pt the maximum data point + * \ingroup filters + */ + template void + getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const pcl::Indices &indices, int x_idx, int y_idx, int z_idx, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt); + + + /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. + * \note Performs internal data filtering as well. + * \tparam T the coordinate type + * \tparam D the distance type + * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset + * \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. + * \ingroup filters + */ + template void + getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, + const std::string &distance_field_name, D min_distance, D max_distance, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt, bool limit_negative = false); + + + /** \brief Obtain the maximum and minimum points in 3D from a given point cloud. + * \note Performs internal data filtering as well. + * \tparam T the coordinate type + * \tparam D the distance type + * \param[in] cloud the pointer to a pcl::PCLPointCloud2 dataset + * \param[in] indices the point cloud indices that need to be considered + * \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. + * \ingroup filters + */ + template void + getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const pcl::Indices &indices, int x_idx, int y_idx, int z_idx, const std::string &distance_field_name, D min_distance, D max_distance, + Eigen::Matrix &min_pt, Eigen::Matrix &max_pt, bool limit_negative = false); + + /** \brief Get the minimum and maximum values on each of the 3 (x-y-z) dimensions * in a given pointcloud, without considering points outside of a distance threshold from the laser origin * \param[in] cloud the point cloud data message diff --git a/filters/src/voxel_grid.cpp b/filters/src/voxel_grid.cpp index 7c83f277807..ac87c97df56 100644 --- a/filters/src/voxel_grid.cpp +++ b/filters/src/voxel_grid.cpp @@ -46,307 +46,6 @@ using Array4size_t = Eigen::Array; // NOLINTBEGIN(readability-container-data-pointer) -/////////////////////////////////////////////////////////////////////////////////////////// -void -pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, int x_idx, int y_idx, int z_idx, - Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt) -{ - // @todo fix this - if (cloud->fields[x_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[y_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[z_idx].datatype != pcl::PCLPointField::FLOAT32) - { - PCL_ERROR ("[pcl::getMinMax3D] XYZ dimensions are not float type!\n"); - return; - } - - Eigen::Array4f min_p, max_p; - min_p.setConstant (std::numeric_limits::max()); - max_p.setConstant (std::numeric_limits::lowest()); - - std::size_t nr_points = cloud->width * cloud->height; - - Eigen::Array4f pt = Eigen::Array4f::Zero (); - Array4size_t xyz_offset (cloud->fields[x_idx].offset, cloud->fields[y_idx].offset, cloud->fields[z_idx].offset, 0); - - for (std::size_t cp = 0; cp < nr_points; ++cp) - { - // Unoptimized memcpys: assume fields x, y, z are in random order - memcpy (&pt[0], &cloud->data[xyz_offset[0]], sizeof (float)); - memcpy (&pt[1], &cloud->data[xyz_offset[1]], sizeof (float)); - memcpy (&pt[2], &cloud->data[xyz_offset[2]], sizeof (float)); - // Check if the point is invalid - if (!std::isfinite (pt[0]) || - !std::isfinite (pt[1]) || - !std::isfinite (pt[2])) - { - xyz_offset += cloud->point_step; - continue; - } - xyz_offset += cloud->point_step; - min_p = (min_p.min) (pt); - max_p = (max_p.max) (pt); - } - min_pt = min_p; - max_pt = max_p; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -void -pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const pcl::Indices &indices, int x_idx, int y_idx, int z_idx, - Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt) -{ - if (cloud->fields[x_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[y_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[z_idx].datatype != pcl::PCLPointField::FLOAT32) - { - PCL_ERROR ("[pcl::getMinMax3D] XYZ dimensions are not float type!\n"); - return; - } - - Eigen::Array4f min_p, max_p; - min_p.setConstant (std::numeric_limits::max()); - max_p.setConstant (std::numeric_limits::lowest()); - - Eigen::Array4f pt = Eigen::Array4f::Zero (); - Array4size_t xyz_offset (cloud->fields[x_idx].offset, cloud->fields[y_idx].offset, cloud->fields[z_idx].offset, 0); - - if(cloud->is_dense) // no need to check validity of points - { - for (const auto& index : indices) - { - // Unoptimized memcpys: assume fields x, y, z are in random order - memcpy(&pt[0],&cloud->data[xyz_offset[0] + cloud->point_step * index],sizeof(float)); - memcpy(&pt[1],&cloud->data[xyz_offset[1] + cloud->point_step * index],sizeof(float)); - memcpy(&pt[2],&cloud->data[xyz_offset[2] + cloud->point_step * index],sizeof(float)); - min_p = (min_p.min)(pt); - max_p = (max_p.max)(pt); - } - } - else - { - for (const auto& index : indices) - { - // Unoptimized memcpys: assume fields x, y, z are in random order - memcpy(&pt[0],&cloud->data[xyz_offset[0] + cloud->point_step * index],sizeof(float)); - memcpy(&pt[1],&cloud->data[xyz_offset[1] + cloud->point_step * index],sizeof(float)); - memcpy(&pt[2],&cloud->data[xyz_offset[2] + cloud->point_step * index],sizeof(float)); - // Check if the point is invalid - if (!std::isfinite(pt[0]) || - !std::isfinite(pt[1]) || - !std::isfinite(pt[2])) - { - continue; - } - min_p = (min_p.min)(pt); - max_p = (max_p.max)(pt); - } - } - min_pt = min_p; - max_pt = max_p; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -void -pcl::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) -{ - // @todo fix this - if (cloud->fields[x_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[y_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[z_idx].datatype != pcl::PCLPointField::FLOAT32) - { - PCL_ERROR ("[pcl::getMinMax3D] XYZ dimensions are not float type!\n"); - return; - } - - Eigen::Array4f min_p, max_p; - min_p.setConstant (std::numeric_limits::max()); - max_p.setConstant (std::numeric_limits::lowest()); - - // Get the distance field index - int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name); - - // @todo fix this - if (cloud->fields[distance_idx].datatype != pcl::PCLPointField::FLOAT32) - { - PCL_ERROR ("[pcl::getMinMax3D] Filtering dimensions is not float type!\n"); - return; - } - - std::size_t nr_points = cloud->width * cloud->height; - - Eigen::Array4f pt = Eigen::Array4f::Zero (); - Array4size_t xyz_offset (cloud->fields[x_idx].offset, - cloud->fields[y_idx].offset, - cloud->fields[z_idx].offset, - 0); - float distance_value = 0; - for (std::size_t cp = 0; cp < nr_points; ++cp) - { - std::size_t point_offset = cp * cloud->point_step; - - // Get the distance value - memcpy (&distance_value, &cloud->data[point_offset + cloud->fields[distance_idx].offset], sizeof (float)); - - if (limit_negative) - { - // Use a threshold for cutting out points which inside the interval - if ((distance_value < max_distance) && (distance_value > min_distance)) - { - xyz_offset += cloud->point_step; - continue; - } - } - else - { - // Use a threshold for cutting out points which are too close/far away - if ((distance_value > max_distance) || (distance_value < min_distance)) - { - xyz_offset += cloud->point_step; - continue; - } - } - - // Unoptimized memcpys: assume fields x, y, z are in random order - memcpy (&pt[0], &cloud->data[xyz_offset[0]], sizeof (float)); - memcpy (&pt[1], &cloud->data[xyz_offset[1]], sizeof (float)); - memcpy (&pt[2], &cloud->data[xyz_offset[2]], sizeof (float)); - // Check if the point is invalid - if (!std::isfinite (pt[0]) || - !std::isfinite (pt[1]) || - !std::isfinite (pt[2])) - { - xyz_offset += cloud->point_step; - continue; - } - xyz_offset += cloud->point_step; - min_p = (min_p.min) (pt); - max_p = (max_p.max) (pt); - } - min_pt = min_p; - max_pt = max_p; -} - -/////////////////////////////////////////////////////////////////////////////////////////// -void -pcl::getMinMax3D (const pcl::PCLPointCloud2ConstPtr &cloud, const pcl::Indices &indices, 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) -{ - // @todo fix this - if (cloud->fields[x_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[y_idx].datatype != pcl::PCLPointField::FLOAT32 || - cloud->fields[z_idx].datatype != pcl::PCLPointField::FLOAT32) - { - PCL_ERROR ("[pcl::getMinMax3D] XYZ dimensions are not float type!\n"); - return; - } - - Eigen::Array4f min_p, max_p; - min_p.setConstant (std::numeric_limits::max()); - max_p.setConstant (std::numeric_limits::lowest()); - - // Get the distance field index - int distance_idx = pcl::getFieldIndex (*cloud, distance_field_name); - - // @todo fix this - if (cloud->fields[distance_idx].datatype != pcl::PCLPointField::FLOAT32) - { - PCL_ERROR ("[pcl::getMinMax3D] Filtering dimensions is not float type!\n"); - return; - } - - Eigen::Array4f pt = Eigen::Array4f::Zero (); - Array4size_t xyz_offset (cloud->fields[x_idx].offset, - cloud->fields[y_idx].offset, - cloud->fields[z_idx].offset, - 0); - float distance_value = 0; - if(cloud->is_dense) - { - for (const auto& index : indices) { - std::size_t point_offset = index * cloud->point_step; - - // Get the distance value - memcpy(&distance_value, - &cloud->data[point_offset + cloud->fields[distance_idx].offset], - sizeof(float)); - - if (limit_negative) { - // Use a threshold for cutting out points which inside the interval - if ((distance_value < max_distance) && (distance_value > min_distance)) { - continue; - } - } - else { - // Use a threshold for cutting out points which are too close/far away - if ((distance_value > max_distance) || (distance_value < min_distance)) { - continue; - } - } - - // Unoptimized memcpys: assume fields x, y, z are in random order - memcpy(&pt[0], - &cloud->data[xyz_offset[0] + index * cloud->point_step], - sizeof(float)); - memcpy(&pt[1], - &cloud->data[xyz_offset[1] + index * cloud->point_step], - sizeof(float)); - memcpy(&pt[2], - &cloud->data[xyz_offset[2] + index * cloud->point_step], - sizeof(float)); - min_p = (min_p.min)(pt); - max_p = (max_p.max)(pt); - } - } - else - { - for (const auto& index : indices) - { - std::size_t point_offset = index * cloud->point_step; - - // Get the distance value - memcpy(&distance_value,&cloud->data[point_offset + cloud->fields[distance_idx].offset],sizeof(float)); - - if (limit_negative) - { - // Use a threshold for cutting out points which inside the interval - if ((distance_value < max_distance) && (distance_value > min_distance)) - { - continue; - } - } - else - { - // Use a threshold for cutting out points which are too close/far away - if ((distance_value > max_distance) || (distance_value < min_distance)) - { - continue; - } - } - - // Unoptimized memcpys: assume fields x, y, z are in random order - memcpy(&pt[0],&cloud->data[xyz_offset[0] + index * cloud->point_step],sizeof(float)); - memcpy(&pt[1],&cloud->data[xyz_offset[1] + index * cloud->point_step],sizeof(float)); - memcpy(&pt[2],&cloud->data[xyz_offset[2] + index * cloud->point_step],sizeof(float)); - // Check if the point is invalid - if (!std::isfinite(pt[0]) - || !std::isfinite(pt[1]) - || !std::isfinite(pt[2])) - { - continue; - } - min_p = (min_p.min)(pt); - max_p = (max_p.max)(pt); - } - } - min_pt = min_p; - max_pt = max_p; -} - - /////////////////////////////////////////////////////////////////////////////////////////// void pcl::VoxelGrid::applyFilter (PCLPointCloud2 &output) @@ -700,4 +399,17 @@ pcl::VoxelGrid::applyFilter (PCLPointCloud2 &output) PCL_INSTANTIATE(getMinMax3D, PCL_XYZ_POINT_TYPES) PCL_INSTANTIATE(VoxelGrid, PCL_XYZ_POINT_TYPES) +// Explicit instantiations for float (to maintain ABI compatibility) +template PCL_EXPORTS void +pcl::getMinMax3D(const pcl::PCLPointCloud2ConstPtr&, int, int, int, Eigen::Matrix&, Eigen::Matrix&); + +template PCL_EXPORTS void +pcl::getMinMax3D(const pcl::PCLPointCloud2ConstPtr&, const pcl::Indices&, int, int, int, Eigen::Matrix&, Eigen::Matrix&); + +template PCL_EXPORTS void +pcl::getMinMax3D(const pcl::PCLPointCloud2ConstPtr&, int, int, int, const std::string&, float, float, Eigen::Matrix&, Eigen::Matrix&, bool); + +template PCL_EXPORTS void +pcl::getMinMax3D(const pcl::PCLPointCloud2ConstPtr&, const pcl::Indices&, int, int, int, const std::string&, float, float, Eigen::Matrix&, Eigen::Matrix&, bool); + #endif // PCL_NO_PRECOMPILE