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

source code of qtbase/src/gui/math3d/qvector3d.cpp