Ocean
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"
13 #include "ocean/math/Vector3.h"
14 
15 #include <vector>
16 
17 namespace Ocean
18 {
19 
20 // Forward declaration.
21 template <typename T> class LineT3;
22 
23 /**
24  * Definition of the Line3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single or double precision float data type.
25  * @see LineT3
26  * @ingroup math
27  */
29 
30 /**
31  * Instantiation of the LineT3 template class using a double precision float data type.
32  * @see LineT3
33  * @ingroup math
34  */
36 
37 /**
38  * Instantiation of the LineT3 template class using a single precision float data type.
39  * @see LineT3
40  * @ingroup math
41  */
43 
44 /**
45  * Definition of a typename alias for vectors with LineT3 objects.
46  * @see LineT3
47  * @ingroup math
48  */
49 template <typename T>
50 using LinesT3 = std::vector<LineT3<T>>;
51 
52 /**
53  * Definition of a vector holding Line3 objects.
54  * @see Line3
55  * @ingroup math
56  */
57 typedef std::vector<Line3> Lines3;
58 
59 /**
60  * This class implements an infinite line in 3D space.
61  * The line is defined by a point lying on the line and a direction vector.<br>
62  * The direction vector must not be a zero vector.<br>
63  * The length of the vector may be arbitrary, however a unit vector is necessary for most functions.<br>
64  * @tparam T Data type used to represent lines
65  * @see Line3, LineF3, LineD3, FiniteLine3, FiniteLine3.
66  * @ingroup math
67  */
68 template <typename T>
69 class LineT3
70 {
71  template <typename U> friend class LineT3;
72 
73  public:
74 
75  /**
76  * Definition of the used data type.
77  */
78  typedef T Type;
79 
80  public:
81 
82  /**
83  * Creates an invalid line.
84  */
85  LineT3() = default;
86 
87  /**
88  * Creates a line defined by two different intersection points.
89  * @param point Intersection point on the line
90  * @param direction Vector representing the direction of the line, a unit vector might be appropriate
91  */
93 
94  /**
95  * Copies a line with different data type than T.
96  * @param line The line to copy
97  * @tparam U The data type of the second line
98  */
99  template <typename U>
100  inline explicit LineT3(const LineT3<U>& line);
101 
102  /**
103  * Returns a point on the line.
104  * @return Point on line
105  */
106  inline const VectorT3<T>& point() const;
107 
108  /**
109  * Returns a point on the line that is defined by a scalar.
110  * The result is determined by point() + direction() * distance;
111  * @param distance The distance to determine the line point for
112  * @return Point on line
113  */
114  inline const VectorT3<T> point(const T distance) const;
115 
116  /**
117  * Returns the direction of the line.
118  * @return Unit vector
119  */
120  inline const VectorT3<T>& direction() const;
121 
122  /**
123  * Sets a point of this line.
124  * @param point The point of this line
125  */
126  inline void setPoint(const VectorT3<T>& point);
127 
128  /**
129  * Sets the direction of this line.
130  * @param direction Vector defining the new direction, a unit vector might be appropriate
131  */
132  inline void setDirection(const VectorT3<T>& direction);
133 
134  /**
135  * Returns whether a given point is part of the line.
136  * This function needs a unit vector as direction!
137  * @param point The point to check
138  * @return True, if so
139  */
140  bool isOnLine(const VectorT3<T>& point) const;
141 
142  /**
143  * Returns the distance between the line and a given point.
144  * This function needs a unit vector as direction!
145  * @param point The point to return the distance for
146  * @return Positive distance between point and line, with range [0, infinity)
147  */
148  T distance(const VectorT3<T>& point) const;
149 
150  /**
151  * Returns the distance between two lines.
152  * This function needs a unit vector as direction!<br>
153  * @param line Second line to calculate the distance for
154  * @return Distance
155  */
156  T distance(const LineT3<T>& line) const;
157 
158  /**
159  * Returns the square distance between the line and a given point.
160  * This function needs a unit vector as direction!
161  * @param point The point to return the distance for
162  * @return The square distance between point and line, with range [0, infinity)
163  */
164  T sqrDistance(const VectorT3<T>& point) const;
165 
166  /**
167  * Returns the point on this line nearest to an arbitrary given point.
168  * This function needs a unit vector as direction!<br>
169  * @param point Arbitrary point outside the line
170  * @return Nearest point on the line
171  */
173 
174  /**
175  * Returns the middle of two nearest points for two crossing lines.
176  * This function needs a unit vector as direction!<br>
177  * Both lines must not be parallel.<br>
178  * @param line Second line to calculate the point for
179  * @param middle Nearest point between two lines
180  * @return True, if succeeded
181  */
182  bool nearestPoint(const LineT3<T>& line, VectorT3<T>& middle) const;
183 
184  /**
185  * Returns the two nearest points for two crossing lines.
186  * Both lines must not be parallel.<br>
187  * This function needs a unit vector as direction!<br>
188  * @param line Second line to calculate the points for
189  * @param first Nearest point on the first line
190  * @param second Nearest point on the second line
191  * @return True, if succeeded
192  */
193  bool nearestPoints(const LineT3<T>& line, VectorT3<T>& first, VectorT3<T>& second) const;
194 
195  /**
196  * Returns whether two lines are parallel up to a small epsilon.
197  * This function needs a unit vector as direction!
198  * @param right Second line
199  * @return True, if so
200  */
201  inline bool isParallel(const LineT3<T>& right) const;
202 
203  /**
204  * Returns whether this line and a given vector are parallel up to a small epsilon.
205  * This function needs a unit vector as direction!
206  * @param right Vector to be compared
207  * @return True, if so
208  */
209  inline bool isParallel(const VectorT3<T>& right) const;
210 
211  /**
212  * Returns whether this line has valid parameters.
213  * @return True, if so
214  */
215  inline bool isValid() const;
216 
217  /**
218  * Returns whether this line has a unit vector as direction.
219  * @return True, if so
220  */
221  inline bool hasUnitDirection() const;
222 
223  /**
224  * Returns whether two line are identical up to a small epsilon.
225  * This function needs a unit vector as direction!
226  * @param right The right line
227  * @return True, if so
228  */
229  inline bool operator==(const LineT3<T>& right) const;
230 
231  /**
232  * Returns whether two line are identical up to a small epsilon.
233  * This function needs a unit vector as direction!
234  * @param right The right line
235  * @return True, if so
236  */
237  inline bool operator!=(const LineT3<T>& right) const;
238 
239  /**
240  * Returns whether this line is valid.
241  * @return True, if so
242  */
243  explicit inline operator bool() const;
244 
245  protected:
246 
247  /// Point on the line.
249 
250  /// Direction of the line.
252 };
253 
254 template <typename T>
255 LineT3<T>::LineT3(const VectorT3<T>& first, const VectorT3<T>& direction) :
256  point_(first),
257  direction_(direction)
258 {
259  ocean_assert(!direction_.isNull());
260 }
261 
262 template <typename T>
263 template <typename U>
264 inline LineT3<T>::LineT3(const LineT3<U>& line)
265 {
266  point_ = VectorT3<T>(line.point_);
267  direction_ = VectorT3<T>(line.direction_);
268 }
269 
270 template <typename T>
271 inline const VectorT3<T>& LineT3<T>::point() const
272 {
273  return point_;
274 }
275 
276 template <typename T>
277 inline const VectorT3<T> LineT3<T>::point(const T distance) const
278 {
279  ocean_assert(isValid());
280  return point_ + direction_ * distance;
281 }
282 
283 template <typename T>
284 inline const VectorT3<T>& LineT3<T>::direction() const
285 {
286  return direction_;
287 }
288 
289 template <typename T>
290 inline void LineT3<T>::setPoint(const VectorT3<T>& point)
291 {
292  point_ = point;
293 }
294 
295 template <typename T>
296 inline void LineT3<T>::setDirection(const VectorT3<T>& direction)
297 {
298  ocean_assert(NumericT<T>::isEqual(direction.length(), T(1.0)));
299  direction_ = direction;
300 }
301 
302 template <typename T>
303 bool LineT3<T>::isValid() const
304 {
305  return !direction_.isNull();
306 }
307 
308 template <typename T>
309 inline bool LineT3<T>::hasUnitDirection() const
310 {
311  return NumericT<T>::isEqual(direction_.length(), T(1.0));
312 }
313 
314 template <typename T>
315 inline bool LineT3<T>::isParallel(const LineT3<T>& right) const
316 {
317  ocean_assert(isValid() && right.isValid());
318  ocean_assert(hasUnitDirection() && right.hasUnitDirection());
319 
320  const T scalarProduct = direction_ * right.direction_;
321 
322  return NumericT<T>::isEqual(NumericT<T>::abs(scalarProduct), T(1.0));
323 }
324 
325 template <typename T>
326 inline bool LineT3<T>::isParallel(const VectorT3<T>& right) const
327 {
328  ocean_assert(isValid());
329  ocean_assert(hasUnitDirection() && NumericT<T>::isEqual(right.length(), T(1.0)));
330 
331  const T scalarProduct = direction_ * right;
332 
333  return NumericT<T>::isEqual(NumericT<T>::abs(scalarProduct), T(1.0));
334 }
335 
336 template <typename T>
337 inline bool LineT3<T>::operator==(const LineT3<T>& right) const
338 {
339  ocean_assert(isValid() && right.isValid());
340 
341  return isParallel(right) && isOnLine(right.point());
342 }
343 
344 template <typename T>
345 inline bool LineT3<T>::operator!=(const LineT3<T>& right) const
346 {
347  return !(*this == right);
348 }
349 
350 template <typename T>
351 inline LineT3<T>::operator bool() const
352 {
353  return isValid();
354 }
355 
356 template <typename T>
357 bool LineT3<T>::isOnLine(const VectorT3<T>& point) const
358 {
359  ocean_assert(isValid());
360  ocean_assert(hasUnitDirection());
361 
362  const VectorT3<T> offset(point - point_);
363  const T length = offset.length();
364 
365  if (NumericT<T>::isEqualEps(length))
366  {
367  return true;
368  }
369 
370 #ifdef OCEAN_DEBUG
371  if (!std::is_same<T, float>::value)
372  {
373  ocean_assert(NumericT<T>::isEqual(NumericT<T>::abs((offset / length) * direction_), T(1.0))
374  == NumericT<T>::isEqual(NumericT<T>::abs(offset * direction_), length, NumericT<T>::eps() * length));
375  }
376 #endif
377 
378  // 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)
379  return NumericT<T>::isEqual(NumericT<T>::abs(offset * direction_), length, NumericT<T>::eps() * length);
380 }
381 
382 template <>
383 inline bool LineT3<float>::isOnLine(const VectorT3<float>& point) const
384 {
385  ocean_assert(isValid());
386  ocean_assert(hasUnitDirection());
387 
388  const VectorT3<float> offset(point - point_);
389  const float length = offset.length();
390 
391  if (NumericT<float>::isEqualEps(length))
392  {
393  return true;
394  }
395 
396  if (length > 1.0f)
397  {
398  // 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)
399  return NumericT<float>::isEqual(NumericT<float>::abs(offset * direction_), length, NumericT<float>::eps() * length);
400  }
401 
402  return NumericT<float>::isEqual(NumericT<float>::abs(offset * direction_), length, NumericT<float>::eps());
403 }
404 
405 template <typename T>
406 T LineT3<T>::distance(const VectorT3<T>& point) const
407 {
408  ocean_assert(isValid());
409  ocean_assert(hasUnitDirection());
410 
411  const VectorT3<T> pointOnLine(nearestPoint(point));
412 
413  return (pointOnLine - point).length();
414 }
415 
416 template <typename T>
417 T LineT3<T>::distance(const LineT3<T>& line) const
418 {
419  // idea: creating a plane which intersect the second line and is parallel to the first line
420  // the distance is the projection of the vector between the two base point onto the plane normal
421 
422  ocean_assert(isValid() && line.isValid());
423  ocean_assert(hasUnitDirection() && line.hasUnitDirection());
424 
425  const VectorT3<T> offset(point_ - line.point_);
426 
427  // if the base points of the two lines are identical
428  if (NumericT<T>::isEqualEps(offset.sqr()))
429  {
430  return T(0.0);
431  }
432 
433  if (isParallel(line))
434  {
435  return (line.point_ - point_ + direction_ * (direction_ * offset)).length();
436  }
437 
438  // plane normal
439  const VectorT3<T> normal(direction_.cross(line.direction_).normalizedOrZero());
440 
441  // projection of point offset onto plane normal
442  return NumericT<T>::abs(offset * normal);
443 }
444 
445 template <typename T>
446 T LineT3<T>::sqrDistance(const VectorT3<T>& point) const
447 {
448  ocean_assert(isValid());
449  ocean_assert(hasUnitDirection());
450 
451  const VectorT3<T> pointOnLine(nearestPoint(point));
452 
453  return (pointOnLine - point).sqr();
454 }
455 
456 template <typename T>
458 {
459  ocean_assert(isValid());
460  ocean_assert(hasUnitDirection());
461 
462  const VectorT3<T> offset(point - point_);
463 
464  return point_ + direction_ * (direction_ * offset);
465 }
466 
467 template <typename T>
468 bool LineT3<T>::nearestPoint(const LineT3<T>& line, VectorT3<T>& middle) const
469 {
470  ocean_assert(isValid() && line.isValid());
471  ocean_assert(hasUnitDirection() && line.hasUnitDirection());
472 
473  VectorT3<T> first, second;
474  if (nearestPoints(line, first, second))
475  {
476  middle = (first + second) * T(0.5);
477  return true;
478  }
479 
480  return false;
481 }
482 
483 template <typename T>
484 bool LineT3<T>::nearestPoints(const LineT3<T>& line, VectorT3<T>& first, VectorT3<T>& second) const
485 {
486  ocean_assert(isValid() && line.isValid());
487  ocean_assert(hasUnitDirection() && line.hasUnitDirection());
488 
489  if (isParallel(line))
490  {
491  return false;
492  }
493 
494  const VectorT3<T> d = line.direction_ - direction_ * (direction_ * line.direction_);
495  const VectorT3<T> p = line.point_ - point_ + direction_ * (direction_ * point_);
496 
497  const T denominator = d.sqr();
498 
499  if (NumericT<T>::isEqualEps(denominator))
500  {
501  return false;
502  }
503 
504  const T factor = - (p * d) / denominator;
505 
506  second = line.point_ + line.direction_ * factor;
507  first = nearestPoint(second);
508 
509  return true;
510 }
511 
512 }
513 
514 #endif // META_OCEAN_MATH_LINE_3_H
This class implements an infinite line in 3D space.
Definition: Line3.h:70
bool isParallel(const LineT3< T > &right) const
Returns whether two lines are parallel up to a small epsilon.
Definition: Line3.h:315
bool operator==(const LineT3< T > &right) const
Returns whether two line are identical up to a small epsilon.
Definition: Line3.h:337
void setPoint(const VectorT3< T > &point)
Sets a point of this line.
Definition: Line3.h:290
VectorT3< T > direction_
Direction of the line.
Definition: Line3.h:251
T sqrDistance(const VectorT3< T > &point) const
Returns the square distance between the line and a given point.
Definition: Line3.h:446
bool isOnLine(const VectorT3< T > &point) const
Returns whether a given point is part of the line.
Definition: Line3.h:357
void setDirection(const VectorT3< T > &direction)
Sets the direction of this line.
Definition: Line3.h:296
bool isValid() const
Returns whether this line has valid parameters.
Definition: Line3.h:303
const VectorT3< T > & direction() const
Returns the direction of the line.
Definition: Line3.h:284
T Type
Definition of the used data type.
Definition: Line3.h:78
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:484
VectorT3< T > nearestPoint(const VectorT3< T > &point) const
Returns the point on this line nearest to an arbitrary given point.
Definition: Line3.h:457
friend class LineT3
Definition: Line3.h:71
const VectorT3< T > & point() const
Returns a point on the line.
Definition: Line3.h:271
LineT3()=default
Creates an invalid line.
VectorT3< T > point_
Point on the line.
Definition: Line3.h:248
T distance(const VectorT3< T > &point) const
Returns the distance between the line and a given point.
Definition: Line3.h:406
bool hasUnitDirection() const
Returns whether this line has a unit vector as direction.
Definition: Line3.h:309
bool operator!=(const LineT3< T > &right) const
Returns whether two line are identical up to a small epsilon.
Definition: Line3.h:345
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:2386
This class implements a vector with three elements.
Definition: Vector3.h:97
T length() const
Returns the length of the vector.
Definition: Vector3.h:664
T sqr() const
Returns the square of the vector length.
Definition: Vector3.h:670
LineT3< Scalar > Line3
Definition of the Line3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single o...
Definition: Line3.h:21
LineT3< double > LineD3
Instantiation of the LineT3 template class using a double precision float data type.
Definition: Line3.h:35
std::vector< Line3 > Lines3
Definition of a vector holding Line3 objects.
Definition: Line3.h:57
LineT3< float > LineF3
Instantiation of the LineT3 template class using a single precision float data type.
Definition: Line3.h:42
std::vector< LineT3< T > > LinesT3
Definition of a typename alias for vectors with LineT3 objects.
Definition: Line3.h:50
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15