Ocean
Cone3.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_CONE_3_H
9 #define META_OCEAN_MATH_CONE_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 ConeT3;
24 
25 /**
26  * Definition of the Cone3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single or double precision float data type.
27  * @see ConeT3
28  * @ingroup math
29  */
31 
32 /**
33  * Definition of a 3D cone with double values.
34  * @see ConeT3
35  * @ingroup math
36  */
38 
39 /**
40  * Definition of a 3D cone with float values.
41  * @see ConeT3
42  * @ingroup math
43  */
45 
46 /**
47  * Definition of a vector holding Cone3 objects.
48  * @see Cone3
49  * @ingroup math
50  */
51 typedef std::vector<Cone3> Cones3;
52 
53 /**
54  * This class implements a (possibly truncated) 3D cone.
55  * @ingroup math
56  */
57 template <typename T>
58 class ConeT3
59 {
60  public:
61 
62  /**
63  * Creates an invalid cone.
64  */
65  ConeT3() = default;
66 
67  /**
68  * Defines a new cone.
69  * @param apex 3D coordinate for the tip of the cone
70  * @param axis Direction vector of the cone's axis, expected to already be normalized to unit length
71  * @param apexAngle Angle in radians formed at the apex by any vertical slice of the cone through its apex, must be in (0, pi)
72  * @param minSignedDistanceAlongAxis For a truncated cone, the minimum signed distance along the cone's axis at which the cones stops, defaults to the apex of the cone (distance = 0); for an infinite cone, set the minimum radius to -infinity
73  * @param maxSignedDistanceAlongAxis For a truncated cone, the maximum signed distance along the cone's axis at which the cone stops; note that only horizontal slices (perpendicular to its axis) through the cone are supported
74  */
75  inline ConeT3(const VectorT3<T>& apex, const VectorT3<T>& axis, const T apexAngle, const T minSignedDistanceAlongAxis = T(0.0), const T maxSignedDistanceAlongAxis = std::numeric_limits<T>::infinity());
76 
77  /**
78  * Returns the tip of the cone.
79  * @return Cone apex
80  */
81  inline const VectorT3<T>& apex() const;
82 
83  /**
84  * Returns the unit-length axis of the cone.
85  * @return Cone axis
86  */
87  inline const VectorT3<T>& axis() const;
88 
89  /**
90  * Returns the angle made between diametrically opposite points on the cone and the apex.
91  * @return Cone's apex angle in radians, in range (0, pi)
92  */
93  inline T apexAngle() const;
94 
95  /**
96  * Returns the minimum signed truncation distance along the cone's axis. If the cone ends at its apex, the value is zero; otherwise, the value is simply less than maxSignedDistanceAlongAxis.
97  * @return Distance value, with range (-infinity, maxSignedDistanceAlongAxis)
98  */
99  inline const T& minSignedDistanceAlongAxis() const;
100 
101  /**
102  * Returns the maximum signed truncation distance along the cone's axis.
103  * @return Distance value, with range (minSignedDistanceAlongAxis, infinity)
104  */
105  inline const T& maxSignedDistanceAlongAxis() const;
106 
107  /**
108  * Returns the closest point of intersection of a ray with the *outer surface* of the cone, ignoring intersections with the cone's base and intersections that 1) exit the cone or 2) are a negative signed distance along the ray.
109  * @param ray Ray for which to find the intersection, must be valid
110  * @param point Output 3D point of intersection
111  * @return True if the computed intersection point is valid, otherwise false
112  */
113  bool nearestIntersection(const LineT3<T>& ray, VectorT3<T>& point) const;
114 
115  /**
116  * Returns whether this cone is valid.
117  * @return True, if so
118  */
119  inline bool isValid() const;
120 
121  protected:
122 
123  /// Cone tip.
124  VectorT3<T> apex_ = VectorT3<T>(T(0), T(0), T(0));
125 
126  /// Cone axis, a unit vector.
127  VectorT3<T> axis_ = VectorT3<T>(T(0), T(0), T(0));
128 
129  /// Cosine-squared of half of the cone's apex angle.
131 
132  /// Minimum signed truncation distance along the cone's axis.
134 
135  /// Maximum signed truncation distance along the cone's axis.
137 };
138 
139 template <typename T>
140 inline ConeT3<T>::ConeT3(const VectorT3<T>& apex, const VectorT3<T>& axis, const T apexAngle, const T minSignedDistanceAlongAxis, const T maxSignedDistanceAlongAxis) :
141  apex_(apex),
142  axis_(axis),
143  cosSquaredHalfApexAngle_(NumericT<T>::sqr(NumericT<T>::cos(T(0.5) * apexAngle))),
144  minSignedDistanceAlongAxis_(minSignedDistanceAlongAxis),
145  maxSignedDistanceAlongAxis_(maxSignedDistanceAlongAxis)
146 {
147  ocean_assert(NumericT<T>::isEqual(axis.length(), 1));
150 }
151 
152 template <typename T>
153 inline const VectorT3<T>& ConeT3<T>::apex() const
154 {
155  return apex_;
156 }
157 
158 template <typename T>
159 inline const VectorT3<T>& ConeT3<T>::axis() const
160 {
161  return axis_;
162 }
163 
164 template <typename T>
165 inline T ConeT3<T>::apexAngle() const
166 {
167  ocean_assert(cosSquaredHalfApexAngle_ >= Scalar(0.0));
168  return T(2.0) * NumericT<T>::acos(NumericT<T>::sqrt(cosSquaredHalfApexAngle_));
169 }
170 
171 template <typename T>
173 {
174  return maxSignedDistanceAlongAxis_;
175 }
176 
177 template <typename T>
179 {
180  return minSignedDistanceAlongAxis_;
181 }
182 
183 template <typename T>
185 {
186  ocean_assert(isValid() && ray.isValid());
187 
188  // Denote the cone apex as Q and its axis as q. Let the ray origin be C and its direction be d.
189  // The surface of the cone is defined as S = { X = \in R^3 | (1 / ||X - Q||) * (X - Q).q) = cos(theta/2), where theta is the apex angle of the cone.
190  // 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.
191  // Denoting V = C - Q and m = cos^2(theta/2), and then squaring the equation for the domain of S, we have
192  // (1 / ||V + t * d||^2) * [ (V + t * d).q ]^2 = m
193  // (V.q)^2 + 2 * t * V.q * d.q) + t^2 * (d.q)^2 = m * (V.V + t * 2 * V.d + t^2 * d.d) <= multiplied by ||.|| term and expanded
194  // => t^2 * ((d.q)^2 - m * d.d) + t * 2 * (V.q * d.q - m * V.d) + (V.q)^2 - m * V.V = 0, <= subtracted right side
195  // which we can then solve using the quadratic equation.
196 
197  const VectorT3<T> V = ray.point() - apex_;
198  const VectorT3<T>& d = ray.direction();
199  const VectorT3<T>& q = axis_;
200  const T& m = cosSquaredHalfApexAngle_;
201 
202  const T d_dot_q = d * q;
203  const T d_dot_d = d.sqr();
204  const T V_dot_q = V * q;
205  const T V_dot_d = V * d;
206  const T V_dot_V = V.sqr();
207 
208  T a = d_dot_q * d_dot_q - m * d_dot_d;
209  T b = T(2.0) * (V_dot_q * d_dot_q - m * V_dot_d);
210  T c = V_dot_q * V_dot_q - m * V_dot_V;
211 
212  // Normalize the quadratic before solving.
213  const T magnitude = std::max(std::max(NumericT<T>::abs(a), NumericT<T>::abs(b)), NumericT<T>::abs(c));
214  if (NumericT<T>::isNotEqualEps(magnitude))
215  {
216  a /= magnitude;
217  b /= magnitude;
218  c /= magnitude;
219  }
220 
221  T minDistance = T(-1.0);
222  T maxDistance = T(-1.0);
223 
224  // Check the corner case of a linear equation.
226  {
228  {
229  minDistance = -c / b;
230  maxDistance = minDistance;
231  }
232  }
233  else if (EquationT<T>::solveQuadratic(a, b, c, minDistance, maxDistance))
234  {
235  if (minDistance > maxDistance)
236  {
237  std::swap(minDistance, maxDistance);
238  }
239  }
240 
241  // If the minimum distance is negative, either the ray origin is inside the cone, or the ray does
242  // not intersect with the cone.
243  if (minDistance < T(0.0)) // use <= to disallow points exactly on the surface
244  {
245  return false;
246  }
247 
248  point = ray.point(minDistance);
249 
250  const T minIntersectionDistanceAlongAxis = (point - apex_) * axis_; // signed distance of point projected onto cone's axis
251 
252  bool intersectionIsValid = minIntersectionDistanceAlongAxis >= minSignedDistanceAlongAxis_ && minIntersectionDistanceAlongAxis <= maxSignedDistanceAlongAxis_;
253 
254  // We also have to check the case that the first intersection point actually exits the cone.
255  // In this case, the ray origin is inside the infinite cone and may or may not be inside the
256  // truncated cone, itself.
257  // \ /
258  // \ O / <- ray origin
259  // \| /
260  // A / <- first intersection (exit)
261  // |\/
262  // |/\
263  // B \ <- second intersection (entrance)
264  // /| \
265  // / | \
266  // / V \
267  //
268  // In this case, we'll return the second intersection point; this can be detected by checking
269  // whether there is a sign flip of the projected signed distance along the cone's axis between
270  // points A and B in the figure above. Note that we'll only return true, however, if point A is
271  // not also on the surface of the truncated cone (otherwise, B is "occluded").
272 
273  if (maxDistance > minDistance)
274  {
275  const VectorT3<T> maxPoint = ray.point(maxDistance);
276  const T maxIntersectionDistanceAlongAxis = (maxPoint - apex_) * axis_;
277 
278  if (NumericT<T>::sign(minIntersectionDistanceAlongAxis) != NumericT<T>::sign(maxIntersectionDistanceAlongAxis))
279  {
280  point = maxPoint;
281  intersectionIsValid = !intersectionIsValid && maxIntersectionDistanceAlongAxis >= minSignedDistanceAlongAxis_ && maxIntersectionDistanceAlongAxis <= maxSignedDistanceAlongAxis_;
282  }
283  }
284 
285  return intersectionIsValid;
286 }
287 
288 template <typename T>
289 inline bool ConeT3<T>::isValid() const
290 {
291  return cosSquaredHalfApexAngle_ > T(0.0) && maxSignedDistanceAlongAxis_ > minSignedDistanceAlongAxis_ && NumericT<T>::isEqual(axis_.sqr(), T(1.0));
292 }
293 
294 } // namespace Ocean
295 
296 #endif // META_OCEAN_MATH_CONE_3_H
This class implements a (possibly truncated) 3D cone.
Definition: Cone3.h:59
T cosSquaredHalfApexAngle_
Cosine-squared of half of the cone's apex angle.
Definition: Cone3.h:130
bool isValid() const
Returns whether this cone is valid.
Definition: Cone3.h:289
T minSignedDistanceAlongAxis_
Minimum signed truncation distance along the cone's axis.
Definition: Cone3.h:133
T maxSignedDistanceAlongAxis_
Maximum signed truncation distance along the cone's axis.
Definition: Cone3.h:136
ConeT3()=default
Creates an invalid cone.
T apexAngle() const
Returns the angle made between diametrically opposite points on the cone and the apex.
Definition: Cone3.h:165
VectorT3< T > apex_
Cone tip.
Definition: Cone3.h:124
const VectorT3< T > & axis() const
Returns the unit-length axis of the cone.
Definition: Cone3.h:159
VectorT3< T > axis_
Cone axis, a unit vector.
Definition: Cone3.h:127
const VectorT3< T > & apex() const
Returns the tip of the cone.
Definition: Cone3.h:153
const T & maxSignedDistanceAlongAxis() const
Returns the maximum signed truncation distance along the cone's axis.
Definition: Cone3.h:172
const T & minSignedDistanceAlongAxis() const
Returns the minimum signed truncation distance along the cone's axis.
Definition: Cone3.h:178
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 cone,...
Definition: Cone3.h:184
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 constexpr T sign(const T &value)
Returns the sign of a given value by either returning -1, 0, or +1.
Definition: Numeric.h:3256
static bool isEqual(const T first, const T second)
Returns whether two values are equal up to a small epsilon.
Definition: Numeric.h:2386
static T acos(const T value)
Returns the arccosine of a given value.
Definition: Numeric.h:2907
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
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition: base/Utilities.h:1029
ConeT3< Scalar > Cone3
Definition of the Cone3 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single o...
Definition: Cone3.h:23
float Scalar
Definition of a scalar type.
Definition: Math.h:128
std::vector< Cone3 > Cones3
Definition of a vector holding Cone3 objects.
Definition: Cone3.h:51
ConeT3< double > ConeD3
Definition of a 3D cone with double values.
Definition: Cone3.h:37
ConeT3< float > ConeF3
Definition of a 3D cone with float values.
Definition: Cone3.h:44
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15