forked from qt-creator/qt-creator
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 <mahmoud.badri@qt.io>
This commit is contained in:
@@ -88,14 +88,21 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function focusObject(targetObject, rotation, updateZoom, closeUp)
|
function focusObject(targetNodes, rotation, updateZoom, closeUp)
|
||||||
{
|
{
|
||||||
if (!camera)
|
if (!camera)
|
||||||
return;
|
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;
|
camera.eulerRotation = rotation;
|
||||||
var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
|
var newLookAtAndZoom = _generalHelper.focusNodesToCamera(
|
||||||
camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor,
|
camera, _defaultCameraLookAtDistance, nodes, view3d, _zoomFactor,
|
||||||
updateZoom, closeUp);
|
updateZoom, closeUp);
|
||||||
_lookAtPoint = newLookAtAndZoom.toVector3d();
|
_lookAtPoint = newLookAtAndZoom.toVector3d();
|
||||||
_zoomFactor = newLookAtAndZoom.w;
|
_zoomFactor = newLookAtAndZoom.w;
|
||||||
|
@@ -176,9 +176,16 @@ Item {
|
|||||||
function fitToView()
|
function fitToView()
|
||||||
{
|
{
|
||||||
if (editView) {
|
if (editView) {
|
||||||
var targetNode = selectionBoxes.length > 0
|
var boxModels = [];
|
||||||
? selectionBoxes[0].model : null;
|
if (selectedNodes.length > 1) {
|
||||||
cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true, false);
|
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
|
width: 100
|
||||||
height: width
|
height: width
|
||||||
editCameraCtrl: cameraControl
|
editCameraCtrl: cameraControl
|
||||||
selectedNode : viewRoot.selectedNodes.length ? selectionBoxes[0].model : null
|
selectedNode: viewRoot.selectedNodes.length === 1 ? viewRoot.selectionBoxes[0].model
|
||||||
|
: viewRoot.selectedNode
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@@ -88,14 +88,21 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function focusObject(targetObject, rotation, updateZoom, closeUp)
|
function focusObject(targetNodes, rotation, updateZoom, closeUp)
|
||||||
{
|
{
|
||||||
if (!camera)
|
if (!camera)
|
||||||
return;
|
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;
|
camera.eulerRotation = rotation;
|
||||||
var newLookAtAndZoom = _generalHelper.focusObjectToCamera(
|
var newLookAtAndZoom = _generalHelper.focusNodesToCamera(
|
||||||
camera, _defaultCameraLookAtDistance, targetObject, view3d, _zoomFactor,
|
camera, _defaultCameraLookAtDistance, nodes, view3d, _zoomFactor,
|
||||||
updateZoom, closeUp);
|
updateZoom, closeUp);
|
||||||
_lookAtPoint = newLookAtAndZoom.toVector3d();
|
_lookAtPoint = newLookAtAndZoom.toVector3d();
|
||||||
_zoomFactor = newLookAtAndZoom.w;
|
_zoomFactor = newLookAtAndZoom.w;
|
||||||
|
@@ -176,9 +176,16 @@ Item {
|
|||||||
function fitToView()
|
function fitToView()
|
||||||
{
|
{
|
||||||
if (editView) {
|
if (editView) {
|
||||||
var targetNode = selectionBoxes.length > 0
|
var boxModels = [];
|
||||||
? selectionBoxes[0].model : null;
|
if (selectedNodes.length > 1) {
|
||||||
cameraControl.focusObject(targetNode, editView.camera.eulerRotation, true, false);
|
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
|
width: 100
|
||||||
height: width
|
height: width
|
||||||
editCameraCtrl: cameraControl
|
editCameraCtrl: cameraControl
|
||||||
selectedNode : viewRoot.selectedNodes.length ? selectionBoxes[0].model : null
|
selectedNode: viewRoot.selectedNodes.length === 1 ? viewRoot.selectionBoxes[0].model
|
||||||
|
: viewRoot.selectedNode
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@@ -46,6 +46,8 @@
|
|||||||
#include <QtQuick/qquickitem.h>
|
#include <QtQuick/qquickitem.h>
|
||||||
#include <QtCore/qmath.h>
|
#include <QtCore/qmath.h>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -151,20 +153,42 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return value contains new lookAt point (xyz) and zoom factor (w)
|
// Return value contains new lookAt point (xyz) and zoom factor (w)
|
||||||
QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
|
const QVariant &nodes, QQuick3DViewport *viewPort,
|
||||||
float oldZoom, bool updateZoom, bool closeUp)
|
float oldZoom, bool updateZoom, bool closeUp)
|
||||||
{
|
{
|
||||||
if (!camera)
|
if (!camera)
|
||||||
return QVector4D(0.f, 0.f, 0.f, 1.f);
|
return QVector4D(0.f, 0.f, 0.f, 1.f);
|
||||||
|
|
||||||
QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D();
|
QList<QQuick3DNode *> nodeList;
|
||||||
|
const QVariantList varNodes = nodes.value<QVariantList>();
|
||||||
|
for (const auto &varNode : varNodes) {
|
||||||
|
auto model = varNode.value<QQuick3DNode *>();
|
||||||
|
if (model)
|
||||||
|
nodeList.append(model);
|
||||||
|
}
|
||||||
|
|
||||||
// Get object bounds
|
// Get bounds
|
||||||
|
QVector3D totalMinBound;
|
||||||
|
QVector3D totalMaxBound;
|
||||||
const qreal defaultExtent = 200.;
|
const qreal defaultExtent = 200.;
|
||||||
|
|
||||||
|
if (!nodeList.isEmpty()) {
|
||||||
|
static const float floatMin = std::numeric_limits<float>::lowest();
|
||||||
|
static const float floatMax = std::numeric_limits<float>::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<QQuick3DModel *>(node);
|
||||||
qreal maxExtent = defaultExtent;
|
qreal maxExtent = defaultExtent;
|
||||||
if (auto modelNode = qobject_cast<QQuick3DModel *>(targetObject)) {
|
QVector3D center = node->scenePosition();
|
||||||
auto targetPriv = QQuick3DObjectPrivate::get(targetObject);
|
if (model) {
|
||||||
|
auto targetPriv = QQuick3DObjectPrivate::get(model);
|
||||||
if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
|
if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
|
||||||
QWindow *window = static_cast<QWindow *>(viewPort->window());
|
QWindow *window = static_cast<QWindow *>(viewPort->window());
|
||||||
if (window) {
|
if (window) {
|
||||||
@@ -176,7 +200,7 @@ QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defau
|
|||||||
#endif
|
#endif
|
||||||
if (!context.isNull()) {
|
if (!context.isNull()) {
|
||||||
QSSGBounds3 bounds;
|
QSSGBounds3 bounds;
|
||||||
auto geometry = qobject_cast<SelectionBoxGeometry *>(modelNode->geometry());
|
auto geometry = qobject_cast<SelectionBoxGeometry *>(model->geometry());
|
||||||
if (geometry) {
|
if (geometry) {
|
||||||
bounds = geometry->bounds();
|
bounds = geometry->bounds();
|
||||||
} else {
|
} else {
|
||||||
@@ -184,23 +208,35 @@ QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defau
|
|||||||
bounds = renderModel->getModelBounds(bufferManager);
|
bounds = renderModel->getModelBounds(bufferManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector3D center = bounds.center();
|
center = renderModel->globalTransform.map(bounds.center());
|
||||||
const QVector3D e = bounds.extents();
|
const QVector3D e = bounds.extents();
|
||||||
const QVector3D s = targetObject->sceneScale();
|
const QVector3D s = model->sceneScale();
|
||||||
qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z()));
|
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 = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z()));
|
||||||
maxExtent *= maxScale;
|
maxExtent *= maxScale;
|
||||||
|
|
||||||
if (maxExtent < 0.0001)
|
if (maxExtent < 0.0001)
|
||||||
maxExtent = defaultExtent;
|
maxExtent = defaultExtent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float halfExtent = float(maxExtent / 2.);
|
||||||
|
const QVector3D halfExtents {halfExtent, halfExtent, halfExtent};
|
||||||
|
|
||||||
// Adjust lookAt to look directly at the center of the object bounds
|
const QVector3D minBound = center - halfExtents;
|
||||||
lookAt = renderModel->globalTransform.map(center);
|
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
|
// Reset camera position to default zoom
|
||||||
QMatrix4x4 m = camera->sceneTransform();
|
QMatrix4x4 m = camera->sceneTransform();
|
||||||
const float *dataPtr(m.data());
|
const float *dataPtr(m.data());
|
||||||
@@ -210,9 +246,9 @@ QVector4D GeneralHelper::focusObjectToCamera(QQuick3DCamera *camera, float defau
|
|||||||
|
|
||||||
camera->setPosition(lookAt + newLookVector);
|
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);
|
float cameraZoomFactor = zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
|
||||||
|
|
||||||
return QVector4D(lookAt, cameraZoomFactor);
|
return QVector4D(lookAt, cameraZoomFactor);
|
||||||
|
@@ -67,8 +67,8 @@ public:
|
|||||||
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance,
|
||||||
float defaultLookAtDistance, const QVector3D &lookAt,
|
float defaultLookAtDistance, const QVector3D &lookAt,
|
||||||
float zoomFactor, bool relative);
|
float zoomFactor, bool relative);
|
||||||
Q_INVOKABLE QVector4D focusObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
Q_INVOKABLE QVector4D focusNodesToCamera(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||||
QQuick3DNode *targetObject, QQuick3DViewport *viewPort,
|
const QVariant &nodes, QQuick3DViewport *viewPort,
|
||||||
float oldZoom, bool updateZoom = true,
|
float oldZoom, bool updateZoom = true,
|
||||||
bool closeUp = false);
|
bool closeUp = false);
|
||||||
Q_INVOKABLE bool fuzzyCompare(double a, double b);
|
Q_INVOKABLE bool fuzzyCompare(double a, double b);
|
||||||
|
Reference in New Issue
Block a user