Ocean
Cylinder3.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_CYLINDER_3_H
9 #define META_OCEAN_MATH_CYLINDER_3_H
10 
11 #include "ocean/math/Math.h"
12 
13 #include "ocean/math/Equation.h"
14 #include "ocean/math/Line3.h"
15 #include "ocean/math/Numeric.h"
16 #include "ocean/math/Vector3.h"
17 
18 namespace Ocean
19 {
20 
21 // Forward declaration.
22 template <typename T>
23 class CylinderT3;
24 
25 /**
26  * Definition of the Cylinder3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single or double precision float data type.
27  * @see CylinderT3
28  * @ingroup math
29  */
31 
32 /**
33  * Definition of a 3D cylinder with double values.
34  * @see CylinderT3
35  * @ingroup math
36  */
38 
39 /**
40  * Definition of a 3D cylinder with float values.
41  * @see CylinderT3
42  * @ingroup math
43  */
45 
46 /**
47  * Definition of a vector holding Cylinder3 objects.
48  * @see Cylinder3
49  * @ingroup math
50  */
51 typedef std::vector<Cylinder3> Cylinders3;
52 
53 /**
54  * This class implements a 3D cylinder defined by its origin, axis, radius, and (signed) starting and stopping points along its axis.
55  *
56  * Consider a finite right cylinder, consisting of (1) two circular endcaps that lie in parallel planes and (2) the curved surface connecting the endcaps.
57  * Let one of these endcaps be the "bottom base" and the other endcap be the "top base" of the cylinder.
58  * The cylinder axis is the unit vector pointing from the center of the bottom base to the center of
59  * the top base.
60  * Since we are considering a right (i.e., non-oblique) cylinder, each cylinder base is perpendicular to the axis.
61  *
62  * Each cylinder has a 4DOF coordinate frame consisting of the line through its axis in 3D space.
63  * The cylinder origin can be defined using any 3D point lying on this line.
64  * The 3D center point of each cylinder base also lies on this line, at a fixed 1D distance along
65  * the line from the cylinder origin:
66  * bottom = origin + minSignedDistance * axis,
67  * top = origin + maxSignedDistance * axis.
68  *
69  * The cylinder radius, r, is defined as the radius of the two circular endcaps.
70  * For any 3D point X lying on the cylinder surface between the endcaps, the distance to the nearest point on the cylinder center-line is r.
71  *
72  * Note that the origin does not need to lie within the cylinder.
73  * Infinite cylinders (without endcaps) and half-infinite cylinders (with only one endcap) are also allowed.
74  *
75  * Currently, cylinder-ray intersection checking is only supported for portion of the cylinder between its endcaps. Ray intersections with cylinder endcaps are not computed.
76  * @ingroup math
77  */
78 template <typename T>
80 {
81  public:
82 
83  /**
84  * Creates an invalid cylinder.
85  */
86  inline CylinderT3();
87 
88  /**
89  * Defines a new cylinder with a base along its axis at distance = 0 and with the specified height (positive distance along the axis).
90  * @param origin 3D coordinate for the center of the base of the cylinder
91  * @param axis Direction vector of the cylinder's axis, expected to already be normalized to unit length
92  * @param radius Radius of the cylinder, with range (0, infinity)
93  * @param height The height of the cylinder, with range [0, infinity]
94  */
95  inline CylinderT3(const VectorT3<T>& origin, const VectorT3<T>& axis, const T radius, const T height);
96 
97  /**
98  * Defines a new cylinder.
99  * @param origin 3D coordinate for the center of the base of the cylinder
100  * @param axis Direction vector of the cylinder's axis, expected to already be normalized to unit length
101  * @param radius Radius of the cylinder, with range (0, infinity)
102  * @param minSignedDistanceAlongAxis Signed distance along the axis for the bottom of the cylinder, with range [-infinity, maxSignedDistanceAlongAxis]
103  * @param maxSignedDistanceAlongAxis Signed distance along the axis for the top of the cylinder, with range [minSignedDistanceAlongAxis, infinity]
104  */
106 
107  /**
108  * Returns the center of the cylinder's base
109  * @return Cylinder origin
110  */
111  inline const VectorT3<T>& origin() const;
112 
113  /**
114  * Returns the unit-length axis of the cylinder.
115  * @return Cylinder axis
116  */
117  inline const VectorT3<T>& axis() const;
118 
119  /**
120  * Returns the radius of the cylinder
121  * @return Cylinder radius, with range (0, infinity)
122  */
123  inline const T& radius() const;
124 
125  /**
126  * Returns the minimum signed truncation distance along the cylinder's axis.
127  * @return Distance value, with range [-infinity, maxSignedDistanceAlongAxis]
128  */
129  inline const T& minSignedDistanceAlongAxis() const;
130 
131  /**
132  * Returns the maximum signed truncation distance along the cylinder's axis.
133  * @return Distance value, with range [minSignedDistanceAlongAxis, infinity]
134  */
135  inline const T& maxSignedDistanceAlongAxis() const;
136 
137  /**
138  * Returns the length of the cylinder along its axis
139  * @return Cylinder's height, with range [0, infinity]
140  */
141  inline T height() const;
142 
143  /**
144  * Returns the closest point of intersection of a ray with the *outer surface* of the cylinder, ignoring intersections with the cylinder's base and intersections that 1) exit the cylinder or 2) are a negative signed distance along the ray.
145  * @param ray Ray for which to find the intersection, must be valid
146  * @param point Output 3D point of intersection
147  * @return True if the computed intersection point is valid, otherwie false
148  */
149  bool nearestIntersection(const LineT3<T>& ray, VectorT3<T>& point) const;
150 
151  /**
152  * Returns whether this cylinder is valid.
153  * @return True, if so
154  */
155  inline bool isValid() const;
156 
157  protected:
158 
159  /// Center of the cylinder's base
161 
162  /// Cylinder axis, a unit vector.
164 
165  /// Radius of the cylinder.
167 
168  /// Minimum signed truncation distance along the cone's axis.
170 
171  /// Maximum signed truncation distance along the cone's axis.
173 };
174 
175 template <typename T>
177  origin_(0.0, 0.0, 0.0),
178  axis_(0.0, 0.0, 0.0),
179  radius_(0.0),
180  minSignedDistanceAlongAxis_(0.0),
181  maxSignedDistanceAlongAxis_(0.0)
182 {
183  // nothing to do here
184 }
185 
186 template <typename T>
187 inline CylinderT3<T>::CylinderT3(const VectorT3<T>& origin, const VectorT3<T>& axis, const T radius, const T height) :
188  CylinderT3(origin, axis, radius, T(0.0), height)
189 {
190  // nothing to do here
191 }
192 
193 template <typename T>
194 CylinderT3<T>::CylinderT3(const VectorT3<T>& origin, const VectorT3<T>& axis, const T radius, const T minSignedDistanceAlongAxis, const T maxSignedDistanceAlongAxis) :
195  origin_(origin),
196  axis_(axis),
197  radius_(radius),
198  minSignedDistanceAlongAxis_(minSignedDistanceAlongAxis),
199  maxSignedDistanceAlongAxis_(maxSignedDistanceAlongAxis)
200 {
201  ocean_assert(NumericT<T>::isEqual(axis.length(), 1));
203 }
204 
205 template <typename T>
206 inline const VectorT3<T>& CylinderT3<T>::origin() const
207 {
208  return origin_;
209 }
210 
211 template <typename T>
212 inline const VectorT3<T>& CylinderT3<T>::axis() const
213 {
214  return axis_;
215 }
216 
217 template <typename T>
218 inline const T& CylinderT3<T>::radius() const
219 {
220  return radius_;
221 }
222 
223 template <typename T>
225 {
226  return minSignedDistanceAlongAxis_;
227 }
228 
229 template <typename T>
231 {
232  return maxSignedDistanceAlongAxis_;
233 }
234 
235 template <typename T>
236 inline T CylinderT3<T>::height() const
237 {
238  return maxSignedDistanceAlongAxis_ - minSignedDistanceAlongAxis_;
239 }
240 
241 template <typename T>
242 bool CylinderT3<T>::nearestIntersection(const LineT3<T>& ray, VectorT3<T>& intersection) const
243 {
244  ocean_assert(isValid() && ray.isValid());
245 
246  // First, we'll compute the intersection of the ray with an infinite cylinder -- i.e., we'll ignore the end caps of the cylinder.
247  // We'll then check if the intersection point falls between the cylinder caps (if applicable).
248  //
249  // Denote the cylinder origin as Q, its axis by unit vector q, and its radius as r.
250  // When Q is projected onto the 2D plane perpendicular to q, the projected point lies at the origin.
251  // The surface of the (infinite) cylinder is defined as
252  //
253  // S = { X \in R^3 | || (X - Q) - ((X - Q)^T * q) * q || = r },
254  //
255  // i.e., project 3D point X onto the 2D plane perpendicular to q, and check that this projected point lies on the circle with radius r.
256  //
257  // Denote the ray origin as C and its unit direction vector as d.
258  // An intersection point P \in S satisfies P = C + t * d, where t is the signed distance from the ray origin. We find values of t, accordingly.
259  //
260  // Denoting V = C - Q and then squaring the equation for the domain of S, we have
261  //
262  // [ V + t * d - ((V + t * d)^T * q) * q ]^2 = r^2,
263  //
264  // which reduces to
265  //
266  // [ d^T * d - (d^T * q)^2 ] * t^2 + 2 * [ d^T * V - (d^T * q) * (V^T * q) ] * t + [ (V^T * V) - (V^T * q)^2 - r^2] = 0,
267  //
268  // which we can then solve using the quadratic equation.
269 
270  const VectorT3<T> V = ray.point() - origin_;
271  const VectorT3<T>& d = ray.direction();
272  const VectorT3<T>& q = axis_;
273 
274  const T d_dot_q = d * q;
275  const T d_dot_d = d.sqr();
276  const T V_dot_q = V * q;
277  const T V_dot_d = V * d;
278  const T V_dot_V = V.sqr();
279 
280  const T a = d_dot_d - d_dot_q * d_dot_q;
281  const T b = T(2.) * (V_dot_d - d_dot_q * V_dot_q);
282  const T c = V_dot_V - V_dot_q * V_dot_q - radius_ * radius_;
283 
284  T minDistance = T(-1.), maxDistance = T(-1.);
285 
286  if (EquationT<T>::solveQuadratic(a, b, c, minDistance, maxDistance))
287  {
288  minDistance = min(minDistance, maxDistance);
289  }
290  else
291  {
292  // Check the corner case of a linear equation (the axis and direction are parallel, and the
293  // point might be on the surface).
295  {
296  minDistance = -c / b;
297  }
298  }
299 
300  if (minDistance < T(0.)) // use <= to disallow points exactly on the surface
301  {
302  return false;
303  }
304 
305  intersection = ray.point(minDistance);
306 
307  const T distanceAlongAxis = (intersection - origin_) * axis_; // signed distance of the intersection point projected onto the cylinder's axis
308  return (distanceAlongAxis >= minSignedDistanceAlongAxis_ && distanceAlongAxis <= maxSignedDistanceAlongAxis_);
309 }
310 
311 template <typename T>
312 inline bool CylinderT3<T>::isValid() const
313 {
314  return radius_ > T(0.) && maxSignedDistanceAlongAxis_ >= minSignedDistanceAlongAxis_ && NumericT<T>::isEqual(axis_.sqr(), T(1.));
315 }
316 
317 } // namespace Ocean
318 
319 #endif // META_OCEAN_MATH_CYLINDER_3_H
320 
This class implements a 3D cylinder defined by its origin, axis, radius, and (signed) starting and st...
Definition: Cylinder3.h:80
VectorT3< T > origin_
Center of the cylinder's base.
Definition: Cylinder3.h:160
const T & maxSignedDistanceAlongAxis() const
Returns the maximum signed truncation distance along the cylinder's axis.
Definition: Cylinder3.h:230
bool isValid() const
Returns whether this cylinder is valid.
Definition: Cylinder3.h:312
const VectorT3< T > & axis() const
Returns the unit-length axis of the cylinder.
Definition: Cylinder3.h:212
const T & radius() const
Returns the radius of the cylinder.
Definition: Cylinder3.h:218
T maxSignedDistanceAlongAxis_
Maximum signed truncation distance along the cone's axis.
Definition: Cylinder3.h:172
VectorT3< T > axis_
Cylinder axis, a unit vector.
Definition: Cylinder3.h:163
T radius_
Radius of the cylinder.
Definition: Cylinder3.h:166
bool nearestIntersection(const LineT3< T > &ray, VectorT3< T > &point) const
Returns the closest point of intersection of a ray with the outer surface of the cylinder,...
Definition: Cylinder3.h:242
T height() const
Returns the length of the cylinder along its axis.
Definition: Cylinder3.h:236
CylinderT3()
Creates an invalid cylinder.
Definition: Cylinder3.h:176
const VectorT3< T > & origin() const
Returns the center of the cylinder's base.
Definition: Cylinder3.h:206
const T & minSignedDistanceAlongAxis() const
Returns the minimum signed truncation distance along the cylinder's axis.
Definition: Cylinder3.h:224
T minSignedDistanceAlongAxis_
Minimum signed truncation distance along the cone's axis.
Definition: Cylinder3.h:169
This class provides several functions to solve equations with different degree using floating point v...
Definition: Equation.h:53
This class implements an infinite line in 3D space.
Definition: Line3.h:70
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
const VectorT3< T > & point() const
Returns a point on the line.
Definition: Line3.h:271
This class provides basic numeric functionalities.
Definition: Numeric.h:57
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 sqr() const
Returns the square of the vector length.
Definition: Vector3.h:670
CylinderT3< double > CylinderD3
Definition of a 3D cylinder with double values.
Definition: Cylinder3.h:37
std::vector< Cylinder3 > Cylinders3
Definition of a vector holding Cylinder3 objects.
Definition: Cylinder3.h:51
CylinderT3< Scalar > Cylinder3
Definition of the Cylinder3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with sing...
Definition: Cylinder3.h:23
CylinderT3< float > CylinderF3
Definition of a 3D cylinder with float values.
Definition: Cylinder3.h:44
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15