183 typename Tree = nanoflann::KDTreeSingleIndexAdaptor<
193 template <
typename _DistanceType =
float,
typename _IndexType = pcl::index_t>
194 class PCLRadiusResultSet {
196 using DistanceType = _DistanceType;
197 using IndexType = _IndexType;
200 const DistanceType radius;
202 std::vector<IndexType>& m_indices;
203 std::vector<DistanceType>& m_dists;
204 std::size_t max_results_;
206 explicit PCLRadiusResultSet(
207 DistanceType radius_,
208 std::vector<IndexType>& indices,
209 std::vector<DistanceType>& dists,
210 std::size_t max_results = std::numeric_limits<std::size_t>::max())
211 : radius(radius_), m_indices(indices), m_dists(dists), max_results_(max_results)
220 if (max_results_ != std::numeric_limits<std::size_t>::max()) {
221 m_indices.reserve(max_results_);
222 m_dists.reserve(max_results_);
235 return m_indices.size();
240 return m_indices.empty();
255 addPoint(DistanceType dist, IndexType index)
258 m_indices.emplace_back(index);
259 m_dists.emplace_back(dist);
261 return (m_indices.size() < max_results_);
293 using Ptr = shared_ptr<KdTreeNanoflann<PointT, Dim, Distance, Tree>>;
294 using ConstPtr = shared_ptr<const KdTreeNanoflann<PointT, Dim, Distance, Tree>>;
296 using KdTreePtr = shared_ptr<Tree>;
297 using KdTreeConstPtr = shared_ptr<const Tree>;
298 using PointRepresentationConstPtr = shared_ptr<const PointRepresentation<PointT>>;
312 KdTreeNanoflann(
bool sorted,
313 std::size_t leaf_max_size,
314 unsigned int n_thread_build = 1)
316 , leaf_max_size_(leaf_max_size)
317 , n_thread_build_(n_thread_build)
327 KdTreeNanoflann(
bool sorted =
false) : KdTreeNanoflann(sorted, 15, 1) {}
330 ~KdTreeNanoflann()
override =
default;
338 setPointRepresentation(
const PointRepresentationConstPtr& point_representation)
override
340 PCL_DEBUG(
"[KdTreeNanoflann::setPointRepresentation] "
341 "KdTreeNanoflann::setPointRepresentation called, "
342 "point_representation->getNumberOfDimensions()=%i, "
343 "point_representation->isTrivial()=%i\n",
344 point_representation->getNumberOfDimensions(),
345 point_representation->isTrivial());
346 if (Dim != -1 && Dim != point_representation->getNumberOfDimensions()) {
347 PCL_ERROR(
"[KdTreeNanoflann::setPointRepresentation] The given point "
348 "representation uses %i dimensions, but the nr of dimensions given as "
349 "template parameter to KdTreeNanoflann is %i.\n",
350 point_representation->getNumberOfDimensions(),
354 point_representation_ = point_representation;
362 inline PointRepresentationConstPtr
363 getPointRepresentation()
const
365 return point_representation_;
372 setSortedResults(
bool sorted_results)
override
374 sorted_results_ = sorted_results;
382 setEpsilon(
float eps)
402 setUseRKNN(
bool use_rknn)
404 use_rknn_ = use_rknn;
412 setInputCloud(
const PointCloudConstPtr& cloud,
426 return nanoflann_tree_;
439 nearestKSearch(
const PointT& point,
442 std::vector<float>& k_sqr_distances)
const override
444 assert(point_representation_->isValid(point) &&
445 "Invalid (NaN, Inf) point coordinates given to nearestKSearch!");
446 if (
static_cast<std::size_t
>(k) > adaptor_->kdtree_get_point_count())
447 k = adaptor_->kdtree_get_point_count();
449 k_sqr_distances.resize(k);
450 float* query_point =
nullptr;
451 if (!point_representation_->isTrivial()) {
452 query_point =
new float[point_representation_->getNumberOfDimensions()];
453 point_representation_->vectorize(point, query_point);
456 nanoflann::KNNResultSet<float, pcl::index_t> resultSet(k);
457 resultSet.init(k_indices.data(), k_sqr_distances.data());
458 nanoflann_tree_->findNeighbors(
460 (query_point ? query_point :
reinterpret_cast<const float*
>(&point))
461#if NANOFLANN_VERSION < 0x150
463 nanoflann::SearchParams()
466 const auto search_result = resultSet.size();
467 delete[] query_point;
468 assert(search_result == k);
470 if (!identity_mapping_) {
471 for (
auto& index : k_indices) {
472 index = index_mapping_[index];
475 return search_result;
490 radiusSearch(
const PointT& point,
493 std::vector<float>& k_sqr_distances,
494 unsigned int max_nn = 0)
const override
496 assert(point_representation_->isValid(point) &&
497 "Invalid (NaN, Inf) point coordinates given to radiusSearch!");
498 float* query_point =
nullptr;
499 if (!point_representation_->isTrivial()) {
500 query_point =
new float[point_representation_->getNumberOfDimensions()];
501 point_representation_->vectorize(point, query_point);
508 if (sorted_results_) {
509#if NANOFLANN_VERSION < 0x150
510 std::vector<std::pair<pcl::index_t, float>>
513 std::vector<nanoflann::ResultItem<pcl::index_t, float>> IndicesDists;
516 nanoflann::RadiusResultSet<float, pcl::index_t> resultSet(
517 pcl::search::internal::square_if_l2<Distance>(radius), IndicesDists);
518 nanoflann_tree_->findNeighbors(
520 (query_point ? query_point :
reinterpret_cast<const float*
>(&point)),
521#if NANOFLANN_VERSION < 0x150
522 {32, eps_, sorted_results_}
525 {eps_, sorted_results_}
528#if NANOFLANN_VERSION < 0x160
532 IndicesDists.begin(), IndicesDists.end(), nanoflann::IndexDist_Sorter());
534 const auto search_result = resultSet.size();
535 k_indices.resize(IndicesDists.size());
536 k_sqr_distances.resize(IndicesDists.size());
537 for (std::size_t i = 0; i < IndicesDists.size(); ++i) {
538 k_indices[i] = identity_mapping_ ? IndicesDists[i].first
539 : index_mapping_[IndicesDists[i].first];
540 k_sqr_distances[i] = IndicesDists[i].second;
542 delete[] query_point;
543 return search_result;
546 PCLRadiusResultSet<float, pcl::index_t> resultSet(
547 pcl::search::internal::square_if_l2<Distance>(radius),
551 nanoflann_tree_->findNeighbors(
553 (query_point ? query_point :
reinterpret_cast<const float*
>(&point)),
554#if NANOFLANN_VERSION < 0x150
555 {32, eps_, sorted_results_}
558 {eps_, sorted_results_}
561 const auto search_result = resultSet.size();
562 if (!identity_mapping_) {
563 for (
auto& index : k_indices) {
564 index = index_mapping_[index];
568 this->sortResults(k_indices, k_sqr_distances);
569 delete[] query_point;
570 return search_result;
577 if (
static_cast<std::size_t
>(max_nn) > adaptor_->kdtree_get_point_count())
578 max_nn = adaptor_->kdtree_get_point_count();
579 k_indices.resize(max_nn);
580 k_sqr_distances.resize(max_nn);
581#if NANOFLANN_VERSION < 0x151
584 nanoflann::KNNResultSet<float, pcl::index_t> resultSet(max_nn);
585 resultSet.init(k_indices.data(), k_sqr_distances.data());
586 nanoflann_tree_->findNeighbors(
588 (query_point ? query_point :
reinterpret_cast<const float*
>(&point))
589#if NANOFLANN_VERSION < 0x150
591 nanoflann::SearchParams()
594 auto search_result = resultSet.size();
595 for (
auto iter = k_sqr_distances.rbegin();
596 iter != k_sqr_distances.rend() &&
597 *iter > pcl::search::internal::square_if_l2<Distance>(radius);
601 k_indices.resize(search_result);
602 k_sqr_distances.resize(search_result);
605 nanoflann::RKNNResultSet<float, pcl::index_t> resultSet(
606 max_nn, pcl::search::internal::square_if_l2<Distance>(radius));
607 resultSet.init(k_indices.data(), k_sqr_distances.data());
608 nanoflann_tree_->findNeighbors(
610 (query_point ? query_point :
reinterpret_cast<const float*
>(&point)));
611 const auto search_result = resultSet.size();
612 k_indices.resize(search_result);
613 k_sqr_distances.resize(search_result);
615 if (!identity_mapping_) {
616 for (
auto& index : k_indices) {
617 index = index_mapping_[index];
620 delete[] query_point;
621 return search_result;
625 PCLRadiusResultSet<float, pcl::index_t> resultSet(
626 pcl::search::internal::square_if_l2<Distance>(radius),
631 nanoflann_tree_->findNeighbors(
633 (query_point ? query_point :
reinterpret_cast<const float*
>(&point)),
634#if NANOFLANN_VERSION < 0x150
635 {32, eps_, sorted_results_}
638 {eps_, sorted_results_}
641 const auto search_result = resultSet.size();
642 if (!identity_mapping_) {
643 for (
auto& index : k_indices) {
644 index = index_mapping_[index];
648 this->sortResults(k_indices, k_sqr_distances);
649 delete[] query_point;
650 return search_result;
662 if (!point_representation_ || !input_ || input_->empty()) {
663 PCL_ERROR(
"[KdTreeNanoflann::setUpTree] point representation is null or input is "
664 "null or input is empty\n");
668 const std::size_t dim = point_representation_->getNumberOfDimensions();
669 if (Dim != -1 && Dim !=
static_cast<int>(dim)) {
670 PCL_ERROR(
"[KdTreeNanoflann::setUpTree] The given point "
671 "representation uses %i dimensions, but the nr of dimensions given as "
672 "template parameter to KdTreeNanoflann is %i.\n",
677 index_mapping_.clear();
678 if (indices_ && !indices_->empty()) {
679 index_mapping_.reserve(indices_->size());
680 for (
const auto& index : *indices_) {
681 if (point_representation_->isValid((*input_)[index])) {
682 index_mapping_.emplace_back(index);
687 index_mapping_.reserve(input_->size());
688 for (std::size_t index = 0; index < input_->size(); ++index) {
689 if (point_representation_->isValid((*input_)[index])) {
690 index_mapping_.emplace_back(index);
694 identity_mapping_ =
true;
696 identity_mapping_ &&
static_cast<std::size_t
>(index) < index_mapping_.size();
698 identity_mapping_ = identity_mapping_ && index_mapping_[index] == index;
701 PCL_DEBUG(
"[KdTreeNanoflann::setUpTree] identity_mapping_=%i, "
702 "point_representation_->getNumberOfDimensions()=%lu, "
703 "point_representation_->isTrivial ()=%i\n",
704 identity_mapping_ ? 1 : 0,
706 point_representation_->isTrivial() ? 1 : 0);
707 if (identity_mapping_ && point_representation_->isTrivial() &&
708 sizeof(
PointT) %
sizeof(
float) == 0) {
710 PCL_DEBUG(
"[KdTreeNanoflann::setUpTree] Mapping cloud directly, without "
711 "allocating memory.\n");
713 reinterpret_cast<const float*
>(&(*input_)[0]),
715 sizeof(
PointT) /
sizeof(
float),
716 index_mapping_.size()));
719 float* data =
new float[dim * index_mapping_.size()];
720 float* data_itr = data;
721 for (
auto& index : index_mapping_) {
722 point_representation_->vectorize((*input_)[index], data_itr);
726 data,
true, dim, index_mapping_.size()));
728 nanoflann_tree_.reset(
731#
if NANOFLANN_VERSION >= 0x150
734 nanoflann::KDTreeSingleIndexAdaptorFlags::None,
738 if (n_thread_build_ != 1)
739 PCL_WARN(
"[KdTreeNanoflann::setUpTree] concurrent tree building is only possible "
740 "with nanoflann version 1.5.0 and newer\n");
745 KdTreePtr nanoflann_tree_;
747 shared_ptr<internal::PointCloudAdaptor<float>> adaptor_;
749 PointRepresentationConstPtr point_representation_{
754 bool identity_mapping_{
false};
756 std::size_t leaf_max_size_{15};
758 unsigned int n_thread_build_{1};
762 bool use_rknn_{
true};