summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-03-25 15:07:06 +0200
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-03-26 12:25:18 +0200
commitb36b9eb7c65e3a4f6972d2f2145722470d1ad29b (patch)
tree1d2225a3a107d0a786482c57dab8c50177a16149 /src
parentb16a964d0ed24b720e4e71da03cea87e35db7806 (diff)
Implement QLogValue3DAxisFormatter
Task-number: QTRD-2787 Change-Id: I6ecff5c3d2047a2c566051951bf237bf3e68ffab Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com> Reviewed-by: Mika Salmela <mika.salmela@digia.com> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/datavisualization/axis/axis.pri7
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter.cpp398
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter.h75
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter_p.h73
-rw-r--r--src/datavisualization/axis/qvalue3daxis.cpp8
-rw-r--r--src/datavisualization/axis/qvalue3daxis_p.h3
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter.cpp133
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter.h5
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter_p.h5
-rw-r--r--src/datavisualization/engine/abstract3dcontroller.cpp50
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp1
-rw-r--r--src/datavisualization/engine/axisrendercache_p.h8
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp1
13 files changed, 691 insertions, 76 deletions
diff --git a/src/datavisualization/axis/axis.pri b/src/datavisualization/axis/axis.pri
index 24463d1e..0173b597 100644
--- a/src/datavisualization/axis/axis.pri
+++ b/src/datavisualization/axis/axis.pri
@@ -6,10 +6,13 @@ HEADERS += \
$$PWD/qcategory3daxis.h \
$$PWD/qcategory3daxis_p.h \
$$PWD/qvalue3daxisformatter.h \
- $$PWD/qvalue3daxisformatter_p.h
+ $$PWD/qvalue3daxisformatter_p.h \
+ $$PWD/qlogvalue3daxisformatter.h \
+ $$PWD/qlogvalue3daxisformatter_p.h
SOURCES += \
$$PWD/qabstract3daxis.cpp \
$$PWD/qvalue3daxis.cpp \
$$PWD/qcategory3daxis.cpp \
- $$PWD/qvalue3daxisformatter.cpp
+ $$PWD/qvalue3daxisformatter.cpp \
+ $$PWD/qlogvalue3daxisformatter.cpp
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter.cpp b/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
new file mode 100644
index 00000000..36f27c02
--- /dev/null
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qlogvalue3daxisformatter_p.h"
+#include "qvalue3daxis_p.h"
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QLogValue3DAxisFormatter
+ * \inmodule QtDataVisualization
+ * \brief QLogValue3DAxisFormatter implements logarithmic value axis formatter.
+ * \since Qt Data Visualization 1.1
+ *
+ * This class provides formatting rules for a logarithmic QValue3DAxis.
+ *
+ * When a QLogValue3DAxisFormatter is attached to a QValue3DAxis, the axis range
+ * cannot include negative values or the zero.
+ *
+ * \sa QValue3DAxisFormatter
+ */
+
+/*!
+ * \qmltype LogValueAxis3DFormatter
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.1
+ * \ingroup datavisualization_qml
+ * \instantiates QLogValue3DAxisFormatter
+ * \brief LogValueAxis3DFormatter implements logarithmic value axis formatter.
+ *
+ * This type provides formatting rules for a logarithmic ValueAxis3D.
+ * When a LogValueAxis3DFormatter is attached to a ValueAxis3D, the axis range
+ * cannot include negative values or the zero.
+ */
+
+/*!
+ * \qmlproperty real LogValueAxis3DFormatter::base
+ *
+ * The \a base of the logarithm used to map axis values. If the base is non-zero, the parent axis
+ * segment count will be automatically adjusted whenever the axis formatter is recalculated.
+ * If you want the range to be divided into equal segments like normal value axis, set this
+ * property value to zero.
+ *
+ * The \a base has to be zero or positive value and not equal to one.
+ * Defaults to ten.
+ *
+ * \sa ValueAxis3D::segmentCount
+ */
+
+/*!
+ * \qmlproperty bool LogValueAxis3DFormatter::autoSubGrid
+ *
+ * If this property value is set to \c true, the parent axis sub-segment count is adjusted
+ * automatically according to the base property value. The number of subsegments is set to
+ * base value minus one, rounded down.
+ * Defaults to \c true.
+ *
+ * \sa base, ValueAxis3D::subSegmentCount
+ */
+
+/*!
+ * \qmlproperty bool LogValueAxis3DFormatter::showMaxLabel
+ *
+ * When the base property is non-zero, the segments that get automatically generated and depending
+ * on the range, the last segment is often smaller than the other segments. In extreme cases this
+ * can lead to overlapping labels on the last two grid lines. By setting this property to \c false,
+ * you can suppress showing the max label for the axis in cases where the segments do not exactly
+ * fit the axis.
+ * Defaults to \c true.
+ *
+ * \sa base, AbstractAxis3D::labels
+ */
+
+/*!
+ * \internal
+ */
+QLogValue3DAxisFormatter::QLogValue3DAxisFormatter(QLogValue3DAxisFormatterPrivate *d,
+ QObject *parent) :
+ QValue3DAxisFormatter(d, parent)
+{
+}
+
+/*!
+ * Constructs a new QLogValue3DAxisFormatter instance with optional \a parent.
+ */
+QLogValue3DAxisFormatter::QLogValue3DAxisFormatter(QObject *parent) :
+ QValue3DAxisFormatter(new QLogValue3DAxisFormatterPrivate(this), parent)
+{
+}
+
+/*!
+ * Destroys QLogValue3DAxisFormatter.
+ */
+QLogValue3DAxisFormatter::~QLogValue3DAxisFormatter()
+{
+}
+
+/*!
+ * \property QLogValue3DAxisFormatter::base
+ *
+ * The \a base of the logarithm used to map axis values. If the base is non-zero, the parent axis
+ * segment count will be automatically adjusted whenever the axis formatter is recalculated.
+ * If you want the range to be divided into equal segments like normal value axis, set this
+ * property value to zero.
+ *
+ * The \a base has to be zero or positive value and not equal to one.
+ * Defaults to ten.
+ *
+ * \sa QValue3DAxis::segmentCount
+ */
+void QLogValue3DAxisFormatter::setBase(qreal base)
+{
+ if (base < 0.0f || base == 1.0f) {
+ qWarning() << "Warning: The logarithm base must be greater than 0 and not equal to 1,"
+ << "attempted:" << base;
+ return;
+ }
+ if (dptr()->m_base != base) {
+ dptr()->m_base = base;
+ markDirty(true);
+ emit baseChanged(base);
+ }
+}
+
+qreal QLogValue3DAxisFormatter::base() const
+{
+ return dptrc()->m_base;
+}
+
+/*!
+ * \property QLogValue3DAxisFormatter::autoSubGrid
+ *
+ * If this property value is set to \c true, the parent axis sub-segment count is adjusted
+ * automatically according to the base property value. The number of subsegments is set to
+ * base value minus one, rounded up.
+ * Defaults to \c true.
+ *
+ * \sa base, QValue3DAxis::subSegmentCount
+ */
+void QLogValue3DAxisFormatter::setAutoSubGrid(bool enabled)
+{
+ if (dptr()->m_autoSubGrid != enabled) {
+ dptr()->m_autoSubGrid = enabled;
+ markDirty(false);
+ emit autoSubGridChanged(enabled);
+ }
+}
+
+bool QLogValue3DAxisFormatter::autoSubGrid() const
+{
+ return dptrc()->m_autoSubGrid;
+}
+
+/*!
+ * \property QLogValue3DAxisFormatter::showMaxLabel
+ *
+ * When the base property is non-zero, the segments get automatically generated, and depending
+ * on the range, the last segment is often smaller than the other segments. In extreme cases this
+ * can lead to overlapping labels on the last two grid lines. By setting this property to \c false,
+ * you can suppress showing the max label for the axis in cases where the segments do not exactly
+ * fit the axis.
+ * Defaults to \c true.
+ *
+ * \sa base, QAbstract3DAxis::labels
+ */
+void QLogValue3DAxisFormatter::setShowMaxLabel(bool enabled)
+{
+ if (dptr()->m_showMaxLabel != enabled) {
+ dptr()->m_showMaxLabel = enabled;
+ markDirty(true);
+ emit showMaxLabelChanged(enabled);
+ }
+}
+
+bool QLogValue3DAxisFormatter::showMaxLabel() const
+{
+ return dptrc()->m_showMaxLabel;
+}
+
+/*!
+ * \internal
+ */
+bool QLogValue3DAxisFormatter::allowNegatives() const
+{
+ return false;
+}
+
+/*!
+ * \internal
+ */
+bool QLogValue3DAxisFormatter::allowZero() const
+{
+ return false;
+}
+
+/*!
+ * \internal
+ */
+QValue3DAxisFormatter *QLogValue3DAxisFormatter::createNewInstance() const
+{
+ return new QLogValue3DAxisFormatter();
+}
+
+/*!
+ * \internal
+ */
+void QLogValue3DAxisFormatter::recalculate()
+{
+ dptr()->recalculate();
+}
+
+/*!
+ * \internal
+ */
+float QLogValue3DAxisFormatter::positionAt(float value) const
+{
+ return dptrc()->positionAt(value);
+}
+
+/*!
+ * \internal
+ */
+float QLogValue3DAxisFormatter::valueAt(float position) const
+{
+ return dptrc()->valueAt(position);
+}
+
+/*!
+ * \internal
+ */
+void QLogValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter &copy) const
+{
+ QValue3DAxisFormatter::populateCopy(copy);
+ dptrc()->populateCopy(copy);
+}
+
+/*!
+ * \internal
+ */
+QString QLogValue3DAxisFormatter::labelForIndex(int index) const
+{
+ return dptrc()->labelForIndex(index);
+}
+
+/*!
+ * \internal
+ */
+QLogValue3DAxisFormatterPrivate *QLogValue3DAxisFormatter::dptr()
+{
+ return static_cast<QLogValue3DAxisFormatterPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QLogValue3DAxisFormatterPrivate *QLogValue3DAxisFormatter::dptrc() const
+{
+ return static_cast<const QLogValue3DAxisFormatterPrivate *>(d_ptr.data());
+}
+
+// QLogValue3DAxisFormatterPrivate
+QLogValue3DAxisFormatterPrivate::QLogValue3DAxisFormatterPrivate(QLogValue3DAxisFormatter *q)
+ : QValue3DAxisFormatterPrivate(q),
+ m_base(10.0f),
+ m_logMin(0.0f),
+ m_logMax(0.0f),
+ m_logRangeNormalizer(0.0f),
+ m_autoSubGrid(true),
+ m_showMaxLabel(true),
+ m_evenSegments(true)
+{
+}
+
+QLogValue3DAxisFormatterPrivate::~QLogValue3DAxisFormatterPrivate()
+{
+}
+
+void QLogValue3DAxisFormatterPrivate::recalculate()
+{
+ if (m_base > 0.0) {
+ // Update parent axis segment counts
+ qreal logMin = qLn(qreal(m_min)) / qLn(m_base);
+ qreal logMax = qLn(qreal(m_max)) / qLn(m_base);
+ qreal logRangeNormalizer = logMax - logMin;
+
+ int segmentCount = qCeil(logRangeNormalizer);
+
+ m_axis->setSegmentCount(segmentCount);
+ if (m_autoSubGrid) {
+ int subSegmentCount = qCeil(m_base) - 1;
+ if (subSegmentCount < 1)
+ subSegmentCount = 1;
+ m_axis->setSubSegmentCount(subSegmentCount);
+ }
+
+ resetPositionArrays();
+
+ // Calculate segment positions
+ for (int i = 0; i < segmentCount; i++) {
+ float gridValue = float(qreal(i) / logRangeNormalizer);
+ m_gridPositions[i] = gridValue;
+ m_labelPositions[i] = gridValue;
+ }
+ // Ensure max value doesn't suffer from any rounding errors
+ m_gridPositions[segmentCount] = 1.0f;
+ m_labelPositions[segmentCount] = 1.0f;
+ float lastDiff = 1.0f - m_labelPositions.at(segmentCount - 1);
+ float firstDiff = m_labelPositions.at(1) - m_labelPositions.at(0);
+ m_evenSegments = qFuzzyCompare(lastDiff, firstDiff);
+ } else {
+ // Grid lines and label positions are the same as the parent class, so call parent impl
+ // first to populate those
+ QValue3DAxisFormatterPrivate::doRecalculate();
+ m_evenSegments = true;
+ }
+
+ // When doing position/value mappings, base doesn't matter, so just use natural logarithm
+ m_logMin = qLn(qreal(m_min));
+ m_logMax = qLn(qreal(m_max));
+ m_logRangeNormalizer = m_logMax - m_logMin;
+
+ // Subgrid line positions are logarithmically spaced
+ int subGridCount = m_axis->subSegmentCount() - 1;
+ if (subGridCount > 0) {
+ float firstSegmentRange = valueAt(m_gridPositions.at(1)) - m_min;
+ float subSegmentStep = firstSegmentRange / float(subGridCount + 1);
+
+ // Since the logarithm has the same curvature across whole axis range, we can just calculate
+ // subgrid positions for the first segment and replicate them to other segments.
+ QVector<float> actualSubSegmentSteps(subGridCount);
+
+ for (int i = 0; i < subGridCount; i++) {
+ float currentSubPosition = positionAt(m_min + ((i + 1) * subSegmentStep));
+ actualSubSegmentSteps[i] = currentSubPosition;
+ }
+
+ int segmentCount = m_axis->segmentCount();
+ for (int i = 0; i < segmentCount; i++) {
+ for (int j = 0; j < subGridCount; j++) {
+ float position = m_gridPositions.at(i) + actualSubSegmentSteps.at(j);
+ if (position > 1.0f)
+ position = 1.0f;
+ m_subGridPositions[i][j] = position;
+ }
+ }
+ }
+}
+
+void QLogValue3DAxisFormatterPrivate::populateCopy(QValue3DAxisFormatter &copy) const
+{
+ QLogValue3DAxisFormatter *logFormatter = static_cast<QLogValue3DAxisFormatter *>(&copy);
+ QLogValue3DAxisFormatterPrivate *priv = logFormatter->dptr();
+
+ priv->m_base = m_base;
+ priv->m_logMin = m_logMin;
+ priv->m_logMax = m_logMax;
+ priv->m_logRangeNormalizer = m_logRangeNormalizer;
+}
+
+float QLogValue3DAxisFormatterPrivate::positionAt(float value) const
+{
+ qreal logValue = qLn(qreal(value));
+ float retval = float((logValue - m_logMin) / m_logRangeNormalizer);
+
+ return retval;
+}
+
+float QLogValue3DAxisFormatterPrivate::valueAt(float position) const
+{
+ qreal logValue = (qreal(position) * m_logRangeNormalizer) + m_logMin;
+ return float(qExp(logValue));
+}
+
+QString QLogValue3DAxisFormatterPrivate::labelForIndex(int index) const
+{
+ if (index == m_gridPositions.size() - 1 && !m_evenSegments && !m_showMaxLabel)
+ return QString();
+ else
+ return QValue3DAxisFormatterPrivate::labelForIndex(index);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter.h b/src/datavisualization/axis/qlogvalue3daxisformatter.h
new file mode 100644
index 00000000..33466492
--- /dev/null
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef QLOGVALUE3DAXISFORMATTER_H
+#define QLOGVALUE3DAXISFORMATTER_H
+
+#include <QtDataVisualization/qvalue3daxisformatter.h>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QLogValue3DAxisFormatterPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QLogValue3DAxisFormatter : public QValue3DAxisFormatter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal base READ base WRITE setBase NOTIFY baseChanged)
+ Q_PROPERTY(bool autoSubGrid READ autoSubGrid WRITE setAutoSubGrid NOTIFY autoSubGridChanged)
+ Q_PROPERTY(bool showMaxLabel READ showMaxLabel WRITE setShowMaxLabel NOTIFY showMaxLabelChanged)
+
+protected:
+ explicit QLogValue3DAxisFormatter(QLogValue3DAxisFormatterPrivate *d, QObject *parent = 0);
+public:
+ explicit QLogValue3DAxisFormatter(QObject *parent = 0);
+ virtual ~QLogValue3DAxisFormatter();
+
+ void setBase(qreal base);
+ qreal base() const;
+ void setAutoSubGrid(bool enabled);
+ bool autoSubGrid() const;
+ void setShowMaxLabel(bool enabled);
+ bool showMaxLabel() const;
+
+signals:
+ void baseChanged(qreal base);
+ void autoSubGridChanged(bool enabled);
+ void showMaxLabelChanged(bool enabled);
+
+protected:
+ virtual bool allowNegatives() const;
+ virtual bool allowZero() const;
+ virtual QValue3DAxisFormatter *createNewInstance() const;
+ virtual void recalculate();
+ virtual float positionAt(float value) const;
+ virtual float valueAt(float position) const;
+ virtual void populateCopy(QValue3DAxisFormatter &copy) const;
+ virtual QString labelForIndex(int index) const;
+
+ QLogValue3DAxisFormatterPrivate *dptr();
+ const QLogValue3DAxisFormatterPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QLogValue3DAxisFormatter)
+
+ friend class QLogValue3DAxisFormatterPrivate;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter_p.h b/src/datavisualization/axis/qlogvalue3daxisformatter_p.h
new file mode 100644
index 00000000..44b5c80c
--- /dev/null
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include "datavisualizationglobal_p.h"
+#include "qlogvalue3daxisformatter.h"
+#include "qvalue3daxisformatter_p.h"
+
+#ifndef QLOGVALUE3DAXISFORMATTER_P_H
+#define QLOGVALUE3DAXISFORMATTER_P_H
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QLogValue3DAxis;
+
+class QLogValue3DAxisFormatterPrivate : public QValue3DAxisFormatterPrivate
+{
+ Q_OBJECT
+
+public:
+ QLogValue3DAxisFormatterPrivate(QLogValue3DAxisFormatter *q);
+ virtual ~QLogValue3DAxisFormatterPrivate();
+
+ void recalculate();
+ void populateCopy(QValue3DAxisFormatter &copy) const;
+
+ float positionAt(float value) const;
+ float valueAt(float position) const;
+ QString labelForIndex(int index) const;
+
+protected:
+ QLogValue3DAxisFormatter *qptr();
+
+ qreal m_base;
+ qreal m_logMin;
+ qreal m_logMax;
+ qreal m_logRangeNormalizer;
+ bool m_autoSubGrid;
+ bool m_showMaxLabel;
+
+private:
+ bool m_evenSegments;
+
+ friend class QLogValue3DAxisFormatter;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/axis/qvalue3daxis.cpp b/src/datavisualization/axis/qvalue3daxis.cpp
index 841349dd..b0b8caa6 100644
--- a/src/datavisualization/axis/qvalue3daxis.cpp
+++ b/src/datavisualization/axis/qvalue3daxis.cpp
@@ -105,7 +105,7 @@ void QValue3DAxis::setSegmentCount(int count)
<< count << "-> 1";
count = 1;
}
- if (dptr()->m_segmentCount != count){
+ if (dptr()->m_segmentCount != count) {
dptr()->m_segmentCount = count;
dptr()->emitLabelsChanged();
emit segmentCountChanged(count);
@@ -270,10 +270,8 @@ void QValue3DAxisPrivate::updateLabels()
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->gridPositions().at(i));
- newLabels.append(m_formatter->stringForValue(value, m_labelFormat));
- }
+ for (int i = 0; i <= m_segmentCount; i++)
+ newLabels.append(m_formatter->labelForIndex(i));
if (m_labels != newLabels)
m_labels = newLabels;
diff --git a/src/datavisualization/axis/qvalue3daxis_p.h b/src/datavisualization/axis/qvalue3daxis_p.h
index ff281f0c..b49447af 100644
--- a/src/datavisualization/axis/qvalue3daxis_p.h
+++ b/src/datavisualization/axis/qvalue3daxis_p.h
@@ -46,11 +46,12 @@ public:
virtual void setMin(float min);
virtual void setMax (float max);
+ void emitLabelsChanged();
+
signals:
void formatterDirty();
protected:
- void emitLabelsChanged();
virtual void updateLabels();
virtual bool allowZero();
diff --git a/src/datavisualization/axis/qvalue3daxisformatter.cpp b/src/datavisualization/axis/qvalue3daxisformatter.cpp
index c8e0a662..b1183023 100644
--- a/src/datavisualization/axis/qvalue3daxisformatter.cpp
+++ b/src/datavisualization/axis/qvalue3daxisformatter.cpp
@@ -33,7 +33,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* 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
+ * \sa QLogValue3DAxisFormatter
*/
/*!
@@ -108,12 +108,15 @@ QValue3DAxisFormatter *QValue3DAxisFormatter::createNewInstance() const
* any values needed for mapping between value and position. It is allowed to access
* the parent axis from inside this function.
*
- * This method must be reimplemented in a subclass.
+ * This method must be reimplemented in a subclass. The resetPositionArrays() method must be called
+ * in the subclass implementation before the position arrays are recalculated. If the subclass
+ * implementation changes any parent axis values, these changes must be done before
+ * the resetPositionArrays() call.
*
* See gridPositions(), subGridPositions(), and labelPositions() documentation about the arrays
* that need to be populated.
*
- * \sa gridPositions(), subGridPositions(), labelPositions(), axis()
+ * \sa gridPositions(), subGridPositions(), labelPositions(), axis(), resetPositionArrays()
*/
void QValue3DAxisFormatter::recalculate()
{
@@ -121,12 +124,26 @@ void QValue3DAxisFormatter::recalculate()
}
/*!
+ * The parent axis uses this method to request axis label strings for label \a index.
+ * Reimplement this method if default labeling is not sufficient.
+ * If an empty string is returned, the label is not shown.
+ *
+ * \return A string formatted using axis label formatter.
+ *
+ * \sa stringForValue()
+ */
+QString QValue3DAxisFormatter::labelForIndex(int index) const
+{
+ return d_ptr->labelForIndex(index);
+}
+
+/*!
* Reimplement this method in a subclass to resolve the formatted string for a given \a value
* if the default formatting provided by QValue3DAxis::labelFormat property is not sufficient.
*
* \return the formatted label string using \a value and \a format.
*
- * \sa recalculate(), stringForValue(), QValue3DAxis::labelFormat
+ * \sa recalculate(), labelForIndex(), QValue3DAxis::labelFormat
*/
QString QValue3DAxisFormatter::stringForValue(float value, const QString &format) const
{
@@ -141,7 +158,7 @@ QString QValue3DAxisFormatter::stringForValue(float value, const QString &format
* 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()
+ * \sa recalculate(), valueAt()
*/
float QValue3DAxisFormatter::positionAt(float value) const
{
@@ -156,7 +173,7 @@ float QValue3DAxisFormatter::positionAt(float value) const
* 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()
+ * \sa recalculate(), positionAt()
*/
float QValue3DAxisFormatter::valueAt(float position) const
{
@@ -176,13 +193,26 @@ void QValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter &copy) const
}
/*!
+ * Resets the position arrays based on values read from the parent axis.
+ * This must be called in recalculate method before the arrays are accessed in subclasses,
+ * but after any changes to the values of the parent axis.
+ *
+ * \sa gridPositions(), subGridPositions(), labelPositions(), axis(), recalculate()
+ */
+void QValue3DAxisFormatter::resetPositionArrays()
+{
+ d_ptr->resetPositionArrays();
+}
+
+/*!
* 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.
+ * is changed in a way that affects the resolved values. Specify \c true for \a labelsChange
+ * parameter if the change was such that it requires regenerating the parent axis label strings.
*/
-void QValue3DAxisFormatter::markDirty()
+void QValue3DAxisFormatter::markDirty(bool labelsChange)
{
- d_ptr->markDirty();
+ d_ptr->markDirty(labelsChange);
}
/*!
@@ -197,10 +227,12 @@ QValue3DAxis *QValue3DAxisFormatter::axis() const
}
/*!
- * \return Returns a reference to the array of normalized grid positions.
+ * \return 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 QValue3DAxis::segmentCount
*/
QVector<float> &QValue3DAxisFormatter::gridPositions() const
{
@@ -208,10 +240,12 @@ QVector<float> &QValue3DAxisFormatter::gridPositions() const
}
/*!
- * \return Returns a reference to the array of normalized subgrid positions.
- * The array size is equal to segment count of tha parent axis times subsegment count of the parent
+ * \return a reference to the array of normalized subgrid positions.
+ * The array size is equal to segment count of the parent axis times sub-segment count of the parent
* axis minus one.
* The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive.
+ *
+ * \sa QValue3DAxis::segmentCount, QValue3DAxis::subSegmentCount
*/
QVector<QVector<float> > &QValue3DAxisFormatter::subGridPositions() const
{
@@ -219,10 +253,12 @@ QVector<QVector<float> > &QValue3DAxisFormatter::subGridPositions() const
}
/*!
- * \return Returns a reference to the array of normalized label positions.
+ * \return a reference to the array of normalized label 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 label at the index zero corresponds to the minimum value of the axis.
+ *
+ * \sa QValue3DAxis::segmentCount, QAbstract3DAxis::labels
*/
QVector<float> &QValue3DAxisFormatter::labelPositions() const
{
@@ -250,40 +286,29 @@ 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)
+ if (m_axis && m_needsRecalculate) {
+ m_min = m_axis->min();
+ m_max = m_axis->max();
+ m_rangeNormalizer = (m_max - m_min);
+
q_ptr->recalculate();
+ m_needsRecalculate = false;
+ }
}
void QValue3DAxisFormatterPrivate::doRecalculate()
{
- m_needsRecalculate = false;
-
- m_gridPositions.clear();
- m_subGridPositions.clear();
- m_labelPositions.clear();
+ resetPositionArrays();
int segmentCount = m_axis->segmentCount();
int subGridCount = m_axis->subSegmentCount() - 1;
- m_min = m_axis->min();
- m_max = m_axis->max();
- m_rangeNormalizer = (m_max - m_min);
-
- m_gridPositions.resize(segmentCount + 1);
float segmentStep = 1.0f / float(segmentCount);
float subSegmentStep = 0;
-
- if (subGridCount > 0) {
- subSegmentStep = segmentStep / (subGridCount + 1);
- m_subGridPositions.resize(segmentCount);
- for (int i = 0; i < segmentCount; i++)
- m_subGridPositions[i].resize(subGridCount);
- }
-
- m_labelPositions.resize(segmentCount + 1);
+ if (subGridCount > 0)
+ subSegmentStep = segmentStep / float(subGridCount + 1);
// Calculate positions
-
for (int i = 0; i < segmentCount; i++) {
float gridValue = segmentStep * i;
m_gridPositions[i] = gridValue;
@@ -316,6 +341,11 @@ void QValue3DAxisFormatterPrivate::doPopulateCopy(QValue3DAxisFormatterPrivate &
copy.m_subGridPositions = m_subGridPositions;
}
+QString QValue3DAxisFormatterPrivate::labelForIndex(int index) const
+{
+ return q_ptr->stringForValue(q_ptr->valueAt(m_gridPositions.at(index)), m_axis->labelFormat());
+}
+
QString QValue3DAxisFormatterPrivate::stringForValue(float value, const QString &format)
{
if (m_previousLabelFormat.compare(format)) {
@@ -343,20 +373,47 @@ void QValue3DAxisFormatterPrivate::setAxis(QValue3DAxis *axis)
Q_ASSERT(axis);
connect(axis, &QValue3DAxis::segmentCountChanged,
- this, &QValue3DAxisFormatterPrivate::markDirty);
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
connect(axis, &QValue3DAxis::subSegmentCountChanged,
- this, &QValue3DAxisFormatterPrivate::markDirty);
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
connect(axis, &QAbstract3DAxis::rangeChanged,
- this, &QValue3DAxisFormatterPrivate::markDirty);
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
m_axis = axis;
}
-void QValue3DAxisFormatterPrivate::markDirty()
+void QValue3DAxisFormatterPrivate::resetPositionArrays()
+{
+ m_gridPositions.clear();
+ m_subGridPositions.clear();
+ m_labelPositions.clear();
+
+ int segmentCount = m_axis->segmentCount();
+ int subGridCount = m_axis->subSegmentCount() - 1;
+
+ m_gridPositions.resize(segmentCount + 1);
+
+ if (subGridCount > 0) {
+ m_subGridPositions.resize(segmentCount);
+ for (int i = 0; i < segmentCount; i++)
+ m_subGridPositions[i].resize(subGridCount);
+ }
+
+ m_labelPositions.resize(segmentCount + 1);
+}
+
+void QValue3DAxisFormatterPrivate::markDirty(bool labelsChange)
{
m_needsRecalculate = true;
+ if (labelsChange)
+ m_axis->dptr()->emitLabelsChanged();
if (m_axis && m_axis->orientation() != QAbstract3DAxis::AxisOrientationNone)
emit m_axis->dptr()->formatterDirty();
}
+void QValue3DAxisFormatterPrivate::markDirtyNoLabelChange()
+{
+ markDirty(false);
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/axis/qvalue3daxisformatter.h b/src/datavisualization/axis/qvalue3daxisformatter.h
index 14ecdc15..6e0e873a 100644
--- a/src/datavisualization/axis/qvalue3daxisformatter.h
+++ b/src/datavisualization/axis/qvalue3daxisformatter.h
@@ -43,12 +43,14 @@ protected:
virtual bool allowZero() const;
virtual QValue3DAxisFormatter *createNewInstance() const;
virtual void recalculate();
+ virtual QString labelForIndex(int index) const;
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 &copy) const;
- void markDirty();
+ void resetPositionArrays();
+ void markDirty(bool labelsChange = false);
QValue3DAxis *axis() const;
QVector<float> &gridPositions() const;
@@ -67,6 +69,7 @@ private:
friend class Surface3DRenderer;
friend class SurfaceObject;
friend class QValue3DAxisFormatterPrivate;
+ friend class QLogValue3DAxisFormatter;
friend class QValue3DAxis;
friend class QValue3DAxisPrivate;
friend class AxisRenderCache;
diff --git a/src/datavisualization/axis/qvalue3daxisformatter_p.h b/src/datavisualization/axis/qvalue3daxisformatter_p.h
index d9f90934..74b6f20f 100644
--- a/src/datavisualization/axis/qvalue3daxisformatter_p.h
+++ b/src/datavisualization/axis/qvalue3daxisformatter_p.h
@@ -51,14 +51,17 @@ public:
void populateCopy(QValue3DAxisFormatter &copy);
void doPopulateCopy(QValue3DAxisFormatterPrivate &copy);
+ QString labelForIndex(int index) const;
QString stringForValue(float value, const QString &format);
float positionAt(float value) const;
float valueAt(float position) const;
void setAxis(QValue3DAxis *axis);
+ void resetPositionArrays();
+ void markDirty(bool labelsChange);
public slots:
- void markDirty();
+ void markDirtyNoLabelChange();
protected:
QValue3DAxisFormatter *q_ptr;
diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp
index a6c086aa..7f905243 100644
--- a/src/datavisualization/engine/abstract3dcontroller.cpp
+++ b/src/datavisualization/engine/abstract3dcontroller.cpp
@@ -183,6 +183,31 @@ void Abstract3DController::synchDataToRenderer()
m_changeTracker.selectionModeChanged = false;
}
+ if (m_changeTracker.axisXFormatterChanged) {
+ m_changeTracker.axisXFormatterChanged = false;
+ if (m_axisX->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX);
+ m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationX,
+ valueAxisX->formatter());
+ }
+ }
+ if (m_changeTracker.axisYFormatterChanged) {
+ m_changeTracker.axisYFormatterChanged = false;
+ if (m_axisY->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY);
+ m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationY,
+ valueAxisY->formatter());
+ }
+ }
+ if (m_changeTracker.axisZFormatterChanged) {
+ m_changeTracker.axisZFormatterChanged = false;
+ if (m_axisZ->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisZ = static_cast<QValue3DAxis *>(m_axisZ);
+ m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationZ,
+ valueAxisZ->formatter());
+ }
+ }
+
if (m_changeTracker.axisXTypeChanged) {
m_renderer->updateAxisType(QAbstract3DAxis::AxisOrientationX, m_axisX->type());
m_changeTracker.axisXTypeChanged = false;
@@ -326,31 +351,6 @@ void Abstract3DController::synchDataToRenderer()
}
}
- if (m_changeTracker.axisXFormatterChanged) {
- m_changeTracker.axisXFormatterChanged = false;
- if (m_axisX->type() & QAbstract3DAxis::AxisTypeValue) {
- QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX);
- m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationX,
- valueAxisX->formatter());
- }
- }
- if (m_changeTracker.axisYFormatterChanged) {
- m_changeTracker.axisYFormatterChanged = false;
- if (m_axisY->type() & QAbstract3DAxis::AxisTypeValue) {
- QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY);
- m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationY,
- valueAxisY->formatter());
- }
- }
- if (m_changeTracker.axisZFormatterChanged) {
- m_changeTracker.axisZFormatterChanged = false;
- if (m_axisZ->type() & QAbstract3DAxis::AxisTypeValue) {
- QValue3DAxis *valueAxisZ = static_cast<QValue3DAxis *>(m_axisZ);
- m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationZ,
- valueAxisZ->formatter());
- }
- }
-
if (m_isSeriesVisibilityDirty || m_isSeriesVisualsDirty) {
m_renderer->updateSeries(m_seriesList, m_isSeriesVisibilityDirty);
m_isSeriesVisibilityDirty = false;
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
index c5e265aa..f0aec0cc 100644
--- a/src/datavisualization/engine/abstract3drenderer.cpp
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -345,6 +345,7 @@ void Abstract3DRenderer::updateAxisFormatter(QAbstract3DAxis::AxisOrientation or
cache.setCtrlFormatter(formatter);
}
formatter->d_ptr->populateCopy(*(cache.formatter()));
+ cache.markPositionsDirty();
}
void Abstract3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh mesh)
diff --git a/src/datavisualization/engine/axisrendercache_p.h b/src/datavisualization/engine/axisrendercache_p.h
index eede9917..f37857d9 100644
--- a/src/datavisualization/engine/axisrendercache_p.h
+++ b/src/datavisualization/engine/axisrendercache_p.h
@@ -33,6 +33,7 @@
#include "labelitem_p.h"
#include "qabstract3daxis_p.h"
#include "drawer_p.h"
+#include <QtCore/QPointer>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -66,11 +67,11 @@ public:
m_formatter = formatter; m_positionsDirty = true;
}
inline QValue3DAxisFormatter *formatter() const { return m_formatter; }
- inline void setCtrlFormatter(const QValue3DAxisFormatter *formatter)
+ inline void setCtrlFormatter(QValue3DAxisFormatter *formatter)
{
m_ctrlFormatter = formatter;
}
- inline const QValue3DAxisFormatter *ctrlFormatter() const { return m_ctrlFormatter; }
+ inline QValue3DAxisFormatter *ctrlFormatter() const { return m_ctrlFormatter; }
inline LabelItem &titleItem() { return m_titleItem; }
inline QList<LabelItem *> &labelItems() { return m_labelItems; }
@@ -80,6 +81,7 @@ public:
inline int labelCount() { return m_adjustedLabelPositions.size(); }
void updateAllPositions();
inline bool positionsDirty() const { return m_positionsDirty; }
+ inline void markPositionsDirty() { m_positionsDirty = true; }
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; }
@@ -106,7 +108,7 @@ private:
QString m_labelFormat;
QFont m_font;
QValue3DAxisFormatter *m_formatter;
- const QValue3DAxisFormatter *m_ctrlFormatter;
+ QPointer<QValue3DAxisFormatter> m_ctrlFormatter;
// Renderer items
Drawer *m_drawer; // Not owned
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index ed99e49e..9ce80081 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -900,6 +900,7 @@ void Surface3DRenderer::drawSlicedScene()
// Vertical lines
QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth);
+ gridLineCount = sliceCache.gridLineCount();
for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;