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
438 // TODO: this function should return a pair
459 void orthoBase(Point& u, Point& v) const requires (N == 3)
460 {
461 const double locEps = double(1e-7);
462
463 Point<Scalar, 3> up(0, 1, 0);
464 u = Base::cross(up);
465
466 double len = u.norm();
467 if (len < locEps) {
468 if (std::abs(at(0)) < std::abs(at(1))) {
469 if (std::abs(at(0)) < std::abs(at(2)))
470 up = Point<Scalar, 3>(1, 0, 0); // x is the min
471 else
472 up = Point<Scalar, 3>(0, 0, 1); // z is the min
473 }
474 else {
475 if (std::abs(at(1)) < std::abs(at(2)))
476 up = Point<Scalar, 3>(0, 1, 0); // y is the min
477 else
478 up = Point<Scalar, 3>(0, 0, 1); // z is the min
479 }
480 u = Base::cross(up);
481 }
482 v = Base::cross(u);
483 }
484
489 void serialize(std::ostream& os) const
490 {
491 vcl::serializeN(os, Base::data(), N);
492 }
493
498 void deserialize(std::istream& is)
499 {
500 vcl::deserializeN(is, Base::data(), N);
501 }
502
511 std::size_t hash() const
512 {
513 std::size_t h = 0;
514 for (size_t i = 0; i < DIM; ++i)
515 hashCombine(h, at(i));
516 return h;
517 }
518
524 template<typename OtherDerived>
525 Point& operator=(const Eigen::MatrixBase<OtherDerived>& other)
526 {
527 this->Base::operator=(other);
528 return *this;
529 }
530
545 auto operator<=>(const Point& p1) const
546 {
547 uint i = 0;
548 while (i < DIM && at(i) == p1[i]) {
549 ++i;
550 }
551 return i == DIM ? std::strong_ordering::equal : at(i) <=> p1[i];
552 }
553
565 Point operator+(const Scalar& s) const { return Base(Base::array() + s); }
566
578 Point operator-(const Scalar& s) const { return Base(Base::array() - s); }
579
591 Scalar operator*(const Point& p1) const { return Base::dot(p1); }
592
608 Point operator*(const Eigen::Matrix<Scalar, N + 1, N + 1>& m) const
609 requires (N == 3)
610 {
611 Eigen::Matrix<Scalar, 1, N> s;
612
613 s(0) = m(0, 0) * at(0) + m(0, 1) * at(1) + m(0, 2) * at(2) + m(0, 3);
614 s(1) = m(1, 0) * at(0) + m(1, 1) * at(1) + m(1, 2) * at(2) + m(1, 3);
615 s(2) = m(2, 0) * at(0) + m(2, 1) * at(1) + m(2, 2) * at(2) + m(2, 3);
616
617 Scalar w =
618 at(0) * m(3, 0) + at(1) * m(3, 1) + at(2) * m(3, 2) + m(3, 3);
619 if (w != 0) [[likely]]
620 s = s / w;
621 return Point(s);
622 }
623
634 Point& operator+=(const Scalar& s)
635 {
636 *this = *this + s;
637 return *this;
638 }
639
650 Point& operator-=(const Scalar& s)
651 {
652 *this = *this - s;
653 return *this;
654 }
655
669 Point& operator*=(const Eigen::Matrix<Scalar, N + 1, N + 1>& m)
670 requires (N == 3)
671 {
672 *this = *this * m;
673 return *this;
674 }
675
676private:
677 // hide Base begin and end members
678 using Base::begin;
679 using Base::end;
680};
681
682/* Specialization Aliases */
683
695template<typename Scalar>
697
708
720
732
744template<typename Scalar>
746
757
769
781
793template<typename Scalar>
795
806
818
830
831/* Concepts */
832
843template<typename T>
844concept PointConcept = std::derived_from< // same type or derived type
845 std::remove_cvref_t<T>,
846 Point<typename RemoveRef<T>::ScalarType, RemoveRef<T>::DIM>>;
847
858template<typename T>
859concept Point2Concept = PointConcept<T> && RemoveRef<T>::DIM == 2;
860
871template<typename T>
872concept Point3Concept = PointConcept<T> && RemoveRef<T>::DIM == 3;
873
884template<typename T>
885concept Point4Concept = PointConcept<T> && RemoveRef<T>::DIM == 4;
886
898template<typename It>
901
914template<typename It>
917
930template<typename It>
933
946template<typename It>
949
950/* Utility functions */
951
965template<typename Scalar, uint N>
966bool epsilonEquals(
967 const Point<Scalar, N>& p1,
968 const Point<Scalar, N>& p2,
969 const Scalar& epsilon = std::numeric_limits<Scalar>::epsilon())
970{
971 return p1.epsilonEquals(p2, epsilon);
972}
973
984template<typename Scalar, uint N>
985constexpr Point<Scalar, N> min(
986 const Point<Scalar, N>& p1,
987 const Point<Scalar, N>& p2)
988{
990 for (size_t i = 0; i < p.DIM; i++) {
991 p[i] = std::min(p1[i], p2[i]);
992 }
993 return p;
994}
995
1006template<typename Scalar, uint N>
1007constexpr Point<Scalar, N> max(
1008 const Point<Scalar, N>& p1,
1009 const Point<Scalar, N>& p2)
1010{
1011 Point<Scalar, N> p;
1012 for (size_t i = 0; i < p.DIM; i++) {
1013 p[i] = std::max(p1[i], p2[i]);
1014 }
1015 return p;
1016}
1017
1032template<typename Scalar, uint N>
1033std::ostream& operator<<(std::ostream& os, const Point<Scalar, N>& p)
1034{
1035 // Create a custom IOFormat for single row output
1036 // Parameters: precision, flags, coeffSeparator, rowSeparator, rowPrefix,
1037 // rowSuffix, matPrefix, matSuffix
1038 static const Eigen::IOFormat rowFormat(
1039 Eigen::StreamPrecision, // precision (use stream's precision)
1040 Eigen::DontAlignCols, // flags
1041 ", ", // coeffSeparator (between elements)
1042 ", ", // rowSeparator (not used for vectors)
1043 "", // rowPrefix
1044 "", // rowSuffix
1045 "[", // matPrefix
1046 "]" // matSuffix
1047 );
1048
1049 return os << static_cast<const typename Point<Scalar, N>::BaseMatrixType&>(
1050 p)
1051 .format(rowFormat);
1052}
1053
1054/* Deduction guides */
1055
1056template<typename S, typename... Scalars>
1057Point(S, Scalars... scalars) -> Point<S, sizeof...(Scalars) + 1>;
1058
1059} // namespace vcl
1060
1061// inject vcl::Point hash function in std namespace
1062namespace std {
1063
1064template<typename Scalar, unsigned int N>
1065struct hash<vcl::Point<Scalar, N>>
1066{
1076 size_t operator()(const vcl::Point<Scalar, N>& id) const noexcept
1077 {
1078 return id.hash();
1079 }
1080};
1081
1082} // namespace std
1083
1084#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:669
Point & operator+=(const Scalar &s)
Adds a scalar value to this point.
Definition point.h:634
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:608
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:591
Point operator-(const Scalar &s) const
Subtracts a scalar value from each coordinate of the point.
Definition point.h:578
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:459
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:565
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:525
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:650
void deserialize(std::istream &is)
Deserializes the point from the given input stream.
Definition point.h:498
auto operator<=>(const Point &p1) const
Compares the point with another point using the spaceship operator.
Definition point.h:545
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:489
std::size_t hash() const
Computes the hash value of the point.
Definition point.h:511
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:859
A concept representing an iterator that iterates over 2D Points (specifically, a class that satisfies...
Definition point.h:915
A concept representing a 3D Point.
Definition point.h:872
A concept representing an iterator that iterates over 3D Points (specifically, a class that satisfies...
Definition point.h:931
A concept representing a 4D Point.
Definition point.h:885
A concept representing an iterator that iterates over 4D Points (specifically, a class that satisfies...
Definition point.h:947
A concept representing a Point.
Definition point.h:844
A concept representing an iterator that iterates over Points (specifically, a class that satisfies th...
Definition point.h:899
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