5#ifndef NURI_CORE_GEOMETRY_H_
6#define NURI_CORE_GEOMETRY_H_
15#include <absl/log/absl_check.h>
24 using Array8i = Array<int, 8, 1>;
28 OCTreeNode(Array8i &&children,
int begin,
int nleaf)
29 : children_(std::move(children)), begin_(begin), nleaf_(nleaf) { }
31 const Array8i &children()
const {
return children_; }
33 int child(
int i)
const {
return children_[i]; }
35 int operator[](
int i)
const {
return child(i); }
37 bool leaf()
const {
return nleaf_ <= 8; }
39 int begin()
const {
return begin_; }
40 int end()
const {
return begin_ + nleaf_; }
42 int nleaf()
const {
return nleaf_; }
85 std::vector<double> &distsq,
double cutoff = -1)
const;
88 std::vector<int> &
idxs,
89 std::vector<double> &distsq)
const;
92 std::vector<int> &self,
93 std::vector<int> &other)
const;
99 std::vector<int> &right)
const;
101 const Matrix3Xd &
pts()
const {
return pts_; }
103 const Vector3d &
max()
const {
return max_; }
105 const Vector3d &
len()
const {
return len_; }
120 const std::vector<internal::OCTreeNode> &
nodes()
const {
return nodes_; }
122 int size()
const {
return static_cast<int>(nodes_.size()); }
128 const ArrayXi &
idxs()
const {
return idxs_; }
130 const internal::OCTreeNode &
node(
int i)
const {
return nodes_[i]; }
132 const internal::OCTreeNode &
operator[](
int idx)
const {
return nodes_[idx]; }
135 void rebuild_impl(
Points src);
140 std::vector<internal::OCTreeNode> nodes_;
143 int bucket_size_ = 32;
190 std::vector<double> &distsq)
const;
201 std::vector<int> &other)
const;
210 std::vector<std::vector<int>>
224 std::vector<int> &right)
const;
233 const Matrix3Xd &
pts()
const {
return pts_; }
235 double cutoff()
const {
return cutoff_; }
237 const Vector3d &
origin()
const {
return origin_; }
239 const Array3i &
dims()
const {
return dims_; }
241 int num_cells()
const {
return static_cast<int>(cell_offset_.size()) - 1; }
245 const ArrayXi &
cell_pts()
const {
return cell_pts_; }
248 void rebuild_impl(
Points src);
253 ArrayXi cell_offset_;
261 3.1415926535897932384626433832795028841971693993751058209749445923078164;
264 6.2831853071795864769252867665590057683943387987502116419498891846156328;
268 0.9659258262890682867497431997288973676339048390084045504023430763;
270 0.8660254037844386467637231707529361834714026269051903140279034897;
272 0.8090169943749474241022934171828190588601545899028814310677243114;
274 0.7071067811865475244008443621048490392848359376884740365883398690;
276 0.5877852522924731291687059546390727685976524376431459910722724808;
279 0.2588190451025207623488988376240483283490689013199305138140032073;
281 -0.173648177666930348851716626769314796000375677184069387236241378;
283 -0.207911690817759337101742284405125166216584760627723836407181973;
285 -0.374606593415912035414963774501195131000158922253676174103440371;
287 -0.422618261740699436186978489647730181563129301194864623444415159;
289 -0.573576436351046096108031912826157864620433371450986351081027118;
291 -0.906307787036649963242552656754316983267712625175864680871298408;
293 -0.996194698091745532295010402473888046183562672645850974525442277;
295 0.0874886635259240052220186694349614581194542763681082291452366622;
297 0.1316524975873958534715264574097171035928141022232375735535653257;
299 1.6003345290410503553267330811833575255040718469227591484115002297;
301 4.5107085036620571342899391172547519686713241944553043587162345185;
305template <
class DT, std::enable_if_t<std::is_
floating_po
int_v<DT>,
int> = 0>
310template <
class DT, std::enable_if_t<std::is_
integral_v<DT>,
int> = 0>
315template <
class DT, std::enable_if_t<std::is_
floating_po
int_v<DT>,
int> = 0>
320template <
class DT, std::enable_if_t<std::is_
integral_v<DT>,
int> = 0>
327template <
class MatrixLike,
class ArrayLike>
328void pdistsq(ArrayLike &&distsq,
const MatrixLike &m) {
329 using DT =
typename MatrixLike::Scalar;
330 constexpr Eigen::Index rows = MatrixLike::RowsAtCompileTime;
332 const Eigen::Index n = m.cols();
333 ABSL_DCHECK(distsq.size() == n * (n - 1) / 2);
335 Vector<DT, rows> v(m.rows());
336 for (Eigen::Index i = 1, k = 0; i < n; ++i) {
338 for (Eigen::Index j = 0; j < i; ++j, ++k) {
339 distsq[k] = (v - m.col(j)).squaredNorm();
344template <
class MatrixLike>
346 using DT =
typename MatrixLike::Scalar;
348 const Eigen::Index n = m.cols();
349 ArrayX<DT> distsq(n * (n - 1) / 2);
354template <
class MatrixLike,
class ArrayLike>
355void pdist(ArrayLike &&dist,
const MatrixLike &m) {
360template <
class MatrixLike>
367template <
class AL,
class DAL>
369 ABSL_DCHECK(dists.rows() == n);
370 ABSL_DCHECK(dists.cols() == n);
372 dists.diagonal().setZero();
373 for (Eigen::Index i = 1, k = 0; i < n; ++i)
374 for (Eigen::Index j = 0; j < i; ++j, ++k)
375 dists(i, j) = dists(j, i) = pdists[k];
378template <
class ArrayLike>
380 using DT =
typename ArrayLike::Scalar;
382 MatrixX<DT> dists(n, n);
388 class ML1,
class ML2,
class DML,
389 std::enable_if_t<internal::extract_if_enum_v(ML1::RowsAtCompileTime)
390 == internal::extract_if_enum_v(ML2::RowsAtCompileTime),
392void cdistsq(DML &&distsq,
const ML1 &a,
const ML2 &b) {
393 ABSL_DCHECK(distsq.rows() == a.cols());
394 ABSL_DCHECK(distsq.cols() == b.cols());
396 for (Eigen::Index j = 0; j < b.cols(); ++j)
397 distsq.col(j) = (a.colwise() - b.col(j)).colwise().squaredNorm();
400template <
class ML1,
class ML2>
402 using DT =
typename ML1::Scalar;
404 MatrixX<DT> distsq(a.cols(), b.cols());
409template <
class ML1,
class ML2,
class DML>
410void cdist(DML &&dist,
const ML1 &a,
const ML2 &b) {
412 dist = dist.cwiseSqrt();
415template <
class ML1,
class ML2>
416auto cdist(
const ML1 &a,
const ML2 &b) {
418 ret = ret.cwiseSqrt();
422template <
class ML1,
class ML2>
423auto msd(
const ML1 &a,
const ML2 &b) {
424 return (a - b).colwise().squaredNorm().mean();
428 constexpr double safe_normalizer(
double sqn,
double eps = 1e-12) {
429 return sqn > eps ? 1 / std::sqrt(sqn) : 0;
432 template <
class VectorLike>
433 inline void safe_normalize(VectorLike &&m,
double eps = 1e-12) {
434 m.array() *= safe_normalizer(m.squaredNorm(), eps);
437 template <
class VectorLike>
438 inline auto safe_normalized(VectorLike &&m,
double eps = 1e-12) {
439 using T = remove_cvref_t<VectorLike>;
440 using Scalar =
typename T::Scalar;
441 constexpr auto size = T::SizeAtCompileTime;
442 constexpr auto max_size = T::MaxSizeAtCompileTime;
444 Matrix<Scalar, size, 1, 0, max_size, 1> ret = std::forward<VectorLike>(m);
445 safe_normalize(ret, eps);
449 template <
class MatrixLike>
450 inline void safe_colwise_normalize(MatrixLike &&m,
double eps = 1e-12) {
451 using ArrayLike =
decltype(m.colwise().squaredNorm().array());
452 constexpr auto max_cols = ArrayLike::MaxColsAtCompileTime;
454 if constexpr (max_cols != Eigen::Dynamic) {
455 using T = remove_cvref_t<MatrixLike>;
456 using Scalar =
typename T::Scalar;
458 constexpr auto cols = ArrayLike::ColsAtCompileTime;
460 Array<Scalar, 1, cols, Eigen::RowMajor, 1, max_cols> norm =
461 m.colwise().squaredNorm().array();
462 m.array().rowwise() *= (norm > eps).select(norm.sqrt().inverse(), 0);
464 for (Eigen::Index i = 0; i < m.cols(); ++i)
465 safe_normalize(m.col(i), eps);
469 template <
class MatrixLike>
470 inline auto safe_colwise_normalized(MatrixLike &&m,
double eps = 1e-12) {
471 using T = remove_cvref_t<MatrixLike>;
472 using Scalar =
typename T::Scalar;
473 constexpr auto rows = T::RowsAtCompileTime, cols = T::ColsAtCompileTime;
474 constexpr auto max_rows = T::MaxRowsAtCompileTime,
475 max_cols = T::MaxColsAtCompileTime;
477 Matrix<Scalar, rows, cols, 0, max_rows, max_cols> ret =
478 std::forward<MatrixLike>(m);
479 safe_colwise_normalize(ret, eps);
492inline double cos_angle(
const Vector3d &oa,
const Vector3d &ob) {
494 * internal::safe_normalizer(oa.squaredNorm() * ob.squaredNorm());
504inline double cos_angle(
const Vector3d &o,
const Vector3d &a,
506 Vector3d oa = a - o, ob = b - o;
525template <
class Scalar,
class Indexer,
int N,
auto... Extra>
526inline std::pair<Scalar, Scalar>
527sum_tan2_half(
const Matrix<Scalar, 3, N, 0, Extra...> &m,
const Indexer &idxs) {
528 double csum = (m + m(Eigen::all, idxs)).colwise().norm().sum(),
529 ssum = (m - m(Eigen::all, idxs)).colwise().norm().sum();
530 return std::make_pair(ssum, csum);
545template <
class Scalar,
int N,
auto... Extra>
546inline std::pair<Scalar, Scalar>
548 if constexpr (N == Eigen::Dynamic) {
567inline double cos_dihedral(
const Vector3d &axis, Vector3d v, Vector3d w) {
568 v -= v.dot(axis) * axis;
569 w -= w.dot(axis) * axis;
571 * internal::safe_normalizer(v.squaredNorm() * w.squaredNorm());
585 const Vector3d &c,
const Vector3d &d) {
586 Vector3d axis = internal::safe_normalized(c - b);
600template <
class MatrixLike>
601Vector4d
fit_plane(
const MatrixLike &pts,
bool normalize =
true) {
602 Vector3d cntr = pts.rowwise().mean();
603 MatrixXd m = pts.colwise() - cntr;
604 auto svd = m.jacobiSvd(Eigen::ComputeThinU);
607 ret.head<3>() = svd.matrixU().col(2);
609 internal::safe_normalize(ret.head<3>());
610 ret[3] = -ret.head<3>().dot(cntr);
626template <
class VectorLike>
628 Vector3d w = { std::copysign(v[2], v[0]),
629 std::copysign(v[2], v[1]),
630 -std::copysign(v[0], v[2]) - std::copysign(v[1], v[2]) };
632 internal::safe_normalize(w);
701extern std::pair<Isometry3d, double>
kabsch(ConstRef<Matrix3Xd> query,
702 ConstRef<Matrix3Xd> templ,
704 bool reflection =
false);
775extern std::pair<Isometry3d, double>
776qcp(
const Eigen::Ref<const Matrix3Xd> &query,
778 bool reflection =
false,
double evalprec = 1e-11,
double evecprec = 1e-6,
852extern std::pair<Isometry3d, double>
855 double evalprec = 1e-11,
double evecprec = 1e-6,
int maxiter = 50);
Cyclic indexer for Eigen types with a given offset.
Definition eigen_config.h:134
int size() const
Definition geometry.h:122
std::vector< std::vector< int > > find_neighbors_tree(const OCTree &oct, double cutoff) const
const ArrayXi & idxs() const
Definition geometry.h:128
OCTree(Points pts, int bucket_size=32)
Definition geometry.h:73
const Vector3d & max() const
Definition geometry.h:103
int bucket_size() const
Definition geometry.h:126
const std::vector< internal::OCTreeNode > & nodes() const
Definition geometry.h:120
const Matrix3Xd & pts() const
Definition geometry.h:101
void find_neighbors_d(const Vector3d &pt, double cutoff, std::vector< int > &idxs, std::vector< double > &distsq) const
void find_neighbors_tree(const OCTree &oct, double cutoff, std::vector< int > &self, std::vector< int > &other) const
void find_neighbors_self(double cutoff, std::vector< int > &left, std::vector< int > &right) const
const internal::OCTreeNode & node(int i) const
Definition geometry.h:130
ConstRef< Matrix3Xd > Points
Definition geometry.h:69
int root() const
Definition geometry.h:124
void find_neighbors_kd(const Vector3d &pt, int k, std::vector< int > &idxs, std::vector< double > &distsq, double cutoff=-1) const
void notify_transform(const Vector3d &new_max, const Vector3d &new_len)
Notify the octree that the point set has been transformed by scaling and/or translation.
const Vector3d & len() const
Definition geometry.h:105
void rebuild(Points pts, int bucket_size=-1)
Definition geometry.h:77
const internal::OCTreeNode & operator[](int idx) const
Definition geometry.h:132
int num_cells() const
Definition geometry.h:241
void find_neighbors_d(const Vector3d &pt, std::vector< int > &idxs, std::vector< double > &distsq) const
Find indices of all points within the build-time cutoff of a query point.
void find_neighbors_grid(const VoxelGrid &grid, std::vector< int > &self, std::vector< int > &other) const
Find all pairs (i, j) where i is in *this and j is in grid and the distance between the points is wit...
double cutoff() const
Definition geometry.h:235
const Matrix3Xd & pts() const
The grid-owned, cell-reordered copy of the input coordinates.
Definition geometry.h:233
VoxelGrid(Points pts, double cutoff)
Definition geometry.h:171
const Vector3d & origin() const
Definition geometry.h:237
std::vector< std::vector< int > > find_neighbors_grid(const VoxelGrid &grid) const
Convenience overload returning a per-self adjacency list.
const Array3i & dims() const
Definition geometry.h:239
void rebuild(Points pts, double cutoff=-1.0)
Definition geometry.h:175
const ArrayXi & cell_offset() const
Definition geometry.h:243
const ArrayXi & cell_pts() const
Definition geometry.h:245
ConstRef< Matrix3Xd > Points
Definition geometry.h:167
void find_neighbors_self(std::vector< int > &left, std::vector< int > &right) const
Find all non-redundant pairs of neighbors within the build-time cutoff.
Definition geometry.h:259
constexpr double kCos125
Definition geometry.h:288
constexpr double kCos115
Definition geometry.h:286
constexpr double kCos102
Definition geometry.h:282
constexpr double kCos54
Definition geometry.h:275
constexpr double kTan10_2
Definition geometry.h:294
constexpr double kTan116_2
Definition geometry.h:298
constexpr double kTwoPi
Definition geometry.h:263
constexpr double kCos100
Definition geometry.h:280
constexpr double kCos36
Definition geometry.h:271
constexpr double kCos45
Definition geometry.h:273
constexpr double kCos30
Definition geometry.h:269
constexpr double kCos75
Definition geometry.h:278
constexpr double kCos112
Definition geometry.h:284
constexpr double kCos15
Definition geometry.h:267
constexpr double kCos155
Definition geometry.h:290
constexpr double kPi
Definition geometry.h:260
constexpr double kTan15_2
Definition geometry.h:296
constexpr double kTan155_2
Definition geometry.h:300
constexpr double kCos60
Definition geometry.h:277
constexpr double kCos175
Definition geometry.h:292
std::pair< Isometry3d, double > kabsch(ConstRef< Matrix3Xd > query, ConstRef< Matrix3Xd > templ, AlignMode mode=AlignMode::kBoth, bool reflection=false)
An implementation of the Kabsch algorithm for aligning two sets of points. This algorithm is based on...
constexpr DT rad2deg(DT rad)
Definition geometry.h:316
std::pair< Isometry3d, double > qcp(const Eigen::Ref< const Matrix3Xd > &query, const Eigen::Ref< const Matrix3Xd > &templ, AlignMode mode=AlignMode::kBoth, bool reflection=false, double evalprec=1e-11, double evecprec=1e-6, int maxiter=50)
Perform quaternion-based superposition of two sets of points.
Matrix3Xd canonical_fibonacci_lattice(int npts)
Generate points on a unit sphere using the "canonical" Fibonacci lattice method.
bool embed_distances_3d(Eigen::Ref< Matrix3Xd > pts, MatrixXd &dsqs)
A routine for converting squared pairwise distances to cartesian coordinates.
auto msd(const ML1 &a, const ML2 &b)
Definition geometry.h:423
double cos_dihedral(const Vector3d &axis, Vector3d v, Vector3d w)
Calculate A - (v) - B - (axis) - C - (w) - D dihedral angle along the axis. Axis should be normalized...
Definition geometry.h:567
constexpr DT deg2rad(DT deg)
Definition geometry.h:306
void pdist(ArrayLike &&dist, const MatrixLike &m)
Definition geometry.h:355
AlignMode
Definition geometry.h:636
@ kXformOnly
Definition geometry.h:638
@ kBoth
Definition geometry.h:639
@ kMsdOnly
Definition geometry.h:637
void cdist(DML &&dist, const ML1 &a, const ML2 &b)
Definition geometry.h:410
Vector4d fit_plane(const MatrixLike &pts, bool normalize=true)
Perform a least-squares fit of a plane to a set of points.
Definition geometry.h:601
void to_square_form(DAL &&dists, const AL &pdists, Eigen::Index n)
Definition geometry.h:368
void pdistsq(ArrayLike &&distsq, const MatrixLike &m)
Definition geometry.h:328
double cos_angle(const Vector3d &oa, const Vector3d &ob)
Calculate the cosine of the angle between two vectors.
Definition geometry.h:492
Vector3d any_perpendicular(const VectorLike &v, bool normalize=true)
Find a vector perpendicular to the given vector.
Definition geometry.h:627
bool embed_distances_4d(Eigen::Ref< Matrix4Xd > pts, MatrixXd &dsqs)
A routine for converting squared pairwise distances to cartesian coordinates.
void cdistsq(DML &&distsq, const ML1 &a, const ML2 &b)
Definition geometry.h:392
std::pair< Scalar, Scalar > sum_tan2_half(const Matrix< Scalar, 3, N, 0, Extra... > &m, const Indexer &idxs)
Calculate sin and cos of half an average angle between vectors, (0 - idxs[0]), (1 - idxs[1]),...
Definition geometry.h:527
std::pair< Isometry3d, double > qcp_inplace(MutRef< Matrix3Xd > query, MutRef< Matrix3Xd > templ, AlignMode mode=AlignMode::kBoth, bool reflection=false, double evalprec=1e-11, double evecprec=1e-6, int maxiter=50)
In-place version of qcp().