Lagrange
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
BVHNanoflann.h
1/*
2 * Copyright 2019 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <memory>
15
16#include <nanoflann.hpp>
17
18#include <lagrange/Logger.h>
19#include <lagrange/bvh/BVH.h>
20#include <lagrange/utils/assert.h>
21#include <lagrange/utils/safe_cast.h>
22
23namespace lagrange {
24namespace bvh {
25
26template <typename _VertexArray, typename _ElementArray = lagrange::Triangles>
27class BVHNanoflann : public BVH<_VertexArray, _ElementArray>
28{
29public:
31 using VertexArray = typename Parent::VertexArray;
32 using ElementArray = typename Parent::ElementArray;
33 using Scalar = typename Parent::Scalar;
34 using Index = typename Parent::Index;
35 using PointType = typename Parent::PointType;
36 using ClosestPoint = typename Parent::ClosestPoint;
37 using KDTree = nanoflann::KDTreeEigenMatrixAdaptor<VertexArray>;
38
39public:
40 BVHType get_bvh_type() const override
41 {
42 return BVHType::NANOFLANN;
43 }
44
45 bool does_support_pointcloud() const override
46 {
47 return true;
48 }
49 bool does_support_triangles() const override
50 {
51 return false;
52 }
53 bool does_support_lines() const override
54 {
55 return false;
56 }
57
58 void build(const VertexArray&, const ElementArray&) override
59 {
60 la_runtime_assert(0, "BVHNannoflann does not support elements.");
61 }
62
63 void build(const VertexArray& vertices) override
64 {
65 // Nanoflann stores a const ref to vertices, we need to make sure
66 // vertices outlives the BVH. Storing a local copy for now.
67 m_vertices = vertices;
68
69 constexpr int max_leaf = 10; // TODO: Experiment with different values.
70 m_tree = std::make_unique<KDTree>(m_vertices.cols(), m_vertices, max_leaf);
71 m_tree->index_->buildIndex();
72 }
73
75 {
76 return true;
77 }
78 ClosestPoint query_closest_point(const PointType& p) const override
79 {
80 la_runtime_assert(m_tree);
81 ClosestPoint r;
82
83 typename KDTree::IndexType out_idx[1];
84 Scalar out_sq_dist[1];
85 auto num_valid_pts = m_tree->index_->knnSearch(p.data(), 1, out_idx, out_sq_dist);
86
87 if (num_valid_pts == 0) {
88 throw std::runtime_error("Nanoflann did not find any valid closest points.");
89 }
90
91 r.closest_vertex_idx = lagrange::safe_cast<Index>(out_idx[0]);
92 r.closest_point = m_vertices.row(out_idx[0]);
93 r.squared_distance = out_sq_dist[0];
94
95 return r;
96 }
97
99 {
100 return true;
101 }
102 std::vector<ClosestPoint> query_k_nearest_neighbours(const PointType& p, int k) const override
103 {
104 la_runtime_assert(m_tree);
105 std::vector<ClosestPoint> rs;
106
107 std::vector<typename KDTree::IndexType> out_idxs(k);
108 std::vector<Scalar> out_sq_dists(k);
109 auto num_valid_pts =
110 m_tree->index_->knnSearch(p.data(), k, out_idxs.data(), out_sq_dists.data());
111
112 rs.resize(num_valid_pts);
113 for (size_t i = 0; i < num_valid_pts; i++) {
114 rs[i].closest_vertex_idx = lagrange::safe_cast<Index>(out_idxs[i]);
115 rs[i].closest_point = m_vertices.row(out_idxs[i]);
116 rs[i].squared_distance = out_sq_dists[i];
117 }
118
119 return rs;
120 }
121
123 {
124 return true;
125 }
126 std::vector<ClosestPoint> query_in_sphere_neighbours(const PointType& p, const Scalar radius)
127 const override
128 {
129 la_runtime_assert(m_tree);
130 std::vector<ClosestPoint> r;
131
132 std::vector<nanoflann::ResultItem<typename KDTree::IndexType, Scalar>> output;
133 nanoflann::SearchParameters params(
134 0, // Epsilon, should be 0.
135 true); // Sort result by distance.
136 m_tree->index_->radiusSearch(p.data(), radius * radius, output, params);
137
138 r.reserve(output.size());
139 for (const auto& entry : output) {
140 ClosestPoint cp;
141 cp.closest_vertex_idx = (Index)entry.first;
142 cp.closest_point = m_vertices.row(cp.closest_vertex_idx);
143 cp.squared_distance = entry.second;
144 r.push_back(std::move(cp));
145 }
146 return r;
147 }
148
149 std::vector<ClosestPoint> batch_query_closest_point(const VertexArray& query_pts) const override
150 {
151 return Parent::default_batch_query_closest_point(query_pts);
152 }
153
154
155private:
156 VertexArray m_vertices;
157 std::unique_ptr<KDTree> m_tree;
158};
159
160} // namespace bvh
161} // namespace lagrange
Definition: BVH.h:27
Definition: BVHNanoflann.h:28
bool does_support_pointcloud() const override
Does it support supplying elements or just points?
Definition: BVHNanoflann.h:45
std::vector< ClosestPoint > batch_query_closest_point(const VertexArray &query_pts) const override
Batch query closest points.
Definition: BVHNanoflann.h:149
bool does_support_query_k_nearest_neighbours() const override
Query for the k nearest neighbours.
Definition: BVHNanoflann.h:98
BVHType get_bvh_type() const override
Get the enum type.
Definition: BVHNanoflann.h:40
bool does_support_query_closest_point() const override
Query for the closest point.
Definition: BVHNanoflann.h:74
bool does_support_query_in_sphere_neighbours() const override
Query for the closest point with in radius.
Definition: BVHNanoflann.h:122
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
Main namespace for Lagrange.
Definition: AABBIGL.h:30