Visual Computing Library  devel
Loading...
Searching...
No Matches
point.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_SPACE_CORE_POINT_H
24#define VCL_SPACE_CORE_POINT_H
25
26#include <vclib/base.h>
27
28#include <Eigen/Core>
29#include <Eigen/Geometry>
30#include <compare>
31
32namespace vcl {
33
53template<typename Scalar, uint N>
54class Point : public Eigen::Matrix<Scalar, N, 1>
55{
56 using Base = Eigen::Matrix<Scalar, N, 1>;
57
58public:
59 using BaseMatrixType = Base;
60
61 // inherit Base operators
62 using Base::operator+;
63 using Base::operator-;
64 using Base::operator*;
65 using Base::operator/;
66 using Base::operator+=;
67 using Base::operator-=;
68 using Base::operator*=;
69 using Base::operator/=;
70
74 using ScalarType = Scalar;
75
79 static const uint DIM = N;
80
84 Point() { Base::setZero(); }
85
95 template<typename OtherDerived>
96 Point(const Eigen::MatrixBase<OtherDerived>& other) : Base(other)
97 {
98 }
99
113 template<typename... Scalars>
114 Point(Scalars... scalars) requires (sizeof...(scalars) == N)
115 {
116 set(scalars...);
117 }
118
128 ScalarType& x() requires (N >= 1) { return at(0); }
129
139 const ScalarType& x() const requires (N >= 1) { return at(0); }
140
150 ScalarType& y() requires (N >= 2) { return at(1); }
151
161 const ScalarType& y() const requires (N >= 2) { return at(1); }
162
172 ScalarType& z() requires (N >= 3) { return at(2); }
173
183 const ScalarType& z() const requires (N >= 3) { return at(2); }
184
194 ScalarType& w() requires (N >= 4) { return at(3); }
195
205 const ScalarType& w() const requires (N >= 4) { return at(3); }
206
207 ScalarType& at(uint i) { return Base::operator()(i); }
208
209 const ScalarType& at(uint i) const { return Base::operator()(i); }
210
222 template<typename S>
223 auto cast() const
224 {
225 if constexpr (std::is_same_v<Scalar, S>) {
226 return *this;
227 }
228 else {
229 return Point<S, N>(Base::template cast<S>());
230 }
231 }
232
244 bool isDegenerate() const
245 {
246 for (size_t i = 0; i < DIM; ++i)
247 if (vcl::isDegenerate(at(i)))
248 return true;
249 return false;
250 }
251
269 const Point& p1,
270 Scalar epsilon = std::numeric_limits<Scalar>::epsilon()) const
271 {
272 bool b = true;
273 for (size_t i = 0; i < DIM; ++i)
274 b = b && vcl::epsilonEquals(at(i), p1(i), epsilon);
275 return b;
276 }
277
291 Scalar angle(const Point& p1) const
292 {
293 Scalar w = Base::norm() * p1.norm();
294 if (w == 0)
295 return -1;
296 Scalar t = Base::dot(p1) / w;
297 if (t > 1)
298 t = 1;
299 else if (t < -1)
300 t = -1;
301 return (Scalar) acos(t);
302 }
303
316 Scalar dist(const Point& p1) const { return (*this - p1).norm(); }
317
330 Scalar squaredDist(const Point& p1) const
331 {
332 return (*this - p1).squaredNorm();
333 }
334
347 Point mul(const Point& p1) const
348 {
350 for (size_t i = 0; i < DIM; ++i)
351 tmp[i] = at(i) * p1[i];
352 return tmp;
353 }
354
371 Point div(const Point& p1) const
372 {
374 for (size_t i = 0; i < DIM; ++i) {
375 if (p1[i] == 0)
376 throw std::runtime_error(
377 "Math error: Attempted to divide by Zero\n");
378 tmp[i] = at(i) / p1[i];
379 }
380 return tmp;
381 }
382
391 constexpr uint size() const { return N; }
392
407 template<typename... Scalars>
408 void set(Scalars... scalars) requires (sizeof...(scalars) == N)
409 {
410 Scalar args[N] = {static_cast<Scalar>(scalars)...};
411 for (uint i = 0; i < N; i++)
412 at(i) = args[i];
413 }
414
427 auto outerProduct(const Point& p1) const
428 {
429 Eigen::Matrix<ScalarType, DIM, DIM> res;
430 for (uint i = 0; i < DIM; i++) {
431 for (uint j = 0; j < DIM; j++) {
432 res(i, j) = at(i) * p1(j);
433 }
434 }
435 return res;
436 }
437
458 void orthoBase(Point& u, Point& v) const requires (N == 3)
459 {
460 const double locEps = double(1e-7);
461
462 Point<Scalar, 3> up(0, 1, 0);
463 u = Base::cross(up);
464
465 double len = u.norm();
466 if (len < locEps) {
467 if (std::abs(at(0)) < std::abs(at(1))) {
468 if (std::abs(at(0)) < std::abs(at(2)))
469 up = Point<Scalar, 3>(1, 0, 0); // x is the min
470 else
471 up = Point<Scalar, 3>(0, 0, 1); // z is the min
472 }
473 else {
474 if (std::abs(at(1)) < std::abs(at(2)))
475 up = Point<Scalar, 3>(0, 1, 0); // y is the min
476 else
477 up = Point<Scalar, 3>(0, 0, 1); // z is the min
478 }
479 u = Base::cross(up);
480 }
481 v = Base::cross(u);
482 }
483
488 void serialize(std::ostream& os) const
489 {
490 vcl::serializeN(os, Base::data(), N);
491 }
492
497 void deserialize(std::istream& is)
498 {
499 vcl::deserializeN(is, Base::data(), N);
500 }
501
510 std::size_t hash() const
511 {
512 std::size_t h = 0;
513 for (size_t i = 0; i < DIM; ++i)
514 hashCombine(h, at(i));
515 return h;
516 }
517
523 template<typename OtherDerived>
524 Point& operator=(const Eigen::MatrixBase<OtherDerived>& other)
525 {
526 this->Base::operator=(other);
527 return *this;
528 }
529
544 auto operator<=>(const Point& p1) const
545 {
546 uint i = 0;
547 while (i < DIM && at(i) == p1[i]) {
548 ++i;
549 }
550 return i == DIM ? std::strong_ordering::equal : at(i) <=> p1[i];
551 }
552
564 Point operator+(const Scalar& s) const { return Base(Base::array() + s); }
565
577 Point operator-(const Scalar& s) const { return Base(Base::array() - s); }
578
590 Scalar operator*(const Point& p1) const { return Base::dot(p1); }
591
607 Point operator*(const Eigen::Matrix<Scalar, N + 1, N + 1>& m) const
608 requires (N == 3)
609 {
610 Eigen::Matrix<Scalar, 1, N> s;
611
612 s(0) = m(0, 0) * at(0) + m(0, 1) * at(1) + m(0, 2) * at(2) + m(0, 3);
613 s(1) = m(1, 0) * at(0) + m(1, 1) * at(1) + m(1, 2) * at(2) + m(1, 3);
614 s(2) = m(2, 0) * at(0) + m(2, 1) * at(1) + m(2, 2) * at(2) + m(2, 3);
615
616 Scalar w =
617 at(0) * m(3, 0) + at(1) * m(3, 1) + at(2) * m(3, 2) + m(3, 3);
618 if (w != 0) [[likely]]
619 s = s / w;
620 return Point(s);
621 }
622
633 Point& operator+=(const Scalar& s)
634 {
635 *this = *this + s;
636 return *this;
637 }
638
649 Point& operator-=(const Scalar& s)
650 {
651 *this = *this - s;
652 return *this;
653 }
654
668 Point& operator*=(const Eigen::Matrix<Scalar, N + 1, N + 1>& m)
669 requires (N == 3)
670 {
671 *this = *this * m;
672 return *this;
673 }
674
675private:
676 // hide Base begin and end members
677 using Base::begin;
678 using Base::end;
679};
680
681/* Specialization Aliases */
682
694template<typename Scalar>
696
707
719
731
743template<typename Scalar>
745
756
768
780
792template<typename Scalar>
794
805
817
829
830/* Concepts */
831
842template<typename T>
843concept PointConcept = std::derived_from< // same type or derived type
844 std::remove_cvref_t<T>,
845 Point<typename RemoveRef<T>::ScalarType, RemoveRef<T>::DIM>>;
846
857template<typename T>
858concept Point2Concept = PointConcept<T> && RemoveRef<T>::DIM == 2;
859
870template<typename T>
871concept Point3Concept = PointConcept<T> && RemoveRef<T>::DIM == 3;
872
883template<typename T>
884concept Point4Concept = PointConcept<T> && RemoveRef<T>::DIM == 4;
885
897template<typename It>
900
913template<typename It>
916
929template<typename It>
932
945template<typename It>
948
949/* Utility functions */
950
964template<typename Scalar, uint N>
965bool epsilonEquals(
966 const Point<Scalar, N>& p1,
967 const Point<Scalar, N>& p2,
968 const Scalar& epsilon = std::numeric_limits<Scalar>::epsilon())
969{
970 return p1.epsilonEquals(p2, epsilon);
971}
972
983template<typename Scalar, uint N>
984constexpr Point<Scalar, N> min(
985 const Point<Scalar, N>& p1,
986 const Point<Scalar, N>& p2)
987{
989 for (size_t i = 0; i < p.DIM; i++) {
990 p[i] = std::min(p1[i], p2[i]);
991 }
992 return p;
993}
994
1005template<typename Scalar, uint N>
1006constexpr Point<Scalar, N> max(
1007 const Point<Scalar, N>& p1,
1008 const Point<Scalar, N>& p2)
1009{
1010 Point<Scalar, N> p;
1011 for (size_t i = 0; i < p.DIM; i++) {
1012 p[i] = std::max(p1[i], p2[i]);
1013 }
1014 return p;
1015}
1016
1031template<typename Scalar, uint N>
1032std::ostream& operator<<(std::ostream& os, const Point<Scalar, N>& p)
1033{
1034 // Create a custom IOFormat for single row output
1035 // Parameters: precision, flags, coeffSeparator, rowSeparator, rowPrefix,
1036 // rowSuffix, matPrefix, matSuffix
1037 static const Eigen::IOFormat rowFormat(
1038 Eigen::StreamPrecision, // precision (use stream's precision)
1039 Eigen::DontAlignCols, // flags
1040 ", ", // coeffSeparator (between elements)
1041 ", ", // rowSeparator (not used for vectors)
1042 "", // rowPrefix
1043 "", // rowSuffix
1044 "[", // matPrefix
1045 "]" // matSuffix
1046 );
1047
1048 return os << static_cast<const typename Point<Scalar, N>::BaseMatrixType&>(
1049 p)
1050 .format(rowFormat);
1051}
1052
1053/* Deduction guides */
1054
1055template<typename S, typename... Scalars>
1056Point(S, Scalars... scalars) -> Point<S, sizeof...(Scalars) + 1>;
1057
1058} // namespace vcl
1059
1060// inject vcl::Point hash function in std namespace
1061namespace std {
1062
1063template<typename Scalar, unsigned int N>
1064struct hash<vcl::Point<Scalar, N>>
1065{
1075 size_t operator()(const vcl::Point<Scalar, N>& id) const noexcept
1076 {
1077 return id.hash();
1078 }
1079};
1080
1081} // namespace std
1082
1083#endif // VCL_SPACE_CORE_POINT_H
A class representing a box in N-dimensional space.
Definition box.h:46
static const uint DIM
The dimensionality of the box.
Definition box.h:59
The Point class represents an N-dimensional point containing N scalar values.
Definition point.h:55
auto outerProduct(const Point &p1) const
Returns the outer product between this point p and p1, which is p * p1^T.
Definition point.h:427
Point & operator*=(const Eigen::Matrix< Scalar, N+1, N+1 > &m)
Applies a TRS 4x4 matrix transformation to this point.
Definition point.h:668
Point & operator+=(const Scalar &s)
Adds a scalar value to this point.
Definition point.h:633
Point operator*(const Eigen::Matrix< Scalar, N+1, N+1 > &m) const
Returns a new 3D point/vector on which has been applied a TRS 4x4 matrix.
Definition point.h:607
Point(const Eigen::MatrixBase< OtherDerived > &other)
Constructs a Point object from an Eigen matrix.
Definition point.h:96
Scalar operator*(const Point &p1) const
Computes the dot product of this point with another point.
Definition point.h:590
Point operator-(const Scalar &s) const
Subtracts a scalar value from each coordinate of the point.
Definition point.h:577
Scalar squaredDist(const Point &p1) const
Computes the squared Euclidean distance between two Point objects.
Definition point.h:330
Point(Scalars... scalars)
Constructs a Point object from a set of scalar values.
Definition point.h:114
auto cast() const
Casts the Point object to a different scalar type.
Definition point.h:223
const ScalarType & y() const
Returns a const reference to the y-component of the Point object.
Definition point.h:161
Scalar ScalarType
The Scalar type of the Point.
Definition point.h:74
void orthoBase(Point &u, Point &v) const
Computes an Orthonormal Basis starting from this point n.
Definition point.h:458
constexpr uint size() const
Returns the size of the Point object.
Definition point.h:391
ScalarType & z()
Returns a reference to the z-component of the Point object.
Definition point.h:172
Scalar angle(const Point &p1) const
Computes the angle between two Point objects.
Definition point.h:291
Scalar dist(const Point &p1) const
Computes the Euclidean distance between two Point objects.
Definition point.h:316
Point operator+(const Scalar &s) const
Adds a scalar value to each coordinate of the point.
Definition point.h:564
Point()
Constructs a Point object with all components set to zero.
Definition point.h:84
Point div(const Point &p1) const
Divides the components of two Point objects.
Definition point.h:371
ScalarType & x()
Returns a reference to the x-component of the Point object.
Definition point.h:128
Point & operator=(const Eigen::MatrixBase< OtherDerived > &other)
Assigns the point to the given Eigen matrix.
Definition point.h:524
ScalarType & w()
Returns a reference to the w-component of the Point object.
Definition point.h:194
Point & operator-=(const Scalar &s)
Subtracts a scalar value from this point.
Definition point.h:649
void deserialize(std::istream &is)
Deserializes the point from the given input stream.
Definition point.h:497
auto operator<=>(const Point &p1) const
Compares the point with another point using the spaceship operator.
Definition point.h:544
void set(Scalars... scalars)
Sets all the components of the Point object from a set of scalar values.
Definition point.h:408
const ScalarType & z() const
Returns a const reference to the z-component of the Point object.
Definition point.h:183
void serialize(std::ostream &os) const
Serializes the point to the given output stream.
Definition point.h:488
std::size_t hash() const
Computes the hash value of the point.
Definition point.h:510
static const uint DIM
DIM: the number of dimensions of the Point.
Definition point.h:79
Point mul(const Point &p1) const
Multiplies the components of two Point objects.
Definition point.h:347
ScalarType & y()
Returns a reference to the y-component of the Point object.
Definition point.h:150
const ScalarType & w() const
Returns a const reference to the w-component of the Point object.
Definition point.h:205
const ScalarType & x() const
Returns a const reference to the x-component of the Point object.
Definition point.h:139
bool isDegenerate() const
Returns true if at least one of its components is NaN or inf.
Definition point.h:244
bool epsilonEquals(const Point &p1, Scalar epsilon=std::numeric_limits< Scalar >::epsilon()) const
Checks for the equality of two Point objects within a given epsilon tolerance.
Definition point.h:268
The IteratorConcept is satisfied if T is an input or output iterator.
Definition iterators.h:37
A concept representing a 2D Point.
Definition point.h:858
A concept representing an iterator that iterates over 2D Points (specifically, a class that satisfies...
Definition point.h:914
A concept representing a 3D Point.
Definition point.h:871
A concept representing an iterator that iterates over 3D Points (specifically, a class that satisfies...
Definition point.h:930
A concept representing a 4D Point.
Definition point.h:884
A concept representing an iterator that iterates over 4D Points (specifically, a class that satisfies...
Definition point.h:946
A concept representing a Point.
Definition point.h:843
A concept representing an iterator that iterates over Points (specifically, a class that satisfies th...
Definition point.h:898
bool epsilonEquals(Scalar n1, Scalar n2, Scalar epsilon=std::numeric_limits< Scalar >::epsilon())
Checks if two floating point numbers are equal within an epsilon value.
Definition math.h:64
constexpr auto max(const T &p1, const T &p2)
Returns the maximum between the two parameters.
Definition min_max.h:81
bool isDegenerate(Scalar number)
Checks if a floating point number is degenerate.
Definition math.h:43
constexpr auto min(const T &p1, const T &p2)
Returns the minimum between the two parameters.
Definition min_max.h:40
void hashCombine(std::size_t &seed, const T &v, const Rest &... rest)
Starting from a seed, computes the hash of a series of objects.
Definition hash.h:42