1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_GF_RAY_H
25 #define PXR_BASE_GF_RAY_H
26 
27 /// \file gf/ray.h
28 /// \ingroup group_gf_BasicGeometry
29 
30 #include "pxr/pxr.h"
31 #include "pxr/base/gf/matrix4d.h"
32 #include "pxr/base/gf/api.h"
33 
34 #include <float.h>
35 #include <limits>
36 #include <iosfwd>
37 
38 PXR_NAMESPACE_OPEN_SCOPE
39 
40 class GfBBox3d;
41 class GfLine;
42 class GfLineSeg;
43 class GfPlane;
44 class GfRange3d;
45 
46 /// \class GfRay
47 /// \ingroup group_gf_BasicGeometry
48 ///
49 /// Basic type: Ray used for intersection testing
50 ///
51 /// This class represents a three-dimensional ray in space, typically
52 /// used for intersection testing. It consists of an origin and a
53 /// direction.
54 ///
55 /// Note that by default a \c GfRay does not normalize its direction
56 /// vector to unit length.
57 ///
58 /// Note for ray intersections, the start point is included in the computations,
59 /// i.e., a distance of zero is defined to be intersecting.
60 ///
61 class GfRay {
62 
63   public:
64 
65     /// The default constructor leaves the ray parameters undefined.
GfRay()66     GfRay() {
67     }
68 
69     /// This constructor takes a starting point and a direction.
GfRay(const GfVec3d & startPoint,const GfVec3d & direction)70     GfRay(const GfVec3d &startPoint, const GfVec3d &direction) {
71         SetPointAndDirection(startPoint, direction);
72     }
73 
74     /// Sets the ray by specifying a starting point and a direction.
75     GF_API
76     void        SetPointAndDirection(const GfVec3d &startPoint,
77                                      const GfVec3d &direction);
78 
79     /// Sets the ray by specifying a starting point and an ending point.
80     GF_API
81     void        SetEnds(const GfVec3d &startPoint, const GfVec3d &endPoint);
82 
83     /// Returns the starting point of the segment.
GetStartPoint()84     const GfVec3d &     GetStartPoint() const {
85         return _startPoint;
86     }
87 
88     /// Returns the direction vector of the segment. This is not guaranteed to
89     /// be unit length.
GetDirection()90     const GfVec3d &     GetDirection() const {
91         return _direction;
92     }
93 
94     /// Returns the point that is \p distance units from the starting point
95     /// along the direction vector, expressed in parametic distance.
GetPoint(double distance)96     GfVec3d             GetPoint(double distance) const {
97         return _startPoint + distance * _direction;
98     }
99 
100     /// Transforms the ray by the given matrix.
101     GF_API
102     GfRay &     Transform(const GfMatrix4d &matrix);
103 
104     /// Returns the point on the ray that is closest to \p point. If \p
105     /// rayDistance is not \c NULL, it will be set to the parametric distance
106     /// along the ray of the closest point.
107     GF_API
108     GfVec3d             FindClosestPoint(const GfVec3d &point,
109                                          double *rayDistance = NULL) const;
110 
111     /// Component-wise equality test. The starting points, directions, and
112     /// lengths must match exactly for rays to be considered equal.
113     bool		operator ==(const GfRay &r) const {
114 	return (_startPoint == r._startPoint &&
115 		_direction  == r._direction);
116     }
117 
118     /// Component-wise inequality test. The starting points, directions, and
119     /// lengths must match exactly for rays to be considered equal.
120     bool		operator !=(const GfRay &r) const {
121 	return ! (*this == r);
122     }
123 
124     /// \name Intersection methods.
125     ///
126     /// The methods in this group intersect the ray with a geometric entity.
127     ///
128     ///@{
129 
130     /// Intersects the ray with the triangle formed by points \p p0, \p p1,
131     /// and \p p2, returning \c true if it hits. If there is an intersection,
132     /// it also returns the parametric distance to the intersection point in
133     /// \p distance, the barycentric coordinates of the intersection point in
134     /// \p barycentricCoords and the front-facing flag in \p frontFacing. The
135     /// barycentric coordinates are defined with respect to the three vertices
136     /// taken in order.  The front-facing flag is \c true if the intersection
137     /// hit the side of the triangle that is formed when the vertices are
138     /// ordered counter-clockwise (right-hand rule). If any of the return
139     /// pointers are \c NULL, the corresponding values are not returned.
140     ///
141     /// If the distance to the intersection is greater than \p maxDist, then
142     /// the method will return false.
143     ///
144     /// Barycentric coordinates are defined to sum to 1 and satisfy this
145     /// relationsip:
146     /// \code
147     ///     intersectionPoint = (barycentricCoords[0] * p0 +
148     ///                          barycentricCoords[1] * p1 +
149     ///                          barycentricCoords[2] * p2);
150     /// \endcode
151     GF_API
152     bool    Intersect(const GfVec3d &p0,
153                       const GfVec3d &p1,
154                       const GfVec3d &p2,
155                       double *distance = NULL,
156                       GfVec3d *barycentricCoords = NULL,
157                       bool *frontFacing = NULL,
158                       double maxDist = std::numeric_limits<double>::infinity())
159                       const;
160 
161     /// Intersects the ray with a plane, returning \c true if the ray is not
162     /// parallel to the plane and the intersection is within the ray bounds.
163     /// If there is an intersection, it also returns the parametric distance
164     /// to the intersection point in \p distance and the front-facing flag in
165     /// \p frontFacing, if they are not \c NULL. The front-facing flag is \c
166     /// true if the intersection is on the side of the plane in which its
167     /// normal points.
168     GF_API
169     bool	Intersect(const GfPlane &plane, double *distance = NULL,
170 			  bool *frontFacing = NULL) const;
171 
172     /// Intersects the ray with an axis-aligned box, returning \c true if the
173     /// ray intersects it at all within bounds. If there is an intersection,
174     /// this also returns the parametric distances to the two intersection
175     /// points in \p enterDistance and \p exitDistance.
176     GF_API
177     bool        Intersect(const GfRange3d &box,
178                           double *enterDistance = NULL,
179                           double *exitDistance = NULL) const;
180 
181     /// Intersects the ray with an oriented box, returning \c true if the
182     /// ray intersects it at all within bounds. If there is an intersection,
183     /// this also returns the parametric distances to the two intersection
184     /// points in \p enterDistance and \p exitDistance.
185     GF_API
186     bool        Intersect(const GfBBox3d &box,
187                           double *enterDistance = NULL,
188                           double *exitDistance = NULL) const;
189 
190     /// Intersects the ray with a sphere, returning \c true if the ray
191     /// intersects it at all within bounds.  If there is an intersection,
192     /// returns the parametric distance to the two intersection points in \p
193     /// enterDistance and \p exitDistance.
194     GF_API
195     bool        Intersect(const GfVec3d &center, double radius,
196                           double *enterDistance = NULL,
197                           double *exitDistance = NULL ) const;
198 
199     /// Intersects the ray with an infinite cylinder, with axis \p axis,
200     /// centered at the \p origin, with radius \p radius.
201     ///
202     /// Returns \c true if the ray intersects it at all within bounds. If
203     /// there is an intersection, returns the parametric distance to the two
204     /// intersection points in \p enterDistance and \p exitDistance.
205     ///
206     /// Note this method does not validate whether the radius is valid.
207     GF_API
208     bool Intersect(const GfVec3d &origin,
209                    const GfVec3d &axis,
210                    const double  radius,
211                    double        *enterDistance = NULL,
212                    double        *exitDistance = NULL) const;
213 
214     /// Intersects the ray with an infinite non-double cone, centered at \p
215     /// origin, with axis \p axis, radius \p radius and apex at \p height.
216     ///
217     /// Returns \c true if the ray intersects it at all within bounds. If
218     /// there is an intersection, returns the parametric distance to the two
219     /// intersection points in \p enterDistance and \p exitDistance.
220     ///
221     /// Note this method does not validate whether the radius are height are
222     /// valid.
223     GF_API
224     bool Intersect(const GfVec3d &origin,
225                    const GfVec3d &axis,
226                    const double  radius,
227                    const double  height,
228                    double        *enterDistance = NULL,
229                    double        *exitDistance = NULL) const;
230     ///@}
231 
232   private:
233     GF_API
234     friend bool GfFindClosestPoints( const GfRay &, const GfLine &,
235                                      GfVec3d *, GfVec3d *,
236                                      double *, double * );
237     GF_API
238     friend bool GfFindClosestPoints( const GfRay &, const GfLineSeg &,
239                                      GfVec3d *, GfVec3d *,
240                                      double *, double * );
241 
242     /// Solves the quadratic equation returning the solutions, if defined, in
243     /// \p enterDistance and \p exitDistance, where \p enterDistance is less
244     /// than or equal to \p exitDistance.
245     bool _SolveQuadratic(const double a,
246                          const double b,
247                          const double c,
248                          double       *enterDistance = NULL,
249                          double       *exitDistance = NULL) const;
250 
251     /// The starting point of the ray.
252     GfVec3d             _startPoint;
253     /// The direction vector.
254     GfVec3d             _direction;
255 };
256 
257 /// Computes the closest points between a ray and a line. The two points are
258 /// returned in \p rayPoint and \p linePoint.  The parametric distance of each
259 /// point on the lines is returned in \p rayDistance and \p lineDistance.
260 ///
261 /// This returns \c false if the lines were close enough to parallel that no
262 /// points could be computed; in this case, the other return values are
263 /// undefined.
264 GF_API
265 bool GfFindClosestPoints( const GfRay &ray, const GfLine &line,
266                           GfVec3d *rayPoint = nullptr,
267                           GfVec3d *linePoint = nullptr,
268                           double *rayDistance = nullptr,
269                           double *lineDistance = nullptr );
270 
271 /// Computes the closest points between a ray and a line segment. The two
272 /// points are returned in \p rayPoint and \p segPoint.  The parametric
273 /// distance of each point is returned in \p rayDistance and \p segDistance.
274 ///
275 /// This returns \c false if the lines were close enough to parallel that no
276 /// points could be computed; in this case, the other return values are
277 /// undefined.
278 GF_API
279 bool GfFindClosestPoints( const GfRay &ray, const GfLineSeg &seg,
280                           GfVec3d *rayPoint = nullptr,
281                           GfVec3d *segPoint = nullptr,
282                           double *rayDistance = nullptr,
283                           double *segDistance = nullptr );
284 
285 /// Output a GfRay using the format [(x y z) >> (x y z)].
286 /// \ingroup group_gf_DebuggingOutput
287 GF_API std::ostream& operator<<(std::ostream&, const GfRay&);
288 
289 PXR_NAMESPACE_CLOSE_SCOPE
290 
291 #endif // PXR_BASE_GF_RAY_H
292