1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qvector3d.h"
41#include "qvector2d.h"
42#include "qvector4d.h"
43#include "qmatrix4x4.h"
44#include <QtCore/qdatastream.h>
45#include <QtCore/qmath.h>
46#include <QtCore/qvariant.h>
47#include <QtCore/qdebug.h>
48#include <QtCore/qrect.h>
49
50QT_BEGIN_NAMESPACE
51
52#ifndef QT_NO_VECTOR3D
53
54static_assert(std::is_standard_layout<QVector3D>::value, "QVector3D is supposed to be standard layout");
55static_assert(sizeof(QVector3D) == sizeof(float) * 3, "QVector3D is not supposed to have padding at the end");
56
57/*!
58 \class QVector3D
59 \brief The QVector3D class represents a vector or vertex in 3D space.
60 \since 4.6
61 \ingroup painting-3D
62 \inmodule QtGui
63
64 Vectors are one of the main building blocks of 3D representation and
65 drawing. They consist of three coordinates, traditionally called
66 x, y, and z.
67
68 The QVector3D class can also be used to represent vertices in 3D space.
69 We therefore do not need to provide a separate vertex class.
70
71 \sa QVector2D, QVector4D, QQuaternion
72*/
73
74/*!
75 \fn QVector3D::QVector3D()
76
77 Constructs a null vector, i.e. with coordinates (0, 0, 0).
78*/
79
80/*!
81 \fn QVector3D::QVector3D(Qt::Initialization)
82 \since 5.5
83 \internal
84
85 Constructs a vector without initializing the contents.
86*/
87
88/*!
89 \fn QVector3D::QVector3D(float xpos, float ypos, float zpos)
90
91 Constructs a vector with coordinates (\a xpos, \a ypos, \a zpos).
92*/
93
94/*!
95 \fn QVector3D::QVector3D(const QPoint& point)
96
97 Constructs a vector with x and y coordinates from a 2D \a point, and a
98 z coordinate of 0.
99*/
100
101/*!
102 \fn QVector3D::QVector3D(const QPointF& point)
103
104 Constructs a vector with x and y coordinates from a 2D \a point, and a
105 z coordinate of 0.
106*/
107
108#ifndef QT_NO_VECTOR2D
109
110/*!
111 Constructs a 3D vector from the specified 2D \a vector. The z
112 coordinate is set to zero.
113
114 \sa toVector2D()
115*/
116QVector3D::QVector3D(const QVector2D& vector)
117{
118 v[0] = vector.v[0];
119 v[1] = vector.v[1];
120 v[2] = 0.0f;
121}
122
123/*!
124 Constructs a 3D vector from the specified 2D \a vector. The z
125 coordinate is set to \a zpos.
126
127 \sa toVector2D()
128*/
129QVector3D::QVector3D(const QVector2D& vector, float zpos)
130{
131 v[0] = vector.v[0];
132 v[1] = vector.v[1];
133 v[2] = zpos;
134}
135
136#endif
137
138#ifndef QT_NO_VECTOR4D
139
140/*!
141 Constructs a 3D vector from the specified 4D \a vector. The w
142 coordinate is dropped.
143
144 \sa toVector4D()
145*/
146QVector3D::QVector3D(const QVector4D& vector)
147{
148 v[0] = vector.v[0];
149 v[1] = vector.v[1];
150 v[2] = vector.v[2];
151}
152
153#endif
154
155/*!
156 \fn bool QVector3D::isNull() const
157
158 Returns \c true if the x, y, and z coordinates are set to 0.0,
159 otherwise returns \c false.
160*/
161
162/*!
163 \fn float QVector3D::x() const
164
165 Returns the x coordinate of this point.
166
167 \sa setX(), y(), z()
168*/
169
170/*!
171 \fn float QVector3D::y() const
172
173 Returns the y coordinate of this point.
174
175 \sa setY(), x(), z()
176*/
177
178/*!
179 \fn float QVector3D::z() const
180
181 Returns the z coordinate of this point.
182
183 \sa setZ(), x(), y()
184*/
185
186/*!
187 \fn void QVector3D::setX(float x)
188
189 Sets the x coordinate of this point to the given \a x coordinate.
190
191 \sa x(), setY(), setZ()
192*/
193
194/*!
195 \fn void QVector3D::setY(float y)
196
197 Sets the y coordinate of this point to the given \a y coordinate.
198
199 \sa y(), setX(), setZ()
200*/
201
202/*!
203 \fn void QVector3D::setZ(float z)
204
205 Sets the z coordinate of this point to the given \a z coordinate.
206
207 \sa z(), setX(), setY()
208*/
209
210/*! \fn float &QVector3D::operator[](int i)
211 \since 5.2
212
213 Returns the component of the vector at index position \a i
214 as a modifiable reference.
215
216 \a i must be a valid index position in the vector (i.e., 0 <= \a i
217 < 3).
218*/
219
220/*! \fn float QVector3D::operator[](int i) const
221 \since 5.2
222
223 Returns the component of the vector at index position \a i.
224
225 \a i must be a valid index position in the vector (i.e., 0 <= \a i
226 < 3).
227*/
228
229/*!
230 Returns the normalized unit vector form of this vector.
231
232 If this vector is null, then a null vector is returned. If the length
233 of the vector is very close to 1, then the vector will be returned as-is.
234 Otherwise the normalized form of the vector of length 1 will be returned.
235
236 \sa length(), normalize()
237*/
238QVector3D QVector3D::normalized() const
239{
240 // Need some extra precision if the length is very small.
241 double len = double(v[0]) * double(v[0]) +
242 double(v[1]) * double(v[1]) +
243 double(v[2]) * double(v[2]);
244 if (qFuzzyIsNull(len - 1.0f)) {
245 return *this;
246 } else if (!qFuzzyIsNull(len)) {
247 double sqrtLen = std::sqrt(len);
248 return QVector3D(float(double(v[0]) / sqrtLen),
249 float(double(v[1]) / sqrtLen),
250 float(double(v[2]) / sqrtLen));
251 } else {
252 return QVector3D();
253 }
254}
255
256/*!
257 Normalizes the currect vector in place. Nothing happens if this
258 vector is a null vector or the length of the vector is very close to 1.
259
260 \sa length(), normalized()
261*/
262void QVector3D::normalize()
263{
264 // Need some extra precision if the length is very small.
265 double len = double(v[0]) * double(v[0]) +
266 double(v[1]) * double(v[1]) +
267 double(v[2]) * double(v[2]);
268 if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
269 return;
270
271 len = std::sqrt(len);
272
273 v[0] = float(double(v[0]) / len);
274 v[1] = float(double(v[1]) / len);
275 v[2] = float(double(v[2]) / len);
276}
277
278/*!
279 \fn QVector3D &QVector3D::operator+=(const QVector3D &vector)
280
281 Adds the given \a vector to this vector and returns a reference to
282 this vector.
283
284 \sa operator-=()
285*/
286
287/*!
288 \fn QVector3D &QVector3D::operator-=(const QVector3D &vector)
289
290 Subtracts the given \a vector from this vector and returns a reference to
291 this vector.
292
293 \sa operator+=()
294*/
295
296/*!
297 \fn QVector3D &QVector3D::operator*=(float factor)
298
299 Multiplies this vector's coordinates by the given \a factor, and
300 returns a reference to this vector.
301
302 \sa operator/=()
303*/
304
305/*!
306 \fn QVector3D &QVector3D::operator*=(const QVector3D& vector)
307 \overload
308
309 Multiplies the components of this vector by the corresponding
310 components in \a vector.
311
312 Note: this is not the same as the crossProduct() of this
313 vector and \a vector.
314
315 \sa crossProduct()
316*/
317
318/*!
319 \fn QVector3D &QVector3D::operator/=(float divisor)
320
321 Divides this vector's coordinates by the given \a divisor, and
322 returns a reference to this vector.
323
324 \sa operator*=()
325*/
326
327/*!
328 \fn QVector3D &QVector3D::operator/=(const QVector3D &vector)
329 \since 5.5
330
331 Divides the components of this vector by the corresponding
332 components in \a vector.
333
334 \sa operator*=()
335*/
336
337/*!
338 Returns the dot product of \a v1 and \a v2.
339*/
340float QVector3D::dotProduct(const QVector3D& v1, const QVector3D& v2)
341{
342 return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1] + v1.v[2] * v2.v[2];
343}
344
345/*!
346 Returns the cross-product of vectors \a v1 and \a v2, which corresponds
347 to the normal vector of a plane defined by \a v1 and \a v2.
348
349 \sa normal()
350*/
351QVector3D QVector3D::crossProduct(const QVector3D& v1, const QVector3D& v2)
352{
353 return QVector3D(v1.v[1] * v2.v[2] - v1.v[2] * v2.v[1],
354 v1.v[2] * v2.v[0] - v1.v[0] * v2.v[2],
355 v1.v[0] * v2.v[1] - v1.v[1] * v2.v[0]);
356}
357
358/*!
359 Returns the normal vector of a plane defined by vectors \a v1 and \a v2,
360 normalized to be a unit vector.
361
362 Use crossProduct() to compute the cross-product of \a v1 and \a v2 if you
363 do not need the result to be normalized to a unit vector.
364
365 \sa crossProduct(), distanceToPlane()
366*/
367QVector3D QVector3D::normal(const QVector3D& v1, const QVector3D& v2)
368{
369 return crossProduct(v1, v2).normalized();
370}
371
372/*!
373 \overload
374
375 Returns the normal vector of a plane defined by vectors
376 \a v2 - \a v1 and \a v3 - \a v1, normalized to be a unit vector.
377
378 Use crossProduct() to compute the cross-product of \a v2 - \a v1 and
379 \a v3 - \a v1 if you do not need the result to be normalized to a
380 unit vector.
381
382 \sa crossProduct(), distanceToPlane()
383*/
384QVector3D QVector3D::normal
385 (const QVector3D& v1, const QVector3D& v2, const QVector3D& v3)
386{
387 return crossProduct((v2 - v1), (v3 - v1)).normalized();
388}
389
390/*!
391 \since 5.5
392
393 Returns the window coordinates of this vector initially in object/model
394 coordinates using the model view matrix \a modelView, the projection matrix
395 \a projection and the viewport dimensions \a viewport.
396
397 When transforming from clip to normalized space, a division by the w
398 component on the vector components takes place. To prevent dividing by 0 if
399 w equals to 0, it is set to 1.
400
401 \note the returned y coordinates are in OpenGL orientation. OpenGL expects
402 the bottom to be 0 whereas for Qt top is 0.
403
404 \sa unproject()
405 */
406QVector3D QVector3D::project(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport) const
407{
408 QVector4D tmp(*this, 1.0f);
409 tmp = projection * modelView * tmp;
410 if (qFuzzyIsNull(tmp.w()))
411 tmp.setW(1.0f);
412 tmp /= tmp.w();
413
414 tmp = tmp * 0.5f + QVector4D(0.5f, 0.5f, 0.5f, 0.5f);
415 tmp.setX(tmp.x() * viewport.width() + viewport.x());
416 tmp.setY(tmp.y() * viewport.height() + viewport.y());
417
418 return tmp.toVector3D();
419}
420
421/*!
422 \since 5.5
423
424 Returns the object/model coordinates of this vector initially in window
425 coordinates using the model view matrix \a modelView, the projection matrix
426 \a projection and the viewport dimensions \a viewport.
427
428 When transforming from clip to normalized space, a division by the w
429 component of the vector components takes place. To prevent dividing by 0 if
430 w equals to 0, it is set to 1.
431
432 \note y coordinates in \a viewport should use OpenGL orientation. OpenGL
433 expects the bottom to be 0 whereas for Qt top is 0.
434
435 \sa project()
436 */
437QVector3D QVector3D::unproject(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport) const
438{
439 QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted();
440
441 QVector4D tmp(*this, 1.0f);
442 tmp.setX((tmp.x() - float(viewport.x())) / float(viewport.width()));
443 tmp.setY((tmp.y() - float(viewport.y())) / float(viewport.height()));
444 tmp = tmp * 2.0f - QVector4D(1.0f, 1.0f, 1.0f, 1.0f);
445
446 QVector4D obj = inverse * tmp;
447 if (qFuzzyIsNull(obj.w()))
448 obj.setW(1.0f);
449 obj /= obj.w();
450 return obj.toVector3D();
451}
452
453/*!
454 \since 5.1
455
456 Returns the distance from this vertex to a point defined by
457 the vertex \a point.
458
459 \sa distanceToPlane(), distanceToLine()
460*/
461float QVector3D::distanceToPoint(const QVector3D& point) const
462{
463 return (*this - point).length();
464}
465
466/*!
467 Returns the distance from this vertex to a plane defined by
468 the vertex \a plane and a \a normal unit vector. The \a normal
469 parameter is assumed to have been normalized to a unit vector.
470
471 The return value will be negative if the vertex is below the plane,
472 or zero if it is on the plane.
473
474 \sa normal(), distanceToLine()
475*/
476float QVector3D::distanceToPlane
477 (const QVector3D& plane, const QVector3D& normal) const
478{
479 return dotProduct(*this - plane, normal);
480}
481
482/*!
483 \overload
484
485 Returns the distance from this vertex to a plane defined by
486 the vertices \a plane1, \a plane2 and \a plane3.
487
488 The return value will be negative if the vertex is below the plane,
489 or zero if it is on the plane.
490
491 The two vectors that define the plane are \a plane2 - \a plane1
492 and \a plane3 - \a plane1.
493
494 \sa normal(), distanceToLine()
495*/
496float QVector3D::distanceToPlane
497 (const QVector3D& plane1, const QVector3D& plane2, const QVector3D& plane3) const
498{
499 QVector3D n = normal(plane2 - plane1, plane3 - plane1);
500 return dotProduct(*this - plane1, n);
501}
502
503/*!
504 Returns the distance that this vertex is from a line defined
505 by \a point and the unit vector \a direction.
506
507 If \a direction is a null vector, then it does not define a line.
508 In that case, the distance from \a point to this vertex is returned.
509
510 \sa distanceToPlane()
511*/
512float QVector3D::distanceToLine
513 (const QVector3D& point, const QVector3D& direction) const
514{
515 if (direction.isNull())
516 return (*this - point).length();
517 QVector3D p = point + dotProduct(*this - point, direction) * direction;
518 return (*this - p).length();
519}
520
521/*!
522 \fn bool operator==(const QVector3D &v1, const QVector3D &v2)
523 \relates QVector3D
524
525 Returns \c true if \a v1 is equal to \a v2; otherwise returns \c false.
526 This operator uses an exact floating-point comparison.
527*/
528
529/*!
530 \fn bool operator!=(const QVector3D &v1, const QVector3D &v2)
531 \relates QVector3D
532
533 Returns \c true if \a v1 is not equal to \a v2; otherwise returns \c false.
534 This operator uses an exact floating-point comparison.
535*/
536
537/*!
538 \fn const QVector3D operator+(const QVector3D &v1, const QVector3D &v2)
539 \relates QVector3D
540
541 Returns a QVector3D object that is the sum of the given vectors, \a v1
542 and \a v2; each component is added separately.
543
544 \sa QVector3D::operator+=()
545*/
546
547/*!
548 \fn const QVector3D operator-(const QVector3D &v1, const QVector3D &v2)
549 \relates QVector3D
550
551 Returns a QVector3D object that is formed by subtracting \a v2 from \a v1;
552 each component is subtracted separately.
553
554 \sa QVector3D::operator-=()
555*/
556
557/*!
558 \fn const QVector3D operator*(float factor, const QVector3D &vector)
559 \relates QVector3D
560
561 Returns a copy of the given \a vector, multiplied by the given \a factor.
562
563 \sa QVector3D::operator*=()
564*/
565
566/*!
567 \fn const QVector3D operator*(const QVector3D &vector, float factor)
568 \relates QVector3D
569
570 Returns a copy of the given \a vector, multiplied by the given \a factor.
571
572 \sa QVector3D::operator*=()
573*/
574
575/*!
576 \fn const QVector3D operator*(const QVector3D &v1, const QVector3D& v2)
577 \relates QVector3D
578
579 Multiplies the components of \a v1 by the corresponding components in \a v2.
580
581 Note: this is not the same as the crossProduct() of \a v1 and \a v2.
582
583 \sa QVector3D::crossProduct()
584*/
585
586/*!
587 \fn const QVector3D operator-(const QVector3D &vector)
588 \relates QVector3D
589 \overload
590
591 Returns a QVector3D object that is formed by changing the sign of
592 all three components of the given \a vector.
593
594 Equivalent to \c {QVector3D(0,0,0) - vector}.
595*/
596
597/*!
598 \fn const QVector3D operator/(const QVector3D &vector, float divisor)
599 \relates QVector3D
600
601 Returns the QVector3D object formed by dividing all three components of
602 the given \a vector by the given \a divisor.
603
604 \sa QVector3D::operator/=()
605*/
606
607/*!
608 \fn const QVector3D operator/(const QVector3D &vector, const QVector3D &divisor)
609 \relates QVector3D
610 \since 5.5
611
612 Returns the QVector3D object formed by dividing components of the given
613 \a vector by a respective components of the given \a divisor.
614
615 \sa QVector3D::operator/=()
616*/
617
618/*!
619 \fn bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2)
620 \relates QVector3D
621
622 Returns \c true if \a v1 and \a v2 are equal, allowing for a small
623 fuzziness factor for floating-point comparisons; false otherwise.
624*/
625
626#ifndef QT_NO_VECTOR2D
627
628/*!
629 Returns the 2D vector form of this 3D vector, dropping the z coordinate.
630
631 \sa toVector4D(), toPoint()
632*/
633QVector2D QVector3D::toVector2D() const
634{
635 return QVector2D(v[0], v[1]);
636}
637
638#endif
639
640#ifndef QT_NO_VECTOR4D
641
642/*!
643 Returns the 4D form of this 3D vector, with the w coordinate set to zero.
644
645 \sa toVector2D(), toPoint()
646*/
647QVector4D QVector3D::toVector4D() const
648{
649 return QVector4D(v[0], v[1], v[2], 0.0f);
650}
651
652#endif
653
654/*!
655 \fn QPoint QVector3D::toPoint() const
656
657 Returns the QPoint form of this 3D vector. The z coordinate
658 is dropped.
659
660 \sa toPointF(), toVector2D()
661*/
662
663/*!
664 \fn QPointF QVector3D::toPointF() const
665
666 Returns the QPointF form of this 3D vector. The z coordinate
667 is dropped.
668
669 \sa toPoint(), toVector2D()
670*/
671
672/*!
673 Returns the 3D vector as a QVariant.
674*/
675QVector3D::operator QVariant() const
676{
677 return QVariant::fromValue(*this);
678}
679
680/*!
681 Returns the length of the vector from the origin.
682
683 \sa lengthSquared(), normalized()
684*/
685float QVector3D::length() const
686{
687 // Need some extra precision if the length is very small.
688 double len = double(v[0]) * double(v[0]) +
689 double(v[1]) * double(v[1]) +
690 double(v[2]) * double(v[2]);
691 return float(std::sqrt(len));
692}
693
694/*!
695 Returns the squared length of the vector from the origin.
696 This is equivalent to the dot product of the vector with itself.
697
698 \sa length(), dotProduct()
699*/
700float QVector3D::lengthSquared() const
701{
702 return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
703}
704
705#ifndef QT_NO_DEBUG_STREAM
706
707QDebug operator<<(QDebug dbg, const QVector3D &vector)
708{
709 QDebugStateSaver saver(dbg);
710 dbg.nospace() << "QVector3D("
711 << vector.x() << ", " << vector.y() << ", " << vector.z() << ')';
712 return dbg;
713}
714
715#endif
716
717#ifndef QT_NO_DATASTREAM
718
719/*!
720 \fn QDataStream &operator<<(QDataStream &stream, const QVector3D &vector)
721 \relates QVector3D
722
723 Writes the given \a vector to the given \a stream and returns a
724 reference to the stream.
725
726 \sa {Serializing Qt Data Types}
727*/
728
729QDataStream &operator<<(QDataStream &stream, const QVector3D &vector)
730{
731 stream << vector.x() << vector.y() << vector.z();
732 return stream;
733}
734
735/*!
736 \fn QDataStream &operator>>(QDataStream &stream, QVector3D &vector)
737 \relates QVector3D
738
739 Reads a 3D vector from the given \a stream into the given \a vector
740 and returns a reference to the stream.
741
742 \sa {Serializing Qt Data Types}
743*/
744
745QDataStream &operator>>(QDataStream &stream, QVector3D &vector)
746{
747 float x, y, z;
748 stream >> x;
749 stream >> y;
750 stream >> z;
751 vector.setX(x);
752 vector.setY(y);
753 vector.setZ(z);
754 return stream;
755}
756
757#endif // QT_NO_DATASTREAM
758
759#endif // QT_NO_VECTOR3D
760
761QT_END_NAMESPACE
762