From 724bcb35136ed1af699fe8631b9297deb07571ad Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 18 Mar 2014 15:33:00 +0200 Subject: Actually use axis formatter in renderer. Task-number: QTRD-2787 Change-Id: I0ced8e506928df5fba2e8df94258b53457f4412e Reviewed-by: Mika Salmela --- src/datavisualization/axis/qabstract3daxis.cpp | 6 +- src/datavisualization/axis/qvalue3daxis.cpp | 3 +- src/datavisualization/axis/qvalue3daxis.h | 3 +- src/datavisualization/axis/qvalue3daxis_p.h | 1 + .../axis/qvalue3daxisformatter.cpp | 243 +++++--------- src/datavisualization/axis/qvalue3daxisformatter.h | 38 +-- .../axis/qvalue3daxisformatter_p.h | 4 +- .../engine/abstract3dcontroller.cpp | 13 +- .../engine/abstract3drenderer.cpp | 22 +- .../engine/abstract3drenderer_p.h | 2 +- src/datavisualization/engine/axisrendercache.cpp | 74 ++--- src/datavisualization/engine/axisrendercache_p.h | 43 ++- src/datavisualization/engine/bars3drenderer.cpp | 131 ++++---- src/datavisualization/engine/bars3drenderer_p.h | 2 +- .../engine/meshes/backgroundNegatives.obj | 6 +- src/datavisualization/engine/scatter3drenderer.cpp | 274 +++++++--------- src/datavisualization/engine/surface3drenderer.cpp | 359 ++++++++------------- src/datavisualization/engine/surface3drenderer_p.h | 8 +- .../engine/surfaceseriesrendercache.cpp | 8 +- .../engine/surfaceseriesrendercache_p.h | 9 +- src/datavisualization/utils/surfaceobject.cpp | 133 ++++---- src/datavisualization/utils/surfaceobject_p.h | 29 +- tests/barstest/chart.cpp | 9 +- tests/barstest/chart.h | 1 + tests/barstest/main.cpp | 9 +- tests/scattertest/main.cpp | 80 ++++- tests/scattertest/scatterchart.cpp | 53 ++- tests/scattertest/scatterchart.h | 6 + tests/surfacetest/graphmodifier.cpp | 44 ++- tests/surfacetest/graphmodifier.h | 4 + tests/surfacetest/main.cpp | 30 +- 31 files changed, 786 insertions(+), 861 deletions(-) diff --git a/src/datavisualization/axis/qabstract3daxis.cpp b/src/datavisualization/axis/qabstract3daxis.cpp index e01f980c..3b60ff5d 100644 --- a/src/datavisualization/axis/qabstract3daxis.cpp +++ b/src/datavisualization/axis/qabstract3daxis.cpp @@ -407,11 +407,11 @@ void QAbstract3DAxisPrivate::setMax(float max) float oldMin = m_min; m_min = max - 1.0f; if (!allowNegatives() && m_min < 0.0f) { - if (allowZero()) { + if (allowZero()) m_min = 0.0f; - } else { + else m_min = max / 2.0f; // Need some positive value smaller than max - } + if (!allowMinMaxSame() && max == 0.0f) { m_min = oldMin; qWarning() << "Unable to set maximum value to zero."; diff --git a/src/datavisualization/axis/qvalue3daxis.cpp b/src/datavisualization/axis/qvalue3daxis.cpp index e93f440f..841349dd 100644 --- a/src/datavisualization/axis/qvalue3daxis.cpp +++ b/src/datavisualization/axis/qvalue3daxis.cpp @@ -269,8 +269,9 @@ void QValue3DAxisPrivate::updateLabels() QStringList newLabels; newLabels.reserve(m_segmentCount + 1); + m_formatter->d_ptr->recalculate(); for (int i = 0; i <= m_segmentCount; i++) { - float value = m_formatter->valueAt(m_formatter->gridPosition(i)); + float value = m_formatter->valueAt(m_formatter->gridPositions().at(i)); newLabels.append(m_formatter->stringForValue(value, m_labelFormat)); } diff --git a/src/datavisualization/axis/qvalue3daxis.h b/src/datavisualization/axis/qvalue3daxis.h index c5982f33..bb90f6d3 100644 --- a/src/datavisualization/axis/qvalue3daxis.h +++ b/src/datavisualization/axis/qvalue3daxis.h @@ -62,10 +62,11 @@ protected: private: Q_DISABLE_COPY(QValue3DAxis) + friend class Abstract3DController; friend class Bars3DController; friend class Scatter3DController; friend class Surface3DController; - friend class QValue3DAxisFormatter; + friend class QValue3DAxisFormatterPrivate; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/axis/qvalue3daxis_p.h b/src/datavisualization/axis/qvalue3daxis_p.h index c198db75..ff281f0c 100644 --- a/src/datavisualization/axis/qvalue3daxis_p.h +++ b/src/datavisualization/axis/qvalue3daxis_p.h @@ -67,6 +67,7 @@ private: QValue3DAxis *qptr(); friend class QValue3DAxis; + friend class Abstract3DController; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/axis/qvalue3daxisformatter.cpp b/src/datavisualization/axis/qvalue3daxisformatter.cpp index 5f943bd3..c8e0a662 100644 --- a/src/datavisualization/axis/qvalue3daxisformatter.cpp +++ b/src/datavisualization/axis/qvalue3daxisformatter.cpp @@ -30,19 +30,23 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * This class provides formatting rules for a linear QValue3DAxis. Subclass it if you * want to implement custom value axes. * + * The base class has no public API beyond constructors and destructors. It is meant to be only + * used internally. However, subclasses may implement public properties as needed. + * * \sa QLog3DAxisFormatter */ /*! * \qmltype ValueAxis3DFormatter * \inqmlmodule QtDataVisualization - * \since QtDataVisualization 1.0 + * \since QtDataVisualization 1.1 * \ingroup datavisualization_qml * \instantiates QValue3DAxisFormatter * \brief ValueAxis3DFormatter is base type for value axis formatters. * * This type provides formatting rules for a linear ValueAxis3D. * This type is the default type for ValueAxis3D and thus never needs to be explicitly created. + * This type has not public functionality. */ /*! @@ -88,148 +92,17 @@ bool QValue3DAxisFormatter::allowZero() const return true; } -/*! - * \return the normalized position along the axis for the grid line indicated by the \a index. - * The total amount of grid lines is equal to segment count plus one. The returned value should be - * between -1.0 (for minimum value) and 1.0 (for maximum value), inclusive. - * The grid line at the index zero corresponds to the minimum value of the axis. - * This value is used to position the segment grid lines when the graph is rendered. - * - * \sa doRecalculate(), gridPositions() - */ -float QValue3DAxisFormatter::gridPosition(int index) -{ - d_ptr->recalculate(); - - Q_ASSERT(d_ptr->m_gridPositions.size() > index); - - return d_ptr->m_gridPositions.at(index); -} - -/*! - * \return the normalized position along the axis for a subsegment grid line of a segment. - * The \a subGridIndex and \a segmentIndex specify the desired subgrid line. - * The returned value should be between -1.0 (for minimum value) and 1.0 (for maximum value), - * inclusive. - * The amount of subgrid lines per segment is equal to subsegment count minus one. - * This value is used to position the subsegment grid lines when the graph is rendered. - * - * \sa doRecalculate(), subGridPositions() - */ -float QValue3DAxisFormatter::subGridPosition(int subGridIndex, int segmentIndex) -{ - d_ptr->recalculate(); - - Q_ASSERT(d_ptr->m_subGridPositions.size() > subGridIndex); - Q_ASSERT(d_ptr->m_subGridPositions.at(0).size() > segmentIndex); - - return d_ptr->m_subGridPositions.at(segmentIndex).at(subGridIndex); -} - -/*! - * \return the normalized position along the axis for given label \a index. - * The total amount of labels is equal to segment count plus one. The label \a index zero - * corresponds to the minimum value of the axis. - * The returned value should be between -1.0 (for minimum value) and 1.0 (for maximum value), - * inclusive. This value is used to position the axis labels when the graph is rendered. - * - * \sa doRecalculate(), labelPositions() - */ -float QValue3DAxisFormatter::labelPosition(int index) -{ - d_ptr->recalculate(); - - Q_ASSERT(d_ptr->m_labelPositions.size() > index); - - return d_ptr->m_labelPositions.at(index); -} - -/*! - * This method can be used to convert a value to a string using formatter specific formatting - * rules supported by the labelFormat property of the parent axis. - * - * \return the formatted label string using \a value and \a format. - * - * \sa doRecalculate(), doStringForValue(), QValue3DAxis::labelFormat - */ -QString QValue3DAxisFormatter::stringForValue(float value, const QString &format) -{ - d_ptr->recalculate(); - return doStringForValue(value, format); -} - -/*! - * \return the normalized position along the axis for the given \a value. - * The returned value should be between -1.0 (for minimum value) and 1.0 (for maximum value), - * inclusive. This value is used to position the items when the graph is rendered. - * - * \sa doRecalculate(), doPositionAt() - */ -float QValue3DAxisFormatter::positionAt(float value) -{ - d_ptr->recalculate(); - return doPositionAt(value); -} - -/*! - * \return the value at the normalized \a position along the axis. - * The \a position value should be between -1.0 (for minimum value) and 1.0 (for maximum value), - * inclusive. - * - * \sa doRecalculate(), doValueAt() - */ -float QValue3DAxisFormatter::valueAt(float position) -{ - d_ptr->recalculate(); - return doValueAt(position); -} - /*! * Creates a new empty instance of this formatter. Must be reimplemented in a subclass. * * \return the new instance. The renderer uses this method to cache a copy of the * the formatter. The ownership of the new copy transfers to the caller. */ -QValue3DAxisFormatter *QValue3DAxisFormatter::createNewInstance() +QValue3DAxisFormatter *QValue3DAxisFormatter::createNewInstance() const { return new QValue3DAxisFormatter(); } -/*! - * Populates the \a copy with the values of this formatter. - * - * \sa doPopulateCopy() - */ -void QValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter ©) -{ - d_ptr->recalculate(); - doPopulateCopy(copy); -} - -/*! - * Marks this formatter dirty, prompting the renderer to make a new copy of its cache on the next - * renderer synchronization. Recalculation is also triggered on next access to the values. - * This method should be called by a subclass whenever the formatter - * is changed in a way that affects the resolved values. - */ -void QValue3DAxisFormatter::markDirty() -{ - d_ptr->m_needsRecalculate = true; - if (d_ptr->m_axis) - emit d_ptr->m_axis->dptr()->formatterDirty(); -} - -/*! - * \return the parent axis. The parent axis must only be accessed in doRecalculate() - * method to maintain thread safety in environments using a threaded renderer. - * - * \sa doRecalculate() - */ -QValue3DAxis *QValue3DAxisFormatter::axis() const -{ - return d_ptr->m_axis; -} - /*! * This method populates the label and grid line position arrays, as well as calculates * any values needed for mapping between value and position. It is allowed to access @@ -237,9 +110,12 @@ QValue3DAxis *QValue3DAxisFormatter::axis() const * * This method must be reimplemented in a subclass. * + * See gridPositions(), subGridPositions(), and labelPositions() documentation about the arrays + * that need to be populated. + * * \sa gridPositions(), subGridPositions(), labelPositions(), axis() */ -void QValue3DAxisFormatter::doRecalculate() +void QValue3DAxisFormatter::recalculate() { d_ptr->doRecalculate(); } @@ -250,9 +126,9 @@ void QValue3DAxisFormatter::doRecalculate() * * \return the formatted label string using \a value and \a format. * - * \sa doRecalculate(), stringForValue(), QValue3DAxis::labelFormat + * \sa recalculate(), stringForValue(), QValue3DAxis::labelFormat */ -QString QValue3DAxisFormatter::doStringForValue(float value, const QString &format) +QString QValue3DAxisFormatter::stringForValue(float value, const QString &format) const { return d_ptr->stringForValue(value, format); } @@ -262,12 +138,12 @@ QString QValue3DAxisFormatter::doStringForValue(float value, const QString &form * between the parent axis minimum and maximum values. * * \return the normalized position along the axis for the given \a value. - * The returned value should be between -1.0 (for minimum value) and 1.0 (for maximum value), + * The returned value should be between 0.0 (for minimum value) and 1.0 (for maximum value), * inclusive, if the value is within the parent axis range. * * \sa doRecalculate(), positionAt() */ -float QValue3DAxisFormatter::doPositionAt(float value) +float QValue3DAxisFormatter::positionAt(float value) const { return d_ptr->positionAt(value); } @@ -277,12 +153,12 @@ float QValue3DAxisFormatter::doPositionAt(float value) * between the parent axis minimum and maximum values. * * \return the value at the normalized \a position along the axis. - * The \a position value should be between -1.0 (for minimum value) and 1.0 (for maximum value), + * The \a position value should be between 0.0 (for minimum value) and 1.0 (for maximum value), * inclusive to obtain values within the parent axis range. * * \sa doRecalculate(), positionAt() */ -float QValue3DAxisFormatter::doValueAt(float position) +float QValue3DAxisFormatter::valueAt(float position) const { return d_ptr->valueAt(position); } @@ -294,31 +170,50 @@ float QValue3DAxisFormatter::doValueAt(float position) * * \return the new copy. The ownership of the new copy transfers to the caller. */ -void QValue3DAxisFormatter::doPopulateCopy(QValue3DAxisFormatter ©) +void QValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter ©) const +{ + d_ptr->doPopulateCopy(*(copy.d_ptr.data())); +} + +/*! + * Marks this formatter dirty, prompting the renderer to make a new copy of its cache on the next + * renderer synchronization. This method should be called by a subclass whenever the formatter + * is changed in a way that affects the resolved values. + */ +void QValue3DAxisFormatter::markDirty() { - copy.d_ptr->m_min = d_ptr->m_min; - copy.d_ptr->m_max = d_ptr->m_max; + d_ptr->markDirty(); +} + +/*! + * \return the parent axis. The parent axis must only be accessed in recalculate() + * method to maintain thread safety in environments using a threaded renderer. + * + * \sa recalculate() + */ +QValue3DAxis *QValue3DAxisFormatter::axis() const +{ + return d_ptr->m_axis; } /*! * \return Returns a reference to the array of normalized grid positions. * The array size is equal to the segment count of the parent axis plus one. + * The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive. * The grid line at the index zero corresponds to the minimum value of the axis. - * - * \sa gridPosition() */ -QVector &QValue3DAxisFormatter::gridPositions() +QVector &QValue3DAxisFormatter::gridPositions() const { return d_ptr->m_gridPositions; } /*! * \return Returns a reference to the array of normalized subgrid positions. - * The array size is equal to subsegment count of the parent axis minus one. - * - * \sa subGridPosition() + * The array size is equal to segment count of tha parent axis times subsegment count of the parent + * axis minus one. + * The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive. */ -QVector > &QValue3DAxisFormatter::subGridPositions() +QVector > &QValue3DAxisFormatter::subGridPositions() const { return d_ptr->m_subGridPositions; } @@ -326,10 +221,10 @@ QVector > &QValue3DAxisFormatter::subGridPositions() /*! * \return Returns a reference to the array of normalized label positions. * The array size is equal to the segment count of the parent axis plus one. - * - * \sa labelPosition() + * The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive. + * The label at the index zero corresponds to the minimum value of the axis. */ -QVector &QValue3DAxisFormatter::labelPositions() +QVector &QValue3DAxisFormatter::labelPositions() const { return d_ptr->m_labelPositions; } @@ -356,7 +251,7 @@ void QValue3DAxisFormatterPrivate::recalculate() // Only recalculate if we need to and have m_axis pointer. If we do not have // m_axis, either we are not attached to an axis or this is a renderer cache. if (m_axis && m_needsRecalculate) - q_ptr->doRecalculate(); + q_ptr->recalculate(); } void QValue3DAxisFormatterPrivate::doRecalculate() @@ -371,12 +266,13 @@ void QValue3DAxisFormatterPrivate::doRecalculate() int subGridCount = m_axis->subSegmentCount() - 1; m_min = m_axis->min(); m_max = m_axis->max(); - m_rangeNormalizer = (m_max - m_min) / 2.0f; + m_rangeNormalizer = (m_max - m_min); m_gridPositions.resize(segmentCount + 1); - float segmentStep = 2.0f / float(segmentCount); + float segmentStep = 1.0f / float(segmentCount); float subSegmentStep = 0; + if (subGridCount > 0) { subSegmentStep = segmentStep / (subGridCount + 1); m_subGridPositions.resize(segmentCount); @@ -389,12 +285,12 @@ void QValue3DAxisFormatterPrivate::doRecalculate() // Calculate positions for (int i = 0; i < segmentCount; i++) { - float gridValue = -1.0f + segmentStep * i; + float gridValue = segmentStep * i; m_gridPositions[i] = gridValue; m_labelPositions[i] = gridValue; if (m_subGridPositions.size()) { for (int j = 0; j < subGridCount; j++) - m_subGridPositions[i][j] = gridValue + subSegmentStep * i; + m_subGridPositions[i][j] = gridValue + subSegmentStep * (j + 1); } } @@ -403,6 +299,23 @@ void QValue3DAxisFormatterPrivate::doRecalculate() m_labelPositions[segmentCount] = 1.0f; } +void QValue3DAxisFormatterPrivate::populateCopy(QValue3DAxisFormatter ©) +{ + recalculate(); + q_ptr->populateCopy(copy); +} + +void QValue3DAxisFormatterPrivate::doPopulateCopy(QValue3DAxisFormatterPrivate ©) +{ + copy.m_min = m_min; + copy.m_max = m_max; + copy.m_rangeNormalizer = m_rangeNormalizer; + + copy.m_gridPositions = m_gridPositions; + copy.m_labelPositions = m_labelPositions; + copy.m_subGridPositions = m_subGridPositions; +} + QString QValue3DAxisFormatterPrivate::stringForValue(float value, const QString &format) { if (m_previousLabelFormat.compare(format)) { @@ -417,12 +330,12 @@ QString QValue3DAxisFormatterPrivate::stringForValue(float value, const QString float QValue3DAxisFormatterPrivate::positionAt(float value) const { - return (((value - m_min) / m_rangeNormalizer) - 1.0f); + return ((value - m_min) / m_rangeNormalizer); } float QValue3DAxisFormatterPrivate::valueAt(float position) const { - return (((position + 1.0f) * m_rangeNormalizer) + m_min); + return ((position * m_rangeNormalizer) + m_min); } void QValue3DAxisFormatterPrivate::setAxis(QValue3DAxis *axis) @@ -430,18 +343,20 @@ void QValue3DAxisFormatterPrivate::setAxis(QValue3DAxis *axis) Q_ASSERT(axis); connect(axis, &QValue3DAxis::segmentCountChanged, - this, &QValue3DAxisFormatterPrivate::setNeedsRecalculate); + this, &QValue3DAxisFormatterPrivate::markDirty); connect(axis, &QValue3DAxis::subSegmentCountChanged, - this, &QValue3DAxisFormatterPrivate::setNeedsRecalculate); + this, &QValue3DAxisFormatterPrivate::markDirty); connect(axis, &QAbstract3DAxis::rangeChanged, - this, &QValue3DAxisFormatterPrivate::setNeedsRecalculate); + this, &QValue3DAxisFormatterPrivate::markDirty); m_axis = axis; } -void QValue3DAxisFormatterPrivate::setNeedsRecalculate() +void QValue3DAxisFormatterPrivate::markDirty() { m_needsRecalculate = true; + if (m_axis && m_axis->orientation() != QAbstract3DAxis::AxisOrientationNone) + emit m_axis->dptr()->formatterDirty(); } QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/axis/qvalue3daxisformatter.h b/src/datavisualization/axis/qvalue3daxisformatter.h index a67b6094..14ecdc15 100644 --- a/src/datavisualization/axis/qvalue3daxisformatter.h +++ b/src/datavisualization/axis/qvalue3daxisformatter.h @@ -38,33 +38,22 @@ public: explicit QValue3DAxisFormatter(QObject *parent = 0); virtual ~QValue3DAxisFormatter(); +protected: virtual bool allowNegatives() const; virtual bool allowZero() const; + virtual QValue3DAxisFormatter *createNewInstance() const; + virtual void recalculate(); + virtual QString stringForValue(float value, const QString &format) const; + virtual float positionAt(float value) const; + virtual float valueAt(float position) const; + virtual void populateCopy(QValue3DAxisFormatter ©) const; - // Getters not const as they can trigger recalculate - float gridPosition(int index); - float subGridPosition(int subGridIndex, int segmentIndex); - float labelPosition(int index); - QString stringForValue(float value, const QString &format); - float positionAt(float value); - float valueAt(float position); - - virtual QValue3DAxisFormatter *createNewInstance(); - void populateCopy(QValue3DAxisFormatter ©); - -protected: void markDirty(); QValue3DAxis *axis() const; - virtual void doRecalculate(); - virtual QString doStringForValue(float value, const QString &format); - virtual float doPositionAt(float value); - virtual float doValueAt(float position); - virtual void doPopulateCopy(QValue3DAxisFormatter ©); - - QVector &gridPositions(); - QVector > &subGridPositions(); - QVector &labelPositions(); + QVector &gridPositions() const; + QVector > &subGridPositions() const; + QVector &labelPositions() const; QScopedPointer d_ptr; @@ -72,8 +61,15 @@ private: Q_DISABLE_COPY(QValue3DAxisFormatter) friend class Abstract3DController; + friend class Abstract3DRenderer; + friend class Bars3DRenderer; + friend class Scatter3DRenderer; + friend class Surface3DRenderer; + friend class SurfaceObject; friend class QValue3DAxisFormatterPrivate; friend class QValue3DAxis; + friend class QValue3DAxisPrivate; + friend class AxisRenderCache; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/axis/qvalue3daxisformatter_p.h b/src/datavisualization/axis/qvalue3daxisformatter_p.h index 90b0f49e..d9f90934 100644 --- a/src/datavisualization/axis/qvalue3daxisformatter_p.h +++ b/src/datavisualization/axis/qvalue3daxisformatter_p.h @@ -48,6 +48,8 @@ public: void recalculate(); void doRecalculate(); + void populateCopy(QValue3DAxisFormatter ©); + void doPopulateCopy(QValue3DAxisFormatterPrivate ©); QString stringForValue(float value, const QString &format); float positionAt(float value) const; @@ -56,7 +58,7 @@ public: void setAxis(QValue3DAxis *axis); public slots: - void setNeedsRecalculate(); + void markDirty(); protected: QValue3DAxisFormatter *q_ptr; diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp index 2a8564a0..8ae9f790 100644 --- a/src/datavisualization/engine/abstract3dcontroller.cpp +++ b/src/datavisualization/engine/abstract3dcontroller.cpp @@ -19,7 +19,7 @@ #include "abstract3dcontroller_p.h" #include "camerahelper_p.h" #include "qabstract3daxis_p.h" -#include "qvalue3daxis.h" +#include "qvalue3daxis_p.h" #include "qcategory3daxis.h" #include "abstract3drenderer_p.h" #include "q3dcamera.h" @@ -967,13 +967,15 @@ void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender) void Abstract3DController::handleAxisFormatterDirtyBySender(QObject *sender) { - if (sender == m_axisX) { + // Sender is QValue3DAxisPrivate + QValue3DAxis *valueAxis = static_cast(sender)->qptr(); + if (valueAxis == m_axisX) { m_isDataDirty = true; m_changeTracker.axisXFormatterChanged = true; - } else if (sender == m_axisY) { + } else if (valueAxis == m_axisY) { m_isDataDirty = true; m_changeTracker.axisYFormatterChanged = true; - } else if (sender == m_axisZ) { + } else if (valueAxis == m_axisZ) { m_isDataDirty = true; m_changeTracker.axisZFormatterChanged = true; } else { @@ -1050,10 +1052,13 @@ void Abstract3DController::setAxisHelper(QAbstract3DAxis::AxisOrientation orient this, &Abstract3DController::handleAxisSubSegmentCountChanged); QObject::connect(valueAxis, &QValue3DAxis::labelFormatChanged, this, &Abstract3DController::handleAxisLabelFormatChanged); + QObject::connect(valueAxis->dptr(), &QValue3DAxisPrivate::formatterDirty, + this, &Abstract3DController::handleAxisFormatterDirty); handleAxisSegmentCountChangedBySender(valueAxis); handleAxisSubSegmentCountChangedBySender(valueAxis); handleAxisLabelFormatChangedBySender(valueAxis); + handleAxisFormatterDirtyBySender(valueAxis->dptr()); } } diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 48453a82..c5e265aa 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -138,13 +138,13 @@ void Abstract3DRenderer::render(const GLuint defaultFboHandle) glDisable(GL_SCISSOR_TEST); } -QString Abstract3DRenderer::generateValueLabel(const QString &format, float value) -{ - QString valueLabelFormat = format; - Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat); - QByteArray valueFormatArray = valueLabelFormat.toUtf8(); - return Utils::formatLabel(valueFormatArray, valueParamType, value); -} +//QString Abstract3DRenderer::generateValueLabel(const QString &format, float value) +//{ +// QString valueLabelFormat = format; +// Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat); +// QByteArray valueFormatArray = valueLabelFormat.toUtf8(); +// return Utils::formatLabel(valueFormatArray, valueParamType, value); +//} void Abstract3DRenderer::updateSelectionState(SelectionState state) { @@ -318,13 +318,15 @@ void Abstract3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orient void Abstract3DRenderer::updateAxisSegmentCount(QAbstract3DAxis::AxisOrientation orientation, int count) { - axisCacheForOrientation(orientation).setSegmentCount(count); + AxisRenderCache &cache = axisCacheForOrientation(orientation); + cache.setSegmentCount(count); } void Abstract3DRenderer::updateAxisSubSegmentCount(QAbstract3DAxis::AxisOrientation orientation, int count) { - axisCacheForOrientation(orientation).setSubSegmentCount(count); + AxisRenderCache &cache = axisCacheForOrientation(orientation); + cache.setSubSegmentCount(count); } void Abstract3DRenderer::updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation orientation, @@ -342,7 +344,7 @@ void Abstract3DRenderer::updateAxisFormatter(QAbstract3DAxis::AxisOrientation or cache.setFormatter(formatter->createNewInstance()); cache.setCtrlFormatter(formatter); } - formatter->populateCopy(*(cache.formatter())); + formatter->d_ptr->populateCopy(*(cache.formatter())); } void Abstract3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh mesh) diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h index b198f004..f6415cca 100644 --- a/src/datavisualization/engine/abstract3drenderer_p.h +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -60,7 +60,7 @@ protected: SelectOnSlice }; - QString generateValueLabel(const QString &format, float value); +// QString generateValueLabel(const QString &format, float value); public: virtual ~Abstract3DRenderer(); diff --git a/src/datavisualization/engine/axisrendercache.cpp b/src/datavisualization/engine/axisrendercache.cpp index bc0ab703..1b4fd52d 100644 --- a/src/datavisualization/engine/axisrendercache.cpp +++ b/src/datavisualization/engine/axisrendercache.cpp @@ -33,8 +33,9 @@ AxisRenderCache::AxisRenderCache() m_formatter(0), m_ctrlFormatter(0), m_drawer(0), - m_segmentStep(10.0f), - m_subSegmentStep(10.0f) + m_positionsDirty(true), + m_translate(0.0f), + m_scale(1.0f) { } @@ -73,8 +74,6 @@ void AxisRenderCache::setType(QAbstract3DAxis::AxisType type) foreach (LabelItem *label, m_labelItems) delete label; m_labelItems.clear(); - m_segmentStep = 10.0f; - m_subSegmentStep = 10.0f; } void AxisRenderCache::setTitle(const QString &title) @@ -114,28 +113,38 @@ void AxisRenderCache::setLabels(const QStringList &labels) } } -void AxisRenderCache::setMin(float min) +void AxisRenderCache::updateAllPositions() { - m_min = min; - updateSegmentStep(); -} - -void AxisRenderCache::setMax(float max) -{ - m_max = max; - updateSegmentStep(); -} - -void AxisRenderCache::setSegmentCount(int count) -{ - m_segmentCount = count; - updateSegmentStep(); -} + // As long as grid and subgrid lines are drawn identically, we can further optimize + // by caching all grid and subgrid positions into a single vector. + // If subgrid lines are ever themed separately, this array will probably become obsolete. + if (m_formatter) { + int subGridCount = m_subSegmentCount - 1; + int fullSize = m_segmentCount + 1 + (m_segmentCount * subGridCount); + m_adjustedGridLinePositions.resize(fullSize); + m_adjustedLabelPositions.resize(m_segmentCount + 1); + int index = 0; + int segment = 0; + for (; segment < m_segmentCount; segment++) { + m_adjustedLabelPositions[segment] = + m_formatter->labelPositions().at(segment) * m_scale + m_translate; + m_adjustedGridLinePositions[index++] = + m_formatter->gridPositions().at(segment) * m_scale + m_translate; + if (subGridCount > 0) { + for (int subGrid = 0; subGrid < subGridCount; subGrid++) { + m_adjustedGridLinePositions[index++] = + m_formatter->subGridPositions().at(segment).at(subGrid) * m_scale + m_translate; + } + } + } + // Last gridline + m_adjustedLabelPositions[segment] = + m_formatter->labelPositions().at(segment) * m_scale + m_translate; + m_adjustedGridLinePositions[index] = + m_formatter->gridPositions().at(segment) * m_scale + m_translate; -void AxisRenderCache::setSubSegmentCount(int count) -{ - m_subSegmentCount = count; - updateSubSegmentStep(); + m_positionsDirty = false; + } } void AxisRenderCache::updateTextures() @@ -157,23 +166,6 @@ void AxisRenderCache::updateTextures() } } -void AxisRenderCache::updateSegmentStep() -{ - if (m_segmentCount > 0) - m_segmentStep = qFabs((m_max - m_min) / m_segmentCount); - else - m_segmentStep = 0.0f; // Irrelevant - updateSubSegmentStep(); -} - -void AxisRenderCache::updateSubSegmentStep() -{ - if (m_subSegmentCount > 1) - m_subSegmentStep = m_segmentStep / m_subSegmentCount; - else - m_subSegmentStep = m_segmentStep; -} - int AxisRenderCache::maxLabelWidth(const QStringList &labels) const { int labelWidth = 0; diff --git a/src/datavisualization/engine/axisrendercache_p.h b/src/datavisualization/engine/axisrendercache_p.h index 5b48fbdf..eede9917 100644 --- a/src/datavisualization/engine/axisrendercache_p.h +++ b/src/datavisualization/engine/axisrendercache_p.h @@ -51,32 +51,48 @@ public: inline const QString &title() const { return m_title; } void setLabels(const QStringList &labels); inline const QStringList &labels() const { return m_labels; } - void setMin(float min); + inline void setMin(float min) { m_min = min; } inline float min() const { return m_min; } - void setMax(float max); + inline void setMax(float max) { m_max = max; } inline float max() const { return m_max; } - void setSegmentCount(int count); + inline void setSegmentCount(int count) { m_segmentCount = count; m_positionsDirty = true; } inline int segmentCount() const { return m_segmentCount; } - void setSubSegmentCount(int count); + inline void setSubSegmentCount(int count) { m_subSegmentCount = count; m_positionsDirty = true; } 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 setFormatter(QValue3DAxisFormatter *formatter) { m_formatter = formatter; } + inline void setFormatter(QValue3DAxisFormatter *formatter) + { + m_formatter = formatter; m_positionsDirty = true; + } inline QValue3DAxisFormatter *formatter() const { return m_formatter; } - inline void setCtrlFormatter(const QValue3DAxisFormatter *formatter) { m_ctrlFormatter = formatter; } + inline void setCtrlFormatter(const QValue3DAxisFormatter *formatter) + { + m_ctrlFormatter = formatter; + } inline const QValue3DAxisFormatter *ctrlFormatter() const { return m_ctrlFormatter; } inline LabelItem &titleItem() { return m_titleItem; } inline QList &labelItems() { return m_labelItems; } - inline GLfloat segmentStep() const { return m_segmentStep; } - inline GLfloat subSegmentStep() const { return m_subSegmentStep; } + inline float gridLinePosition(int index) { return m_adjustedGridLinePositions.at(index); } + inline int gridLineCount() { return m_adjustedGridLinePositions.size(); } + inline float labelPosition(int index) { return m_adjustedLabelPositions.at(index); } + inline int labelCount() { return m_adjustedLabelPositions.size(); } + void updateAllPositions(); + inline bool positionsDirty() const { return m_positionsDirty; } + inline void setTranslate(float translate) { m_translate = translate; m_positionsDirty = true; } + inline float translate() { return m_translate; } + inline void setScale(float scale) { m_scale = scale; m_positionsDirty = true; } + inline float scale() { return m_scale; } + inline float positionAt(float value) + { + return m_formatter->positionAt(value) * m_scale + m_translate; + } public slots: void updateTextures(); private: - void updateSegmentStep(); - void updateSubSegmentStep(); int maxLabelWidth(const QStringList &labels) const; // Cached axis values @@ -96,8 +112,11 @@ private: Drawer *m_drawer; // Not owned LabelItem m_titleItem; QList m_labelItems; - GLfloat m_segmentStep; - GLfloat m_subSegmentStep; + QVector m_adjustedGridLinePositions; + QVector m_adjustedLabelPositions; + bool m_positionsDirty; + float m_translate; + float m_scale; Q_DISABLE_COPY(AxisRenderCache) }; diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index 3a685c91..f0a5e3d4 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -84,7 +84,7 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) m_maxSceneSize(40.0f), m_visualSelectedBarPos(Bars3DController::invalidSelectionPosition()), m_visualSelectedBarSeriesIndex(-1), - m_hasHeightAdjustmentChanged(true), + m_resetCameraBaseOrientation(true), m_selectedBarPos(Bars3DController::invalidSelectionPosition()), m_selectedBarSeries(0), m_noZeroInRange(false), @@ -95,6 +95,8 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller) m_clickedPosition(Bars3DController::invalidSelectionPosition()), m_keepSeriesUniform(false) { + m_axisCacheY.setScale(2.0f); + initializeOpenGLFunctions(); initializeOpenGL(); } @@ -187,6 +189,8 @@ void Bars3DRenderer::updateData() calculateSceneScalingFactors(); } + const QValue3DAxisFormatter *axisFormatter = m_axisCacheY.formatter(); + float zeroPosition = axisFormatter->positionAt(0.0f); for (int series = 0; series < seriesCount; series++) { BarRenderItemArray &renderArray = m_renderingArrays[series]; if (newRows != renderArray.size() @@ -215,22 +219,22 @@ void Bars3DRenderer::updateData() int dataColIndex = minCol; for (; j < updateSize ; j++) { float value = dataRow->at(dataColIndex).value(); - if (!m_noZeroInRange) { - heightValue = GLfloat(value); - } else { - // Adjust height to range - if (!m_hasNegativeValues) { - heightValue = value - m_axisCacheY.min(); - if (heightValue < 0.0f) - heightValue = 0.0f; - } else if (m_axisCacheY.max() < 0.0f) { - heightValue = value - m_axisCacheY.max(); + heightValue = axisFormatter->positionAt(value); + if (m_noZeroInRange) { + if (m_hasNegativeValues) { + heightValue = -1.0f + heightValue; if (heightValue > 0.0f) heightValue = 0.0f; + } else { + if (heightValue < 0.0f) + heightValue = 0.0f; } + } else { + heightValue -= zeroPosition; } renderRow[j].setValue(value); - renderRow[j].setHeight(heightValue / m_heightNormalizer); + renderRow[j].setHeight(heightValue); + float angle = dataRow->at(dataColIndex).rotation(); if (angle) { renderRow[j].setRotation( @@ -263,12 +267,12 @@ void Bars3DRenderer::updateScene(Q3DScene *scene) else scene->activeCamera()->d_ptr->setMinYRotation(0.0f); - if (m_hasHeightAdjustmentChanged) { + if (m_resetCameraBaseOrientation) { // Set initial camera position. Also update if height adjustment has changed. scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector, zeroVector, upVector); - m_hasHeightAdjustmentChanged = false; + m_resetCameraBaseOrientation = false; } Abstract3DRenderer::updateScene(scene); @@ -281,6 +285,9 @@ void Bars3DRenderer::render(GLuint defaultFboHandle) // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); + if (m_axisCacheY.positionsDirty()) + m_axisCacheY.updateAllPositions(); + drawScene(defaultFboHandle); if (m_cachedIsSlicingActivated) drawSlicedScene(); @@ -323,6 +330,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 scaleFactor = 0.0f; if (rowMode) scaleFactor = (1.1f * m_rowWidth) / m_scaleFactor; @@ -356,20 +364,18 @@ void Bars3DRenderer::drawSlicedScene() lineShader->setUniformValue(lineShader->lightS(), 0.0f); lineShader->setUniformValue(lineShader->lightColor(), lightColor); - GLfloat gridStep = (2.0f * m_axisCacheY.subSegmentStep()) / m_heightNormalizer; - GLfloat gridPos = barPosYAdjustment; - int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); - // Use the position of the bottom grid line as the base y position for bar labels - // Horizontal lines if (m_axisCacheY.segmentCount() > 0) { + int gridLineCount = m_axisCacheY.gridLineCount(); + QVector3D gridLineScale(scaleFactor, gridLineWidth, gridLineWidth); bool noZero = true; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; + GLfloat gridPos = m_axisCacheY.gridLinePosition(line) + gridAdjustment; modelMatrix.translate(0.0f, gridPos, 0.0f); modelMatrix.scale(gridLineScale); itModelMatrix = modelMatrix; @@ -391,8 +397,6 @@ void Bars3DRenderer::drawSlicedScene() // Check if we have a line at zero position already if (gridPos == (barPosYAdjustment + zeroPosAdjustment)) noZero = false; - - gridPos += gridStep; } // Draw a line at zero, if none exists @@ -431,14 +435,13 @@ void Bars3DRenderer::drawSlicedScene() // Draw grid labels int labelNbr = 0; int labelCount = m_axisCacheY.labels().size(); - gridStep = (2.0f * m_axisCacheY.segmentStep()) / m_heightNormalizer; - gridPos = barPosYAdjustment; QVector3D backLabelRotation(0.0f, 0.0f, 0.0f); QVector3D labelTrans = QVector3D(scaleFactor + labelMargin, 0.0f, 0.0f); for (int i = 0; i < labelCount; i++) { if (m_axisCacheY.labelItems().size() > labelNbr) { const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + GLfloat gridPos = m_axisCacheY.labelPosition(i) + gridAdjustment; labelTrans.setY(gridPos); m_dummyBarRenderItem.setTranslation(labelTrans); m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, @@ -447,7 +450,6 @@ void Bars3DRenderer::drawSlicedScene() activeCamera, true, true, Drawer::LabelMid, Qt::AlignRight); } labelNbr++; - gridPos += gridStep; } glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); @@ -645,8 +647,9 @@ void Bars3DRenderer::drawSlicedScene() if (item.height() != 0.0f || (!m_noZeroInRange && item.value() == 0.0f)) { // Create label texture if we need it if (item.sliceLabel().isNull() || m_updateLabels) { - item.setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(), - item.value())); + QString valueLabelText = m_axisCacheY.formatter()->stringForValue( + item.value(), m_axisCacheY.labelFormat()); + item.setSliceLabel(valueLabelText); m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel()); m_updateLabels = false; } @@ -670,8 +673,9 @@ void Bars3DRenderer::drawSlicedScene() && item.seriesIndex() == m_visualSelectedBarSeriesIndex) { // Create label texture if we need it if (item.sliceLabel().isNull() || m_updateLabels) { - item.setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(), - item.value())); + QString valueLabelText = m_axisCacheY.formatter()->stringForValue( + item.value(), m_axisCacheY.labelFormat()); + item.setSliceLabel(valueLabelText); m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel()); m_updateLabels = false; } @@ -1336,12 +1340,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 itModelMatrix; QVector3D backgroundScaler(rowScaleFactor, 1.0f, columnScaleFactor); - if (m_hasNegativeValues) { - backgroundScaler.setY(0.5f); - modelMatrix.translate(0.0f, m_negativeBackgroundAdjustment, 0.0f); - } else { - modelMatrix.translate(0.0f, 1.0f, 0.0f); - } + modelMatrix.translate(0.0f, m_negativeBackgroundAdjustment, 0.0f); + modelMatrix.scale(backgroundScaler); itModelMatrix.scale(backgroundScaler); modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f); @@ -1434,7 +1434,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) glDisable(GL_TEXTURE_2D); // Draw grid lines - if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { + if (m_cachedTheme->isGridEnabled()) { #if !(defined QT_OPENGL_ES_2) ShaderHelper *lineShader = m_backgroundShader; #else @@ -1559,30 +1559,20 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) if (m_axisCacheY.segmentCount() > 0) { // Wall lines: back wall - GLfloat heightStep = m_axisCacheY.subSegmentStep(); - GLfloat startLine = 0.0f; - int segmentCount = m_axisCacheY.segmentCount() * m_axisCacheY.subSegmentCount(); + int gridLineCount = m_axisCacheY.gridLineCount(); GLfloat zWallLinePosition = -columnScaleFactor + gridLineOffset; if (m_zFlipped) zWallLinePosition = -zWallLinePosition; - if (m_hasNegativeValues) { - if (m_noZeroInRange) - startLine = m_axisCacheY.min() - m_axisCacheY.max(); - else - startLine = m_axisCacheY.min(); - } - - GLfloat lineHeight = startLine; gridLineScaler = QVector3D(rowScaleFactor, gridLineWidth, gridLineWidth); - for (int segment = 0; segment <= segmentCount; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; modelMatrix.translate(0.0f, - 2.0f * lineHeight / m_heightNormalizer, + m_axisCacheY.gridLinePosition(line), zWallLinePosition); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1613,7 +1603,6 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - lineHeight += heightStep; } // Wall lines: side wall @@ -1626,15 +1615,14 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) else lineRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f); - lineHeight = startLine; gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, columnScaleFactor); - for (int segment = 0; segment <= segmentCount; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; modelMatrix.translate(xWallLinePosition, - 2.0f * lineHeight / m_heightNormalizer, + m_axisCacheY.gridLinePosition(line), 0.0f); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1663,7 +1651,6 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - lineHeight += heightStep; } } } @@ -1678,16 +1665,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) // Y Labels int labelNbr = 0; - GLfloat heightStep = m_axisCacheY.segmentStep(); - GLfloat startLine = 0.0f; int labelCount = m_axisCacheY.labels().size(); - if (m_hasNegativeValues) { - if (m_noZeroInRange) - startLine = m_axisCacheY.min() - m_axisCacheY.max(); - else - startLine = m_axisCacheY.min(); - } - GLfloat labelPos = startLine; GLfloat labelMarginXTrans = labelMargin; GLfloat labelMarginZTrans = labelMargin; GLfloat labelXTrans = rowScaleFactor; @@ -1715,7 +1693,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) for (int i = 0; i < labelCount; i++) { if (m_axisCacheY.labelItems().size() > labelNbr) { - backLabelTrans.setY(2.0f * labelPos / m_heightNormalizer); + backLabelTrans.setY(m_axisCacheY.labelPosition(i)); sideLabelTrans.setY(backLabelTrans.y()); glPolygonOffset(GLfloat(i) / -10.0f, 1.0f); @@ -1737,7 +1715,6 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) true, true, Drawer::LabelMid, sideAlignment); } labelNbr++; - labelPos += heightStep; } // Calculate the positions for row and column labels and store them @@ -1844,9 +1821,9 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) static const QString seriesNameTag(QStringLiteral("@seriesName")); // Custom format expects printf format specifier. There is no tag for it. - labelText = generateValueLabel( - m_visibleSeriesList[m_visualSelectedBarSeriesIndex].itemLabelFormat(), - selectedBar->value()); + labelText = m_axisCacheY.formatter()->stringForValue( + selectedBar->value(), + m_visibleSeriesList[m_visualSelectedBarSeriesIndex].itemLabelFormat()); int selBarPosRow = selectedBar->position().x(); int selBarPosCol = selectedBar->position().y(); @@ -1865,10 +1842,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle) labelText.replace(valueTitleTag, m_axisCacheY.title()); if (labelText.contains(valueLabelTag)) { - QString labelFormat = m_axisCacheY.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, selectedBar->value()); + QString valueLabelText = m_axisCacheY.formatter()->stringForValue( + selectedBar->value(), m_axisCacheY.labelFormat()); labelText.replace(valueLabelTag, valueLabelText); } @@ -1945,7 +1920,6 @@ void Bars3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orientatio Abstract3DRenderer::updateAxisRange(orientation, min, max); if (orientation == QAbstract3DAxis::AxisOrientationY) { - calculateHeightAdjustment(); // Check if we have negative values if (min < 0 && !m_hasNegativeValues) { m_hasNegativeValues = true; @@ -1958,6 +1932,7 @@ void Bars3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orientatio loadBackgroundMesh(); emit needRender(); } + calculateHeightAdjustment(); } } @@ -2100,7 +2075,7 @@ void Bars3DRenderer::calculateSceneScalingFactors() void Bars3DRenderer::calculateHeightAdjustment() { - GLfloat newAdjustment = 0.0f; + GLfloat newAdjustment = 1.0f; GLfloat maxAbs = qFabs(m_axisCacheY.max()); if (m_axisCacheY.max() < 0.0f) { @@ -2111,7 +2086,8 @@ void Bars3DRenderer::calculateHeightAdjustment() } // Height fractions are used in gradient calculations and are therefore doubled - if (m_axisCacheY.max() < 0.0f || m_axisCacheY.min() > 0.0f) { + // Note that if max or min is exactly zero, we still consider it outside the range + if (m_axisCacheY.max() <= 0.0f || m_axisCacheY.min() >= 0.0f) { m_noZeroInRange = true; m_gradientFraction = 2.0f; } else { @@ -2121,11 +2097,12 @@ void Bars3DRenderer::calculateHeightAdjustment() } // Calculate translation adjustment for negative background - newAdjustment = qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) * 2.0f - 0.5f; + if (m_hasNegativeValues) + newAdjustment = (qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) - 0.5f) * 2.0f; if (newAdjustment != m_negativeBackgroundAdjustment) { - m_hasHeightAdjustmentChanged = true; m_negativeBackgroundAdjustment = newAdjustment; + m_axisCacheY.setTranslate(m_negativeBackgroundAdjustment - 1.0f); } } diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h index 37ac2b76..2c0417e4 100644 --- a/src/datavisualization/engine/bars3drenderer_p.h +++ b/src/datavisualization/engine/bars3drenderer_p.h @@ -96,7 +96,7 @@ private: GLfloat m_maxSceneSize; QPoint m_visualSelectedBarPos; int m_visualSelectedBarSeriesIndex; - bool m_hasHeightAdjustmentChanged; + bool m_resetCameraBaseOrientation; QPoint m_selectedBarPos; const QBar3DSeries *m_selectedBarSeries; BarRenderItem m_dummyBarRenderItem; diff --git a/src/datavisualization/engine/meshes/backgroundNegatives.obj b/src/datavisualization/engine/meshes/backgroundNegatives.obj index d314e1fc..0b94617f 100644 --- a/src/datavisualization/engine/meshes/backgroundNegatives.obj +++ b/src/datavisualization/engine/meshes/backgroundNegatives.obj @@ -4,9 +4,9 @@ o Cube v 1.000000 1.000000 1.000000 v -1.000000 1.000000 1.000000 v -1.000000 1.000000 -1.000000 -v 1.000000 -3.000000 1.000000 -v -1.000000 -3.000000 1.000000 -v -1.000000 -3.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 vt 0.000000 0.000000 vt 0.500000 0.000000 vt 0.500000 1.000000 diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp index 38e48cc2..ae4b3831 100644 --- a/src/datavisualization/engine/scatter3drenderer.cpp +++ b/src/datavisualization/engine/scatter3drenderer.cpp @@ -48,7 +48,6 @@ const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will const GLfloat labelMargin = 0.05f; const GLfloat defaultMinSize = 0.01f; const GLfloat defaultMaxSize = 0.1f; -const GLfloat defaultMargin = 1.0f + defaultMaxSize; // Default margin for background const GLfloat itemScaler = 3.0f; const GLfloat gridLineWidth = 0.005f; @@ -90,10 +89,13 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_areaSize(QSizeF(0.0, 0.0)), m_dotSizeScale(1.0f), m_hasHeightAdjustmentChanged(true), - m_backgroundMargin(defaultMargin), + m_backgroundMargin(defaultMaxSize), m_maxItemSize(0.0f), m_clickedIndex(Scatter3DController::invalidSelectionIndex()) { + m_axisCacheY.setScale(2.0f); + m_axisCacheY.setTranslate(-1.0f); + initializeOpenGLFunctions(); initializeOpenGL(); } @@ -176,10 +178,11 @@ void Scatter3DRenderer::updateSeries(const QList &seriesLis if (m_cachedItemSize.at(series) != itemSize) m_cachedItemSize[series] = itemSize; } - m_backgroundMargin = defaultMargin; m_maxItemSize = maxItemSize; if (maxItemSize > defaultMaxSize) - m_backgroundMargin += maxItemSize / itemScaler; + m_backgroundMargin = maxItemSize / itemScaler; + else + m_backgroundMargin = defaultMaxSize; } void Scatter3DRenderer::updateData() @@ -255,6 +258,13 @@ void Scatter3DRenderer::render(GLuint defaultFboHandle) // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); + if (m_axisCacheX.positionsDirty()) + m_axisCacheX.updateAllPositions(); + if (m_axisCacheY.positionsDirty()) + m_axisCacheY.updateAllPositions(); + if (m_axisCacheZ.positionsDirty()) + m_axisCacheZ.updateAllPositions(); + // Draw dots scene drawScene(defaultFboHandle); } @@ -776,17 +786,17 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) QMatrix4x4 itModelMatrix; #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor; - GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) / m_scaleFactor; + GLfloat xScale = (aspectRatio * m_areaSize.width()) / m_scaleFactor + m_backgroundMargin; + GLfloat zScale = (aspectRatio * m_areaSize.height()) / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > xScale) xScale = m_maxItemSize; if (m_maxItemSize > zScale) zScale = m_maxItemSize; - QVector3D bgScale(xScale, m_backgroundMargin, zScale); + QVector3D bgScale(xScale, 1.0f + m_backgroundMargin, zScale); #else // ..and this if we want uniform scaling based on largest dimension - QVector3D bgScale((aspectRatio * m_backgroundMargin), - m_backgroundMargin, - (aspectRatio * m_backgroundMargin)); + QVector3D bgScale((aspectRatio + m_backgroundMargin), + 1.0f + m_backgroundMargin, + (aspectRatio + m_backgroundMargin)); #endif modelMatrix.scale(bgScale); // If we're viewing from below, background object must be flipped @@ -845,15 +855,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) glDisable(GL_TEXTURE_2D); // Draw grid lines -#ifdef USE_UNIFORM_SCALING - AxisRenderCache *axisCacheMax; - if (m_axisCacheZ.max() > m_axisCacheX.max()) - axisCacheMax = &m_axisCacheZ; - else - axisCacheMax = &m_axisCacheX; -#endif - - if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) { + if (m_cachedTheme->isGridEnabled()) { #if !(defined QT_OPENGL_ES_2) ShaderHelper *lineShader = m_backgroundShader; #else @@ -897,39 +899,31 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) else lineXRotation = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f); - GLfloat yFloorLinePosition = -m_backgroundMargin + gridLineOffset; + GLfloat yFloorLinePosition = -1.0f - m_backgroundMargin + gridLineOffset; if (m_yFlipped) yFloorLinePosition = -yFloorLinePosition; // Rows (= Z) if (m_axisCacheZ.segmentCount() > 0) { // Floor lines -#ifndef USE_UNIFORM_SCALING - GLfloat lineStep = aspectRatio * m_axisCacheZ.subSegmentStep(); - GLfloat linePos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); // Start line - int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); -#else - GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep(); - GLfloat linePos = -aspectRatio * m_scaleFactor; // Start line - int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount(); -#endif + int gridLineCount = m_axisCacheZ.gridLineCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor; + GLfloat xScale = (aspectRatio * m_areaSize.width()) / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > xScale) xScale = m_maxItemSize; QVector3D gridLineScaler(xScale, gridLineWidth, gridLineWidth); #else // ..and this if we want uniform scaling based on largest dimension - QVector3D gridLineScaler((aspectRatio * m_backgroundMargin), + QVector3D gridLineScaler((aspectRatio + m_backgroundMargin), gridLineWidth, gridLineWidth); #endif - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, yFloorLinePosition, linePos / m_scaleFactor); + modelMatrix.translate(0.0f, yFloorLinePosition, m_axisCacheZ.gridLinePosition(line)); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -959,30 +953,27 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos -= lineStep; } // Side wall lines - gridLineScaler = QVector3D(gridLineWidth, m_backgroundMargin, gridLineWidth); + gridLineScaler = QVector3D(gridLineWidth, 1.0f + m_backgroundMargin, gridLineWidth); #ifndef USE_UNIFORM_SCALING - GLfloat lineXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor - gridLineOffset; + GLfloat lineXTrans = (aspectRatio * m_areaSize.width()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineXTrans) lineXTrans = m_maxItemSize - gridLineOffset; - linePos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); // Start line #else - GLfloat lineXTrans = aspectRatio * m_backgroundMargin - gridLineOffset; - linePos = -aspectRatio * m_scaleFactor; // Start line + GLfloat lineXTrans = aspectRatio + m_backgroundMargin - gridLineOffset; #endif if (!m_xFlipped) lineXTrans = -lineXTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(lineXTrans, 0.0f, linePos / m_scaleFactor); + modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line)); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1017,7 +1008,6 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos -= lineStep; } } @@ -1027,28 +1017,24 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) lineXRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f); #endif // Floor lines + int gridLineCount = m_axisCacheX.gridLineCount(); + #ifndef USE_UNIFORM_SCALING - GLfloat lineStep = aspectRatio * m_axisCacheX.subSegmentStep(); - GLfloat linePos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x()); - int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); - GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) / m_scaleFactor; + GLfloat zScale = (aspectRatio * m_areaSize.height()) / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > zScale) zScale = m_maxItemSize; QVector3D gridLineScaler(gridLineWidth, gridLineWidth, zScale); #else - GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep(); - GLfloat linePos = -aspectRatio * m_scaleFactor; - int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount(); QVector3D gridLineScaler(gridLineWidth, gridLineWidth, - aspectRatio * m_backgroundMargin); + aspectRatio + m_backgroundMargin); #endif - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos / m_scaleFactor, yFloorLinePosition, 0.0f); + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition, 0.0f); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1078,31 +1064,28 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } // Back wall lines #ifndef USE_UNIFORM_SCALING - GLfloat lineZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor - gridLineOffset; + GLfloat lineZTrans = (aspectRatio * m_areaSize.height()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineZTrans) lineZTrans = m_maxItemSize - gridLineOffset; - linePos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x()); #else - GLfloat lineZTrans = aspectRatio * m_backgroundMargin - gridLineOffset; - linePos = -aspectRatio * m_scaleFactor; + GLfloat lineZTrans = aspectRatio + m_backgroundMargin - gridLineOffset; #endif if (!m_zFlipped) lineZTrans = -lineZTrans; - gridLineScaler = QVector3D(gridLineWidth, m_backgroundMargin, gridLineWidth); + gridLineScaler = QVector3D(gridLineWidth, 1.0f + m_backgroundMargin, gridLineWidth); - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos / m_scaleFactor, 0.0f, lineZTrans); + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1139,40 +1122,37 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } } // Horizontal wall lines if (m_axisCacheY.segmentCount() > 0) { // Back wall - GLfloat lineStep = m_axisCacheY.subSegmentStep(); - GLfloat linePos = m_axisCacheY.min() - m_translationOffset.y(); - int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + int gridLineCount = m_axisCacheY.gridLineCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat lineZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor - gridLineOffset; + GLfloat lineZTrans = (aspectRatio * m_areaSize.height()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineZTrans) lineZTrans = m_maxItemSize - gridLineOffset; - GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor; + GLfloat xScale = (aspectRatio * m_areaSize.width()) / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > xScale) xScale = m_maxItemSize; QVector3D gridLineScaler(xScale, gridLineWidth, gridLineWidth); #else // ..and this if we want uniform scaling based on largest dimension - GLfloat lineZTrans = aspectRatio * m_backgroundMargin - gridLineOffset; - QVector3D gridLineScaler((aspectRatio * m_backgroundMargin), + GLfloat lineZTrans = aspectRatio + m_backgroundMargin - gridLineOffset; + QVector3D gridLineScaler((aspectRatio + m_backgroundMargin), gridLineWidth, gridLineWidth); #endif if (!m_zFlipped) lineZTrans = -lineZTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, linePos / m_heightNormalizer, lineZTrans); + modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), lineZTrans); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1204,36 +1184,33 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } // Side wall - linePos = m_axisCacheY.min() - m_translationOffset.y(); - lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat lineXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor - gridLineOffset; + GLfloat lineXTrans = (aspectRatio * m_areaSize.width()) + / m_scaleFactor - gridLineOffset + m_backgroundMargin; if (m_maxItemSize > lineXTrans) lineXTrans = m_maxItemSize - gridLineOffset; - GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat zScale = (aspectRatio * m_areaSize.height()) + / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > zScale) zScale = m_maxItemSize; gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, zScale); #else // ..and this if we want uniform scaling based on largest dimension - GLfloat lineXTrans = aspectRatio * m_backgroundMargin - gridLineOffset; + GLfloat lineXTrans = aspectRatio + m_backgroundMargin - gridLineOffset; gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, - aspectRatio * m_backgroundMargin); + aspectRatio + m_backgroundMargin); #endif if (!m_xFlipped) lineXTrans = -lineXTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(lineXTrans, linePos / m_heightNormalizer, 0.0f); + modelMatrix.translate(lineXTrans, m_axisCacheY.gridLinePosition(line), 0.0f); modelMatrix.scale(gridLineScaler); itModelMatrix.scale(gridLineScaler); @@ -1263,13 +1240,11 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } } } // Draw axis labels - // Bind label shader m_labelShader->bind(); glEnable(GL_TEXTURE_2D); @@ -1279,22 +1254,17 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) // Z Labels if (m_axisCacheZ.segmentCount() > 0) { + int labelCount = m_axisCacheZ.labelItems().size(); #ifndef USE_UNIFORM_SCALING - GLfloat posStep = aspectRatio * m_axisCacheZ.segmentStep(); - GLfloat labelPos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); - int lastSegment = m_axisCacheZ.segmentCount(); - GLfloat labelXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor + labelMargin; + GLfloat labelXTrans = (aspectRatio * m_areaSize.width()) + / m_scaleFactor + labelMargin + m_backgroundMargin; if (m_maxItemSize > labelXTrans) labelXTrans = m_maxItemSize + labelMargin; #else - GLfloat posStep = aspectRatio * axisCacheMax->segmentStep(); - GLfloat labelPos = aspectRatio * m_scaleFactor; - int lastSegment = axisCacheMax->segmentCount(); - GLfloat labelXTrans = aspectRatio * m_backgroundMargin + labelMargin; + GLfloat labelXTrans = aspectRatio + m_backgroundMargin + labelMargin; #endif int labelNbr = 0; - GLfloat labelYTrans = -m_backgroundMargin; + GLfloat labelYTrans = -1.0f - m_backgroundMargin; GLfloat rotLabelX = -90.0f; GLfloat rotLabelY = 0.0f; GLfloat rotLabelZ = 0.0f; @@ -1312,23 +1282,15 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) } QVector3D labelRotateVector(rotLabelX, rotLabelY, rotLabelZ); QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, 0.0f); - for (int segment = 0; segment <= lastSegment; segment++) { -#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + for (int label = 0; label < labelCount; label++) { if (m_axisCacheZ.labelItems().size() > labelNbr) { -#else // ..and this if we want uniform scaling based on largest dimension - if (axisCacheMax->labelItems().size() > labelNbr) { -#endif - labelTrans.setZ(labelPos / m_scaleFactor); + labelTrans.setZ(m_axisCacheZ.labelPosition(label)); - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); // Draw the label here m_dummyRenderItem.setTranslation(labelTrans); -#ifndef USE_UNIFORM_SCALING const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr); -#else - const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr); -#endif m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, zeroVector, labelRotateVector, 0, m_cachedSelectionMode, @@ -1336,27 +1298,21 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) Drawer::LabelMid, alignment); } labelNbr++; - labelPos -= posStep; } } // X Labels if (m_axisCacheX.segmentCount() > 0) { + int labelCount = m_axisCacheX.labelItems().size(); #ifndef USE_UNIFORM_SCALING - GLfloat posStep = aspectRatio * m_axisCacheX.segmentStep(); - GLfloat labelPos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x()); - int lastSegment = m_axisCacheX.segmentCount(); - GLfloat labelZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor + labelMargin; + GLfloat labelZTrans = (aspectRatio * m_areaSize.height()) + / m_scaleFactor + labelMargin + m_backgroundMargin; if (m_maxItemSize > labelZTrans) labelZTrans = m_maxItemSize + labelMargin; #else - GLfloat posStep = aspectRatio * axisCacheMax->segmentStep(); - GLfloat labelPos = -aspectRatio * m_scaleFactor; - int lastSegment = axisCacheMax->segmentCount(); - GLfloat labelZTrans = aspectRatio * m_backgroundMargin + labelMargin; + GLfloat labelZTrans = aspectRatio + m_backgroundMargin + labelMargin; #endif int labelNbr = 0; - GLfloat labelYTrans = -m_backgroundMargin; + GLfloat labelYTrans = -1.0f - m_backgroundMargin; GLfloat rotLabelX = -90.0f; GLfloat rotLabelY = 90.0f; GLfloat rotLabelZ = 0.0f; @@ -1374,23 +1330,15 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) } QVector3D labelRotateVector(rotLabelX, rotLabelY, rotLabelZ); QVector3D labelTrans = QVector3D(0.0f, labelYTrans, labelZTrans); - for (int segment = 0; segment <= lastSegment; segment++) { -#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + for (int label = 0; label < labelCount; label++) { if (m_axisCacheX.labelItems().size() > labelNbr) { -#else // ..and this if we want uniform scaling based on largest dimension - if (axisCacheMax->labelItems().size() > labelNbr) { -#endif - labelTrans.setX(labelPos / m_scaleFactor); + labelTrans.setX(m_axisCacheX.labelPosition(label)); - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); // Draw the label here m_dummyRenderItem.setTranslation(labelTrans); -#ifndef USE_UNIFORM_SCALING const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); -#else - const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr); -#endif m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, zeroVector, labelRotateVector, 0, m_cachedSelectionMode, @@ -1398,25 +1346,23 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) Drawer::LabelMid, alignment); } labelNbr++; - labelPos += posStep; } } // Y Labels if (m_axisCacheY.segmentCount() > 0) { - GLfloat posStep = m_axisCacheY.segmentStep(); - GLfloat labelPos = m_axisCacheY.min() - m_translationOffset.y(); + int labelCount = m_axisCacheY.labelItems().size(); int labelNbr = 0; #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat labelXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width()) - / m_scaleFactor; - GLfloat labelZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat labelXTrans = (aspectRatio* m_areaSize.width()) + / m_scaleFactor + m_backgroundMargin; + GLfloat labelZTrans = (aspectRatio * m_areaSize.height()) + / m_scaleFactor + m_backgroundMargin; if (m_maxItemSize > labelXTrans) labelXTrans = m_maxItemSize; if (m_maxItemSize > labelZTrans) labelZTrans = m_maxItemSize; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat labelXTrans = aspectRatio * m_backgroundMargin; + GLfloat labelXTrans = aspectRatio + m_backgroundMargin; GLfloat labelZTrans = labelXTrans; #endif // Back wall init @@ -1453,12 +1399,12 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) QVector3D labelRotateVectorSide(rotLabelX, rotLabelY, rotLabelZ); QVector3D labelTransSide(-labelXTrans - labelMarginXTrans, 0.0f, -labelZTrans); - for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + for (int label = 0; label < labelCount; label++) { if (m_axisCacheY.labelItems().size() > labelNbr) { const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); - const GLfloat labelYTrans = labelPos / m_heightNormalizer; + const GLfloat labelYTrans = m_axisCacheY.labelPosition(label); - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); // Back wall labelTransBack.setY(labelYTrans); @@ -1477,7 +1423,6 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) Drawer::LabelMid, alignmentSide); } labelNbr++; - labelPos += posStep; } } glDisable(GL_POLYGON_OFFSET_FILL); @@ -1509,30 +1454,22 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle) labelText.replace(zTitleTag, m_axisCacheZ.title()); if (labelText.contains(xLabelTag)) { - QString labelFormat = m_axisCacheX.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - selectedItem->position().x()); + QString valueLabelText = m_axisCacheX.formatter()->stringForValue( + selectedItem->position().x(), m_axisCacheX.labelFormat()); labelText.replace(xLabelTag, valueLabelText); } if (labelText.contains(yLabelTag)) { - QString labelFormat = m_axisCacheY.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - selectedItem->position().y()); + QString valueLabelText = m_axisCacheY.formatter()->stringForValue( + selectedItem->position().y(), m_axisCacheY.labelFormat()); labelText.replace(yLabelTag, valueLabelText); } if (labelText.contains(zLabelTag)) { - QString labelFormat = m_axisCacheZ.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - selectedItem->position().z()); + QString valueLabelText = m_axisCacheZ.formatter()->stringForValue( + selectedItem->position().z(), m_axisCacheZ.labelFormat()); labelText.replace(zLabelTag, valueLabelText); } - labelText.replace(seriesNameTag, m_visibleSeriesList[m_selectedItemSeriesIndex].name()); + labelText.replace(seriesNameTag, + m_visibleSeriesList[m_selectedItemSeriesIndex].name()); setSelectionLabel(labelText); m_selectionLabelDirty = false; @@ -1671,11 +1608,10 @@ void Scatter3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Me void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item) { // We need to normalize translations - GLfloat xTrans = (aspectRatio * (item.position().x() - m_translationOffset.x())) - / m_scaleFactor; - GLfloat zTrans = -(aspectRatio * (item.position().z() - m_translationOffset.z())) - / m_scaleFactor; - GLfloat yTrans = (item.position().y() - m_translationOffset.y()) / m_heightNormalizer; + const QVector3D &pos = item.position(); + float xTrans = m_axisCacheX.positionAt(pos.x()); + float yTrans = m_axisCacheY.positionAt(pos.y()); + float zTrans = m_axisCacheZ.positionAt(pos.z()); item.setTranslation(QVector3D(xTrans, yTrans, zTrans)); } @@ -1686,10 +1622,16 @@ void Scatter3DRenderer::calculateSceneScalingFactors() m_areaSize.setWidth((m_axisCacheX.max() - m_axisCacheX.min()) / 2.0f); m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); - // Calculate translation offsets - m_translationOffset = QVector3D((m_axisCacheX.max() + m_axisCacheX.min()) / 2.0f, - (m_axisCacheY.max() + m_axisCacheY.min()) / 2.0f, - (m_axisCacheZ.max() + m_axisCacheZ.min()) / 2.0f); +#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z + float factorScaler = 2.0f * aspectRatio / m_scaleFactor; + m_axisCacheX.setScale(factorScaler * m_areaSize.width()); + m_axisCacheZ.setScale(-factorScaler * m_areaSize.height()); +#else // ..and this if we want uniform scaling based on largest dimension + m_axisCacheX.setScale(2.0f * aspectRatio); + m_axisCacheZ.setScale(-m_axisCacheX.scale()); +#endif + m_axisCacheX.setTranslate(-m_axisCacheX.scale() / 2.0f); + m_axisCacheZ.setTranslate(-m_axisCacheZ.scale() / 2.0f); } void Scatter3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader) diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index 243c27de..ed99e49e 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -41,7 +41,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION //#define SHOW_DEPTH_TEXTURE_SCENE const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd. -const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background) +const GLfloat backgroundMargin = 1.1f; // Margin for background (1.10 make it 10% larger to avoid + // selection ball being drawn inside background) const GLfloat labelMargin = 0.05f; const GLfloat gridLineWidth = 0.005f; const GLfloat sliceZScale = 0.1f; @@ -96,6 +97,9 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) m_selectionTexturesDirty(false), m_noShadowTexture(0) { + m_axisCacheY.setScale(2.0f); + m_axisCacheY.setTranslate(-1.0f); + // Check if flat feature is supported ShaderHelper tester(this, QStringLiteral(":/shaders/vertexSurfaceFlat"), QStringLiteral(":/shaders/fragmentSurfaceFlat")); @@ -196,7 +200,7 @@ void Surface3DRenderer::updateData() // Need minimum of 2x2 array to draw a surface if (array.size() >= 2 && array.at(0)->size() >= 2) { - QRect sampleSpace = calculateSampleRect(cache, array); + QRect sampleSpace = calculateSampleRect(array); QSurfaceDataArray &dataArray = cache->dataArray(); bool dimensionChanged = false; @@ -259,7 +263,7 @@ void Surface3DRenderer::updateSeries(const QList &seriesLis QSurface3DSeries *surfaceSeries = static_cast(series); SurfaceSeriesRenderCache *cache = m_renderCacheList.value(surfaceSeries); if (!cache) { - cache = new SurfaceSeriesRenderCache; + cache = new SurfaceSeriesRenderCache(this); m_renderCacheList[surfaceSeries] = cache; m_selectionTexturesDirty = true; @@ -341,15 +345,10 @@ void Surface3DRenderer::updateRows(const QVector srcArray->at(row)->at(j + sampleSpace.x()); } - if (cache->isFlatShadingEnabled()) { - cache->surfaceObject()->updateCoarseRow(dstArray, row - sampleSpace.y(), - m_heightNormalizer, - m_axisCacheY.min()); - } else { - cache->surfaceObject()->updateSmoothRow(dstArray, row - sampleSpace.y(), - m_heightNormalizer, - m_axisCacheY.min()); - } + if (cache->isFlatShadingEnabled()) + cache->surfaceObject()->updateCoarseRow(dstArray, row - sampleSpace.y()); + else + cache->surfaceObject()->updateSmoothRow(dstArray, row - sampleSpace.y()); } if (updateBuffers) cache->surfaceObject()->uploadBuffers(); @@ -385,13 +384,10 @@ void Surface3DRenderer::updateItem(const QVectorat(point.y())->at(point.x()); - if (cache->isFlatShadingEnabled()) { - cache->surfaceObject()->updateCoarseItem(dstArray, y, x, m_heightNormalizer, - m_axisCacheY.min()); - } else { - cache->surfaceObject()->updateSmoothItem(dstArray, y, x, m_heightNormalizer, - m_axisCacheY.min()); - } + if (cache->isFlatShadingEnabled()) + cache->surfaceObject()->updateCoarseItem(dstArray, y, x); + else + cache->surfaceObject()->updateSmoothItem(dstArray, y, x); } if (updateBuffers) cache->surfaceObject()->uploadBuffers(); @@ -407,10 +403,17 @@ void Surface3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orienta { Abstract3DRenderer::updateAxisRange(orientation, min, max); - if (orientation == QAbstract3DAxis::AxisOrientationY) { - foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) - cache->setObjectDirty(true); - } + foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) + cache->setObjectDirty(true); +} + +void Surface3DRenderer::updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation, + QValue3DAxisFormatter *formatter) +{ + Abstract3DRenderer::updateAxisFormatter(orientation, formatter); + + foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) + cache->setObjectDirty(true); } void Surface3DRenderer::updateSliceDataModel(const QPoint &point) @@ -556,19 +559,27 @@ void Surface3DRenderer::updateSliceObject(SurfaceSeriesRenderCache *cache, const QSurfaceDataRow *sliceRow; QSurfaceDataArray &dataArray = cache->dataArray(); float adjust = (0.025f * m_heightNormalizer) / 2.0f; - float stepDown = 2.0f * adjust; + float doubleAdjust = 2.0f * adjust; + bool flipZX = false; + float zBack; + float zFront; if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow)) { QSurfaceDataRow *src = dataArray.at(row); sliceRow = new QSurfaceDataRow(src->size()); + zBack = m_axisCacheZ.min(); + zFront = m_axisCacheZ.max(); for (int i = 0; i < sliceRow->size(); i++) - (*sliceRow)[i].setPosition(QVector3D(src->at(i).x(), src->at(i).y() + adjust, -1.0f)); + (*sliceRow)[i].setPosition(QVector3D(src->at(i).x(), src->at(i).y() + adjust, zFront)); } else { + flipZX = true; const QRect &sampleSpace = cache->sampleSpace(); sliceRow = new QSurfaceDataRow(sampleSpace.height()); + zBack = m_axisCacheX.min(); + zFront = m_axisCacheX.max(); for (int i = 0; i < sampleSpace.height(); i++) { (*sliceRow)[i].setPosition(QVector3D(dataArray.at(i)->at(column).z(), dataArray.at(i)->at(column).y() + adjust, - -1.0f)); + zFront)); } } sliceDataArray << sliceRow; @@ -577,27 +588,21 @@ void Surface3DRenderer::updateSliceObject(SurfaceSeriesRenderCache *cache, const QSurfaceDataRow *duplicateRow = new QSurfaceDataRow(*sliceRow); for (int i = 0; i < sliceRow->size(); i++) { (*sliceRow)[i].setPosition(QVector3D(sliceRow->at(i).x(), - sliceRow->at(i).y() - stepDown, - 1.0f)); + sliceRow->at(i).y() - doubleAdjust, + zBack)); } sliceDataArray << duplicateRow; QRect sliceRect(0, 0, sliceRow->size(), 2); if (sliceRow->size() > 0) { - if (cache->isFlatShadingEnabled()) { - cache->sliceSurfaceObject()->setUpData(sliceDataArray, sliceRect, - m_heightNormalizer, - m_axisCacheY.min(), true); - } else { - cache->sliceSurfaceObject()->setUpSmoothData(sliceDataArray, sliceRect, - m_heightNormalizer, - m_axisCacheY.min(), true); - } + if (cache->isFlatShadingEnabled()) + cache->sliceSurfaceObject()->setUpData(sliceDataArray, sliceRect, true, flipZX); + else + cache->sliceSurfaceObject()->setUpSmoothData(sliceDataArray, sliceRect, true, flipZX); } } -QRect Surface3DRenderer::calculateSampleRect(SurfaceSeriesRenderCache *cache, - const QSurfaceDataArray &array) +QRect Surface3DRenderer::calculateSampleRect(const QSurfaceDataArray &array) { QRect sampleSpace; @@ -673,17 +678,6 @@ QRect Surface3DRenderer::calculateSampleRect(SurfaceSeriesRenderCache *cache, m_visibleColumnRange = m_maxVisibleColumnValue - m_minVisibleColumnValue; m_visibleRowRange = m_maxVisibleRowValue - m_minVisibleRowValue; - GLfloat surfaceScaleX = m_scaleX * m_visibleColumnRange / m_areaSize.width(); - GLfloat surfaceScaleZ = m_scaleZ * m_visibleRowRange / m_areaSize.height(); - GLfloat axis2XCenterX = axisMinX + axisMaxX; - GLfloat axis2XCenterZ = axisMinZ + axisMaxZ; - GLfloat data2XCenterX = GLfloat(m_minVisibleColumnValue + m_maxVisibleColumnValue); - GLfloat data2XCenterZ = GLfloat(m_minVisibleRowValue + m_maxVisibleRowValue); - GLfloat surfaceOffsetX = m_scaleX * (data2XCenterX - axis2XCenterX) / m_areaSize.width(); - GLfloat surfaceOffsetZ = -m_scaleZ * (data2XCenterZ - axis2XCenterZ) / m_areaSize.height(); - - cache->setScale(QVector3D(surfaceScaleX, 1.0f, surfaceScaleZ)); - cache->setOffset(QVector3D(surfaceOffsetX, 0.0f, surfaceOffsetZ)); return sampleSpace; } @@ -714,6 +708,13 @@ void Surface3DRenderer::render(GLuint defaultFboHandle) // Handle GL state setup for FBO buffers and clearing of the render surface Abstract3DRenderer::render(defaultFboHandle); + if (m_axisCacheX.positionsDirty()) + m_axisCacheX.updateAllPositions(); + if (m_axisCacheY.positionsDirty()) + m_axisCacheY.updateAllPositions(); + if (m_axisCacheZ.positionsDirty()) + m_axisCacheZ.updateAllPositions(); + drawScene(defaultFboHandle); if (m_cachedIsSlicingActivated) drawSlicedScene(); @@ -766,6 +767,7 @@ void Surface3DRenderer::drawSlicedScene() const Q3DCamera *activeCamera = m_cachedScene->activeCamera(); bool rowMode = m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow); + AxisRenderCache &sliceCache = rowMode ? m_axisCacheX : m_axisCacheZ; GLfloat scaleXBackground = 0.0f; @@ -780,24 +782,16 @@ void Surface3DRenderer::drawSlicedScene() drawGrid = true; } - GLfloat scaleX = 0.0f; - GLfloat offset = 0.0f; - if (rowMode) { - scaleX = cache->scale().x(); + if (rowMode) scaleXBackground = m_scaleXWithBackground; - offset = cache->offset().x(); - } else { - scaleX = cache->scale().z(); + else scaleXBackground = m_scaleZWithBackground; - offset = -cache->offset().z(); - } QMatrix4x4 MVPMatrix; QMatrix4x4 modelMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(offset, 0.0f, 0.0f); - QVector3D scaling(scaleX, 1.0f, sliceZScale); + QVector3D scaling(1.0f, 1.0f, sliceZScale); modelMatrix.scale(scaling); itModelMatrix.scale(scaling); @@ -872,19 +866,16 @@ void Surface3DRenderer::drawSlicedScene() lineShader->setUniformValue(lineShader->lightColor(), lightColor); // Horizontal lines + int gridLineCount = m_axisCacheY.gridLineCount(); if (m_axisCacheY.segmentCount() > 0) { QVector3D gridLineScaleX(scaleXBackground, gridLineWidth, gridLineWidth); - GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer; - GLfloat linePos = -1.0f; - int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); - - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, linePos, -sliceZScale); + modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), -1.0f); modelMatrix.scale(gridLineScaleX); itModelMatrix.scale(gridLineScaleX); @@ -903,33 +894,18 @@ void Surface3DRenderer::drawSlicedScene() #else m_drawer->drawLine(lineShader); #endif - - linePos += lineStep; } } // Vertical lines QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth); - int lastSegment; - GLfloat lineStep; - GLfloat linePos; - if (rowMode) { - lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor; - lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); - linePos = m_scaleX; - } else { - lineStep = -2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor; - lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); - linePos = m_scaleZ; - } - - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos, 0.0f, -sliceZScale); + modelMatrix.translate(sliceCache.gridLinePosition(line), 0.0f, -1.0f); modelMatrix.scale(gridLineScaleY); itModelMatrix.scale(gridLineScaleY); #if (defined QT_OPENGL_ES_2) @@ -951,8 +927,6 @@ void Surface3DRenderer::drawSlicedScene() #else m_drawer->drawLine(lineShader); #endif - - linePos += lineStep; } } @@ -965,16 +939,15 @@ void Surface3DRenderer::drawSlicedScene() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Y Labels to back wall - GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer; - GLfloat labelPos = -1.0f; int labelNbr = 0; QVector3D positionComp(0.0f, 0.0f, 0.0f); QVector3D rotation(0.0f, 0.0f, 0.0f); - QVector3D labelTrans = QVector3D(scaleXBackground + labelMargin, labelPos, 0.0f); - for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + QVector3D labelTrans = QVector3D(scaleXBackground + labelMargin, 0.0f, 0.0f); + int labelCount = m_axisCacheY.labelCount(); + for (int label = 0; label < labelCount; label++) { if (m_axisCacheY.labelItems().size() > labelNbr) { - labelTrans.setY(labelPos); + labelTrans.setY(m_axisCacheY.labelPosition(label)); const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); // Draw the label here @@ -985,40 +958,25 @@ void Surface3DRenderer::drawSlicedScene() true, true, Drawer::LabelMid, Qt::AlignRight, true); } labelNbr++; - labelPos += posStep; } // X Labels to ground - int countLabelItems; - int lastSegment; - if (rowMode) { - posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor; - labelPos = -m_scaleX; - lastSegment = m_axisCacheX.segmentCount(); - countLabelItems = m_axisCacheX.labelItems().size(); - } else { - posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor; - labelPos = -m_scaleZ; - lastSegment = m_axisCacheZ.segmentCount(); - countLabelItems = m_axisCacheZ.labelItems().size(); - } + int countLabelItems = sliceCache.labelItems().size(); labelNbr = 0; positionComp.setY(-0.1f); rotation.setZ(-45.0f); labelTrans.setY(-backgroundMargin); - for (int segment = 0; segment <= lastSegment; segment++) { + labelCount = sliceCache.labelCount(); + for (int label = 0; label < labelCount; label++) { if (countLabelItems > labelNbr) { // Draw the label here - labelTrans.setX(labelPos); + labelTrans.setX(sliceCache.labelPosition(label)); m_dummyRenderItem.setTranslation(labelTrans); LabelItem *axisLabelItem; - if (rowMode) - axisLabelItem = m_axisCacheX.labelItems().at(labelNbr); - else - axisLabelItem = m_axisCacheZ.labelItems().at(labelNbr); + axisLabelItem = sliceCache.labelItems().at(labelNbr); m_drawer->drawLabel(m_dummyRenderItem, *axisLabelItem, viewMatrix, projectionMatrix, positionComp, rotation, 0, QAbstract3DGraph::SelectionRow, @@ -1026,23 +984,16 @@ void Surface3DRenderer::drawSlicedScene() false, false, Drawer::LabelBelow, Qt::AlignBottom, true); } labelNbr++; - labelPos += posStep; } // Draw labels for axes AbstractRenderItem *dummyItem(0); positionComp.setY(m_autoScaleAdjustment); - if (rowMode) { - m_drawer->drawLabel(*dummyItem, m_axisCacheX.titleItem(), viewMatrix, projectionMatrix, - positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelBottom, - Qt::AlignCenter, true); - } else { - m_drawer->drawLabel(*dummyItem, m_axisCacheZ.titleItem(), viewMatrix, projectionMatrix, - positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, - m_labelObj, activeCamera, false, false, Drawer::LabelBottom, - Qt::AlignCenter, true); - } + m_drawer->drawLabel(*dummyItem, sliceCache.titleItem(), viewMatrix, projectionMatrix, + positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader, + m_labelObj, activeCamera, false, false, Drawer::LabelBottom, + Qt::AlignCenter, true); + // Y-axis label labelTrans = QVector3D(-scaleXBackground - labelMargin, 0.0f, 0.0f); m_dummyRenderItem.setTranslation(labelTrans); @@ -1150,8 +1101,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; - modelMatrix.translate(cache->offset()); - modelMatrix.scale(cache->scale()); MVPMatrix = depthProjectionViewMatrix * modelMatrix; cache->setMVPMatrix(MVPMatrix); m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix); @@ -1244,9 +1193,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; - modelMatrix.translate(cache->offset()); - modelMatrix.scale(cache->scale()); - MVPMatrix = projectionViewMatrix * modelMatrix; m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix); @@ -1293,10 +1239,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(cache->offset()); - modelMatrix.scale(cache->scale()); - itModelMatrix.scale(cache->scale()); - #ifdef SHOW_DEPTH_TEXTURE_SCENE MVPMatrix = depthProjectionViewMatrix * modelMatrix; #else @@ -1508,16 +1450,14 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) // Rows (= Z) if (m_axisCacheZ.segmentCount() > 0) { // Floor lines - GLfloat lineStep = 2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor; - GLfloat linePos = m_scaleZ; // Start line - int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); + int gridLineCount = m_axisCacheZ.gridLineCount(); - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, yFloorLinePosition, linePos); + modelMatrix.translate(0.0f, yFloorLinePosition, m_axisCacheZ.gridLinePosition(line)); modelMatrix.scale(gridLineScaleX); itModelMatrix.scale(gridLineScaleX); @@ -1547,22 +1487,20 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos -= lineStep; } // Side wall lines GLfloat lineXTrans = m_scaleXWithBackground - gridLineOffset; - linePos = m_scaleZ; // Start line if (!m_xFlipped) lineXTrans = -lineXTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(lineXTrans, 0.0f, linePos); + modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line)); modelMatrix.scale(gridLineScaleY); itModelMatrix.scale(gridLineScaleY); @@ -1597,7 +1535,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos -= lineStep; } } @@ -1607,16 +1544,14 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) lineXRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f); #endif // Floor lines - GLfloat lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor; - GLfloat linePos = m_scaleX; - int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); + int gridLineCount = m_axisCacheX.gridLineCount(); - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos, yFloorLinePosition, 0.0f); + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition, 0.0f); modelMatrix.scale(gridLineScaleZ); itModelMatrix.scale(gridLineScaleZ); @@ -1646,22 +1581,20 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } // Back wall lines GLfloat lineZTrans = m_scaleZWithBackground - gridLineOffset; - linePos = m_scaleX; if (!m_zFlipped) lineZTrans = -lineZTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos, 0.0f, lineZTrans); + modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans); modelMatrix.scale(gridLineScaleY); itModelMatrix.scale(gridLineScaleY); @@ -1698,28 +1631,25 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } } // Horizontal wall lines if (m_axisCacheY.segmentCount() > 0) { // Back wall - GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer; - GLfloat linePos = -1.0f; - int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + int gridLineCount = m_axisCacheY.gridLineCount(); GLfloat lineZTrans = m_scaleZWithBackground - gridLineOffset; if (!m_zFlipped) lineZTrans = -lineZTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, linePos, lineZTrans); + modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), lineZTrans); modelMatrix.scale(gridLineScaleX); itModelMatrix.scale(gridLineScaleX); @@ -1751,23 +1681,20 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } // Side wall - linePos = -1.0f; - lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); GLfloat lineXTrans = m_scaleXWithBackground - gridLineOffset; if (!m_xFlipped) lineXTrans = -lineXTrans; - for (int segment = 0; segment <= lastSegment; segment++) { + for (int line = 0; line < gridLineCount; line++) { QMatrix4x4 modelMatrix; QMatrix4x4 MVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(lineXTrans, linePos, 0.0f); + modelMatrix.translate(lineXTrans, m_axisCacheY.gridLinePosition(line), 0.0f); modelMatrix.scale(gridLineScaleZ); itModelMatrix.scale(gridLineScaleZ); @@ -1797,7 +1724,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) #else m_drawer->drawLine(lineShader); #endif - linePos += lineStep; } } } @@ -1812,9 +1738,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) // Z Labels QVector3D positionZComp(0.0f, 0.0f, 0.0f); if (m_axisCacheZ.segmentCount() > 0) { - GLfloat posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor; - GLfloat labelPos = m_scaleZ; - int lastSegment = m_axisCacheZ.segmentCount(); + int labelCount = m_axisCacheZ.labelItems().size(); int labelNbr = 0; GLfloat labelXTrans = m_scaleXWithBackground + labelMargin; GLfloat labelYTrans = -backgroundMargin; @@ -1835,14 +1759,14 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) } QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, - labelPos); + 0.0f); QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ); - for (int segment = 0; segment <= lastSegment; segment++) { + for (int label = 0; label < labelCount; label++) { if (m_axisCacheZ.labelItems().size() > labelNbr) { - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); // Draw the label here - labelTrans.setZ(labelPos); + labelTrans.setZ(m_axisCacheZ.labelPosition(label)); m_dummyRenderItem.setTranslation(labelTrans); const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr); @@ -1852,14 +1776,11 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) true, true, Drawer::LabelMid, alignment); } labelNbr++; - labelPos -= posStep; } } // X Labels if (m_axisCacheX.segmentCount() > 0) { - GLfloat posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor; - GLfloat labelPos = -m_scaleX; - int lastSegment = m_axisCacheX.segmentCount(); + int labelCount = m_axisCacheX.labelItems().size(); int labelNbr = 0; GLfloat labelZTrans = m_scaleZWithBackground + labelMargin; @@ -1879,16 +1800,16 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) rotLabelY += 180.0f; labelYTrans = -labelYTrans; } - QVector3D labelTrans = QVector3D(labelPos, + QVector3D labelTrans = QVector3D(0.0f, labelYTrans, labelZTrans); QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ); - for (int segment = 0; segment <= lastSegment; segment++) { + for (int label = 0; label < labelCount; label++) { if (m_axisCacheX.labelItems().size() > labelNbr) { - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); // Draw the label here - labelTrans.setX(labelPos); + labelTrans.setX(m_axisCacheX.labelPosition(label)); m_dummyRenderItem.setTranslation(labelTrans); const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); @@ -1898,13 +1819,12 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) true, true, Drawer::LabelMid, alignment); } labelNbr++; - labelPos += posStep; } } // Y Labels if (m_axisCacheY.segmentCount() > 0) { - GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer; - GLfloat labelPos = -1.0f; + int labelCount = m_axisCacheY.labelItems().size(); + int labelNbr = 0; GLfloat labelXTrans = m_scaleXWithBackground; GLfloat labelZTrans = m_scaleZWithBackground; @@ -1943,14 +1863,15 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) QVector3D labelRotateVectorSide(rotLabelX, rotLabelY, rotLabelZ); QVector3D labelTransSide(-labelXTrans - labelMarginXTrans, 0.0f, -labelZTrans); - for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + for (int label = 0; label < labelCount; label++) { if (m_axisCacheY.labelItems().size() > labelNbr) { const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + const GLfloat labelYTrans = m_axisCacheY.labelPosition(label); - glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f); + glPolygonOffset(GLfloat(label) / -10.0f, 1.0f); // Back wall - labelTransBack.setY(labelPos); + labelTransBack.setY(labelYTrans); m_dummyRenderItem.setTranslation(labelTransBack); m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, positionZComp, labelRotateVectorBack, 0, m_cachedSelectionMode, @@ -1958,7 +1879,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) true, true, Drawer::LabelMid, alignmentBack); // Side wall - labelTransSide.setY(labelPos); + labelTransSide.setY(labelYTrans); m_dummyRenderItem.setTranslation(labelTransSide); m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, positionZComp, labelRotateVectorSide, 0, m_cachedSelectionMode, @@ -1966,7 +1887,6 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle) true, true, Drawer::LabelMid, alignmentSide); } labelNbr++; - labelPos += posStep; } } glDisable(GL_POLYGON_OFFSET_FILL); @@ -2123,8 +2043,14 @@ void Surface3DRenderer::calculateSceneScalingFactors() m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); m_scaleX = aspectRatio * m_areaSize.width() / m_scaleFactor; m_scaleZ = aspectRatio * m_areaSize.height() / m_scaleFactor; - m_scaleXWithBackground = m_scaleX * backgroundMargin; - m_scaleZWithBackground = m_scaleZ * backgroundMargin; + m_scaleXWithBackground = m_scaleX + backgroundMargin - 1.0f; + m_scaleZWithBackground = m_scaleZ + backgroundMargin - 1.0f; + + float factorScaler = 2.0f * aspectRatio / m_scaleFactor; + m_axisCacheX.setScale(factorScaler * m_areaSize.width()); + m_axisCacheZ.setScale(-factorScaler * m_areaSize.height()); + m_axisCacheX.setTranslate(-m_axisCacheX.scale() / 2.0f); + m_axisCacheZ.setTranslate(-m_axisCacheZ.scale() / 2.0f); } void Surface3DRenderer::checkFlatSupport(SurfaceSeriesRenderCache *cache) @@ -2144,13 +2070,10 @@ void Surface3DRenderer::updateObjects(SurfaceSeriesRenderCache *cache, bool dime const QRect &sampleSpace = cache->sampleSpace(); - if (cache->isFlatShadingEnabled()) { - cache->surfaceObject()->setUpData(dataArray, sampleSpace, m_heightNormalizer, - m_axisCacheY.min(), dimensionChanged); - } else { - cache->surfaceObject()->setUpSmoothData(dataArray, sampleSpace, m_heightNormalizer, - m_axisCacheY.min(), dimensionChanged); - } + if (cache->isFlatShadingEnabled()) + cache->surfaceObject()->setUpData(dataArray, sampleSpace, dimensionChanged); + else + cache->surfaceObject()->setUpSmoothData(dataArray, sampleSpace, dimensionChanged); } void Surface3DRenderer::updateSelectedPoint(const QPoint &position, const QSurface3DSeries *series) @@ -2226,9 +2149,6 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co if (column < 0 || row < 0) return; - QSurfaceDataArray &dataArray = cache->dataArray(); - float value = dataArray.at(row)->at(column).y(); - SelectionPointer *slicePointer = cache->sliceSelectionPointer(); if (!slicePointer && m_cachedIsSlicingActivated) { slicePointer = new SelectionPointer(m_drawer); @@ -2240,26 +2160,23 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co cache->setMainSelectionPointer(mainPointer); } - const QVector3D &scale = cache->scale(); - const QVector3D &offset = cache->offset(); QString selectionLabel; if (label) - selectionLabel = createSelectionLabel(cache, value, column, row); + selectionLabel = createSelectionLabel(cache, column, row); if (m_cachedIsSlicingActivated) { - QVector3D subPos; + QVector3D subPosFront; + QVector3D subPosBack; if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow)) { - subPos = cache->sliceSurfaceObject()->vertexAt(column, 0); - subPos *= QVector3D(scale.x(), 1.0f, 0.0f); - subPos += QVector3D(offset.x(), 0.0f, 0.0f); + subPosFront = cache->sliceSurfaceObject()->vertexAt(column, 0); + subPosBack = cache->sliceSurfaceObject()->vertexAt(column, 1); } else if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionColumn)) { - subPos = cache->sliceSurfaceObject()->vertexAt(row, 0); - subPos *= QVector3D(scale.z(), 1.0f, 0.0f); - subPos += QVector3D(-offset.z(), 0.0f, 0.0f); + subPosFront = cache->sliceSurfaceObject()->vertexAt(row, 0); + subPosBack = cache->sliceSurfaceObject()->vertexAt(row, 1); } slicePointer->updateBoundingRect(m_secondarySubViewport); slicePointer->updateSliceData(true, m_autoScaleAdjustment); - slicePointer->setPosition(subPos); + slicePointer->setPosition((subPosFront + subPosBack) / 2.0f); slicePointer->setLabel(selectionLabel); slicePointer->setPointerObject(cache->object()); slicePointer->setHighlightColor(cache->singleHighlightColor()); @@ -2270,8 +2187,6 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co QVector3D mainPos; mainPos = cache->surfaceObject()->vertexAt(column, row); - mainPos *= scale; - mainPos += offset; mainPointer->updateBoundingRect(m_primarySubViewport); mainPointer->updateSliceData(false, m_autoScaleAdjustment); mainPointer->setPosition(mainPos); @@ -2307,7 +2222,7 @@ QPoint Surface3DRenderer::selectionIdToSurfacePoint(uint id) return QPoint(row, column); } -QString Surface3DRenderer::createSelectionLabel(SurfaceSeriesRenderCache *cache, float value, +QString Surface3DRenderer::createSelectionLabel(SurfaceSeriesRenderCache *cache, int column, int row) { QSurfaceDataArray &dataArray = cache->dataArray(); @@ -2325,26 +2240,18 @@ QString Surface3DRenderer::createSelectionLabel(SurfaceSeriesRenderCache *cache, labelText.replace(zTitleTag, m_axisCacheZ.title()); if (labelText.contains(xLabelTag)) { - QString labelFormat = m_axisCacheX.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - dataArray.at(row)->at(column).x()); + QString valueLabelText = m_axisCacheX.formatter()->stringForValue( + dataArray.at(row)->at(column).x(), m_axisCacheX.labelFormat()); labelText.replace(xLabelTag, valueLabelText); } if (labelText.contains(yLabelTag)) { - QString labelFormat = m_axisCacheY.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, value); + QString valueLabelText = m_axisCacheY.formatter()->stringForValue( + dataArray.at(row)->at(column).y(), m_axisCacheY.labelFormat()); labelText.replace(yLabelTag, valueLabelText); } if (labelText.contains(zLabelTag)) { - QString labelFormat = m_axisCacheZ.labelFormat(); - if (labelFormat.isEmpty()) - labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, - dataArray.at(row)->at(column).z()); + QString valueLabelText = m_axisCacheZ.formatter()->stringForValue( + dataArray.at(row)->at(column).z(), m_axisCacheZ.labelFormat()); labelText.replace(zLabelTag, valueLabelText); } diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h index 5d93ee4a..9fd5d0d9 100644 --- a/src/datavisualization/engine/surface3drenderer_p.h +++ b/src/datavisualization/engine/surface3drenderer_p.h @@ -112,6 +112,8 @@ public: void updateRows(const QVector &rows); void updateItem(const QVector &points); void updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min, float max); + void updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation, + QValue3DAxisFormatter *formatter); void updateScene(Q3DScene *scene); void updateSlicingActive(bool isSlicing); void updateSelectedPoint(const QPoint &position, const QSurface3DSeries *series); @@ -138,7 +140,7 @@ private: void updateShadowQuality(QAbstract3DGraph::ShadowQuality quality); void updateTextures(); void initShaders(const QString &vertexShader, const QString &fragmentShader); - QRect calculateSampleRect(SurfaceSeriesRenderCache *cache, const QSurfaceDataArray &array); + QRect calculateSampleRect(const QSurfaceDataArray &array); void loadBackgroundMesh(); void loadLabelMesh(); void drawScene(GLuint defaultFboHandle); @@ -156,7 +158,7 @@ private: void surfacePointSelected(const QPoint &point); void updateSelectionPoint(SurfaceSeriesRenderCache *cache, const QPoint &point, bool label); QPoint selectionIdToSurfacePoint(uint id); - QString createSelectionLabel(SurfaceSeriesRenderCache *cache, float value, int column, int row); + QString createSelectionLabel(SurfaceSeriesRenderCache *cache, int column, int row); #if !defined(QT_OPENGL_ES_2) void loadGridLineMesh(); void updateDepthBuffer(); @@ -164,6 +166,8 @@ private: void emitSelectedPointChanged(QPoint position); Q_DISABLE_COPY(Surface3DRenderer) + + friend class SurfaceObject; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/engine/surfaceseriesrendercache.cpp b/src/datavisualization/engine/surfaceseriesrendercache.cpp index ba25d71d..ad81f714 100644 --- a/src/datavisualization/engine/surfaceseriesrendercache.cpp +++ b/src/datavisualization/engine/surfaceseriesrendercache.cpp @@ -25,20 +25,18 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION -SurfaceSeriesRenderCache::SurfaceSeriesRenderCache() +SurfaceSeriesRenderCache::SurfaceSeriesRenderCache(Surface3DRenderer *renderer) : m_surfaceVisible(false), m_surfaceGridVisible(false), m_surfaceFlatShading(true), - m_surfaceObj(new SurfaceObject), - m_sliceSurfaceObj(new SurfaceObject), + m_surfaceObj(new SurfaceObject(renderer)), + m_sliceSurfaceObj(new SurfaceObject(renderer)), m_sampleSpace(QRect(0, 0, 0 , 0)), m_selectionTexture(0), m_selectionIdStart(0), m_selectionIdEnd(0), m_flatChangeAllowed(true), m_flatStatusDirty(false), - m_scale(QVector3D(1.0f, 1.0f, 1.0f)), - m_offset(QVector3D(0.0f, 0.0f, 0.0f)), m_sliceSelectionPointer(0), m_mainSelectionPointer(0), m_slicePointerActive(false), diff --git a/src/datavisualization/engine/surfaceseriesrendercache_p.h b/src/datavisualization/engine/surfaceseriesrendercache_p.h index 2dda0670..bab16201 100644 --- a/src/datavisualization/engine/surfaceseriesrendercache_p.h +++ b/src/datavisualization/engine/surfaceseriesrendercache_p.h @@ -41,13 +41,14 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION class Abstract3DRenderer; +class Surface3DRenderer; class ObjectHelper; class TextureHelper; class SurfaceSeriesRenderCache : public SeriesRenderCache { public: - SurfaceSeriesRenderCache(); + SurfaceSeriesRenderCache(Surface3DRenderer *renderer); virtual ~SurfaceSeriesRenderCache(); void populate(QSurface3DSeries *series, Abstract3DRenderer *renderer); @@ -81,10 +82,6 @@ public: selection <= m_selectionIdEnd; } inline bool isFlatStatusDirty() const { return m_flatStatusDirty; } inline void setFlatStatusDirty(bool status) { m_flatStatusDirty = status; } - inline void setScale(const QVector3D &scale) { m_scale = scale; } - inline const QVector3D &scale() const { return m_scale; } - inline void setOffset(const QVector3D &offset) { m_offset = offset; } - inline const QVector3D &offset() const { return m_offset; } // m_MVPMatrix is volatile, used only for optimizing rendering a bit inline void setMVPMatrix(const QMatrix4x4 &matrix) { m_MVPMatrix = matrix; } inline const QMatrix4x4 &MVPMatrix() { return m_MVPMatrix; } @@ -113,8 +110,6 @@ protected: uint m_selectionIdEnd; bool m_flatChangeAllowed; bool m_flatStatusDirty; - QVector3D m_scale; - QVector3D m_offset; QMatrix4x4 m_MVPMatrix; SelectionPointer *m_sliceSelectionPointer; SelectionPointer *m_mainSelectionPointer; diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp index 9bcdfee2..b21961cb 100644 --- a/src/datavisualization/utils/surfaceobject.cpp +++ b/src/datavisualization/utils/surfaceobject.cpp @@ -18,16 +18,21 @@ #include "surfaceobject_p.h" #include "abstractobjecthelper_p.h" +#include "surface3drenderer_p.h" #include QT_BEGIN_NAMESPACE_DATAVISUALIZATION -SurfaceObject::SurfaceObject() +SurfaceObject::SurfaceObject(Surface3DRenderer *renderer) : m_surfaceType(Undefined), m_columns(0), m_rows(0), - m_gridIndexCount(0) + m_gridIndexCount(0), + m_axisCacheX(renderer->m_axisCacheX), + m_axisCacheY(renderer->m_axisCacheY), + m_axisCacheZ(renderer->m_axisCacheZ) + { m_indicesType = GL_UNSIGNED_INT; initializeOpenGLFunctions(); @@ -45,16 +50,11 @@ SurfaceObject::~SurfaceObject() } void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, - GLfloat yRange, GLfloat yMin, bool changeGeometry) + bool changeGeometry, bool flipXZ) { m_columns = space.width(); m_rows = space.height(); int totalSize = m_rows * m_columns; - GLfloat xMin = dataArray.at(0)->at(0).x(); - GLfloat zMin = dataArray.at(0)->at(0).z(); - GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; - GLfloat yNormalizer = yRange / 2.0f; - GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; GLfloat uvX = 1.0f / GLfloat(m_columns - 1); GLfloat uvY = 1.0f / GLfloat(m_rows - 1); @@ -68,21 +68,31 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR if (changeGeometry) uvs.resize(totalSize); int totalIndex = 0; + + AxisRenderCache &xCache = flipXZ ? m_axisCacheZ : m_axisCacheX; + AxisRenderCache &zCache = flipXZ ? m_axisCacheX : m_axisCacheZ; + for (int i = 0; i < m_rows; i++) { const QSurfaceDataRow &p = *dataArray.at(i); for (int j = 0; j < m_columns; j++) { const QSurfaceDataItem &data = p.at(j); - float normalizedX = ((data.x() - xMin) / xNormalizer); - float normalizedY = ((data.y() - yMin) / yNormalizer); - float normalizedZ = ((data.z() - zMin) / zNormalizer); - m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, - normalizedZ + 1.0f); + float normalizedX = xCache.positionAt(data.x()); + float normalizedY = m_axisCacheY.positionAt(data.y()); + float normalizedZ = zCache.positionAt(data.z()); + m_vertices[totalIndex] = QVector3D(normalizedX, normalizedY, normalizedZ); if (changeGeometry) uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY); totalIndex++; } } + if (flipXZ) { + for (int i = 0; i < m_vertices.size(); i++) { + m_vertices[i].setX(-m_vertices.at(i).x()); + m_vertices[i].setZ(-m_vertices.at(i).z()); + } + } + // Create normals int rowLimit = m_rows - 1; int colLimit = m_columns - 1; @@ -123,24 +133,18 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR createBuffers(m_vertices, uvs, m_normals, 0, changeGeometry); } -void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowIndex, - GLfloat yRange, GLfloat yMin) +void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowIndex) { - GLfloat xMin = dataArray.at(0)->at(0).x(); - GLfloat zMin = dataArray.at(0)->at(0).z(); - GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; - GLfloat yNormalizer = yRange / 2.0f; - GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; - // Update vertices int p = rowIndex * m_columns; const QSurfaceDataRow &dataRow = *dataArray.at(rowIndex); + for (int j = 0; j < m_columns; j++) { const QSurfaceDataItem &data = dataRow.at(j); - float normalizedX = ((data.x() - xMin) / xNormalizer); - float normalizedY = ((data.y() - yMin) / yNormalizer); - float normalizedZ = ((data.z() - zMin) / zNormalizer); - m_vertices[p++] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); + float normalizedX = m_axisCacheX.positionAt(data.x()); + float normalizedY = m_axisCacheY.positionAt(data.y()); + float normalizedZ = m_axisCacheZ.positionAt(data.z()); + m_vertices[p++] = QVector3D(normalizedX, normalizedY, normalizedZ); } // Create normals @@ -183,22 +187,14 @@ void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowI } } -void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row, - int column, GLfloat yRange, GLfloat yMin) +void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row, int column) { - GLfloat xMin = dataArray.at(0)->at(0).x(); - GLfloat zMin = dataArray.at(0)->at(0).z(); - GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; - GLfloat yNormalizer = yRange / 2.0f; - GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; - // Update a vertice const QSurfaceDataItem &data = dataArray.at(row)->at(column); - float normalizedX = ((data.x() - xMin) / xNormalizer); - float normalizedY = ((data.y() - yMin) / yNormalizer); - float normalizedZ = ((data.z() - zMin) / zNormalizer); - m_vertices[row * m_columns + column] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, - normalizedZ + 1.0f); + float normalizedX = m_axisCacheX.positionAt(data.x()); + float normalizedY = m_axisCacheY.positionAt(data.y()); + float normalizedZ = m_axisCacheZ.positionAt(data.z()); + m_vertices[row * m_columns + column] = QVector3D(normalizedX, normalizedY, normalizedZ); // Create normals int startRow = row; @@ -321,16 +317,11 @@ void SurfaceObject::createSmoothGridlineIndices(int x, int y, int endX, int endY } void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space, - GLfloat yRange, GLfloat yMin, bool changeGeometry) + bool changeGeometry, bool flipXZ) { m_columns = space.width(); m_rows = space.height(); int totalSize = m_rows * m_columns * 2; - GLfloat xMin = dataArray.at(0)->at(0).x(); - GLfloat zMin = dataArray.at(0)->at(0).z(); - GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; - GLfloat yNormalizer = yRange / 2.0f; - GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; GLfloat uvX = 1.0f / GLfloat(m_columns - 1); GLfloat uvY = 1.0f / GLfloat(m_rows - 1); @@ -350,15 +341,17 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s int doubleColumns = m_columns * 2 - 2; int rowColLimit = rowLimit * doubleColumns; + AxisRenderCache &xCache = flipXZ ? m_axisCacheZ : m_axisCacheX; + AxisRenderCache &zCache = flipXZ ? m_axisCacheX : m_axisCacheZ; + for (int i = 0; i < m_rows; i++) { const QSurfaceDataRow &row = *dataArray.at(i); for (int j = 0; j < m_columns; j++) { const QSurfaceDataItem &data = row.at(j); - float normalizedX = ((data.x() - xMin) / xNormalizer); - float normalizedY = ((data.y() - yMin) / yNormalizer); - float normalizedZ = ((data.z() - zMin) / zNormalizer); - m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, - normalizedZ + 1.0f); + float normalizedX = xCache.positionAt(data.x()); + float normalizedY = m_axisCacheY.positionAt(data.y()); + float normalizedZ = zCache.positionAt(data.z()); + m_vertices[totalIndex] = QVector3D(normalizedX, normalizedY, normalizedZ); if (changeGeometry) uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY); @@ -373,6 +366,13 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s } } + if (flipXZ) { + for (int i = 0; i < m_vertices.size(); i++) { + m_vertices[i].setX(-m_vertices.at(i).x()); + m_vertices[i].setZ(-m_vertices.at(i).z()); + } + } + // Create normals & indices table GLint *indices = 0; int p = 0; @@ -421,26 +421,20 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s delete[] indices; } -void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex, - GLfloat yRange, GLfloat yMin) +void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex) { - GLfloat xMin = dataArray.at(0)->at(0).x(); - GLfloat zMin = dataArray.at(0)->at(0).z(); - GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; - GLfloat yNormalizer = yRange / 2.0f; - GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; - int colLimit = m_columns - 1; int doubleColumns = m_columns * 2 - 2; int p = rowIndex * doubleColumns; const QSurfaceDataRow &dataRow = *dataArray.at(rowIndex); + for (int j = 0; j < m_columns; j++) { const QSurfaceDataItem &data = dataRow.at(j); - float normalizedX = ((data.x() - xMin) / xNormalizer); - float normalizedY = ((data.y() - yMin) / yNormalizer); - float normalizedZ = ((data.z() - zMin) / zNormalizer); - m_vertices[p++] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); + float normalizedX = m_axisCacheX.positionAt(data.x()); + float normalizedY = m_axisCacheY.positionAt(data.y()); + float normalizedZ = m_axisCacheZ.positionAt(data.z()); + m_vertices[p++] = QVector3D(normalizedX, normalizedY, normalizedZ); if (j > 0 && j < colLimit) { m_vertices[p] = m_vertices[p - 1]; @@ -472,25 +466,18 @@ void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowI } } -void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row, - int column, GLfloat yRange, GLfloat yMin) +void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row, int column) { - GLfloat xMin = dataArray.at(0)->at(0).x(); - GLfloat zMin = dataArray.at(0)->at(0).z(); - GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; - GLfloat yNormalizer = yRange / 2.0f; - GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; - int colLimit = m_columns - 1; int doubleColumns = m_columns * 2 - 2; // Update a vertice int p = row * doubleColumns + column * 2 - (column > 0); const QSurfaceDataItem &data = dataArray.at(row)->at(column); - float normalizedX = ((data.x() - xMin) / xNormalizer); - float normalizedY = ((data.y() - yMin) / yNormalizer); - float normalizedZ = ((data.z() - zMin) / zNormalizer); - m_vertices[p] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); + float normalizedX = m_axisCacheX.positionAt(data.x()); + float normalizedY = m_axisCacheY.positionAt(data.y()); + float normalizedZ = m_axisCacheZ.positionAt(data.z()); + m_vertices[p] = QVector3D(normalizedX, normalizedY, normalizedZ); p++; if (column > 0 && column < colLimit) diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h index 69cb7e5d..c8f7de95 100644 --- a/src/datavisualization/utils/surfaceobject_p.h +++ b/src/datavisualization/utils/surfaceobject_p.h @@ -37,6 +37,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION +class Surface3DRenderer; +class AxisRenderCache; + class SurfaceObject : public AbstractObjectHelper { public: @@ -47,21 +50,17 @@ public: }; public: - SurfaceObject(); + SurfaceObject(Surface3DRenderer *renderer); ~SurfaceObject(); - void setUpData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, - GLfloat yMin, bool changeGeometry); - void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, - GLfloat yMin, bool changeGeometry); - void updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex, - GLfloat yRange, GLfloat yMin); - void updateSmoothRow(const QSurfaceDataArray &dataArray, int startRow, - GLfloat yRange, GLfloat yMin); - void updateSmoothItem(const QSurfaceDataArray &dataArray, int row, - int column, GLfloat yRange, GLfloat yMin); - void updateCoarseItem(const QSurfaceDataArray &dataArray, int row, - int column, GLfloat yRange, GLfloat yMin); + void setUpData(const QSurfaceDataArray &dataArray, const QRect &space, + bool changeGeometry, bool flipXZ = false); + void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, + bool changeGeometry, bool flipXZ = false); + void updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex); + void updateSmoothRow(const QSurfaceDataArray &dataArray, int startRow); + void updateSmoothItem(const QSurfaceDataArray &dataArray, int row, int column); + void updateCoarseItem(const QSurfaceDataArray &dataArray, int row, int column); void createSmoothIndices(int x, int y, int endX, int endY); void createCoarseIndices(int x, int y, int columns, int rows); void createSmoothGridlineIndices(int x, int y, int endX, int endY); @@ -86,6 +85,10 @@ private: GLuint m_gridIndexCount; QVector m_vertices; QVector m_normals; + // Caches are not owned + AxisRenderCache &m_axisCacheX; + AxisRenderCache &m_axisCacheY; + AxisRenderCache &m_axisCacheZ; }; QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/tests/barstest/chart.cpp b/tests/barstest/chart.cpp index 7374f25f..cf044a45 100644 --- a/tests/barstest/chart.cpp +++ b/tests/barstest/chart.cpp @@ -144,7 +144,7 @@ GraphModifier::GraphModifier(Q3DBars *barchart, QColorDialog *colorDialog) m_dummyData4->setName("Dummy 4"); m_dummyData5->setName("Dummy 5"); - m_temperatureData->setItemLabelFormat(QStringLiteral("@seriesName: @valueTitle for @colLabel @rowLabel: @valueLabel")); + m_temperatureData->setItemLabelFormat(QStringLiteral("@seriesName: @valueTitle for @colLabel @rowLabel: @valueLabel ~ %.4f")); m_temperatureData2->setItemLabelFormat(QStringLiteral("@seriesName: @valueTitle for @colLabel @rowLabel: @valueLabel")); m_genericData->setItemLabelFormat(QStringLiteral("@seriesName: @valueTitle for (@rowIdx, @colIdx): @valueLabel")); @@ -1055,7 +1055,12 @@ void GraphModifier::useLogAxis() // logAxis->formatter()->setBase(10); // logAxis->setSegmentCount(5); // logAxis->setRange(1, 100000); -// m_graph->setValueAxis(logAxis); + // m_graph->setValueAxis(logAxis); +} + +void GraphModifier::changeValueAxisFormat(const QString & text) +{ + m_graph->valueAxis()->setLabelFormat(text); } void GraphModifier::insertRemoveTimerTimeout() diff --git a/tests/barstest/chart.h b/tests/barstest/chart.h index 557270e0..304103cd 100644 --- a/tests/barstest/chart.h +++ b/tests/barstest/chart.h @@ -86,6 +86,7 @@ public: void insertRemoveTestToggle(); void toggleRotation(); void useLogAxis(); + void changeValueAxisFormat(const QString & text); public slots: void flipViews(); diff --git a/tests/barstest/main.cpp b/tests/barstest/main.cpp index b02fa48f..edf61e2e 100644 --- a/tests/barstest/main.cpp +++ b/tests/barstest/main.cpp @@ -32,6 +32,7 @@ #include #include #include +#include int main(int argc, char **argv) { @@ -290,6 +291,8 @@ int main(int argc, char **argv) shadowQuality->addItem(QStringLiteral("High Soft")); shadowQuality->setCurrentIndex(5); + QLineEdit *valueAxisFormatEdit = new QLineEdit(widget); + vLayout->addWidget(addDataButton, 0, Qt::AlignTop); vLayout->addWidget(addMultiDataButton, 0, Qt::AlignTop); vLayout->addWidget(insertDataButton, 0, Qt::AlignTop); @@ -344,7 +347,9 @@ int main(int argc, char **argv) vLayout2->addWidget(new QLabel(QStringLiteral("Change font")), 0, Qt::AlignTop); vLayout2->addWidget(fontList, 0, Qt::AlignTop); vLayout2->addWidget(new QLabel(QStringLiteral("Adjust font size")), 0, Qt::AlignTop); - vLayout2->addWidget(fontSizeSlider, 1, Qt::AlignTop); + vLayout2->addWidget(fontSizeSlider, 0, Qt::AlignTop); + vLayout2->addWidget(new QLabel(QStringLiteral("Value axis format")), 0, Qt::AlignTop); + vLayout2->addWidget(valueAxisFormatEdit, 1, Qt::AlignTop); // TODO: Add example for setMeshFileName widget->show(); @@ -380,6 +385,8 @@ int main(int argc, char **argv) &QComboBox::setCurrentIndex); QObject::connect(fontSizeSlider, &QSlider::valueChanged, modifier, &GraphModifier::changeFontSize); + QObject::connect(valueAxisFormatEdit, &QLineEdit::textEdited, modifier, + &GraphModifier::changeValueAxisFormat); QObject::connect(multiScaleButton, &QPushButton::clicked, modifier, &GraphModifier::toggleMultiseriesScaling); diff --git a/tests/scattertest/main.cpp b/tests/scattertest/main.cpp index 30382ca5..fbe257f5 100644 --- a/tests/scattertest/main.cpp +++ b/tests/scattertest/main.cpp @@ -40,6 +40,7 @@ int main(int argc, char **argv) QWidget *widget = new QWidget; QHBoxLayout *hLayout = new QHBoxLayout(widget); QVBoxLayout *vLayout = new QVBoxLayout(); + QVBoxLayout *vLayout2 = new QVBoxLayout(); Q3DScatter *chart = new Q3DScatter(); QSize screenSize = chart->screen()->size(); @@ -54,6 +55,7 @@ int main(int argc, char **argv) hLayout->addWidget(container, 1); hLayout->addLayout(vLayout); + hLayout->addLayout(vLayout2); QPushButton *themeButton = new QPushButton(widget); themeButton->setText(QStringLiteral("Change theme")); @@ -161,6 +163,48 @@ int main(int argc, char **argv) pointSizeSlider->setValue(30); pointSizeSlider->setMaximum(100); + QSlider *minSliderX = new QSlider(Qt::Horizontal, widget); + minSliderX->setTickInterval(1); + minSliderX->setTickPosition(QSlider::TicksBelow); + minSliderX->setMinimum(-100); + minSliderX->setValue(-50); + minSliderX->setMaximum(100); + + QSlider *minSliderY = new QSlider(Qt::Horizontal, widget); + minSliderY->setTickInterval(1); + minSliderY->setTickPosition(QSlider::TicksBelow); + minSliderY->setMinimum(-200); + minSliderY->setValue(-100); + minSliderY->setMaximum(200); + + QSlider *minSliderZ = new QSlider(Qt::Horizontal, widget); + minSliderZ->setTickInterval(1); + minSliderZ->setTickPosition(QSlider::TicksBelow); + minSliderZ->setMinimum(-100); + minSliderZ->setValue(-50); + minSliderZ->setMaximum(100); + + QSlider *maxSliderX = new QSlider(Qt::Horizontal, widget); + maxSliderX->setTickInterval(1); + maxSliderX->setTickPosition(QSlider::TicksAbove); + maxSliderX->setMinimum(-100); + maxSliderX->setValue(50); + maxSliderX->setMaximum(100); + + QSlider *maxSliderY = new QSlider(Qt::Horizontal, widget); + maxSliderY->setTickInterval(1); + maxSliderY->setTickPosition(QSlider::TicksAbove); + maxSliderY->setMinimum(-200); + maxSliderY->setValue(120); + maxSliderY->setMaximum(200); + + QSlider *maxSliderZ = new QSlider(Qt::Horizontal, widget); + maxSliderZ->setTickInterval(1); + maxSliderZ->setTickPosition(QSlider::TicksAbove); + maxSliderZ->setMinimum(-100); + maxSliderZ->setValue(50); + maxSliderZ->setMaximum(100); + vLayout->addWidget(themeButton, 0, Qt::AlignTop); vLayout->addWidget(labelButton, 0, Qt::AlignTop); vLayout->addWidget(styleButton, 0, Qt::AlignTop); @@ -185,13 +229,21 @@ int main(int argc, char **argv) vLayout->addWidget(backgroundCheckBox); vLayout->addWidget(gridCheckBox); vLayout->addWidget(new QLabel(QStringLiteral("Adjust shadow quality"))); - vLayout->addWidget(shadowQuality); - vLayout->addWidget(new QLabel(QStringLiteral("Change font"))); - vLayout->addWidget(fontList); - vLayout->addWidget(new QLabel(QStringLiteral("Adjust font size"))); - vLayout->addWidget(fontSizeSlider, 1, Qt::AlignTop); - vLayout->addWidget(new QLabel(QStringLiteral("Adjust point size"))); - vLayout->addWidget(pointSizeSlider, 1, Qt::AlignTop); + vLayout->addWidget(shadowQuality, 1, Qt::AlignTop); + + vLayout2->addWidget(new QLabel(QStringLiteral("Adjust point size"))); + vLayout2->addWidget(pointSizeSlider, 0, Qt::AlignTop); + vLayout2->addWidget(new QLabel(QStringLiteral("Adjust data window"))); + vLayout2->addWidget(minSliderX, 0, Qt::AlignTop); + vLayout2->addWidget(maxSliderX, 0, Qt::AlignTop); + vLayout2->addWidget(minSliderY, 0, Qt::AlignTop); + vLayout2->addWidget(maxSliderY, 0, Qt::AlignTop); + vLayout2->addWidget(minSliderZ, 0, Qt::AlignTop); + vLayout2->addWidget(maxSliderZ, 0, Qt::AlignTop); + vLayout2->addWidget(new QLabel(QStringLiteral("Change font"))); + vLayout2->addWidget(fontList); + vLayout2->addWidget(new QLabel(QStringLiteral("Adjust font size"))); + vLayout2->addWidget(fontSizeSlider, 1, Qt::AlignTop); widget->show(); @@ -257,6 +309,20 @@ int main(int argc, char **argv) QObject::connect(gridCheckBox, &QCheckBox::stateChanged, modifier, &ScatterDataModifier::setGridEnabled); + QObject::connect(minSliderX, &QSlider::valueChanged, modifier, + &ScatterDataModifier::setMinX); + QObject::connect(minSliderY, &QSlider::valueChanged, modifier, + &ScatterDataModifier::setMinY); + QObject::connect(minSliderZ, &QSlider::valueChanged, modifier, + &ScatterDataModifier::setMinZ); + QObject::connect(maxSliderX, &QSlider::valueChanged, modifier, + &ScatterDataModifier::setMaxX); + QObject::connect(maxSliderY, &QSlider::valueChanged, modifier, + &ScatterDataModifier::setMaxY); + QObject::connect(maxSliderZ, &QSlider::valueChanged, modifier, + &ScatterDataModifier::setMaxZ); + + modifier->start(); return app.exec(); diff --git a/tests/scattertest/scatterchart.cpp b/tests/scattertest/scatterchart.cpp index aa0c5454..a589919f 100644 --- a/tests/scattertest/scatterchart.cpp +++ b/tests/scattertest/scatterchart.cpp @@ -83,6 +83,12 @@ void ScatterDataModifier::addData() m_chart->axisX()->setRange(-50.0f, 50.0f); m_chart->axisY()->setRange(-1.0f, 1.2f); m_chart->axisZ()->setRange(-50.0f, 50.0f); + m_chart->axisX()->setSegmentCount(6); + m_chart->axisY()->setSegmentCount(4); + m_chart->axisZ()->setSegmentCount(9); + m_chart->axisX()->setSubSegmentCount(2); + m_chart->axisY()->setSubSegmentCount(3); + m_chart->axisZ()->setSubSegmentCount(1); QScatterDataArray *dataArray = new QScatterDataArray; dataArray->resize(numberOfItems); @@ -229,9 +235,12 @@ void ScatterDataModifier::resetAxes() m_chart->setAxisX(new QValue3DAxis); m_chart->setAxisY(new QValue3DAxis); m_chart->setAxisZ(new QValue3DAxis); - m_chart->axisX()->setSegmentCount(5); - m_chart->axisY()->setSegmentCount(5); - m_chart->axisZ()->setSegmentCount(5); + m_chart->axisX()->setSegmentCount(6); + m_chart->axisY()->setSegmentCount(4); + m_chart->axisZ()->setSegmentCount(9); + m_chart->axisX()->setSubSegmentCount(2); + m_chart->axisY()->setSubSegmentCount(3); + m_chart->axisZ()->setSubSegmentCount(1); m_chart->axisX()->setTitle("X"); m_chart->axisY()->setTitle("Y"); m_chart->axisZ()->setTitle("Z"); @@ -516,12 +525,46 @@ void ScatterDataModifier::setGridEnabled(int enabled) m_chart->activeTheme()->setGridEnabled((bool)enabled); } +void ScatterDataModifier::setMinX(int min) +{ + m_chart->axisX()->setMin(min); +} + +void ScatterDataModifier::setMinY(int min) +{ + m_chart->axisY()->setMin(float(min) / 100.0f); +} + +void ScatterDataModifier::setMinZ(int min) +{ + m_chart->axisZ()->setMin(min); +} + +void ScatterDataModifier::setMaxX(int max) +{ + m_chart->axisX()->setMax(max); +} + +void ScatterDataModifier::setMaxY(int max) +{ + m_chart->axisY()->setMax(float(max) / 100.0f); +} + +void ScatterDataModifier::setMaxZ(int max) +{ + m_chart->axisZ()->setMax(max); +} + QVector3D ScatterDataModifier::randVector() { - return QVector3D( + QVector3D retvec = QVector3D( (float)(rand() % 100) / 2.0f - (float)(rand() % 100) / 2.0f, (float)(rand() % 100) / 100.0f - (float)(rand() % 100) / 100.0f, (float)(rand() % 100) / 2.0f - (float)(rand() % 100) / 2.0f); + + qDebug() << __FUNCTION__ << retvec; + + return retvec; } QScatter3DSeries *ScatterDataModifier::createAndAddSeries() @@ -535,7 +578,7 @@ QScatter3DSeries *ScatterDataModifier::createAndAddSeries() m_chart->addSeries(series); series->setName(QString("Series %1").arg(counter++)); - series->setItemLabelFormat(QStringLiteral("@seriesName: @xLabel - @yLabel - @zLabel")); + series->setItemLabelFormat(QStringLiteral("@seriesName: (X:@xLabel / Z:@zLabel) Y:@yLabel")); series->setMesh(QAbstract3DSeries::MeshSphere); series->setMeshSmooth(true); series->setBaseColor(QColor(rand() % 256, rand() % 256, rand() % 256)); diff --git a/tests/scattertest/scatterchart.h b/tests/scattertest/scatterchart.h index 21357d62..23071c85 100644 --- a/tests/scattertest/scatterchart.h +++ b/tests/scattertest/scatterchart.h @@ -45,6 +45,12 @@ public: void changePointSize(int pointSize); void setBackgroundEnabled(int enabled); void setGridEnabled(int enabled); + void setMinX(int min); + void setMinY(int min); + void setMinZ(int min); + void setMaxX(int max); + void setMaxY(int max); + void setMaxZ(int max); void start(); public slots: diff --git a/tests/surfacetest/graphmodifier.cpp b/tests/surfacetest/graphmodifier.cpp index 7f2a3ef2..e1fed76a 100644 --- a/tests/surfacetest/graphmodifier.cpp +++ b/tests/surfacetest/graphmodifier.cpp @@ -49,8 +49,10 @@ GraphModifier::GraphModifier(Q3DSurface *graph) m_activeSample(0), m_fontSize(40), m_rangeX(16.0), + m_rangeY(16.0), m_rangeZ(16.0), m_minX(-8.0), + m_minY(-8.0), m_minZ(-8.0), m_addRowCounter(m_zCount), m_insertTestZPos(0), @@ -85,14 +87,15 @@ GraphModifier::GraphModifier(Q3DSurface *graph) m_multiSampleOffsetX[3] = m_offset; m_multiSampleOffsetZ[3] = m_offset; - m_graph->axisX()->setRange(-m_limitX - m_offset, m_limitX + m_offset); - m_graph->axisY()->setRange(-1.0f, 4.5f); - m_graph->axisZ()->setRange(-m_limitZ - m_offset, m_limitZ + m_offset); +// m_graph->axisX()->setRange(-m_limitX - m_offset, m_limitX + m_offset); +// m_graph->axisY()->setRange(-1.0f, 4.5f); +// m_graph->axisZ()->setRange(-m_limitZ - m_offset, m_limitZ + m_offset); #else - m_graph->axisX()->setRange(m_minX, m_minX + m_rangeX); - m_graph->axisZ()->setRange(m_minZ, m_minZ + m_rangeZ); m_graph->addSeries(m_theSeries); #endif + m_graph->axisX()->setRange(m_minX, m_minX + m_rangeX); + m_graph->axisY()->setRange(m_minY, m_minY + m_rangeY); + m_graph->axisZ()->setRange(m_minZ, m_minZ + m_rangeZ); for (int i = 0; i < 4; i++) { m_multiseries[i] = new QSurface3DSeries; @@ -134,18 +137,27 @@ void GraphModifier::fillSeries() QSurfaceDataArray *dataArray4 = new QSurfaceDataArray; dataArray4->reserve(m_zCount); + for (int i = 0; i < m_zCount; i++) { QSurfaceDataRow *newRow[4]; + float zAdjust = 0.0f; + if (i == 3) + zAdjust = 0.7f; + for (int s = 0; s < 4; s++) { newRow[s] = new QSurfaceDataRow(m_xCount); - float z = float(i) - m_limitZ + 0.5f + m_multiSampleOffsetZ[s]; + float z = float(i) - m_limitZ + 0.5f + m_multiSampleOffsetZ[s] + zAdjust; for (int j = 0; j < m_xCount; j++) { - float x = float(j) - m_limitX + 0.5f + m_multiSampleOffsetX[s]; + float xAdjust = 0.0f; + if (j == 3) + xAdjust = 0.7f; + float x = float(j) - m_limitX + 0.5f + m_multiSampleOffsetX[s] + xAdjust; float angle = (z * x) / full * 1.57f; - float y = qSin(angle * float(qPow(1.3f, s))) + 1.1f * s; + float y = (qSin(angle * float(qPow(1.3f, s))) + 1.1f * s) * 3.0f - 5.0f + xAdjust + zAdjust; (*newRow[s])[j].setPosition(QVector3D(x, y, z)); } } + qDebug() << newRow[0]->at(0).z(); *dataArray1 << newRow[0]; *dataArray2 << newRow[1]; *dataArray3 << newRow[2]; @@ -550,6 +562,14 @@ void GraphModifier::adjustXRange(int range) qDebug() << "X Range =" << range; } +void GraphModifier::adjustYRange(int range) +{ + m_rangeY = range; + m_graph->axisY()->setRange(m_minY, m_minY + m_rangeY); + + qDebug() << "Y Range =" << range; +} + void GraphModifier::adjustZRange(int range) { m_rangeZ = range; @@ -566,6 +586,14 @@ void GraphModifier::adjustXMin(int min) qDebug() << "X Minimum =" << min; } +void GraphModifier::adjustYMin(int min) +{ + m_minY = min; + m_graph->axisY()->setRange(m_minY, m_minY + m_rangeY); + + qDebug() << "Y Minimum =" << min; +} + void GraphModifier::adjustZMin(int min) { m_minZ = min; diff --git a/tests/surfacetest/graphmodifier.h b/tests/surfacetest/graphmodifier.h index 7d7d425e..9fd0360b 100644 --- a/tests/surfacetest/graphmodifier.h +++ b/tests/surfacetest/graphmodifier.h @@ -82,8 +82,10 @@ public: void adjustXCount(int count); void adjustZCount(int count); void adjustXRange(int range); + void adjustYRange(int range); void adjustZRange(int range); void adjustXMin(int min); + void adjustYMin(int min); void adjustZMin(int min); void updateSamples(); void gradientPressed(); @@ -143,8 +145,10 @@ private: int m_activeSample; int m_fontSize; float m_rangeX; + float m_rangeY; float m_rangeZ; float m_minX; + float m_minY; float m_minZ; int m_addRowCounter; int m_insertTestZPos; diff --git a/tests/surfacetest/main.cpp b/tests/surfacetest/main.cpp index 99c60893..6b54b8dd 100644 --- a/tests/surfacetest/main.cpp +++ b/tests/surfacetest/main.cpp @@ -182,28 +182,40 @@ int main(int argc, char *argv[]) QSlider *axisRangeSliderX = new QSlider(Qt::Horizontal, widget); axisRangeSliderX->setTickInterval(1); - axisRangeSliderX->setMinimum(2); + axisRangeSliderX->setMinimum(1); axisRangeSliderX->setValue(16); axisRangeSliderX->setMaximum(100); axisRangeSliderX->setEnabled(true); + QSlider *axisRangeSliderY = new QSlider(Qt::Horizontal, widget); + axisRangeSliderY->setTickInterval(1); + axisRangeSliderY->setMinimum(1); + axisRangeSliderY->setValue(16); + axisRangeSliderY->setMaximum(100); + axisRangeSliderY->setEnabled(true); QSlider *axisRangeSliderZ = new QSlider(Qt::Horizontal, widget); axisRangeSliderZ->setTickInterval(1); - axisRangeSliderZ->setMinimum(2); + axisRangeSliderZ->setMinimum(1); axisRangeSliderZ->setValue(16); axisRangeSliderZ->setMaximum(100); axisRangeSliderZ->setEnabled(true); QSlider *axisMinSliderX = new QSlider(Qt::Horizontal, widget); axisMinSliderX->setTickInterval(1); - axisMinSliderX->setMinimum(-50); + axisMinSliderX->setMinimum(-100); axisMinSliderX->setValue(-8); - axisMinSliderX->setMaximum(50); + axisMinSliderX->setMaximum(100); axisMinSliderX->setEnabled(true); + QSlider *axisMinSliderY = new QSlider(Qt::Horizontal, widget); + axisMinSliderY->setTickInterval(1); + axisMinSliderY->setMinimum(-100); + axisMinSliderY->setValue(-8); + axisMinSliderY->setMaximum(100); + axisMinSliderY->setEnabled(true); QSlider *axisMinSliderZ = new QSlider(Qt::Horizontal, widget); axisMinSliderZ->setTickInterval(1); - axisMinSliderZ->setMinimum(-50); + axisMinSliderZ->setMinimum(-100); axisMinSliderZ->setValue(-8); - axisMinSliderZ->setMaximum(50); + axisMinSliderZ->setMaximum(100); axisMinSliderZ->setEnabled(true); QLinearGradient gr(0, 0, 100, 1); @@ -378,9 +390,11 @@ int main(int argc, char *argv[]) #endif vLayout->addWidget(new QLabel(QStringLiteral("Adjust axis range"))); vLayout->addWidget(axisRangeSliderX); + vLayout->addWidget(axisRangeSliderY); vLayout->addWidget(axisRangeSliderZ); vLayout->addWidget(new QLabel(QStringLiteral("Adjust axis minimum"))); vLayout->addWidget(axisMinSliderX); + vLayout->addWidget(axisMinSliderY); vLayout->addWidget(axisMinSliderZ); vLayout2->addWidget(new QLabel(QStringLiteral("Change font"))); vLayout2->addWidget(fontList); @@ -510,10 +524,14 @@ int main(int argc, char *argv[]) #endif QObject::connect(axisRangeSliderX, &QSlider::valueChanged, modifier, &GraphModifier::adjustXRange); + QObject::connect(axisRangeSliderY, &QSlider::valueChanged, + modifier, &GraphModifier::adjustYRange); QObject::connect(axisRangeSliderZ, &QSlider::valueChanged, modifier, &GraphModifier::adjustZRange); QObject::connect(axisMinSliderX, &QSlider::valueChanged, modifier, &GraphModifier::adjustXMin); + QObject::connect(axisMinSliderY, &QSlider::valueChanged, + modifier, &GraphModifier::adjustYMin); QObject::connect(axisMinSliderZ, &QSlider::valueChanged, modifier, &GraphModifier::adjustZMin); QObject::connect(colorPB, &QPushButton::pressed, -- cgit v1.2.3