ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
NearestNeighborSearch.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <Logging.h>
11 
12 namespace cloudViewer {
13 namespace core {
14 namespace nns {
15 
17 
18 bool NearestNeighborSearch::SetIndex() {
19  nanoflann_index_.reset(new NanoFlannIndex());
20  return nanoflann_index_->SetTensorData(dataset_points_, index_dtype_);
21 };
22 
24  if (dataset_points_.IsCUDA()) {
25 #ifdef BUILD_CUDA_MODULE
26  knn_index_.reset(new nns::KnnIndex());
27  return knn_index_->SetTensorData(dataset_points_, index_dtype_);
28 #else
30  "-DBUILD_CUDA_MODULE=OFF. Please recompile CloudViewer with "
31  "-DBUILD_CUDA_MODULE=ON.");
32 #endif
33  } else {
34  return SetIndex();
35  }
36 };
37 
38 bool NearestNeighborSearch::MultiRadiusIndex() { return SetIndex(); };
39 
41  if (dataset_points_.IsCUDA()) {
42  if (!radius.has_value())
43  utility::LogError("radius is required for GPU FixedRadiusIndex.");
44 #ifdef BUILD_CUDA_MODULE
46  return fixed_radius_index_->SetTensorData(dataset_points_,
47  radius.value(), index_dtype_);
48 #else
50  "FixedRadiusIndex with GPU tensor is disabled since "
51  "-DBUILD_CUDA_MODULE=OFF. Please recompile CloudViewer with "
52  "-DBUILD_CUDA_MODULE=ON.");
53 #endif
54 
55  } else {
56  return SetIndex();
57  }
58 }
59 
61  if (dataset_points_.IsCUDA()) {
62  if (!radius.has_value())
63  utility::LogError("radius is required for GPU HybridIndex.");
64 #ifdef BUILD_CUDA_MODULE
66  return fixed_radius_index_->SetTensorData(dataset_points_,
67  radius.value(), index_dtype_);
68 #else
70  "-DBUILD_CUDA_MODULE=OFF. Please recompile CloudViewer with "
71  "-DBUILD_CUDA_MODULE=ON.");
72 #endif
73 
74  } else {
75  return SetIndex();
76  }
77 };
78 
79 std::pair<Tensor, Tensor> NearestNeighborSearch::KnnSearch(
80  const Tensor& query_points, int knn) {
82 
83  if (dataset_points_.IsCUDA()) {
84  if (knn_index_) {
85  return knn_index_->SearchKnn(query_points, knn);
86  } else {
87  utility::LogError("Index is not set.");
88  }
89  } else {
90  if (nanoflann_index_) {
91  return nanoflann_index_->SearchKnn(query_points, knn);
92  } else {
93  utility::LogError("Index is not set.");
94  }
95  }
96 }
97 
98 std::tuple<Tensor, Tensor, Tensor> NearestNeighborSearch::FixedRadiusSearch(
99  const Tensor& query_points, double radius, bool sort) {
101 
102  if (dataset_points_.IsCUDA()) {
103  if (fixed_radius_index_) {
104  return fixed_radius_index_->SearchRadius(query_points, radius,
105  sort);
106  } else {
107  utility::LogError("Index is not set.");
108  }
109  } else {
110  if (nanoflann_index_) {
111  return nanoflann_index_->SearchRadius(query_points, radius);
112  } else {
113  utility::LogError("Index is not set.");
114  }
115  }
116 }
117 
118 std::tuple<Tensor, Tensor, Tensor> NearestNeighborSearch::MultiRadiusSearch(
119  const Tensor& query_points, const Tensor& radii) {
120  AssertNotCUDA(query_points);
121  AssertTensorDtype(query_points, dataset_points_.GetDtype());
123 
124  if (!nanoflann_index_) {
125  utility::LogError("Index is not set.");
126  }
127  return nanoflann_index_->SearchRadius(query_points, radii);
128 }
129 
130 std::tuple<Tensor, Tensor, Tensor> NearestNeighborSearch::HybridSearch(
131  const Tensor& query_points,
132  const double radius,
133  const int max_knn) const {
135 
136  if (dataset_points_.IsCUDA()) {
137  if (fixed_radius_index_) {
138  return fixed_radius_index_->SearchHybrid(query_points, radius,
139  max_knn);
140  } else {
141  utility::LogError("Index is not set.");
142  }
143  } else {
144  if (nanoflann_index_) {
145  return nanoflann_index_->SearchHybrid(query_points, radius,
146  max_knn);
147  } else {
148  utility::LogError("Index is not set.");
149  }
150  }
151 }
152 
153 void NearestNeighborSearch::AssertNotCUDA(const Tensor& t) const {
154  if (t.IsCUDA()) {
156  "TODO: NearestNeighborSearch does not support CUDA tensor "
157  "yet.");
158  }
159 }
160 
161 } // namespace nns
162 } // namespace core
163 } // namespace cloudViewer
#define AssertTensorDevice(tensor,...)
Definition: TensorCheck.h:45
#define AssertTensorDtype(tensor,...)
Definition: TensorCheck.h:21
bool IsCUDA() const
Definition: Device.h:99
Dtype GetDtype() const
Definition: Tensor.h:1164
Device GetDevice() const override
Definition: Tensor.cpp:1435
FixedRadiusIndex for nearest neighbor range search.
std::tuple< Tensor, Tensor, Tensor > FixedRadiusSearch(const Tensor &query_points, double radius, bool sort=true)
bool HybridIndex(utility::optional< double > radius={})
std::unique_ptr< nns::FixedRadiusIndex > fixed_radius_index_
bool FixedRadiusIndex(utility::optional< double > radius={})
std::tuple< Tensor, Tensor, Tensor > HybridSearch(const Tensor &query_points, const double radius, const int max_knn) const
std::unique_ptr< NanoFlannIndex > nanoflann_index_
std::tuple< Tensor, Tensor, Tensor > MultiRadiusSearch(const Tensor &query_points, const Tensor &radii)
std::pair< Tensor, Tensor > KnnSearch(const Tensor &query_points, int knn)
constexpr bool has_value() const noexcept
Definition: Optional.h:440
constexpr T const & value() const &
Definition: Optional.h:465
#define LogError(...)
Definition: Logging.h:60
Generic file read and write utility for python interface.
std::vector< PointCoordinateType > radii
Definition: qM3C2Tools.cpp:42