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 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | namespace Qt3DRender { |
11 | namespace 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 | */ |
48 | QRay3D::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 | */ |
66 | QRay3D::QRay3D(const Vector3D &origin, const Vector3D &direction, float distance) |
67 | : m_origin(origin) |
68 | , m_direction(direction.normalized()) |
69 | , m_distance(distance) |
70 | {} |
71 | |
72 | QRay3D::~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 | */ |
83 | Vector3D 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 | */ |
95 | void 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 | */ |
107 | Vector3D 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 | */ |
119 | void QRay3D::setDirection(const Vector3D &value) |
120 | { |
121 | if (value.isNull()) |
122 | return; |
123 | |
124 | m_direction = value.normalized(); |
125 | } |
126 | |
127 | float QRay3D::distance() const |
128 | { |
129 | return m_distance; |
130 | } |
131 | |
132 | void QRay3D::setDistance(float distance) |
133 | { |
134 | m_distance = distance; |
135 | } |
136 | |
137 | Vector3D QRay3D::point(float t) const |
138 | { |
139 | return m_origin + t * m_direction; |
140 | } |
141 | |
142 | QRay3D &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 | |
150 | QRay3D QRay3D::transformed(const Matrix4x4 &matrix) const |
151 | { |
152 | return QRay3D(matrix.map(point: m_origin), matrix.mapVector(vector: m_direction).normalized()); |
153 | } |
154 | |
155 | bool QRay3D::operator==(const QRay3D &other) const |
156 | { |
157 | return m_origin == other.origin() && m_direction == other.direction(); |
158 | } |
159 | |
160 | bool 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 | */ |
168 | bool 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 | */ |
184 | bool 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 | */ |
220 | float 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 | */ |
237 | Vector3D 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 | */ |
250 | float 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 | |
300 | QDebug 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 | */ |
321 | QDataStream &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 | */ |
336 | QDataStream &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 | |
354 | QT_END_NAMESPACE |
355 | |