1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D 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 "qtransform.h" |
41 | #include "qtransform_p.h" |
42 | |
43 | #include <Qt3DCore/qpropertyupdatedchange.h> |
44 | |
45 | #include <Qt3DCore/private/qmath3d_p.h> |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | namespace Qt3DCore { |
50 | |
51 | QTransformPrivate::QTransformPrivate() |
52 | : QComponentPrivate() |
53 | , m_rotation() |
54 | , m_scale(1.0f, 1.0f, 1.0f) |
55 | , m_translation() |
56 | , m_eulerRotationAngles() |
57 | , m_matrixDirty(false) |
58 | { |
59 | m_shareable = false; |
60 | } |
61 | |
62 | QTransformPrivate::~QTransformPrivate() |
63 | { |
64 | } |
65 | |
66 | /*! |
67 | \qmltype Transform |
68 | \inqmlmodule Qt3D.Core |
69 | \inherits Component3D |
70 | \instantiates Qt3DCore::QTransform |
71 | \since 5.6 |
72 | \brief Used to perform transforms on meshes. |
73 | |
74 | The Transform component is not shareable between multiple Entity's. |
75 | The transformation is held as vector3d scale, quaternion rotation and |
76 | vector3d translation components. The transformations are applied to the |
77 | mesh in that order. When Transform::matrix property is set, it is decomposed |
78 | to these transform components and corresponding transform signals are emitted. |
79 | |
80 | Several helper functions are provided to set up the Transform; |
81 | fromAxisAndAngle and fromAxesAndAngles can be used to set the rotation around |
82 | specific axes, fromEulerAngles can be used to set the rotation based on euler |
83 | angles and rotateAround can be used to rotate the object around specific point |
84 | relative to local origin. |
85 | */ |
86 | |
87 | /*! |
88 | \qmlproperty matrix4x4 Transform::matrix |
89 | |
90 | Holds the matrix4x4 of the transform. |
91 | \note When the matrix property is set, it is decomposed to translation, rotation and scale components. |
92 | */ |
93 | |
94 | /*! |
95 | \qmlproperty real Transform::rotationX |
96 | |
97 | Holds the x rotation of the transform as Euler angle. |
98 | */ |
99 | |
100 | /*! |
101 | \qmlproperty real Transform::rotationY |
102 | |
103 | Holds the y rotation of the transform as Euler angle. |
104 | */ |
105 | |
106 | /*! |
107 | \qmlproperty real Transform::rotationZ |
108 | |
109 | Holds the z rotation of the transform as Euler angle. |
110 | */ |
111 | |
112 | /*! |
113 | \qmlproperty vector3d Transform::scale3D |
114 | |
115 | Holds the scale of the transform as vector3d. |
116 | */ |
117 | |
118 | /*! |
119 | \qmlproperty real Transform::scale |
120 | |
121 | Holds the uniform scale of the transform. If the scale has been set with scale3D, holds |
122 | the x value only. |
123 | */ |
124 | |
125 | /*! |
126 | \qmlproperty quaternion Transform::rotation |
127 | |
128 | Holds the rotation of the transform as quaternion. |
129 | */ |
130 | |
131 | /*! |
132 | \qmlproperty vector3d Transform::translation |
133 | |
134 | Holds the translation of the transform as vector3d. |
135 | */ |
136 | |
137 | /*! |
138 | \qmlproperty matrix4x4 QTransform::worldMatrix |
139 | |
140 | Holds the world transformation matrix for the transform. This assumes the |
141 | Transform component is being referenced by an Entity. This makes it more |
142 | convenient to identify when an Entity part of a subtree has been |
143 | transformed in the world even though its local transformation might not |
144 | have changed. |
145 | |
146 | \since 5.14 |
147 | */ |
148 | |
149 | /*! |
150 | \qmlmethod quaternion Transform::fromAxisAndAngle(vector3d axis, real angle) |
151 | Creates a quaternion from \a axis and \a angle. |
152 | Returns the resulting quaternion. |
153 | */ |
154 | |
155 | /*! |
156 | \qmlmethod quaternion Transform::fromAxisAndAngle(real x, real y, real z, real angle) |
157 | Creates a quaternion from \a x, \a y, \a z, and \a angle. |
158 | Returns the resulting quaternion. |
159 | */ |
160 | |
161 | /*! |
162 | \qmlmethod quaternion Transform::fromAxesAndAngles(vector3d axis1, real angle1, |
163 | vector3d axis2, real angle2) |
164 | Creates a quaternion from \a axis1, \a angle1, \a axis2, and \a angle2. |
165 | Returns the resulting quaternion. |
166 | */ |
167 | |
168 | /*! |
169 | \qmlmethod quaternion Transform::fromAxesAndAngles(vector3d axis1, real angle1, |
170 | vector3d axis2, real angle2, |
171 | vector3d axis3, real angle3) |
172 | Creates a quaternion from \a axis1, \a angle1, \a axis2, \a angle2, \a axis3, and \a angle3. |
173 | Returns the resulting quaternion. |
174 | */ |
175 | |
176 | /*! |
177 | \qmlmethod quaternion Transform::fromEulerAngles(vector3d eulerAngles) |
178 | Creates a quaternion from \a eulerAngles. |
179 | Returns the resulting quaternion. |
180 | */ |
181 | |
182 | /*! |
183 | \qmlmethod quaternion Transform::fromEulerAngles(real pitch, real yaw, real roll) |
184 | Creates a quaternion from \a pitch, \a yaw, and \a roll. |
185 | Returns the resulting quaternion. |
186 | */ |
187 | |
188 | /*! |
189 | \qmlmethod matrix4x4 Transform::rotateAround(vector3d point, real angle, vector3d axis) |
190 | Creates a rotation matrix from \a axis and \a angle around \a point relative to local origin. |
191 | Returns the resulting matrix4x4. |
192 | */ |
193 | |
194 | /*! |
195 | \class Qt3DCore::QTransform |
196 | \inmodule Qt3DCore |
197 | \inherits Qt3DCore::QComponent |
198 | \since 5.6 |
199 | \brief Used to perform transforms on meshes. |
200 | |
201 | The QTransform component is not shareable between multiple QEntity's. |
202 | The transformation is held as QVector3D scale, QQuaternion rotation and |
203 | QVector3D translation components. The transformations are applied to the |
204 | mesh in that order. When QTransform::matrix property is set, it is decomposed |
205 | to these transform components and corresponding signals are emitted. |
206 | |
207 | Several helper functions are provided to set up the QTransform; |
208 | fromAxisAndAngle and fromAxesAndAngles can be used to set the rotation around |
209 | specific axes, fromEulerAngles can be used to set the rotation based on euler |
210 | angles and rotateAround can be used to rotate the object around specific point |
211 | relative to local origin. |
212 | */ |
213 | |
214 | /*! |
215 | Constructs a new QTransform with \a parent. |
216 | */ |
217 | QTransform::QTransform(QNode *parent) |
218 | : QComponent(*new QTransformPrivate, parent) |
219 | { |
220 | } |
221 | |
222 | /*! |
223 | \internal |
224 | */ |
225 | QTransform::~QTransform() |
226 | { |
227 | } |
228 | |
229 | /*! |
230 | \internal |
231 | */ |
232 | QTransform::QTransform(QTransformPrivate &dd, QNode *parent) |
233 | : QComponent(dd, parent) |
234 | { |
235 | } |
236 | |
237 | /*! |
238 | \internal |
239 | */ |
240 | // TODO Unused remove in Qt6 |
241 | void QTransform::sceneChangeEvent(const QSceneChangePtr &change) |
242 | { |
243 | Q_D(QTransform); |
244 | switch (change->type()) { |
245 | case PropertyUpdated: { |
246 | Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(src: change); |
247 | if (propertyChange->propertyName() == QByteArrayLiteral("worldMatrix" )) { |
248 | const bool blocked = blockNotifications(block: true); |
249 | d->setWorldMatrix(propertyChange->value().value<QMatrix4x4>()); |
250 | blockNotifications(block: blocked); |
251 | } |
252 | break; |
253 | } |
254 | default: |
255 | break; |
256 | } |
257 | } |
258 | |
259 | void QTransformPrivate::setWorldMatrix(const QMatrix4x4 &worldMatrix) |
260 | { |
261 | Q_Q(QTransform); |
262 | if (m_worldMatrix == worldMatrix) |
263 | return; |
264 | m_worldMatrix = worldMatrix; |
265 | emit q->worldMatrixChanged(worldMatrix); |
266 | } |
267 | |
268 | void QTransform::setMatrix(const QMatrix4x4 &m) |
269 | { |
270 | Q_D(QTransform); |
271 | if (m != matrix()) { |
272 | d->m_matrix = m; |
273 | d->m_matrixDirty = false; |
274 | |
275 | QVector3D s; |
276 | QVector3D t; |
277 | QQuaternion r; |
278 | decomposeQMatrix4x4(m, position&: t, orientation&: r, scale&: s); |
279 | d->m_scale = s; |
280 | d->m_rotation = r; |
281 | d->m_translation = t; |
282 | d->m_eulerRotationAngles = d->m_rotation.toEulerAngles(); |
283 | emit scale3DChanged(scale: s); |
284 | emit rotationChanged(rotation: r); |
285 | emit translationChanged(translation: t); |
286 | const bool wasBlocked = blockNotifications(block: true); |
287 | emit matrixChanged(); |
288 | emit scaleChanged(scale: d->m_scale.x()); |
289 | emit rotationXChanged(rotationX: d->m_eulerRotationAngles.x()); |
290 | emit rotationYChanged(rotationY: d->m_eulerRotationAngles.y()); |
291 | emit rotationZChanged(rotationZ: d->m_eulerRotationAngles.z()); |
292 | blockNotifications(block: wasBlocked); |
293 | } |
294 | } |
295 | |
296 | void QTransform::setRotationX(float rotationX) |
297 | { |
298 | Q_D(QTransform); |
299 | |
300 | if (d->m_eulerRotationAngles.x() == rotationX) |
301 | return; |
302 | |
303 | d->m_eulerRotationAngles.setX(rotationX); |
304 | QQuaternion rotation = QQuaternion::fromEulerAngles(eulerAngles: d->m_eulerRotationAngles); |
305 | if (rotation != d->m_rotation) { |
306 | d->m_rotation = rotation; |
307 | d->m_matrixDirty = true; |
308 | emit rotationChanged(rotation); |
309 | } |
310 | |
311 | const bool wasBlocked = blockNotifications(block: true); |
312 | emit rotationXChanged(rotationX); |
313 | emit matrixChanged(); |
314 | blockNotifications(block: wasBlocked); |
315 | } |
316 | |
317 | void QTransform::setRotationY(float rotationY) |
318 | { |
319 | Q_D(QTransform); |
320 | |
321 | if (d->m_eulerRotationAngles.y() == rotationY) |
322 | return; |
323 | |
324 | d->m_eulerRotationAngles.setY(rotationY); |
325 | QQuaternion rotation = QQuaternion::fromEulerAngles(eulerAngles: d->m_eulerRotationAngles); |
326 | if (rotation != d->m_rotation) { |
327 | d->m_rotation = rotation; |
328 | d->m_matrixDirty = true; |
329 | emit rotationChanged(rotation); |
330 | } |
331 | |
332 | const bool wasBlocked = blockNotifications(block: true); |
333 | emit rotationYChanged(rotationY); |
334 | emit matrixChanged(); |
335 | blockNotifications(block: wasBlocked); |
336 | } |
337 | |
338 | void QTransform::setRotationZ(float rotationZ) |
339 | { |
340 | Q_D(QTransform); |
341 | if (d->m_eulerRotationAngles.z() == rotationZ) |
342 | return; |
343 | |
344 | d->m_eulerRotationAngles.setZ(rotationZ); |
345 | QQuaternion rotation = QQuaternion::fromEulerAngles(eulerAngles: d->m_eulerRotationAngles); |
346 | if (rotation != d->m_rotation) { |
347 | d->m_rotation = rotation; |
348 | d->m_matrixDirty = true; |
349 | emit rotationChanged(rotation); |
350 | } |
351 | |
352 | const bool wasBlocked = blockNotifications(block: true); |
353 | emit rotationZChanged(rotationZ); |
354 | emit matrixChanged(); |
355 | blockNotifications(block: wasBlocked); |
356 | } |
357 | |
358 | /*! |
359 | \property Qt3DCore::QTransform::matrix |
360 | |
361 | Holds the QMatrix4x4 of the transform. |
362 | \note When the matrix property is set, it is decomposed to translation, rotation and scale components. |
363 | */ |
364 | QMatrix4x4 QTransform::matrix() const |
365 | { |
366 | Q_D(const QTransform); |
367 | if (d->m_matrixDirty) { |
368 | composeQMatrix4x4(position: d->m_translation, orientation: d->m_rotation, scale: d->m_scale, m&: d->m_matrix); |
369 | d->m_matrixDirty = false; |
370 | } |
371 | return d->m_matrix; |
372 | } |
373 | |
374 | /*! |
375 | \property QTransform::worldMatrix |
376 | |
377 | Holds the world transformation matrix for the transform. This assumes the |
378 | QTransform component is being referenced by a QEntity. This makes it more |
379 | convenient to identify when a QEntity part of a subtree has been |
380 | transformed in the world even though its local transformation might not |
381 | have changed. |
382 | |
383 | \since 5.14 |
384 | */ |
385 | |
386 | /*! |
387 | Returns the world transformation matrix associated to the QTransform when |
388 | referenced by a QEntity which may be part of a QEntity hierarchy. |
389 | |
390 | \since 5.14 |
391 | */ |
392 | QMatrix4x4 QTransform::worldMatrix() const |
393 | { |
394 | Q_D(const QTransform); |
395 | return d->m_worldMatrix; |
396 | } |
397 | |
398 | /*! |
399 | \property Qt3DCore::QTransform::rotationX |
400 | |
401 | Holds the x rotation of the transform as Euler angle. |
402 | */ |
403 | float QTransform::rotationX() const |
404 | { |
405 | Q_D(const QTransform); |
406 | return d->m_eulerRotationAngles.x(); |
407 | } |
408 | |
409 | /*! |
410 | \property Qt3DCore::QTransform::rotationY |
411 | |
412 | Holds the y rotation of the transform as Euler angle. |
413 | */ |
414 | float QTransform::rotationY() const |
415 | { |
416 | Q_D(const QTransform); |
417 | return d->m_eulerRotationAngles.y(); |
418 | } |
419 | |
420 | /*! |
421 | \property Qt3DCore::QTransform::rotationZ |
422 | |
423 | Holds the z rotation of the transform as Euler angle. |
424 | */ |
425 | float QTransform::rotationZ() const |
426 | { |
427 | Q_D(const QTransform); |
428 | return d->m_eulerRotationAngles.z(); |
429 | } |
430 | |
431 | void QTransform::setScale3D(const QVector3D &scale) |
432 | { |
433 | Q_D(QTransform); |
434 | if (scale != d->m_scale) { |
435 | d->m_scale = scale; |
436 | d->m_matrixDirty = true; |
437 | emit scale3DChanged(scale); |
438 | |
439 | const bool wasBlocked = blockNotifications(block: true); |
440 | emit matrixChanged(); |
441 | blockNotifications(block: wasBlocked); |
442 | } |
443 | } |
444 | |
445 | /*! |
446 | \property Qt3DCore::QTransform::scale3D |
447 | |
448 | Holds the scale of the transform as QVector3D. |
449 | */ |
450 | QVector3D QTransform::scale3D() const |
451 | { |
452 | Q_D(const QTransform); |
453 | return d->m_scale; |
454 | } |
455 | |
456 | void QTransform::setScale(float scale) |
457 | { |
458 | Q_D(QTransform); |
459 | if (scale != d->m_scale.x()) { |
460 | setScale3D(QVector3D(scale, scale, scale)); |
461 | |
462 | const bool wasBlocked = blockNotifications(block: true); |
463 | emit scaleChanged(scale); |
464 | blockNotifications(block: wasBlocked); |
465 | } |
466 | } |
467 | |
468 | /*! |
469 | \property Qt3DCore::QTransform::scale |
470 | |
471 | Holds the uniform scale of the transform. If the scale has been set with setScale3D, holds |
472 | the x value only. |
473 | */ |
474 | float QTransform::scale() const |
475 | { |
476 | Q_D(const QTransform); |
477 | return d->m_scale.x(); |
478 | } |
479 | |
480 | void QTransform::setRotation(const QQuaternion &rotation) |
481 | { |
482 | Q_D(QTransform); |
483 | if (rotation != d->m_rotation) { |
484 | d->m_rotation = rotation; |
485 | const QVector3D oldRotation = d->m_eulerRotationAngles; |
486 | d->m_eulerRotationAngles = d->m_rotation.toEulerAngles(); |
487 | d->m_matrixDirty = true; |
488 | emit rotationChanged(rotation); |
489 | |
490 | const bool wasBlocked = blockNotifications(block: true); |
491 | emit matrixChanged(); |
492 | if (d->m_eulerRotationAngles.x() != oldRotation.x()) |
493 | emit rotationXChanged(rotationX: d->m_eulerRotationAngles.x()); |
494 | if (d->m_eulerRotationAngles.y() != oldRotation.y()) |
495 | emit rotationYChanged(rotationY: d->m_eulerRotationAngles.y()); |
496 | if (d->m_eulerRotationAngles.z() != oldRotation.z()) |
497 | emit rotationZChanged(rotationZ: d->m_eulerRotationAngles.z()); |
498 | blockNotifications(block: wasBlocked); |
499 | } |
500 | } |
501 | |
502 | /*! |
503 | \property Qt3DCore::QTransform::rotation |
504 | |
505 | Holds the rotation of the transform as QQuaternion. |
506 | */ |
507 | QQuaternion QTransform::rotation() const |
508 | { |
509 | Q_D(const QTransform); |
510 | return d->m_rotation; |
511 | } |
512 | |
513 | void QTransform::setTranslation(const QVector3D &translation) |
514 | { |
515 | Q_D(QTransform); |
516 | if (translation != d->m_translation) { |
517 | d->m_translation = translation; |
518 | d->m_matrixDirty = true; |
519 | emit translationChanged(translation); |
520 | |
521 | const bool wasBlocked = blockNotifications(block: true); |
522 | emit matrixChanged(); |
523 | blockNotifications(block: wasBlocked); |
524 | } |
525 | } |
526 | |
527 | /*! |
528 | \property Qt3DCore::QTransform::translation |
529 | |
530 | Holds the translation of the transform as QVector3D. |
531 | */ |
532 | QVector3D QTransform::translation() const |
533 | { |
534 | Q_D(const QTransform); |
535 | return d->m_translation; |
536 | } |
537 | |
538 | /*! |
539 | Creates a QQuaternion from \a axis and \a angle. |
540 | Returns the resulting QQuaternion. |
541 | */ |
542 | QQuaternion QTransform::fromAxisAndAngle(const QVector3D &axis, float angle) |
543 | { |
544 | return QQuaternion::fromAxisAndAngle(axis, angle); |
545 | } |
546 | |
547 | /*! |
548 | Creates a QQuaternion from \a x, \a y, \a z, and \a angle. |
549 | Returns the resulting QQuaternion. |
550 | */ |
551 | QQuaternion QTransform::fromAxisAndAngle(float x, float y, float z, float angle) |
552 | { |
553 | return QQuaternion::fromAxisAndAngle(x, y, z, angle); |
554 | } |
555 | |
556 | /*! |
557 | Creates a QQuaternion from \a axis1, \a angle1, \a axis2, and \a angle2. |
558 | Returns the resulting QQuaternion. |
559 | */ |
560 | QQuaternion QTransform::fromAxesAndAngles(const QVector3D &axis1, float angle1, |
561 | const QVector3D &axis2, float angle2) |
562 | { |
563 | const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis: axis1, angle: angle1); |
564 | const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis: axis2, angle: angle2); |
565 | return q2 * q1; |
566 | } |
567 | |
568 | /*! |
569 | Creates a QQuaternion from \a axis1, \a angle1, \a axis2, \a angle2, \a axis3, and \a angle3. |
570 | Returns the resulting QQuaternion. |
571 | */ |
572 | QQuaternion QTransform::fromAxesAndAngles(const QVector3D &axis1, float angle1, |
573 | const QVector3D &axis2, float angle2, |
574 | const QVector3D &axis3, float angle3) |
575 | { |
576 | const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis: axis1, angle: angle1); |
577 | const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis: axis2, angle: angle2); |
578 | const QQuaternion q3 = QQuaternion::fromAxisAndAngle(axis: axis3, angle: angle3); |
579 | return q3 * q2 * q1; |
580 | } |
581 | |
582 | /*! |
583 | Creates a QQuaterniom definining a rotation from the axes \a xAxis, \a yAxis and \a zAxis. |
584 | \since 5.11 |
585 | */ |
586 | QQuaternion QTransform::fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis) |
587 | { |
588 | return QQuaternion::fromAxes(xAxis, yAxis, zAxis); |
589 | } |
590 | |
591 | /*! |
592 | Creates a QQuaternion from \a eulerAngles. |
593 | Returns the resulting QQuaternion. |
594 | */ |
595 | QQuaternion QTransform::fromEulerAngles(const QVector3D &eulerAngles) |
596 | { |
597 | return QQuaternion::fromEulerAngles(eulerAngles); |
598 | } |
599 | |
600 | /*! |
601 | Creates a QQuaternion from \a pitch, \a yaw, and \a roll. |
602 | Returns the resulting QQuaternion. |
603 | */ |
604 | QQuaternion QTransform::fromEulerAngles(float pitch, float yaw, float roll) |
605 | { |
606 | return QQuaternion::fromEulerAngles(pitch, yaw, roll); |
607 | } |
608 | |
609 | /*! |
610 | Creates a rotation matrix from \a axis and \a angle around \a point. |
611 | Returns the resulting QMatrix4x4. |
612 | */ |
613 | QMatrix4x4 QTransform::rotateAround(const QVector3D &point, float angle, const QVector3D &axis) |
614 | { |
615 | QMatrix4x4 m; |
616 | m.translate(vector: point); |
617 | m.rotate(angle, vector: axis); |
618 | m.translate(vector: -point); |
619 | return m; |
620 | } |
621 | |
622 | /*! |
623 | Returns a rotation matrix defined from the axes \a xAxis, \a yAxis, \a zAxis. |
624 | \since 5.11 |
625 | */ |
626 | QMatrix4x4 QTransform::rotateFromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis) |
627 | { |
628 | return QMatrix4x4(xAxis.x(), yAxis.x(), zAxis.x(), 0.0f, |
629 | xAxis.y(), yAxis.y(), zAxis.y(), 0.0f, |
630 | xAxis.z(), yAxis.z(), zAxis.z(), 0.0f, |
631 | 0.0f, 0.0f, 0.0f, 1.0f); |
632 | } |
633 | |
634 | QNodeCreatedChangeBasePtr QTransform::createNodeCreationChange() const |
635 | { |
636 | auto creationChange = QNodeCreatedChangePtr<QTransformData>::create(arguments: this); |
637 | auto &data = creationChange->data; |
638 | |
639 | Q_D(const QTransform); |
640 | data.rotation = d->m_rotation; |
641 | data.scale = d->m_scale; |
642 | data.translation = d->m_translation; |
643 | |
644 | return creationChange; |
645 | } |
646 | |
647 | } // namespace Qt3DCore |
648 | |
649 | QT_END_NAMESPACE |
650 | |
651 | #include "moc_qtransform.cpp" |
652 | |