summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2013-08-08 15:10:54 +0300
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2013-08-09 07:43:49 +0300
commit44871935507e215c9d7881911a1c9ade81cf5770 (patch)
tree9a1a349b857133823aa4767ec0916ecac26d512a
parente516c51ebf6e8c6c257e479f23196a54b15d6b2c (diff)
Value axis labels support for barchart
+ Subtick support for value axes + misc fixes Change-Id: I409670312ec0dede1a1faa33c30c5b6bc7c7ee29 Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
-rw-r--r--examples/widget/chart.cpp5
-rw-r--r--examples/widget/chart.h1
-rw-r--r--src/datavis3d/axis/qabstractaxis.cpp2
-rw-r--r--src/datavis3d/axis/qabstractaxis.h2
-rw-r--r--src/datavis3d/axis/qabstractaxis_p.h1
-rw-r--r--src/datavis3d/axis/qvalueaxis.cpp87
-rw-r--r--src/datavis3d/axis/qvalueaxis.h7
-rw-r--r--src/datavis3d/axis/qvalueaxis_p.h4
-rw-r--r--src/datavis3d/data/abstractrenderitem_p.h2
-rw-r--r--src/datavis3d/data/barrenderitem.cpp1
-rw-r--r--src/datavis3d/data/qabstractdataproxy.cpp10
-rw-r--r--src/datavis3d/data/qabstractdataproxy.h2
-rw-r--r--src/datavis3d/data/qabstractdataproxy_p.h2
-rw-r--r--src/datavis3d/data/qbardataproxy.cpp6
-rw-r--r--src/datavis3d/data/qbardataproxy.h5
-rw-r--r--src/datavis3d/data/qbardataproxy_p.h2
-rw-r--r--src/datavis3d/data/qmapdataitem.cpp4
-rw-r--r--src/datavis3d/data/qmapdataitem.h4
-rw-r--r--src/datavis3d/data/qmapdataproxy.cpp6
-rw-r--r--src/datavis3d/data/qmapdataproxy.h4
-rw-r--r--src/datavis3d/data/qmapdataproxy_p.h1
-rw-r--r--src/datavis3d/data/qscatterdataproxy.cpp4
-rw-r--r--src/datavis3d/data/qscatterdataproxy.h4
-rw-r--r--src/datavis3d/engine/abstract3dcontroller.cpp15
-rw-r--r--src/datavis3d/engine/abstract3dcontroller_p.h12
-rw-r--r--src/datavis3d/engine/abstract3drenderer.cpp8
-rw-r--r--src/datavis3d/engine/abstract3drenderer_p.h1
-rw-r--r--src/datavis3d/engine/axisrendercache.cpp24
-rw-r--r--src/datavis3d/engine/axisrendercache_p.h6
-rw-r--r--src/datavis3d/engine/bars3dcontroller.cpp7
-rw-r--r--src/datavis3d/engine/bars3dcontroller_p.h2
-rw-r--r--src/datavis3d/engine/bars3drenderer.cpp99
-rw-r--r--src/datavis3d/engine/bars3drenderer_p.h1
-rw-r--r--src/datavis3d/engine/maps3dcontroller.cpp2
-rw-r--r--src/datavis3d/engine/scatter3drenderer.cpp2
35 files changed, 278 insertions, 67 deletions
diff --git a/examples/widget/chart.cpp b/examples/widget/chart.cpp
index 1a8d6c5d..af35bba6 100644
--- a/examples/widget/chart.cpp
+++ b/examples/widget/chart.cpp
@@ -60,7 +60,8 @@ ChartModifier::ChartModifier(Q3DBars *barchart)
m_barSpacingX(0.1f),
m_barSpacingZ(0.1f),
m_fontSize(20),
- m_ticks(10),
+ m_ticks(4),
+ m_subTicks(3),
m_minval(-20.0), // TODO Barchart Y-axis currently only properly supports zero-centered ranges
m_maxval(20.0)
{
@@ -107,6 +108,7 @@ void ChartModifier::restart(bool dynamicData)
// Set selection mode to full
m_chart->setSelectionMode(ModeBarRowAndColumn);
m_chart->valueAxis()->setTickCount(m_ticks * 2);
+ m_chart->valueAxis()->setSubTickCount(0);
m_chart->valueAxis()->setAutoAdjustRange(true);
m_chart->rowAxis()->setTitle("Generic Row");
@@ -155,6 +157,7 @@ void ChartModifier::addDataSet()
m_chart->rowAxis()->setLabels(years);
m_chart->columnAxis()->setLabels(months);
m_chart->valueAxis()->setTickCount(m_ticks);
+ m_chart->valueAxis()->setSubTickCount(m_subTicks);
m_chart->valueAxis()->setRange(m_minval, m_maxval);
// Create data rows
diff --git a/examples/widget/chart.h b/examples/widget/chart.h
index 3c759d27..a35f76f9 100644
--- a/examples/widget/chart.h
+++ b/examples/widget/chart.h
@@ -99,6 +99,7 @@ private:
float m_barSpacingZ;
int m_fontSize;
int m_ticks;
+ int m_subTicks;
qreal m_minval;
qreal m_maxval;
QStringList m_genericRowLabels;
diff --git a/src/datavis3d/axis/qabstractaxis.cpp b/src/datavis3d/axis/qabstractaxis.cpp
index ba215fd1..f49f195e 100644
--- a/src/datavis3d/axis/qabstractaxis.cpp
+++ b/src/datavis3d/axis/qabstractaxis.cpp
@@ -59,7 +59,7 @@ QString QAbstractAxis::title() const
return d_ptr->m_title;
}
-QStringList &QAbstractAxis::labels() const
+QStringList QAbstractAxis::labels() const
{
return d_ptr->m_labels;
}
diff --git a/src/datavis3d/axis/qabstractaxis.h b/src/datavis3d/axis/qabstractaxis.h
index f8c799ac..f95f53e9 100644
--- a/src/datavis3d/axis/qabstractaxis.h
+++ b/src/datavis3d/axis/qabstractaxis.h
@@ -82,7 +82,7 @@ public:
virtual ~QAbstractAxis();
QString title() const;
- QStringList &labels() const;
+ QStringList labels() const;
AxisOrientation orientation() const;
AxisType type() const;
diff --git a/src/datavis3d/axis/qabstractaxis_p.h b/src/datavis3d/axis/qabstractaxis_p.h
index abe20ae5..3b5f2e2c 100644
--- a/src/datavis3d/axis/qabstractaxis_p.h
+++ b/src/datavis3d/axis/qabstractaxis_p.h
@@ -49,6 +49,7 @@
//
// We mean it.
+#include "datavis3dglobal_p.h"
#include "qabstractaxis.h"
#ifndef QABSTRACTAXIS_P_H
diff --git a/src/datavis3d/axis/qvalueaxis.cpp b/src/datavis3d/axis/qvalueaxis.cpp
index f6ec52c4..54851965 100644
--- a/src/datavis3d/axis/qvalueaxis.cpp
+++ b/src/datavis3d/axis/qvalueaxis.cpp
@@ -85,6 +85,7 @@ void QValueAxis::setTickCount(int count)
{
if (dptr()->m_tickCount != count){
dptr()->m_tickCount = count;
+ dptr()->recreateLabels();
emit tickCountChanged(count);
}
}
@@ -94,6 +95,19 @@ int QValueAxis::tickCount() const
return dptrc()->m_tickCount;
}
+void QValueAxis::setSubTickCount(int count)
+{
+ if (dptr()->m_subTickCount != count) {
+ dptr()->m_subTickCount = count;
+ emit subTickCountChanged(count);
+ }
+}
+
+int QValueAxis::subTickCount() const
+{
+ return dptrc()->m_subTickCount;
+}
+
void QValueAxis::setAutoAdjustRange(bool autoAdjust)
{
if (dptr()->m_autoAdjust != autoAdjust) {
@@ -107,6 +121,20 @@ bool QValueAxis::isAutoAdjustRange() const
return dptrc()->m_autoAdjust;
}
+void QValueAxis::setLabelFormat(const QString &format)
+{
+ if (dptr()->m_labelFormat != format) {
+ dptr()->m_labelFormat = format;
+ dptr()->recreateLabels();
+ emit labelFormatChanged(format);
+ }
+}
+
+QString QValueAxis::labelFormat() const
+{
+ return dptrc()->m_labelFormat;
+}
+
QValueAxisPrivate *QValueAxis::dptr()
{
return static_cast<QValueAxisPrivate *>(d_ptr.data());
@@ -122,6 +150,7 @@ QValueAxisPrivate::QValueAxisPrivate(QValueAxis *q)
m_min(0.0),
m_max(10.0),
m_tickCount(10),
+ m_subTickCount(0),
m_autoAdjust(true)
{
}
@@ -132,23 +161,44 @@ QValueAxisPrivate::~QValueAxisPrivate()
void QValueAxisPrivate::setRange(qreal min, qreal max)
{
+ // If min >= max, we adjust ranges so that
+ // m_max becomes (min + 1.0)
+ // as axes need some kind of valid range.
+ // TODO: Make "reverse" axes work (i.e. min > max)
bool dirty = false;
if (m_min != min) {
m_min = min;
dirty = true;
}
if (m_max != max) {
- m_max = max;
+ if (min >= max) {
+ m_max = min + 1.0;
+ qWarning() << "Warning: Tried to set invalid range for value axis."
+ " Range automatically adjusted to a valid one:"
+ << min << "-" << max << "-->" << m_min << "-" << m_max;
+ } else {
+ m_max = max;
+ }
dirty = true;
}
- if (dirty)
+ if (dirty) {
+ recreateLabels();
emit qptr()->rangeChanged(min, max);
+ }
}
void QValueAxisPrivate::setMin(qreal min)
{
if (m_min != min) {
- m_min = min;
+ if (min >= m_max) {
+ m_min = m_max - 1.0;
+ qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for"
+ " value axis. Minimum automatically adjusted to a valid one:"
+ << min << "-->" << m_min;
+ } else {
+ m_min = min;
+ }
+ recreateLabels();
emit qptr()->rangeChanged(m_min, m_max);
}
}
@@ -156,11 +206,40 @@ void QValueAxisPrivate::setMin(qreal min)
void QValueAxisPrivate::setMax(qreal max)
{
if (m_max != max) {
- m_max = max;
+ if (max <= m_min) {
+ m_max = m_min + 1.0;
+ qWarning() << "Warning: Tried to set maximum to equal or smaller than minimum for"
+ " value axis. Maximum automatically adjusted to a valid one:"
+ << max << "-->" << m_max;
+ } else {
+ m_max = max;
+ }
+ recreateLabels();
emit qptr()->rangeChanged(m_min, m_max);
}
}
+void QValueAxisPrivate::recreateLabels()
+{
+ QStringList newLabels;
+ newLabels.reserve(m_tickCount + 1);
+
+ // First label is at axis min, which is an extra tick
+ qreal tickStep = (m_max - m_min) / m_tickCount;
+
+ for (int i = 0; i < m_tickCount; i++) {
+ // TODO Actually do proper formatting
+ newLabels.append(QString::number(m_min + (tickStep * i)));
+ }
+ // Ensure max label doesn't suffer from any rounding errors
+ newLabels.append(QString::number(m_max));
+
+ if (m_labels != newLabels) {
+ m_labels = newLabels;
+ emit q_ptr->labelsChanged();
+ }
+}
+
QValueAxis *QValueAxisPrivate::qptr()
{
return static_cast<QValueAxis *>(q_ptr);
diff --git a/src/datavis3d/axis/qvalueaxis.h b/src/datavis3d/axis/qvalueaxis.h
index af410d9c..09b99123 100644
--- a/src/datavis3d/axis/qvalueaxis.h
+++ b/src/datavis3d/axis/qvalueaxis.h
@@ -63,14 +63,21 @@ public:
void setTickCount(int count);
int tickCount() const;
+ void setSubTickCount(int count);
+ int subTickCount() const;
void setAutoAdjustRange(bool autoAdjust);
bool isAutoAdjustRange() const;
+ void setLabelFormat(const QString &format);
+ QString labelFormat() const;
+
signals:
void rangeChanged(qreal min, qreal max);
void tickCountChanged(int count);
+ void subTickCountChanged(int count);
void autoAdjustRangeChanged(bool autoAdjust);
+ void labelFormatChanged(QString format);
protected:
QValueAxisPrivate *dptr();
diff --git a/src/datavis3d/axis/qvalueaxis_p.h b/src/datavis3d/axis/qvalueaxis_p.h
index ac5aae38..c9c9417a 100644
--- a/src/datavis3d/axis/qvalueaxis_p.h
+++ b/src/datavis3d/axis/qvalueaxis_p.h
@@ -70,10 +70,14 @@ public:
void setMax (qreal max);
protected:
+ void recreateLabels();
+
qreal m_min;
qreal m_max;
int m_tickCount;
+ int m_subTickCount;
bool m_autoAdjust;
+ QString m_labelFormat;
private:
QValueAxis *qptr();
diff --git a/src/datavis3d/data/abstractrenderitem_p.h b/src/datavis3d/data/abstractrenderitem_p.h
index 7db487fd..5d37dbee 100644
--- a/src/datavis3d/data/abstractrenderitem_p.h
+++ b/src/datavis3d/data/abstractrenderitem_p.h
@@ -72,11 +72,9 @@ public:
inline const QVector3D &translation() const {return m_translation; }
// Label item for formatted label
- // Ownership of the label texture (if any) transfers to QAbstractDataItemPrivate
LabelItem &labelItem();
// Selection label item (containing special selection texture, if mode is activated)
- // Ownership of the label texture (if any) transfers to QAbstractDataItemPrivate
LabelItem &selectionLabel();
// Formatted label for item.
diff --git a/src/datavis3d/data/barrenderitem.cpp b/src/datavis3d/data/barrenderitem.cpp
index 97f561c8..942dd8aa 100644
--- a/src/datavis3d/data/barrenderitem.cpp
+++ b/src/datavis3d/data/barrenderitem.cpp
@@ -55,6 +55,7 @@ BarRenderItem::~BarRenderItem()
{
}
+// This should be accessed only under data mutex
void BarRenderItem::formatLabel()
{
// Format the string on first access
diff --git a/src/datavis3d/data/qabstractdataproxy.cpp b/src/datavis3d/data/qabstractdataproxy.cpp
index 9cdbd99e..62b40426 100644
--- a/src/datavis3d/data/qabstractdataproxy.cpp
+++ b/src/datavis3d/data/qabstractdataproxy.cpp
@@ -61,11 +61,11 @@ QAbstractDataProxy::DataType QAbstractDataProxy::type() const
void QAbstractDataProxy::setItemLabelFormat(const QString &format)
{
- d_ptr->m_itemLabelFormat = format;
+ d_ptr->setItemLabelFormat(format);
emit itemLabelFormatChanged();
}
-const QString &QAbstractDataProxy::itemLabelFormat() const
+QString QAbstractDataProxy::itemLabelFormat() const
{
return d_ptr->m_itemLabelFormat;
}
@@ -89,4 +89,10 @@ QAbstractDataProxyPrivate::~QAbstractDataProxyPrivate()
{
}
+void QAbstractDataProxyPrivate::setItemLabelFormat(const QString &format)
+{
+ QMutexLocker locker(&m_mutex);
+ m_itemLabelFormat = format;
+}
+
QT_DATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/data/qabstractdataproxy.h b/src/datavis3d/data/qabstractdataproxy.h
index 7ba8e3b2..1b86f18a 100644
--- a/src/datavis3d/data/qabstractdataproxy.h
+++ b/src/datavis3d/data/qabstractdataproxy.h
@@ -76,7 +76,7 @@ public:
// Items use this string to format single item labels, unless custom proxy initializes
// item labels with something else.
void setItemLabelFormat(const QString &format);
- const QString &itemLabelFormat() const;
+ QString itemLabelFormat() const;
QMutex *mutex();
diff --git a/src/datavis3d/data/qabstractdataproxy_p.h b/src/datavis3d/data/qabstractdataproxy_p.h
index 0ec2e1dc..fda0a5eb 100644
--- a/src/datavis3d/data/qabstractdataproxy_p.h
+++ b/src/datavis3d/data/qabstractdataproxy_p.h
@@ -66,7 +66,7 @@ public:
QAbstractDataProxyPrivate(QAbstractDataProxy *q, QAbstractDataProxy::DataType type);
virtual ~QAbstractDataProxyPrivate();
-public slots:
+ void setItemLabelFormat(const QString &format);
protected:
QAbstractDataProxy *q_ptr;
diff --git a/src/datavis3d/data/qbardataproxy.cpp b/src/datavis3d/data/qbardataproxy.cpp
index c503d2bc..f27e3407 100644
--- a/src/datavis3d/data/qbardataproxy.cpp
+++ b/src/datavis3d/data/qbardataproxy.cpp
@@ -105,9 +105,9 @@ int QBarDataProxy::rowCount()
return dptrc()->m_dataArray.size();
}
-const QBarDataArray &QBarDataProxy::array() const
+const QBarDataArray *QBarDataProxy::array() const
{
- return dptrc()->m_dataArray;
+ return &dptrc()->m_dataArray;
}
const QBarDataRow *QBarDataProxy::rowAt(int rowIndex) const
@@ -218,7 +218,7 @@ void QBarDataProxyPrivate::clearArray()
QPair<GLfloat, GLfloat> QBarDataProxyPrivate::limitValues(int startRow, int endRow, int startColumn, int endColumn)
{
QMutexLocker locker(&m_mutex);
- QPair<GLfloat, GLfloat> limits = qMakePair(100.0f, -100.0f);
+ QPair<GLfloat, GLfloat> limits = qMakePair(0.0f, 0.0f);
endRow = qMin(endRow, m_dataArray.size() - 1);
for (int i = startRow; i <= endRow; i++) {
QBarDataRow *row = m_dataArray.at(i);
diff --git a/src/datavis3d/data/qbardataproxy.h b/src/datavis3d/data/qbardataproxy.h
index f72a6d07..754083d3 100644
--- a/src/datavis3d/data/qbardataproxy.h
+++ b/src/datavis3d/data/qbardataproxy.h
@@ -68,8 +68,10 @@ public:
// requires allocating additional data object for the bar.
// If data is accessed from same thread that sets it, access doesn't need to be protected with mutex.
+ // Row and item pointers are guaranteed to be valid only until next call that modifies data.
+ // Array pointer is guaranteed to be valid for lifetime of proxy.
int rowCount();
- const QBarDataArray &array() const;
+ const QBarDataArray *array() const;
const QBarDataRow *rowAt(int rowIndex) const;
const QBarDataItem *itemAt(int rowIndex, int columnIndex) const; // Row and column in said row need to exist or this crashes
@@ -86,6 +88,7 @@ public:
// TODO Leaving them public gives user more options.
// QBarDataProxy takes ownership of all QBarDataArrays, QBarDataRows, and QBarDataItems passed to it.
+ // The pointers passed to it are not guaranteed to be valid after the calls.
// Clears the existing array and sets it data to new array.
void resetArray(QBarDataArray *newArray);
diff --git a/src/datavis3d/data/qbardataproxy_p.h b/src/datavis3d/data/qbardataproxy_p.h
index dcab4a1d..c9dec1e4 100644
--- a/src/datavis3d/data/qbardataproxy_p.h
+++ b/src/datavis3d/data/qbardataproxy_p.h
@@ -80,8 +80,6 @@ private:
QBarDataArray m_dataArray;
- QString m_itemLabelFormat;
-
private:
friend class QBarDataProxy;
};
diff --git a/src/datavis3d/data/qmapdataitem.cpp b/src/datavis3d/data/qmapdataitem.cpp
index 4ec2a9e7..8e1acc3c 100644
--- a/src/datavis3d/data/qmapdataitem.cpp
+++ b/src/datavis3d/data/qmapdataitem.cpp
@@ -90,7 +90,7 @@ void QMapDataItem::setMapPosition(const QPointF &position)
m_mapPosition = position;
}
-const QPointF &QMapDataItem::mapPosition() const
+QPointF QMapDataItem::mapPosition() const
{
return m_mapPosition;
}
@@ -100,7 +100,7 @@ void QMapDataItem::setLabel(const QString &label)
m_label = label;
}
-const QString &QMapDataItem::label() const
+QString QMapDataItem::label() const
{
return m_label;
}
diff --git a/src/datavis3d/data/qmapdataitem.h b/src/datavis3d/data/qmapdataitem.h
index adcd265b..91e1a381 100644
--- a/src/datavis3d/data/qmapdataitem.h
+++ b/src/datavis3d/data/qmapdataitem.h
@@ -60,10 +60,10 @@ public:
QMapDataItem &operator=(const QMapDataItem &other);
void setMapPosition(const QPointF &position);
- const QPointF &mapPosition() const;
+ QPointF mapPosition() const;
void setLabel(const QString &label);
- const QString &label() const;
+ QString label() const;
protected:
virtual void createExtraData();
diff --git a/src/datavis3d/data/qmapdataproxy.cpp b/src/datavis3d/data/qmapdataproxy.cpp
index d9e42884..4e59f8a3 100644
--- a/src/datavis3d/data/qmapdataproxy.cpp
+++ b/src/datavis3d/data/qmapdataproxy.cpp
@@ -72,9 +72,9 @@ int QMapDataProxy::itemCount()
return dptr()->m_dataArray.size();
}
-const QMapDataArray &QMapDataProxy::array() const
+const QMapDataArray *QMapDataProxy::array() const
{
- return dptrc()->m_dataArray;
+ return &dptrc()->m_dataArray;
}
const QMapDataItem *QMapDataProxy::itemAt(int index) const
@@ -126,7 +126,7 @@ bool QMapDataProxyPrivate::resetArray(QMapDataArray *newArray)
QPair<GLfloat, GLfloat> QMapDataProxyPrivate::limitValues()
{
QMutexLocker locker(&m_mutex);
- QPair<GLfloat, GLfloat> limits = qMakePair(100.0f, -100.0f);
+ QPair<GLfloat, GLfloat> limits = qMakePair(0.0f, 0.0f);
for (int i = 0; i < m_dataArray.size(); i++) {
const QMapDataItem &item = m_dataArray.at(i);
qreal itemValue = item.value();
diff --git a/src/datavis3d/data/qmapdataproxy.h b/src/datavis3d/data/qmapdataproxy.h
index b87b6120..8c224b86 100644
--- a/src/datavis3d/data/qmapdataproxy.h
+++ b/src/datavis3d/data/qmapdataproxy.h
@@ -65,8 +65,10 @@ public:
// requires allocating additional data object for the bar.
// If data is accessed from same thread that sets it, access doesn't need to be protected with mutex.
+ // Item pointers are guaranteed to be valid only until next call that modifies data.
+ // Array pointer is guaranteed to be valid for lifetime of proxy.
int itemCount();
- const QMapDataArray &array() const;
+ const QMapDataArray *array() const;
const QMapDataItem *itemAt(int index) const; // Index needs to exist or this crashes
// All array/item manipulation functions are internally protected by data mutex.
diff --git a/src/datavis3d/data/qmapdataproxy_p.h b/src/datavis3d/data/qmapdataproxy_p.h
index 17850e75..9d9755d4 100644
--- a/src/datavis3d/data/qmapdataproxy_p.h
+++ b/src/datavis3d/data/qmapdataproxy_p.h
@@ -71,7 +71,6 @@ public:
private:
QMapDataArray m_dataArray;
- QString m_itemLabelFormat;
private:
friend class QMapDataProxy;
diff --git a/src/datavis3d/data/qscatterdataproxy.cpp b/src/datavis3d/data/qscatterdataproxy.cpp
index d39ef7fe..72d676f6 100644
--- a/src/datavis3d/data/qscatterdataproxy.cpp
+++ b/src/datavis3d/data/qscatterdataproxy.cpp
@@ -72,9 +72,9 @@ int QScatterDataProxy::itemCount()
return dptr()->m_dataArray.size();
}
-const QScatterDataArray &QScatterDataProxy::array() const
+const QScatterDataArray *QScatterDataProxy::array() const
{
- return dptrc()->m_dataArray;
+ return &dptrc()->m_dataArray;
}
const QScatterDataItem *QScatterDataProxy::itemAt(int index) const
diff --git a/src/datavis3d/data/qscatterdataproxy.h b/src/datavis3d/data/qscatterdataproxy.h
index fe83c7fe..c96854e2 100644
--- a/src/datavis3d/data/qscatterdataproxy.h
+++ b/src/datavis3d/data/qscatterdataproxy.h
@@ -65,8 +65,10 @@ public:
// requires allocating additional data object for the bar.
// If data is accessed from same thread that sets it, access doesn't need to be protected with mutex.
+ // Item pointers are guaranteed to be valid only until next call that modifies data.
+ // Array pointer is guaranteed to be valid for lifetime of proxy.
int itemCount();
- const QScatterDataArray &array() const;
+ const QScatterDataArray *array() const;
const QScatterDataItem *itemAt(int index) const; // Index needs to exist or this crashes
// All array/item manipulation functions are internally protected by data mutex.
diff --git a/src/datavis3d/engine/abstract3dcontroller.cpp b/src/datavis3d/engine/abstract3dcontroller.cpp
index 44022a4b..086aa6d6 100644
--- a/src/datavis3d/engine/abstract3dcontroller.cpp
+++ b/src/datavis3d/engine/abstract3dcontroller.cpp
@@ -314,6 +314,18 @@ void Abstract3DController::handleAxisTickCountChanged(int count)
qWarning() << __FUNCTION__ << "invoked for invalid axis";
}
+void Abstract3DController::handleAxisSubTickCountChanged(int count)
+{
+ if (sender() == m_axisX)
+ emit axisSubTickCountChanged(QAbstractAxis::AxisOrientationX, count);
+ else if (sender() == m_axisY)
+ emit axisSubTickCountChanged(QAbstractAxis::AxisOrientationY, count);
+ else if (sender() == m_axisZ)
+ emit axisSubTickCountChanged(QAbstractAxis::AxisOrientationZ, count);
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+}
+
void Abstract3DController::handleAxisAutoAdjustRangeChanged(bool autoAdjust)
{
Q_UNUSED(autoAdjust)
@@ -345,10 +357,13 @@ void Abstract3DController::setAxisHelper(QAbstractAxis::AxisOrientation orientat
this, &Abstract3DController::handleAxisRangeChanged);
QObject::connect(valueAxis, &QValueAxis::tickCountChanged,
this, &Abstract3DController::handleAxisTickCountChanged);
+ QObject::connect(valueAxis, &QValueAxis::subTickCountChanged,
+ this, &Abstract3DController::handleAxisSubTickCountChanged);
QObject::connect(valueAxis, &QValueAxis::autoAdjustRangeChanged,
this, &Abstract3DController::handleAxisAutoAdjustRangeChanged);
emit axisRangeChanged(orientation, valueAxis->min(), valueAxis->max());
emit axisTickCountChanged(orientation, valueAxis->tickCount());
+ emit axisSubTickCountChanged(orientation, valueAxis->subTickCount());
handleAxisAutoAdjustRangeChanged(valueAxis->isAutoAdjustRange());
}
}
diff --git a/src/datavis3d/engine/abstract3dcontroller_p.h b/src/datavis3d/engine/abstract3dcontroller_p.h
index 7075cb7e..b2042764 100644
--- a/src/datavis3d/engine/abstract3dcontroller_p.h
+++ b/src/datavis3d/engine/abstract3dcontroller_p.h
@@ -161,11 +161,12 @@ public:
virtual LabelTransparency labelTransparency();
public slots:
- void handleAxisTitleChanged(const QString &title);
- void handleAxisLabelsChanged();
- void handleAxisRangeChanged(qreal min, qreal max);
- void handleAxisTickCountChanged(int count);
- void handleAxisAutoAdjustRangeChanged(bool autoAdjust);
+ virtual void handleAxisTitleChanged(const QString &title);
+ virtual void handleAxisLabelsChanged();
+ virtual void handleAxisRangeChanged(qreal min, qreal max);
+ virtual void handleAxisTickCountChanged(int count);
+ virtual void handleAxisSubTickCountChanged(int count);
+ virtual void handleAxisAutoAdjustRangeChanged(bool autoAdjust);
signals:
void boundingRectChanged(QRect boundingRect);
@@ -181,6 +182,7 @@ signals:
void axisLabelsChanged(QAbstractAxis::AxisOrientation orientation, QStringList labels);
void axisRangeChanged(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max);
void axisTickCountChanged(QAbstractAxis::AxisOrientation orientation, int count);
+ void axisSubTickCountChanged(QAbstractAxis::AxisOrientation orientation, int count);
private:
void setAxisHelper(QAbstractAxis::AxisOrientation orientation, QAbstractAxis *axis, QAbstractAxis **axisPtr);
diff --git a/src/datavis3d/engine/abstract3drenderer.cpp b/src/datavis3d/engine/abstract3drenderer.cpp
index d355f6ee..6c1d1878 100644
--- a/src/datavis3d/engine/abstract3drenderer.cpp
+++ b/src/datavis3d/engine/abstract3drenderer.cpp
@@ -78,6 +78,8 @@ void Abstract3DRenderer::initializePreOpenGL()
&Abstract3DRenderer::updateAxisRange);
QObject::connect(m_controller, &Abstract3DController::axisTickCountChanged, this,
&Abstract3DRenderer::updateAxisTickCount);
+ QObject::connect(m_controller, &Abstract3DController::axisSubTickCountChanged, this,
+ &Abstract3DRenderer::updateAxisSubTickCount);
updateTheme(m_controller->theme());
updateFont(m_controller->font());
@@ -214,6 +216,11 @@ void Abstract3DRenderer::updateAxisTickCount(QAbstractAxis::AxisOrientation orie
axisCacheForOrientation(orientation).setTickCount(count);
}
+void Abstract3DRenderer::updateAxisSubTickCount(QAbstractAxis::AxisOrientation orientation, int count)
+{
+ axisCacheForOrientation(orientation).setSubTickCount(count);
+}
+
// This method needs to be called under the controller-renderer sync mutex
void Abstract3DRenderer::initializeAxisCache(QAbstractAxis::AxisOrientation orientation, const QAbstractAxis *axis)
{
@@ -227,6 +234,7 @@ void Abstract3DRenderer::initializeAxisCache(QAbstractAxis::AxisOrientation orie
const QValueAxis *valueAxis = static_cast<const QValueAxis *>(axis);
updateAxisRange(orientation, valueAxis->min(), valueAxis->max());
updateAxisTickCount(orientation, valueAxis->tickCount());
+ updateAxisSubTickCount(orientation, valueAxis->subTickCount());
}
}
}
diff --git a/src/datavis3d/engine/abstract3drenderer_p.h b/src/datavis3d/engine/abstract3drenderer_p.h
index 98a37d3c..bbbbae7f 100644
--- a/src/datavis3d/engine/abstract3drenderer_p.h
+++ b/src/datavis3d/engine/abstract3drenderer_p.h
@@ -105,6 +105,7 @@ protected:
virtual void updateAxisLabels(QAbstractAxis::AxisOrientation orientation, const QStringList &labels);
virtual void updateAxisRange(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max);
virtual void updateAxisTickCount(QAbstractAxis::AxisOrientation orientation, int count);
+ virtual void updateAxisSubTickCount(QAbstractAxis::AxisOrientation orientation, int count);
void initializeAxisCache(QAbstractAxis::AxisOrientation orientation, const QAbstractAxis *axis);
AxisRenderCache &axisCacheForOrientation(QAbstractAxis::AxisOrientation orientation);
diff --git a/src/datavis3d/engine/axisrendercache.cpp b/src/datavis3d/engine/axisrendercache.cpp
index a5466aba..5595dd60 100644
--- a/src/datavis3d/engine/axisrendercache.cpp
+++ b/src/datavis3d/engine/axisrendercache.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "axisrendercache_p.h"
+#include "qmath.h"
QT_DATAVIS3D_BEGIN_NAMESPACE
@@ -47,8 +48,11 @@ AxisRenderCache::AxisRenderCache()
: m_type(QAbstractAxis::AxisTypeNone),
m_min(0.0),
m_max(0.0),
+ m_tickCount(0),
+ m_subTickCount(0),
m_drawer(0),
- m_tickStep(0.0f)
+ m_tickStep(0.0f),
+ m_subTickStep(0.0f)
{
}
@@ -131,6 +135,12 @@ void AxisRenderCache::setTickCount(int count)
updateTickStep();
}
+void AxisRenderCache::setSubTickCount(int count)
+{
+ m_subTickCount = count;
+ updateSubTickStep();
+}
+
void AxisRenderCache::updateTextures()
{
if (m_title.isEmpty())
@@ -149,10 +159,18 @@ void AxisRenderCache::updateTextures()
void AxisRenderCache::updateTickStep()
{
if (m_tickCount > 0)
- m_tickStep = (m_max - m_min) / m_tickCount;
+ m_tickStep = qFabs((m_max - m_min) / m_tickCount);
else
- m_tickStep = 0.0f;
+ m_tickStep = 0.0f; // Irrelevant
+ updateSubTickStep();
+}
+void AxisRenderCache::updateSubTickStep()
+{
+ if (m_subTickCount > 1)
+ m_subTickStep = m_tickStep / m_subTickCount;
+ else
+ m_subTickStep = m_tickStep;
}
QT_DATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/axisrendercache_p.h b/src/datavis3d/engine/axisrendercache_p.h
index 5f9a0292..f20a093f 100644
--- a/src/datavis3d/engine/axisrendercache_p.h
+++ b/src/datavis3d/engine/axisrendercache_p.h
@@ -80,16 +80,20 @@ public:
inline qreal max() { return m_max; }
void setTickCount(int count);
inline int tickCount() const { return m_tickCount; }
+ void setSubTickCount(int count);
+ inline int subTickCount() const { return m_subTickCount; }
inline LabelItem &titleItem() { return m_titleItem; }
inline QList<LabelItem *> &labelItems() { return m_labelItems; }
inline GLfloat tickStep() const { return m_tickStep; }
+ inline GLfloat subTickStep() const { return m_subTickStep; }
public slots:
void updateTextures();
private:
void updateTickStep();
+ void updateSubTickStep();
// Cached axis values
QAbstractAxis::AxisType m_type;
@@ -98,12 +102,14 @@ private:
qreal m_min;
qreal m_max;
int m_tickCount;
+ int m_subTickCount;
// Renderer items
Drawer *m_drawer; // Not owned
LabelItem m_titleItem;
QList<LabelItem *> m_labelItems;
GLfloat m_tickStep;
+ GLfloat m_subTickStep;
Q_DISABLE_COPY(AxisRenderCache)
};
diff --git a/src/datavis3d/engine/bars3dcontroller.cpp b/src/datavis3d/engine/bars3dcontroller.cpp
index 6188d203..bba744ec 100644
--- a/src/datavis3d/engine/bars3dcontroller.cpp
+++ b/src/datavis3d/engine/bars3dcontroller.cpp
@@ -270,7 +270,8 @@ void Bars3dController::setDataProxy(QBarDataProxy *proxy)
QObject::connect(m_data, &QBarDataProxy::rowsRemoved, this, &Bars3dController::handleRowsRemoved);
QObject::connect(m_data, &QBarDataProxy::rowsInserted, this, &Bars3dController::handleRowsInserted);
- // emit something? Renderer might be interested?
+ adjustValueAxisRange();
+ m_valuesDirty = true;
}
QBarDataProxy *Bars3dController::dataProxy()
@@ -478,13 +479,15 @@ int Bars3dController::rowCount()
void Bars3dController::adjustValueAxisRange()
{
QValueAxis *valueAxis = static_cast<QValueAxis *>(m_axisY);
- if (valueAxis && valueAxis->isAutoAdjustRange()) {
+ if (valueAxis && valueAxis->isAutoAdjustRange() && m_data) {
QPair<GLfloat, GLfloat> limits = m_data->dptr()->limitValues(0, m_rowCount, 0, m_columnCount);
if (limits.first < 0) {
// TODO: Currently we only support symmetric y-axis for bar chart if there are negative values
qreal maxAbs = qMax(qFabs(limits.first), qFabs(limits.second));
// Call private implementation to avoid unsetting auto adjust flag
valueAxis->dptr()->setRange(-maxAbs, maxAbs);
+ } else if (limits.second == 0.0) {
+ valueAxis->dptr()->setRange(0.0, 1.0); // Only zero value values in data set, set range to something.
} else {
valueAxis->dptr()->setRange(0.0, limits.second);
}
diff --git a/src/datavis3d/engine/bars3dcontroller_p.h b/src/datavis3d/engine/bars3dcontroller_p.h
index cf186ff1..4810d60b 100644
--- a/src/datavis3d/engine/bars3dcontroller_p.h
+++ b/src/datavis3d/engine/bars3dcontroller_p.h
@@ -183,7 +183,7 @@ public slots:
void handleRowsRemoved(int startIndex, int count);
void handleRowsInserted(int startIndex, int count);
- void handleAxisAutoAdjustRangeChanged(bool autoAdjust);
+ virtual void handleAxisAutoAdjustRangeChanged(bool autoAdjust);
signals:
void selectionModeChanged(SelectionMode mode);
diff --git a/src/datavis3d/engine/bars3drenderer.cpp b/src/datavis3d/engine/bars3drenderer.cpp
index cb3dc875..7df1e2b9 100644
--- a/src/datavis3d/engine/bars3drenderer.cpp
+++ b/src/datavis3d/engine/bars3drenderer.cpp
@@ -1156,13 +1156,11 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
if (m_axisCacheY.tickCount() > 0) {
// Wall lines: back wall
- GLfloat heightStep = m_axisCacheY.tickStep();
- GLfloat startLine;
+ GLfloat heightStep = m_axisCacheY.subTickStep();
+ GLfloat startLine = 0.0f;
if (m_hasNegativeValues)
startLine = -m_heightNormalizer;
- else
- startLine = heightStep;
for (GLfloat lineHeight = startLine; lineHeight <= m_heightNormalizer;
lineHeight += heightStep) {
@@ -1271,8 +1269,6 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
m_barShader->release();
}
- // TODO: Draw y labels
-
// Generate label textures for slice selection if m_updateLabels is set
if (m_cachedIsSlicingActivated && m_updateLabels) {
// Create label textures
@@ -1372,7 +1368,7 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
// Go through all rows and get position of max+1 or min-1 column, depending on x flip
// We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems
rowPos = (row + 1) * (m_cachedBarSpacing.height());
- barPos = 0;
+ barPos = m_rowWidth;
GLfloat rotLabelX = -90.0f;
GLfloat rotLabelY = 0.0f;
GLfloat rotLabelZ = 0.0f;
@@ -1380,7 +1376,7 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
if (m_zFlipped)
rotLabelY = 180.0f;
if (m_xFlipped) {
- barPos = (m_cachedColumnCount + 1) * (m_cachedBarSpacing.width());
+ barPos = -m_rowWidth;
alignment = Qt::AlignLeft;
}
if (m_yFlipped) {
@@ -1390,15 +1386,13 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
rotLabelY = 180.0f;
rotLabelZ = 180.0f;
}
- QVector3D labelPos = QVector3D((m_rowWidth - barPos) / m_scaleFactor,
+ QVector3D labelPos = QVector3D(barPos / m_scaleFactor,
-m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
(m_columnDepth - rowPos) / m_scaleFactor + zComp);
- // TODO: Try it; draw the label here
-
m_dummyBarRenderItem.setTranslation(labelPos);
const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(row);
- //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << dataSet->rowLabels().at(row);
+ //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << m_axisCacheX.labels().at(row);
m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
QVector3D(0.0f, m_yAdjustment, zComp),
@@ -1414,7 +1408,7 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
// Go through all columns and get position of max+1 or min-1 row, depending on z flip
// We need only positions for them, labels have already been generated at QDataSetPrivate. Just add LabelItems
barPos = (bar + 1) * (m_cachedBarSpacing.width());
- rowPos = 0;
+ rowPos = m_columnDepth;
GLfloat rotLabelX = -90.0f;
GLfloat rotLabelY = 90.0f;
GLfloat rotLabelZ = 0.0f;
@@ -1422,7 +1416,7 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
if (m_xFlipped)
rotLabelY = -90.0f;
if (m_zFlipped) {
- rowPos = (m_cachedRowCount + 1) * (m_cachedBarSpacing.height());
+ rowPos = -m_columnDepth;
alignment = Qt::AlignRight;
}
if (m_yFlipped) {
@@ -1434,13 +1428,13 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
}
QVector3D labelPos = QVector3D((m_rowWidth - barPos) / m_scaleFactor,
-m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
- (m_columnDepth - rowPos) / m_scaleFactor + zComp);
+ rowPos / m_scaleFactor + zComp);
// TODO: Try it; draw the label here
m_dummyBarRenderItem.setTranslation(labelPos);
const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(bar);
- //qDebug() << "labelPos, col" << bar + 1 << ":" << labelPos << dataSet->columnLabels().at(bar);
+ //qDebug() << "labelPos, col" << bar + 1 << ":" << labelPos << m_axisCacheZ.labels().at(bar);
m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
QVector3D(0.0f, m_yAdjustment, zComp),
@@ -1450,6 +1444,73 @@ void Bars3dRenderer::drawScene(CameraHelper *camera,
alignment);
}
}
+
+ // Y Labels
+ int labelNbr = 0;
+ GLfloat heightStep = m_axisCacheY.tickStep();
+ GLfloat startLine = 0.0f;
+ int labelCount = m_axisCacheY.labels().size();
+ if (m_hasNegativeValues)
+ startLine = -m_heightNormalizer;
+ GLfloat labelPos = startLine;
+
+ for (int i = 0; i < labelCount; i++) {
+ if (m_axisCacheY.labelItems().size() > labelNbr) {
+ GLfloat labelXTrans = m_rowWidth / m_scaleFactor;
+ GLfloat labelZTrans = m_columnDepth / m_scaleFactor;
+ GLfloat labelYTrans = 2.0f * labelPos / m_heightNormalizer - m_yAdjustment;
+ GLfloat rotLabelX = 0.0f;
+ GLfloat rotLabelY = -90.0f;
+ GLfloat rotLabelZ = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (!m_xFlipped) {
+ labelXTrans = -labelXTrans;
+ rotLabelY = 90.0f;
+ }
+ if (m_zFlipped) {
+ labelZTrans = -labelZTrans;
+ alignment = Qt::AlignRight;
+ }
+
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+
+ // Back wall
+ QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, labelZTrans + zComp);
+
+ //qDebug() << "labelPos, value:" << labelTrans;
+
+ m_dummyBarRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, camera, true, true, LabelMid,
+ alignment);
+
+ // Side wall
+ if (m_xFlipped)
+ alignment = Qt::AlignLeft;
+ else
+ alignment = Qt::AlignRight;
+ if (m_zFlipped)
+ rotLabelY = 180.0f;
+ else
+ rotLabelY = 0.0f;
+
+ labelTrans = QVector3D(-labelXTrans, labelYTrans, -labelZTrans + zComp);
+
+ m_dummyBarRenderItem.setTranslation(labelTrans);
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, rotLabelZ),
+ 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, camera, true, true, LabelMid,
+ alignment);
+ }
+ labelNbr++;
+ labelPos += heightStep;
+ }
+
glDisable(GL_TEXTURE_2D);
if (m_cachedLabelTransparency > TransparencyNone)
glDisable(GL_BLEND);
@@ -1505,12 +1566,6 @@ void Bars3dRenderer::updateMeshFileName(const QString &objFileName)
loadBarMesh();
}
-void Bars3dRenderer::updateAxisTickCount(QAbstractAxis::AxisOrientation orientation, int count)
-{
- Abstract3DRenderer::updateAxisTickCount(orientation, count);
- calculateHeightAdjustment();
-}
-
void Bars3dRenderer::updateAxisRange(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max)
{
Abstract3DRenderer::updateAxisRange(orientation, min, max);
diff --git a/src/datavis3d/engine/bars3drenderer_p.h b/src/datavis3d/engine/bars3drenderer_p.h
index 046efa4f..d8792b8b 100644
--- a/src/datavis3d/engine/bars3drenderer_p.h
+++ b/src/datavis3d/engine/bars3drenderer_p.h
@@ -184,7 +184,6 @@ public slots:
void updateMeshFileName(const QString &objFileName);
// Overloaded from abstract renderer
- virtual void updateAxisTickCount(QAbstractAxis::AxisOrientation orientation, int count);
virtual void updateAxisRange(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max);
// Requests that upon next render pass the column and row under the given point is inspected for selection.
diff --git a/src/datavis3d/engine/maps3dcontroller.cpp b/src/datavis3d/engine/maps3dcontroller.cpp
index b6076814..332a9240 100644
--- a/src/datavis3d/engine/maps3dcontroller.cpp
+++ b/src/datavis3d/engine/maps3dcontroller.cpp
@@ -291,7 +291,7 @@ void Maps3DController::render(const GLuint defaultFboHandle)
QMutexLocker(m_data->mutex());
// Update cached values
if (m_valuesDirty) {
- const QMapDataArray &dataArray = m_data->array();
+ const QMapDataArray &dataArray = *m_data->array();
int dataSize = dataArray.size();
m_renderItemArray.resize(dataSize);
for (int i = 0; i < dataSize ; i++) {
diff --git a/src/datavis3d/engine/scatter3drenderer.cpp b/src/datavis3d/engine/scatter3drenderer.cpp
index b703d96b..7964d662 100644
--- a/src/datavis3d/engine/scatter3drenderer.cpp
+++ b/src/datavis3d/engine/scatter3drenderer.cpp
@@ -257,7 +257,7 @@ void Scatter3DRenderer::render(QScatterDataProxy *dataProxy,
// TODO this cache initialization assumes data window starts at 0,0 offset from array
// Update cached values
if (valuesDirty) {
- const QScatterDataArray &dataArray = m_dataProxy->array();
+ const QScatterDataArray &dataArray = *m_dataProxy->array();
int dataSize = dataArray.size();
m_renderItemArray.resize(dataSize);
for (int i = 0; i < dataSize ; i++) {