Point Cloud Library (PCL) 1.15.1-dev
Loading...
Searching...
No Matches
octree_search.hpp
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2010-2011, Willow Garage, Inc.
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 * * Neither the name of Willow Garage, Inc. nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * $Id$
37 */
38
39#ifndef PCL_OCTREE_SEARCH_IMPL_H_
40#define PCL_OCTREE_SEARCH_IMPL_H_
41
42#include <cassert>
43#include <type_traits> // for std::false_type, std::true_type, std::void_t
44#include <utility> // for std::declval
45
46namespace pcl {
47
48namespace octree {
49
50namespace detail {
51template <class T, class = void>
52struct has_getPointIndicesVector : std::false_type {};
53
54template <class T>
56 T,
57 std::void_t<decltype(std::declval<const T&>().getPointIndicesVector())>>
58: std::true_type {};
59
60/** If leaf has function getPointIndicesVector(), call it. Otherwise call
61 * leaf.getPointIndices().
62 */
63template <class T, std::enable_if_t<has_getPointIndicesVector<T>::value, int> = 0>
64decltype(auto)
65getPointIndices(const T& leaf)
66{
67 return leaf.getPointIndicesVector();
68}
69
70/** If leaf has function getPointIndicesVector(), call it. Otherwise call
71 * leaf.getPointIndices().
72 */
73template <class T, std::enable_if_t<!has_getPointIndicesVector<T>::value, int> = 0>
75getPointIndices(const T& leaf)
76{
77 pcl::Indices decoded_point_vector;
78 leaf.getPointIndices(decoded_point_vector);
79 return decoded_point_vector;
80}
81} // namespace detail
82
83template <typename PointT, typename LeafContainerT, typename BranchContainerT>
84bool
86 const PointT& point, Indices& point_idx_data)
87{
88 assert(isFinite(point) &&
89 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
90 OctreeKey key;
91 bool b_success = false;
92
93 // generate key
94 this->genOctreeKeyforPoint(point, key);
95
96 LeafContainerT* leaf = this->findLeaf(key);
97
98 if (leaf) {
99 (*leaf).getPointIndices(point_idx_data);
100 b_success = true;
101 }
102
103 return (b_success);
104}
105
106template <typename PointT, typename LeafContainerT, typename BranchContainerT>
107bool
109 const uindex_t index, Indices& point_idx_data)
110{
111 const PointT search_point = this->getPointByIndex(index);
112 return (this->voxelSearch(search_point, point_idx_data));
113}
114
115template <typename PointT, typename LeafContainerT, typename BranchContainerT>
118 const PointT& p_q,
119 uindex_t k,
120 Indices& k_indices,
121 std::vector<float>& k_sqr_distances)
122{
123 assert(this->leaf_count_ > 0);
124 assert(isFinite(p_q) &&
125 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
126
127 k_indices.clear();
128 k_sqr_distances.clear();
129
130 if (k < 1)
131 return 0;
132
133 prioPointQueueEntry point_entry;
134 std::vector<prioPointQueueEntry> point_candidates;
135 point_candidates.reserve(k);
136
137 OctreeKey key;
138 key.x = key.y = key.z = 0;
139
140 // initialize smallest point distance in search with high value
141 double smallest_dist = std::numeric_limits<double>::max();
142
143 getKNearestNeighborRecursive(
144 p_q, k, this->root_node_, key, 1, smallest_dist, point_candidates);
145
146 const auto result_count = static_cast<uindex_t>(point_candidates.size());
147
148 k_indices.resize(result_count);
149 k_sqr_distances.resize(result_count);
150
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_;
154 }
155
156 return k_indices.size();
157}
158
159template <typename PointT, typename LeafContainerT, typename BranchContainerT>
162 uindex_t index, uindex_t k, Indices& k_indices, std::vector<float>& k_sqr_distances)
163{
164 const PointT search_point = this->getPointByIndex(index);
165 return (nearestKSearch(search_point, k, k_indices, k_sqr_distances));
166}
167
168template <typename PointT, typename LeafContainerT, typename BranchContainerT>
169void
171 const PointT& p_q, index_t& result_index, float& sqr_distance)
172{
173 assert(this->leaf_count_ > 0);
174 assert(isFinite(p_q) &&
175 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
176
177 OctreeKey key;
178 key.x = key.y = key.z = 0;
179
180 approxNearestSearchRecursive(
181 p_q, this->root_node_, key, 1, result_index, sqr_distance);
182
183 return;
184}
185
186template <typename PointT, typename LeafContainerT, typename BranchContainerT>
187void
189 uindex_t query_index, index_t& result_index, float& sqr_distance)
190{
191 const PointT search_point = this->getPointByIndex(query_index);
192
193 return (approxNearestSearch(search_point, result_index, sqr_distance));
194}
195
196template <typename PointT, typename LeafContainerT, typename BranchContainerT>
199 const PointT& p_q,
200 const double radius,
201 Indices& k_indices,
202 std::vector<float>& k_sqr_distances,
203 uindex_t max_nn) const
204{
205 assert(isFinite(p_q) &&
206 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
207 OctreeKey key;
208 key.x = key.y = key.z = 0;
209
210 k_indices.clear();
211 k_sqr_distances.clear();
212
213 getNeighborsWithinRadiusRecursive(p_q,
214 radius * radius,
215 this->root_node_,
216 key,
217 1,
218 k_indices,
219 k_sqr_distances,
220 max_nn);
222 return k_indices.size();
223}
224
225template <typename PointT, typename LeafContainerT, typename BranchContainerT>
228 uindex_t index,
229 const double radius,
230 Indices& k_indices,
231 std::vector<float>& k_sqr_distances,
232 uindex_t max_nn) const
233{
234 const PointT search_point = this->getPointByIndex(index);
235
236 return (radiusSearch(search_point, radius, k_indices, k_sqr_distances, max_nn));
237}
238
239template <typename PointT, typename LeafContainerT, typename BranchContainerT>
242 const Eigen::Vector3f& min_pt,
243 const Eigen::Vector3f& max_pt,
244 Indices& k_indices) const
245{
246
247 OctreeKey key;
248 key.x = key.y = key.z = 0;
249
250 k_indices.clear();
251
252 boxSearchRecursive(min_pt, max_pt, this->root_node_, key, 1, k_indices);
253
254 return k_indices.size();
256
257template <typename PointT, typename LeafContainerT, typename BranchContainerT>
258double
261 const PointT& point,
262 uindex_t K,
263 const BranchNode* node,
264 const OctreeKey& key,
265 uindex_t tree_depth,
266 const double squared_search_radius,
267 std::vector<prioPointQueueEntry>& point_candidates) const
268{
269 std::vector<prioBranchQueueEntry> search_heap;
270 search_heap.resize(8);
271
272 OctreeKey new_key;
273
274 double smallest_squared_dist = squared_search_radius;
275
276 // get spatial voxel information
277 double voxelSquaredDiameter = this->getVoxelSquaredDiameter(tree_depth);
278
279 // iterate over all children
280 for (unsigned char child_idx = 0; child_idx < 8; child_idx++) {
281 if (this->branchHasChild(*node, child_idx)) {
282 PointT voxel_center;
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)));
287
288 // generate voxel center point for voxel at key
289 this->genVoxelCenterFromOctreeKey(
290 search_heap[child_idx].key, tree_depth, voxel_center);
291
292 // generate new priority queue element
293 search_heap[child_idx].node = this->getBranchChildPtr(*node, child_idx);
294 search_heap[child_idx].point_distance = pointSquaredDist(voxel_center, point);
295 }
296 else {
297 search_heap[child_idx].point_distance = std::numeric_limits<float>::infinity();
298 }
299 }
300
301 std::sort(search_heap.begin(), search_heap.end());
302
303 // iterate over all children in priority queue
304 // check if the distance to search candidate is smaller than the best point distance
305 // (smallest_squared_dist)
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;
311
312 // read from priority queue element
313 child_node = search_heap.back().node;
314 new_key = search_heap.back().key;
315
316 if (child_node->getNodeType() == BRANCH_NODE) {
317 // we have not reached maximum tree depth
318 smallest_squared_dist =
319 getKNearestNeighborRecursive(point,
320 K,
321 static_cast<const BranchNode*>(child_node),
322 new_key,
323 tree_depth + 1,
324 smallest_squared_dist,
325 point_candidates);
326 }
327 else {
328 // we reached leaf node level
329 Indices decoded_point_vector;
330
331 const auto* child_leaf = static_cast<const LeafNode*>(child_node);
332
333 // decode leaf node into decoded_point_vector
334 (*child_leaf)->getPointIndices(decoded_point_vector);
335
336 // Linearly iterate over all decoded (unsorted) points
337 for (const auto& point_index : decoded_point_vector) {
338
339 const PointT& candidate_point = this->getPointByIndex(point_index);
340
341 // calculate point distance to search point
342 float squared_dist = pointSquaredDist(candidate_point, point);
343
344 const auto insert_into_queue = [&] {
345 point_candidates.emplace(
346 std::upper_bound(point_candidates.begin(),
347 point_candidates.end(),
348 squared_dist,
349 [](float dist, const prioPointQueueEntry& ent) {
350 return dist < ent.point_distance_;
351 }),
352 point_index,
353 squared_dist);
354 };
355 if (point_candidates.size() < K) {
356 insert_into_queue();
357 }
358 else if (point_candidates.back().point_distance_ > squared_dist) {
359 point_candidates.pop_back();
360 insert_into_queue();
361 }
362 }
363
364 if (point_candidates.size() == K)
365 smallest_squared_dist = point_candidates.back().point_distance_;
366 }
367 // pop element from priority queue
368 search_heap.pop_back();
370
371 return (smallest_squared_dist);
372}
373
374template <typename PointT, typename LeafContainerT, typename BranchContainerT>
375void
378 const double radiusSquared,
379 const BranchNode* node,
380 const OctreeKey& key,
381 uindex_t tree_depth,
382 Indices& k_indices,
383 std::vector<float>& k_sqr_distances,
384 uindex_t max_nn) const
385{
386 // iterate over all children
387 for (unsigned char child_idx = 0; child_idx < 8; child_idx++) {
388 if (!this->branchHasChild(*node, child_idx))
389 continue;
390
391 const OctreeNode* child_node;
392 child_node = this->getBranchChildPtr(*node, child_idx);
393
394 OctreeKey new_key;
395 float squared_dist;
396
397 // generate new key for current branch voxel
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)));
401
402 // compute min distance between query point and any point in this child node, to
403 // decide whether we can skip it
404 Eigen::Vector3f min_pt, max_pt;
405 this->genVoxelBoundsFromOctreeKey(new_key, tree_depth, min_pt, max_pt);
406 squared_dist = 0.0f;
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_)) {
420 if (child_node->getNodeType() == BRANCH_NODE) {
421 // we have not reached maximum tree depth
422 getNeighborsWithinRadiusRecursive(point,
423 radiusSquared,
424 static_cast<const BranchNode*>(child_node),
425 new_key,
426 tree_depth + 1,
427 k_indices,
428 k_sqr_distances,
429 max_nn);
430 if (max_nn != 0 && k_indices.size() == max_nn)
431 return;
432 }
433 else {
434 // we reached leaf node level
435 const auto* child_leaf = static_cast<const LeafNode*>(child_node);
436
437 // Linearly iterate over all points in the leaf
438 for (const auto& index : detail::getPointIndices(*(*child_leaf))) {
439 const PointT& candidate_point = this->getPointByIndex(index);
440
441 // calculate point distance to search point
442 squared_dist = pointSquaredDist(candidate_point, point);
443
444 // check if a match is found
445 if (squared_dist > radiusSquared)
446 continue;
447
448 // add point to result vector
449 k_indices.push_back(index);
450 k_sqr_distances.push_back(squared_dist);
451
452 if (max_nn != 0 && k_indices.size() == max_nn)
453 return;
454 }
455 }
456 }
457 }
458}
459
460template <typename PointT, typename LeafContainerT, typename BranchContainerT>
461void
464 const BranchNode* node,
465 const OctreeKey& key,
466 uindex_t tree_depth,
467 index_t& result_index,
468 float& sqr_distance)
469{
470 OctreeKey minChildKey;
471 OctreeKey new_key;
472
473 const OctreeNode* child_node;
474
475 // set minimum voxel distance to maximum value
476 double min_voxel_center_distance = std::numeric_limits<double>::max();
477
478 unsigned char min_child_idx = 0xFF;
479
480 // iterate over all children
481 for (unsigned char child_idx = 0; child_idx < 8; child_idx++) {
482 if (!this->branchHasChild(*node, child_idx))
483 continue;
484
485 PointT voxel_center;
486 double voxelPointDist;
487
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)));
491
492 // generate voxel center point for voxel at key
493 this->genVoxelCenterFromOctreeKey(new_key, tree_depth, voxel_center);
494
495 voxelPointDist = pointSquaredDist(voxel_center, point);
496
497 // search for child voxel with shortest distance to search point
498 if (voxelPointDist >= min_voxel_center_distance)
499 continue;
501 min_voxel_center_distance = voxelPointDist;
502 min_child_idx = child_idx;
503 minChildKey = new_key;
504 }
505
506 // make sure we found at least one branch child
507 assert(min_child_idx < 8);
508
509 child_node = this->getBranchChildPtr(*node, min_child_idx);
510
511 if (child_node->getNodeType() == BRANCH_NODE) {
512 // we have not reached maximum tree depth
513 approxNearestSearchRecursive(point,
514 static_cast<const BranchNode*>(child_node),
515 minChildKey,
516 tree_depth + 1,
517 result_index,
518 sqr_distance);
519 }
520 else {
521 // we reached leaf node level
522 Indices decoded_point_vector;
523
524 const auto* child_leaf = static_cast<const LeafNode*>(child_node);
525
526 float smallest_squared_dist = std::numeric_limits<float>::max();
527
528 // decode leaf node into decoded_point_vector
529 (**child_leaf).getPointIndices(decoded_point_vector);
530
531 // Linearly iterate over all decoded (unsorted) points
532 for (const auto& index : decoded_point_vector) {
533 const PointT& candidate_point = this->getPointByIndex(index);
534
535 // calculate point distance to search point
536 float squared_dist = pointSquaredDist(candidate_point, point);
537
538 // check if a closer match is found
539 if (squared_dist >= smallest_squared_dist)
540 continue;
541
542 result_index = index;
543 smallest_squared_dist = squared_dist;
544 sqr_distance = squared_dist;
545 }
546 }
547}
548
549template <typename PointT, typename LeafContainerT, typename BranchContainerT>
550float
552 const PointT& point_a, const PointT& point_b) const
553{
554 return (point_a.getVector3fMap() - point_b.getVector3fMap()).squaredNorm();
555}
556
557template <typename PointT, typename LeafContainerT, typename BranchContainerT>
558void
560 const Eigen::Vector3f& min_pt,
561 const Eigen::Vector3f& max_pt,
562 const BranchNode* node,
563 const OctreeKey& key,
564 uindex_t tree_depth,
565 Indices& k_indices) const
566{
567 // iterate over all children
568 for (unsigned char child_idx = 0; child_idx < 8; child_idx++) {
569
570 const OctreeNode* child_node;
571 child_node = this->getBranchChildPtr(*node, child_idx);
572
573 if (!child_node)
574 continue;
575
576 OctreeKey new_key;
577 // generate new key for current branch voxel
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)));
581
582 // voxel corners
583 Eigen::Vector3f lower_voxel_corner;
584 Eigen::Vector3f upper_voxel_corner;
585 // get voxel coordinates
586 this->genVoxelBoundsFromOctreeKey(
587 new_key, tree_depth, lower_voxel_corner, upper_voxel_corner);
588
589 // test if search region overlap with voxel space
590
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))) {
594
595 if (child_node->getNodeType() == BRANCH_NODE) {
596 // we have not reached maximum tree depth
597 boxSearchRecursive(min_pt,
598 max_pt,
599 static_cast<const BranchNode*>(child_node),
600 new_key,
601 tree_depth + 1,
602 k_indices);
603 }
604 else {
605 // we reached leaf node level
606 Indices decoded_point_vector;
607
608 const auto* child_leaf = static_cast<const LeafNode*>(child_node);
609
610 // decode leaf node into decoded_point_vector
611 (**child_leaf).getPointIndices(decoded_point_vector);
612
613 // Linearly iterate over all decoded (unsorted) points
614 for (const auto& index : decoded_point_vector) {
615 const PointT& candidate_point = this->getPointByIndex(index);
616
617 // check if point falls within search box
618 bool bInBox =
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)));
622
623 if (bInBox)
624 // add to result vector
625 k_indices.push_back(index);
626 }
627 }
628 }
629 }
630}
631
632template <typename PointT, typename LeafContainerT, typename BranchContainerT>
635 getIntersectedVoxelCenters(Eigen::Vector3f origin,
636 Eigen::Vector3f direction,
637 AlignedPointTVector& voxel_center_list,
638 uindex_t max_voxel_count) const
639{
640 OctreeKey key;
641 key.x = key.y = key.z = 0;
642
643 voxel_center_list.clear();
644
645 // Voxel child_idx remapping
646 unsigned char a = 0;
647
648 double min_x, min_y, min_z, max_x, max_y, max_z;
649
650 initIntersectedVoxel(origin, direction, min_x, min_y, min_z, max_x, max_y, max_z, a);
651
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,
654 min_y,
655 min_z,
656 max_x,
657 max_y,
658 max_z,
659 a,
660 this->root_node_,
661 key,
662 voxel_center_list,
663 max_voxel_count);
664
665 return (0);
666}
667
668template <typename PointT, typename LeafContainerT, typename BranchContainerT>
671 getIntersectedVoxelIndices(Eigen::Vector3f origin,
672 Eigen::Vector3f direction,
673 Indices& k_indices,
674 uindex_t max_voxel_count) const
675{
676 OctreeKey key;
677 key.x = key.y = key.z = 0;
678
679 k_indices.clear();
680
681 // Voxel child_idx remapping
682 unsigned char a = 0;
683 double min_x, min_y, min_z, max_x, max_y, max_z;
684
685 initIntersectedVoxel(origin, direction, min_x, min_y, min_z, max_x, max_y, max_z, a);
686
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,
689 min_y,
690 min_z,
691 max_x,
692 max_y,
693 max_z,
694 a,
695 this->root_node_,
696 key,
697 k_indices,
698 max_voxel_count);
699 return (0);
700}
701
702template <typename PointT, typename LeafContainerT, typename BranchContainerT>
706 double min_y,
707 double min_z,
708 double max_x,
709 double max_y,
710 double max_z,
711 unsigned char a,
712 const OctreeNode* node,
713 const OctreeKey& key,
714 AlignedPointTVector& voxel_center_list,
715 uindex_t max_voxel_count) const
716{
717 if (max_x < 0.0 || max_y < 0.0 || max_z < 0.0)
718 return (0);
719
720 // If leaf node, get voxel center and increment intersection count
721 if (node->getNodeType() == LEAF_NODE) {
722 PointT newPoint;
723
724 this->genLeafNodeCenterFromOctreeKey(key, newPoint);
725
726 voxel_center_list.push_back(newPoint);
727
728 return (1);
729 }
730
731 // Voxel intersection count for branches children
732 uindex_t voxel_count = 0;
733
734 // Voxel mid lines
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);
738
739 // First voxel node ray will intersect
740 auto curr_node = getFirstIntersectedNode(min_x, min_y, min_z, mid_x, mid_y, mid_z);
741
742 // Child index, node and key
743 unsigned char child_idx;
744 OctreeKey child_key;
745
746 do {
747 if (curr_node != 0)
748 child_idx = static_cast<unsigned char>(curr_node ^ a);
749 else
750 child_idx = a;
751
752 // child_node == 0 if child_node doesn't exist
753 const OctreeNode* child_node =
754 this->getBranchChildPtr(static_cast<const BranchNode&>(*node), child_idx);
755
756 // Generate new key for current branch voxel
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)));
760
761 // Recursively call each intersected child node, selecting the next
762 // node intersected by the ray. Children that do not intersect will
763 // not be traversed.
764
765 switch (curr_node) {
766 case 0:
767 if (child_node)
768 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
769 min_y,
770 min_z,
771 mid_x,
772 mid_y,
773 mid_z,
774 a,
775 child_node,
776 child_key,
777 voxel_center_list,
778 max_voxel_count);
779 curr_node = getNextIntersectedNode(mid_x, mid_y, mid_z, 4, 2, 1);
780 break;
781
782 case 1:
783 if (child_node)
784 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
785 min_y,
786 mid_z,
787 mid_x,
788 mid_y,
789 max_z,
790 a,
791 child_node,
792 child_key,
793 voxel_center_list,
794 max_voxel_count);
795 curr_node = getNextIntersectedNode(mid_x, mid_y, max_z, 5, 3, 8);
796 break;
797
798 case 2:
799 if (child_node)
800 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
801 mid_y,
802 min_z,
803 mid_x,
804 max_y,
805 mid_z,
806 a,
807 child_node,
808 child_key,
809 voxel_center_list,
810 max_voxel_count);
811 curr_node = getNextIntersectedNode(mid_x, max_y, mid_z, 6, 8, 3);
812 break;
813
814 case 3:
815 if (child_node)
816 voxel_count += getIntersectedVoxelCentersRecursive(min_x,
817 mid_y,
818 mid_z,
819 mid_x,
820 max_y,
821 max_z,
822 a,
823 child_node,
824 child_key,
825 voxel_center_list,
826 max_voxel_count);
827 curr_node = getNextIntersectedNode(mid_x, max_y, max_z, 7, 8, 8);
828 break;
829
830 case 4:
831 if (child_node)
832 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
833 min_y,
834 min_z,
835 max_x,
836 mid_y,
837 mid_z,
838 a,
839 child_node,
840 child_key,
841 voxel_center_list,
842 max_voxel_count);
843 curr_node = getNextIntersectedNode(max_x, mid_y, mid_z, 8, 6, 5);
844 break;
845
846 case 5:
847 if (child_node)
848 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
849 min_y,
850 mid_z,
851 max_x,
852 mid_y,
853 max_z,
854 a,
855 child_node,
856 child_key,
857 voxel_center_list,
858 max_voxel_count);
859 curr_node = getNextIntersectedNode(max_x, mid_y, max_z, 8, 7, 8);
860 break;
861
862 case 6:
863 if (child_node)
864 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
865 mid_y,
866 min_z,
867 max_x,
868 max_y,
869 mid_z,
870 a,
871 child_node,
872 child_key,
873 voxel_center_list,
874 max_voxel_count);
875 curr_node = getNextIntersectedNode(max_x, max_y, mid_z, 8, 8, 7);
876 break;
877
878 case 7:
879 if (child_node)
880 voxel_count += getIntersectedVoxelCentersRecursive(mid_x,
881 mid_y,
882 mid_z,
883 max_x,
884 max_y,
885 max_z,
886 a,
887 child_node,
888 child_key,
889 voxel_center_list,
890 max_voxel_count);
891 curr_node = 8;
892 break;
893 }
894 } while ((curr_node < 8) && (max_voxel_count <= 0 || voxel_count < max_voxel_count));
895 return (voxel_count);
896}
897
898template <typename PointT, typename LeafContainerT, typename BranchContainerT>
902 double min_y,
903 double min_z,
904 double max_x,
905 double max_y,
906 double max_z,
907 unsigned char a,
908 const OctreeNode* node,
909 const OctreeKey& key,
910 Indices& k_indices,
911 uindex_t max_voxel_count) const
912{
913 if (max_x < 0.0 || max_y < 0.0 || max_z < 0.0)
914 return (0);
915
916 // If leaf node, get voxel center and increment intersection count
917 if (node->getNodeType() == LEAF_NODE) {
918 const auto* leaf = static_cast<const LeafNode*>(node);
919
920 // decode leaf node into k_indices
921 (*leaf)->getPointIndices(k_indices);
922
923 return (1);
924 }
925
926 // Voxel intersection count for branches children
927 uindex_t voxel_count = 0;
928
929 // Voxel mid lines
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);
933
934 // First voxel node ray will intersect
935 auto curr_node = getFirstIntersectedNode(min_x, min_y, min_z, mid_x, mid_y, mid_z);
936
937 // Child index, node and key
938 unsigned char child_idx;
939 OctreeKey child_key;
940 do {
941 if (curr_node != 0)
942 child_idx = static_cast<unsigned char>(curr_node ^ a);
943 else
944 child_idx = a;
945
946 // child_node == 0 if child_node doesn't exist
947 const OctreeNode* child_node =
948 this->getBranchChildPtr(static_cast<const BranchNode&>(*node), child_idx);
949 // Generate new key for current branch voxel
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)));
953
954 // Recursively call each intersected child node, selecting the next
955 // node intersected by the ray. Children that do not intersect will
956 // not be traversed.
957 switch (curr_node) {
958 case 0:
959 if (child_node)
960 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
961 min_y,
962 min_z,
963 mid_x,
964 mid_y,
965 mid_z,
966 a,
967 child_node,
968 child_key,
969 k_indices,
970 max_voxel_count);
971 curr_node = getNextIntersectedNode(mid_x, mid_y, mid_z, 4, 2, 1);
972 break;
973
974 case 1:
975 if (child_node)
976 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
977 min_y,
978 mid_z,
979 mid_x,
980 mid_y,
981 max_z,
982 a,
983 child_node,
984 child_key,
985 k_indices,
986 max_voxel_count);
987 curr_node = getNextIntersectedNode(mid_x, mid_y, max_z, 5, 3, 8);
988 break;
989
990 case 2:
991 if (child_node)
992 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
993 mid_y,
994 min_z,
995 mid_x,
996 max_y,
997 mid_z,
998 a,
999 child_node,
1000 child_key,
1001 k_indices,
1002 max_voxel_count);
1003 curr_node = getNextIntersectedNode(mid_x, max_y, mid_z, 6, 8, 3);
1004 break;
1005
1006 case 3:
1007 if (child_node)
1008 voxel_count += getIntersectedVoxelIndicesRecursive(min_x,
1009 mid_y,
1010 mid_z,
1011 mid_x,
1012 max_y,
1013 max_z,
1014 a,
1015 child_node,
1016 child_key,
1017 k_indices,
1018 max_voxel_count);
1019 curr_node = getNextIntersectedNode(mid_x, max_y, max_z, 7, 8, 8);
1020 break;
1021
1022 case 4:
1023 if (child_node)
1024 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1025 min_y,
1026 min_z,
1027 max_x,
1028 mid_y,
1029 mid_z,
1030 a,
1031 child_node,
1032 child_key,
1033 k_indices,
1034 max_voxel_count);
1035 curr_node = getNextIntersectedNode(max_x, mid_y, mid_z, 8, 6, 5);
1036 break;
1037
1038 case 5:
1039 if (child_node)
1040 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1041 min_y,
1042 mid_z,
1043 max_x,
1044 mid_y,
1045 max_z,
1046 a,
1047 child_node,
1048 child_key,
1049 k_indices,
1050 max_voxel_count);
1051 curr_node = getNextIntersectedNode(max_x, mid_y, max_z, 8, 7, 8);
1052 break;
1053
1054 case 6:
1055 if (child_node)
1056 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1057 mid_y,
1058 min_z,
1059 max_x,
1060 max_y,
1061 mid_z,
1062 a,
1063 child_node,
1064 child_key,
1065 k_indices,
1066 max_voxel_count);
1067 curr_node = getNextIntersectedNode(max_x, max_y, mid_z, 8, 8, 7);
1068 break;
1069
1070 case 7:
1071 if (child_node)
1072 voxel_count += getIntersectedVoxelIndicesRecursive(mid_x,
1073 mid_y,
1074 mid_z,
1075 max_x,
1076 max_y,
1077 max_z,
1078 a,
1079 child_node,
1080 child_key,
1081 k_indices,
1082 max_voxel_count);
1083 curr_node = 8;
1084 break;
1085 }
1086 } while ((curr_node < 8) && (max_voxel_count <= 0 || voxel_count < max_voxel_count));
1087
1088 return (voxel_count);
1089}
1090
1091} // namespace octree
1092} // namespace pcl
1093
1094#define PCL_INSTANTIATE_OctreePointCloudSearch(T) \
1095 template class PCL_EXPORTS pcl::octree::OctreePointCloudSearch<T>;
1096
1097#endif // PCL_OCTREE_SEARCH_IMPL_H_
Octree key class
Definition octree_key.h:54
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
@ K
Definition norms.h:54
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.
Definition types.h:120
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...
Definition point_tests.h:56
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition types.h:112
IndicesAllocator<> Indices
Type used for indices in PCL.
Definition types.h:133
void void_t
A point structure representing Euclidean xyz coordinates, and the RGB color.