39#ifndef PCL_OCTREE_SEARCH_IMPL_H_
40#define PCL_OCTREE_SEARCH_IMPL_H_
51template <
class T,
class =
void>
57 std::
void_t<decltype(std::declval<const T&>().getPointIndicesVector())>>
63template <class T, std::enable_if_t<has_getPointIndicesVector<T>::value,
int> = 0>
67 return leaf.getPointIndicesVector();
73template <class T, std::enable_if_t<!has_getPointIndicesVector<T>::value,
int> = 0>
78 leaf.getPointIndices(decoded_point_vector);
79 return decoded_point_vector;
83template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
89 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
91 bool b_success =
false;
94 this->genOctreeKeyforPoint(point, key);
96 LeafContainerT* leaf = this->findLeaf(key);
99 (*leaf).getPointIndices(point_idx_data);
106template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
111 const PointT search_point = this->getPointByIndex(index);
112 return (this->voxelSearch(search_point, point_idx_data));
115template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
121 std::vector<float>& k_sqr_distances)
123 assert(this->leaf_count_ > 0);
125 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
128 k_sqr_distances.clear();
134 std::vector<prioPointQueueEntry> point_candidates;
135 point_candidates.reserve(k);
138 key.
x = key.
y = key.
z = 0;
141 double smallest_dist = std::numeric_limits<double>::max();
143 getKNearestNeighborRecursive(
144 p_q, k, this->root_node_, key, 1, smallest_dist, point_candidates);
146 const auto result_count =
static_cast<uindex_t>(point_candidates.size());
148 k_indices.resize(result_count);
149 k_sqr_distances.resize(result_count);
151 for (
uindex_t i = 0; i < result_count; ++i) {
152 k_indices[i] = point_candidates[i].point_idx_;
153 k_sqr_distances[i] = point_candidates[i].point_distance_;
156 return k_indices.size();
159template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
164 const PointT search_point = this->getPointByIndex(index);
165 return (nearestKSearch(search_point, k, k_indices, k_sqr_distances));
168template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
171 const PointT& p_q,
index_t& result_index,
float& sqr_distance)
173 assert(this->leaf_count_ > 0);
175 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
178 key.
x = key.
y = key.
z = 0;
180 approxNearestSearchRecursive(
181 p_q, this->root_node_, key, 1, result_index, sqr_distance);
186template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
191 const PointT search_point = this->getPointByIndex(query_index);
193 return (approxNearestSearch(search_point, result_index, sqr_distance));
196template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
202 std::vector<float>& k_sqr_distances,
206 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
208 key.
x = key.
y = key.
z = 0;
211 k_sqr_distances.clear();
213 getNeighborsWithinRadiusRecursive(p_q,
222 return k_indices.size();
225template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
231 std::vector<float>& k_sqr_distances,
234 const PointT search_point = this->getPointByIndex(index);
236 return (radiusSearch(search_point, radius, k_indices, k_sqr_distances, max_nn));
239template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
242 const Eigen::Vector3f& min_pt,
243 const Eigen::Vector3f& max_pt,
248 key.
x = key.
y = key.
z = 0;
252 boxSearchRecursive(min_pt, max_pt, this->root_node_, key, 1, k_indices);
254 return k_indices.size();
257template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
266 const double squared_search_radius,
267 std::vector<prioPointQueueEntry>& point_candidates)
const
269 std::vector<prioBranchQueueEntry> search_heap;
270 search_heap.resize(8);
274 double smallest_squared_dist = squared_search_radius;
277 double voxelSquaredDiameter = this->getVoxelSquaredDiameter(tree_depth);
280 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
281 if (this->branchHasChild(*node, child_idx)) {
284 search_heap[child_idx].key.x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
285 search_heap[child_idx].key.y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
286 search_heap[child_idx].key.z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
289 this->genVoxelCenterFromOctreeKey(
290 search_heap[child_idx].key, tree_depth, voxel_center);
293 search_heap[child_idx].node = this->getBranchChildPtr(*node, child_idx);
294 search_heap[child_idx].point_distance = pointSquaredDist(voxel_center, point);
297 search_heap[child_idx].point_distance = std::numeric_limits<float>::infinity();
301 std::sort(search_heap.begin(), search_heap.end());
306 while ((!search_heap.empty()) &&
307 (search_heap.back().point_distance <
308 smallest_squared_dist + voxelSquaredDiameter / 4.0 +
309 sqrt(smallest_squared_dist * voxelSquaredDiameter) - this->epsilon_)) {
310 const OctreeNode* child_node;
313 child_node = search_heap.back().node;
314 new_key = search_heap.back().key;
318 smallest_squared_dist =
319 getKNearestNeighborRecursive(point,
321 static_cast<const BranchNode*
>(child_node),
324 smallest_squared_dist,
331 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
334 (*child_leaf)->getPointIndices(decoded_point_vector);
337 for (
const auto& point_index : decoded_point_vector) {
339 const PointT& candidate_point = this->getPointByIndex(point_index);
342 float squared_dist = pointSquaredDist(candidate_point, point);
344 const auto insert_into_queue = [&] {
345 point_candidates.emplace(
346 std::upper_bound(point_candidates.begin(),
347 point_candidates.end(),
349 [](
float dist,
const prioPointQueueEntry& ent) {
350 return dist < ent.point_distance_;
355 if (point_candidates.size() <
K) {
358 else if (point_candidates.back().point_distance_ > squared_dist) {
359 point_candidates.pop_back();
364 if (point_candidates.size() ==
K)
365 smallest_squared_dist = point_candidates.back().point_distance_;
368 search_heap.pop_back();
371 return (smallest_squared_dist);
374template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
378 const double radiusSquared,
383 std::vector<float>& k_sqr_distances,
387 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
388 if (!this->branchHasChild(*node, child_idx))
392 child_node = this->getBranchChildPtr(*node, child_idx);
398 new_key.
x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
399 new_key.
y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
400 new_key.
z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
404 Eigen::Vector3f min_pt, max_pt;
405 this->genVoxelBoundsFromOctreeKey(new_key, tree_depth, min_pt, max_pt);
407 if (point.x < min_pt.x())
408 squared_dist += std::pow(point.x - min_pt.x(), 2);
409 else if (point.x > max_pt.x())
410 squared_dist += std::pow(point.x - max_pt.x(), 2);
411 if (point.y < min_pt.y())
412 squared_dist += std::pow(point.y - min_pt.y(), 2);
413 else if (point.y > max_pt.y())
414 squared_dist += std::pow(point.y - max_pt.y(), 2);
415 if (point.z < min_pt.z())
416 squared_dist += std::pow(point.z - min_pt.z(), 2);
417 else if (point.z > max_pt.z())
418 squared_dist += std::pow(point.z - max_pt.z(), 2);
419 if (squared_dist < (radiusSquared + this->epsilon_)) {
422 getNeighborsWithinRadiusRecursive(point,
430 if (max_nn != 0 && k_indices.size() == max_nn)
435 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
438 for (
const auto& index : detail::getPointIndices(*(*child_leaf))) {
439 const PointT& candidate_point = this->getPointByIndex(index);
442 squared_dist = pointSquaredDist(candidate_point, point);
445 if (squared_dist > radiusSquared)
449 k_indices.push_back(index);
450 k_sqr_distances.push_back(squared_dist);
452 if (max_nn != 0 && k_indices.size() == max_nn)
460template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
476 double min_voxel_center_distance = std::numeric_limits<double>::max();
478 unsigned char min_child_idx = 0xFF;
481 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
482 if (!this->branchHasChild(*node, child_idx))
486 double voxelPointDist;
488 new_key.
x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
489 new_key.
y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
490 new_key.
z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
493 this->genVoxelCenterFromOctreeKey(new_key, tree_depth, voxel_center);
495 voxelPointDist = pointSquaredDist(voxel_center, point);
498 if (voxelPointDist >= min_voxel_center_distance)
501 min_voxel_center_distance = voxelPointDist;
502 min_child_idx = child_idx;
503 minChildKey = new_key;
507 assert(min_child_idx < 8);
509 child_node = this->getBranchChildPtr(*node, min_child_idx);
513 approxNearestSearchRecursive(point,
514 static_cast<const BranchNode*
>(child_node),
524 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
526 float smallest_squared_dist = std::numeric_limits<float>::max();
529 (**child_leaf).getPointIndices(decoded_point_vector);
532 for (
const auto& index : decoded_point_vector) {
533 const PointT& candidate_point = this->getPointByIndex(index);
536 float squared_dist = pointSquaredDist(candidate_point, point);
539 if (squared_dist >= smallest_squared_dist)
542 result_index = index;
543 smallest_squared_dist = squared_dist;
544 sqr_distance = squared_dist;
549template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
554 return (point_a.getVector3fMap() - point_b.getVector3fMap()).squaredNorm();
557template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
560 const Eigen::Vector3f& min_pt,
561 const Eigen::Vector3f& max_pt,
568 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
571 child_node = this->getBranchChildPtr(*node, child_idx);
578 new_key.
x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
579 new_key.
y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
580 new_key.
z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
583 Eigen::Vector3f lower_voxel_corner;
584 Eigen::Vector3f upper_voxel_corner;
586 this->genVoxelBoundsFromOctreeKey(
587 new_key, tree_depth, lower_voxel_corner, upper_voxel_corner);
591 if ((lower_voxel_corner(0) <= max_pt(0)) && (min_pt(0) <= upper_voxel_corner(0)) &&
592 (lower_voxel_corner(1) <= max_pt(1)) && (min_pt(1) <= upper_voxel_corner(1)) &&
593 (lower_voxel_corner(2) <= max_pt(2)) && (min_pt(2) <= upper_voxel_corner(2))) {
597 boxSearchRecursive(min_pt,
608 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
611 (**child_leaf).getPointIndices(decoded_point_vector);
614 for (
const auto& index : decoded_point_vector) {
615 const PointT& candidate_point = this->getPointByIndex(index);
619 ((candidate_point.x >= min_pt(0)) && (candidate_point.x <= max_pt(0)) &&
620 (candidate_point.y >= min_pt(1)) && (candidate_point.y <= max_pt(1)) &&
621 (candidate_point.z >= min_pt(2)) && (candidate_point.z <= max_pt(2)));
625 k_indices.push_back(index);
632template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
636 Eigen::Vector3f direction,
641 key.
x = key.
y = key.
z = 0;
643 voxel_center_list.clear();
648 double min_x, min_y, min_z, max_x, max_y, max_z;
650 initIntersectedVoxel(origin, direction, min_x, min_y, min_z, max_x, max_y, max_z, a);
652 if (std::max(std::max(min_x, min_y), min_z) < std::min(std::min(max_x, max_y), max_z))
653 return getIntersectedVoxelCentersRecursive(min_x,
668template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
672 Eigen::Vector3f direction,
677 key.
x = key.
y = key.
z = 0;
683 double min_x, min_y, min_z, max_x, max_y, max_z;
685 initIntersectedVoxel(origin, direction, min_x, min_y, min_z, max_x, max_y, max_z, a);
687 if (std::max(std::max(min_x, min_y), min_z) < std::min(std::min(max_x, max_y), max_z))
688 return getIntersectedVoxelIndicesRecursive(min_x,
702template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
717 if (max_x < 0.0 || max_y < 0.0 || max_z < 0.0)
724 this->genLeafNodeCenterFromOctreeKey(key, newPoint);
726 voxel_center_list.push_back(newPoint);
735 double mid_x = 0.5 * (min_x + max_x);
736 double mid_y = 0.5 * (min_y + max_y);
737 double mid_z = 0.5 * (min_z + max_z);
740 auto curr_node = getFirstIntersectedNode(min_x, min_y, min_z, mid_x, mid_y, mid_z);
743 unsigned char child_idx;
748 child_idx =
static_cast<unsigned char>(curr_node ^ a);
754 this->getBranchChildPtr(
static_cast<const BranchNode&
>(*node), child_idx);
757 child_key.
x = (key.
x << 1) | (!!(child_idx & (1 << 2)));
758 child_key.
y = (key.
y << 1) | (!!(child_idx & (1 << 1)));
759 child_key.
z = (key.
z << 1) | (!!(child_idx & (1 << 0)));
768 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
779 curr_node = getNextIntersectedNode(mid_x, mid_y, mid_z, 4, 2, 1);
784 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
795 curr_node = getNextIntersectedNode(mid_x, mid_y, max_z, 5, 3, 8);
800 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
811 curr_node = getNextIntersectedNode(mid_x, max_y, mid_z, 6, 8, 3);
816 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
827 curr_node = getNextIntersectedNode(mid_x, max_y, max_z, 7, 8, 8);
832 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
843 curr_node = getNextIntersectedNode(max_x, mid_y, mid_z, 8, 6, 5);
848 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
859 curr_node = getNextIntersectedNode(max_x, mid_y, max_z, 8, 7, 8);
864 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
875 curr_node = getNextIntersectedNode(max_x, max_y, mid_z, 8, 8, 7);
880 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
894 }
while ((curr_node < 8) && (max_voxel_count <= 0 || voxel_count < max_voxel_count));
895 return (voxel_count);
898template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
913 if (max_x < 0.0 || max_y < 0.0 || max_z < 0.0)
918 const auto* leaf =
static_cast<const LeafNode*
>(node);
921 (*leaf)->getPointIndices(k_indices);
930 double mid_x = 0.5 * (min_x + max_x);
931 double mid_y = 0.5 * (min_y + max_y);
932 double mid_z = 0.5 * (min_z + max_z);
935 auto curr_node = getFirstIntersectedNode(min_x, min_y, min_z, mid_x, mid_y, mid_z);
938 unsigned char child_idx;
942 child_idx =
static_cast<unsigned char>(curr_node ^ a);
948 this->getBranchChildPtr(
static_cast<const BranchNode&
>(*node), child_idx);
950 child_key.
x = (key.
x << 1) | (!!(child_idx & (1 << 2)));
951 child_key.
y = (key.
y << 1) | (!!(child_idx & (1 << 1)));
952 child_key.
z = (key.
z << 1) | (!!(child_idx & (1 << 0)));
960 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
971 curr_node = getNextIntersectedNode(mid_x, mid_y, mid_z, 4, 2, 1);
976 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
987 curr_node = getNextIntersectedNode(mid_x, mid_y, max_z, 5, 3, 8);
992 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
1003 curr_node = getNextIntersectedNode(mid_x, max_y, mid_z, 6, 8, 3);
1008 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
1019 curr_node = getNextIntersectedNode(mid_x, max_y, max_z, 7, 8, 8);
1024 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1035 curr_node = getNextIntersectedNode(max_x, mid_y, mid_z, 8, 6, 5);
1040 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1051 curr_node = getNextIntersectedNode(max_x, mid_y, max_z, 8, 7, 8);
1056 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1067 curr_node = getNextIntersectedNode(max_x, max_y, mid_z, 8, 8, 7);
1072 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1086 }
while ((curr_node < 8) && (max_voxel_count <= 0 || voxel_count < max_voxel_count));
1088 return (voxel_count);
1094#define PCL_INSTANTIATE_OctreePointCloudSearch(T) \
1095 template class PCL_EXPORTS pcl::octree::OctreePointCloudSearch<T>;
Abstract octree node class
virtual node_type_t getNodeType() const =0
Pure virtual method for retrieving the type of octree node (branch or leaf)
Priority queue entry for point candidates
typename OctreeT::LeafNode LeafNode
double getKNearestNeighborRecursive(const PointT &point, uindex_t K, const BranchNode *node, const OctreeKey &key, uindex_t tree_depth, const double squared_search_radius, std::vector< prioPointQueueEntry > &point_candidates) const
Recursive search method that explores the octree and finds the K nearest neighbors.
uindex_t getIntersectedVoxelIndices(Eigen::Vector3f origin, Eigen::Vector3f direction, Indices &k_indices, uindex_t max_voxel_count=0) const
Get indices of all voxels that are intersected by a ray (origin, direction).
uindex_t getIntersectedVoxelIndicesRecursive(double min_x, double min_y, double min_z, double max_x, double max_y, double max_z, unsigned char a, const OctreeNode *node, const OctreeKey &key, Indices &k_indices, uindex_t max_voxel_count) const
Recursively search the tree for all intersected leaf nodes and return a vector of indices.
uindex_t getIntersectedVoxelCenters(Eigen::Vector3f origin, Eigen::Vector3f direction, AlignedPointTVector &voxel_center_list, uindex_t max_voxel_count=0) const
Get a PointT vector of centers of all voxels that intersected by a ray (origin, direction).
bool voxelSearch(const PointT &point, Indices &point_idx_data)
Search for neighbors within a voxel at given point.
uindex_t boxSearch(const Eigen::Vector3f &min_pt, const Eigen::Vector3f &max_pt, Indices &k_indices) const
Search for points within rectangular search area Points exactly on the edges of the search rectangle ...
uindex_t getIntersectedVoxelCentersRecursive(double min_x, double min_y, double min_z, double max_x, double max_y, double max_z, unsigned char a, const OctreeNode *node, const OctreeKey &key, AlignedPointTVector &voxel_center_list, uindex_t max_voxel_count) const
Recursively search the tree for all intersected leaf nodes and return a vector of voxel centers.
void approxNearestSearchRecursive(const PointT &point, const BranchNode *node, const OctreeKey &key, uindex_t tree_depth, index_t &result_index, float &sqr_distance)
Recursive search method that explores the octree and finds the approximate nearest neighbor.
uindex_t nearestKSearch(const PointCloud &cloud, uindex_t index, uindex_t k, Indices &k_indices, std::vector< float > &k_sqr_distances)
Search for k-nearest neighbors at the query point.
void boxSearchRecursive(const Eigen::Vector3f &min_pt, const Eigen::Vector3f &max_pt, const BranchNode *node, const OctreeKey &key, uindex_t tree_depth, Indices &k_indices) const
Recursive search method that explores the octree and finds points within a rectangular search area.
float pointSquaredDist(const PointT &point_a, const PointT &point_b) const
Helper function to calculate the squared distance between two points.
void getNeighborsWithinRadiusRecursive(const PointT &point, const double radiusSquared, const BranchNode *node, const OctreeKey &key, uindex_t tree_depth, Indices &k_indices, std::vector< float > &k_sqr_distances, uindex_t max_nn) const
Recursive search method that explores the octree and finds neighbors within a given radius.
typename OctreeT::BranchNode BranchNode
void approxNearestSearch(const PointCloud &cloud, uindex_t query_index, index_t &result_index, float &sqr_distance)
Search for approx.
uindex_t radiusSearch(const PointCloud &cloud, uindex_t index, double radius, Indices &k_indices, std::vector< float > &k_sqr_distances, index_t max_nn=0)
Search for all neighbors of query point that are within a given radius.
std::vector< PointT, Eigen::aligned_allocator< PointT > > AlignedPointTVector
decltype(auto) getPointIndices(const T &leaf)
If leaf has function getPointIndicesVector(), call it.
detail::int_type_t< detail::index_type_size, false > uindex_t
Type used for an unsigned index in PCL.
bool isFinite(const PointT &pt)
Tests if the 3D components of a point are all finite param[in] pt point to be tested return true if f...
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
IndicesAllocator<> Indices
Type used for indices in PCL.
A point structure representing Euclidean xyz coordinates, and the RGB color.