diff options
Diffstat (limited to 'src/datavisualization/engine/q3dscene.cpp')
-rw-r--r-- | src/datavisualization/engine/q3dscene.cpp | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/src/datavisualization/engine/q3dscene.cpp b/src/datavisualization/engine/q3dscene.cpp new file mode 100644 index 00000000..4908bde4 --- /dev/null +++ b/src/datavisualization/engine/q3dscene.cpp @@ -0,0 +1,375 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include <qmath.h> + +#include "datavisualizationglobal_p.h" + +#include "q3dscene.h" +#include "q3dscene_p.h" +#include "q3dcamera_p.h" +#include "q3dlight_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE +/*! + * \class Q3DScene + * \inmodule QtDataVisualization + * \brief Q3DScene class provides description of the 3D scene being visualized. + * \since 1.0.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. + * + * 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. + */ + +/*! + * 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 + * + * This property contains the current viewport rectangle where all 3D rendering + * is targeted. + */ +QRect Q3DScene::viewport() const +{ + return d_ptr->m_viewport; +} + +void Q3DScene::setViewport(const QRect &viewport) +{ + if (d_ptr->m_viewport.width() != viewport.width() + || d_ptr->m_viewport.height() != viewport.height()) { + d_ptr->m_viewport = viewport; + d_ptr->m_viewport.setX(0); + d_ptr->m_viewport.setY(0); + d_ptr->m_changeTracker.viewportChanged = true; + emit viewportChanged(viewport); + } +} + +/*! + * Sets the \a width and \a height of the viewport only, without changing its location. + */ +void Q3DScene::setViewportSize(int width, int height) +{ + if (d_ptr->m_viewport.width() != width + || d_ptr->m_viewport.height() != height) { + d_ptr->m_viewport.setWidth(width); + d_ptr->m_viewport.setHeight(height); + d_ptr->m_changeTracker.viewportChanged = true; + emit viewportChanged(d_ptr->m_viewport); + } +} + +/*! + * \property Q3DScene::primarySubViewport + * + * This property contains the current main viewport rectangle inside the viewport where the + * primary view of the data visualization is targeted to. + */ +QRect Q3DScene::primarySubViewport() const +{ + return d_ptr->m_primarySubViewport; +} + +void Q3DScene::setPrimarySubViewport(const QRect &primarySubViewport) +{ + if (d_ptr->m_primarySubViewport != primarySubViewport) { + d_ptr->m_primarySubViewport = primarySubViewport; + d_ptr->m_changeTracker.primarySubViewportChanged = true; + emit primarySubViewportChanged(primarySubViewport); + } +} + +/*! + * Returns whether the given \a point resides inside the primary subview or not. + * The method takes care of correctly mapping between OpenGL coordinates used in the + * viewport definitions and the Qt event coordinate system used in the input system. + * \return true if the point is inside the primary subview. + */ +bool Q3DScene::isPointInPrimarySubView(const QPoint &point) +{ + // TODO: Needs fixing. Doesn't respect whether slice or main view is on top or if slicing is even activated currently. + int x = point.x(); + int y = point.y(); + int areaMinX = d_ptr->m_primarySubViewport.x(); + int areaMaxX = d_ptr->m_primarySubViewport.x() + d_ptr->m_primarySubViewport.width(); + int areaMaxY = d_ptr->m_viewport.height() - d_ptr->m_primarySubViewport.y(); + int areaMinY = d_ptr->m_viewport.height() - (d_ptr->m_primarySubViewport.y() + d_ptr->m_primarySubViewport.height()); + + return ( x > areaMinX && x < areaMaxX && y > areaMinY && y < areaMaxY ); +} + +/*! + * Returns whether the given \a point resides inside the secondary subview or not. + * The method takes care of correctly mapping between OpenGL coordinates used in the + * viewport definitions and the Qt event coordinate system used in the input system. + * \return true if the point is inside the secondary subview. + */ +bool Q3DScene::isPointInSecondarySubView(const QPoint &point) +{ + // TODO: Needs fixing. Doesn't respect whether slice or main view is on top or if slicing is even activated currently. + int x = point.x(); + int y = point.y(); + int areaMinX = d_ptr->m_secondarySubViewport.x(); + int areaMaxX = d_ptr->m_secondarySubViewport.x() + d_ptr->m_secondarySubViewport.width(); + int areaMaxY = d_ptr->m_viewport.height() - d_ptr->m_secondarySubViewport.y(); + int areaMinY = d_ptr->m_viewport.height() - (d_ptr->m_secondarySubViewport.y() + d_ptr->m_secondarySubViewport.height()); + + return ( x > areaMinX && x < areaMaxX && y > areaMinY && y < areaMaxY ); +} + +/*! + * \property Q3DScene::secondarySubViewport + * + * This property contains the secondary viewport rectangle inside the viewport. The secondary + * viewport is used for drawing the 2D slice view in some visualizations. + */ +QRect Q3DScene::secondarySubViewport() const +{ + return d_ptr->m_secondarySubViewport; +} + +void Q3DScene::setSecondarySubViewport(const QRect &secondarySubViewport) +{ + if (d_ptr->m_secondarySubViewport != secondarySubViewport) { + d_ptr->m_secondarySubViewport = secondarySubViewport; + d_ptr->m_changeTracker.secondarySubViewportChanged = true; + emit secondarySubViewportChanged(secondarySubViewport); + } +} + +/*! + * \property Q3DScene::slicingActive + * + * This property contains whether 2D slicing view is currently active or not. + * \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; + emit slicingActiveChanged(isSlicing); + emitNeedRender(); + } +} + +/*! + * \property Q3DScene::activeCamera + * + * This property contains the currently active camera in the 3D scene. + * When a new Q3DCamera objects is set in the property it gets 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, this, + &Q3DScene::emitNeedRender); + disconnect(d_ptr->m_camera, &Q3DCamera::yRotationChanged, this, + &Q3DScene::emitNeedRender); + } + + d_ptr->m_camera = camera; + d_ptr->m_changeTracker.cameraChanged = true; + + if (camera) { + connect(camera, &Q3DCamera::xRotationChanged, this, + &Q3DScene::emitNeedRender); + connect(camera, &Q3DCamera::yRotationChanged, this, + &Q3DScene::emitNeedRender); + } + + emit activeCameraChanged(camera); + emitNeedRender(); + } +} + +void Q3DScene::emitNeedRender() +{ + emit needRender(); +} + +/*! + * \property Q3DScene::activeLight + * + * This property contains the currently active light in the 3D scene. + * When a new Q3DLight objects is set in the property it gets 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; + emit activeLightChanged(light); + } +} + +/*! + * \property Q3DScene::devicePixelRatio + * + * This property contains the current device pixel ratio that is used when mapping input + * coordinates to pixel coordinates. + */ +qreal Q3DScene::devicePixelRatio() const +{ + return d_ptr->m_devicePixelRatio; +} + +void Q3DScene::setDevicePixelRatio(qreal pixelRatio) +{ + if (d_ptr->m_devicePixelRatio != pixelRatio) { + d_ptr->m_devicePixelRatio = pixelRatio; + emit devicePixelRatioChanged(pixelRatio); + } +} + +/*! + * Calculates and sets the light position relative to the currently active camera using the given parameters. + * \a relativePosition defines the relative 3D offset to the current camera position. + * 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 Q3DScene::setLightPositionRelativeToCamera(const QVector3D &relativePosition, + qreal fixedRotation, qreal distanceModifier) +{ + d_ptr->m_light->setPosition( + d_ptr->m_camera->calculatePositionRelativeToCamera(relativePosition, + fixedRotation, + distanceModifier)); +} + +/*! + * \fn Q3DScene::needRender() + * \internal + */ + +Q3DScenePrivate::Q3DScenePrivate(Q3DScene *q) : + q_ptr(q), + m_devicePixelRatio(1.f), + m_camera(), + m_light(), + m_isUnderSideCameraEnabled(false), + m_isSlicingActive(false) +{ +} + +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.viewportChanged) { + other.q_ptr->setViewport(q_ptr->viewport()); + m_changeTracker.viewportChanged = false; + other.m_changeTracker.viewportChanged = 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.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; + } +} + +QT_DATAVISUALIZATION_END_NAMESPACE |