39 #ifndef PCL_OCTREE_SEARCH_IMPL_H_
40 #define PCL_OCTREE_SEARCH_IMPL_H_
48 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
54 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
56 bool b_success =
false;
59 this->genOctreeKeyforPoint(point, key);
61 LeafContainerT* leaf = this->findLeaf(key);
64 (*leaf).getPointIndices(point_idx_data);
71 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
76 const PointT search_point = this->getPointByIndex(index);
77 return (this->voxelSearch(search_point, point_idx_data));
80 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
86 std::vector<float>& k_sqr_distances)
88 assert(this->leaf_count_ > 0);
90 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
93 k_sqr_distances.clear();
98 prioPointQueueEntry point_entry;
99 std::vector<prioPointQueueEntry> point_candidates;
100 point_candidates.reserve(k);
103 key.
x = key.
y = key.
z = 0;
106 double smallest_dist = std::numeric_limits<double>::max();
108 getKNearestNeighborRecursive(
109 p_q, k, this->root_node_, key, 1, smallest_dist, point_candidates);
111 const auto result_count =
static_cast<uindex_t>(point_candidates.size());
113 k_indices.resize(result_count);
114 k_sqr_distances.resize(result_count);
116 for (
uindex_t i = 0; i < result_count; ++i) {
117 k_indices[i] = point_candidates[i].point_idx_;
118 k_sqr_distances[i] = point_candidates[i].point_distance_;
121 return k_indices.size();
124 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
129 const PointT search_point = this->getPointByIndex(index);
130 return (nearestKSearch(search_point, k, k_indices, k_sqr_distances));
133 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
136 const PointT& p_q,
index_t& result_index,
float& sqr_distance)
138 assert(this->leaf_count_ > 0);
140 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
143 key.
x = key.
y = key.
z = 0;
145 approxNearestSearchRecursive(
146 p_q, this->root_node_, key, 1, result_index, sqr_distance);
151 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
156 const PointT search_point = this->getPointByIndex(query_index);
158 return (approxNearestSearch(search_point, result_index, sqr_distance));
161 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
167 std::vector<float>& k_sqr_distances,
171 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
173 key.
x = key.
y = key.
z = 0;
176 k_sqr_distances.clear();
178 getNeighborsWithinRadiusRecursive(p_q,
187 return k_indices.size();
190 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
196 std::vector<float>& k_sqr_distances,
199 const PointT search_point = this->getPointByIndex(index);
201 return (radiusSearch(search_point, radius, k_indices, k_sqr_distances, max_nn));
204 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
207 const Eigen::Vector3f& min_pt,
208 const Eigen::Vector3f& max_pt,
213 key.
x = key.
y = key.
z = 0;
217 boxSearchRecursive(min_pt, max_pt, this->root_node_, key, 1, k_indices);
219 return k_indices.size();
222 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
231 const double squared_search_radius,
232 std::vector<prioPointQueueEntry>& point_candidates)
const
234 std::vector<prioBranchQueueEntry> search_heap;
235 search_heap.resize(8);
239 double smallest_squared_dist = squared_search_radius;
242 double voxelSquaredDiameter = this->getVoxelSquaredDiameter(tree_depth);
245 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
246 if (this->branchHasChild(*node, child_idx)) {
249 search_heap[child_idx].key.x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
250 search_heap[child_idx].key.y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
251 search_heap[child_idx].key.z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
254 this->genVoxelCenterFromOctreeKey(
255 search_heap[child_idx].key, tree_depth, voxel_center);
258 search_heap[child_idx].node = this->getBranchChildPtr(*node, child_idx);
259 search_heap[child_idx].point_distance = pointSquaredDist(voxel_center, point);
262 search_heap[child_idx].point_distance = std::numeric_limits<float>::infinity();
266 std::sort(search_heap.begin(), search_heap.end());
271 while ((!search_heap.empty()) &&
272 (search_heap.back().point_distance <
273 smallest_squared_dist + voxelSquaredDiameter / 4.0 +
274 sqrt(smallest_squared_dist * voxelSquaredDiameter) - this->epsilon_)) {
278 child_node = search_heap.back().node;
279 new_key = search_heap.back().key;
283 smallest_squared_dist =
284 getKNearestNeighborRecursive(point,
289 smallest_squared_dist,
296 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
299 (*child_leaf)->getPointIndices(decoded_point_vector);
302 for (
const auto& point_index : decoded_point_vector) {
304 const PointT& candidate_point = this->getPointByIndex(point_index);
307 float squared_dist = pointSquaredDist(candidate_point, point);
309 const auto insert_into_queue = [&] {
310 point_candidates.emplace(
311 std::upper_bound(point_candidates.begin(),
312 point_candidates.end(),
314 [](
float dist,
const prioPointQueueEntry& ent) {
315 return dist < ent.point_distance_;
320 if (point_candidates.size() <
K) {
323 else if (point_candidates.back().point_distance_ > squared_dist) {
324 point_candidates.pop_back();
329 if (point_candidates.size() ==
K)
330 smallest_squared_dist = point_candidates.back().point_distance_;
333 search_heap.pop_back();
336 return (smallest_squared_dist);
339 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
343 const double radiusSquared,
348 std::vector<float>& k_sqr_distances,
352 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
353 if (!this->branchHasChild(*node, child_idx))
357 child_node = this->getBranchChildPtr(*node, child_idx);
363 new_key.
x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
364 new_key.
y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
365 new_key.
z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
369 Eigen::Vector3f min_pt, max_pt;
370 this->genVoxelBoundsFromOctreeKey(new_key, tree_depth, min_pt, max_pt);
372 if (point.x < min_pt.x())
373 squared_dist += std::pow(point.x - min_pt.x(), 2);
374 else if (point.x > max_pt.x())
375 squared_dist += std::pow(point.x - max_pt.x(), 2);
376 if (point.y < min_pt.y())
377 squared_dist += std::pow(point.y - min_pt.y(), 2);
378 else if (point.y > max_pt.y())
379 squared_dist += std::pow(point.y - max_pt.y(), 2);
380 if (point.z < min_pt.z())
381 squared_dist += std::pow(point.z - min_pt.z(), 2);
382 else if (point.z > max_pt.z())
383 squared_dist += std::pow(point.z - max_pt.z(), 2);
384 if (squared_dist < (radiusSquared + this->epsilon_)) {
395 if (max_nn != 0 && k_indices.size() == max_nn)
400 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
404 (*child_leaf)->getPointIndices(decoded_point_vector);
407 for (
const auto& index : decoded_point_vector) {
408 const PointT& candidate_point = this->getPointByIndex(index);
411 squared_dist = pointSquaredDist(candidate_point, point);
414 if (squared_dist > radiusSquared)
418 k_indices.push_back(index);
419 k_sqr_distances.push_back(squared_dist);
421 if (max_nn != 0 && k_indices.size() == max_nn)
429 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
445 double min_voxel_center_distance = std::numeric_limits<double>::max();
447 unsigned char min_child_idx = 0xFF;
450 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
451 if (!this->branchHasChild(*node, child_idx))
455 double voxelPointDist;
457 new_key.
x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
458 new_key.
y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
459 new_key.
z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
462 this->genVoxelCenterFromOctreeKey(new_key, tree_depth, voxel_center);
464 voxelPointDist = pointSquaredDist(voxel_center, point);
467 if (voxelPointDist >= min_voxel_center_distance)
470 min_voxel_center_distance = voxelPointDist;
471 min_child_idx = child_idx;
472 minChildKey = new_key;
476 assert(min_child_idx < 8);
478 child_node = this->getBranchChildPtr(*node, min_child_idx);
482 approxNearestSearchRecursive(point,
493 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
495 float smallest_squared_dist = std::numeric_limits<float>::max();
498 (**child_leaf).getPointIndices(decoded_point_vector);
501 for (
const auto& index : decoded_point_vector) {
502 const PointT& candidate_point = this->getPointByIndex(index);
505 float squared_dist = pointSquaredDist(candidate_point, point);
508 if (squared_dist >= smallest_squared_dist)
511 result_index = index;
512 smallest_squared_dist = squared_dist;
513 sqr_distance = squared_dist;
518 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
523 return (point_a.getVector3fMap() - point_b.getVector3fMap()).squaredNorm();
526 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
529 const Eigen::Vector3f& min_pt,
530 const Eigen::Vector3f& max_pt,
537 for (
unsigned char child_idx = 0; child_idx < 8; child_idx++) {
540 child_node = this->getBranchChildPtr(*node, child_idx);
547 new_key.
x = (key.
x << 1) + (!!(child_idx & (1 << 2)));
548 new_key.
y = (key.
y << 1) + (!!(child_idx & (1 << 1)));
549 new_key.
z = (key.
z << 1) + (!!(child_idx & (1 << 0)));
552 Eigen::Vector3f lower_voxel_corner;
553 Eigen::Vector3f upper_voxel_corner;
555 this->genVoxelBoundsFromOctreeKey(
556 new_key, tree_depth, lower_voxel_corner, upper_voxel_corner);
560 if ((lower_voxel_corner(0) <= max_pt(0)) && (min_pt(0) <= upper_voxel_corner(0)) &&
561 (lower_voxel_corner(1) <= max_pt(1)) && (min_pt(1) <= upper_voxel_corner(1)) &&
562 (lower_voxel_corner(2) <= max_pt(2)) && (min_pt(2) <= upper_voxel_corner(2))) {
566 boxSearchRecursive(min_pt,
577 const auto* child_leaf =
static_cast<const LeafNode*
>(child_node);
580 (**child_leaf).getPointIndices(decoded_point_vector);
583 for (
const auto& index : decoded_point_vector) {
584 const PointT& candidate_point = this->getPointByIndex(index);
588 ((candidate_point.x >= min_pt(0)) && (candidate_point.x <= max_pt(0)) &&
589 (candidate_point.y >= min_pt(1)) && (candidate_point.y <= max_pt(1)) &&
590 (candidate_point.z >= min_pt(2)) && (candidate_point.z <= max_pt(2)));
594 k_indices.push_back(index);
601 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
605 Eigen::Vector3f direction,
610 key.
x = key.
y = key.
z = 0;
612 voxel_center_list.clear();
617 double min_x, min_y, min_z, max_x, max_y, max_z;
619 initIntersectedVoxel(origin, direction, min_x, min_y, min_z, max_x, max_y, max_z, a);
621 if (std::max(std::max(min_x, min_y), min_z) < std::min(std::min(max_x, max_y), max_z))
622 return getIntersectedVoxelCentersRecursive(min_x,
637 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
641 Eigen::Vector3f direction,
646 key.
x = key.
y = key.
z = 0;
652 double min_x, min_y, min_z, max_x, max_y, max_z;
654 initIntersectedVoxel(origin, direction, min_x, min_y, min_z, max_x, max_y, max_z, a);
656 if (std::max(std::max(min_x, min_y), min_z) < std::min(std::min(max_x, max_y), max_z))
657 return getIntersectedVoxelIndicesRecursive(min_x,
671 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
686 if (max_x < 0.0 || max_y < 0.0 || max_z < 0.0)
693 this->genLeafNodeCenterFromOctreeKey(key, newPoint);
695 voxel_center_list.push_back(newPoint);
704 double mid_x = 0.5 * (min_x + max_x);
705 double mid_y = 0.5 * (min_y + max_y);
706 double mid_z = 0.5 * (min_z + max_z);
709 auto curr_node = getFirstIntersectedNode(min_x, min_y, min_z, mid_x, mid_y, mid_z);
712 unsigned char child_idx;
717 child_idx =
static_cast<unsigned char>(curr_node ^ a);
723 this->getBranchChildPtr(
static_cast<const BranchNode&
>(*node), child_idx);
726 child_key.
x = (key.
x << 1) | (!!(child_idx & (1 << 2)));
727 child_key.
y = (key.
y << 1) | (!!(child_idx & (1 << 1)));
728 child_key.
z = (key.
z << 1) | (!!(child_idx & (1 << 0)));
737 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
748 curr_node = getNextIntersectedNode(mid_x, mid_y, mid_z, 4, 2, 1);
753 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
764 curr_node = getNextIntersectedNode(mid_x, mid_y, max_z, 5, 3, 8);
769 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
780 curr_node = getNextIntersectedNode(mid_x, max_y, mid_z, 6, 8, 3);
785 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
796 curr_node = getNextIntersectedNode(mid_x, max_y, max_z, 7, 8, 8);
801 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
812 curr_node = getNextIntersectedNode(max_x, mid_y, mid_z, 8, 6, 5);
817 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
828 curr_node = getNextIntersectedNode(max_x, mid_y, max_z, 8, 7, 8);
833 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
844 curr_node = getNextIntersectedNode(max_x, max_y, mid_z, 8, 8, 7);
849 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
863 }
while ((curr_node < 8) && (max_voxel_count <= 0 || voxel_count < max_voxel_count));
864 return (voxel_count);
867 template <
typename Po
intT,
typename LeafContainerT,
typename BranchContainerT>
882 if (max_x < 0.0 || max_y < 0.0 || max_z < 0.0)
887 const auto* leaf =
static_cast<const LeafNode*
>(node);
890 (*leaf)->getPointIndices(k_indices);
899 double mid_x = 0.5 * (min_x + max_x);
900 double mid_y = 0.5 * (min_y + max_y);
901 double mid_z = 0.5 * (min_z + max_z);
904 auto curr_node = getFirstIntersectedNode(min_x, min_y, min_z, mid_x, mid_y, mid_z);
907 unsigned char child_idx;
911 child_idx =
static_cast<unsigned char>(curr_node ^ a);
917 this->getBranchChildPtr(
static_cast<const BranchNode&
>(*node), child_idx);
919 child_key.
x = (key.
x << 1) | (!!(child_idx & (1 << 2)));
920 child_key.
y = (key.
y << 1) | (!!(child_idx & (1 << 1)));
921 child_key.
z = (key.
z << 1) | (!!(child_idx & (1 << 0)));
929 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
940 curr_node = getNextIntersectedNode(mid_x, mid_y, mid_z, 4, 2, 1);
945 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
956 curr_node = getNextIntersectedNode(mid_x, mid_y, max_z, 5, 3, 8);
961 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
972 curr_node = getNextIntersectedNode(mid_x, max_y, mid_z, 6, 8, 3);
977 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
988 curr_node = getNextIntersectedNode(mid_x, max_y, max_z, 7, 8, 8);
993 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1004 curr_node = getNextIntersectedNode(max_x, mid_y, mid_z, 8, 6, 5);
1009 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1020 curr_node = getNextIntersectedNode(max_x, mid_y, max_z, 8, 7, 8);
1025 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1036 curr_node = getNextIntersectedNode(max_x, max_y, mid_z, 8, 8, 7);
1041 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1055 }
while ((curr_node < 8) && (max_voxel_count <= 0 || voxel_count < max_voxel_count));
1057 return (voxel_count);
1063 #define PCL_INSTANTIATE_OctreePointCloudSearch(T) \
1064 template class PCL_EXPORTS pcl::octree::OctreePointCloudSearch<T>;
Abstract octree branch class
Abstract octree node class
virtual node_type_t getNodeType() const =0
Pure virtual method for retrieving the type of octree node (branch or leaf)
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
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.