| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the Qt Data Visualization module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "q3dscene_p.h" |
| #include "q3dcamera_p.h" |
| #include "q3dlight_p.h" |
| |
| QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
| |
| /*! |
| * \class Q3DScene |
| * \inmodule QtDataVisualization |
| * \brief Q3DScene class provides description of the 3D scene being visualized. |
| * \since QtDataVisualization 1.0 |
| * |
| * The 3D scene contains a single active camera and a single active light source. |
| * Visualized data is assumed to be at a fixed location. |
| * |
| * The 3D scene also keeps track of the viewport in which visualization rendering is done, |
| * the primary subviewport inside the viewport where the main 3D data visualization view resides |
| * and the secondary subviewport where the 2D sliced view of the data resides. The subviewports are |
| * by default resized by the \a Q3DScene. To override the resize behavior you need to listen to both |
| * \l viewportChanged() and \l slicingActiveChanged() signals and recalculate the subviewports accordingly. |
| * |
| * Also the scene has flag for tracking if the secondary 2D slicing view is currently active or not. |
| * \note Not all visualizations support the secondary 2D slicing view. |
| */ |
| |
| /*! |
| * \class Q3DSceneChangeBitField |
| * \internal |
| */ |
| |
| /*! |
| * \qmltype Scene3D |
| * \inqmlmodule QtDataVisualization |
| * \since QtDataVisualization 1.0 |
| * \ingroup datavisualization_qml |
| * \instantiates Q3DScene |
| * \brief Scene3D type provides description of the 3D scene being visualized. |
| * |
| * The 3D scene contains a single active camera and a single active light source. |
| * Visualized data is assumed to be at a fixed location. |
| * |
| * The 3D scene also keeps track of the viewport in which visualization rendering is done, |
| * the primary subviewport inside the viewport where the main 3D data visualization view resides |
| * and the secondary subviewport where the 2D sliced view of the data resides. |
| * |
| * Also the scene has flag for tracking if the secondary 2D slicing view is currently active or not. |
| * \note Not all visualizations support the secondary 2D slicing view. |
| */ |
| |
| /*! |
| * \qmlproperty rect Scene3D::viewport |
| * |
| * The current viewport rectangle where all 3D rendering is targeted. |
| */ |
| |
| /*! |
| * \qmlproperty rect Scene3D::primarySubViewport |
| * |
| * The current subviewport rectangle inside the viewport where the |
| * primary view of the data visualization is targeted. |
| * |
| * If slicingActive is \c false, the primary sub viewport will be equal to the |
| * viewport. If slicingActive is \c true and the primary sub viewport has not |
| * been explicitly set, it will be one fifth of the viewport. |
| * \note Setting primarySubViewport larger than or outside of viewport resizes viewport accordingly. |
| */ |
| |
| /*! |
| * \qmlproperty rect Scene3D::secondarySubViewport |
| * |
| * The secondary viewport rectangle inside the viewport. The secondary viewport |
| * is used for drawing the 2D slice view in some visualizations. If it has not |
| * been explicitly set, it will be null. If slicingActive is \c true, it will |
| * be equal to the viewport. |
| * \note If the secondary sub viewport is larger than or outside of the |
| * viewport, the viewport is resized accordingly. |
| */ |
| |
| /*! |
| * \qmlproperty point Scene3D::selectionQueryPosition |
| * |
| * The coordinates for the user input that should be processed |
| * by the scene as a selection. If this property is set to a value other than |
| * invalidSelectionPoint, the |
| * graph tries to select a data item at the given point within the primary viewport. |
| * After the rendering pass, the property is returned to its default state of |
| * invalidSelectionPoint. |
| */ |
| |
| /*! |
| * \qmlproperty point Scene3D::graphPositionQuery |
| * |
| * The coordinates for the user input that should be processed by the scene as a |
| * graph position query. If this property is set to value other than |
| * invalidSelectionPoint, the graph tries to match a graph position to the given point |
| * within the primary viewport. |
| * After the rendering pass, this property is returned to its default state of |
| * invalidSelectionPoint. The queried graph position can be read from the |
| * AbstractGraph3D::queriedGraphPosition property after the next render pass. |
| * |
| * There is no single correct 3D coordinate to match a particular screen position, so to be |
| * consistent, the queries are always done against the inner sides of an invisible box surrounding |
| * the graph. |
| * |
| * \note Bar graphs allow graph position queries only at the graph floor level. |
| * |
| * \sa AbstractGraph3D::queriedGraphPosition |
| */ |
| |
| /*! |
| * \qmlproperty bool Scene3D::slicingActive |
| * |
| * Defines whether the 2D slicing view is currently active. If \c true, |
| * AbstractGraph3D::selectionMode must have either the |
| * \l{QAbstract3DGraph::SelectionRow}{AbstractGraph3D.SelectionRow} or |
| * \l{QAbstract3DGraph::SelectionColumn}{AbstractGraph3D.SelectionColumn} |
| * set to a valid selection. |
| * \note Not all visualizations support the 2D slicing view. |
| */ |
| |
| /*! |
| * \qmlproperty bool Scene3D::secondarySubviewOnTop |
| * |
| * Defines whether the 2D slicing view or the 3D view is drawn on top. |
| */ |
| |
| /*! |
| * \qmlproperty Camera3D Scene3D::activeCamera |
| * |
| * The currently active camera in the 3D scene. |
| * When a Camera3D is set in the property, it is automatically added as child of |
| * the scene. |
| */ |
| |
| /*! |
| * \qmlproperty Light3D Scene3D::activeLight |
| * |
| * The currently active light in the 3D scene. |
| * When a Light3D is set in the property, it is automatically added as child of |
| * the scene. |
| */ |
| |
| /*! |
| * \qmlproperty float Scene3D::devicePixelRatio |
| * |
| * The current device pixel ratio that is used when mapping input |
| * coordinates to pixel coordinates. |
| */ |
| |
| /*! |
| * \qmlproperty point Scene3D::invalidSelectionPoint |
| * A constant property providing an invalid point for selection. |
| */ |
| |
| /*! |
| * Constructs a basic scene with one light and one camera in it. An |
| * optional \a parent parameter can be given and is then passed to QObject constructor. |
| */ |
| Q3DScene::Q3DScene(QObject *parent) : |
| QObject(parent), |
| d_ptr(new Q3DScenePrivate(this)) |
| { |
| setActiveCamera(new Q3DCamera(0)); |
| setActiveLight(new Q3DLight(0)); |
| } |
| |
| /*! |
| * Destroys the 3D scene and all the objects contained within it. |
| */ |
| Q3DScene::~Q3DScene() |
| { |
| } |
| |
| /*! |
| * \property Q3DScene::viewport |
| * |
| * \brief A read only property that contains the current viewport rectangle |
| * where all the 3D rendering is targeted. |
| */ |
| QRect Q3DScene::viewport() const |
| { |
| return d_ptr->m_viewport; |
| } |
| |
| /*! |
| * \property Q3DScene::primarySubViewport |
| * |
| * \brief The current subviewport rectangle inside the viewport where the |
| * primary view of the data visualization is targeted. |
| * |
| * If isSlicingActive() is \c false, the primary sub viewport is equal to |
| * viewport(). If isSlicingActive() is \c true and the primary sub viewport has |
| * not been explicitly set, it will be one fifth of viewport(). |
| * |
| * \note Setting primarySubViewport larger than or outside of the viewport |
| * resizes the viewport accordingly. |
| */ |
| QRect Q3DScene::primarySubViewport() const |
| { |
| QRect primary = d_ptr->m_primarySubViewport; |
| if (primary.isNull()) { |
| if (d_ptr->m_isSlicingActive) |
| primary = d_ptr->m_defaultSmallViewport; |
| else |
| primary = d_ptr->m_defaultLargeViewport; |
| } |
| return primary; |
| } |
| |
| void Q3DScene::setPrimarySubViewport(const QRect &primarySubViewport) |
| { |
| if (d_ptr->m_primarySubViewport != primarySubViewport) { |
| if (!primarySubViewport.isValid() && !primarySubViewport.isNull()) { |
| qWarning("Viewport is invalid."); |
| return; |
| } |
| |
| // If viewport is smaller than primarySubViewport, enlarge it |
| if ((d_ptr->m_viewport.width() < (primarySubViewport.width() |
| + primarySubViewport.x())) |
| || (d_ptr->m_viewport.height() < (primarySubViewport.height() |
| + primarySubViewport.y()))) { |
| d_ptr->m_viewport.setWidth(qMax(d_ptr->m_viewport.width(), |
| primarySubViewport.width() + primarySubViewport.x())); |
| d_ptr->m_viewport.setHeight(qMax(d_ptr->m_viewport.height(), |
| primarySubViewport.height() + primarySubViewport.y())); |
| d_ptr->calculateSubViewports(); |
| } |
| |
| d_ptr->m_primarySubViewport = primarySubViewport; |
| d_ptr->updateGLSubViewports(); |
| d_ptr->m_changeTracker.primarySubViewportChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit primarySubViewportChanged(primarySubViewport); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| /*! |
| * Returns whether the given \a point resides inside the primary subview or not. |
| * \return \c true if the point is inside the primary subview. |
| * \note If subviews are superimposed, and the given \a point resides inside both, result is |
| * \c true only when the primary subview is on top. |
| */ |
| bool Q3DScene::isPointInPrimarySubView(const QPoint &point) |
| { |
| int x = point.x(); |
| int y = point.y(); |
| bool isInSecondary = d_ptr->isInArea(secondarySubViewport(), x, y); |
| if (!isInSecondary || (isInSecondary && !d_ptr->m_isSecondarySubviewOnTop)) |
| return d_ptr->isInArea(primarySubViewport(), x, y); |
| else |
| return false; |
| } |
| |
| /*! |
| * Returns whether the given \a point resides inside the secondary subview or not. |
| * \return \c true if the point is inside the secondary subview. |
| * \note If subviews are superimposed, and the given \a point resides inside both, result is |
| * \c true only when the secondary subview is on top. |
| */ |
| bool Q3DScene::isPointInSecondarySubView(const QPoint &point) |
| { |
| int x = point.x(); |
| int y = point.y(); |
| bool isInPrimary = d_ptr->isInArea(primarySubViewport(), x, y); |
| if (!isInPrimary || (isInPrimary && d_ptr->m_isSecondarySubviewOnTop)) |
| return d_ptr->isInArea(secondarySubViewport(), x, y); |
| else |
| return false; |
| } |
| |
| /*! |
| * \property Q3DScene::secondarySubViewport |
| * |
| * \brief The secondary viewport rectangle inside the viewport. |
| * |
| * The secondary viewport is used for drawing the 2D slice view in some |
| * visualizations. If it has not been explicitly set, it will be equal to |
| * QRect. If isSlicingActive() is \c true, it will be equal to \l viewport. |
| * \note If the secondary sub viewport is larger than or outside of the |
| * viewport, the viewport is resized accordingly. |
| */ |
| QRect Q3DScene::secondarySubViewport() const |
| { |
| QRect secondary = d_ptr->m_secondarySubViewport; |
| if (secondary.isNull() && d_ptr->m_isSlicingActive) |
| secondary = d_ptr->m_defaultLargeViewport; |
| return secondary; |
| } |
| |
| void Q3DScene::setSecondarySubViewport(const QRect &secondarySubViewport) |
| { |
| if (d_ptr->m_secondarySubViewport != secondarySubViewport) { |
| if (!secondarySubViewport.isValid() && !secondarySubViewport.isNull()) { |
| qWarning("Viewport is invalid."); |
| return; |
| } |
| |
| // If viewport is smaller than secondarySubViewport, enlarge it |
| if ((d_ptr->m_viewport.width() < (secondarySubViewport.width() |
| + secondarySubViewport.x())) |
| || (d_ptr->m_viewport.height() < (secondarySubViewport.height() |
| + secondarySubViewport.y()))) { |
| d_ptr->m_viewport.setWidth(qMax(d_ptr->m_viewport.width(), |
| secondarySubViewport.width() |
| + secondarySubViewport.x())); |
| d_ptr->m_viewport.setHeight(qMax(d_ptr->m_viewport.height(), |
| secondarySubViewport.height() |
| + secondarySubViewport.y())); |
| d_ptr->calculateSubViewports(); |
| } |
| |
| d_ptr->m_secondarySubViewport = secondarySubViewport; |
| d_ptr->updateGLSubViewports(); |
| d_ptr->m_changeTracker.secondarySubViewportChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit secondarySubViewportChanged(secondarySubViewport); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| /*! |
| * \property Q3DScene::selectionQueryPosition |
| * |
| * \brief The coordinates for the user input that should be processed |
| * by the scene as a selection. |
| * |
| * If this property is set to a value other than invalidSelectionPoint(), the |
| * graph tries to select a data item, axis label, or a custom item at the |
| * specified coordinates within the primary viewport. |
| * After the rendering pass, the property is returned to its default state of |
| * invalidSelectionPoint(). |
| * |
| * \sa QAbstract3DGraph::selectedElement |
| */ |
| void Q3DScene::setSelectionQueryPosition(const QPoint &point) |
| { |
| if (point != d_ptr->m_selectionQueryPosition) { |
| d_ptr->m_selectionQueryPosition = point; |
| d_ptr->m_changeTracker.selectionQueryPositionChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit selectionQueryPositionChanged(point); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| QPoint Q3DScene::selectionQueryPosition() const |
| { |
| return d_ptr->m_selectionQueryPosition; |
| } |
| |
| /*! |
| * \return a QPoint signifying an invalid selection position. |
| */ |
| QPoint Q3DScene::invalidSelectionPoint() |
| { |
| static const QPoint invalidSelectionPos(-1, -1); |
| return invalidSelectionPos; |
| } |
| |
| /*! |
| * \property Q3DScene::graphPositionQuery |
| * |
| * \brief The coordinates for the user input that should be processed |
| * by the scene as a graph position query. |
| * |
| * If this property is set to a value other than invalidSelectionPoint(), the |
| * graph tries to match a graph position to the specified coordinates |
| * within the primary viewport. |
| * After the rendering pass, this property is returned to its default state of |
| * invalidSelectionPoint(). The queried graph position can be read from the |
| * QAbstract3DGraph::queriedGraphPosition property after the next render pass. |
| * |
| * There is no single correct 3D coordinate to match a particular screen position, so to be |
| * consistent, the queries are always done against the inner sides of an invisible box surrounding |
| * the graph. |
| * |
| * \note Bar graphs allow graph position queries only at the graph floor level. |
| * |
| * \sa QAbstract3DGraph::queriedGraphPosition |
| */ |
| void Q3DScene::setGraphPositionQuery(const QPoint &point) |
| { |
| if (point != d_ptr->m_graphPositionQueryPosition) { |
| d_ptr->m_graphPositionQueryPosition = point; |
| d_ptr->m_changeTracker.graphPositionQueryPositionChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit graphPositionQueryChanged(point); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| QPoint Q3DScene::graphPositionQuery() const |
| { |
| return d_ptr->m_graphPositionQueryPosition; |
| } |
| |
| /*! |
| * \property Q3DScene::slicingActive |
| * |
| * \brief Whether the 2D slicing view is currently active. |
| * |
| * If \c true, QAbstract3DGraph::selectionMode must have either |
| * QAbstract3DGraph::SelectionRow or QAbstract3DGraph::SelectionColumn set |
| * to a valid selection. |
| * \note Not all visualizations support the 2D slicing view. |
| */ |
| bool Q3DScene::isSlicingActive() const |
| { |
| return d_ptr->m_isSlicingActive; |
| } |
| |
| void Q3DScene::setSlicingActive(bool isSlicing) |
| { |
| if (d_ptr->m_isSlicingActive != isSlicing) { |
| d_ptr->m_isSlicingActive = isSlicing; |
| d_ptr->m_changeTracker.slicingActivatedChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| // Set secondary subview behind primary to achieve default functionality (= clicking on |
| // primary disables slice) |
| setSecondarySubviewOnTop(!isSlicing); |
| |
| d_ptr->calculateSubViewports(); |
| emit slicingActiveChanged(isSlicing); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| /*! |
| * \property Q3DScene::secondarySubviewOnTop |
| * |
| * \brief Whether the 2D slicing view or the 3D view is drawn on top. |
| */ |
| bool Q3DScene::isSecondarySubviewOnTop() const |
| { |
| return d_ptr->m_isSecondarySubviewOnTop; |
| } |
| |
| void Q3DScene::setSecondarySubviewOnTop(bool isSecondaryOnTop) |
| { |
| if (d_ptr->m_isSecondarySubviewOnTop != isSecondaryOnTop) { |
| d_ptr->m_isSecondarySubviewOnTop = isSecondaryOnTop; |
| d_ptr->m_changeTracker.subViewportOrderChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit secondarySubviewOnTopChanged(isSecondaryOnTop); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| /*! |
| * \property Q3DScene::activeCamera |
| * |
| * \brief The currently active camera in the 3D scene. |
| * |
| * When a new Q3DCamera object is set, it is automatically added as child of |
| * the scene. |
| */ |
| Q3DCamera *Q3DScene::activeCamera() const |
| { |
| return d_ptr->m_camera; |
| } |
| |
| void Q3DScene::setActiveCamera(Q3DCamera *camera) |
| { |
| Q_ASSERT(camera); |
| |
| // Add new camera as child of the scene |
| if (camera->parent() != this) |
| camera->setParent(this); |
| |
| if (camera != d_ptr->m_camera) { |
| if (d_ptr->m_camera) { |
| disconnect(d_ptr->m_camera, &Q3DCamera::xRotationChanged, d_ptr.data(), |
| &Q3DScenePrivate::needRender); |
| disconnect(d_ptr->m_camera, &Q3DCamera::yRotationChanged, d_ptr.data(), |
| &Q3DScenePrivate::needRender); |
| disconnect(d_ptr->m_camera, &Q3DCamera::zoomLevelChanged, d_ptr.data(), |
| &Q3DScenePrivate::needRender); |
| } |
| |
| d_ptr->m_camera = camera; |
| d_ptr->m_changeTracker.cameraChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| |
| if (camera) { |
| connect(camera, &Q3DCamera::xRotationChanged, d_ptr.data(), |
| &Q3DScenePrivate::needRender); |
| connect(camera, &Q3DCamera::yRotationChanged, d_ptr.data(), |
| &Q3DScenePrivate::needRender); |
| connect(camera, &Q3DCamera::zoomLevelChanged, d_ptr.data(), |
| &Q3DScenePrivate::needRender); |
| } |
| |
| emit activeCameraChanged(camera); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| /*! |
| * \property Q3DScene::activeLight |
| * |
| * \brief The currently active light in the 3D scene. |
| * |
| * When a new Q3DLight objects is set, it is automatically added as child of |
| * the scene. |
| */ |
| Q3DLight *Q3DScene::activeLight() const |
| { |
| return d_ptr->m_light; |
| } |
| |
| void Q3DScene::setActiveLight(Q3DLight *light) |
| { |
| Q_ASSERT(light); |
| |
| // Add new light as child of the scene |
| if (light->parent() != this) |
| light->setParent(this); |
| |
| if (light != d_ptr->m_light) { |
| d_ptr->m_light = light; |
| d_ptr->m_changeTracker.lightChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit activeLightChanged(light); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| /*! |
| * \property Q3DScene::devicePixelRatio |
| * |
| * \brief The device pixel ratio that is used when mapping input |
| * coordinates to pixel coordinates. |
| */ |
| float Q3DScene::devicePixelRatio() const |
| { |
| return d_ptr->m_devicePixelRatio; |
| } |
| |
| void Q3DScene::setDevicePixelRatio(float pixelRatio) |
| { |
| if (d_ptr->m_devicePixelRatio != pixelRatio) { |
| d_ptr->m_devicePixelRatio = pixelRatio; |
| d_ptr->m_changeTracker.devicePixelRatioChanged = true; |
| d_ptr->m_sceneDirty = true; |
| |
| emit devicePixelRatioChanged(pixelRatio); |
| d_ptr->updateGLViewport(); |
| emit d_ptr->needRender(); |
| } |
| } |
| |
| Q3DScenePrivate::Q3DScenePrivate(Q3DScene *q) : |
| QObject(0), |
| q_ptr(q), |
| m_isSecondarySubviewOnTop(true), |
| m_devicePixelRatio(1.f), |
| m_camera(), |
| m_light(), |
| m_isUnderSideCameraEnabled(false), |
| m_isSlicingActive(false), |
| m_selectionQueryPosition(Q3DScene::invalidSelectionPoint()), |
| m_graphPositionQueryPosition(Q3DScene::invalidSelectionPoint()), |
| m_windowSize(QSize(0, 0)), |
| m_sceneDirty(true) |
| { |
| } |
| |
| Q3DScenePrivate::~Q3DScenePrivate() |
| { |
| delete m_camera; |
| delete m_light; |
| } |
| |
| // Copies changed values from this scene to the other scene. If the other scene had same changes, |
| // those changes are discarded. |
| void Q3DScenePrivate::sync(Q3DScenePrivate &other) |
| { |
| if (m_changeTracker.windowSizeChanged) { |
| other.setWindowSize(windowSize()); |
| m_changeTracker.windowSizeChanged = false; |
| other.m_changeTracker.windowSizeChanged = false; |
| } |
| if (m_changeTracker.viewportChanged) { |
| other.setViewport(m_viewport); |
| m_changeTracker.viewportChanged = false; |
| other.m_changeTracker.viewportChanged = false; |
| } |
| if (m_changeTracker.subViewportOrderChanged) { |
| other.q_ptr->setSecondarySubviewOnTop(q_ptr->isSecondarySubviewOnTop()); |
| m_changeTracker.subViewportOrderChanged = false; |
| other.m_changeTracker.subViewportOrderChanged = false; |
| } |
| if (m_changeTracker.primarySubViewportChanged) { |
| other.q_ptr->setPrimarySubViewport(q_ptr->primarySubViewport()); |
| m_changeTracker.primarySubViewportChanged = false; |
| other.m_changeTracker.primarySubViewportChanged = false; |
| } |
| if (m_changeTracker.secondarySubViewportChanged) { |
| other.q_ptr->setSecondarySubViewport(q_ptr->secondarySubViewport()); |
| m_changeTracker.secondarySubViewportChanged = false; |
| other.m_changeTracker.secondarySubViewportChanged = false; |
| } |
| if (m_changeTracker.selectionQueryPositionChanged) { |
| other.q_ptr->setSelectionQueryPosition(q_ptr->selectionQueryPosition()); |
| m_changeTracker.selectionQueryPositionChanged = false; |
| other.m_changeTracker.selectionQueryPositionChanged = false; |
| } |
| if (m_changeTracker.graphPositionQueryPositionChanged) { |
| other.q_ptr->setGraphPositionQuery(q_ptr->graphPositionQuery()); |
| m_changeTracker.graphPositionQueryPositionChanged = false; |
| other.m_changeTracker.graphPositionQueryPositionChanged = false; |
| } |
| if (m_changeTracker.cameraChanged) { |
| m_camera->setDirty(true); |
| m_changeTracker.cameraChanged = false; |
| other.m_changeTracker.cameraChanged = false; |
| } |
| m_camera->d_ptr->sync(*other.m_camera); |
| |
| if (m_changeTracker.lightChanged) { |
| m_light->setDirty(true); |
| m_changeTracker.lightChanged = false; |
| other.m_changeTracker.lightChanged = false; |
| } |
| m_light->d_ptr->sync(*other.m_light); |
| |
| if (m_changeTracker.slicingActivatedChanged) { |
| other.q_ptr->setSlicingActive(q_ptr->isSlicingActive()); |
| m_changeTracker.slicingActivatedChanged = false; |
| other.m_changeTracker.slicingActivatedChanged = false; |
| } |
| |
| if (m_changeTracker.devicePixelRatioChanged) { |
| other.q_ptr->setDevicePixelRatio(q_ptr->devicePixelRatio()); |
| m_changeTracker.devicePixelRatioChanged = false; |
| other.m_changeTracker.devicePixelRatioChanged = false; |
| } |
| |
| m_sceneDirty = false; |
| other.m_sceneDirty = false; |
| } |
| |
| void Q3DScenePrivate::setViewport(const QRect &viewport) |
| { |
| if (m_viewport != viewport && viewport.isValid()) { |
| m_viewport = viewport; |
| calculateSubViewports(); |
| emit needRender(); |
| } |
| } |
| |
| void Q3DScenePrivate::setViewportSize(int width, int height) |
| { |
| if (m_viewport.width() != width || m_viewport.height() != height) { |
| m_viewport.setWidth(width); |
| m_viewport.setHeight(height); |
| calculateSubViewports(); |
| emit needRender(); |
| } |
| } |
| |
| /*! |
| * \internal |
| * Sets the size of the window being rendered to. With widget based graphs, this |
| * is equal to the size of the QWindow and is same as the bounding rectangle. |
| * With declarative graphs this is equal to the size of the QQuickWindow and |
| * can be different from the bounding rectangle. |
| */ |
| void Q3DScenePrivate::setWindowSize(const QSize &size) |
| { |
| if (m_windowSize != size) { |
| m_windowSize = size; |
| updateGLViewport(); |
| m_changeTracker.windowSizeChanged = true; |
| emit needRender(); |
| } |
| } |
| |
| QSize Q3DScenePrivate::windowSize() const |
| { |
| return m_windowSize; |
| } |
| |
| void Q3DScenePrivate::calculateSubViewports() |
| { |
| // Calculates the default subviewport layout, used when slicing |
| const float smallerViewPortRatio = 0.2f; |
| m_defaultSmallViewport = QRect(0, 0, |
| m_viewport.width() * smallerViewPortRatio, |
| m_viewport.height() * smallerViewPortRatio); |
| m_defaultLargeViewport = QRect(0, 0, |
| m_viewport.width(), |
| m_viewport.height()); |
| |
| updateGLViewport(); |
| } |
| |
| void Q3DScenePrivate::updateGLViewport() |
| { |
| // Update GL viewport |
| m_glViewport.setX(m_viewport.x() * m_devicePixelRatio); |
| m_glViewport.setY((m_windowSize.height() - (m_viewport.y() + m_viewport.height())) |
| * m_devicePixelRatio); |
| m_glViewport.setWidth(m_viewport.width() * m_devicePixelRatio); |
| m_glViewport.setHeight(m_viewport.height() * m_devicePixelRatio); |
| |
| m_changeTracker.viewportChanged = true; |
| m_sceneDirty = true; |
| |
| // Do default subviewport changes first, then allow signal listeners to override. |
| updateGLSubViewports(); |
| emit q_ptr->viewportChanged(m_viewport); |
| } |
| |
| void Q3DScenePrivate::updateGLSubViewports() |
| { |
| if (m_isSlicingActive) { |
| QRect primary = m_primarySubViewport; |
| QRect secondary = m_secondarySubViewport; |
| if (primary.isNull()) |
| primary = m_defaultSmallViewport; |
| if (secondary.isNull()) |
| secondary = m_defaultLargeViewport; |
| |
| m_glPrimarySubViewport.setX((primary.x() + m_viewport.x()) * m_devicePixelRatio); |
| m_glPrimarySubViewport.setY((m_windowSize.height() |
| - (primary.y() + primary.height() + m_viewport.y())) |
| * m_devicePixelRatio); |
| m_glPrimarySubViewport.setWidth(primary.width() * m_devicePixelRatio); |
| m_glPrimarySubViewport.setHeight(primary.height() * m_devicePixelRatio); |
| |
| m_glSecondarySubViewport.setX((secondary.x() + m_viewport.x()) * m_devicePixelRatio); |
| m_glSecondarySubViewport.setY((m_windowSize.height() |
| - (secondary.y() + secondary.height() + m_viewport.y())) |
| * m_devicePixelRatio); |
| m_glSecondarySubViewport.setWidth(secondary.width() * m_devicePixelRatio); |
| m_glSecondarySubViewport.setHeight(secondary.height() * m_devicePixelRatio); |
| } else { |
| m_glPrimarySubViewport.setX(m_viewport.x() * m_devicePixelRatio); |
| m_glPrimarySubViewport.setY((m_windowSize.height() - (m_viewport.y() + m_viewport.height())) |
| * m_devicePixelRatio); |
| m_glPrimarySubViewport.setWidth(m_viewport.width() * m_devicePixelRatio); |
| m_glPrimarySubViewport.setHeight(m_viewport.height() * m_devicePixelRatio); |
| |
| m_glSecondarySubViewport = QRect(); |
| } |
| } |
| |
| QRect Q3DScenePrivate::glViewport() |
| { |
| return m_glViewport; |
| } |
| |
| QRect Q3DScenePrivate::glPrimarySubViewport() |
| { |
| return m_glPrimarySubViewport; |
| } |
| |
| QRect Q3DScenePrivate::glSecondarySubViewport() |
| { |
| return m_glSecondarySubViewport; |
| } |
| |
| /*! |
| * \internal |
| * Calculates and sets the light position relative to the currently active camera using the given |
| * parameters. |
| * The relative 3D offset to the current camera position is defined in \a relativePosition. |
| * Optional \a fixedRotation fixes the light rotation around the data visualization area to the |
| * given value in degrees. |
| * Optional \a distanceModifier modifies the distance of the light from the data visualization. |
| */ |
| void Q3DScenePrivate::setLightPositionRelativeToCamera(const QVector3D &relativePosition, |
| float fixedRotation, float distanceModifier) |
| { |
| m_light->setPosition(m_camera->d_ptr->calculatePositionRelativeToCamera(relativePosition, |
| fixedRotation, |
| distanceModifier)); |
| } |
| |
| void Q3DScenePrivate::markDirty() |
| { |
| m_sceneDirty = true; |
| emit needRender(); |
| } |
| |
| bool Q3DScenePrivate::isInArea(const QRect &area, int x, int y) const |
| { |
| int areaMinX = area.x(); |
| int areaMaxX = area.x() + area.width(); |
| int areaMinY = area.y(); |
| int areaMaxY = area.y() + area.height(); |
| return ( x >= areaMinX && x <= areaMaxX && y >= areaMinY && y <= areaMaxY ); |
| } |
| |
| QT_END_NAMESPACE_DATAVISUALIZATION |