diff options
26 files changed, 440 insertions, 70 deletions
diff --git a/examples/datavisualization/bars/graphmodifier.cpp b/examples/datavisualization/bars/graphmodifier.cpp index 5df4066c..d19910ec 100644 --- a/examples/datavisualization/bars/graphmodifier.cpp +++ b/examples/datavisualization/bars/graphmodifier.cpp @@ -278,3 +278,8 @@ void GraphModifier::setSeriesVisibility(int enabled) { m_secondarySeries->setVisible(bool(enabled)); } + +void GraphModifier::setReverseValueAxis(int enabled) +{ + m_graph->valueAxis()->setReversed(enabled); +} diff --git a/examples/datavisualization/bars/graphmodifier.h b/examples/datavisualization/bars/graphmodifier.h index cac002a1..e1aacaf7 100644 --- a/examples/datavisualization/bars/graphmodifier.h +++ b/examples/datavisualization/bars/graphmodifier.h @@ -48,6 +48,7 @@ public: void setGridEnabled(int enabled); void setSmoothBars(int smooth); void setSeriesVisibility(int enabled); + void setReverseValueAxis(int enabled); public slots: void changeRange(int range); diff --git a/examples/datavisualization/bars/main.cpp b/examples/datavisualization/bars/main.cpp index e6461202..79b2967a 100644 --- a/examples/datavisualization/bars/main.cpp +++ b/examples/datavisualization/bars/main.cpp @@ -132,6 +132,10 @@ int main(int argc, char **argv) seriesCheckBox->setText(QStringLiteral("Show second series")); seriesCheckBox->setChecked(false); + QCheckBox *reverseValueAxisCheckBox = new QCheckBox(widget); + reverseValueAxisCheckBox->setText(QStringLiteral("Reverse value axis")); + reverseValueAxisCheckBox->setChecked(false); + //! [4] QSlider *rotationSliderX = new QSlider(Qt::Horizontal, widget); rotationSliderX->setTickInterval(30); @@ -191,6 +195,7 @@ int main(int argc, char **argv) vLayout->addWidget(gridCheckBox); vLayout->addWidget(smoothCheckBox); vLayout->addWidget(seriesCheckBox); + vLayout->addWidget(reverseValueAxisCheckBox); vLayout->addWidget(new QLabel(QStringLiteral("Show year"))); vLayout->addWidget(rangeList); vLayout->addWidget(new QLabel(QStringLiteral("Change bar style"))); @@ -228,6 +233,8 @@ int main(int argc, char **argv) &GraphModifier::setSmoothBars); QObject::connect(seriesCheckBox, &QCheckBox::stateChanged, modifier, &GraphModifier::setSeriesVisibility); + QObject::connect(reverseValueAxisCheckBox, &QCheckBox::stateChanged, modifier, + &GraphModifier::setReverseValueAxis); QObject::connect(modifier, &GraphModifier::backgroundEnabledChanged, backgroundCheckBox, &QCheckBox::setChecked); diff --git a/src/datavisualization/axis/qvalue3daxis.cpp b/src/datavisualization/axis/qvalue3daxis.cpp index 79d374ea..1c7b647a 100644 --- a/src/datavisualization/axis/qvalue3daxis.cpp +++ b/src/datavisualization/axis/qvalue3daxis.cpp @@ -83,6 +83,15 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION */ /*! + * \qmlproperty bool ValueAxis3D::reversed + * \since QtDataVisualization 1.1 + * + * If \c{true}, the axis will be rendered in reverse, i.e. the positions of minimum and maximum + * values are swapped when the graph is rendered. This property doesn't affect the actual + * minimum and maximum values of the axis. + */ + +/*! * Constructs QValue3DAxis with the given \a parent. */ QValue3DAxis::QValue3DAxis(QObject *parent) : @@ -204,6 +213,27 @@ QValue3DAxisFormatter *QValue3DAxis::formatter() const } /*! + * \property QValue3DAxis::reversed + * \since Qt Data Visualization 1.1 + * + * If \c{true}, the axis will be rendered in reverse, i.e. the positions of minimum and maximum + * values are swapped when the graph is rendered. This property doesn't affect the actual + * minimum and maximum values of the axis. + */ +void QValue3DAxis::setReversed(bool enable) +{ + if (dptr()->m_reversed != enable) { + dptr()->m_reversed = enable; + emit reversedChanged(enable); + } +} + +bool QValue3DAxis::reversed() const +{ + return dptrc()->m_reversed; +} + +/*! * \internal */ QValue3DAxisPrivate *QValue3DAxis::dptr() @@ -225,7 +255,8 @@ QValue3DAxisPrivate::QValue3DAxisPrivate(QValue3DAxis *q) m_subSegmentCount(1), m_labelFormat(Utils::defaultLabelFormat()), m_labelsDirty(true), - m_formatter(0) + m_formatter(0), + m_reversed(false) { } diff --git a/src/datavisualization/axis/qvalue3daxis.h b/src/datavisualization/axis/qvalue3daxis.h index 39a4a886..f552269c 100644 --- a/src/datavisualization/axis/qvalue3daxis.h +++ b/src/datavisualization/axis/qvalue3daxis.h @@ -33,6 +33,7 @@ class QT_DATAVISUALIZATION_EXPORT QValue3DAxis : public QAbstract3DAxis Q_PROPERTY(int subSegmentCount READ subSegmentCount WRITE setSubSegmentCount NOTIFY subSegmentCountChanged) Q_PROPERTY(QString labelFormat READ labelFormat WRITE setLabelFormat NOTIFY labelFormatChanged) Q_PROPERTY(QValue3DAxisFormatter* formatter READ formatter WRITE setFormatter NOTIFY formatterChanged REVISION 1) + Q_PROPERTY(bool reversed READ reversed WRITE setReversed NOTIFY reversedChanged REVISION 1) public: explicit QValue3DAxis(QObject *parent = 0); @@ -50,11 +51,15 @@ public: void setFormatter(QValue3DAxisFormatter *formatter); QValue3DAxisFormatter *formatter() const; + void setReversed(bool enable); + bool reversed() const; + signals: void segmentCountChanged(int count); void subSegmentCountChanged(int count); void labelFormatChanged(const QString &format); Q_REVISION(1) void formatterChanged(QValue3DAxisFormatter *formatter); + Q_REVISION(1) void reversedChanged(bool enable); protected: QValue3DAxisPrivate *dptr(); diff --git a/src/datavisualization/axis/qvalue3daxis_p.h b/src/datavisualization/axis/qvalue3daxis_p.h index eeccf527..47fd7e06 100644 --- a/src/datavisualization/axis/qvalue3daxis_p.h +++ b/src/datavisualization/axis/qvalue3daxis_p.h @@ -63,6 +63,7 @@ protected: QString m_labelFormat; bool m_labelsDirty; QValue3DAxisFormatter *m_formatter; + bool m_reversed; private: QValue3DAxis *qptr(); diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp index 31dcab95..2b566a91 100644 --- a/src/datavisualization/engine/abstract3dcontroller.cpp +++ b/src/datavisualization/engine/abstract3dcontroller.cpp @@ -357,6 +357,33 @@ void Abstract3DController::synchDataToRenderer() } } + if (m_changeTracker.axisXReversedChanged) { + m_changeTracker.axisXReversedChanged = false; + if (m_axisX->type() & QAbstract3DAxis::AxisTypeValue) { + QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX); + m_renderer->updateAxisReversed(QAbstract3DAxis::AxisOrientationX, + valueAxisX->reversed()); + } + } + + if (m_changeTracker.axisYReversedChanged) { + m_changeTracker.axisYReversedChanged = false; + if (m_axisY->type() & QAbstract3DAxis::AxisTypeValue) { + QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY); + m_renderer->updateAxisReversed(QAbstract3DAxis::AxisOrientationY, + valueAxisY->reversed()); + } + } + + if (m_changeTracker.axisZReversedChanged) { + m_changeTracker.axisZReversedChanged = false; + if (m_axisZ->type() & QAbstract3DAxis::AxisTypeValue) { + QValue3DAxis *valueAxisZ = static_cast<QValue3DAxis *>(m_axisZ); + m_renderer->updateAxisReversed(QAbstract3DAxis::AxisOrientationZ, + valueAxisZ->reversed()); + } + } + if (m_changedSeriesList.size()) { m_renderer->modifiedSeriesList(m_changedSeriesList); m_changedSeriesList.clear(); @@ -985,6 +1012,12 @@ void Abstract3DController::handleAxisLabelFormatChanged(const QString &format) handleAxisLabelFormatChangedBySender(sender()); } +void Abstract3DController::handleAxisReversedChanged(bool enable) +{ + Q_UNUSED(enable) + handleAxisReversedChangedBySender(sender()); +} + void Abstract3DController::handleAxisFormatterDirty() { handleAxisFormatterDirtyBySender(sender()); @@ -1052,6 +1085,24 @@ void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender) emitNeedRender(); } +void Abstract3DController::handleAxisReversedChangedBySender(QObject *sender) +{ + // Reversing change needs to dirty the data so item positions are recalculated + if (sender == m_axisX) { + m_isDataDirty = true; + m_changeTracker.axisXReversedChanged = true; + } else if (sender == m_axisY) { + m_isDataDirty = true; + m_changeTracker.axisYReversedChanged = true; + } else if (sender == m_axisZ) { + m_isDataDirty = true; + m_changeTracker.axisZReversedChanged = true; + } else { + qWarning() << __FUNCTION__ << "invoked for invalid axis"; + } + emitNeedRender(); +} + void Abstract3DController::handleAxisFormatterDirtyBySender(QObject *sender) { // Sender is QValue3DAxisPrivate @@ -1149,12 +1200,15 @@ void Abstract3DController::setAxisHelper(QAbstract3DAxis::AxisOrientation orient this, &Abstract3DController::handleAxisSubSegmentCountChanged); QObject::connect(valueAxis, &QValue3DAxis::labelFormatChanged, this, &Abstract3DController::handleAxisLabelFormatChanged); + QObject::connect(valueAxis, &QValue3DAxis::reversedChanged, + this, &Abstract3DController::handleAxisReversedChanged); QObject::connect(valueAxis->dptr(), &QValue3DAxisPrivate::formatterDirty, this, &Abstract3DController::handleAxisFormatterDirty); handleAxisSegmentCountChangedBySender(valueAxis); handleAxisSubSegmentCountChangedBySender(valueAxis); handleAxisLabelFormatChangedBySender(valueAxis); + handleAxisReversedChangedBySender(valueAxis); handleAxisFormatterDirtyBySender(valueAxis->dptr()); } } diff --git a/src/datavisualization/engine/abstract3dcontroller_p.h b/src/datavisualization/engine/abstract3dcontroller_p.h index 07aa9ca3..78c6c81c 100644 --- a/src/datavisualization/engine/abstract3dcontroller_p.h +++ b/src/datavisualization/engine/abstract3dcontroller_p.h @@ -76,6 +76,9 @@ struct Abstract3DChangeBitField { bool axisXLabelFormatChanged : 1; bool axisYLabelFormatChanged : 1; bool axisZLabelFormatChanged : 1; + bool axisXReversedChanged : 1; + bool axisYReversedChanged : 1; + bool axisZReversedChanged : 1; bool axisXFormatterChanged : 1; bool axisYFormatterChanged : 1; bool axisZFormatterChanged : 1; @@ -107,6 +110,9 @@ struct Abstract3DChangeBitField { axisXLabelFormatChanged(true), axisYLabelFormatChanged(true), axisZLabelFormatChanged(true), + axisXReversedChanged(true), + axisYReversedChanged(true), + axisZReversedChanged(true), axisXFormatterChanged(true), axisYFormatterChanged(true), axisZFormatterChanged(true) @@ -254,6 +260,7 @@ public: virtual void handleAxisAutoAdjustRangeChangedInOrientation( QAbstract3DAxis::AxisOrientation orientation, bool autoAdjust) = 0; virtual void handleAxisLabelFormatChangedBySender(QObject *sender); + virtual void handleAxisReversedChangedBySender(QObject *sender); virtual void handleAxisFormatterDirtyBySender(QObject *sender); virtual void handleSeriesVisibilityChangedBySender(QObject *sender); virtual void handlePendingClick() = 0; @@ -269,6 +276,7 @@ public slots: void handleAxisSubSegmentCountChanged(int count); void handleAxisAutoAdjustRangeChanged(bool autoAdjust); void handleAxisLabelFormatChanged(const QString &format); + void handleAxisReversedChanged(bool enable); void handleAxisFormatterDirty(); void handleInputViewChanged(QAbstract3DInputHandler::InputView view); void handleInputPositionChanged(const QPoint &position); diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index bd19959b..95cecbd3 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -333,6 +333,14 @@ void Abstract3DRenderer::updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation axisCacheForOrientation(orientation).setLabelFormat(format); } +void Abstract3DRenderer::updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation, + bool enable) +{ + axisCacheForOrientation(orientation).setReversed(enable); + foreach (SeriesRenderCache *cache, m_renderCacheList) + cache->setDataDirty(true); +} + void Abstract3DRenderer::updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation, QValue3DAxisFormatter *formatter) { diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h index ecbbebac..65dcd8f6 100644 --- a/src/datavisualization/engine/abstract3drenderer_p.h +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -103,6 +103,8 @@ public: int count); virtual void updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation orientation, const QString &format); + virtual void updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation, + bool enable); virtual void updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation, QValue3DAxisFormatter *formatter); virtual void modifiedSeriesList(const QVector<QAbstract3DSeries *> &seriesList); diff --git a/src/datavisualization/engine/axisrendercache.cpp b/src/datavisualization/engine/axisrendercache.cpp index 8e78522a..baa733b3 100644 --- a/src/datavisualization/engine/axisrendercache.cpp +++ b/src/datavisualization/engine/axisrendercache.cpp @@ -29,6 +29,7 @@ AxisRenderCache::AxisRenderCache() m_max(10.0f), m_segmentCount(5), m_subSegmentCount(1), + m_reversed(false), m_font(QFont(QStringLiteral("Arial"))), m_formatter(0), m_ctrlFormatter(0), @@ -129,17 +130,24 @@ void AxisRenderCache::updateAllPositions() int index = 0; int grid = 0; int label = 0; + float position = 0.0f; for (; label < labelCount; label++) { - m_adjustedLabelPositions[label] = - m_formatter->labelPositions().at(label) * m_scale + m_translate; + position = m_formatter->labelPositions().at(label); + if (m_reversed) + position = 1.0f - position; + m_adjustedLabelPositions[label] = position * m_scale + m_translate; } for (; grid < gridCount; grid++) { - m_adjustedGridLinePositions[index++] = - m_formatter->gridPositions().at(grid) * m_scale + m_translate; + position = m_formatter->gridPositions().at(grid); + if (m_reversed) + position = 1.0f - position; + m_adjustedGridLinePositions[index++] = position * m_scale + m_translate; } for (int subGrid = 0; subGrid < subGridCount; subGrid++) { - m_adjustedGridLinePositions[index++] = - m_formatter->subGridPositions().at(subGrid) * m_scale + m_translate; + position = m_formatter->subGridPositions().at(subGrid); + if (m_reversed) + position = 1.0f - position; + m_adjustedGridLinePositions[index++] = position * m_scale + m_translate; } m_positionsDirty = false; diff --git a/src/datavisualization/engine/axisrendercache_p.h b/src/datavisualization/engine/axisrendercache_p.h index f37857d9..800421b1 100644 --- a/src/datavisualization/engine/axisrendercache_p.h +++ b/src/datavisualization/engine/axisrendercache_p.h @@ -62,6 +62,8 @@ public: inline int subSegmentCount() const { return m_subSegmentCount; } inline void setLabelFormat(const QString &format) { m_labelFormat = format; } inline const QString &labelFormat() const { return m_labelFormat; } + inline void setReversed(bool enable) { m_reversed = enable; m_positionsDirty = true; } + inline bool reversed() const { return m_reversed; } inline void setFormatter(QValue3DAxisFormatter *formatter) { m_formatter = formatter; m_positionsDirty = true; @@ -88,7 +90,10 @@ public: inline float scale() { return m_scale; } inline float positionAt(float value) { - return m_formatter->positionAt(value) * m_scale + m_translate; + if (m_reversed) + return (1.0f - m_formatter->positionAt(value)) * m_scale + m_translate; + else + return m_formatter->positionAt(value) * m_scale + m_translate; } public slots: @@ -106,6 +111,7 @@ private: int m_segmentCount; int m_subSegmentCount; QString m_labelFormat; + bool m_reversed; QFont m_font; QValue3DAxisFormatter *m_formatter; QPointer<QValue3DAxisFormatter> m_ctrlFormatter; diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp index 35b24218..c394ad2f 100644 --- a/src/datavisualization/engine/bars3dcontroller.cpp +++ b/src/datavisualization/engine/bars3dcontroller.cpp @@ -80,6 +80,13 @@ void Bars3DController::synchDataToRenderer() series->d_ptr->m_changeTracker.meshChanged = true; } + // If y range or reverse changed, scene needs to be updated to update camera limits + bool needSceneUpdate = false; + if (Abstract3DController::m_changeTracker.axisYRangeChanged + || Abstract3DController::m_changeTracker.axisYReversedChanged) { + needSceneUpdate = true; + } + Abstract3DController::synchDataToRenderer(); // Notify changes to renderer @@ -110,6 +117,13 @@ void Bars3DController::synchDataToRenderer() m_renderer->updateSelectedBar(m_selectedBar, m_selectedBarSeries); m_changeTracker.selectedBarChanged = false; } + + if (needSceneUpdate) { + // Since scene is updated before axis updates are handled, + // do another render pass for scene update + m_scene->d_ptr->m_sceneDirty = true; + emitNeedRender(); + } } void Bars3DController::handleArrayReset() diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index f93d20b6..a6f893e5 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -75,7 +75,7 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) m_shadowQualityToShader(100.0f), m_shadowQualityMultiplier(3), m_heightNormalizer(1.0f), - m_negativeBackgroundAdjustment(0.0f), + m_backgroundAdjustment(0.0f), m_rowWidth(0), m_columnDepth(0), m_maxDimension(0), @@ -266,6 +266,9 @@ void Bars3DRenderer::updateRenderItem(const QBarDataItem &dataItem, BarRenderIte } else { heightValue -= m_zeroPosition; } + if (m_axisCacheY.reversed()) + heightValue = -heightValue; + renderItem.setValue(value); renderItem.setHeight(heightValue); @@ -387,10 +390,19 @@ void Bars3DRenderer::updateItems(const QVector<Bars3DController::ChangeItem> &it void Bars3DRenderer::updateScene(Q3DScene *scene) { - if (m_hasNegativeValues) + if (!m_noZeroInRange) { scene->activeCamera()->d_ptr->setMinYRotation(-90.0); - else - scene->activeCamera()->d_ptr->setMinYRotation(0.0f); + scene->activeCamera()->d_ptr->setMaxYRotation(90.0); + } else { + if ((m_hasNegativeValues && !m_axisCacheY.reversed()) + || (!m_hasNegativeValues && m_axisCacheY.reversed())) { + scene->activeCamera()->d_ptr->setMinYRotation(-90.0f); + scene->activeCamera()->d_ptr->setMaxYRotation(0.0); + } else { + scene->activeCamera()->d_ptr->setMinYRotation(0.0f); + scene->activeCamera()->d_ptr->setMaxYRotation(90.0); + } + } if (m_resetCameraBaseOrientation) { // Set initial camera position. Also update if height adjustment has changed. @@ -455,7 +467,7 @@ void Bars3DRenderer::drawSlicedScene() bool itemMode = m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionItem); GLfloat barPosYAdjustment = -0.8f; // Translate to -1.0 + 0.2 for row/column labels - GLfloat gridAdjustment = 1.0f + barPosYAdjustment - m_negativeBackgroundAdjustment; + GLfloat gridAdjustment = 1.0f + barPosYAdjustment - m_backgroundAdjustment; GLfloat scaleFactor = 0.0f; if (rowMode) scaleFactor = (1.1f * m_rowWidth) / m_scaleFactor; @@ -463,10 +475,15 @@ void Bars3DRenderer::drawSlicedScene() scaleFactor = (1.1f * m_columnDepth) / m_scaleFactor; GLfloat barLabelYPos = barPosYAdjustment - 0.4f - labelMargin; // 0.4 for labels GLfloat zeroPosAdjustment = 0.0f; - if (!m_noZeroInRange) - zeroPosAdjustment = 2.0f * m_axisCacheY.min() / m_heightNormalizer; - else if (m_hasNegativeValues) - zeroPosAdjustment = -2.0f; + GLfloat directionMultiplier = 2.0f; + GLfloat directionBase = 0.0f; + if (m_axisCacheY.reversed()) { + directionMultiplier = -2.0f; + directionBase = -2.0f; + } + zeroPosAdjustment = directionBase + + directionMultiplier * m_axisCacheY.min() / m_heightNormalizer; + zeroPosAdjustment = qBound(-2.0f, zeroPosAdjustment, 0.0f); // Draw grid lines if (m_cachedTheme->isGridEnabled()) { @@ -624,7 +641,9 @@ void Bars3DRenderer::drawSlicedScene() QQuaternion seriesRotation; foreach (SeriesRenderCache *baseCache, m_renderCacheList) { - if (baseCache->isVisible()) { + if (baseCache->isVisible() + && (baseCache == m_selectedSeriesCache + || m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries))) { BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache); QVector<BarRenderSliceItem> &sliceArray = cache->sliceArray(); int sliceCount = sliceArray.size(); @@ -768,6 +787,7 @@ void Bars3DRenderer::drawSlicedScene() m_dummyBarRenderItem.setTranslation(QVector3D(item.translation().x(), barLabelYPos, item.translation().z())); + // Draw labels m_drawer->drawLabel(m_dummyBarRenderItem, *m_sliceCache->labelItems().at(labelNo), viewMatrix, projectionMatrix, positionComp, sliceLabelRotation, @@ -811,7 +831,7 @@ void Bars3DRenderer::drawSlicedScene() } } } - } else { + } else if (selectedItem) { // Only draw value for selected item when grid labels are on // Create label texture if we need it if (selectedItem->sliceLabel().isNull() || m_updateLabels) { @@ -1468,7 +1488,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 itModelMatrix; QVector3D backgroundScaler(rowScaleFactor, 1.0f, columnScaleFactor); - modelMatrix.translate(0.0f, m_negativeBackgroundAdjustment, 0.0f); + modelMatrix.translate(0.0f, m_backgroundAdjustment, 0.0f); modelMatrix.scale(backgroundScaler); itModelMatrix.scale(backgroundScaler); @@ -1517,44 +1537,42 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) m_drawer->drawObject(m_backgroundShader, m_backgroundObj); } - // Draw floor for graph with negatives - if (m_hasNegativeValues) { - modelMatrix = QMatrix4x4(); - itModelMatrix = QMatrix4x4(); + // Draw floor + modelMatrix = QMatrix4x4(); + itModelMatrix = QMatrix4x4(); - modelMatrix.scale(backgroundScaler); + modelMatrix.scale(backgroundScaler); - if (m_yFlipped) - modelMatrix.rotate(90.0f, 1.0f, 0.0f, 0.0f); - else - modelMatrix.rotate(-90.0f, 1.0f, 0.0f, 0.0f); + if (m_yFlipped) + modelMatrix.rotate(90.0f, 1.0f, 0.0f, 0.0f); + else + modelMatrix.rotate(-90.0f, 1.0f, 0.0f, 0.0f); - itModelMatrix = modelMatrix; + itModelMatrix = modelMatrix; #ifdef SHOW_DEPTH_TEXTURE_SCENE - MVPMatrix = depthProjectionViewMatrix * modelMatrix; + MVPMatrix = depthProjectionViewMatrix * modelMatrix; #else - MVPMatrix = projectionViewMatrix * modelMatrix; + MVPMatrix = projectionViewMatrix * modelMatrix; #endif - // Set changed shader bindings - m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix); - m_backgroundShader->setUniformValue(m_backgroundShader->nModel(), - itModelMatrix.inverted().transposed()); - m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix); + // Set changed shader bindings + m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix); + m_backgroundShader->setUniformValue(m_backgroundShader->nModel(), + itModelMatrix.inverted().transposed()); + m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix); #if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { - // Set shadow shader bindings - QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; - m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix); - // Draw the object - m_drawer->drawObject(m_backgroundShader, m_gridLineObj, 0, m_depthTexture); - } else + if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) { + // Set shadow shader bindings + QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix; + m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix); + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_gridLineObj, 0, m_depthTexture); + } else #endif - { - // Draw the object - m_drawer->drawObject(m_backgroundShader, m_gridLineObj); - } + { + // Draw the object + m_drawer->drawObject(m_backgroundShader, m_gridLineObj); } } @@ -2047,21 +2065,22 @@ void Bars3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orientatio if (orientation == QAbstract3DAxis::AxisOrientationY) { // Check if we have negative values - if (min < 0 && !m_hasNegativeValues) { + if (min < 0) m_hasNegativeValues = true; - // Reload background - loadBackgroundMesh(); - emit needRender(); - } else if (min >= 0 && m_hasNegativeValues) { + else if (min >= 0) m_hasNegativeValues = false; - // Reload background - loadBackgroundMesh(); - emit needRender(); - } calculateHeightAdjustment(); } } +void Bars3DRenderer::updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation, bool enable) +{ + Abstract3DRenderer::updateAxisReversed(orientation, enable); + if (orientation == QAbstract3DAxis::AxisOrientationY) + calculateHeightAdjustment(); +} + + void Bars3DRenderer::updateSelectedBar(const QPoint &position, QBar3DSeries *series) { m_selectedBarPos = position; @@ -2142,10 +2161,7 @@ void Bars3DRenderer::loadBackgroundMesh() { if (m_backgroundObj) delete m_backgroundObj; - if (m_hasNegativeValues) - m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground")); - else - m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background")); + m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground")); m_backgroundObj->load(); } @@ -2216,13 +2232,14 @@ void Bars3DRenderer::calculateHeightAdjustment() m_gradientFraction = qMax(minAbs, maxAbs) / m_heightNormalizer * 2.0f; } - // Calculate translation adjustment for negative background - if (m_hasNegativeValues) - newAdjustment = (qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) - 0.5f) * 2.0f; + // Calculate translation adjustment for background floor + newAdjustment = (qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) - 0.5f) * 2.0f; + if (m_axisCacheY.reversed()) + newAdjustment = -newAdjustment; - if (newAdjustment != m_negativeBackgroundAdjustment) { - m_negativeBackgroundAdjustment = newAdjustment; - m_axisCacheY.setTranslate(m_negativeBackgroundAdjustment - 1.0f); + if (newAdjustment != m_backgroundAdjustment) { + m_backgroundAdjustment = newAdjustment; + m_axisCacheY.setTranslate(m_backgroundAdjustment - 1.0f); } } diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h index 8e39ee11..68848673 100644 --- a/src/datavisualization/engine/bars3drenderer_p.h +++ b/src/datavisualization/engine/bars3drenderer_p.h @@ -86,7 +86,7 @@ private: GLint m_shadowQualityMultiplier; GLfloat m_heightNormalizer; GLfloat m_gradientFraction; - GLfloat m_negativeBackgroundAdjustment; + GLfloat m_backgroundAdjustment; GLfloat m_rowWidth; GLfloat m_columnDepth; GLfloat m_maxDimension; @@ -140,6 +140,8 @@ public slots: // Overloaded from abstract renderer virtual void updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min, float max); + virtual void updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation, + bool enable); private: virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); diff --git a/src/datavisualization/engine/q3dscene.h b/src/datavisualization/engine/q3dscene.h index 39c9791f..1699b125 100644 --- a/src/datavisualization/engine/q3dscene.h +++ b/src/datavisualization/engine/q3dscene.h @@ -95,6 +95,7 @@ private: friend class QAbstract3DGraph; friend class QAbstract3DGraphPrivate; friend class Abstract3DController; + friend class Bars3DController; friend class Q3DScenePrivate; friend class Abstract3DRenderer; friend class Bars3DRenderer; diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 198a034d..56219104 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -747,6 +747,9 @@ void Surface3DRenderer::drawSlicedScene() GLfloat scaleXBackground = 0.0f; + // Disable culling to avoid ugly conditionals with reversed axes and data + glDisable(GL_CULL_FACE); + if (!m_renderCacheList.isEmpty()) { bool drawGrid = false; @@ -825,6 +828,9 @@ void Surface3DRenderer::drawSlicedScene() // Disable textures glDisable(GL_TEXTURE_2D); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + // Grid lines if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { #if !(defined QT_OPENGL_ES_2) diff --git a/tests/barstest/chart.cpp b/tests/barstest/chart.cpp index 9bf21cbd..4e5c8976 100644 --- a/tests/barstest/chart.cpp +++ b/tests/barstest/chart.cpp @@ -1400,6 +1400,11 @@ void GraphModifier::testItemAndRowChanges() counter++; } +void GraphModifier::reverseValueAxis(int enabled) +{ + m_graph->valueAxis()->setReversed(enabled); +} + void GraphModifier::changeValueAxisSegments(int value) { qDebug() << __FUNCTION__ << value; diff --git a/tests/barstest/chart.h b/tests/barstest/chart.h index 385e139c..47d29c25 100644 --- a/tests/barstest/chart.h +++ b/tests/barstest/chart.h @@ -93,6 +93,7 @@ public: void setFpsLabel(QLabel *fpsLabel) { m_fpsLabel = fpsLabel; } void addRemoveSeries(); void testItemAndRowChanges(); + void reverseValueAxis(int enabled); public slots: void flipViews(); diff --git a/tests/barstest/main.cpp b/tests/barstest/main.cpp index 1182ffdf..5ecf63a4 100644 --- a/tests/barstest/main.cpp +++ b/tests/barstest/main.cpp @@ -201,6 +201,10 @@ int main(int argc, char **argv) fpsCheckBox->setText(QStringLiteral("Measure Fps")); fpsCheckBox->setChecked(false); + QCheckBox *reverseValueAxisCheckBox = new QCheckBox(widget); + reverseValueAxisCheckBox->setText(QStringLiteral("Reverse value axis")); + reverseValueAxisCheckBox->setChecked(false); + QCheckBox *backgroundCheckBox = new QCheckBox(widget); backgroundCheckBox->setText(QStringLiteral("Show background")); backgroundCheckBox->setChecked(true); @@ -364,6 +368,7 @@ int main(int argc, char **argv) vLayout2->addWidget(maxSliderY, 0, Qt::AlignTop); vLayout2->addWidget(fpsLabel, 0, Qt::AlignTop); vLayout2->addWidget(fpsCheckBox, 0, Qt::AlignTop); + vLayout2->addWidget(reverseValueAxisCheckBox, 0, Qt::AlignTop); vLayout2->addWidget(backgroundCheckBox, 0, Qt::AlignTop); vLayout2->addWidget(gridCheckBox, 0, Qt::AlignTop); vLayout2->addWidget(new QLabel(QStringLiteral("Adjust shadow quality")), 0, Qt::AlignTop); @@ -477,6 +482,8 @@ int main(int argc, char **argv) QObject::connect(fpsCheckBox, &QCheckBox::stateChanged, modifier, &GraphModifier::setFpsMeasurement); + QObject::connect(reverseValueAxisCheckBox, &QCheckBox::stateChanged, modifier, + &GraphModifier::reverseValueAxis); QObject::connect(backgroundCheckBox, &QCheckBox::stateChanged, modifier, &GraphModifier::setBackgroundEnabled); QObject::connect(gridCheckBox, &QCheckBox::stateChanged, modifier, diff --git a/tests/scattertest/main.cpp b/tests/scattertest/main.cpp index 82d025aa..b0e52c8c 100644 --- a/tests/scattertest/main.cpp +++ b/tests/scattertest/main.cpp @@ -126,6 +126,9 @@ int main(int argc, char **argv) QPushButton *testItemChangesButton = new QPushButton(widget); testItemChangesButton->setText(QStringLiteral("Test Item changing")); + QPushButton *testReverseButton = new QPushButton(widget); + testReverseButton->setText(QStringLiteral("Test Axis Reversing")); + QLinearGradient grBtoY(0, 0, 100, 0); grBtoY.setColorAt(1.0, Qt::black); grBtoY.setColorAt(0.67, Qt::blue); @@ -242,7 +245,8 @@ int main(int argc, char **argv) vLayout->addWidget(changeSeriesNameButton, 0, Qt::AlignTop); vLayout->addWidget(startTimerButton, 0, Qt::AlignTop); vLayout->addWidget(massiveDataTestButton, 0, Qt::AlignTop); - vLayout->addWidget(testItemChangesButton, 1, Qt::AlignTop); + vLayout->addWidget(testItemChangesButton, 0, Qt::AlignTop); + vLayout->addWidget(testReverseButton, 1, Qt::AlignTop); vLayout2->addWidget(gradientBtoYPB, 0, Qt::AlignTop); vLayout2->addWidget(fpsLabel, 0, Qt::AlignTop); @@ -316,6 +320,8 @@ int main(int argc, char **argv) &ScatterDataModifier::massiveDataTest); QObject::connect(testItemChangesButton, &QPushButton::clicked, modifier, &ScatterDataModifier::testItemChanges); + QObject::connect(testReverseButton, &QPushButton::clicked, modifier, + &ScatterDataModifier::testAxisReverse); QObject::connect(gradientBtoYPB, &QPushButton::clicked, modifier, &ScatterDataModifier::setGradient); QObject::connect(themeButton, &QPushButton::clicked, modifier, diff --git a/tests/scattertest/scatterchart.cpp b/tests/scattertest/scatterchart.cpp index 13a0f040..430279c3 100644 --- a/tests/scattertest/scatterchart.cpp +++ b/tests/scattertest/scatterchart.cpp @@ -411,6 +411,70 @@ void ScatterDataModifier::testItemChanges() counter++; } +void ScatterDataModifier::testAxisReverse() +{ + static int counter = 0; + const int rowCount = 16; + const int colCount = 16; + static QScatter3DSeries *series0 = 0; + static QScatter3DSeries *series1 = 0; + + switch (counter) { + case 0: { + qDebug() << __FUNCTION__ << counter << "Setup test"; + foreach (QScatter3DSeries *series, m_chart->seriesList()) + m_chart->removeSeries(series); + foreach (QValue3DAxis *axis, m_chart->axes()) + m_chart->releaseAxis(axis); + delete series0; + delete series1; + series0 = new QScatter3DSeries; + series1 = new QScatter3DSeries; + populateRisingSeries(series0, rowCount, colCount, 0.0f, 50.0f); + populateRisingSeries(series1, rowCount, colCount, -20.0f, 30.0f); + m_chart->axisX()->setRange(0.0f, 10.0f); + m_chart->axisY()->setRange(-20.0f, 50.0f); + m_chart->axisZ()->setRange(5.0f, 15.0f); + m_chart->addSeries(series0); + m_chart->addSeries(series1); + } + break; + case 1: { + qDebug() << __FUNCTION__ << counter << "Reverse X axis"; + m_chart->axisX()->setReversed(true); + } + break; + case 2: { + qDebug() << __FUNCTION__ << counter << "Reverse Y axis"; + m_chart->axisY()->setReversed(true); + } + break; + case 3: { + qDebug() << __FUNCTION__ << counter << "Reverse Z axis"; + m_chart->axisZ()->setReversed(true); + } + break; + case 4: { + qDebug() << __FUNCTION__ << counter << "Return all axes to normal"; + m_chart->axisX()->setReversed(false); + m_chart->axisY()->setReversed(false); + m_chart->axisZ()->setReversed(false); + } + break; + case 5: { + qDebug() << __FUNCTION__ << counter << "Reverse all axes"; + m_chart->axisX()->setReversed(true); + m_chart->axisY()->setReversed(true); + m_chart->axisZ()->setReversed(true); + } + break; + default: + qDebug() << __FUNCTION__ << "Resetting test"; + counter = -1; + } + counter++; +} + void ScatterDataModifier::addData() { // Add labels @@ -950,3 +1014,19 @@ void ScatterDataModifier::populateFlatSeries(QScatter3DSeries *series, int rows, } series->dataProxy()->resetArray(dataArray); } + +void ScatterDataModifier::populateRisingSeries(QScatter3DSeries *series, int rows, int columns, + float minValue, float maxValue) +{ + QScatterDataArray *dataArray = new QScatterDataArray; + int arraySize = rows * columns; + dataArray->resize(arraySize); + float range = maxValue - minValue; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + float yValue = minValue + (range * i * j / arraySize); + (*dataArray)[i * columns + j].setPosition(QVector3D(float(i), yValue, float(j))); + } + } + series->dataProxy()->resetArray(dataArray); +} diff --git a/tests/scattertest/scatterchart.h b/tests/scattertest/scatterchart.h index f239cb73..977e1201 100644 --- a/tests/scattertest/scatterchart.h +++ b/tests/scattertest/scatterchart.h @@ -59,6 +59,7 @@ public: void setFpsMeasurement(bool enable); void setFpsLabel(QLabel *fpsLabel) { m_fpsLabel = fpsLabel; } void testItemChanges(); + void testAxisReverse(); public slots: void changeShadowQuality(int quality); @@ -96,6 +97,8 @@ private: QVector3D randVector(); QScatter3DSeries *createAndAddSeries(); void populateFlatSeries(QScatter3DSeries *series, int rows, int columns, float value); + void populateRisingSeries(QScatter3DSeries *series, int rows, int columns, float minValue, + float maxValue); Q3DScatter *m_chart; int m_fontSize; diff --git a/tests/surfacetest/graphmodifier.cpp b/tests/surfacetest/graphmodifier.cpp index 0f3aa985..6dd20de7 100644 --- a/tests/surfacetest/graphmodifier.cpp +++ b/tests/surfacetest/graphmodifier.cpp @@ -781,6 +781,25 @@ QSurfaceDataRow *GraphModifier::createMultiRow(int row, int series, bool change) return newRow; } +void GraphModifier::populateRisingSeries(QSurface3DSeries *series, int rows, int columns, + float minValue, float maxValue) +{ + QSurfaceDataArray *dataArray = new QSurfaceDataArray; + dataArray->reserve(rows); + float range = maxValue - minValue; + int arraySize = rows * columns; + for (int i = 0; i < rows; i++) { + QSurfaceDataRow *dataRow = new QSurfaceDataRow(columns); + for (int j = 0; j < columns; j++) { + float yValue = minValue + (range * i * j / arraySize); + (*dataRow)[j].setPosition(QVector3D(float(j), yValue, float(i))); + } + dataArray->append(dataRow); + } + series->dataProxy()->resetArray(dataArray); + +} + void GraphModifier::changeRows() { if (m_activeSample == GraphModifier::SqrtSin) { @@ -1278,6 +1297,70 @@ void GraphModifier::massiveTestAppendAndScroll() m_graph->axisZ()->setRange(min, max); } +void GraphModifier::testAxisReverse() +{ + static int counter = 0; + const int rowCount = 16; + const int colCount = 16; + static QSurface3DSeries *series0 = 0; + static QSurface3DSeries *series1 = 0; + + switch (counter) { + case 0: { + qDebug() << __FUNCTION__ << counter << "Setup test"; + foreach (QSurface3DSeries *series, m_graph->seriesList()) + m_graph->removeSeries(series); + foreach (QValue3DAxis *axis, m_graph->axes()) + m_graph->releaseAxis(axis); + delete series0; + delete series1; + series0 = new QSurface3DSeries; + series1 = new QSurface3DSeries; + populateRisingSeries(series0, rowCount, colCount, 0.0f, 50.0f); + populateRisingSeries(series1, rowCount, colCount, -20.0f, 30.0f); + m_graph->axisX()->setRange(0.0f, 10.0f); + m_graph->axisY()->setRange(-20.0f, 50.0f); + m_graph->axisZ()->setRange(5.0f, 15.0f); + m_graph->addSeries(series0); + m_graph->addSeries(series1); + } + break; + case 1: { + qDebug() << __FUNCTION__ << counter << "Reverse X axis"; + m_graph->axisX()->setReversed(true); + } + break; + case 2: { + qDebug() << __FUNCTION__ << counter << "Reverse Y axis"; + m_graph->axisY()->setReversed(true); + } + break; + case 3: { + qDebug() << __FUNCTION__ << counter << "Reverse Z axis"; + m_graph->axisZ()->setReversed(true); + } + break; + case 4: { + qDebug() << __FUNCTION__ << counter << "Return all axes to normal"; + m_graph->axisX()->setReversed(false); + m_graph->axisY()->setReversed(false); + m_graph->axisZ()->setReversed(false); + } + break; + case 5: { + qDebug() << __FUNCTION__ << counter << "Reverse all axes"; + m_graph->axisX()->setReversed(true); + m_graph->axisY()->setReversed(true); + m_graph->axisZ()->setReversed(true); + } + break; + default: + qDebug() << __FUNCTION__ << "Resetting test"; + counter = -1; + } + counter++; +} + void GraphModifier::changeMesh() { static int model = 0; diff --git a/tests/surfacetest/graphmodifier.h b/tests/surfacetest/graphmodifier.h index f79055df..f3e95a1b 100644 --- a/tests/surfacetest/graphmodifier.h +++ b/tests/surfacetest/graphmodifier.h @@ -110,6 +110,7 @@ public: void massiveDataTest(); void massiveTestScroll(); void massiveTestAppendAndScroll(); + void testAxisReverse(); public slots: void changeShadowQuality(int quality); @@ -128,6 +129,8 @@ private: void resetArrayAndSliders(QSurfaceDataArray *array, float minZ, float maxZ, float minX, float maxX); QSurfaceDataRow *createMultiRow(int row, int series, bool change); + void populateRisingSeries(QSurface3DSeries *series, int rows, int columns, float minValue, + float maxValue); Q3DSurface *m_graph; QSurface3DSeries *m_multiseries[4]; diff --git a/tests/surfacetest/main.cpp b/tests/surfacetest/main.cpp index aa300207..8371e2cf 100644 --- a/tests/surfacetest/main.cpp +++ b/tests/surfacetest/main.cpp @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) surfaceGraph->activeTheme()->setType(Q3DTheme::Theme(initialTheme)); QWidget *container = QWidget::createWindowContainer(surfaceGraph); - container->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 2)); + container->setMinimumSize(QSize(screenSize.width() / 4, screenSize.height() / 4)); container->setMaximumSize(screenSize); container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); container->setFocusPolicy(Qt::StrongFocus); @@ -347,6 +347,9 @@ int main(int argc, char *argv[]) QPushButton *massiveDataTestButton = new QPushButton(widget); massiveDataTestButton->setText(QStringLiteral("Massive data test")); + QPushButton *testReverseButton = new QPushButton(widget); + testReverseButton->setText(QStringLiteral("Test Axis Reversing")); + QFrame* line = new QFrame(); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); @@ -435,6 +438,7 @@ int main(int argc, char *argv[]) vLayout2->addWidget(resetArrayButton); vLayout2->addWidget(resetArrayEmptyButton); vLayout2->addWidget(massiveDataTestButton); + vLayout2->addWidget(testReverseButton); widget->show(); @@ -592,6 +596,8 @@ int main(int argc, char *argv[]) modifier, &GraphModifier::resetArrayEmpty); QObject::connect(massiveDataTestButton,&QPushButton::clicked, modifier, &GraphModifier::massiveDataTest); + QObject::connect(testReverseButton, &QPushButton::clicked, + modifier, &GraphModifier::testAxisReverse); #ifdef MULTI_SERIES modifier->setSeries1CB(series1CB); |