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>
20#include <lagrange/utils/warnoff.h>
21#include <igl/barycenter.h>
22#include <lagrange/utils/warnon.h>
35template <
typename Scalar>
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)
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]));
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)
86 for (
int c = 0; c < DIM; c++) {
87 if (p[c] < B.min()[c]) {
89 result += sqr(p[c] - B.min()[c]);
90 }
else if (p[c] > B.max()[c]) {
92 result += sqr(p[c] - B.max()[c]);
96 result = -inner_point_box_squared_distance(p, B);
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());
124template <
typename VertexArray,
typename EdgeArray,
int DIM>
129 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> centroids;
130 igl::barycenter(V, E, centroids);
134 std::vector<Index> edges(E.rows());
135 std::iota(edges.begin(), edges.end(), 0);
137 std::function<Index(Index, Index, Index)> top_down = [&](Index i, Index j, Index parent) {
140 return invalid<Index>();
147 RowVectorType a = V.row(E(e, 0));
148 RowVectorType b = V.row(E(e, 1));
149 node.bbox = internal::bbox_edge<Scalar, DIM>(a, b);
151 node.
left = node.
right = invalid<Index>();
153 m_nodes.push_back(node);
154 return (Index)(m_nodes.size() - 1);
158 Eigen::AlignedBox<Scalar, DIM> centroid_box;
159 for (Index k = i; k < j; ++k) {
160 Eigen::Matrix<Scalar, DIM, 1> c = centroids.row(edges[k]).transpose();
161 centroid_box.extend(c);
163 auto extent = centroid_box.diagonal();
165 for (
int dim = 1; dim < DIM; ++dim) {
166 if (extent(dim) > extent(longest_dim)) {
170 std::sort(edges.begin() + i, edges.begin() + j, [&](Index f1, Index f2) {
171 return centroids(f1, longest_dim) < centroids(f2, longest_dim);
175 Index current = (Index)m_nodes.size();
176 m_nodes.resize(current + 1);
177 Index midpoint = (i + j) / 2;
178 Index left = top_down(i, midpoint, current);
179 Index right = top_down(midpoint, j, current);
180 Node& node = m_nodes[current];
184 node.
index = invalid<Index>();
185 node.bbox = m_nodes[node.
left].bbox.extend(m_nodes[node.
right].bbox);
190 m_root = top_down(0, (Index)edges.size(), invalid<Index>());
197template <
typename VertexArray,
typename EdgeArray,
int DIM>
199 const RowVectorType& p,
201 RowVectorType& closest_point,
202 Scalar& closest_sq_dist)
const
204 RowVectorType v0 = m_vertices->row((*m_edges)(element_id, 0));
205 RowVectorType v1 = m_vertices->row((*m_edges)(element_id, 1));
216template <
typename VertexArray,
typename EdgeArray,
int DIM>
218 const RowVectorType& p,
220 std::function<
void(Scalar, Index,
const RowVectorType&)> func)
const
222 foreach_element_in_radius_recursive(p, sq_dist, (Index)m_root, func);
225template <
typename VertexArray,
typename EdgeArray,
int DIM>
227 const RowVectorType& p,
230 ActionCallback func)
const
232 const auto& node = m_nodes[node_id];
233 if (node.is_leaf()) {
234 RowVectorType closest_point;
235 Scalar closest_sq_dist;
236 get_element_closest_point(p, node.index, closest_point, closest_sq_dist);
237 if (closest_sq_dist <= sq_dist) {
238 func(closest_sq_dist, node.index, closest_point);
244 internal::point_box_signed_squared_distance<Scalar, DIM>(p, m_nodes[node.left].bbox);
246 internal::point_box_signed_squared_distance<Scalar, DIM>(p, m_nodes[node.right].bbox);
249 foreach_element_in_radius_recursive(p, sq_dist, node.left, func);
252 foreach_element_in_radius_recursive(p, sq_dist, node.right, func);
258template <
typename VertexArray,
typename EdgeArray,
int DIM>
260 const RowVectorType& p,
261 std::function<
void(Scalar, Index,
const RowVectorType&)> func)
const
263 foreach_element_containing_recursive(p, (Index)m_root, func);
266template <
typename VertexArray,
typename EdgeArray,
int DIM>
268 const RowVectorType& p,
270 ActionCallback func)
const
272 const auto& node = m_nodes[node_id];
273 if (node.is_leaf()) {
274 RowVectorType p0 = m_vertices->row((*m_edges)(node.index, 0));
275 RowVectorType p1 = m_vertices->row((*m_edges)(node.index, 1));
277 func(0, node.index, p);
283 internal::point_box_signed_squared_distance<Scalar, DIM>(p, m_nodes[node.left].bbox);
285 internal::point_box_signed_squared_distance<Scalar, DIM>(p, m_nodes[node.right].bbox);
288 foreach_element_containing_recursive(p, node.left, func);
291 foreach_element_containing_recursive(p, node.right, func);
297template <
typename VertexArray,
typename EdgeArray,
int DIM>
299 const RowVectorType& query_pt,
301 RowVectorType& closest_point,
302 Scalar& closest_sq_dist,
303 std::function<
bool(Index)> filter_func)
const
306 element_id = invalid<Index>();
307 closest_sq_dist = std::numeric_limits<Scalar>::max();
308 closest_point.setConstant(invalid<Scalar>());
310 std::function<void(Index)> traverse_aabb_tree;
311 traverse_aabb_tree = [&](Index node_id) {
312 const auto& node = m_nodes[node_id];
313 if (node.is_leaf()) {
314 if (!filter_func || filter_func(node.index)) {
315 RowVectorType _closest_point;
316 Scalar _closest_sq_dist;
317 get_element_closest_point(query_pt, node.index, _closest_point, _closest_sq_dist);
318 if (_closest_sq_dist <= closest_sq_dist) {
319 closest_sq_dist = _closest_sq_dist;
320 element_id = node.index;
321 closest_point = _closest_point;
325 using namespace internal;
327 point_box_signed_squared_distance<Scalar, DIM>(query_pt, m_nodes[node.left].bbox);
329 point_box_signed_squared_distance<Scalar, DIM>(query_pt, m_nodes[node.right].bbox);
333 if (dl <= closest_sq_dist) {
334 traverse_aabb_tree(node.left);
336 if (dr <= closest_sq_dist) {
337 traverse_aabb_tree(node.right);
340 if (dr <= closest_sq_dist) {
341 traverse_aabb_tree(node.right);
343 if (dl <= closest_sq_dist) {
344 traverse_aabb_tree(node.left);
350 traverse_aabb_tree((Index)m_root);
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
Main namespace for Lagrange.
Definition: AABBIGL.h:30
auto point_segment_squared_distance(const Eigen::MatrixBase< PointType > &point, const Eigen::MatrixBase< PointType > &V0, const Eigen::MatrixBase< PointType > &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
Definition: EdgeAABBTree.h:32
Index parent
Index of the parent node (INVALID for root).
Definition: EdgeAABBTree.h:34
Index index
Edge id for the leaf (INVALID for internal nodes).
Definition: EdgeAABBTree.h:37
Index right
Index of the right child (INVALID for a leaf).
Definition: EdgeAABBTree.h:36
Index left
Index of the left child (INVALID for a leaf).
Definition: EdgeAABBTree.h:35
Definition: EdgeAABBTree.h:25
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:198
void foreach_element_containing(const RowVectorType &p, ActionCallback func) const
Iterate over edges that contain exactly a given query point.
Definition: EdgeAABBTree.impl.h:259
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:217
void get_closest_point(const RowVectorType &p, Index &element_id, RowVectorType &closest_point, Scalar &closest_sq_dist, std::function< bool(Index)> filter_func=nullptr) const
Gets the closest point to an element of the tree.
Definition: EdgeAABBTree.impl.h:298