NuriKit v0.1.0b2
Loading...
Searching...
No Matches
geometry.h
Go to the documentation of this file.
1//
2// Project NuriKit - Copyright 2023 SNU Compbio Lab.
3// SPDX-License-Identifier: Apache-2.0
4//
5#ifndef NURI_CORE_GEOMETRY_H_
6#define NURI_CORE_GEOMETRY_H_
7
9#include <cmath>
10#include <cstdint>
11#include <type_traits>
12#include <utility>
13#include <vector>
14
15#include <absl/log/absl_check.h>
16#include <Eigen/Dense>
18
19#include "nuri/eigen_config.h"
20#include "nuri/meta.h"
21
22namespace nuri {
23namespace internal {
24 using Array8i = Array<int, 8, 1>;
25
26 class OCTreeNode {
27 public:
28 OCTreeNode(Array8i &&children, int begin, int nleaf)
29 : children_(std::move(children)), begin_(begin), nleaf_(nleaf) { }
30
31 const Array8i &children() const { return children_; }
32
33 int child(int i) const { return children_[i]; }
34
35 int operator[](int i) const { return child(i); }
36
37 bool leaf() const { return nleaf_ <= 8; }
38
39 int begin() const { return begin_; }
40 int end() const { return begin_ + nleaf_; }
41
42 int nleaf() const { return nleaf_; }
43
44 private:
45 Array8i children_; // < 0 -> not exist, >= 0 -> index of child
46 int begin_;
47 int nleaf_; // <= 8 -> leaf, > 8 -> internal node
48 };
49} // namespace internal
50
67class OCTree {
68public:
69 using Points = ConstRef<Matrix3Xd>;
70
71 OCTree() = default;
72
73 explicit OCTree(Points pts, int bucket_size = 32): bucket_size_(bucket_size) {
74 rebuild_impl(pts);
75 }
76
77 void rebuild(Points pts, int bucket_size = -1) {
78 if (bucket_size > 0)
79 bucket_size_ = bucket_size;
80
81 rebuild_impl(pts);
82 }
83
84 void find_neighbors_kd(const Vector3d &pt, int k, std::vector<int> &idxs,
85 std::vector<double> &distsq, double cutoff = -1) const;
86
87 void find_neighbors_d(const Vector3d &pt, double cutoff,
88 std::vector<int> &idxs,
89 std::vector<double> &distsq) const;
90
91 void find_neighbors_tree(const OCTree &oct, double cutoff,
92 std::vector<int> &self,
93 std::vector<int> &other) const;
94
95 std::vector<std::vector<int>> find_neighbors_tree(const OCTree &oct,
96 double cutoff) const;
97
98 void find_neighbors_self(double cutoff, std::vector<int> &left,
99 std::vector<int> &right) const;
100
101 const Matrix3Xd &pts() const { return pts_; }
102
103 const Vector3d &max() const { return max_; }
104
105 const Vector3d &len() const { return len_; }
106
118 void notify_transform(const Vector3d &new_max, const Vector3d &new_len);
119
120 const std::vector<internal::OCTreeNode> &nodes() const { return nodes_; }
121
122 int size() const { return static_cast<int>(nodes_.size()); }
123
124 int root() const { return size() - 1; }
125
126 int bucket_size() const { return bucket_size_; }
127
128 const ArrayXi &idxs() const { return idxs_; }
129
130 const internal::OCTreeNode &node(int i) const { return nodes_[i]; }
131
132 const internal::OCTreeNode &operator[](int idx) const { return nodes_[idx]; }
133
134private:
135 void rebuild_impl(Points src);
136
137 Matrix3Xd pts_;
138 Vector3d max_;
139 Vector3d len_;
140 std::vector<internal::OCTreeNode> nodes_;
141 ArrayXi idxs_;
142
143 int bucket_size_ = 32;
144};
145
166public:
167 using Points = ConstRef<Matrix3Xd>;
168
169 VoxelGrid() = default;
170
171 explicit VoxelGrid(Points pts, double cutoff): cutoff_(cutoff) {
172 rebuild_impl(pts);
173 }
174
175 void rebuild(Points pts, double cutoff = -1.0) {
176 if (cutoff > 0)
177 cutoff_ = cutoff;
178 rebuild_impl(pts);
179 }
180
189 void find_neighbors_d(const Vector3d &pt, std::vector<int> &idxs,
190 std::vector<double> &distsq) const;
191
200 void find_neighbors_grid(const VoxelGrid &grid, std::vector<int> &self,
201 std::vector<int> &other) const;
202
210 std::vector<std::vector<int>>
211 find_neighbors_grid(const VoxelGrid &grid) const;
212
223 void find_neighbors_self(std::vector<int> &left,
224 std::vector<int> &right) const;
225
233 const Matrix3Xd &pts() const { return pts_; }
234
235 double cutoff() const { return cutoff_; }
236
237 const Vector3d &origin() const { return origin_; }
238
239 const Array3i &dims() const { return dims_; }
240
241 int num_cells() const { return static_cast<int>(cell_offset_.size()) - 1; }
242
243 const ArrayXi &cell_offset() const { return cell_offset_; }
244
245 const ArrayXi &cell_pts() const { return cell_pts_; }
246
247private:
248 void rebuild_impl(Points src);
249
250 Matrix3Xd pts_;
251 Vector3d origin_;
252 Array3i dims_;
253 ArrayXi cell_offset_;
254 ArrayXi cell_pts_;
255 double cutoff_;
256 int max_occ_;
257};
258
259namespace constants {
260 constexpr double kPi =
261 3.1415926535897932384626433832795028841971693993751058209749445923078164;
262
263 constexpr double kTwoPi =
264 6.2831853071795864769252867665590057683943387987502116419498891846156328;
265
266 // NOLINTBEGIN(*-identifier-naming)
267 constexpr double kCos15 =
268 0.9659258262890682867497431997288973676339048390084045504023430763;
269 constexpr double kCos30 =
270 0.8660254037844386467637231707529361834714026269051903140279034897;
271 constexpr double kCos36 =
272 0.8090169943749474241022934171828190588601545899028814310677243114;
273 constexpr double kCos45 =
274 0.7071067811865475244008443621048490392848359376884740365883398690;
275 constexpr double kCos54 =
276 0.5877852522924731291687059546390727685976524376431459910722724808;
277 constexpr double kCos60 = 0.5;
278 constexpr double kCos75 =
279 0.2588190451025207623488988376240483283490689013199305138140032073;
280 constexpr double kCos100 =
281 -0.173648177666930348851716626769314796000375677184069387236241378;
282 constexpr double kCos102 =
283 -0.207911690817759337101742284405125166216584760627723836407181973;
284 constexpr double kCos112 =
285 -0.374606593415912035414963774501195131000158922253676174103440371;
286 constexpr double kCos115 =
287 -0.422618261740699436186978489647730181563129301194864623444415159;
288 constexpr double kCos125 =
289 -0.573576436351046096108031912826157864620433371450986351081027118;
290 constexpr double kCos155 =
291 -0.906307787036649963242552656754316983267712625175864680871298408;
292 constexpr double kCos175 =
293 -0.996194698091745532295010402473888046183562672645850974525442277;
294 constexpr double kTan10_2 =
295 0.0874886635259240052220186694349614581194542763681082291452366622;
296 constexpr double kTan15_2 =
297 0.1316524975873958534715264574097171035928141022232375735535653257;
298 constexpr double kTan116_2 =
299 1.6003345290410503553267330811833575255040718469227591484115002297;
300 constexpr double kTan155_2 =
301 4.5107085036620571342899391172547519686713241944553043587162345185;
302 // NOLINTEND(*-identifier-naming)
303} // namespace constants
304
305template <class DT, std::enable_if_t<std::is_floating_point_v<DT>, int> = 0>
306constexpr DT deg2rad(DT deg) {
307 return deg * static_cast<DT>(constants::kPi / 180);
308}
309
310template <class DT, std::enable_if_t<std::is_integral_v<DT>, int> = 0>
311constexpr double deg2rad(DT deg) {
312 return static_cast<double>(deg) * constants::kPi / 180;
313}
314
315template <class DT, std::enable_if_t<std::is_floating_point_v<DT>, int> = 0>
316constexpr DT rad2deg(DT rad) {
317 return rad * 180 / static_cast<DT>(constants::kPi);
318}
319
320template <class DT, std::enable_if_t<std::is_integral_v<DT>, int> = 0>
321constexpr double rad2deg(DT rad) {
322 return static_cast<double>(rad) * 180 / constants::kPi;
323}
324
325// NOLINTBEGIN(*-missing-std-forward)
326
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;
331
332 const Eigen::Index n = m.cols();
333 ABSL_DCHECK(distsq.size() == n * (n - 1) / 2);
334
335 Vector<DT, rows> v(m.rows());
336 for (Eigen::Index i = 1, k = 0; i < n; ++i) {
337 v = m.col(i);
338 for (Eigen::Index j = 0; j < i; ++j, ++k) {
339 distsq[k] = (v - m.col(j)).squaredNorm();
340 }
341 }
342}
343
344template <class MatrixLike>
345auto pdistsq(const MatrixLike &m) {
346 using DT = typename MatrixLike::Scalar;
347
348 const Eigen::Index n = m.cols();
349 ArrayX<DT> distsq(n * (n - 1) / 2);
350 pdistsq(distsq, m);
351 return distsq;
352}
353
354template <class MatrixLike, class ArrayLike>
355void pdist(ArrayLike &&dist, const MatrixLike &m) {
356 pdistsq(dist, m);
357 dist = dist.sqrt();
358}
359
360template <class MatrixLike>
361auto pdist(const MatrixLike &m) {
362 auto ret = pdistsq(m);
363 ret = ret.sqrt();
364 return ret;
365}
366
367template <class AL, class DAL>
368void to_square_form(DAL &&dists, const AL &pdists, Eigen::Index n) {
369 ABSL_DCHECK(dists.rows() == n);
370 ABSL_DCHECK(dists.cols() == n);
371
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];
376}
377
378template <class ArrayLike>
379auto to_square_form(const ArrayLike &pdists, Eigen::Index n) {
380 using DT = typename ArrayLike::Scalar;
381
382 MatrixX<DT> dists(n, n);
383 to_square_form(dists, pdists, n);
384 return dists;
385}
386
387template <
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),
391 int> = 0>
392void cdistsq(DML &&distsq, const ML1 &a, const ML2 &b) {
393 ABSL_DCHECK(distsq.rows() == a.cols());
394 ABSL_DCHECK(distsq.cols() == b.cols());
395
396 for (Eigen::Index j = 0; j < b.cols(); ++j)
397 distsq.col(j) = (a.colwise() - b.col(j)).colwise().squaredNorm();
398}
399
400template <class ML1, class ML2>
401auto cdistsq(const ML1 &a, const ML2 &b) {
402 using DT = typename ML1::Scalar;
403
404 MatrixX<DT> distsq(a.cols(), b.cols());
405 cdistsq(distsq, a, b);
406 return distsq;
407}
408
409template <class ML1, class ML2, class DML>
410void cdist(DML &&dist, const ML1 &a, const ML2 &b) {
411 cdistsq(dist, a, b);
412 dist = dist.cwiseSqrt();
413}
414
415template <class ML1, class ML2>
416auto cdist(const ML1 &a, const ML2 &b) {
417 auto ret = cdistsq(a, b);
418 ret = ret.cwiseSqrt();
419 return ret;
420}
421
422template <class ML1, class ML2>
423auto msd(const ML1 &a, const ML2 &b) {
424 return (a - b).colwise().squaredNorm().mean();
425}
426
427namespace internal {
428 constexpr double safe_normalizer(double sqn, double eps = 1e-12) {
429 return sqn > eps ? 1 / std::sqrt(sqn) : 0;
430 }
431
432 template <class VectorLike>
433 inline void safe_normalize(VectorLike &&m, double eps = 1e-12) {
434 m.array() *= safe_normalizer(m.squaredNorm(), eps);
435 }
436
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;
443
444 Matrix<Scalar, size, 1, 0, max_size, 1> ret = std::forward<VectorLike>(m);
445 safe_normalize(ret, eps);
446 return ret;
447 }
448
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;
453
454 if constexpr (max_cols != Eigen::Dynamic) {
455 using T = remove_cvref_t<MatrixLike>;
456 using Scalar = typename T::Scalar;
457
458 constexpr auto cols = ArrayLike::ColsAtCompileTime;
459
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);
463 } else {
464 for (Eigen::Index i = 0; i < m.cols(); ++i)
465 safe_normalize(m.col(i), eps);
466 }
467 }
468
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;
476
477 Matrix<Scalar, rows, cols, 0, max_rows, max_cols> ret =
478 std::forward<MatrixLike>(m);
479 safe_colwise_normalize(ret, eps);
480 return ret;
481 }
482} // namespace internal
483
484// NOLINTEND(*-missing-std-forward)
485
492inline double cos_angle(const Vector3d &oa, const Vector3d &ob) {
493 return oa.dot(ob)
494 * internal::safe_normalizer(oa.squaredNorm() * ob.squaredNorm());
495}
496
504inline double cos_angle(const Vector3d &o, const Vector3d &a,
505 const Vector3d &b) {
506 Vector3d oa = a - o, ob = b - o;
507 return cos_angle(oa, ob);
508}
509
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);
531}
532
545template <class Scalar, int N, auto... Extra>
546inline std::pair<Scalar, Scalar>
547sum_tan2_half(const Matrix<Scalar, 3, N, 0, Extra...> &m) {
548 if constexpr (N == Eigen::Dynamic) {
549 CyclicIndex<1> idxs(m.cols());
550 return sum_tan2_half(m, idxs);
551 }
552
554 return sum_tan2_half(m, idxs);
555}
556
567inline double cos_dihedral(const Vector3d &axis, Vector3d v, Vector3d w) {
568 v -= v.dot(axis) * axis;
569 w -= w.dot(axis) * axis;
570 return v.dot(w)
571 * internal::safe_normalizer(v.squaredNorm() * w.squaredNorm());
572}
573
584inline double cos_dihedral(const Vector3d &a, const Vector3d &b,
585 const Vector3d &c, const Vector3d &d) {
586 Vector3d axis = internal::safe_normalized(c - b);
587 return cos_dihedral(axis, a - b, d - c);
588}
589
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);
605
606 Vector4d ret;
607 ret.head<3>() = svd.matrixU().col(2);
608 if (normalize)
609 internal::safe_normalize(ret.head<3>());
610 ret[3] = -ret.head<3>().dot(cntr);
611 return ret;
612}
613
626template <class VectorLike>
627Vector3d any_perpendicular(const VectorLike &v, bool normalize = true) {
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]) };
631 if (normalize)
632 internal::safe_normalize(w);
633 return w;
634}
635
636enum class AlignMode : std::uint8_t {
637 kMsdOnly = 0x1,
640};
641
701extern std::pair<Isometry3d, double> kabsch(ConstRef<Matrix3Xd> query,
702 ConstRef<Matrix3Xd> templ,
704 bool reflection = false);
705
775extern std::pair<Isometry3d, double>
776qcp(const Eigen::Ref<const Matrix3Xd> &query,
777 const Eigen::Ref<const Matrix3Xd> &templ, AlignMode mode = AlignMode::kBoth,
778 bool reflection = false, double evalprec = 1e-11, double evecprec = 1e-6,
779 int maxiter = 50);
780
852extern std::pair<Isometry3d, double>
853qcp_inplace(MutRef<Matrix3Xd> query, MutRef<Matrix3Xd> templ,
854 AlignMode mode = AlignMode::kBoth, bool reflection = false,
855 double evalprec = 1e-11, double evecprec = 1e-6, int maxiter = 50);
856
871extern bool embed_distances_3d(Eigen::Ref<Matrix3Xd> pts, MatrixXd &dsqs);
872
887extern bool embed_distances_4d(Eigen::Ref<Matrix4Xd> pts, MatrixXd &dsqs);
888
913extern Matrix3Xd canonical_fibonacci_lattice(int npts);
914} // namespace nuri
915
916#endif /* NURI_CORE_GEOMETRY_H_ */
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
OCTree()=default
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
VoxelGrid()=default
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
Definition crdgen.h:16
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().