summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-03-26 09:52:28 +0200
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-03-26 12:26:22 +0200
commit1e99ff2c532977d21776f5f363b8171ef147a7d9 (patch)
treeedd5a350afa5241019a7dfed1c723587f3d82265
parentb36b9eb7c65e3a4f6972d2f2145722470d1ad29b (diff)
Make axis labels more accurate by using qreals for label values
Also refactor axis formatter sub grid array to be one dimensional. There is no need to know which segment each sub grid line belongs to. Change-Id: Ie9813088650fcc0ca844f3c358ea1abae9258367 Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter.cpp25
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter.cpp66
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter.h7
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter_p.h7
-rw-r--r--src/datavisualization/engine/axisrendercache.cpp37
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp8
-rw-r--r--src/datavisualization/engine/scatter3drenderer.cpp6
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp6
-rw-r--r--src/datavisualization/utils/utils.cpp2
-rw-r--r--src/datavisualization/utils/utils_p.h2
10 files changed, 94 insertions, 72 deletions
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter.cpp b/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
index 36f27c02..17ae4476 100644
--- a/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
@@ -293,6 +293,11 @@ QLogValue3DAxisFormatterPrivate::~QLogValue3DAxisFormatterPrivate()
void QLogValue3DAxisFormatterPrivate::recalculate()
{
+ // 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;
+
if (m_base > 0.0) {
// Update parent axis segment counts
qreal logMin = qLn(qreal(m_min)) / qLn(m_base);
@@ -309,17 +314,19 @@ void QLogValue3DAxisFormatterPrivate::recalculate()
m_axis->setSubSegmentCount(subSegmentCount);
}
- resetPositionArrays();
+ resetArrays();
// Calculate segment positions
for (int i = 0; i < segmentCount; i++) {
- float gridValue = float(qreal(i) / logRangeNormalizer);
+ float gridValue = float(i) / float(logRangeNormalizer);
m_gridPositions[i] = gridValue;
m_labelPositions[i] = gridValue;
+ m_labelValues[i] = qPow(m_base, qreal(i) + logMin);
}
// Ensure max value doesn't suffer from any rounding errors
m_gridPositions[segmentCount] = 1.0f;
m_labelPositions[segmentCount] = 1.0f;
+ m_labelValues[segmentCount] = qreal(m_max);
float lastDiff = 1.0f - m_labelPositions.at(segmentCount - 1);
float firstDiff = m_labelPositions.at(1) - m_labelPositions.at(0);
m_evenSegments = qFuzzyCompare(lastDiff, firstDiff);
@@ -327,13 +334,15 @@ void QLogValue3DAxisFormatterPrivate::recalculate()
// Grid lines and label positions are the same as the parent class, so call parent impl
// first to populate those
QValue3DAxisFormatterPrivate::doRecalculate();
+
+ // Label value array needs to be repopulated
+ qreal segmentStep = 1.0 / qreal(m_axis->segmentCount());
+ for (int i = 0; i < m_labelPositions.size(); i++)
+ m_labelValues[i] = qExp(segmentStep * qreal(i) * m_logRangeNormalizer + m_logMin);
+
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;
@@ -355,8 +364,8 @@ void QLogValue3DAxisFormatterPrivate::recalculate()
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;
+ position = 1.0f;
+ m_subGridPositions[i * subGridCount + j] = position;
}
}
}
diff --git a/src/datavisualization/axis/qvalue3daxisformatter.cpp b/src/datavisualization/axis/qvalue3daxisformatter.cpp
index b1183023..7c7db398 100644
--- a/src/datavisualization/axis/qvalue3daxisformatter.cpp
+++ b/src/datavisualization/axis/qvalue3daxisformatter.cpp
@@ -104,11 +104,11 @@ QValue3DAxisFormatter *QValue3DAxisFormatter::createNewInstance() const
}
/*!
- * 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
+ * This method populates the label and grid line position arrays and the label value array, as well
+ * as calculates 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. The resetPositionArrays() method must be called
+ * This method must be reimplemented in a subclass. The resetArrays() 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.
@@ -116,7 +116,7 @@ QValue3DAxisFormatter *QValue3DAxisFormatter::createNewInstance() const
* See gridPositions(), subGridPositions(), and labelPositions() documentation about the arrays
* that need to be populated.
*
- * \sa gridPositions(), subGridPositions(), labelPositions(), axis(), resetPositionArrays()
+ * \sa gridPositions(), subGridPositions(), labelPositions(), axis(), resetArrays()
*/
void QValue3DAxisFormatter::recalculate()
{
@@ -145,7 +145,7 @@ QString QValue3DAxisFormatter::labelForIndex(int index) const
*
* \sa recalculate(), labelForIndex(), QValue3DAxis::labelFormat
*/
-QString QValue3DAxisFormatter::stringForValue(float value, const QString &format) const
+QString QValue3DAxisFormatter::stringForValue(qreal value, const QString &format) const
{
return d_ptr->stringForValue(value, format);
}
@@ -199,9 +199,9 @@ void QValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter &copy) const
*
* \sa gridPositions(), subGridPositions(), labelPositions(), axis(), recalculate()
*/
-void QValue3DAxisFormatter::resetPositionArrays()
+void QValue3DAxisFormatter::resetArrays()
{
- d_ptr->resetPositionArrays();
+ d_ptr->resetArrays();
}
/*!
@@ -227,7 +227,7 @@ QValue3DAxis *QValue3DAxisFormatter::axis() const
}
/*!
- * \return a reference to the array of normalized grid positions.
+ * \return a reference to the array of normalized grid line 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.
@@ -240,14 +240,14 @@ QVector<float> &QValue3DAxisFormatter::gridPositions() const
}
/*!
- * \return a reference to the array of normalized subgrid positions.
+ * \return a reference to the array of normalized subgrid line 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
+QVector<float> &QValue3DAxisFormatter::subGridPositions() const
{
return d_ptr->m_subGridPositions;
}
@@ -265,6 +265,18 @@ QVector<float> &QValue3DAxisFormatter::labelPositions() const
return d_ptr->m_labelPositions;
}
+/*!
+ * \return a reference to the array of values used to generate label strings.
+ * The array size is equal to the size of the label positions array and
+ * the indexes correspond to that array as well.
+ *
+ * \sa labelPositions()
+ */
+QVector<qreal> &QValue3DAxisFormatter::labelValues() const
+{
+ return d_ptr->m_labelValues;
+}
+
// QValue3DAxisFormatterPrivate
QValue3DAxisFormatterPrivate::QValue3DAxisFormatterPrivate(QValue3DAxisFormatter *q)
: QObject(0),
@@ -298,24 +310,27 @@ void QValue3DAxisFormatterPrivate::recalculate()
void QValue3DAxisFormatterPrivate::doRecalculate()
{
- resetPositionArrays();
+ resetArrays();
int segmentCount = m_axis->segmentCount();
int subGridCount = m_axis->subSegmentCount() - 1;
- float segmentStep = 1.0f / float(segmentCount);
- float subSegmentStep = 0;
+ // Use qreals for intermediate calculations for better accuracy on label values
+ qreal segmentStep = 1.0 / qreal(segmentCount);
+ qreal subSegmentStep = 0;
if (subGridCount > 0)
- subSegmentStep = segmentStep / float(subGridCount + 1);
+ subSegmentStep = segmentStep / qreal(subGridCount + 1);
// Calculate positions
+ qreal rangeNormalizer = qreal(m_max - m_min);
for (int i = 0; i < segmentCount; i++) {
- float gridValue = segmentStep * i;
- m_gridPositions[i] = gridValue;
- m_labelPositions[i] = gridValue;
+ qreal gridValue = segmentStep * qreal(i);
+ m_gridPositions[i] = float(gridValue);
+ m_labelPositions[i] = float(gridValue);
+ m_labelValues[i] = gridValue * rangeNormalizer + qreal(m_min);
if (m_subGridPositions.size()) {
for (int j = 0; j < subGridCount; j++)
- m_subGridPositions[i][j] = gridValue + subSegmentStep * (j + 1);
+ m_subGridPositions[i * subGridCount + j] = gridValue + subSegmentStep * (j + 1);
}
}
@@ -343,10 +358,10 @@ void QValue3DAxisFormatterPrivate::doPopulateCopy(QValue3DAxisFormatterPrivate &
QString QValue3DAxisFormatterPrivate::labelForIndex(int index) const
{
- return q_ptr->stringForValue(q_ptr->valueAt(m_gridPositions.at(index)), m_axis->labelFormat());
+ return q_ptr->stringForValue(m_labelValues.at(index), m_axis->labelFormat());
}
-QString QValue3DAxisFormatterPrivate::stringForValue(float value, const QString &format)
+QString QValue3DAxisFormatterPrivate::stringForValue(qreal value, const QString &format)
{
if (m_previousLabelFormat.compare(format)) {
// Format string different than the previous one used, reparse it
@@ -382,24 +397,21 @@ void QValue3DAxisFormatterPrivate::setAxis(QValue3DAxis *axis)
m_axis = axis;
}
-void QValue3DAxisFormatterPrivate::resetPositionArrays()
+void QValue3DAxisFormatterPrivate::resetArrays()
{
m_gridPositions.clear();
m_subGridPositions.clear();
m_labelPositions.clear();
+ m_labelValues.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_subGridPositions.resize(segmentCount * subGridCount);
m_labelPositions.resize(segmentCount + 1);
+ m_labelValues.resize(segmentCount + 1);
}
void QValue3DAxisFormatterPrivate::markDirty(bool labelsChange)
diff --git a/src/datavisualization/axis/qvalue3daxisformatter.h b/src/datavisualization/axis/qvalue3daxisformatter.h
index 6e0e873a..548135c0 100644
--- a/src/datavisualization/axis/qvalue3daxisformatter.h
+++ b/src/datavisualization/axis/qvalue3daxisformatter.h
@@ -44,18 +44,19 @@ protected:
virtual QValue3DAxisFormatter *createNewInstance() const;
virtual void recalculate();
virtual QString labelForIndex(int index) const;
- virtual QString stringForValue(float value, const QString &format) const;
+ virtual QString stringForValue(qreal value, const QString &format) const;
virtual float positionAt(float value) const;
virtual float valueAt(float position) const;
virtual void populateCopy(QValue3DAxisFormatter &copy) const;
- void resetPositionArrays();
+ void resetArrays();
void markDirty(bool labelsChange = false);
QValue3DAxis *axis() const;
QVector<float> &gridPositions() const;
- QVector<QVector<float> > &subGridPositions() const;
+ QVector<float> &subGridPositions() const;
QVector<float> &labelPositions() const;
+ QVector<qreal> &labelValues() const;
QScopedPointer<QValue3DAxisFormatterPrivate> d_ptr;
diff --git a/src/datavisualization/axis/qvalue3daxisformatter_p.h b/src/datavisualization/axis/qvalue3daxisformatter_p.h
index 74b6f20f..b6749fb3 100644
--- a/src/datavisualization/axis/qvalue3daxisformatter_p.h
+++ b/src/datavisualization/axis/qvalue3daxisformatter_p.h
@@ -52,12 +52,12 @@ public:
void doPopulateCopy(QValue3DAxisFormatterPrivate &copy);
QString labelForIndex(int index) const;
- QString stringForValue(float value, const QString &format);
+ QString stringForValue(qreal value, const QString &format);
float positionAt(float value) const;
float valueAt(float position) const;
void setAxis(QValue3DAxis *axis);
- void resetPositionArrays();
+ void resetArrays();
void markDirty(bool labelsChange);
public slots:
@@ -73,8 +73,9 @@ protected:
float m_rangeNormalizer;
QVector<float> m_gridPositions;
- QVector<QVector<float> > m_subGridPositions;
+ QVector<float> m_subGridPositions;
QVector<float> m_labelPositions;
+ QVector<qreal> m_labelValues;
QValue3DAxis *m_axis;
diff --git a/src/datavisualization/engine/axisrendercache.cpp b/src/datavisualization/engine/axisrendercache.cpp
index 1b4fd52d..8e78522a 100644
--- a/src/datavisualization/engine/axisrendercache.cpp
+++ b/src/datavisualization/engine/axisrendercache.cpp
@@ -119,29 +119,28 @@ void AxisRenderCache::updateAllPositions()
// 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);
+ int gridCount = m_formatter->gridPositions().size();
+ int subGridCount = m_formatter->subGridPositions().size();
+ int labelCount = m_formatter->labelPositions().size();
+ int fullSize = gridCount + subGridCount;
+
m_adjustedGridLinePositions.resize(fullSize);
- m_adjustedLabelPositions.resize(m_segmentCount + 1);
+ m_adjustedLabelPositions.resize(labelCount);
int index = 0;
- int segment = 0;
- for (; segment < m_segmentCount; segment++) {
- m_adjustedLabelPositions[segment] =
- m_formatter->labelPositions().at(segment) * m_scale + m_translate;
+ int grid = 0;
+ int label = 0;
+ for (; label < labelCount; label++) {
+ m_adjustedLabelPositions[label] =
+ m_formatter->labelPositions().at(label) * m_scale + m_translate;
+ }
+ for (; grid < gridCount; grid++) {
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;
- }
- }
+ m_formatter->gridPositions().at(grid) * m_scale + m_translate;
+ }
+ for (int subGrid = 0; subGrid < subGridCount; subGrid++) {
+ m_adjustedGridLinePositions[index++] =
+ m_formatter->subGridPositions().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;
m_positionsDirty = false;
}
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
index f0a5e3d4..0cad8522 100644
--- a/src/datavisualization/engine/bars3drenderer.cpp
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -648,7 +648,7 @@ void Bars3DRenderer::drawSlicedScene()
// Create label texture if we need it
if (item.sliceLabel().isNull() || m_updateLabels) {
QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
- item.value(), m_axisCacheY.labelFormat());
+ qreal(item.value()), m_axisCacheY.labelFormat());
item.setSliceLabel(valueLabelText);
m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel());
m_updateLabels = false;
@@ -674,7 +674,7 @@ void Bars3DRenderer::drawSlicedScene()
// Create label texture if we need it
if (item.sliceLabel().isNull() || m_updateLabels) {
QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
- item.value(), m_axisCacheY.labelFormat());
+ qreal(item.value()), m_axisCacheY.labelFormat());
item.setSliceLabel(valueLabelText);
m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel());
m_updateLabels = false;
@@ -1822,7 +1822,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
// Custom format expects printf format specifier. There is no tag for it.
labelText = m_axisCacheY.formatter()->stringForValue(
- selectedBar->value(),
+ qreal(selectedBar->value()),
m_visibleSeriesList[m_visualSelectedBarSeriesIndex].itemLabelFormat());
int selBarPosRow = selectedBar->position().x();
@@ -1843,7 +1843,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
if (labelText.contains(valueLabelTag)) {
QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
- selectedBar->value(), m_axisCacheY.labelFormat());
+ qreal(selectedBar->value()), m_axisCacheY.labelFormat());
labelText.replace(valueLabelTag, valueLabelText);
}
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp
index f85936f9..49595052 100644
--- a/src/datavisualization/engine/scatter3drenderer.cpp
+++ b/src/datavisualization/engine/scatter3drenderer.cpp
@@ -1463,17 +1463,17 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
if (labelText.contains(xLabelTag)) {
QString valueLabelText = m_axisCacheX.formatter()->stringForValue(
- selectedItem->position().x(), m_axisCacheX.labelFormat());
+ qreal(selectedItem->position().x()), m_axisCacheX.labelFormat());
labelText.replace(xLabelTag, valueLabelText);
}
if (labelText.contains(yLabelTag)) {
QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
- selectedItem->position().y(), m_axisCacheY.labelFormat());
+ qreal(selectedItem->position().y()), m_axisCacheY.labelFormat());
labelText.replace(yLabelTag, valueLabelText);
}
if (labelText.contains(zLabelTag)) {
QString valueLabelText = m_axisCacheZ.formatter()->stringForValue(
- selectedItem->position().z(), m_axisCacheZ.labelFormat());
+ qreal(selectedItem->position().z()), m_axisCacheZ.labelFormat());
labelText.replace(zLabelTag, valueLabelText);
}
labelText.replace(seriesNameTag,
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index 9ce80081..86972fdc 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -2242,17 +2242,17 @@ QString Surface3DRenderer::createSelectionLabel(SurfaceSeriesRenderCache *cache,
if (labelText.contains(xLabelTag)) {
QString valueLabelText = m_axisCacheX.formatter()->stringForValue(
- dataArray.at(row)->at(column).x(), m_axisCacheX.labelFormat());
+ qreal(dataArray.at(row)->at(column).x()), m_axisCacheX.labelFormat());
labelText.replace(xLabelTag, valueLabelText);
}
if (labelText.contains(yLabelTag)) {
QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
- dataArray.at(row)->at(column).y(), m_axisCacheY.labelFormat());
+ qreal(dataArray.at(row)->at(column).y()), m_axisCacheY.labelFormat());
labelText.replace(yLabelTag, valueLabelText);
}
if (labelText.contains(zLabelTag)) {
QString valueLabelText = m_axisCacheZ.formatter()->stringForValue(
- dataArray.at(row)->at(column).z(), m_axisCacheZ.labelFormat());
+ qreal(dataArray.at(row)->at(column).z()), m_axisCacheZ.labelFormat());
labelText.replace(zLabelTag, valueLabelText);
}
diff --git a/src/datavisualization/utils/utils.cpp b/src/datavisualization/utils/utils.cpp
index be087f91..38fa0b2a 100644
--- a/src/datavisualization/utils/utils.cpp
+++ b/src/datavisualization/utils/utils.cpp
@@ -187,7 +187,7 @@ Utils::ParamType Utils::findFormatParamType(const QString &format)
return ParamTypeUnknown;
}
-QString Utils::formatLabel(const QByteArray &format, ParamType paramType, float value)
+QString Utils::formatLabel(const QByteArray &format, ParamType paramType, qreal value)
{
switch (paramType) {
case ParamTypeInt:
diff --git a/src/datavisualization/utils/utils_p.h b/src/datavisualization/utils/utils_p.h
index c87ef19a..d2c23abf 100644
--- a/src/datavisualization/utils/utils_p.h
+++ b/src/datavisualization/utils/utils_p.h
@@ -67,7 +67,7 @@ public:
static QImage getGradientImage(const QLinearGradient &gradient);
static ParamType findFormatParamType(const QString &format);
- static QString formatLabel(const QByteArray &format, ParamType paramType, float value);
+ static QString formatLabel(const QByteArray &format, ParamType paramType, qreal value);
static QString defaultLabelFormat();
static float wrapValue(float value, float min, float max);