From 44871935507e215c9d7881911a1c9ade81cf5770 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 8 Aug 2013 15:10:54 +0300 Subject: Value axis labels support for barchart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Subtick support for value axes + misc fixes Change-Id: I409670312ec0dede1a1faa33c30c5b6bc7c7ee29 Reviewed-by: Tomi Korpipää --- examples/widget/chart.cpp | 5 +- examples/widget/chart.h | 1 + src/datavis3d/axis/qabstractaxis.cpp | 2 +- src/datavis3d/axis/qabstractaxis.h | 2 +- src/datavis3d/axis/qabstractaxis_p.h | 1 + src/datavis3d/axis/qvalueaxis.cpp | 87 +++++++++++++++++++++-- src/datavis3d/axis/qvalueaxis.h | 7 ++ src/datavis3d/axis/qvalueaxis_p.h | 4 ++ src/datavis3d/data/abstractrenderitem_p.h | 2 - src/datavis3d/data/barrenderitem.cpp | 1 + src/datavis3d/data/qabstractdataproxy.cpp | 10 ++- src/datavis3d/data/qabstractdataproxy.h | 2 +- src/datavis3d/data/qabstractdataproxy_p.h | 2 +- src/datavis3d/data/qbardataproxy.cpp | 6 +- src/datavis3d/data/qbardataproxy.h | 5 +- src/datavis3d/data/qbardataproxy_p.h | 2 - src/datavis3d/data/qmapdataitem.cpp | 4 +- src/datavis3d/data/qmapdataitem.h | 4 +- src/datavis3d/data/qmapdataproxy.cpp | 6 +- src/datavis3d/data/qmapdataproxy.h | 4 +- src/datavis3d/data/qmapdataproxy_p.h | 1 - src/datavis3d/data/qscatterdataproxy.cpp | 4 +- src/datavis3d/data/qscatterdataproxy.h | 4 +- src/datavis3d/engine/abstract3dcontroller.cpp | 15 ++++ src/datavis3d/engine/abstract3dcontroller_p.h | 12 ++-- src/datavis3d/engine/abstract3drenderer.cpp | 8 +++ src/datavis3d/engine/abstract3drenderer_p.h | 1 + src/datavis3d/engine/axisrendercache.cpp | 24 ++++++- src/datavis3d/engine/axisrendercache_p.h | 6 ++ src/datavis3d/engine/bars3dcontroller.cpp | 7 +- src/datavis3d/engine/bars3dcontroller_p.h | 2 +- src/datavis3d/engine/bars3drenderer.cpp | 99 +++++++++++++++++++++------ src/datavis3d/engine/bars3drenderer_p.h | 1 - src/datavis3d/engine/maps3dcontroller.cpp | 2 +- src/datavis3d/engine/scatter3drenderer.cpp | 2 +- 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(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(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 QBarDataProxyPrivate::limitValues(int startRow, int endRow, int startColumn, int endColumn) { QMutexLocker locker(&m_mutex); - QPair limits = qMakePair(100.0f, -100.0f); + QPair 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 QMapDataProxyPrivate::limitValues() { QMutexLocker locker(&m_mutex); - QPair limits = qMakePair(100.0f, -100.0f); + QPair 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(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 &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 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(m_axisY); - if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (valueAxis && valueAxis->isAutoAdjustRange() && m_data) { QPair 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++) { -- cgit v1.2.3