From 18f24ffd685ee201f60f67a223548744ec3a38b0 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 1 Jul 2021 16:24:02 +0300 Subject: [PATCH] QmlPuppet: Fix multiselection fit object in 3D editor Multiselection is now properly fit to the view when fit object is used. Fixes: QDS-4608 Change-Id: Ia80133fc861bd177b9102423ebef37b592c74758 Reviewed-by: Mahmoud Badri --- .../mockfiles/qt5/EditCameraController.qml | 13 ++- .../qmlpuppet/mockfiles/qt5/EditView3D.qml | 16 ++- .../mockfiles/qt6/EditCameraController.qml | 13 ++- .../qmlpuppet/mockfiles/qt6/EditView3D.qml | 16 ++- .../qml2puppet/editor3d/generalhelper.cpp | 110 ++++++++++++------ .../qml2puppet/editor3d/generalhelper.h | 8 +- 6 files changed, 121 insertions(+), 55 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditCameraController.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditCameraController.qml index 2b23117aa28..55e310f053d 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditCameraController.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditCameraController.qml @@ -88,14 +88,21 @@ Item { } - function focusObject(targetObject, rotation, updateZoom, closeUp) + function focusObject(targetNodes, rotation, updateZoom, closeUp) { if (!camera) return; + // targetNodes could be a list of nodes or a single node + var nodes = []; + if (targetNodes instanceof Node) + nodes.push(targetNodes); + else + nodes = targetNodes + camera.eulerRotation = rotation; - var newLookAtAndZoom = _generalHelper.focusObjectToCamera( - camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, + var newLookAtAndZoom = _generalHelper.focusNodesToCamera( + camera, _defaultCameraLookAtDistance, nodes, view3d, _zoomFactor, updateZoom, closeUp); _lookAtPoint = newLookAtAndZoom.toVector3d(); _zoomFactor = newLookAtAndZoom.w; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 318673e0c9e..cda0808b734 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -176,9 +176,16 @@ Item { function fitToView() { if (editView) { - var targetNode = selectionBoxes.length > 0 - ? selectionBoxes[0].model : null; - cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true, false); + var boxModels = []; + if (selectedNodes.length > 1) { + for (var i = 0; i < selectedNodes.length; ++i) { + if (selectionBoxes.length > i) + boxModels.push(selectionBoxes[i].model) + } + } else if (selectedNodes.length > 0 && selectionBoxes.length > 0) { + boxModels.push(selectionBoxes[0].model); + } + cameraControl.focusObject(boxModels, editView.camera.eulerRotation, true, false); } } @@ -857,7 +864,8 @@ Item { width: 100 height: width editCameraCtrl: cameraControl - selectedNode : viewRoot.selectedNodes.length ? selectionBoxes[0].model : null + selectedNode: viewRoot.selectedNodes.length === 1 ? viewRoot.selectionBoxes[0].model + : viewRoot.selectedNode } Text { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditCameraController.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditCameraController.qml index 223f8ab74f0..13743094219 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditCameraController.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditCameraController.qml @@ -88,14 +88,21 @@ Item { } - function focusObject(targetObject, rotation, updateZoom, closeUp) + function focusObject(targetNodes, rotation, updateZoom, closeUp) { if (!camera) return; + // targetNodes could be a list of nodes or a single node + var nodes = []; + if (targetNodes instanceof Node) + nodes.push(targetNodes); + else + nodes = targetNodes + camera.eulerRotation = rotation; - var newLookAtAndZoom = _generalHelper.focusObjectToCamera( - camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor, + var newLookAtAndZoom = _generalHelper.focusNodesToCamera( + camera, _defaultCameraLookAtDistance, nodes, view3d, _zoomFactor, updateZoom, closeUp); _lookAtPoint = newLookAtAndZoom.toVector3d(); _zoomFactor = newLookAtAndZoom.w; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 18f444baa50..83e37050402 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -176,9 +176,16 @@ Item { function fitToView() { if (editView) { - var targetNode = selectionBoxes.length > 0 - ? selectionBoxes[0].model : null; - cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true, false); + var boxModels = []; + if (selectedNodes.length > 1) { + for (var i = 0; i < selectedNodes.length; ++i) { + if (selectionBoxes.length > i) + boxModels.push(selectionBoxes[i].model) + } + } else if (selectedNodes.length > 0 && selectionBoxes.length > 0) { + boxModels.push(selectionBoxes[0].model); + } + cameraControl.focusObject(boxModels, editView.camera.eulerRotation, true, false); } } @@ -857,7 +864,8 @@ Item { width: 100 height: width editCameraCtrl: cameraControl - selectedNode : viewRoot.selectedNodes.length ? selectionBoxes[0].model : null + selectedNode: viewRoot.selectedNodes.length === 1 ? viewRoot.selectionBoxes[0].model + : viewRoot.selectedNode } Text { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index d76d335fd7e..39ca48b8e31 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -46,6 +46,8 @@ #include #include +#include + namespace QmlDesigner { namespace Internal { @@ -151,56 +153,90 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de } // Return value contains new lookAt point (xyz) and zoom factor (w) -QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, - QQuick3DNode *targetObject, QQuick3DViewport *viewPort, - float oldZoom, bool updateZoom, bool closeUp) +QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, + const QVariant &nodes, QQuick3DViewport *viewPort, + float oldZoom, bool updateZoom, bool closeUp) { if (!camera) return QVector4D(0.f, 0.f, 0.f, 1.f); - QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D(); + QList nodeList; + const QVariantList varNodes = nodes.value(); + for (const auto &varNode : varNodes) { + auto model = varNode.value(); + if (model) + nodeList.append(model); + } - // Get object bounds + // Get bounds + QVector3D totalMinBound; + QVector3D totalMaxBound; const qreal defaultExtent = 200.; - qreal maxExtent = defaultExtent; - if (auto modelNode = qobject_cast(targetObject)) { - auto targetPriv = QQuick3DObjectPrivate::get(targetObject); - if (auto renderModel = static_cast(targetPriv->spatialNode)) { - QWindow *window = static_cast(viewPort->window()); - if (window) { - QSSGRef context; + + if (!nodeList.isEmpty()) { + static const float floatMin = std::numeric_limits::lowest(); + static const float floatMax = std::numeric_limits::max(); + totalMinBound = {floatMax, floatMax, floatMax}; + totalMaxBound = {floatMin, floatMin, floatMin}; + } else { + const float halfExtent = defaultExtent / 2.f; + totalMinBound = {-halfExtent, -halfExtent, -halfExtent}; + totalMaxBound = {halfExtent, halfExtent, halfExtent}; + } + for (const auto node : qAsConst(nodeList)) { + auto model = qobject_cast(node); + qreal maxExtent = defaultExtent; + QVector3D center = node->scenePosition(); + if (model) { + auto targetPriv = QQuick3DObjectPrivate::get(model); + if (auto renderModel = static_cast(targetPriv->spatialNode)) { + QWindow *window = static_cast(viewPort->window()); + if (window) { + QSSGRef context; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window)); + context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window)); #else - context = targetPriv->sceneManager->rci; + context = targetPriv->sceneManager->rci; #endif - if (!context.isNull()) { - QSSGBounds3 bounds; - auto geometry = qobject_cast(modelNode->geometry()); - if (geometry) { - bounds = geometry->bounds(); - } else { - auto bufferManager = context->bufferManager(); - bounds = renderModel->getModelBounds(bufferManager); + if (!context.isNull()) { + QSSGBounds3 bounds; + auto geometry = qobject_cast(model->geometry()); + if (geometry) { + bounds = geometry->bounds(); + } else { + auto bufferManager = context->bufferManager(); + bounds = renderModel->getModelBounds(bufferManager); + } + + center = renderModel->globalTransform.map(bounds.center()); + const QVector3D e = bounds.extents(); + const QVector3D s = model->sceneScale(); + qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z())); + maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z())); + maxExtent *= maxScale; + + if (maxExtent < 0.0001) + maxExtent = defaultExtent; } - - QVector3D center = bounds.center(); - const QVector3D e = bounds.extents(); - const QVector3D s = targetObject->sceneScale(); - qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z())); - maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z())); - maxExtent *= maxScale; - - if (maxExtent < 0.0001) - maxExtent = defaultExtent; - - // Adjust lookAt to look directly at the center of the object bounds - lookAt = renderModel->globalTransform.map(center); } } } + float halfExtent = float(maxExtent / 2.); + const QVector3D halfExtents {halfExtent, halfExtent, halfExtent}; + + const QVector3D minBound = center - halfExtents; + const QVector3D maxBound = center + halfExtents; + + for (int i = 0; i < 3; ++i) { + totalMinBound[i] = qMin(minBound[i], totalMinBound[i]); + totalMaxBound[i] = qMax(maxBound[i], totalMaxBound[i]); + } } + QVector3D extents = totalMaxBound - totalMinBound; + QVector3D lookAt = totalMinBound + (extents / 2.f); + float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z())); + // Reset camera position to default zoom QMatrix4x4 m = camera->sceneTransform(); const float *dataPtr(m.data()); @@ -210,9 +246,9 @@ QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defau camera->setPosition(lookAt + newLookVector); - qreal divisor = closeUp ? 900. : 725.; + float divisor = closeUp ? 900.f : 725.f; - float newZoomFactor = updateZoom ? qBound(.01f, float(maxExtent / divisor), 100.f) : oldZoom; + float newZoomFactor = updateZoom ? qBound(.01f, maxExtent / divisor, 100.f) : oldZoom; float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false); return QVector4D(lookAt, cameraZoomFactor); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 05ec29249eb..6e888980f81 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -67,10 +67,10 @@ public: Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance, float defaultLookAtDistance, const QVector3D &lookAt, float zoomFactor, bool relative); - Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, - QQuick3DNode *targetObject, QQuick3DViewport *viewPort, - float oldZoom, bool updateZoom = true, - bool closeUp = false); + Q_INVOKABLE QVector4D focusNodesToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, + const QVariant &nodes, QQuick3DViewport *viewPort, + float oldZoom, bool updateZoom = true, + bool closeUp = false); Q_INVOKABLE bool fuzzyCompare(double a, double b); Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property, const QVariant& value);