OpenVDB  12.0.0
Ray.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 /// @file Ray.h
5 ///
6 /// @author Ken Museth
7 ///
8 /// @brief A Ray class.
9 
10 #ifndef OPENVDB_MATH_RAY_HAS_BEEN_INCLUDED
11 #define OPENVDB_MATH_RAY_HAS_BEEN_INCLUDED
12 
13 #include "Math.h"
14 #include "Vec3.h"
15 #include "Transform.h"
16 #include <openvdb/util/Assert.h>
17 #include <algorithm> // for std::swap()
18 #include <iostream> // for std::ostream
19 #include <limits> // for std::numeric_limits<Type>::max()
20 
21 namespace openvdb {
23 namespace OPENVDB_VERSION_NAME {
24 namespace math {
25 
26 template<typename RealT = double>
27 class Ray
28 {
29 public:
30  static_assert(std::is_floating_point<RealT>::value,
31  "math::Ray requires a floating-point value type");
32 
33  using RealType = RealT;
35  using Vec3T = Vec3Type;
36 
37  struct TimeSpan {
38  RealT t0, t1;
39  /// @brief Default constructor
40  TimeSpan() {}
41  /// @brief Constructor
42  TimeSpan(RealT _t0, RealT _t1) : t0(_t0), t1(_t1) {}
43  /// @brief Set both times
44  inline void set(RealT _t0, RealT _t1) { t0=_t0; t1=_t1; }
45  /// @brief Get both times
46  inline void get(RealT& _t0, RealT& _t1) const { _t0=t0; _t1=t1; }
47  /// @brief Return @c true if t1 is larger than t0 by at least eps.
48  inline bool valid(RealT eps=math::Delta<RealT>::value()) const { return (t1-t0)>eps; }
49  /// @brief Return the midpoint of the ray.
50  inline RealT mid() const { return 0.5*(t0 + t1); }
51  /// @brief Multiplies both times
52  inline void scale(RealT s) {OPENVDB_ASSERT(s>0); t0*=s; t1*=s; }
53  /// @brief Return @c true if time is inclusive
54  inline bool test(RealT t) const { return (t>=t0 && t<=t1); }
55  };
56 
57  Ray(const Vec3Type& eye = Vec3Type(0,0,0),
58  const Vec3Type& direction = Vec3Type(1,0,0),
59  RealT t0 = math::Delta<RealT>::value(),
61  : mEye(eye), mDir(direction), mInvDir(1/mDir), mTimeSpan(t0, t1)
62  {
63  }
64 
65  inline void setEye(const Vec3Type& eye) { mEye = eye; }
66 
67  inline void setDir(const Vec3Type& dir)
68  {
69  mDir = dir;
70  mInvDir = 1/mDir;
71  }
72 
73  inline void setMinTime(RealT t0) { OPENVDB_ASSERT(t0>0); mTimeSpan.t0 = t0; }
74 
75  inline void setMaxTime(RealT t1) { OPENVDB_ASSERT(t1>0); mTimeSpan.t1 = t1; }
76 
77  inline void setTimes(
78  RealT t0 = math::Delta<RealT>::value(),
80  {
81  OPENVDB_ASSERT(t0>0 && t1>0);
82  mTimeSpan.set(t0, t1);
83  }
84 
85  inline void scaleTimes(RealT scale) { mTimeSpan.scale(scale); }
86 
87  inline void reset(
88  const Vec3Type& eye,
89  const Vec3Type& direction,
90  RealT t0 = math::Delta<RealT>::value(),
92  {
93  this->setEye(eye);
94  this->setDir(direction);
95  this->setTimes(t0, t1);
96  }
97 
98  inline const Vec3T& eye() const {return mEye;}
99 
100  inline const Vec3T& dir() const {return mDir;}
101 
102  inline const Vec3T& invDir() const {return mInvDir;}
103 
104  inline RealT t0() const {return mTimeSpan.t0;}
105 
106  inline RealT t1() const {return mTimeSpan.t1;}
107 
108  /// @brief Return the position along the ray at the specified time.
109  inline Vec3R operator()(RealT time) const { return mEye + mDir * time; }
110 
111  /// @brief Return the starting point of the ray.
112  inline Vec3R start() const { return (*this)(mTimeSpan.t0); }
113 
114  /// @brief Return the endpoint of the ray.
115  inline Vec3R end() const { return (*this)(mTimeSpan.t1); }
116 
117  /// @brief Return the midpoint of the ray.
118  inline Vec3R mid() const { return (*this)(mTimeSpan.mid()); }
119 
120  /// @brief Return @c true if t1 is larger than t0 by at least eps.
121  inline bool valid(RealT eps=math::Delta<float>::value()) const { return mTimeSpan.valid(eps); }
122 
123  /// @brief Return @c true if @a time is within t0 and t1, both inclusive.
124  inline bool test(RealT time) const { return mTimeSpan.test(time); }
125 
126  /// @brief Return a new Ray that is transformed with the specified map.
127  /// @param map the map from which to construct the new Ray.
128  /// @warning Assumes a linear map and a normalized direction.
129  /// @details The requirement that the direction is normalized
130  /// follows from the transformation of t0 and t1 - and that fact that
131  /// we want applyMap and applyInverseMap to be inverse operations.
132  template<typename MapType>
133  inline Ray applyMap(const MapType& map) const
134  {
135  OPENVDB_ASSERT(map.isLinear());
136  OPENVDB_ASSERT(math::isRelOrApproxEqual(mDir.length(), RealT(1),
138  const Vec3T eye = map.applyMap(mEye);
139  const Vec3T dir = map.applyJacobian(mDir);
140  const RealT length = dir.length();
141  return Ray(eye, dir/length, length*mTimeSpan.t0, length*mTimeSpan.t1);
142  }
143 
144  /// @brief Return a new Ray that is transformed with the inverse of the specified map.
145  /// @param map the map from which to construct the new Ray by inverse mapping.
146  /// @warning Assumes a linear map and a normalized direction.
147  /// @details The requirement that the direction is normalized
148  /// follows from the transformation of t0 and t1 - and that fact that
149  /// we want applyMap and applyInverseMap to be inverse operations.
150  template<typename MapType>
151  inline Ray applyInverseMap(const MapType& map) const
152  {
153  OPENVDB_ASSERT(map.isLinear());
155  const Vec3T eye = map.applyInverseMap(mEye);
156  const Vec3T dir = map.applyInverseJacobian(mDir);
157  const RealT length = dir.length();
158  return Ray(eye, dir/length, length*mTimeSpan.t0, length*mTimeSpan.t1);
159  }
160 
161  /// @brief Return a new ray in world space, assuming the existing
162  /// ray is represented in the index space of the specified grid.
163  template<typename GridType>
164  inline Ray indexToWorld(const GridType& grid) const
165  {
166  return this->applyMap(*(grid.transform().baseMap()));
167  }
168 
169  /// @brief Return a new ray in the index space of the specified
170  /// grid, assuming the existing ray is represented in world space.
171  template<typename GridType>
172  inline Ray worldToIndex(const GridType& grid) const
173  {
174  return this->applyInverseMap(*(grid.transform().baseMap()));
175  }
176 
177  /// @brief Return true if this ray intersects the specified sphere.
178  /// @param center The center of the sphere in the same space as this ray.
179  /// @param radius The radius of the sphere in the same units as this ray.
180  /// @param t0 The first intersection point if an intersection exists.
181  /// @param t1 The second intersection point if an intersection exists.
182  /// @note If the return value is true, i.e. a hit, and t0 =
183  /// this->t0() or t1 == this->t1() only one true intersection exist.
184  inline bool intersects(const Vec3T& center, RealT radius, RealT& t0, RealT& t1) const
185  {
186  const Vec3T origin = mEye - center;
187  const RealT A = mDir.lengthSqr();
188  const RealT B = 2 * mDir.dot(origin);
189  const RealT C = origin.lengthSqr() - radius * radius;
190  const RealT D = B * B - 4 * A * C;
191 
192  if (D < 0) return false;
193 
194  const RealT Q = RealT(-0.5)*(B<0 ? (B + Sqrt(D)) : (B - Sqrt(D)));
195 
196  t0 = Q / A;
197  t1 = C / Q;
198 
199  if (t0 > t1) std::swap(t0, t1);
200  if (t0 < mTimeSpan.t0) t0 = mTimeSpan.t0;
201  if (t1 > mTimeSpan.t1) t1 = mTimeSpan.t1;
202  return t0 <= t1;
203  }
204 
205  /// @brief Return true if this ray intersects the specified sphere.
206  /// @param center The center of the sphere in the same space as this ray.
207  /// @param radius The radius of the sphere in the same units as this ray.
208  inline bool intersects(const Vec3T& center, RealT radius) const
209  {
210  RealT t0, t1;
211  return this->intersects(center, radius, t0, t1)>0;
212  }
213 
214  /// @brief Return true if this ray intersects the specified sphere.
215  /// @note For intersection this ray is clipped to the two intersection points.
216  /// @param center The center of the sphere in the same space as this ray.
217  /// @param radius The radius of the sphere in the same units as this ray.
218  inline bool clip(const Vec3T& center, RealT radius)
219  {
220  RealT t0, t1;
221  const bool hit = this->intersects(center, radius, t0, t1);
222  if (hit) mTimeSpan.set(t0, t1);
223  return hit;
224  }
225 
226  /// @brief Return true if the Ray intersects the specified
227  /// axisaligned bounding box.
228  /// @param bbox Axis-aligned bounding box in the same space as the Ray.
229  /// @param t0 If an intersection is detected this is assigned
230  /// the time for the first intersection point.
231  /// @param t1 If an intersection is detected this is assigned
232  /// the time for the second intersection point.
233  template<typename BBoxT>
234  inline bool intersects(const BBoxT& bbox, RealT& t0, RealT& t1) const
235  {
236  mTimeSpan.get(t0, t1);
237  for (int i = 0; i < 3; ++i) {
238  RealT a = (bbox.min()[i] - mEye[i]) * mInvDir[i];
239  RealT b = (bbox.max()[i] - mEye[i]) * mInvDir[i];
240  if (a > b) std::swap(a, b);
241  if (a > t0) t0 = a;
242  if (b < t1) t1 = b;
243  if (t0 > t1) return false;
244  }
245  return true;
246  }
247 
248  /// @brief Return true if this ray intersects the specified bounding box.
249  /// @param bbox Axis-aligned bounding box in the same space as this ray.
250  template<typename BBoxT>
251  inline bool intersects(const BBoxT& bbox) const
252  {
253  RealT t0, t1;
254  return this->intersects(bbox, t0, t1);
255  }
256 
257  /// @brief Return true if this ray intersects the specified bounding box.
258  /// @note For intersection this ray is clipped to the two intersection points.
259  /// @param bbox Axis-aligned bounding box in the same space as this ray.
260  template<typename BBoxT>
261  inline bool clip(const BBoxT& bbox)
262  {
263  RealT t0, t1;
264  const bool hit = this->intersects(bbox, t0, t1);
265  if (hit) mTimeSpan.set(t0, t1);
266  return hit;
267  }
268 
269  /// @brief Return true if the Ray intersects the plane specified
270  /// by a normal and distance from the origin.
271  /// @param normal Normal of the plane.
272  /// @param distance Distance of the plane to the origin.
273  /// @param t Time of intersection, if one exists.
274  inline bool intersects(const Vec3T& normal, RealT distance, RealT& t) const
275  {
276  const RealT cosAngle = mDir.dot(normal);
277  if (math::isApproxZero(cosAngle)) return false;//parallel
278  t = (distance - mEye.dot(normal))/cosAngle;
279  return this->test(t);
280  }
281 
282  /// @brief Return true if the Ray intersects the plane specified
283  /// by a normal and point.
284  /// @param normal Normal of the plane.
285  /// @param point Point in the plane.
286  /// @param t Time of intersection, if one exists.
287  inline bool intersects(const Vec3T& normal, const Vec3T& point, RealT& t) const
288  {
289  return this->intersects(normal, point.dot(normal), t);
290  }
291 
292 private:
293  Vec3T mEye, mDir, mInvDir;
294  TimeSpan mTimeSpan;
295 }; // end of Ray class
296 
297 
298 /// @brief Output streaming of the Ray class.
299 /// @note Primarily intended for debugging.
300 template<typename RealT>
301 inline std::ostream& operator<<(std::ostream& os, const Ray<RealT>& r)
302 {
303  os << "eye=" << r.eye() << " dir=" << r.dir() << " 1/dir="<<r.invDir()
304  << " t0=" << r.t0() << " t1=" << r.t1();
305  return os;
306 }
307 
308 } // namespace math
309 } // namespace OPENVDB_VERSION_NAME
310 } // namespace openvdb
311 
312 #endif // OPENVDB_MATH_RAY_HAS_BEEN_INCLUDED
TimeSpan(RealT _t0, RealT _t1)
Constructor.
Definition: Ray.h:42
Ray indexToWorld(const GridType &grid) const
Return a new ray in world space, assuming the existing ray is represented in the index space of the s...
Definition: Ray.h:164
const Vec3T & dir() const
Definition: Ray.h:100
void setDir(const Vec3Type &dir)
Definition: Ray.h:67
Tolerance for floating-point comparison.
Definition: Math.h:148
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
bool intersects(const Vec3T &center, RealT radius, RealT &t0, RealT &t1) const
Return true if this ray intersects the specified sphere.
Definition: Ray.h:184
bool intersects(const Vec3T &center, RealT radius) const
Return true if this ray intersects the specified sphere.
Definition: Ray.h:208
Definition: Ray.h:27
Vec3R end() const
Return the endpoint of the ray.
Definition: Ray.h:115
const Vec3T & invDir() const
Definition: Ray.h:102
TimeSpan()
Default constructor.
Definition: Ray.h:40
void setEye(const Vec3Type &eye)
Definition: Ray.h:65
void setMaxTime(RealT t1)
Definition: Ray.h:75
void setMinTime(RealT t0)
Definition: Ray.h:73
Vec3R start() const
Return the starting point of the ray.
Definition: Ray.h:112
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
RealT t1() const
Definition: Ray.h:106
void scaleTimes(RealT scale)
Definition: Ray.h:85
bool valid(RealT eps=math::Delta< float >::value()) const
Return true if t1 is larger than t0 by at least eps.
Definition: Ray.h:121
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
Definition: Math.h:349
Ray(const Vec3Type &eye=Vec3Type(0, 0, 0), const Vec3Type &direction=Vec3Type(1, 0, 0), RealT t0=math::Delta< RealT >::value(), RealT t1=std::numeric_limits< RealT >::max())
Definition: Ray.h:57
bool intersects(const Vec3T &normal, const Vec3T &point, RealT &t) const
Return true if the Ray intersects the plane specified by a normal and point.
Definition: Ray.h:287
const Vec3T & eye() const
Definition: Ray.h:98
void reset(const Vec3Type &eye, const Vec3Type &direction, RealT t0=math::Delta< RealT >::value(), RealT t1=std::numeric_limits< RealT >::max())
Definition: Ray.h:87
bool intersects(const Vec3T &normal, RealT distance, RealT &t) const
Return true if the Ray intersects the plane specified by a normal and distance from the origin...
Definition: Ray.h:274
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:615
Vec3R mid() const
Return the midpoint of the ray.
Definition: Ray.h:118
Ray applyInverseMap(const MapType &map) const
Return a new Ray that is transformed with the inverse of the specified map.
Definition: Ray.h:151
Definition: Exceptions.h:13
Ray worldToIndex(const GridType &grid) const
Return a new ray in the index space of the specified grid, assuming the existing ray is represented i...
Definition: Ray.h:172
bool isRelOrApproxEqual(const Type &a, const Type &b, const Type &absTol, const Type &relTol)
Definition: Math.h:453
bool valid(RealT eps=math::Delta< RealT >::value()) const
Return true if t1 is larger than t0 by at least eps.
Definition: Ray.h:48
bool clip(const Vec3T &center, RealT radius)
Return true if this ray intersects the specified sphere.
Definition: Ray.h:218
void scale(RealT s)
Multiplies both times.
Definition: Ray.h:52
double RealType
Definition: Ray.h:33
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:219
void setTimes(RealT t0=math::Delta< RealT >::value(), RealT t1=std::numeric_limits< RealT >::max())
Definition: Ray.h:77
bool clip(const BBoxT &bbox)
Return true if this ray intersects the specified bounding box.
Definition: Ray.h:261
bool test(RealT t) const
Return true if time is inclusive.
Definition: Ray.h:54
Ray applyMap(const MapType &map) const
Return a new Ray that is transformed with the specified map.
Definition: Ray.h:133
Delta for small floating-point offsets.
Definition: Math.h:155
RealT mid() const
Return the midpoint of the ray.
Definition: Ray.h:50
bool intersects(const BBoxT &bbox) const
Return true if this ray intersects the specified bounding box.
Definition: Ray.h:251
RealT t0() const
Definition: Ray.h:104
T length() const
Length of the vector.
Definition: Vec3.h:201
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:761
T lengthSqr() const
Definition: Vec3.h:212
T dot(const Vec3< T > &v) const
Dot product.
Definition: Vec3.h:192
RealT t1
Definition: Ray.h:38
Vec3R operator()(RealT time) const
Return the position along the ray at the specified time.
Definition: Ray.h:109
bool test(RealT time) const
Return true if time is within t0 and t1, both inclusive.
Definition: Ray.h:124
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218
bool intersects(const BBoxT &bbox, RealT &t0, RealT &t1) const
Return true if the Ray intersects the specified axisaligned bounding box.
Definition: Ray.h:234