diff options
24 files changed, 308 insertions, 48 deletions
diff --git a/src/datavisualization/data/barrenderitem.cpp b/src/datavisualization/data/barrenderitem.cpp index 1bb1271d..a558e1fd 100644 --- a/src/datavisualization/data/barrenderitem.cpp +++ b/src/datavisualization/data/barrenderitem.cpp @@ -39,6 +39,7 @@ BarRenderItem::BarRenderItem(const BarRenderItem &other) m_sliceLabel = other.m_sliceLabel; m_sliceLabelItem = 0; m_seriesIndex = other.m_seriesIndex; + m_rotation = other.m_rotation; } BarRenderItem::~BarRenderItem() @@ -60,7 +61,7 @@ void BarRenderItem::setSliceLabel(const QString &label) m_sliceLabel = label; } -QString &BarRenderItem::sliceLabel() +const QString &BarRenderItem::sliceLabel() const { return m_sliceLabel; } diff --git a/src/datavisualization/data/barrenderitem_p.h b/src/datavisualization/data/barrenderitem_p.h index 7704d65e..66c9c460 100644 --- a/src/datavisualization/data/barrenderitem_p.h +++ b/src/datavisualization/data/barrenderitem_p.h @@ -67,12 +67,15 @@ public: // Formatted label for item. void setSliceLabel(const QString &label); - QString &sliceLabel(); // Formats label if not previously formatted + const QString &sliceLabel() const; // Formats label if not previously formatted // Series index in visual series that this item belongs to. // This is only utilized by slicing, so it may not be up to date on all items. inline void setSeriesIndex(int seriesIndex) { m_seriesIndex = seriesIndex; } - inline int seriesIndex() { return m_seriesIndex; } + inline int seriesIndex() const { return m_seriesIndex; } + + inline void setRotation(const QQuaternion &rotation) { m_rotation = rotation; } + inline const QQuaternion &rotation() const { return m_rotation; } protected: float m_value; @@ -81,6 +84,7 @@ protected: QString m_sliceLabel; LabelItem *m_sliceLabelItem; int m_seriesIndex; + QQuaternion m_rotation; friend class QBarDataItem; }; diff --git a/src/datavisualization/data/qabstract3dseries.cpp b/src/datavisualization/data/qabstract3dseries.cpp index a3f766a8..d80879f0 100644 --- a/src/datavisualization/data/qabstract3dseries.cpp +++ b/src/datavisualization/data/qabstract3dseries.cpp @@ -142,6 +142,18 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty quaternion Abstract3DSeries::meshRotation + * + * Sets the mesh \a rotation that is applied to all items of the series. + * The \a rotation should be a normalized quaternion. + * For those series types that support item specific rotation, the rotations are + * multiplied together. + * Bar3DSeries ignores any rotation that is not around Y-axis. + * Surface3DSeries applies the rotation only to the selection pointer. + * Defaults to no rotation. + */ + +/*! * \qmlproperty string Abstract3DSeries::userDefinedMesh * * Sets the \a fileName for user defined custom mesh for objects that is used when mesh @@ -303,7 +315,8 @@ bool QAbstract3DSeries::isVisible() const */ void QAbstract3DSeries::setMesh(QAbstract3DSeries::Mesh mesh) { - if ((mesh == QAbstract3DSeries::MeshPoint || mesh == QAbstract3DSeries::MeshMinimal) + if ((mesh == QAbstract3DSeries::MeshPoint || mesh == QAbstract3DSeries::MeshMinimal + || mesh == QAbstract3DSeries::MeshArrow) && type() != QAbstract3DSeries::SeriesTypeScatter) { qWarning() << "Specified style is only supported for QScatter3DSeries."; } else if (d_ptr->m_mesh != mesh) { @@ -338,6 +351,30 @@ bool QAbstract3DSeries::isMeshSmooth() const } /*! + * \property QAbstract3DSeries::meshRotation + * + * Sets the mesh \a rotation that is applied to all items of the series. + * The \a rotation should be a normalized QQuaternion. + * For those series types that support item specific rotation, the rotations are + * multiplied together. + * QBar3DSeries ignores any rotation that is not around Y-axis. + * QSurface3DSeries applies the rotation only to the selection pointer. + * Defaults to no rotation. + */ +void QAbstract3DSeries::setMeshRotation(const QQuaternion &rotation) +{ + if (d_ptr->m_meshRotation != rotation) { + d_ptr->setMeshRotation(rotation); + emit meshRotationChanged(rotation); + } +} + +QQuaternion QAbstract3DSeries::meshRotation() const +{ + return d_ptr->m_meshRotation; +} + +/*! * \property QAbstract3DSeries::userDefinedMesh * * Sets the \a fileName for user defined custom mesh for objects that is used when mesh @@ -608,6 +645,14 @@ void QAbstract3DSeriesPrivate::setMeshSmooth(bool enable) m_controller->markSeriesVisualsDirty(); } +void QAbstract3DSeriesPrivate::setMeshRotation(const QQuaternion &rotation) +{ + m_meshRotation = rotation; + m_changeTracker.meshRotationChanged = true; + if (m_controller) + m_controller->markSeriesVisualsDirty(); +} + void QAbstract3DSeriesPrivate::setUserDefinedMesh(const QString &meshFile) { m_userDefinedMesh = meshFile; diff --git a/src/datavisualization/data/qabstract3dseries.h b/src/datavisualization/data/qabstract3dseries.h index df6dada8..5e7fe016 100644 --- a/src/datavisualization/data/qabstract3dseries.h +++ b/src/datavisualization/data/qabstract3dseries.h @@ -23,6 +23,7 @@ #include <QObject> #include <QScopedPointer> #include <QLinearGradient> +#include <QQuaternion> QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -38,6 +39,7 @@ class QT_DATAVISUALIZATION_EXPORT QAbstract3DSeries : public QObject Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) Q_PROPERTY(Mesh mesh READ mesh WRITE setMesh NOTIFY meshChanged) Q_PROPERTY(bool meshSmooth READ isMeshSmooth WRITE setMeshSmooth NOTIFY meshSmoothChanged) + Q_PROPERTY(QQuaternion meshRotation READ meshRotation WRITE setMeshRotation NOTIFY meshRotationChanged) Q_PROPERTY(QString userDefinedMesh READ userDefinedMesh WRITE setUserDefinedMesh NOTIFY userDefinedMeshChanged) Q_PROPERTY(QtDataVisualization::Q3DTheme::ColorStyle colorStyle READ colorStyle WRITE setColorStyle NOTIFY colorStyleChanged) Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged) @@ -91,6 +93,9 @@ public: void setMeshSmooth(bool enable); bool isMeshSmooth() const; + void setMeshRotation(const QQuaternion &rotation); + QQuaternion meshRotation() const; + void setUserDefinedMesh(const QString &fileName); QString userDefinedMesh() const; @@ -117,6 +122,7 @@ signals: void visibilityChanged(bool visible); void meshChanged(Mesh mesh); void meshSmoothChanged(bool enabled); + void meshRotationChanged(QQuaternion rotation); void userDefinedMeshChanged(QString fileName); void colorStyleChanged(Q3DTheme::ColorStyle style); void baseColorChanged(QColor color); diff --git a/src/datavisualization/data/qabstract3dseries_p.h b/src/datavisualization/data/qabstract3dseries_p.h index f1bc1f95..565d35a2 100644 --- a/src/datavisualization/data/qabstract3dseries_p.h +++ b/src/datavisualization/data/qabstract3dseries_p.h @@ -42,6 +42,7 @@ struct QAbstract3DSeriesChangeBitField { bool itemLabelFormatChanged : 1; bool meshChanged : 1; bool meshSmoothChanged : 1; + bool meshRotationChanged : 1; bool userDefinedMeshChanged : 1; bool colorStyleChanged : 1; bool baseColorChanged : 1; @@ -56,6 +57,7 @@ struct QAbstract3DSeriesChangeBitField { : itemLabelFormatChanged(true), meshChanged(true), meshSmoothChanged(true), + meshRotationChanged(true), userDefinedMeshChanged(true), colorStyleChanged(true), baseColorChanged(true), @@ -106,6 +108,7 @@ public: void setVisible(bool visible); void setMesh(QAbstract3DSeries::Mesh mesh); void setMeshSmooth(bool enable); + void setMeshRotation(const QQuaternion &rotation); void setUserDefinedMesh(const QString &meshFile); void setColorStyle(Q3DTheme::ColorStyle style); @@ -129,6 +132,7 @@ public: Abstract3DController *m_controller; QAbstract3DSeries::Mesh m_mesh; bool m_meshSmooth; + QQuaternion m_meshRotation; QString m_userDefinedMesh; Q3DTheme::ColorStyle m_colorStyle; diff --git a/src/datavisualization/data/qbardataitem.cpp b/src/datavisualization/data/qbardataitem.cpp index 3e8ebee2..eb14c7f9 100644 --- a/src/datavisualization/data/qbardataitem.cpp +++ b/src/datavisualization/data/qbardataitem.cpp @@ -37,7 +37,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ QBarDataItem::QBarDataItem() : d_ptr(0), // private data doesn't exist by default (optimization) - m_value(0.0f) + m_value(0.0f), + m_angle(0.0f) { } @@ -46,7 +47,18 @@ QBarDataItem::QBarDataItem() */ QBarDataItem::QBarDataItem(float value) : d_ptr(0), - m_value(value) + m_value(value), + m_angle(0.0f) +{ +} + +/*! + * Constructs QBarDataItem with \a value and \a angle + */ +QBarDataItem::QBarDataItem(float value, float angle) + : d_ptr(0), + m_value(value), + m_angle(angle) { } @@ -72,6 +84,7 @@ QBarDataItem::~QBarDataItem() QBarDataItem &QBarDataItem::operator=(const QBarDataItem &other) { m_value = other.m_value; + m_angle = other.m_angle; if (other.d_ptr) createExtraData(); else @@ -90,6 +103,16 @@ QBarDataItem &QBarDataItem::operator=(const QBarDataItem &other) */ /*! + * \fn void QBarDataItem::setRotation(float angle) + * Sets rotation \a angle in degrees for this data item. + */ + +/*! + * \fn float QBarDataItem::rotation() const + * \return rotation angle in degrees for this data item. + */ + +/*! * \internal */ void QBarDataItem::createExtraData() diff --git a/src/datavisualization/data/qbardataitem.h b/src/datavisualization/data/qbardataitem.h index 57a14efb..f16a21b7 100644 --- a/src/datavisualization/data/qbardataitem.h +++ b/src/datavisualization/data/qbardataitem.h @@ -30,13 +30,16 @@ class QT_DATAVISUALIZATION_EXPORT QBarDataItem public: QBarDataItem(); QBarDataItem(float value); + QBarDataItem(float value, float angle); QBarDataItem(const QBarDataItem &other); ~QBarDataItem(); QBarDataItem &operator=(const QBarDataItem &other); - void setValue(float value) { m_value = value; } - float value() const { return m_value; } + inline void setValue(float value) { m_value = value; } + inline float value() const { return m_value; } + inline void setRotation(float angle) { m_angle = angle; } + inline float rotation() const { return m_angle; } protected: virtual void createExtraData(); @@ -45,6 +48,7 @@ protected: private: float m_value; + float m_angle; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/data/qscatterdataitem.cpp b/src/datavisualization/data/qscatterdataitem.cpp index d4641c7f..b8b85381 100644 --- a/src/datavisualization/data/qscatterdataitem.cpp +++ b/src/datavisualization/data/qscatterdataitem.cpp @@ -72,6 +72,7 @@ QScatterDataItem::~QScatterDataItem() QScatterDataItem &QScatterDataItem::operator=(const QScatterDataItem &other) { m_position = other.m_position; + m_rotation = other.m_rotation; if (other.d_ptr) createExtraData(); @@ -94,11 +95,15 @@ QScatterDataItem &QScatterDataItem::operator=(const QScatterDataItem &other) /*! * \fn void QScatterDataItem::setRotation(const QQuaternion &rotation) * Sets \a rotation to this data item. + * The \a rotation should be a normalized QQuaternion. + * If the series also has rotation, item and series rotations are multiplied together. + * Defaults to no rotation. */ /*! * \fn QQuaternion QScatterDataItem::rotation() const * \return rotation of this data item. + * \sa setRotation() */ /*! diff --git a/src/datavisualization/data/scatterrenderitem.cpp b/src/datavisualization/data/scatterrenderitem.cpp index 635f11cb..236893a8 100644 --- a/src/datavisualization/data/scatterrenderitem.cpp +++ b/src/datavisualization/data/scatterrenderitem.cpp @@ -33,6 +33,7 @@ ScatterRenderItem::ScatterRenderItem(const ScatterRenderItem &other) m_visible(false) { m_position = other.m_position; + m_rotation = other.m_rotation; } ScatterRenderItem::~ScatterRenderItem() diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index 4140f01c..7e727645 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -44,6 +44,7 @@ const GLfloat labelMargin = 0.05f; const GLfloat gridLineWidth = 0.005f; const bool sliceGridLabels = true; +const QQuaternion identityQuaternion; Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) : Abstract3DRenderer(controller), @@ -190,12 +191,13 @@ void Bars3DRenderer::updateData() } for (int series = 0; series < seriesCount; series++) { - if (newRows != m_renderingArrays.at(series).size() - || newColumns != m_renderingArrays.at(series).at(0).size()) { + BarRenderItemArray &renderArray = m_renderingArrays[series]; + if (newRows != renderArray.size() + || newColumns != renderArray.at(0).size()) { // Destroy old render items and reallocate new array - m_renderingArrays[series].resize(newRows); + renderArray.resize(newRows); for (int i = 0; i < newRows; i++) - m_renderingArrays[series][i].resize(newColumns); + renderArray[i].resize(newColumns); } // Update cached data window @@ -208,10 +210,10 @@ void Bars3DRenderer::updateData() GLfloat heightValue = 0.0f; for (int i = 0; i < newRows; i++) { int j = 0; + BarRenderItemRow &renderRow = renderArray[i]; if (dataRowIndex < dataRowCount) { const QBarDataRow *dataRow = dataProxy->rowAt(dataRowIndex); - updateSize = qMin((dataRow->size() - minCol), - m_renderingArrays.at(series).at(i).size()); + updateSize = qMin((dataRow->size() - minCol), renderRow.size()); if (dataRow) { int dataColIndex = minCol; for (; j < updateSize ; j++) { @@ -230,15 +232,24 @@ void Bars3DRenderer::updateData() heightValue = 0.0f; } } - m_renderingArrays[series][i][j].setValue(value); - m_renderingArrays[series][i][j].setHeight(heightValue / m_heightNormalizer); + renderRow[j].setValue(value); + renderRow[j].setHeight(heightValue / m_heightNormalizer); + float angle = dataRow->at(dataColIndex).rotation(); + if (angle) { + renderRow[j].setRotation( + QQuaternion::fromAxisAndAngle( + upVector, angle)); + } else { + renderRow[j].setRotation(identityQuaternion); + } dataColIndex++; } } } for (; j < m_renderingArrays.at(series).at(i).size(); j++) { - m_renderingArrays[series][i][j].setValue(0.0f); - m_renderingArrays[series][i][j].setHeight(0.0f); + renderRow[j].setValue(0.0f); + renderRow[j].setHeight(0.0f); + renderRow[j].setRotation(identityQuaternion); } dataRowIndex++; } @@ -248,6 +259,18 @@ void Bars3DRenderer::updateData() updateSelectedBar(m_selectedBarPos, m_selectedBarSeries); } +void Bars3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList, bool updateVisibility) +{ + Abstract3DRenderer::updateSeries(seriesList, updateVisibility); + + // Fix the series rotations - ignore any rotations that are not along Y-axis + for (int series = 0; series < m_visibleSeriesList.size(); series++) { + QVector3D vector = m_visibleSeriesList.at(series).meshRotation().vector(); + if (vector.x() || vector.z()) + m_visibleSeriesList[series].setMeshRotation(identityQuaternion); + } +} + void Bars3DRenderer::updateScene(Q3DScene *scene) { if (m_hasNegativeValues) @@ -283,6 +306,7 @@ void Bars3DRenderer::drawSlicedScene() GLfloat barPosX = 0; QVector3D lightPos; QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor()); + static QQuaternion ninetyDegreeRotation = QQuaternion::fromAxisAndAngle(upVector, 90.0f); // Specify viewport glViewport(m_secondarySubViewport.x(), @@ -479,6 +503,8 @@ void Bars3DRenderer::drawSlicedScene() if (!item) continue; + QQuaternion seriesRotation; + if (item->seriesIndex() != currentSeriesIndex) { currentSeriesIndex = item->seriesIndex(); currentSeries = &(m_visibleSeriesList.at(currentSeriesIndex)); @@ -509,6 +535,7 @@ void Bars3DRenderer::drawSlicedScene() } previousColorStyle = colorStyle; + seriesRotation = currentSeries->meshRotation(); } if (item->height() < 0) @@ -519,20 +546,27 @@ void Bars3DRenderer::drawSlicedScene() QMatrix4x4 MVPMatrix; QMatrix4x4 modelMatrix; QMatrix4x4 itModelMatrix; - GLfloat barRotation = 0.0f; + QQuaternion barRotation = item->rotation(); GLfloat barPosY = item->translation().y() + barPosYAdjustment - zeroPosAdjustment; if (rowMode) { barPosX = item->translation().x(); } else { barPosX = -(item->translation().z()); // flip z; frontmost bar to the left - barRotation = 90.0f; + barRotation *= ninetyDegreeRotation; } modelMatrix.translate(barPosX, barPosY, 0.0f); modelMatrixScaler.setY(item->height()); - modelMatrix.rotate(barRotation, 0.0f, 1.0f, 0.0f); - itModelMatrix.rotate(barRotation, 0.0f, 1.0f, 0.0f); + + if (!seriesRotation.isIdentity()) + barRotation *= seriesRotation; + + if (!barRotation.isIdentity()) { + modelMatrix.rotate(barRotation); + itModelMatrix.rotate(barRotation); + } + modelMatrix.scale(modelMatrixScaler); itModelMatrix.scale(modelMatrixScaler); @@ -822,6 +856,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) float seriesPos = m_seriesStart; for (int series = 0; series < seriesCount; series++) { ObjectHelper *barObj = m_visibleSeriesList.at(series).object(); + QQuaternion seriesRotation(m_visibleSeriesList.at(series).meshRotation()); for (int row = startRow; row != stopRow; row += stepRow) { for (int bar = startBar; bar != stopBar; bar += stepBar) { GLfloat shadowOffset = 0.0f; @@ -853,6 +888,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) (m_columnDepth - rowPos) / m_scaleFactor); // Scale the bars down in X and Z to reduce self-shadowing issues shadowScaler.setY(item.height()); + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) + modelMatrix.rotate(seriesRotation * item.rotation()); modelMatrix.scale(shadowScaler); MVPMatrix = depthProjectionViewMatrix * modelMatrix; @@ -915,6 +952,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) float seriesPos = m_seriesStart; for (int series = 0; series < seriesCount; series++) { ObjectHelper *barObj = m_visibleSeriesList.at(series).object(); + QQuaternion seriesRotation(m_visibleSeriesList.at(series).meshRotation()); for (int row = startRow; row != stopRow; row += stepRow) { for (int bar = startBar; bar != stopBar; bar += stepBar) { const BarRenderItem &item = m_renderingArrays.at(series).at(row).at(bar); @@ -935,6 +973,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor, item.height(), (m_columnDepth - rowPos) / m_scaleFactor); + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) + modelMatrix.rotate(seriesRotation * item.rotation()); modelMatrix.scale(QVector3D(m_scaleX * m_seriesScaleX, item.height(), m_scaleZ * m_seriesScaleZ)); @@ -1063,6 +1103,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) float seriesPos = m_seriesStart; for (int series = 0; series < seriesCount; series++) { const SeriesRenderCache ¤tSeries = m_visibleSeriesList.at(series); + QQuaternion seriesRotation(currentSeries.meshRotation()); ObjectHelper *barObj = currentSeries.object(); Q3DTheme::ColorStyle colorStyle = currentSeries.colorStyle(); bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform); @@ -1123,6 +1164,11 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) item.height(), (m_columnDepth - rowPos) / m_scaleFactor); modelScaler.setY(item.height()); + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) { + QQuaternion totalRotation = seriesRotation * item.rotation(); + modelMatrix.rotate(totalRotation); + itModelMatrix.rotate(totalRotation); + } modelMatrix.scale(modelScaler); itModelMatrix.scale(modelScaler); #ifdef SHOW_DEPTH_TEXTURE_SCENE @@ -1388,7 +1434,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) // Draw grid lines if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { ShaderHelper *lineShader = m_backgroundShader; - QQuaternion lineRotation = QQuaternion(); + QQuaternion lineRotation; // Bind bar shader lineShader->bind(); @@ -2021,7 +2067,7 @@ void Bars3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh { if (!m_cachedTheme->isBackgroundEnabled()) { // Load full version of meshes that have it available - // Note: Minimal and Point not supported in bar charts + // Note: Minimal, Point, and Arrow not supported in bar charts if (mesh != QAbstract3DSeries::MeshSphere) fileName.append(QStringLiteral("Full")); } diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h index 04e2a1ac..46227aed 100644 --- a/src/datavisualization/engine/bars3drenderer_p.h +++ b/src/datavisualization/engine/bars3drenderer_p.h @@ -114,6 +114,7 @@ public: ~Bars3DRenderer(); void updateData(); + void updateSeries(const QList<QAbstract3DSeries *> &seriesList, bool updateVisibility); void updateScene(Q3DScene *scene); void render(GLuint defaultFboHandle = 0); diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc index 073c7450..18cba7fe 100644 --- a/src/datavisualization/engine/engine.qrc +++ b/src/datavisualization/engine/engine.qrc @@ -27,8 +27,8 @@ <file alias="negativeBackground">meshes/backgroundNegatives.obj</file> <file alias="minimal">meshes/minimalFlat.obj</file> <file alias="minimalSmooth">meshes/minimalSmooth.obj</file> - <file alias="arrowFull">meshes/arrowFlat.obj</file> - <file alias="arrowSmoothFull">meshes/arrowSmooth.obj</file> + <file alias="arrow">meshes/arrowFlat.obj</file> + <file alias="arrowSmooth">meshes/arrowSmooth.obj</file> </qresource> <qresource prefix="/shaders"> <file alias="fragment">shaders/default.frag</file> diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp index 9cbffcdb..7a2bf568 100644 --- a/src/datavisualization/engine/scatter3drenderer.cpp +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -204,15 +204,16 @@ void Scatter3DRenderer::updateData() for (int i = 0; i < dataSize; i++) { QVector3D dotPos = dataArray.at(i).position(); + ScatterRenderItem &renderItem = m_renderingArrays[series][i]; if ((dotPos.x() >= minX && dotPos.x() <= maxX ) && (dotPos.y() >= minY && dotPos.y() <= maxY) && (dotPos.z() >= minZ && dotPos.z() <= maxZ)) { - m_renderingArrays[series][i].setPosition(dotPos); - m_renderingArrays[series][i].setVisible(true); - m_renderingArrays[series][i].setRotation(dataArray.at(i).rotation()); - calculateTranslation(m_renderingArrays[series][i]); + renderItem.setPosition(dotPos); + renderItem.setVisible(true); + renderItem.setRotation(dataArray.at(i).rotation()); + calculateTranslation(renderItem); } else { - m_renderingArrays[series][i].setVisible(false); + renderItem.setVisible(false); } } } @@ -372,6 +373,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) // Draw dots to depth buffer for (int series = 0; series < seriesCount; series++) { ObjectHelper *dotObj = m_visibleSeriesList.at(series).object(); + QQuaternion seriesRotation = m_visibleSeriesList.at(series).meshRotation(); bool drawingPoints = (m_visibleSeriesList.at(series).mesh() == QAbstract3DSeries::MeshPoint); float itemSize = m_cachedItemSize.at(series) / itemScaler; @@ -393,7 +395,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) modelMatrix.translate(item.translation()); if (!drawingPoints) { - modelMatrix.rotate(item.rotation()); + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) + modelMatrix.rotate(seriesRotation * item.rotation()); modelMatrix.scale(modelScaler); } @@ -467,6 +470,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) bool previousDrawingPoints = (m_visibleSeriesList.at(0).mesh() != QAbstract3DSeries::MeshPoint); for (int series = 0; series < seriesCount; series++) { ObjectHelper *dotObj = m_visibleSeriesList.at(series).object(); + QQuaternion seriesRotation = m_visibleSeriesList.at(series).meshRotation(); bool drawingPoints = (m_visibleSeriesList.at(series).mesh() == QAbstract3DSeries::MeshPoint); float itemSize = m_cachedItemSize.at(series) / itemScaler; @@ -504,7 +508,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) modelMatrix.translate(item.translation()); if (!drawingPoints) { - modelMatrix.rotate(item.rotation()); + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) + modelMatrix.rotate(seriesRotation * item.rotation()); modelMatrix.scale(modelScaler); } @@ -601,6 +606,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) for (int series = 0; series < seriesCount; series++) { const SeriesRenderCache ¤tSeries = m_visibleSeriesList.at(series); + QQuaternion seriesRotation = currentSeries.meshRotation(); ObjectHelper *dotObj = currentSeries.object(); bool drawingPoints = (currentSeries.mesh() == QAbstract3DSeries::MeshPoint); Q3DTheme::ColorStyle colorStyle = currentSeries.colorStyle(); @@ -662,10 +668,13 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) modelMatrix.translate(item.translation()); if (!drawingPoints) { - modelMatrix.rotate(item.rotation()); + if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) { + QQuaternion totalRotation = seriesRotation * item.rotation(); + modelMatrix.rotate(totalRotation); + itModelMatrix.rotate(totalRotation); + } modelMatrix.scale(modelScaler); itModelMatrix.scale(modelScaler); - itModelMatrix.rotate(item.rotation()); } #ifdef SHOW_DEPTH_TEXTURE_SCENE MVPMatrix = depthProjectionViewMatrix * modelMatrix; @@ -862,8 +871,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) m_cachedTheme->lightStrength() / 2.5f); } - QQuaternion lineYRotation = QQuaternion(); - QQuaternion lineXRotation = QQuaternion(); + QQuaternion lineYRotation; + QQuaternion lineXRotation; if (m_xFlipped) lineYRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, -90.0f); @@ -1618,7 +1627,8 @@ void Scatter3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Me // Load full version of meshes that have it available if (mesh != QAbstract3DSeries::MeshSphere && mesh != QAbstract3DSeries::MeshMinimal - && mesh != QAbstract3DSeries::MeshPoint) { + && mesh != QAbstract3DSeries::MeshPoint + && mesh != QAbstract3DSeries::MeshArrow) { fileName.append(QStringLiteral("Full")); } } diff --git a/src/datavisualization/engine/selectionpointer.cpp b/src/datavisualization/engine/selectionpointer.cpp index 85fb2b71..2dd23930 100644 --- a/src/datavisualization/engine/selectionpointer.cpp +++ b/src/datavisualization/engine/selectionpointer.cpp @@ -110,8 +110,15 @@ void SelectionPointer::render(GLuint defaultFboHandle) // Position the pointer ball modelMatrix.translate(m_position); + if (!m_rotation.isIdentity()) { + modelMatrix.rotate(m_rotation); + itModelMatrix.rotate(m_rotation); + } + // Scale the point with fixed values (at this point) - modelMatrix.scale(QVector3D(0.05f, 0.05f, 0.05f)); + QVector3D scaleVector(0.05f, 0.05f, 0.05f); + modelMatrix.scale(scaleVector); + itModelMatrix.scale(scaleVector); MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; @@ -189,7 +196,7 @@ void SelectionPointer::render(GLuint defaultFboHandle) glEnable(GL_DEPTH_TEST); } -void SelectionPointer::setPosition(QVector3D position) +void SelectionPointer::setPosition(const QVector3D &position) { m_position = position; } @@ -200,11 +207,16 @@ void SelectionPointer::updateSliceData(bool sliceActivated, GLfloat autoScaleAdj m_autoScaleAdjustment = autoScaleAdjustment; } -void SelectionPointer::setHighlightColor(QVector3D colorVector) +void SelectionPointer::setHighlightColor(const QVector3D &colorVector) { m_highlightColor = colorVector; } +void SelectionPointer::setRotation(const QQuaternion &rotation) +{ + m_rotation = rotation; +} + void SelectionPointer::setLabel(const QString &label) { m_label = label; @@ -222,7 +234,7 @@ void SelectionPointer::handleDrawerChange() setLabel(m_label); } -void SelectionPointer::updateBoundingRect(QRect rect) +void SelectionPointer::updateBoundingRect(const QRect &rect) { m_mainViewPort = rect; } diff --git a/src/datavisualization/engine/selectionpointer_p.h b/src/datavisualization/engine/selectionpointer_p.h index 12317943..5d901caa 100644 --- a/src/datavisualization/engine/selectionpointer_p.h +++ b/src/datavisualization/engine/selectionpointer_p.h @@ -52,14 +52,15 @@ public: ~SelectionPointer(); void render(GLuint defaultFboHandle = 0); - void setPosition(QVector3D position); + void setPosition(const QVector3D &position); void setLabel(const QString &label); void setPointerObject(ObjectHelper *object); void handleDrawerChange(); - void updateBoundingRect(QRect rect); + void updateBoundingRect(const QRect &rect); void updateScene(Q3DScene *scene); void updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment); - void setHighlightColor(QVector3D colorVector); + void setHighlightColor(const QVector3D &colorVector); + void setRotation(const QQuaternion &rotation); private: void initializeOpenGL(); @@ -83,6 +84,7 @@ private: bool m_cachedIsSlicingActivated; GLfloat m_autoScaleAdjustment; QVector3D m_highlightColor; + QQuaternion m_rotation; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/engine/seriesrendercache.cpp b/src/datavisualization/engine/seriesrendercache.cpp index f1165cb7..f13fc2ca 100644 --- a/src/datavisualization/engine/seriesrendercache.cpp +++ b/src/datavisualization/engine/seriesrendercache.cpp @@ -126,6 +126,11 @@ void SeriesRenderCache::populate(QAbstract3DSeries *series, Abstract3DRenderer * } } + if (seriesChanged || changeTracker.meshRotationChanged) { + m_meshRotation = series->meshRotation(); + changeTracker.meshRotationChanged = false; + } + if (seriesChanged || changeTracker.colorStyleChanged) { m_colorStyle = series->colorStyle(); changeTracker.colorStyleChanged = false; diff --git a/src/datavisualization/engine/seriesrendercache_p.h b/src/datavisualization/engine/seriesrendercache_p.h index 81eaacbc..ec6ef0ad 100644 --- a/src/datavisualization/engine/seriesrendercache_p.h +++ b/src/datavisualization/engine/seriesrendercache_p.h @@ -53,6 +53,8 @@ public: inline const QString &itemLabelFormat() const { return m_itemLabelFormat; } inline const QAbstract3DSeries::Mesh &mesh() const { return m_mesh; } + inline const QQuaternion &meshRotation() const { return m_meshRotation; } + inline void setMeshRotation(const QQuaternion &rotation) { m_meshRotation = rotation; } inline ObjectHelper *object() const { return m_object; } inline const Q3DTheme::ColorStyle &colorStyle() const { return m_colorStyle; } inline const QVector3D &baseColor() const { return m_baseColor; } @@ -68,6 +70,7 @@ protected: QString m_itemLabelFormat; ObjectHelper *m_object; QAbstract3DSeries::Mesh m_mesh; + QQuaternion m_meshRotation; Q3DTheme::ColorStyle m_colorStyle; QVector3D m_baseColor; diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 286477df..2ef5ea5d 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -301,6 +301,7 @@ void Surface3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesLis Utils::vectorFromColor(series->singleHighlightColor())); // Make sure selection pointer object reference is still good m_selectionPointer->setPointerObject(m_visibleSeriesList.at(0).object()); + m_selectionPointer->setRotation(m_visibleSeriesList.at(0).meshRotation()); } } } @@ -1222,8 +1223,8 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) m_cachedTheme->lightStrength() / 2.5f); } - QQuaternion lineYRotation = QQuaternion(); - QQuaternion lineXRotation = QQuaternion(); + QQuaternion lineYRotation; + QQuaternion lineXRotation; if (m_xFlipped) lineYRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, -90.0f); @@ -1934,6 +1935,7 @@ void Surface3DRenderer::surfacePointSelected(const QPoint &point) m_selectionPointer->setPointerObject(m_visibleSeriesList.at(0).object()); m_selectionPointer->setHighlightColor(m_visibleSeriesList.at(0).singleHighlightColor()); m_selectionPointer->updateScene(m_cachedScene); + m_selectionPointer->setRotation(m_visibleSeriesList.at(0).meshRotation()); } // Maps selection Id to surface point in data array diff --git a/tests/barstest/chart.cpp b/tests/barstest/chart.cpp index 6b0345ad..187f4886 100644 --- a/tests/barstest/chart.cpp +++ b/tests/barstest/chart.cpp @@ -47,6 +47,7 @@ GraphModifier::GraphModifier(Q3DBars *barchart, QColorDialog *colorDialog) m_minval(-16.0f), m_maxval(20.0f), m_selectedBar(-1, -1), + m_selectedSeries(0), m_autoAdjustingAxis(new QValue3DAxis), m_fixedRangeAxis(new QValue3DAxis), m_temperatureAxis(new QValue3DAxis), @@ -229,6 +230,8 @@ GraphModifier::GraphModifier(Q3DBars *barchart, QColorDialog *colorDialog) QObject::connect(&m_selectionTimer, &QTimer::timeout, this, &GraphModifier::triggerSelection); + QObject::connect(&m_rotationTimer, &QTimer::timeout, this, + &GraphModifier::triggerRotation); resetTemperatureData(); } @@ -702,11 +705,17 @@ void GraphModifier::handleSelectionChange(const QPoint &position) m_selectedBar = position; int index = 0; foreach (QBar3DSeries *series, m_graph->seriesList()) { - if (series == sender()) + if (series == sender()) { + if (series->selectedBar() != QBar3DSeries::invalidSelectionPosition()) + m_selectedSeries = series; break; + } index++; } + if (m_selectedSeries->selectedBar() == QBar3DSeries::invalidSelectionPosition()) + m_selectedSeries = 0; + qDebug() << "Selected bar position:" << position << "series:" << index; } @@ -1027,6 +1036,14 @@ void GraphModifier::insertRemoveTestToggle() } } +void GraphModifier::toggleRotation() +{ + if (m_rotationTimer.isActive()) + m_rotationTimer.stop(); + else + m_rotationTimer.start(20); +} + void GraphModifier::insertRemoveTimerTimeout() { if (m_insertRemoveStep < 32) { @@ -1066,6 +1083,25 @@ void GraphModifier::triggerSelection() m_graph->scene()->setSelectionQueryPosition(m_customInputHandler->inputPosition()); } +void GraphModifier::triggerRotation() +{ + if (m_selectedSeries) { + QPoint selectedBar = m_selectedSeries->selectedBar(); + if (selectedBar != QBar3DSeries::invalidSelectionPosition()) { + QBarDataItem item(*(m_selectedSeries->dataProxy()->itemAt(selectedBar.x(), selectedBar.y()))); + item.setRotation(item.rotation() + 1.0f); + m_selectedSeries->dataProxy()->setItem(selectedBar.x(), selectedBar.y(), item); + } + } else { + // Rotate the first series instead + static float seriesAngle = 0.0f; + if (m_graph->seriesList().size()) { + QQuaternion rotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, seriesAngle++); + m_graph->seriesList().at(0)->setMeshRotation(rotation); + } + } +} + void GraphModifier::setBackgroundEnabled(int enabled) { m_graph->activeTheme()->setBackgroundEnabled(bool(enabled)); diff --git a/tests/barstest/chart.h b/tests/barstest/chart.h index 8e3271cc..c9d2ca9e 100644 --- a/tests/barstest/chart.h +++ b/tests/barstest/chart.h @@ -84,6 +84,7 @@ public: QBarDataArray *makeDummyData(); void primarySeriesTest(); void insertRemoveTestToggle(); + void toggleRotation(); public slots: void flipViews(); @@ -101,6 +102,7 @@ public slots: void insertRemoveTimerTimeout(); void triggerSelection(); + void triggerRotation(); signals: void shadowQualityChanged(int quality); @@ -123,6 +125,7 @@ private: QStringList m_months; QStringList m_years; QPoint m_selectedBar; + QBar3DSeries *m_selectedSeries; QValue3DAxis *m_autoAdjustingAxis; QValue3DAxis *m_fixedRangeAxis; QValue3DAxis *m_temperatureAxis; @@ -148,6 +151,7 @@ private: int m_insertRemoveStep; QAbstract3DInputHandler *m_customInputHandler; QTimer m_selectionTimer; + QTimer m_rotationTimer; }; #endif diff --git a/tests/barstest/main.cpp b/tests/barstest/main.cpp index 52d79468..a57d4aca 100644 --- a/tests/barstest/main.cpp +++ b/tests/barstest/main.cpp @@ -161,6 +161,10 @@ int main(int argc, char **argv) primarySeriesTestsButton->setText(QStringLiteral("Test primary series")); primarySeriesTestsButton->setEnabled(true); + QPushButton *toggleRotationButton = new QPushButton(widget); + toggleRotationButton->setText(QStringLiteral("Toggle rotation")); + toggleRotationButton->setEnabled(true); + QColorDialog *colorDialog = new QColorDialog(widget); QLinearGradient grBtoY(0, 0, 100, 0); @@ -308,6 +312,7 @@ int main(int argc, char **argv) vLayout->addWidget(changeColorStyleButton, 0, Qt::AlignTop); vLayout->addWidget(ownThemeButton, 0, Qt::AlignTop); vLayout->addWidget(primarySeriesTestsButton, 0, Qt::AlignTop); + vLayout->addWidget(toggleRotationButton, 0, Qt::AlignTop); vLayout->addWidget(gradientBtoYPB, 1, Qt::AlignTop); vLayout2->addWidget(staticCheckBox, 0, Qt::AlignTop); @@ -411,6 +416,8 @@ int main(int argc, char **argv) &GraphModifier::useOwnTheme); QObject::connect(primarySeriesTestsButton, &QPushButton::clicked, modifier, &GraphModifier::primarySeriesTest); + QObject::connect(toggleRotationButton, &QPushButton::clicked, modifier, + &GraphModifier::toggleRotation); QObject::connect(colorDialog, &QColorDialog::currentColorChanged, modifier, &GraphModifier::changeBaseColor); QObject::connect(gradientBtoYPB, &QPushButton::clicked, modifier, diff --git a/tests/directional/main.cpp b/tests/directional/main.cpp index 359868cc..34d2e4a1 100644 --- a/tests/directional/main.cpp +++ b/tests/directional/main.cpp @@ -78,6 +78,9 @@ int main(int argc, char **argv) QPushButton *cameraButton = new QPushButton(widget); cameraButton->setText(QStringLiteral("Change camera preset")); + QPushButton *toggleRotationButton = new QPushButton(widget); + toggleRotationButton->setText(QStringLiteral("Toggle rotation")); + QCheckBox *backgroundCheckBox = new QCheckBox(widget); backgroundCheckBox->setText(QStringLiteral("Show background")); backgroundCheckBox->setChecked(true); @@ -103,6 +106,7 @@ int main(int argc, char **argv) //! [5] vLayout->addWidget(labelButton, 0, Qt::AlignTop); vLayout->addWidget(cameraButton, 0, Qt::AlignTop); + vLayout->addWidget(toggleRotationButton, 0, Qt::AlignTop); vLayout->addWidget(backgroundCheckBox); vLayout->addWidget(gridCheckBox); vLayout->addWidget(new QLabel(QStringLiteral("Change dot style"))); @@ -122,6 +126,8 @@ int main(int argc, char **argv) //! [6] QObject::connect(cameraButton, &QPushButton::clicked, modifier, &ScatterDataModifier::changePresetCamera); + QObject::connect(toggleRotationButton, &QPushButton::clicked, modifier, + &ScatterDataModifier::toggleRotation); QObject::connect(labelButton, &QPushButton::clicked, modifier, &ScatterDataModifier::changeLabelStyle); diff --git a/tests/directional/scatterdatamodifier.cpp b/tests/directional/scatterdatamodifier.cpp index f7089ae4..5da48483 100644 --- a/tests/directional/scatterdatamodifier.cpp +++ b/tests/directional/scatterdatamodifier.cpp @@ -56,6 +56,9 @@ ScatterDataModifier::ScatterDataModifier(Q3DScatter *scatter) series->setItemLabelFormat("@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"); m_graph->addSeries(series); + QObject::connect(&m_rotationTimer, &QTimer::timeout, this, + &ScatterDataModifier::triggerRotation); + addData(); } @@ -164,6 +167,24 @@ void ScatterDataModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQ emit shadowQualityChanged(quality); // connected to a checkbox in main.cpp } +void ScatterDataModifier::triggerRotation() +{ + if (m_graph->seriesList().size()) { + int selectedIndex = m_graph->seriesList().at(0)->selectedItem(); + if (selectedIndex != QScatter3DSeries::invalidSelectionIndex()) { + static float itemAngle = 0.0f; + QScatterDataItem item(*(m_graph->seriesList().at(0)->dataProxy()->itemAt(selectedIndex))); + QQuaternion itemRotation = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, itemAngle++); + item.setRotation(itemRotation); + m_graph->seriesList().at(0)->dataProxy()->setItem(selectedIndex, item); + } else { + static float seriesAngle = 0.0f; + QQuaternion rotation = QQuaternion::fromAxisAndAngle(1.0f, 1.0f, 1.0f, seriesAngle++); + m_graph->seriesList().at(0)->setMeshRotation(rotation); + } + } +} + void ScatterDataModifier::changeShadowQuality(int quality) { QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality); @@ -179,3 +200,11 @@ void ScatterDataModifier::setGridEnabled(int enabled) { m_graph->activeTheme()->setGridEnabled((bool)enabled); } + +void ScatterDataModifier::toggleRotation() +{ + if (m_rotationTimer.isActive()) + m_rotationTimer.stop(); + else + m_rotationTimer.start(20); +} diff --git a/tests/directional/scatterdatamodifier.h b/tests/directional/scatterdatamodifier.h index e3979818..f920d43f 100644 --- a/tests/directional/scatterdatamodifier.h +++ b/tests/directional/scatterdatamodifier.h @@ -22,6 +22,7 @@ #include <QtDataVisualization/q3dscatter.h> #include <QtDataVisualization/qabstract3dseries.h> #include <QtGui/QFont> +#include <QtCore/QTimer> using namespace QtDataVisualization; @@ -40,6 +41,7 @@ public: void changeFontSize(int fontsize); void setBackgroundEnabled(int enabled); void setGridEnabled(int enabled); + void toggleRotation(); void start(); public slots: @@ -47,6 +49,7 @@ public slots: void changeTheme(int theme); void changeShadowQuality(int quality); void shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality shadowQuality); + void triggerRotation(); signals: void backgroundEnabledChanged(bool enabled); @@ -59,6 +62,7 @@ private: int m_fontSize; QAbstract3DSeries::Mesh m_style; bool m_smooth; + QTimer m_rotationTimer; }; #endif |