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