Lagrange
Loading...
Searching...
No Matches
EdgeAABBTree.impl.h
1/*
2 * Copyright 2020 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 <lagrange/bvh/EdgeAABBTree.h>
15#include <lagrange/utils/assert.h>
16#include <lagrange/utils/point_on_segment.h>
17#include <lagrange/utils/point_segment_squared_distance.h>
18
19// clang-format off
20#include <lagrange/utils/warnoff.h>
21#include <igl/barycenter.h>
22#include <lagrange/utils/warnon.h>
23// clang-format on
24
25#include <limits>
26#include <numeric>
27
28namespace lagrange {
29namespace bvh {
30
32
33namespace internal {
34
35template <typename Scalar>
36Scalar sqr(Scalar x)
37{
38 return x * x;
39}
40
53template <typename Scalar, int Dim>
54Scalar inner_point_box_squared_distance(
55 const Eigen::Matrix<Scalar, Dim, 1>& p,
56 const Eigen::AlignedBox<Scalar, Dim>& B)
57{
58 assert(B.contains(p));
59 Scalar result = sqr(p[0] - B.min()[0]);
60 result = std::min(result, sqr(p[0] - B.max()[0]));
61 for (int c = 1; c < Dim; ++c) {
62 result = std::min(result, sqr(p[c] - B.min()[c]));
63 result = std::min(result, sqr(p[c] - B.max()[c]));
64 }
65 return result;
66}
67
72/// @param[in] p The point.
73/// @param[in] B The box.
74///
75/// @tparam Scalar Scalar type.
76///
77/// @return The signed squared distance between @p p and @p B.
78///
79template <typename Scalar, int Dim>
80Scalar point_box_signed_squared_distance(
81 const Eigen::Matrix<Scalar, Dim, 1>& p,
82 const Eigen::AlignedBox<Scalar, Dim>& B)
83{
84 bool inside = true;
85 Scalar result = 0;
86 for (int c = 0; c < Dim; c++) {
87 if (p[c] < B.min()[c]) {
88 inside = false;
89 result += sqr(p[c] - B.min()[c]);
90 } else if (p[c] > B.max()[c]) {
91 inside = false;
92 result += sqr(p[c] - B.max()[c]);
93 }
94 }
95 if (inside) {
96 result = -inner_point_box_squared_distance(p, B);
97 }
98 return result;
99}
100
109template <typename Scalar, int Dim>
110Eigen::AlignedBox<Scalar, Dim> bbox_edge(
111 const Eigen::Matrix<Scalar, 1, Dim>& a,
112 const Eigen::Matrix<Scalar, 1, Dim>& b)
114 Eigen::AlignedBox<Scalar, Dim> bbox;
115 bbox.extend(a.transpose());
116 bbox.extend(b.transpose());
117 return bbox;
118}
119
120} // namespace internal
121
123
124template <typename VertexArray, typename EdgeArray, int Dim>
125EdgeAABBTree<VertexArray, EdgeArray, Dim>::EdgeAABBTree(const VertexArray& V, const EdgeArray& E)
126{
127 la_runtime_assert(Dim == V.cols(), "Dimension mismatch in EdgeAABBTree!");
128
129 m_vertices = &V;
130 m_edges = &E;
131
132 // Compute bounding boxes for all edges
133 std::vector<typename AABB<Scalar, Dim>::Box> aabb_boxes(E.rows());
134
135 for (Index i = 0; i < static_cast<Index>(E.rows()); ++i) {
136 RowVectorType a = V.row(E(i, 0));
137 RowVectorType b = V.row(E(i, 1));
138 auto& bbox = aabb_boxes[i];
139 bbox.setEmpty();
140 bbox.extend(a.transpose());
141 bbox.extend(b.transpose());
142 }
143
144 // Build the AABB tree
145 m_aabb.build(span<typename AABB<Scalar, Dim>::Box>(aabb_boxes.data(), aabb_boxes.size()));
146}
147
148// -----------------------------------------------------------------------------
149
150template <typename VertexArray, typename EdgeArray, int Dim>
152 const RowVectorType& p,
153 Index element_id,
154 RowVectorType& closest_point,
155 Scalar& closest_sq_dist) const
156{
157 RowVectorType v0 = m_vertices->row((*m_edges)(element_id, 0));
158 RowVectorType v1 = m_vertices->row((*m_edges)(element_id, 1));
159 Scalar l0, l1;
160 closest_sq_dist = point_segment_squared_distance(p, v0, v1, closest_point, l0, l1);
161 if (point_on_segment(p, v0, v1)) {
162 closest_sq_dist = 0;
163 closest_point = p;
164 }
165}
166
167// -----------------------------------------------------------------------------
168
169template <typename VertexArray, typename EdgeArray, int Dim>
171 const RowVectorType& p,
172 Scalar sq_dist,
173 function_ref<void(Scalar, Index, const RowVectorType&)> func) const
174{
175 m_aabb.foreach_element_within_radius(p, sq_dist, [&](Index edge_idx) {
176 RowVectorType closest_point;
177 Scalar closest_sq_dist;
178 get_element_closest_point(p, edge_idx, closest_point, closest_sq_dist);
179 if (closest_sq_dist <= sq_dist) {
180 func(closest_sq_dist, edge_idx, closest_point);
181 }
182 });
183}
184
185// -----------------------------------------------------------------------------
186
187template <typename VertexArray, typename EdgeArray, int Dim>
189 const RowVectorType& p,
190 function_ref<void(Scalar, Index, const RowVectorType&)> func) const
191{
192 // Create a point query box
193 typename AABB<Scalar, Dim>::Box query_box;
194 typename AABB<Scalar, Dim>::Box::VectorType point_vec = p.transpose();
195 query_box.min() = point_vec;
196 query_box.max() = point_vec;
197
198 // Check each intersecting edge for exact containment
199 m_aabb.intersect(query_box, [&](Index aabb_idx) {
200 Index edge_idx = static_cast<Index>(aabb_idx);
201 RowVectorType p0 = m_vertices->row((*m_edges)(edge_idx, 0));
202 RowVectorType p1 = m_vertices->row((*m_edges)(edge_idx, 1));
203 if (point_on_segment(p, p0, p1)) {
204 func(0, edge_idx, p);
205 }
206 return true;
207 });
208}
209
210// -----------------------------------------------------------------------------
211
212template <typename VertexArray, typename EdgeArray, int Dim>
214 const RowVectorType& query_pt,
215 Index& element_id,
216 RowVectorType& closest_point,
217 Scalar& closest_sq_dist,
218 function_ref<bool(Index)> filter_func) const
219{
221 element_id = invalid<Index>();
222 closest_sq_dist = std::numeric_limits<Scalar>::max();
223 closest_point.setConstant(invalid<Scalar>());
224
225 auto get_closest_point = [&](Index edge_id) {
226 la_debug_assert(edge_id != invalid<Index>());
227 if (!filter_func || filter_func(edge_id)) {
228 get_element_closest_point(query_pt, edge_id, closest_point, closest_sq_dist);
229 return closest_sq_dist;
230 } else {
231 return std::numeric_limits<Scalar>::max();
232 }
233 };
234 element_id = m_aabb.get_closest_element(query_pt.transpose(), get_closest_point);
235 get_closest_point(element_id);
236}
237
238} // namespace bvh
239} // namespace lagrange
Axis-Aligned Bounding Box (AABB) tree for efficient spatial queries.
Definition AABB.h:39
void intersect(const Box &query_box, std::vector< Index > &results) const
Find all boxes that intersect with a query box.
Definition AABB.cpp:127
A lightweight non-owning reference to a callable.
Definition function_ref.h:47
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
#define la_debug_assert(...)
Debug assertion check.
Definition assert.h:194
::nonstd::span< T, Extent > span
A bounds-safe view for sequences of objects.
Definition span.h:27
constexpr T invalid()
You can use invalid<T>() to get a value that can represent "invalid" values, such as invalid indices ...
Definition invalid.h:40
void get_element_closest_point(const RowVectorType &p, Index element_id, RowVectorType &closest_point, Scalar &closest_sq_dist) const
Gets the closest point to a given element.
Definition EdgeAABBTree.impl.h:151
void get_closest_point(const RowVectorType &p, Index &element_id, RowVectorType &closest_point, Scalar &closest_sq_dist, function_ref< bool(Index)> filter_func=[](Index) { return true;}) const
Gets the closest point to an element of the tree.
Definition EdgeAABBTree.impl.h:213
bool empty() const
Test whether the tree is empty.
Definition EdgeAABBTree.h:62
void foreach_element_containing(const RowVectorType &p, ActionCallback func) const
Iterate over edges that contain exactly a given query point.
Definition EdgeAABBTree.impl.h:188
void foreach_element_in_radius(const RowVectorType &p, Scalar sq_dist, ActionCallback func) const
Iterate over edges within a prescribed distance from a query point.
Definition EdgeAABBTree.impl.h:170
Main namespace for Lagrange.
auto point_segment_squared_distance(const Eigen::MatrixBase< PointType > &point, const Eigen::MatrixBase< PointType2 > &V0, const Eigen::MatrixBase< PointType2 > &V1, Eigen::PlainObjectBase< PointType > &closest_point, ScalarOf< PointType > &lambda0, ScalarOf< PointType > &lambda1) -> ScalarOf< PointType >
Computes the point closest to a given point in a nd segment.
Definition point_segment_squared_distance.h:73
bool point_on_segment(const Eigen::MatrixBase< PointType > &p, const Eigen::MatrixBase< PointType > &a, const Eigen::MatrixBase< PointType > &b)
Test if a point lies exactly on a segment [a,b] using exact predicates.
Definition point_on_segment.h:43