1// Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
2// Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <Qt3DRender/private/qray3d_p.h>
6#include <QtCore/qdebug.h>
7
8QT_BEGIN_NAMESPACE
9
10namespace Qt3DRender {
11namespace RayCasting {
12
13/*!
14 \namespace Qt3DRender::RayCasting
15 \internal
16*/
17
18/*!
19 \internal
20 \class Qt3DRender::RayCasting::QRay3D
21 \inmodule Qt3DRender
22 \brief The QRay3D class defines a directional line in 3D space extending through an origin point.
23 \since 5.5
24 \ingroup qt3d
25 \ingroup qt3d::math
26
27 A ray is defined by the origin() point and the direction() vector.
28 Rays are infinite in length, extending out from origin() in
29 both directions. If the direction() is zero length, then the
30 behavior of the class is undefined.
31
32 A ray can be thought of as a one-dimensional co-ordinate system.
33 If the co-ordinate is \b t then the origin() point is at
34 \b t = 0, the point origin() + direction() is at \b t = 1,
35 and the point origin() - direction() is at \b t = -1.
36 The point() method can be used to obtain the position of a point
37 within this one-dimensional co-ordinate system. The projectedDistance()
38 method can be used to convert a point into a value in this
39 one-dimensional co-ordinate system.
40*/
41
42/*!
43 \fn Qt3DRender::RayCasting::QRay3D::QRay3D()
44
45 Construct a default ray with an origin() of (0, 0, 0), a
46 direction() of (0, 0, 1) and a distance of 1.
47*/
48QRay3D::QRay3D()
49 : m_direction(0.0f, 0.0f, 1.0f)
50 , m_distance(1.0f)
51{
52}
53
54/*!
55 \fn Qt3DRender::RayCasting::QRay3D::QRay3D(const Vector3D &origin, const Vector3D &direction, float distance)
56
57 Construct a ray given its defining \a origin, \a direction and \a distance.
58 The \a direction does not need to be normalized.
59
60 To construct a ray that passes through two points, use the following:
61
62 \code
63 QRay3D thruAB(pointA, pointB - pointA);
64 \endcode
65*/
66QRay3D::QRay3D(const Vector3D &origin, const Vector3D &direction, float distance)
67 : m_origin(origin)
68 , m_direction(direction.normalized())
69 , m_distance(distance)
70{}
71
72QRay3D::~QRay3D()
73{
74}
75
76/*!
77 \fn QVector3D Qt3DRender::RayCasting::QRay3D::origin() const
78
79 Returns the origin of this ray. The default value is (0, 0, 0).
80
81 \sa setOrigin(), direction()
82*/
83Vector3D QRay3D::origin() const
84{
85 return m_origin;
86}
87
88/*!
89 \fn void Qt3DRender::RayCasting::QRay3D::setOrigin(const Vector3D &value)
90
91 Sets the origin point of this ray to \a value.
92
93 \sa origin(), setDirection()
94 */
95void QRay3D::setOrigin(const Vector3D &value)
96{
97 m_origin = value;
98}
99
100/*!
101 \fn QVector3D Qt3DRender::RayCasting::QRay3D::direction() const
102
103 Returns the direction vector of this ray. The default value is (0, 0, 1).
104
105 \sa setDirection(), origin()
106*/
107Vector3D QRay3D::direction() const
108{
109 return m_direction;
110}
111
112/*!
113 \fn void Qt3DRender::RayCasting::QRay3D::setDirection(const Vector3D &direction)
114
115 Sets the direction vector of this ray to \a direction.
116
117 \sa direction(), setOrigin()
118*/
119void QRay3D::setDirection(const Vector3D &value)
120{
121 if (value.isNull())
122 return;
123
124 m_direction = value.normalized();
125}
126
127float QRay3D::distance() const
128{
129 return m_distance;
130}
131
132void QRay3D::setDistance(float distance)
133{
134 m_distance = distance;
135}
136
137Vector3D QRay3D::point(float t) const
138{
139 return m_origin + t * m_direction;
140}
141
142QRay3D &QRay3D::transform(const Matrix4x4 &matrix)
143{
144 Vector3D pointAtDistance = point(t: distance());
145 m_origin = matrix.map(point: m_origin);
146 pointAtDistance = matrix.map(point: pointAtDistance);
147 m_direction = (pointAtDistance - m_origin).normalized();
148 m_distance = (pointAtDistance - m_origin).length();
149
150 return *this;
151}
152
153QRay3D QRay3D::transformed(const Matrix4x4 &matrix) const
154{
155 QRay3D cpy(m_origin, m_direction, m_distance);
156 return cpy.transform(matrix);
157}
158
159bool QRay3D::operator==(const QRay3D &other) const
160{
161 return m_origin == other.origin() && m_direction == other.direction();
162}
163
164bool QRay3D::operator!=(const QRay3D &other) const
165{
166 return !(*this == other);
167}
168
169/*!
170 Returns \c true if \a point lies on this ray; \c false otherwise.
171*/
172bool QRay3D::contains(const Vector3D &point) const
173{
174 Vector3D ppVec(point - m_origin);
175 if (ppVec.isNull()) // point coincides with origin
176 return true;
177 const float dot = Vector3D ::dotProduct(a: ppVec, b: m_direction);
178 if (qFuzzyIsNull(f: dot))
179 return false;
180 return qFuzzyCompare(p1: dot*dot, p2: ppVec.lengthSquared() * m_direction.lengthSquared());
181}
182
183/*!
184 Returns \c true if \a ray lies on this ray; \c false otherwise. If true,
185 this implies that the two rays are actually the same, but with
186 different origin() points or an inverted direction().
187*/
188bool QRay3D::contains(const QRay3D &ray) const
189{
190 const float dot = Vector3D ::dotProduct(a: m_direction, b: ray.direction());
191 if (!qFuzzyCompare(p1: dot*dot, p2: m_direction.lengthSquared() * ray.direction().lengthSquared()))
192 return false;
193 return contains(point: ray.origin());
194}
195
196/*!
197 \fn QVector3D Qt3DRender::RayCasting::QRay3D::point(float t) const
198
199 Returns the point on the ray defined by moving \a t units
200 along the ray in the direction of the direction() vector.
201 Note that \a t may be negative in which case the point returned
202 will lie behind the origin() point with respect to the
203 direction() vector.
204
205 The units for \a t are defined by direction(). The return value
206 is precisely origin() + t * direction().
207
208 \sa projectedDistance(), distance()
209*/
210
211/*!
212 Returns the number of direction() units along the ray from origin()
213 to \a point. Essentially, this function computes the value t, where
214 \a point = origin() + t * direction(). If \a point is not on the ray,
215 then the closest point that is on the ray will be used instead.
216
217 If the return value is positive, then \a point lies in front of
218 the origin() with respect to the direction() vector. If the return
219 value is negative, then \a point lies behind the origin() with
220 respect to the direction() vector.
221
222 \sa point(), project()
223*/
224float QRay3D::projectedDistance(const Vector3D &point) const
225{
226 Q_ASSERT(!m_direction.isNull());
227
228 return Vector3D ::dotProduct(a: point - m_origin, b: m_direction) /
229 m_direction.lengthSquared();
230}
231
232/*!
233 Returns the projection of \a vector onto this ray. In the
234 following diagram, the dotted line is the ray, and V is the
235 \a vector. The return value will be the vector V':
236
237 \image qray3d-project.png
238
239 \sa projectedDistance()
240*/
241Vector3D QRay3D::project(const Vector3D &vector) const
242{
243 Vector3D norm = m_direction.normalized();
244 return Vector3D ::dotProduct(a: vector, b: norm) * norm;
245}
246
247/*!
248 Returns the minimum distance from this ray to \a point, or equivalently
249 the length of a line perpendicular to this ray which passes through
250 \a point. If \a point is on the ray, then this function will return zero.
251
252 \sa point()
253*/
254float QRay3D::distance(const Vector3D &point) const
255{
256 float t = projectedDistance(point);
257 return (point - (m_origin + t * m_direction)).length();
258}
259
260/*!
261 \fn Qt3DRender::RayCasting::QRay3D &Qt3DRender::RayCasting::QRay3D::transform(const Matrix4x4 &matrix)
262
263 Transforms this ray using \a matrix, replacing origin() and
264 direction() with the transformed versions.
265
266 \sa transformed()
267*/
268
269/*!
270 \fn Qt3DRender::RayCasting::QRay3D Qt3DRender::RayCasting::QRay3D::transformed(const Matrix4x4 &matrix) const
271
272 Returns a new ray that is formed by transforming origin()
273 and direction() using \a matrix.
274
275 \sa transform()
276*/
277
278/*!
279 \fn bool Qt3DRender::RayCasting::QRay3D::operator==(const QRay3D &other) const
280
281 Returns \c true if this ray is the same as \a other; \c false otherwise.
282
283 \sa operator!=()
284*/
285
286/*!
287 \fn bool Qt3DRender::RayCasting::QRay3D::operator!=(const QRay3D &other) const
288
289 Returns \c true if this ray is not the same as \a other; \c false otherwise.
290
291 \sa operator==()
292*/
293
294/*!
295 \fn bool qFuzzyCompare(const Qt3DRender::RayCasting::QRay3D &ray1, const Qt3DRender::RayCasting::QRay3D &ray2)
296 \relates Qt3DRender::RayCasting::QRay3D
297
298 Returns \c true if \a ray1 and \a ray2 are almost equal; \c false
299 otherwise.
300*/
301
302#ifndef QT_NO_DEBUG_STREAM
303
304QDebug operator<<(QDebug dbg, const QRay3D &ray)
305{
306 QDebugStateSaver saver(dbg);
307 dbg.nospace() << "QRay3D(origin("
308 << ray.origin().x() << ", " << ray.origin().y() << ", "
309 << ray.origin().z() << ") - direction("
310 << ray.direction().x() << ", " << ray.direction().y() << ", "
311 << ray.direction().z() << ") - distance(" << ray.distance() << "))";
312 return dbg;
313}
314
315#endif
316
317#ifndef QT_NO_DATASTREAM
318
319/*!
320 \relates Qt3DRender::RayCasting::QRay3D
321
322 Writes the given \a ray to the given \a stream and returns a
323 reference to the stream.
324*/
325QDataStream &operator<<(QDataStream &stream, const QRay3D &ray)
326{
327 stream << convertToQVector3D(v: ray.origin());
328 stream << convertToQVector3D(v: ray.direction());
329 if (stream.version() >= QDataStream::Qt_5_11)
330 stream << ray.distance();
331 return stream;
332}
333
334/*!
335 \relates Qt3DRender::RayCasting::QRay3D
336
337 Reads a 3D ray from the given \a stream into the given \a ray
338 and returns a reference to the stream.
339*/
340QDataStream &operator>>(QDataStream &stream, QRay3D &ray)
341{
342 QVector3D origin, direction;
343 float distance = 1.f;
344
345 stream >> origin;
346 stream >> direction;
347 if (stream.version() >= QDataStream::Qt_5_11)
348 stream >> distance;
349 ray = QRay3D(Vector3D(origin), Vector3D(direction), distance);
350 return stream;
351}
352
353#endif // QT_NO_DATASTREAM
354
355} // namespace RayCasting
356} // namespace Qt3DRender
357
358QT_END_NAMESPACE
359

source code of qt3d/src/render/raycasting/qray3d.cpp