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 m_origin = matrix.map(point: m_origin);
145 m_direction = matrix.mapVector(vector: m_direction).normalized();
146
147 return *this;
148}
149
150QRay3D QRay3D::transformed(const Matrix4x4 &matrix) const
151{
152 return QRay3D(matrix.map(point: m_origin), matrix.mapVector(vector: m_direction).normalized());
153}
154
155bool QRay3D::operator==(const QRay3D &other) const
156{
157 return m_origin == other.origin() && m_direction == other.direction();
158}
159
160bool QRay3D::operator!=(const QRay3D &other) const
161{
162 return !(*this == other);
163}
164
165/*!
166 Returns \c true if \a point lies on this ray; \c false otherwise.
167*/
168bool QRay3D::contains(const Vector3D &point) const
169{
170 Vector3D ppVec(point - m_origin);
171 if (ppVec.isNull()) // point coincides with origin
172 return true;
173 const float dot = Vector3D ::dotProduct(a: ppVec, b: m_direction);
174 if (qFuzzyIsNull(f: dot))
175 return false;
176 return qFuzzyCompare(p1: dot*dot, p2: ppVec.lengthSquared() * m_direction.lengthSquared());
177}
178
179/*!
180 Returns \c true if \a ray lies on this ray; \c false otherwise. If true,
181 this implies that the two rays are actually the same, but with
182 different origin() points or an inverted direction().
183*/
184bool QRay3D::contains(const QRay3D &ray) const
185{
186 const float dot = Vector3D ::dotProduct(a: m_direction, b: ray.direction());
187 if (!qFuzzyCompare(p1: dot*dot, p2: m_direction.lengthSquared() * ray.direction().lengthSquared()))
188 return false;
189 return contains(point: ray.origin());
190}
191
192/*!
193 \fn QVector3D Qt3DRender::RayCasting::QRay3D::point(float t) const
194
195 Returns the point on the ray defined by moving \a t units
196 along the ray in the direction of the direction() vector.
197 Note that \a t may be negative in which case the point returned
198 will lie behind the origin() point with respect to the
199 direction() vector.
200
201 The units for \a t are defined by direction(). The return value
202 is precisely origin() + t * direction().
203
204 \sa projectedDistance(), distance()
205*/
206
207/*!
208 Returns the number of direction() units along the ray from origin()
209 to \a point. Essentially, this function computes the value t, where
210 \a point = origin() + t * direction(). If \a point is not on the ray,
211 then the closest point that is on the ray will be used instead.
212
213 If the return value is positive, then \a point lies in front of
214 the origin() with respect to the direction() vector. If the return
215 value is negative, then \a point lies behind the origin() with
216 respect to the direction() vector.
217
218 \sa point(), project()
219*/
220float QRay3D::projectedDistance(const Vector3D &point) const
221{
222 Q_ASSERT(!m_direction.isNull());
223
224 return Vector3D ::dotProduct(a: point - m_origin, b: m_direction) /
225 m_direction.lengthSquared();
226}
227
228/*!
229 Returns the projection of \a vector onto this ray. In the
230 following diagram, the dotted line is the ray, and V is the
231 \a vector. The return value will be the vector V':
232
233 \image qray3d-project.png
234
235 \sa projectedDistance()
236*/
237Vector3D QRay3D::project(const Vector3D &vector) const
238{
239 Vector3D norm = m_direction.normalized();
240 return Vector3D ::dotProduct(a: vector, b: norm) * norm;
241}
242
243/*!
244 Returns the minimum distance from this ray to \a point, or equivalently
245 the length of a line perpendicular to this ray which passes through
246 \a point. If \a point is on the ray, then this function will return zero.
247
248 \sa point()
249*/
250float QRay3D::distance(const Vector3D &point) const
251{
252 float t = projectedDistance(point);
253 return (point - (m_origin + t * m_direction)).length();
254}
255
256/*!
257 \fn Qt3DRender::RayCasting::QRay3D &Qt3DRender::RayCasting::QRay3D::transform(const Matrix4x4 &matrix)
258
259 Transforms this ray using \a matrix, replacing origin() and
260 direction() with the transformed versions.
261
262 \sa transformed()
263*/
264
265/*!
266 \fn Qt3DRender::RayCasting::QRay3D Qt3DRender::RayCasting::QRay3D::transformed(const Matrix4x4 &matrix) const
267
268 Returns a new ray that is formed by transforming origin()
269 and direction() using \a matrix.
270
271 \sa transform()
272*/
273
274/*!
275 \fn bool Qt3DRender::RayCasting::QRay3D::operator==(const QRay3D &other) const
276
277 Returns \c true if this ray is the same as \a other; \c false otherwise.
278
279 \sa operator!=()
280*/
281
282/*!
283 \fn bool Qt3DRender::RayCasting::QRay3D::operator!=(const QRay3D &other) const
284
285 Returns \c true if this ray is not the same as \a other; \c false otherwise.
286
287 \sa operator==()
288*/
289
290/*!
291 \fn bool qFuzzyCompare(const Qt3DRender::RayCasting::QRay3D &ray1, const Qt3DRender::RayCasting::QRay3D &ray2)
292 \relates Qt3DRender::RayCasting::QRay3D
293
294 Returns \c true if \a ray1 and \a ray2 are almost equal; \c false
295 otherwise.
296*/
297
298#ifndef QT_NO_DEBUG_STREAM
299
300QDebug operator<<(QDebug dbg, const QRay3D &ray)
301{
302 QDebugStateSaver saver(dbg);
303 dbg.nospace() << "QRay3D(origin("
304 << ray.origin().x() << ", " << ray.origin().y() << ", "
305 << ray.origin().z() << ") - direction("
306 << ray.direction().x() << ", " << ray.direction().y() << ", "
307 << ray.direction().z() << ") - distance(" << ray.distance() << "))";
308 return dbg;
309}
310
311#endif
312
313#ifndef QT_NO_DATASTREAM
314
315/*!
316 \relates Qt3DRender::RayCasting::QRay3D
317
318 Writes the given \a ray to the given \a stream and returns a
319 reference to the stream.
320*/
321QDataStream &operator<<(QDataStream &stream, const QRay3D &ray)
322{
323 stream << convertToQVector3D(v: ray.origin());
324 stream << convertToQVector3D(v: ray.direction());
325 if (stream.version() >= QDataStream::Qt_5_11)
326 stream << ray.distance();
327 return stream;
328}
329
330/*!
331 \relates Qt3DRender::RayCasting::QRay3D
332
333 Reads a 3D ray from the given \a stream into the given \a ray
334 and returns a reference to the stream.
335*/
336QDataStream &operator>>(QDataStream &stream, QRay3D &ray)
337{
338 QVector3D origin, direction;
339 float distance = 1.f;
340
341 stream >> origin;
342 stream >> direction;
343 if (stream.version() >= QDataStream::Qt_5_11)
344 stream >> distance;
345 ray = QRay3D(Vector3D(origin), Vector3D(direction), distance);
346 return stream;
347}
348
349#endif // QT_NO_DATASTREAM
350
351} // namespace RayCasting
352} // namespace Qt3DRender
353
354QT_END_NAMESPACE
355

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