diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2013-09-30 11:06:58 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2013-10-01 09:03:24 +0300 |
commit | 822a19d3e2650c7a9326b69ff4621ccd556e16cc (patch) | |
tree | 064fba99ba0e4ec7a3113c5fb051d3cd50972360 /src/datavisualization | |
parent | 52fcca463e63500bea81b0ac3615d4779bc7682c (diff) |
Refactor surface data item to have X, Y, and Z values.
Task-number: QTRD-2332
Change-Id: I086d3a422ff444cbcede1aa238107ebcbce68729
Reviewed-by: Mika Salmela <mika.salmela@digia.com>
Diffstat (limited to 'src/datavisualization')
20 files changed, 705 insertions, 496 deletions
diff --git a/src/datavisualization/data/data.pri b/src/datavisualization/data/data.pri index f5a283e7..770d2bd1 100644 --- a/src/datavisualization/data/data.pri +++ b/src/datavisualization/data/data.pri @@ -34,7 +34,9 @@ HEADERS += \ $$PWD/qitemmodelsurfacedatamapping_p.h \ $$PWD/qitemmodelsurfacedataproxy.h \ $$PWD/qitemmodelsurfacedataproxy_p.h \ - $$PWD/surfaceitemmodelhandler_p.h + $$PWD/surfaceitemmodelhandler_p.h \ + $$PWD/qsurfacedataitem.h \ + $$PWD/qsurfacedataitem_p.h SOURCES += \ $$PWD/labelitem.cpp \ @@ -58,4 +60,5 @@ SOURCES += \ $$PWD/qheightmapsurfacedataproxy.cpp \ $$PWD/qitemmodelsurfacedatamapping.cpp \ $$PWD/qitemmodelsurfacedataproxy.cpp \ - $$PWD/surfaceitemmodelhandler.cpp + $$PWD/surfaceitemmodelhandler.cpp \ + $$PWD/qsurfacedataitem.cpp diff --git a/src/datavisualization/data/qbardataitem.cpp b/src/datavisualization/data/qbardataitem.cpp index 01bcfd1c..2803c01a 100644 --- a/src/datavisualization/data/qbardataitem.cpp +++ b/src/datavisualization/data/qbardataitem.cpp @@ -81,20 +81,14 @@ QBarDataItem &QBarDataItem::operator=(const QBarDataItem &other) } /*! + * \fn void QBarDataItem::setValue(qreal value) * Sets \a value to this data item. */ -void QBarDataItem::setValue(qreal value) -{ - m_value = value; -} /*! + * \fn qreal QBarDataItem::value() const * \return value of this data item. */ -qreal QBarDataItem::value() const -{ - return m_value; -} /*! * \internal diff --git a/src/datavisualization/data/qbardataitem.h b/src/datavisualization/data/qbardataitem.h index 683120b2..68bbcedf 100644 --- a/src/datavisualization/data/qbardataitem.h +++ b/src/datavisualization/data/qbardataitem.h @@ -35,8 +35,8 @@ public: QBarDataItem &operator=(const QBarDataItem &other); - void setValue(qreal value); - qreal value() const; + void setValue(qreal value) { m_value = value; } + qreal value() const { return m_value; } // TODO Set color, label format, ...? diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp index c0b0723c..05b44a17 100644 --- a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp +++ b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp @@ -20,6 +20,10 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE +// Default ranges correspond value axis defaults +const float defaultMinValue = 0.0f; +const float defaultMaxValue = 10.0f; + /*! * \class QHeightMapSurfaceDataProxy * \inmodule QtDataVisualization @@ -29,6 +33,11 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE * QHeightMapSurfaceDataProxy takes care of surface related height map data handling. It provides a * way for giving the surface plot a height map to be visualized. * + * Since height maps do not contain values for X or Z axes, those values need to be given + * separately using minXValue, maxXValue, minZValue, and maxZValue properties. X-value corresponds + * to image horizontal direction and Z-value to the vertical. Setting any of these + * properties triggers asynchronous re-resolving of any existing height map. + * * \sa QSurfaceDataProxy */ @@ -55,6 +64,11 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE * otherwise it is an average calculated from red, green and blue components of the pixels. Using * grayscale images may improve data conversion speed for large images. * + * Since height maps do not contain values for X or Z axes, those values need to be given + * separately using minXValue, maxXValue, minZValue, and maxZValue properties. X-value corresponds + * to image horizontal direction and Z-value to the vertical. Setting any of these + * properties triggers asynchronous re-resolving of any existing height map. + * * Not recommended formats: all mono formats (for example QImage::Format_Mono). */ @@ -68,6 +82,38 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE */ /*! + * \qmlproperty qreal HeightMapSurfaceDataProxy::minXValue + * + * The minimum X value for the generated surface points. + * When setting this property the corresponding maximum value is adjusted if necessary, + * to ensure that the range remains valid. + */ + +/*! + * \qmlproperty qreal HeightMapSurfaceDataProxy::maxXValue + * + * The maximum X value for the generated surface points. + * When setting this property the corresponding minimum value is adjusted if necessary, + * to ensure that the range remains valid. + */ + +/*! + * \qmlproperty qreal HeightMapSurfaceDataProxy::minZValue + * + * The minimum Z value for the generated surface points. + * When setting this property the corresponding maximum value is adjusted if necessary, + * to ensure that the range remains valid. + */ + +/*! + * \qmlproperty qreal HeightMapSurfaceDataProxy::maxZValue + * + * The maximum Z value for the generated surface points. + * When setting this property the corresponding minimum value is adjusted if necessary, + * to ensure that the range remains valid. + */ + +/*! * Constructs QHeightMapSurfaceDataProxy with the given \a parent. */ QHeightMapSurfaceDataProxy::QHeightMapSurfaceDataProxy(QObject *parent) : @@ -154,6 +200,85 @@ QString QHeightMapSurfaceDataProxy::heightMapFile() const { return dptrc()->m_heightMapFile; } + +/*! + * A convenience function for setting all minimum and maximum values at the same time + * The minimum values must be smaller than the corresponding maximum value. Otherwise + * the values get adjusted so that they are valid. + */ +void QHeightMapSurfaceDataProxy::setValueRanges(float minX, float maxX, float minZ, float maxZ) +{ + dptr()->setValueRanges(minX, maxX, minZ, maxZ); +} + +/*! + * \property QHeightMapSurfaceDataProxy::minXValue + * + * The minimum X value for the generated surface points. + * When setting this property the corresponding maximum value is adjusted if necessary, + * to ensure that the range remains valid. + */ +void QHeightMapSurfaceDataProxy::setMinXValue(float min) +{ + dptr()->setMinXValue(min); +} + +float QHeightMapSurfaceDataProxy::minXValue() const +{ + return dptrc()->m_minXValue; +} + +/*! + * \property QHeightMapSurfaceDataProxy::maxXValue + * + * The maximum X value for the generated surface points. + * When setting this property the corresponding minimum value is adjusted if necessary, + * to ensure that the range remains valid. + */ +void QHeightMapSurfaceDataProxy::setMaxXValue(float max) +{ + dptr()->setMaxXValue(max); +} + +float QHeightMapSurfaceDataProxy::maxXValue() const +{ + return dptrc()->m_maxXValue; +} + +/*! + * \property QHeightMapSurfaceDataProxy::minZValue + * + * The minimum Z value for the generated surface points. + * When setting this property the corresponding maximum value is adjusted if necessary, + * to ensure that the range remains valid. + */ +void QHeightMapSurfaceDataProxy::setMinZValue(float min) +{ + dptr()->setMinZValue(min); +} + +float QHeightMapSurfaceDataProxy::minZValue() const +{ + return dptrc()->m_minZValue; +} + +/*! + * \property QHeightMapSurfaceDataProxy::maxZValue + * + * The maximum Z value for the generated surface points. + * When setting this property the corresponding minimum value is adjusted if necessary, + * to ensure that the range remains valid. + */ +void QHeightMapSurfaceDataProxy::setMaxZValue(float max) +{ + dptr()->setMaxZValue(max); +} + +float QHeightMapSurfaceDataProxy::maxZValue() const +{ + return dptrc()->m_maxZValue; +} + /*! * \internal */ @@ -175,7 +300,11 @@ const QHeightMapSurfaceDataProxyPrivate *QHeightMapSurfaceDataProxy::dptrc() con // QHeightMapSurfaceDataProxyPrivate::QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q) - : QSurfaceDataProxyPrivate(q) + : QSurfaceDataProxyPrivate(q), + m_minXValue(defaultMinValue), + m_maxXValue(defaultMaxValue), + m_minZValue(defaultMinValue), + m_maxZValue(defaultMaxValue) { m_resolveTimer.setSingleShot(true); QObject::connect(&m_resolveTimer, &QTimer::timeout, @@ -191,6 +320,109 @@ QHeightMapSurfaceDataProxy *QHeightMapSurfaceDataProxyPrivate::qptr() return static_cast<QHeightMapSurfaceDataProxy *>(q_ptr); } +void QHeightMapSurfaceDataProxyPrivate::setValueRanges(float minX, float maxX, float minZ, float maxZ) +{ + bool changed = false; + if (m_minXValue != minX || m_minZValue != minZ) { + m_minXValue = minX; + m_minZValue = minZ; + changed = true; + } + if (m_maxXValue != maxX || minX >= maxX) { + if (minX >= maxX) { + m_maxXValue = minX + 1.0; + qWarning() << "Warning: Tried to set invalid range for X value range." + " Range automatically adjusted to a valid one:" + << minX << "-" << maxX << "-->" << m_minXValue << "-" << m_maxXValue; + } else { + m_maxXValue = maxX; + } + changed = true; + } + if (m_maxZValue != maxZ || minZ >= maxZ) { + if (minZ >= maxZ) { + m_maxZValue = minZ + 1.0; + qWarning() << "Warning: Tried to set invalid range for Z value range." + " Range automatically adjusted to a valid one:" + << minZ << "-" << maxZ << "-->" << m_minZValue << "-" << m_maxZValue; + } else { + m_maxZValue = maxZ; + } + changed = true; + } + + if (changed && !m_resolveTimer.isActive()) + m_resolveTimer.start(0); +} + +void QHeightMapSurfaceDataProxyPrivate::setMinXValue(float min) +{ + if (min != m_minXValue) { + if (min >= m_maxXValue) { + qreal oldMax = m_maxXValue; + m_maxXValue = min + 1.0; + qWarning() << "Warning: Tried to set minimum X to equal or larger than maximum X for" + " value range. Maximum automatically adjusted to a valid one:" + << oldMax << "-->" << m_maxXValue; + } + m_minXValue = min; + + if (!m_resolveTimer.isActive()) + m_resolveTimer.start(0); + } +} + +void QHeightMapSurfaceDataProxyPrivate::setMaxXValue(float max) +{ + if (m_maxXValue != max) { + if (max <= m_minXValue) { + qreal oldMin = m_minXValue; + m_minXValue = max - 1.0; + qWarning() << "Warning: Tried to set maximum X to equal or smaller than minimum X for" + " value range. Minimum automatically adjusted to a valid one:" + << oldMin << "-->" << m_minXValue; + } + m_maxXValue = max; + + if (!m_resolveTimer.isActive()) + m_resolveTimer.start(0); + } +} + +void QHeightMapSurfaceDataProxyPrivate::setMinZValue(float min) +{ + if (min != m_minZValue) { + if (min >= m_maxZValue) { + qreal oldMax = m_maxZValue; + m_maxZValue = min + 1.0; + qWarning() << "Warning: Tried to set minimum Z to equal or larger than maximum Z for" + " value range. Maximum automatically adjusted to a valid one:" + << oldMax << "-->" << m_maxZValue; + } + m_minZValue = min; + + if (!m_resolveTimer.isActive()) + m_resolveTimer.start(0); + } +} + +void QHeightMapSurfaceDataProxyPrivate::setMaxZValue(float max) +{ + if (m_maxZValue != max) { + if (max <= m_minZValue) { + qreal oldMin = m_minZValue; + m_minZValue = max - 1.0; + qWarning() << "Warning: Tried to set maximum Z to equal or smaller than minimum Z for" + " value range. Minimum automatically adjusted to a valid one:" + << oldMin << "-->" << m_minZValue; + } + m_maxZValue = max; + + if (!m_resolveTimer.isActive()) + m_resolveTimer.start(0); + } +} + void QHeightMapSurfaceDataProxyPrivate::handlePendingResolve() { QImage heightImage = m_heightMap; @@ -204,7 +436,7 @@ void QHeightMapSurfaceDataProxyPrivate::handlePendingResolve() int imageWidth = heightImage.width(); int bitCount = imageWidth * 4 * (imageHeight - 1); int widthBits = imageWidth * 4; - qreal height = 0; + float height = 0; // Do not recreate array if dimensions have not changed QSurfaceDataArray *dataArray = m_dataArray; @@ -217,12 +449,16 @@ void QHeightMapSurfaceDataProxyPrivate::handlePendingResolve() } } + float xMul = (m_maxXValue - m_minXValue) / float(imageWidth - 1); + float zMul = (m_maxZValue - m_minZValue) / float(imageHeight - 1); + if (heightImage.isGrayscale()) { // Grayscale, it's enough to read Red byte for (int i = 0; i < imageHeight; i++, bitCount -= widthBits) { QSurfaceDataRow &newRow = *dataArray->at(i); for (int j = 0; j < imageWidth; j++) - newRow[j] = qreal(bits[bitCount + (j * 4)]); + newRow[j].setPosition(QVector3D((float(j) * xMul) + m_minXValue, float(bits[bitCount + (j * 4)]), + (float(i) * zMul) + m_minZValue)); } } else { // Not grayscale, we'll need to calculate height from RGB @@ -230,15 +466,16 @@ void QHeightMapSurfaceDataProxyPrivate::handlePendingResolve() QSurfaceDataRow &newRow = *dataArray->at(i); for (int j = 0; j < imageWidth; j++) { int nextpixel = j * 4; - height = (qreal(bits[bitCount + nextpixel]) - + qreal(bits[1 + bitCount + nextpixel]) - + qreal(bits[2 + bitCount + nextpixel])); - newRow[j] = height / 3.0; + height = (float(bits[bitCount + nextpixel]) + + float(bits[1 + bitCount + nextpixel]) + + float(bits[2 + bitCount + nextpixel])); + newRow[j].setPosition(QVector3D((float(j) * xMul) + m_minXValue, height / 3.0f, + (float(i) * zMul) + m_minZValue)); } } } - qptr()->resetArray(dataArray, 0.0, imageHeight, 0.0, imageWidth); + qptr()->resetArray(dataArray); } QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.h b/src/datavisualization/data/qheightmapsurfacedataproxy.h index 8ca9f502..3306059f 100644 --- a/src/datavisualization/data/qheightmapsurfacedataproxy.h +++ b/src/datavisualization/data/qheightmapsurfacedataproxy.h @@ -33,6 +33,10 @@ class QT_DATAVISUALIZATION_EXPORT QHeightMapSurfaceDataProxy : public QSurfaceDa Q_PROPERTY(QImage heightMap READ heightMap WRITE setHeightMap) Q_PROPERTY(QString heightMapFile READ heightMapFile WRITE setHeightMapFile) + Q_PROPERTY(float minXValue READ minXValue WRITE setMinXValue) + Q_PROPERTY(float maxXValue READ maxXValue WRITE setMaxXValue) + Q_PROPERTY(float minZValue READ minZValue WRITE setMinZValue) + Q_PROPERTY(float maxZValue READ maxZValue WRITE setMaxZValue) public: explicit QHeightMapSurfaceDataProxy(QObject *parent = 0); @@ -45,6 +49,16 @@ public: void setHeightMapFile(const QString &filename); QString heightMapFile() const; + void setValueRanges(float minX, float maxX, float minZ, float maxZ); + void setMinXValue(float min); + float minXValue() const; + void setMaxXValue(float max); + float maxXValue() const; + void setMinZValue(float min); + float minZValue() const; + void setMaxZValue(float max); + float maxZValue() const; + protected: explicit QHeightMapSurfaceDataProxy(QHeightMapSurfaceDataProxyPrivate *d, QObject *parent = 0); QHeightMapSurfaceDataProxyPrivate *dptr(); diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy_p.h b/src/datavisualization/data/qheightmapsurfacedataproxy_p.h index 7140c8ef..2d773344 100644 --- a/src/datavisualization/data/qheightmapsurfacedataproxy_p.h +++ b/src/datavisualization/data/qheightmapsurfacedataproxy_p.h @@ -43,6 +43,11 @@ public: QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q); virtual ~QHeightMapSurfaceDataProxyPrivate(); + void setValueRanges(float minX, float maxX, float minZ, float maxZ); + void setMinXValue(float min); + void setMaxXValue(float max); + void setMinZValue(float min); + void setMaxZValue(float max); private: QHeightMapSurfaceDataProxy *qptr(); void handlePendingResolve(); @@ -51,6 +56,11 @@ private: QString m_heightMapFile; QTimer m_resolveTimer; + float m_minXValue; + float m_maxXValue; + float m_minZValue; + float m_maxZValue; + friend class QHeightMapSurfaceDataProxy; }; diff --git a/src/datavisualization/data/qscatterdataitem.cpp b/src/datavisualization/data/qscatterdataitem.cpp index b331e03b..3de5bbd7 100644 --- a/src/datavisualization/data/qscatterdataitem.cpp +++ b/src/datavisualization/data/qscatterdataitem.cpp @@ -84,20 +84,14 @@ QScatterDataItem &QScatterDataItem::operator=(const QScatterDataItem &other) } /*! + * \fn void QScatterDataItem::setPosition(const QVector3D &position) * Sets \a position to this data item. */ -void QScatterDataItem::setPosition(const QVector3D &position) -{ - m_position = position; -} /*! + * \fn QVector3D QScatterDataItem::position() const * \return position of this data item. */ -QVector3D QScatterDataItem::position() const -{ - return m_position; -} //void QScatterDataItem::setSize(qreal size) //{ diff --git a/src/datavisualization/data/qscatterdataitem.h b/src/datavisualization/data/qscatterdataitem.h index 42a27e92..29154259 100644 --- a/src/datavisualization/data/qscatterdataitem.h +++ b/src/datavisualization/data/qscatterdataitem.h @@ -36,8 +36,14 @@ public: QScatterDataItem &operator=(const QScatterDataItem &other); - void setPosition(const QVector3D &position); - QVector3D position() const; + inline void setPosition(const QVector3D &position) { m_position = position; } + inline QVector3D position() const { return m_position; } + inline void setX(float value) { m_position.setX(value); } + inline void setY(float value) { m_position.setY(value); } + inline void setZ(float value) { m_position.setZ(value); } + inline float x() const { return m_position.x(); } + inline float y() const { return m_position.y(); } + inline float z() const { return m_position.z(); } //void setSize(qreal size); //qreal size() const; diff --git a/src/datavisualization/data/qsurfacedataitem.cpp b/src/datavisualization/data/qsurfacedataitem.cpp new file mode 100644 index 00000000..3fb21c95 --- /dev/null +++ b/src/datavisualization/data/qsurfacedataitem.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "qsurfacedataitem_p.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +/*! + * \class QSurfaceDataItem + * \inmodule QtDataVisualization + * \brief The QSurfaceDataItem class provides a container for resolved data to be added to surface + * graphs. + * \since 1.0.0 + * + * A QSurfaceDataItem holds data for a single vertex in surface graph. + * Surface data proxies parse data into QSurfaceDataItem instances for visualizing. + * + * \sa QSurfaceDataProxy, {Qt Data Visualization C++ Classes} + */ + +/*! + * Constructs QSurfaceDataItem. + */ +QSurfaceDataItem::QSurfaceDataItem() + : d_ptr(0) // private data doesn't exist by default (optimization) + +{ +} + +/*! + * Constructs QSurfaceDataItem with \a position. + */ +QSurfaceDataItem::QSurfaceDataItem(const QVector3D &position) + : d_ptr(0), + m_position(position) +{ +} + +/*! + * Constructs a copy of \a other. + */ +QSurfaceDataItem::QSurfaceDataItem(const QSurfaceDataItem &other) +{ + operator=(other); +} + +/*! + * Destroys QSurfaceDataItem. + */ +QSurfaceDataItem::~QSurfaceDataItem() +{ +} + +/*! + * Assigns a copy of \a other to this object. + */ +QSurfaceDataItem &QSurfaceDataItem::operator=(const QSurfaceDataItem &other) +{ + m_position = other.m_position; + //m_size = other.m_size; + + if (other.d_ptr) + createExtraData(); + else + d_ptr = 0; + // TODO set extra data + + return *this; +} + +/*! + * \fn void QSurfaceDataItem::setPosition(const QVector3D &position) + * Sets \a position to this data item. + */ + +/*! + * \fn QVector3D QSurfaceDataItem::position() const + * \return position of this data item. + */ + +/*! + * \internal + */ +void QSurfaceDataItem::createExtraData() +{ + if (!d_ptr) + d_ptr = new QSurfaceDataItemPrivate; +} + +QSurfaceDataItemPrivate::QSurfaceDataItemPrivate() +{ +} + +QSurfaceDataItemPrivate::~QSurfaceDataItemPrivate() +{ +} + +QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/data/qsurfacedataitem.h b/src/datavisualization/data/qsurfacedataitem.h new file mode 100644 index 00000000..dbc849d3 --- /dev/null +++ b/src/datavisualization/data/qsurfacedataitem.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef QSURFACEDATAITEM_H +#define QSURFACEDATAITEM_H + +#include <QtDataVisualization/qdatavisualizationenums.h> +#include <QVector3D> + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class QSurfaceDataItemPrivate; + +class QT_DATAVISUALIZATION_EXPORT QSurfaceDataItem +{ +public: + QSurfaceDataItem(); + QSurfaceDataItem(const QVector3D &position); + QSurfaceDataItem(const QSurfaceDataItem &other); + ~QSurfaceDataItem(); + + QSurfaceDataItem &operator=(const QSurfaceDataItem &other); + + inline void setPosition(const QVector3D &position) { m_position = position; } + inline QVector3D position() const { return m_position; } + inline void setX(float value) { m_position.setX(value); } + inline void setY(float value) { m_position.setY(value); } + inline void setZ(float value) { m_position.setZ(value); } + inline float x() const { return m_position.x(); } + inline float y() const { return m_position.y(); } + inline float z() const { return m_position.z(); } + +protected: + virtual void createExtraData(); + + QSurfaceDataItemPrivate *d_ptr; + +private: + QVector3D m_position; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/data/qsurfacedataitem_p.h b/src/datavisualization/data/qsurfacedataitem_p.h new file mode 100644 index 00000000..d13679a8 --- /dev/null +++ b/src/datavisualization/data/qsurfacedataitem_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the QtDataVisualization API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QSURFACEDATAITEM_P_H +#define QSURFACEDATAITEM_P_H + +#include "datavisualizationglobal_p.h" +#include "qsurfacedataitem.h" + +QT_DATAVISUALIZATION_BEGIN_NAMESPACE + +class QSurfaceDataItemPrivate +{ +public: + QSurfaceDataItemPrivate(); + virtual ~QSurfaceDataItemPrivate(); + + // TODO stores other data for surface items besides position + +protected: + friend class QSurfaceDataItem; +}; + +QT_DATAVISUALIZATION_END_NAMESPACE + +#endif diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp index 3b683bbc..f1351521 100644 --- a/src/datavisualization/data/qsurfacedataproxy.cpp +++ b/src/datavisualization/data/qsurfacedataproxy.cpp @@ -21,10 +21,6 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE -// Default ranges correspond value axis defaults -const qreal defaultMinValue = 0.0; -const qreal defaultMaxValue = 10.0; - /*! * \class QSurfaceDataProxy * \inmodule QtDataVisualization @@ -33,17 +29,19 @@ const qreal defaultMaxValue = 10.0; * * QSurfaceDataProxy takes care of surface related data handling. The QSurfaceDataProxy handles the data * in rows and for this it provides two auxiliary typedefs. QSurfaceDataArray is a QList for - * controlling the rows. For rows there is a QVector typedef QSurfaceDataRow which takes in qreal - * values. See Q3DSurface documentation and basic sample code there how to feed the data for the + * controlling the rows. For rows there is a QVector QSurfaceDataRow which contains QSurfaceDataItem + * objects. See Q3DSurface documentation and basic sample code there how to feed the data for the * QSurfaceDataProxy. * - * All rows must have same number of values. + * All rows must have same number of items. + * + * When determining what rows and columns are visible, the first item in each row and the first item in + * each column determine if the whole row or column is visible, even if other items in the row or column + * individually have different X- or Z-coordinates. * * \note Surfaces with less than two rows or columns are not considered valid surfaces and will * not get rendered. * - * \note The way row and column values are handled is subject to change after technology preview. - * * QSurfaceDataProxy supports the following format tags for QAbstractDataProxy::setItemLabelFormat(): * \table * \row @@ -84,42 +82,6 @@ const qreal defaultMaxValue = 10.0; */ /*! - * \qmlproperty qreal QSurfaceDataProxy::minValueRows - * - * The minimum value of the range in rows. For instance if function z value varies between -8.0 - * and 8.0 set this property to -8.0. - * - * \note The way row and column values are handled is subject to change after technology preview. - */ - -/*! - * \qmlproperty qreal QSurfaceDataProxy::maxValueRows - * - * The maximum value of the range in rows. For instance if function z value varies between -8.0 - * and 8.0 set this property to 8.0. - * - * \note The way row and column values are handled is subject to change after technology preview. - */ - -/*! - * \qmlproperty qreal QSurfaceDataProxy::minValueColumns - * - * The minimum value of the range in columns. For instance if function x value varies between -8.0 - * and 8.0 set this property to -8.0. - * - * \note The way row and column values are handled is subject to change after technology preview. - */ - -/*! - * \qmlproperty qreal QSurfaceDataProxy::maxValueColumns - * - * The maximum value of the range in columns. For instance if function x value varies between -8.0 - * and 8.0 set this property to 8.0. - * - * \note The way row and column values are handled is subject to change after technology preview. - */ - -/*! * Constructs QSurfaceDataProxy with the given \a parent. */ QSurfaceDataProxy::QSurfaceDataProxy(QObject *parent) : @@ -148,36 +110,16 @@ QSurfaceDataProxy::~QSurfaceDataProxy() * signal. * Passing null array deletes the old array and creates a new empty array. * All rows in \a newArray must be of same length. - * Row and column ranges are reset to defaults, unless \a newArray is the same as the old array. - * In that case, old row and column ranges are kept. */ void QSurfaceDataProxy::resetArray(QSurfaceDataArray *newArray) { if (dptr()->m_dataArray != newArray) { - dptr()->resetArray(newArray, defaultMinValue, defaultMaxValue, defaultMinValue, - defaultMaxValue); + dptr()->resetArray(newArray); } emit arrayReset(); } /*! - * Takes ownership of the \a newArray. Clears the existing array and if the \a newArray is - * different than the existing array. If it's the same array, this just triggers arrayReset() - * signal and updates row/column values. - * Passing null array deletes the old array and creates a new empty array. - * All rows in \a newArray must be of same length. - * Row and column ranges are set to values defined by the rest of the parameters: \a minValueRows, - * \a maxValueRows, \a minValueColumns, and \a maxValueColumns. - */ -void QSurfaceDataProxy::resetArray(QSurfaceDataArray *newArray, qreal minValueRows, - qreal maxValueRows, qreal minValueColumns, - qreal maxValueColumns) -{ - dptr()->resetArray(newArray, minValueRows, maxValueRows, minValueColumns, maxValueColumns); - emit arrayReset(); -} - -/*! * \return pointer to the data array. */ const QSurfaceDataArray *QSurfaceDataProxy::array() const @@ -241,110 +183,13 @@ const QSurfaceDataProxyPrivate *QSurfaceDataProxy::dptrc() const * emit this signal yourself or the graph won't get updated. */ -/*! - * Sets the value range for rows from \a min to \a max. For instance if function z value varies between -8.0 - * and 8.0 set \a min to -8.0 and \a max to 8.0. - * When setting the range, the max is adjusted if necessary, to ensure that the range remains valid. - */ -void QSurfaceDataProxy::setValueRangeRows(qreal min, qreal max) -{ - dptr()->setValueRangeRows(min, max); -} - -/*! - * Sets the value range for columns from \a min to \a max. For instance if function x value varies between -8.0 - * and 8.0 set \a min to -8.0 and \a max to 8.0. - * When setting the range, the max is adjusted if necessary, to ensure that the range remains valid. - */ -void QSurfaceDataProxy::setValueRangeColumns(qreal min, qreal max) -{ - dptr()->setValueRangeColumns(min, max); -} - -/*! - * \property QSurfaceDataProxy::minValueRows - * - * Defines the minimum value of the range for rows. For instance if function z value varies between -8.0 - * and 8.0 set this property to -8.0. - * When setting this property the max is adjusted if necessary, to ensure that the range remains - * valid. - */ -void QSurfaceDataProxy::setMinValueRows(qreal min) -{ - dptr()->setMinValueRows(min); -} - -qreal QSurfaceDataProxy::minValueRows() const -{ - return dptrc()->m_minValueRows; -} - -/*! - * \property QSurfaceDataProxy::maxValueRows - * - * Defines the maximum value of the range for rows. For instance if function z value varies between -8.0 - * and 8.0 set this property to 8.0. - * When setting this property the min is adjusted if necessary, to ensure that the range remains - * valid. - */ -void QSurfaceDataProxy::setMaxValueRows(qreal max) -{ - dptr()->setMaxValueRows(max); -} - -qreal QSurfaceDataProxy::maxValueRows() const -{ - return dptrc()->m_maxValueRows; -} - -/*! - * \property QSurfaceDataProxy::minValueColumns - * - * Defines the minimum value of the range for columns. For instance if function x value varies between -8.0 - * and 8.0 set this property to -8.0. - * When setting this property the min is adjusted if necessary, to ensure that the range remains - * valid. - */ -void QSurfaceDataProxy::setMinValueColumns(qreal min) -{ - dptr()->setMinValueColumns(min); -} - -qreal QSurfaceDataProxy::minValueColumns() const -{ - return dptrc()->m_minValueColumns; -} - -/*! - * \property QSurfaceDataProxy::maxValueColumns - * - * Defines the maximum value of the range for columns. For instance if function x value varies between -8.0 - * and 8.0 set this property to 8.0. - * When setting this property the min is adjusted if necessary, to ensure that the range remains - * valid. - */ -void QSurfaceDataProxy::setMaxValueColumns(qreal max) -{ - dptr()->setMaxValueColumns(max); -} - -qreal QSurfaceDataProxy::maxValueColumns() const -{ - return dptrc()->m_maxValueColumns; -} - - // // QSurfaceDataProxyPrivate // QSurfaceDataProxyPrivate::QSurfaceDataProxyPrivate(QSurfaceDataProxy *q) : QAbstractDataProxyPrivate(q, QAbstractDataProxy::DataTypeSurface), - m_dataArray(new QSurfaceDataArray), - m_minValueRows(defaultMinValue), - m_maxValueRows(defaultMaxValue), - m_minValueColumns(defaultMinValue), - m_maxValueColumns(defaultMaxValue) + m_dataArray(new QSurfaceDataArray) { m_itemLabelFormat = QStringLiteral("@yLabel (@xLabel, @zLabel)"); } @@ -354,9 +199,7 @@ QSurfaceDataProxyPrivate::~QSurfaceDataProxyPrivate() clearArray(); } -void QSurfaceDataProxyPrivate::resetArray(QSurfaceDataArray *newArray, qreal minValueRows, - qreal maxValueRows, qreal minValueColumns, - qreal maxValueColumns) +void QSurfaceDataProxyPrivate::resetArray(QSurfaceDataArray *newArray) { if (!newArray) newArray = new QSurfaceDataArray; @@ -365,115 +208,6 @@ void QSurfaceDataProxyPrivate::resetArray(QSurfaceDataArray *newArray, qreal min clearArray(); m_dataArray = newArray; } - - setValueRangeRows(minValueRows, maxValueRows); - setValueRangeColumns(minValueColumns, maxValueColumns); -} - -void QSurfaceDataProxyPrivate::setValueRangeRows(qreal min, qreal max) -{ - bool changed = false; - if (m_minValueRows != min) { - m_minValueRows = min; - changed = true; - } - if (m_maxValueRows != max || min >= max) { - if (min >= max) { - m_maxValueRows = min + 1.0; - qWarning() << "Warning: Tried to set invalid range for value range." - " Range automatically adjusted to a valid one:" - << min << "-" << max << "-->" << m_minValueRows << "-" << m_maxValueRows; - } else { - m_maxValueRows = max; - } - changed = true; - } - - if (changed) - emit qptr()->valueRangeRowsChanged(min, max); -} - -void QSurfaceDataProxyPrivate::setValueRangeColumns(qreal min, qreal max) -{ - bool changed = false; - if (m_minValueColumns != min) { - m_minValueColumns = min; - changed = true; - } - if (m_maxValueColumns != max || min >= max) { - if (min >= max) { - m_maxValueColumns = min + 1.0; - qWarning() << "Warning: Tried to set invalid range for value range." - " Range automatically adjusted to a valid one:" - << min << "-" << max << "-->" << m_minValueColumns << "-" << m_maxValueColumns; - } else { - m_maxValueColumns = max; - } - changed = true; - } - - if (changed) - emit qptr()->valueRangeColumnsChanged(min, max); -} - -void QSurfaceDataProxyPrivate::setMinValueRows(qreal min) -{ - if (min != m_minValueRows) { - if (min >= m_maxValueRows) { - qreal oldMax = m_maxValueRows; - m_maxValueRows = min + 1.0; - qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for" - " value range. Maximum automatically adjusted to a valid one:" - << oldMax << "-->" << m_maxValueRows; - } - m_minValueRows = min; - emit qptr()->valueRangeRowsChanged(m_minValueRows, m_maxValueRows); - } -} - -void QSurfaceDataProxyPrivate::setMaxValueRows(qreal max) -{ - if (m_maxValueRows != max) { - if (max <= m_minValueRows) { - qreal oldMin = m_minValueRows; - m_minValueRows = max - 1.0; - qWarning() << "Warning: Tried to set maximum to equal or smaller than minimum for" - " value range. Minimum automatically adjusted to a valid one:" - << oldMin << "-->" << m_minValueRows; - } - m_maxValueRows = max; - emit qptr()->valueRangeRowsChanged(m_minValueRows, m_maxValueRows); - } -} - -void QSurfaceDataProxyPrivate::setMinValueColumns(qreal min) -{ - if (min != m_minValueColumns) { - if (min >= m_maxValueColumns) { - qreal oldMax = m_maxValueColumns; - m_maxValueColumns = min + 1.0; - qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for" - " value range. Maximum automatically adjusted to a valid one:" - << oldMax << "-->" << m_maxValueColumns; - } - m_minValueColumns = min; - emit qptr()->valueRangeColumnsChanged(m_minValueColumns, m_maxValueRows); - } -} - -void QSurfaceDataProxyPrivate::setMaxValueColumns(qreal max) -{ - if (m_maxValueColumns != max) { - if (max <= m_minValueColumns) { - qreal oldMin = m_minValueColumns; - m_minValueColumns = max - 1.0; - qWarning() << "Warning: Tried to set maximum to equal or smaller than minimum for" - " value range. Minimum automatically adjusted to a valid one:" - << oldMin << "-->" << m_minValueColumns; - } - m_maxValueColumns = max; - emit qptr()->valueRangeColumnsChanged(m_minValueColumns, m_maxValueColumns); - } } QSurfaceDataProxy *QSurfaceDataProxyPrivate::qptr() @@ -492,15 +226,15 @@ void QSurfaceDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxV columns = m_dataArray->at(0)->size(); if (rows && columns) { - min = m_dataArray->at(0)->at(0); - max = m_dataArray->at(0)->at(0); + min = m_dataArray->at(0)->at(0).y(); + max = m_dataArray->at(0)->at(0).y(); } for (int i = 0; i < rows; i++) { QSurfaceDataRow *row = m_dataArray->at(i); if (row) { for (int j = 0; j < columns; j++) { - qreal itemValue = m_dataArray->at(i)->at(j); + qreal itemValue = m_dataArray->at(i)->at(j).y(); if (min > itemValue) min = itemValue; if (max < itemValue) @@ -509,12 +243,19 @@ void QSurfaceDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxV } } - minValues.setX(m_minValueColumns); minValues.setY(min); - minValues.setZ(m_minValueRows); - maxValues.setX(m_maxValueColumns); maxValues.setY(max); - maxValues.setZ(m_maxValueRows); + if (columns) { + minValues.setX(m_dataArray->at(0)->at(0).x()); + minValues.setZ(m_dataArray->at(0)->at(0).z()); + maxValues.setX(m_dataArray->at(0)->last().x()); + maxValues.setZ(m_dataArray->last()->at(0).z()); + } else { + minValues.setX(0.0f); + minValues.setZ(0.0f); + maxValues.setX(0.0f); + maxValues.setZ(0.0f); + } } void QSurfaceDataProxyPrivate::clearRow(int rowIndex) diff --git a/src/datavisualization/data/qsurfacedataproxy.h b/src/datavisualization/data/qsurfacedataproxy.h index de31f188..2aeda80e 100644 --- a/src/datavisualization/data/qsurfacedataproxy.h +++ b/src/datavisualization/data/qsurfacedataproxy.h @@ -19,12 +19,11 @@ #ifndef QSURFACEDATAPROXY_H #define QSURFACEDATAPROXY_H -#include <QtDataVisualization/qdatavisualizationglobal.h> #include <QtDataVisualization/qabstractdataproxy.h> +#include <QtDataVisualization/qsurfacedataitem.h> QT_DATAVISUALIZATION_BEGIN_NAMESPACE -typedef qreal QSurfaceDataItem; // Let's stick to this for now, expand if needed typedef QVector<QSurfaceDataItem> QSurfaceDataRow; typedef QList<QSurfaceDataRow *> QSurfaceDataArray; @@ -36,10 +35,6 @@ class QT_DATAVISUALIZATION_EXPORT QSurfaceDataProxy : public QAbstractDataProxy Q_PROPERTY(int rowCount READ rowCount) Q_PROPERTY(int columnCount READ columnCount) - Q_PROPERTY(qreal minValueRows READ minValueRows WRITE setMinValueRows NOTIFY valueRangeRowsChanged) - Q_PROPERTY(qreal maxValueRows READ maxValueRows WRITE setMaxValueRows NOTIFY valueRangeRowsChanged) - Q_PROPERTY(qreal minValueColumns READ minValueColumns WRITE setMinValueColumns NOTIFY valueRangeColumnsChanged) - Q_PROPERTY(qreal maxValueColumns READ maxValueColumns WRITE setMaxValueColumns NOTIFY valueRangeColumnsChanged) public: explicit QSurfaceDataProxy(QObject *parent = 0); @@ -50,20 +45,7 @@ public: const QSurfaceDataArray *array() const; const QSurfaceDataItem *itemAt(int index) const; - void setValueRangeRows(qreal min, qreal max); - void setValueRangeColumns(qreal min, qreal max); - void setMinValueRows(qreal min); - qreal minValueRows() const; - void setMaxValueRows(qreal max); - qreal maxValueRows() const; - void setMinValueColumns(qreal min); - qreal minValueColumns() const; - void setMaxValueColumns(qreal max); - qreal maxValueColumns() const; - void resetArray(QSurfaceDataArray *newArray); - void resetArray(QSurfaceDataArray *newArray, qreal minValueRows, qreal maxValueRows, - qreal minValueColumns, qreal maxValueColumns); signals: void arrayReset(); diff --git a/src/datavisualization/data/qsurfacedataproxy_p.h b/src/datavisualization/data/qsurfacedataproxy_p.h index a40e8d65..4c8c2820 100644 --- a/src/datavisualization/data/qsurfacedataproxy_p.h +++ b/src/datavisualization/data/qsurfacedataproxy_p.h @@ -43,18 +43,7 @@ public: QSurfaceDataProxyPrivate(QSurfaceDataProxy *q); virtual ~QSurfaceDataProxyPrivate(); - void resetArray(QSurfaceDataArray *newArray, qreal minValueRows, qreal maxValueRows, - qreal minValueColumns, qreal maxValueColumns); - - void setValueRangeRows(qreal min, qreal max); - void setValueRangeColumns(qreal min, qreal max); - void setMinValueRows(qreal min); - void setMaxValueRows(qreal max); - void setMinValueColumns(qreal min); - void setMaxValueColumns(qreal max); - - qreal rowValue(int segment, int segmentCount); - qreal columnValue(int segment, int segmentCount); + void resetArray(QSurfaceDataArray *newArray); void limitValues(QVector3D &minValues, QVector3D &maxValues); @@ -66,11 +55,6 @@ private: void clearRow(int rowIndex); void clearArray(); - qreal m_minValueRows; - qreal m_maxValueRows; - qreal m_minValueColumns; - qreal m_maxValueColumns; - friend class QSurfaceDataProxy; }; diff --git a/src/datavisualization/data/surfaceitemmodelhandler.cpp b/src/datavisualization/data/surfaceitemmodelhandler.cpp index a9882040..70482162 100644 --- a/src/datavisualization/data/surfaceitemmodelhandler.cpp +++ b/src/datavisualization/data/surfaceitemmodelhandler.cpp @@ -49,11 +49,6 @@ void SurfaceItemModelHandler::resolveModel() return; } - float minRowValue = 0.0f; - float maxRowValue = 1.0f; - float minColumnValue = 0.0f; - float maxColumnValue = 1.0f; - QHash<int, QByteArray> roleHash = m_itemModel->roleNames(); // Default to display role if no mapping @@ -72,16 +67,12 @@ void SurfaceItemModelHandler::resolveModel() } for (int i = 0; i < rowCount; i++) { QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i); - for (int j = 0; j < columnCount; j++) - newProxyRow[j] = m_itemModel->index(i, j).data(valueRole).toReal(); - } - if (rowCount) { - minRowValue = m_itemModel->headerData(0, Qt::Vertical).toFloat(); - maxRowValue = m_itemModel->headerData(rowCount - 1, Qt::Vertical).toFloat(); - } - if (columnCount) { - minColumnValue = m_itemModel->headerData(0, Qt::Horizontal).toFloat(); - maxColumnValue = m_itemModel->headerData(columnCount - 1, Qt::Horizontal).toFloat(); + for (int j = 0; j < columnCount; j++) { + newProxyRow[j].setPosition( + QVector3D(m_itemModel->headerData(j, Qt::Horizontal).toFloat(), + m_itemModel->index(i, j).data(valueRole).toFloat(), + m_itemModel->headerData(i, Qt::Vertical).toFloat())); + } } } else { int rowRole = roleHash.key(mapping->rowRole().toLatin1()); @@ -139,22 +130,15 @@ void SurfaceItemModelHandler::resolveModel() for (int i = 0; i < rowList.size(); i++) { QString rowKey = rowList.at(i); QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i); - for (int j = 0; j < columnList.size(); j++) - newProxyRow[j] = itemValueMap[rowKey][columnList.at(j)]; - } - - // Use first and last roles converted to values for limits - if (rowList.size()) { - minRowValue = rowList.first().toFloat(); - maxRowValue = rowList.last().toFloat(); - } - if (columnList.size()) { - minColumnValue = columnList.first().toFloat(); - maxColumnValue = columnList.last().toFloat(); + for (int j = 0; j < columnList.size(); j++) { + newProxyRow[j].setPosition(QVector3D(columnList.at(j).toFloat(), + itemValueMap[rowKey][columnList.at(j)], + rowList.at(i).toFloat())); + } } } - m_proxy->resetArray(m_proxyArray, minRowValue, maxRowValue, minColumnValue, maxColumnValue); + m_proxy->resetArray(m_proxyArray); } QT_DATAVISUALIZATION_END_NAMESPACE diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp index 0009098e..b0e07d70 100644 --- a/src/datavisualization/engine/bars3drenderer.cpp +++ b/src/datavisualization/engine/bars3drenderer.cpp @@ -189,7 +189,7 @@ void Bars3DRenderer::updateDataModel(QBarDataProxy *dataProxy) for (; j < updateSize ; j++) { qreal value = dataRow->at(dataColIndex).value(); m_renderItemArray[i][j].setValue(value); - m_renderItemArray[i][j].setHeight(value / m_heightNormalizer); + m_renderItemArray[i][j].setHeight(GLfloat(value) / m_heightNormalizer); dataColIndex++; } } diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp index bd85ceee..64ceb47e 100644 --- a/src/datavisualization/engine/surface3drenderer.cpp +++ b/src/datavisualization/engine/surface3drenderer.cpp @@ -86,8 +86,8 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller) m_maxVisibleColumnValue(0.0f), m_minVisibleRowValue(0.0f), m_maxVisibleRowValue(0.0f), - m_dataStepX(0.0f), - m_dataStepZ(0.0f), + m_visibleColumnRange(0.0f), + m_visibleRowRange(0.0f), m_backgroundObj(0), m_gridLineObj(0), m_labelObj(0), @@ -207,11 +207,11 @@ void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy) { calculateSceneScalingFactors(); - const QSurfaceDataArray *array = dataProxy->array(); + const QSurfaceDataArray &array = *dataProxy->array(); // Need minimum of 2x2 array to draw a surface - if (array->size() >= 2 && array->at(0)->size() >= 2) { - QRect sampleSpace = calculateSampleRect(dataProxy); + if (array.size() >= 2 && array.at(0)->size() >= 2) { + QRect sampleSpace = calculateSampleRect(array); bool dimensionChanged = false; if (m_sampleSpace != sampleSpace) { @@ -232,7 +232,7 @@ void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy) } for (int i = 0; i < sampleSpace.height(); i++) { for (int j = 0; j < sampleSpace.width(); j++) - (*(m_dataArray.at(i)))[j] = array->at(i + sampleSpace.y())->at(j + sampleSpace.x()); + (*(m_dataArray.at(i)))[j] = array.at(i + sampleSpace.y())->at(j + sampleSpace.x()); } if (m_dataArray.size() > 0) { @@ -242,11 +242,11 @@ void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy) // Note: Data setup can change samplespace (as min width/height is 1) if (m_cachedSmoothSurface) { m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer, - dimensionChanged, + m_axisCacheY.min(), dimensionChanged, m_cachedSelectionMode != QDataVis::ModeNone); } else { m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, - dimensionChanged, + m_axisCacheY.min(), dimensionChanged, m_cachedSelectionMode != QDataVis::ModeNone); } @@ -294,65 +294,107 @@ void Surface3DRenderer::updateSliceDataModel(int selectionId) loadSliceSurfaceObj(); if (m_cachedSmoothSurface) { - m_sliceSurfaceObj->setUpSmoothData(m_sliceDataArray, sliceRect, m_heightNormalizer, - true, true); + m_sliceSurfaceObj->setUpSmoothData(m_sliceDataArray, sliceRect, m_axisCacheY.min(), + m_heightNormalizer, true, true); } else { - m_sliceSurfaceObj->setUpData(m_sliceDataArray, sliceRect, m_heightNormalizer, true, - true); + m_sliceSurfaceObj->setUpData(m_sliceDataArray, sliceRect, m_heightNormalizer, + m_axisCacheY.min(), true, true); } } } -QRect Surface3DRenderer::calculateSampleRect(QSurfaceDataProxy *dataProxy) +QRect Surface3DRenderer::calculateSampleRect(const QSurfaceDataArray &array) { QRect sampleSpace; - m_minVisibleColumnValue = dataProxy->minValueColumns(); - m_maxVisibleColumnValue = dataProxy->maxValueColumns(); - m_minVisibleRowValue = dataProxy->minValueRows(); - m_maxVisibleRowValue = dataProxy->maxValueRows(); - m_dataStepX = (m_maxVisibleColumnValue - m_minVisibleColumnValue) / (dataProxy->columnCount() - 1); - m_dataStepZ = (m_maxVisibleRowValue - m_minVisibleRowValue) / (dataProxy->rowCount() - 1); - - if (m_minVisibleColumnValue > m_axisCacheX.max() || m_maxVisibleColumnValue < m_axisCacheX.min() - || m_minVisibleRowValue > m_axisCacheZ.max() || m_maxVisibleRowValue < m_axisCacheZ.min()) { + int rowCount = array.size(); + int columnCount = array.at(0)->size(); + + int i; + bool found; + float axisMinX = float(m_axisCacheX.min()); + float axisMaxX = float(m_axisCacheX.max()); + float axisMinZ = float(m_axisCacheZ.min()); + float axisMaxZ = float(m_axisCacheZ.max()); + + // Comparisons between float and double are not accurate, so fudge our comparison values + //a little to get all rows and columns into view that need to be visible. + const float fudgeFactor = 0.00001f; + float fudgedAxisXRange = (axisMaxX - axisMinX) * fudgeFactor; + float fudgedAxisZRange = (axisMaxZ - axisMinZ) * fudgeFactor; + axisMinX -= fudgedAxisXRange; + axisMinZ -= fudgedAxisZRange; + axisMaxX += fudgedAxisXRange; + axisMaxZ += fudgedAxisZRange; + + // m_minVisibleColumnValue + for (i = 0, found = false; i < columnCount; i++) { + if (array.at(0)->at(i).x() >= axisMinX) { + found = true; + break; + } + } + if (found) { + m_minVisibleColumnValue = array.at(0)->at(i).x(); + sampleSpace.setLeft(i); + } else { sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; } - int index = 0; - while (m_minVisibleColumnValue < m_axisCacheX.min()) { - m_minVisibleColumnValue += m_dataStepX; - index++; + // m_maxVisibleColumnValue + for (i = columnCount - 1, found = false; i >= 0; i--) { + if (array.at(0)->at(i).x() <= axisMaxX) { + found = true; + break; + } } - sampleSpace.setLeft(index); - - index = dataProxy->columnCount() - 1; - while (m_maxVisibleColumnValue > m_axisCacheX.max()) { - m_maxVisibleColumnValue -= m_dataStepX; - index--; + if (found) { + m_maxVisibleColumnValue = array.at(0)->at(i).x(); + sampleSpace.setRight(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; } - sampleSpace.setRight(index); - index = 0; - while (m_minVisibleRowValue < m_axisCacheZ.min()) { - m_minVisibleRowValue += m_dataStepZ; - index++; + // m_minVisibleRowValue + for (i = 0, found = false; i < rowCount; i++) { + if (array.at(i)->at(0).z() >= axisMinZ) { + found = true; + break; + } + } + if (found) { + m_minVisibleRowValue = array.at(i)->at(0).z(); + sampleSpace.setTop(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; } - sampleSpace.setTop(index); - index = dataProxy->rowCount() - 1; - while (m_maxVisibleRowValue > m_axisCacheZ.max()) { - m_maxVisibleRowValue -= m_dataStepZ; - index--; + // m_maxVisibleRowValue + for (i = rowCount - 1, found = false; i >= 0; i--) { + if (array.at(i)->at(0).z() <= axisMaxZ) { + found = true; + break; + } } - sampleSpace.setBottom(index); - - m_surfaceScaleX = m_scaleX * (m_maxVisibleColumnValue - m_minVisibleColumnValue) / m_areaSize.width(); - m_surfaceScaleZ = m_scaleZ * (m_maxVisibleRowValue - m_minVisibleRowValue) / m_areaSize.height(); - GLfloat axis2XCenterX = (m_axisCacheX.min() + m_axisCacheX.max()); - GLfloat axis2XCenterZ = (m_axisCacheZ.min() + m_axisCacheZ.max()); - GLfloat data2XCenterX = (m_minVisibleColumnValue + m_maxVisibleColumnValue); - GLfloat data2XCenterZ = (m_minVisibleRowValue + m_maxVisibleRowValue); + if (found) { + m_maxVisibleRowValue = array.at(i)->at(0).z(); + sampleSpace.setBottom(i); + } else { + sampleSpace.setWidth(-1); // to indicate nothing needs to be shown + return sampleSpace; + } + + m_visibleColumnRange = m_maxVisibleColumnValue - m_minVisibleColumnValue; + m_visibleRowRange = m_maxVisibleRowValue - m_minVisibleRowValue; + m_surfaceScaleX = m_scaleX * m_visibleColumnRange / m_areaSize.width(); + m_surfaceScaleZ = m_scaleZ * m_visibleRowRange / m_areaSize.height(); + GLfloat axis2XCenterX = axisMinX + axisMaxX; + GLfloat axis2XCenterZ = axisMinZ + axisMaxZ; + GLfloat data2XCenterX = GLfloat(m_minVisibleColumnValue + m_maxVisibleColumnValue); + GLfloat data2XCenterZ = GLfloat(m_minVisibleRowValue + m_maxVisibleRowValue); m_surfaceOffsetX = m_scaleX * (data2XCenterX - axis2XCenterX) / m_areaSize.width(); m_surfaceOffsetZ = -m_scaleZ * (data2XCenterZ - axis2XCenterZ) / m_areaSize.height(); @@ -1759,20 +1801,18 @@ bool Surface3DRenderer::updateSmoothStatus(bool enable) if (enable != m_cachedSmoothSurface) { m_cachedSmoothSurface = enable; changed = true; - } - - if (changed) initSurfaceShaders(); + } - // If no surface object created yet, don't try to update the object, instead return - if (!m_surfaceObj || !changed) { - return m_cachedSmoothSurface; - } else { + // If no surface object created yet, don't try to update the object + if (m_surfaceObj && changed && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) { if (m_cachedSmoothSurface) { - m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer, true, + m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer, + m_axisCacheY.min(), true, m_cachedSelectionMode != QDataVis::ModeNone); } else { - m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, true, + m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, + m_axisCacheY.min(), true, m_cachedSelectionMode != QDataVis::ModeNone); } } @@ -1853,27 +1893,27 @@ void Surface3DRenderer::surfacePointSelected(int id) { int column = (id - 1) % m_sampleSpace.width(); int row = (id - 1) / m_sampleSpace.width(); - qreal value = m_dataArray.at(row)->at(column); + qreal value = qreal(m_dataArray.at(row)->at(column).y()); if (!m_selectionPointer) m_selectionPointer = new SelectionPointer(m_controller, m_drawer); QVector3D pos; if (m_cachedSelectionMode == QDataVis::ModeSliceRow) { - pos = normalize(float(column), value, 0.0f); + pos = normalize(column, 0); pos *= QVector3D(m_surfaceScaleX, 1.0f, 0.0f); pos += QVector3D(m_surfaceOffsetX, 0.0f, 0.0f); m_selectionPointer->updateBoundingRect(m_sliceViewPort); m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); } else if (m_cachedSelectionMode == QDataVis::ModeSliceColumn) { - pos = normalize(0.0f, value, float(row)); + pos = normalize(0, row); pos.setX(-pos.z()); pos *= QVector3D(m_surfaceScaleZ, 1.0f, 0.0f); pos += QVector3D(-m_surfaceOffsetZ, 0.0f, 0.0f); m_selectionPointer->updateBoundingRect(m_sliceViewPort); m_selectionPointer->updateSliceData(true, m_autoScaleAdjustment); } else { - pos = normalize(float(column), value, float(row)); + pos = normalize(column, row); pos *= QVector3D(m_surfaceScaleX, 1.0f, m_surfaceScaleZ);; pos += QVector3D(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ); m_selectionPointer->updateBoundingRect(m_mainViewPort); @@ -1906,7 +1946,8 @@ QString Surface3DRenderer::createSelectionLabel(qreal value, int column, int row QString labelFormat = m_axisCacheX.labelFormat(); if (labelFormat.isEmpty()) labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, columnInRange(column)); + QString valueLabelText = generateValueLabel(labelFormat, + m_dataArray.at(row)->at(column).x()); labelText.replace(xLabelTag, valueLabelText); } if (labelText.contains(yLabelTag)) { @@ -1920,30 +1961,21 @@ QString Surface3DRenderer::createSelectionLabel(qreal value, int column, int row QString labelFormat = m_axisCacheZ.labelFormat(); if (labelFormat.isEmpty()) labelFormat = Utils::defaultLabelFormat(); - QString valueLabelText = generateValueLabel(labelFormat, rowInRange(row)); + QString valueLabelText = generateValueLabel(labelFormat, + m_dataArray.at(row)->at(column).z()); labelText.replace(zLabelTag, valueLabelText); } return labelText; } -// Transforms the model column coordinate to axis coordinate -qreal Surface3DRenderer::columnInRange(int column) -{ - return m_dataStepX * qreal(column) + m_minVisibleColumnValue; -} - -// Transforms the model row coordinate to axis coordinate -qreal Surface3DRenderer::rowInRange(int row) -{ - return m_dataStepZ * qreal(row) + m_minVisibleRowValue; -} - -QVector3D Surface3DRenderer::normalize(float x, float y, float z) +QVector3D Surface3DRenderer::normalize(int x, int z) { - float resX = x / ((float(m_sampleSpace.width()) - 1.0f) / 2.0f) - 1.0f; - float resY = y / (m_heightNormalizer / 2.0f) - 1.0f; - float resZ = z / ((float(m_sampleSpace.height()) - 1.0f) / -2.0f) + 1.0f; + float resX = (m_dataArray.at(z)->at(x).x() - m_minVisibleColumnValue) + / (m_visibleColumnRange / 2.0f) - 1.0f; + float resY = m_dataArray.at(z)->at(x).y() / (m_heightNormalizer / 2.0f) - 1.0f; // TODO min + float resZ = (m_dataArray.at(z)->at(x).z() - m_minVisibleRowValue) + / (m_visibleRowRange / -2.0f) + 1.0f; return QVector3D(resX, resY, resZ); } diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h index 10336f06..9ab36214 100644 --- a/src/datavisualization/engine/surface3drenderer_p.h +++ b/src/datavisualization/engine/surface3drenderer_p.h @@ -91,12 +91,12 @@ private: GLfloat m_surfaceScaleZ; GLfloat m_surfaceOffsetX; GLfloat m_surfaceOffsetZ; - qreal m_minVisibleColumnValue; - qreal m_maxVisibleColumnValue; - qreal m_minVisibleRowValue; - qreal m_maxVisibleRowValue; - qreal m_dataStepX; - qreal m_dataStepZ; + GLfloat m_minVisibleColumnValue; + GLfloat m_maxVisibleColumnValue; + GLfloat m_minVisibleRowValue; + GLfloat m_maxVisibleRowValue; + GLfloat m_visibleColumnRange; + GLfloat m_visibleRowRange; ObjectHelper *m_backgroundObj; ObjectHelper *m_gridLineObj; ObjectHelper *m_labelObj; @@ -154,7 +154,7 @@ private: virtual void updateShadowQuality(QDataVis::ShadowQuality quality); virtual void updateTextures(); virtual void initShaders(const QString &vertexShader, const QString &fragmentShader); - QRect calculateSampleRect(QSurfaceDataProxy *dataProxy); + QRect calculateSampleRect(const QSurfaceDataArray &array); void loadBackgroundMesh(); void loadGridLineMesh(); void loadLabelMesh(); @@ -174,9 +174,7 @@ private: void fillIdCorner(uchar *p, uchar r, uchar g, uchar b, uchar a, int stride); void surfacePointSelected(int id); QString createSelectionLabel(qreal value, int column, int row); - qreal columnInRange(int column); - qreal rowInRange(int row); - QVector3D normalize(float x, float y, float z); + QVector3D normalize(int x, int z); #if !defined(QT_OPENGL_ES_2) void updateDepthBuffer(); #endif diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp index 0f9bb7e0..3b58e781 100644 --- a/src/datavisualization/utils/surfaceobject.cpp +++ b/src/datavisualization/utils/surfaceobject.cpp @@ -43,14 +43,17 @@ SurfaceObject::~SurfaceObject() } void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, - GLfloat yRange, bool changeGeometry, bool needTexture) + GLfloat yRange, GLfloat yMin, bool changeGeometry, + bool needTexture) { int columns = space.width(); int rows = space.height(); int totalSize = rows * columns; - GLfloat width = (GLfloat(columns) - 1.0f) / 2.0f; - GLfloat depth = (GLfloat(rows) - 1.0f) / -2.0f; - GLfloat height = yRange / 2.0f; + GLfloat xMin = dataArray.at(0)->at(0).x(); + GLfloat zMin = dataArray.at(0)->at(0).z(); + GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; + GLfloat yNormalizer = yRange / 2.0f; + GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; // Create/populate vertice table if (changeGeometry) @@ -59,16 +62,17 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR QVector<QVector2D> uvs; if (needTexture) uvs.resize(totalSize); - float uvX = 1.0 / float(columns - 1); - float uvY = 1.0 / float(rows - 1); int totalIndex = 0; for (int i = 0; i < rows; i++) { + const QSurfaceDataRow &p = *dataArray.at(i); for (int j = 0; j < columns; j++) { - m_vertices[totalIndex] = QVector3D(float(j) / width - 1.0f, - float(dataArray.at(i)->at(j)) / height - 1.0f, - float(i) / depth + 1.0f); + const QSurfaceDataItem &data = p.at(j); + float normalizedX = ((data.x() - xMin) / xNormalizer); + float normalizedY = ((data.y() - yMin) / yNormalizer); + float normalizedZ = ((data.z() - zMin) / zNormalizer); + m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); if (needTexture) - uvs[totalIndex] = QVector2D(float(j) * uvX, float(i) * uvY); + uvs[totalIndex] = QVector2D(normalizedX / 2.0f, normalizedZ / -2.0f); totalIndex++; } } @@ -152,16 +156,16 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space, - GLfloat yRange, bool changeGeometry, bool needTexture) + GLfloat yRange, GLfloat yMin, bool changeGeometry, bool needTexture) { int columns = space.width(); int rows = space.height(); int totalSize = rows * columns * 2; - GLfloat width = (GLfloat(columns) - 1.0f) / 2.0f; - GLfloat depth = (GLfloat(rows) - 1.0f) / -2.0f; - GLfloat height = yRange / 2.0f; - float uvX = 1.0 / float(columns - 1); - float uvY = 1.0 / float(rows - 1); + GLfloat xMin = dataArray.at(0)->at(0).x(); + GLfloat zMin = dataArray.at(0)->at(0).z(); + GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f; + GLfloat yNormalizer = yRange / 2.0f; + GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f; // Create vertice table if (changeGeometry) @@ -178,13 +182,15 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s int rowColLimit = rowLimit * doubleColumns; for (int i = 0; i < rows; i++) { + const QSurfaceDataRow &row = *dataArray.at(i); for (int j = 0; j < columns; j++) { - m_vertices[totalIndex] = QVector3D(float(j) / width - 1.0f, - float(dataArray.at(i)->at(j)) / height - 1.0f, - float(i) / depth + 1.0f); - + const QSurfaceDataItem &data = row.at(j); + float normalizedX = ((data.x() - xMin) / xNormalizer); + float normalizedY = ((data.y() - yMin) / yNormalizer); + float normalizedZ = ((data.z() - zMin) / zNormalizer); + m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f); if (needTexture) - uvs[totalIndex] = QVector2D(float(j) * uvX, float(i) * uvY); + uvs[totalIndex] = QVector2D(normalizedX / 2.0f, normalizedZ / -2.0f); totalIndex++; @@ -280,10 +286,11 @@ void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVec &normals.at(0), GL_DYNAMIC_DRAW); if (changeGeometry) { - glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D), - &uvs.at(0), GL_STATIC_DRAW); - + if (uvs.size()) { + glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer); + glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(QVector2D), + &uvs.at(0), GL_STATIC_DRAW); + } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(GLint), indices, GL_STATIC_DRAW); diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h index 0a52ca7c..c8273b1b 100644 --- a/src/datavisualization/utils/surfaceobject_p.h +++ b/src/datavisualization/utils/surfaceobject_p.h @@ -45,9 +45,9 @@ public: ~SurfaceObject(); void setUpData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, - bool changeGeometry, bool needTexture); + GLfloat yMin, bool changeGeometry, bool needTexture); void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, - bool changeGeometry, bool needTexture); + GLfloat yMin, bool changeGeometry, bool needTexture); GLuint gridElementBuf(); GLuint gridIndexCount(); |