Lagrange
Loading...
Searching...
No Matches
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// clang-format off
17#include <lagrange/utils/warnoff.h>
18#include <nanoflann.hpp>
19#include <lagrange/utils/warnon.h>
20// clang-format on
21
22#include <lagrange/Logger.h>
23#include <lagrange/bvh/BVH.h>
24#include <lagrange/utils/assert.h>
25#include <lagrange/utils/safe_cast.h>
26
27namespace lagrange {
28namespace bvh {
29
30template <typename _VertexArray, typename _ElementArray = lagrange::Triangles>
31class BVHNanoflann : public BVH<_VertexArray, _ElementArray>
32{
33public:
34 using Parent = BVH<_VertexArray, _ElementArray>;
35 using VertexArray = typename Parent::VertexArray;
36 using ElementArray = typename Parent::ElementArray;
37 using Scalar = typename Parent::Scalar;
38 using Index = typename Parent::Index;
39 using PointType = typename Parent::PointType;
40 using ClosestPoint = typename Parent::ClosestPoint;
41 using KDTree = nanoflann::KDTreeEigenMatrixAdaptor<VertexArray>;
42
43public:
44 BVHType get_bvh_type() const override { return BVHType::NANOFLANN; }
45
46 bool does_support_pointcloud() const override { return true; }
47 bool does_support_triangles() const override { return false; }
48 bool does_support_lines() const override { return false; }
49
50 void build(const VertexArray&, const ElementArray&) override
51 {
52 la_runtime_assert(0, "BVHNannoflann does not support elements.");
53 }
54
55 void build(const VertexArray& vertices) override
56 {
57 m_vertices = vertices;
58 build_index();
59 }
60
62 void build(VertexArray&& vertices)
63 {
64 m_vertices = std::move(vertices);
65 build_index();
66 }
67
68 bool does_support_query_closest_point() const override { return true; }
69 ClosestPoint query_closest_point(const PointType& p) const override
70 {
71 la_runtime_assert(m_tree);
72 ClosestPoint r;
73
74 typename KDTree::IndexType out_idx[1];
75 Scalar out_sq_dist[1];
76 auto num_valid_pts = m_tree->index_->knnSearch(p.data(), 1, out_idx, out_sq_dist);
77
78 if (num_valid_pts == 0) {
79 throw std::runtime_error("Nanoflann did not find any valid closest points.");
80 }
81
82 r.closest_vertex_idx = lagrange::safe_cast<Index>(out_idx[0]);
83 r.closest_point = m_vertices.row(out_idx[0]);
84 r.squared_distance = out_sq_dist[0];
85
86 return r;
87 }
88
89 bool does_support_query_k_nearest_neighbours() const override { return true; }
90 std::vector<ClosestPoint> query_k_nearest_neighbours(const PointType& p, int k) const override
91 {
92 la_runtime_assert(m_tree);
93 std::vector<ClosestPoint> rs;
94
95 std::vector<typename KDTree::IndexType> out_idxs(k);
96 std::vector<Scalar> out_sq_dists(k);
97 auto num_valid_pts =
98 m_tree->index_->knnSearch(p.data(), k, out_idxs.data(), out_sq_dists.data());
99
100 rs.resize(num_valid_pts);
101 for (size_t i = 0; i < num_valid_pts; i++) {
102 rs[i].closest_vertex_idx = lagrange::safe_cast<Index>(out_idxs[i]);
103 rs[i].closest_point = m_vertices.row(out_idxs[i]);
104 rs[i].squared_distance = out_sq_dists[i];
105 }
106
107 return rs;
108 }
109
110 bool does_support_query_in_sphere_neighbours() const override { return true; }
111 std::vector<ClosestPoint> query_in_sphere_neighbours(const PointType& p, const Scalar radius)
112 const override
113 {
114 la_runtime_assert(m_tree);
115 std::vector<ClosestPoint> r;
116
117 std::vector<nanoflann::ResultItem<typename KDTree::IndexType, Scalar>> output;
118 nanoflann::SearchParameters params(
119 0, // Epsilon, should be 0.
120 true); // Sort result by distance.
121 m_tree->index_->radiusSearch(p.data(), radius * radius, output, params);
122
123 r.reserve(output.size());
124 for (const auto& entry : output) {
125 ClosestPoint cp;
126 cp.closest_vertex_idx = (Index)entry.first;
127 cp.closest_point = m_vertices.row(cp.closest_vertex_idx);
128 cp.squared_distance = entry.second;
129 r.push_back(std::move(cp));
130 }
131 return r;
132 }
133
134 std::vector<ClosestPoint> batch_query_closest_point(const VertexArray& query_pts) const override
135 {
136 return Parent::default_batch_query_closest_point(query_pts);
137 }
138
139
140private:
141 void build_index()
142 {
143 constexpr int max_leaf = 10;
144 m_tree = std::make_unique<KDTree>(m_vertices.cols(), m_vertices, max_leaf);
145 m_tree->index_->buildIndex();
146 }
147
148 VertexArray m_vertices;
149 std::unique_ptr<KDTree> m_tree;
150};
151
152} // namespace bvh
153} // namespace lagrange
Definition BVHNanoflann.h:32
bool does_support_pointcloud() const override
Does it support supplying elements or just points?
Definition BVHNanoflann.h:46
std::vector< ClosestPoint > batch_query_closest_point(const VertexArray &query_pts) const override
Batch query closest points.
Definition BVHNanoflann.h:134
bool does_support_query_k_nearest_neighbours() const override
Query for the k nearest neighbours.
Definition BVHNanoflann.h:89
BVHType get_bvh_type() const override
Get the enum type.
Definition BVHNanoflann.h:44
bool does_support_query_closest_point() const override
Query for the closest point.
Definition BVHNanoflann.h:68
void build(VertexArray &&vertices)
Overload that moves vertices in to avoid an extra copy.
Definition BVHNanoflann.h:62
bool does_support_query_in_sphere_neighbours() const override
Query for the closest point with in radius.
Definition BVHNanoflann.h:110
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:175
constexpr auto safe_cast(SourceType value) -> std::enable_if_t<!std::is_same< SourceType, TargetType >::value, TargetType >
Perform safe cast from SourceType to TargetType, where "safe" means:
Definition safe_cast.h:51
Main namespace for Lagrange.