Ocean
Loading...
Searching...
No Matches
Line3.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_MATH_LINE_3_H
9#define META_OCEAN_MATH_LINE_3_H
10
11#include "ocean/math/Math.h"
12#include "ocean/math/Numeric.h"
14#include "ocean/math/Vector3.h"
15
16namespace Ocean
17{
18
19// Forward declaration.
20template <typename T> class LineT3;
21
22/**
23 * Definition of the Line3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single or double precision float data type.
24 * @see LineT3
25 * @ingroup math
26 */
28
29/**
30 * Instantiation of the LineT3 template class using a double precision float data type.
31 * @see LineT3
32 * @ingroup math
33 */
35
36/**
37 * Instantiation of the LineT3 template class using a single precision float data type.
38 * @see LineT3
39 * @ingroup math
40 */
42
43/**
44 * Definition of a typename alias for vectors with LineT3 objects.
45 * @see LineT3
46 * @ingroup math
47 */
48template <typename T>
49using LinesT3 = std::vector<LineT3<T>>;
50
51/**
52 * Definition of a vector holding Line3 objects.
53 * @see Line3
54 * @ingroup math
55 */
56using Lines3 = std::vector<Line3>;
57
58/**
59 * This class implements an infinite line in 3D space.
60 * The line is defined by a point lying on the line and a direction vector.<br>
61 * The direction vector must not be a zero vector.<br>
62 * The length of the vector may be arbitrary, however a unit vector is necessary for most functions.<br>
63 * @tparam T Data type used to represent lines
64 * @see Line3, LineF3, LineD3, FiniteLine3, FiniteLine3.
65 * @ingroup math
66 */
67template <typename T>
68class LineT3
69{
70 template <typename U> friend class LineT3;
71
72 public:
73
74 /**
75 * Definition of the used data type.
76 */
77 using Type = T;
78
79 public:
80
81 /**
82 * Creates an invalid line.
83 */
84 LineT3() = default;
85
86 /**
87 * Creates a line defined by two different intersection points.
88 * @param point Intersection point on the line
89 * @param direction Vector representing the direction of the line, a unit vector might be appropriate
90 */
92
93 /**
94 * Copies a line with different data type than T.
95 * @param line The line to copy
96 * @tparam U The data type of the second line
97 */
98 template <typename U>
99 inline explicit LineT3(const LineT3<U>& line);
100
101 /**
102 * Returns a point on the line.
103 * @return Point on line
104 */
105 inline const VectorT3<T>& point() const;
106
107 /**
108 * Returns a point on the line that is defined by a scalar.
109 * The result is determined by point() + direction() * distance;
110 * @param distance The distance to determine the line point for
111 * @return Point on line
112 */
113 inline const VectorT3<T> point(const T distance) const;
114
115 /**
116 * Returns the direction of the line.
117 * @return Unit vector
118 */
119 inline const VectorT3<T>& direction() const;
120
121 /**
122 * Sets a point of this line.
123 * @param point The point of this line
124 */
125 inline void setPoint(const VectorT3<T>& point);
126
127 /**
128 * Sets the direction of this line.
129 * @param direction Vector defining the new direction, a unit vector might be appropriate
130 */
131 inline void setDirection(const VectorT3<T>& direction);
132
133 /**
134 * Returns whether a given point is part of the line.
135 * This function needs a unit vector as direction!
136 * @param point The point to check
137 * @return True, if so
138 */
139 bool isOnLine(const VectorT3<T>& point) const;
140
141 /**
142 * Returns the distance between the line and a given point.
143 * This function needs a unit vector as direction!
144 * @param point The point to return the distance for
145 * @return Positive distance between point and line, with range [0, infinity)
146 */
147 T distance(const VectorT3<T>& point) const;
148
149 /**
150 * Returns the distance between two lines.
151 * This function needs a unit vector as direction!<br>
152 * @param line Second line to calculate the distance for
153 * @return Distance
154 */
155 T distance(const LineT3<T>& line) const;
156
157 /**
158 * Returns the square distance between the line and a given point.
159 * This function needs a unit vector as direction!
160 * @param point The point to return the distance for
161 * @return The square distance between point and line, with range [0, infinity)
162 */
163 T sqrDistance(const VectorT3<T>& point) const;
164
165 /**
166 * Returns the point on this line nearest to an arbitrary given point.
167 * This function needs a unit vector as direction!<br>
168 * @param point Arbitrary point outside the line
169 * @return Nearest point on the line
170 */
172
173 /**
174 * Returns the middle of two nearest points for two crossing lines.
175 * This function needs a unit vector as direction!<br>
176 * Both lines must not be parallel.<br>
177 * @param line Second line to calculate the point for
178 * @param middle Nearest point between two lines
179 * @return True, if succeeded
180 */
181 bool nearestPoint(const LineT3<T>& line, VectorT3<T>& middle) const;
182
183 /**
184 * Returns the two nearest points for two crossing lines.
185 * Both lines must not be parallel.<br>
186 * This function needs a unit vector as direction!<br>
187 * @param line Second line to calculate the points for
188 * @param first Nearest point on the first line
189 * @param second Nearest point on the second line
190 * @return True, if succeeded
191 */
192 bool nearestPoints(const LineT3<T>& line, VectorT3<T>& first, VectorT3<T>& second) const;
193
194 /**
195 * Returns whether two lines are parallel up to a small epsilon.
196 * This function needs a unit vector as direction!
197 * @param right Second line
198 * @return True, if so
199 */
200 inline bool isParallel(const LineT3<T>& right) const;
201
202 /**
203 * Returns whether this line and a given vector are parallel up to a small epsilon.
204 * This function needs a unit vector as direction!
205 * @param right Vector to be compared
206 * @return True, if so
207 */
208 inline bool isParallel(const VectorT3<T>& right) const;
209
210 /**
211 * Returns whether this line has valid parameters.
212 * @return True, if so
213 */
214 inline bool isValid() const;
215
216 /**
217 * Returns whether this line has a unit vector as direction.
218 * @return True, if so
219 */
220 inline bool hasUnitDirection() const;
221
222 /**
223 * Returns whether two line are identical up to a small epsilon.
224 * This function needs a unit vector as direction!
225 * @param right The right line
226 * @return True, if so
227 */
228 inline bool operator==(const LineT3<T>& right) const;
229
230 /**
231 * Returns whether two line are identical up to a small epsilon.
232 * This function needs a unit vector as direction!
233 * @param right The right line
234 * @return True, if so
235 */
236 inline bool operator!=(const LineT3<T>& right) const;
237
238 /**
239 * Returns whether this line is valid.
240 * @return True, if so
241 */
242 explicit inline operator bool() const;
243
244 /**
245 * Fits a line to a set of given 3D points by application of the least square measure.
246 * This function uses PCA (Principal Component Analysis) to find the best-fitting line direction.
247 * @param points The points for which the best fitting line is requested, must be valid
248 * @param size The number of given points, with range [2, infinity)
249 * @param line The resulting line with unit direction vector
250 * @return True, if succeeded
251 */
252 static inline bool fitLineLeastSquare(const VectorT3<T>* points, const size_t size, LineT3<T>& line);
253
254 protected:
255
256 /// Point on the line.
258
259 /// Direction of the line.
261};
262
263template <typename T>
264LineT3<T>::LineT3(const VectorT3<T>& first, const VectorT3<T>& direction) :
265 point_(first),
266 direction_(direction)
267{
268 ocean_assert(!direction_.isNull());
269}
270
271template <typename T>
272template <typename U>
273inline LineT3<T>::LineT3(const LineT3<U>& line)
274{
275 point_ = VectorT3<T>(line.point_);
276 direction_ = VectorT3<T>(line.direction_);
277}
278
279template <typename T>
280inline const VectorT3<T>& LineT3<T>::point() const
281{
282 return point_;
283}
284
285template <typename T>
286inline const VectorT3<T> LineT3<T>::point(const T distance) const
287{
288 ocean_assert(isValid());
289 return point_ + direction_ * distance;
290}
291
292template <typename T>
294{
295 return direction_;
296}
297
298template <typename T>
299inline void LineT3<T>::setPoint(const VectorT3<T>& point)
300{
301 point_ = point;
302}
303
304template <typename T>
305inline void LineT3<T>::setDirection(const VectorT3<T>& direction)
306{
307 ocean_assert(NumericT<T>::isEqual(direction.length(), T(1.0)));
308 direction_ = direction;
309}
310
311template <typename T>
313{
314 return !direction_.isNull();
315}
316
317template <typename T>
319{
320 return NumericT<T>::isEqual(direction_.length(), T(1.0));
321}
322
323template <typename T>
324inline bool LineT3<T>::isParallel(const LineT3<T>& right) const
325{
326 ocean_assert(isValid() && right.isValid());
327 ocean_assert(hasUnitDirection() && right.hasUnitDirection());
328
329 const T scalarProduct = direction_ * right.direction_;
330
331 return NumericT<T>::isEqual(NumericT<T>::abs(scalarProduct), T(1.0));
332}
333
334template <typename T>
335inline bool LineT3<T>::isParallel(const VectorT3<T>& right) const
336{
337 ocean_assert(isValid());
338 ocean_assert(hasUnitDirection() && NumericT<T>::isEqual(right.length(), T(1.0)));
339
340 const T scalarProduct = direction_ * right;
341
342 return NumericT<T>::isEqual(NumericT<T>::abs(scalarProduct), T(1.0));
343}
344
345template <typename T>
346inline bool LineT3<T>::operator==(const LineT3<T>& right) const
347{
348 ocean_assert(isValid() && right.isValid());
349
350 return isParallel(right) && isOnLine(right.point());
351}
352
353template <typename T>
354inline bool LineT3<T>::operator!=(const LineT3<T>& right) const
355{
356 return !(*this == right);
357}
358
359template <typename T>
360inline LineT3<T>::operator bool() const
361{
362 return isValid();
363}
364
365template <typename T>
366bool LineT3<T>::isOnLine(const VectorT3<T>& point) const
367{
368 ocean_assert(isValid());
369 ocean_assert(hasUnitDirection());
370
371 const VectorT3<T> offset(point - point_);
372 const T length = offset.length();
373
374 if (NumericT<T>::isEqualEps(length))
375 {
376 return true;
377 }
378
379#ifdef OCEAN_DEBUG
380 if (!std::is_same<T, float>::value)
381 {
382 ocean_assert(NumericT<T>::isEqual(NumericT<T>::abs((offset / length) * direction_), T(1.0))
383 == NumericT<T>::isEqual(NumericT<T>::abs(offset * direction_), length, NumericT<T>::eps() * length));
384 }
385#endif
386
387 // we explicitly adjust the epsilon by the length of the offset vector ensuring that the result is still correct for long vectors (short vectors would have been caught before)
388 return NumericT<T>::isEqual(NumericT<T>::abs(offset * direction_), length, NumericT<T>::eps() * length);
389}
390
391template <>
392inline bool LineT3<float>::isOnLine(const VectorT3<float>& point) const
393{
394 ocean_assert(isValid());
395 ocean_assert(hasUnitDirection());
396
397 const VectorT3<float> offset(point - point_);
398 const float length = offset.length();
399
400 if (NumericT<float>::isEqualEps(length))
401 {
402 return true;
403 }
404
405 if (length > 1.0f)
406 {
407 // we explicitly adjust the epsilon by the length of the offset vector ensuring that the result is still correct for long vectors (short vectors would have been caught before)
408 return NumericT<float>::isEqual(NumericT<float>::abs(offset * direction_), length, NumericT<float>::eps() * length);
409 }
410
411 return NumericT<float>::isEqual(NumericT<float>::abs(offset * direction_), length, NumericT<float>::eps());
412}
413
414template <typename T>
415T LineT3<T>::distance(const VectorT3<T>& point) const
416{
417 ocean_assert(isValid());
418 ocean_assert(hasUnitDirection());
419
420 const VectorT3<T> pointOnLine(nearestPoint(point));
421
422 return (pointOnLine - point).length();
423}
424
425template <typename T>
426T LineT3<T>::distance(const LineT3<T>& line) const
427{
428 // idea: creating a plane which intersect the second line and is parallel to the first line
429 // the distance is the projection of the vector between the two base point onto the plane normal
430
431 ocean_assert(isValid() && line.isValid());
432 ocean_assert(hasUnitDirection() && line.hasUnitDirection());
433
434 const VectorT3<T> offset(point_ - line.point_);
435
436 // if the base points of the two lines are identical
437 if (NumericT<T>::isEqualEps(offset.sqr()))
438 {
439 return T(0.0);
440 }
441
442 if (isParallel(line))
443 {
444 return (line.point_ - point_ + direction_ * (direction_ * offset)).length();
445 }
446
447 // plane normal
448 const VectorT3<T> normal(direction_.cross(line.direction_).normalizedOrZero());
449
450 // projection of point offset onto plane normal
451 return NumericT<T>::abs(offset * normal);
452}
453
454template <typename T>
456{
457 ocean_assert(isValid());
458 ocean_assert(hasUnitDirection());
459
460 const VectorT3<T> pointOnLine(nearestPoint(point));
461
462 return (pointOnLine - point).sqr();
463}
464
465template <typename T>
467{
468 ocean_assert(isValid());
469 ocean_assert(hasUnitDirection());
470
471 const VectorT3<T> offset(point - point_);
472
473 return point_ + direction_ * (direction_ * offset);
474}
475
476template <typename T>
477bool LineT3<T>::nearestPoint(const LineT3<T>& line, VectorT3<T>& middle) const
478{
479 ocean_assert(isValid() && line.isValid());
480 ocean_assert(hasUnitDirection() && line.hasUnitDirection());
481
482 VectorT3<T> first, second;
483 if (nearestPoints(line, first, second))
484 {
485 middle = (first + second) * T(0.5);
486 return true;
487 }
488
489 return false;
490}
491
492template <typename T>
493bool LineT3<T>::nearestPoints(const LineT3<T>& line, VectorT3<T>& first, VectorT3<T>& second) const
494{
495 ocean_assert(isValid() && line.isValid());
496 ocean_assert(hasUnitDirection() && line.hasUnitDirection());
497
498 if (isParallel(line))
499 {
500 return false;
501 }
502
503 const VectorT3<T> d = line.direction_ - direction_ * (direction_ * line.direction_);
504 const VectorT3<T> p = line.point_ - point_ + direction_ * (direction_ * point_);
505
506 const T denominator = d.sqr();
507
508 if (NumericT<T>::isEqualEps(denominator))
509 {
510 return false;
511 }
512
513 const T factor = - (p * d) / denominator;
514
515 second = line.point_ + line.direction_ * factor;
516 first = nearestPoint(second);
517
518 return true;
519}
520
521template <typename T>
522bool LineT3<T>::fitLineLeastSquare(const VectorT3<T>* points, const size_t size, LineT3<T>& line)
523{
524 static_assert(std::is_same<float, T>::value || std::is_same<double, T>::value, "Type T can be either float or double.");
525 ocean_assert(points != nullptr && size >= 2);
526
527 // Step 1: Compute the centroid (mean point)
528 VectorT3<T> centroid(T(0), T(0), T(0));
529
530 for (size_t i = 0; i < size; ++i)
531 {
532 centroid += points[i];
533 }
534
535 ocean_assert(size != 0);
536 const T invSize = T(1) / T(size);
537 centroid *= invSize;
538
539 // Step 2: Compute the covariance matrix
540 T cxx = T(0);
541 T cxy = T(0);
542 T cxz = T(0);
543 T cyy = T(0);
544 T cyz = T(0);
545 T czz = T(0);
546
547 for (size_t i = 0; i < size; ++i)
548 {
549 const VectorT3<T> diff = points[i] - centroid;
550
551 cxx += diff.x() * diff.x();
552 cxy += diff.x() * diff.y();
553 cxz += diff.x() * diff.z();
554 cyy += diff.y() * diff.y();
555 cyz += diff.y() * diff.z();
556 czz += diff.z() * diff.z();
557 }
558
559 // Step 3: Find the eigenvector with the largest eigenvalue using power iteration
560 const SquareMatrixT3<T> covarianceMatrix(cxx, cxy, cxz, cxy, cyy, cyz, cxz, cyz, czz);
561
562 // Initial guess - use the first point's direction from centroid, or a default if that fails
563 VectorT3<T> direction(T(1), T(0), T(0));
564
565 if (size >= 2)
566 {
567 const VectorT3<T> diff = points[0] - centroid;
568
569 if (!diff.isNull())
570 {
571 direction = diff.normalized();
572 }
573 }
574
575 // Power iteration to find the principal eigenvector
576 constexpr unsigned int maxIterations = 100u;
577
578 for (unsigned int iteration = 0u; iteration < maxIterations; ++iteration)
579 {
580 const VectorT3<T> newDirection = covarianceMatrix * direction;
581 const T length = newDirection.length();
582
583 if (NumericT<T>::isEqualEps(length))
584 {
585 return false;
586 }
587
588 const VectorT3<T> normalizedDirection = newDirection / length;
589
590 // Check for convergence
591 if (NumericT<T>::isEqual(NumericT<T>::abs(normalizedDirection * direction), T(1), NumericT<T>::weakEps()))
592 {
593 direction = normalizedDirection;
594 break;
595 }
596
597 direction = normalizedDirection;
598 }
599
600 if (direction.isNull())
601 {
602 return false;
603 }
604
605 line = LineT3<T>(centroid, direction);
606
607 return true;
608}
609
610} // namespace Ocean
611
612#endif // META_OCEAN_MATH_LINE_3_H
This class implements an infinite line in 3D space.
Definition Line3.h:69
bool isParallel(const LineT3< T > &right) const
Returns whether two lines are parallel up to a small epsilon.
Definition Line3.h:324
static bool fitLineLeastSquare(const VectorT3< T > *points, const size_t size, LineT3< T > &line)
Fits a line to a set of given 3D points by application of the least square measure.
Definition Line3.h:522
bool operator==(const LineT3< T > &right) const
Returns whether two line are identical up to a small epsilon.
Definition Line3.h:346
void setPoint(const VectorT3< T > &point)
Sets a point of this line.
Definition Line3.h:299
VectorT3< T > direction_
Direction of the line.
Definition Line3.h:260
T Type
Definition of the used data type.
Definition Line3.h:77
T sqrDistance(const VectorT3< T > &point) const
Returns the square distance between the line and a given point.
Definition Line3.h:455
bool isOnLine(const VectorT3< T > &point) const
Returns whether a given point is part of the line.
Definition Line3.h:366
void setDirection(const VectorT3< T > &direction)
Sets the direction of this line.
Definition Line3.h:305
bool isValid() const
Returns whether this line has valid parameters.
Definition Line3.h:312
const VectorT3< T > & direction() const
Returns the direction of the line.
Definition Line3.h:293
bool nearestPoints(const LineT3< T > &line, VectorT3< T > &first, VectorT3< T > &second) const
Returns the two nearest points for two crossing lines.
Definition Line3.h:493
VectorT3< T > nearestPoint(const VectorT3< T > &point) const
Returns the point on this line nearest to an arbitrary given point.
Definition Line3.h:466
friend class LineT3
Definition Line3.h:70
const VectorT3< T > & point() const
Returns a point on the line.
Definition Line3.h:280
LineT3()=default
Creates an invalid line.
VectorT3< T > point_
Point on the line.
Definition Line3.h:257
T distance(const VectorT3< T > &point) const
Returns the distance between the line and a given point.
Definition Line3.h:415
bool hasUnitDirection() const
Returns whether this line has a unit vector as direction.
Definition Line3.h:318
bool operator!=(const LineT3< T > &right) const
Returns whether two line are identical up to a small epsilon.
Definition Line3.h:354
This class provides basic numeric functionalities.
Definition Numeric.h:57
static T abs(const T value)
Returns the absolute value of a given value.
Definition Numeric.h:1220
static bool isEqual(const T first, const T second)
Returns whether two values are equal up to a small epsilon.
Definition Numeric.h:2395
This class implements a 3x3 square matrix.
Definition SquareMatrix3.h:89
This class implements a vector with three elements.
Definition Vector3.h:97
const T & y() const noexcept
Returns the y value.
Definition Vector3.h:824
const T & x() const noexcept
Returns the x value.
Definition Vector3.h:812
VectorT3< T > normalized() const
Returns the normalized vector.
Definition Vector3.h:617
const T & z() const noexcept
Returns the z value.
Definition Vector3.h:836
bool isNull() const
Returns whether this vector is a null vector up to a small epsilon.
Definition Vector3.h:866
T length() const
Returns the length of the vector.
Definition Vector3.h:676
T sqr() const
Returns the square of the vector length.
Definition Vector3.h:682
std::vector< LineT3< T > > LinesT3
Definition of a typename alias for vectors with LineT3 objects.
Definition Line3.h:49
std::vector< Line3 > Lines3
Definition of a vector holding Line3 objects.
Definition Line3.h:56
The namespace covering the entire Ocean framework.
Definition Accessor.h:15