summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/qmlsurface/qml/qmlsurface/data.qml7
-rw-r--r--examples/qmlsurface/qml/qmlsurface/main.qml10
-rw-r--r--examples/surfacechart/chartmodifier.cpp82
-rw-r--r--examples/surfacechart/chartmodifier.h20
-rw-r--r--examples/surfacechart/main.cpp72
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy.cpp101
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy_p.h4
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.cpp3
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp178
-rw-r--r--src/datavisualization/engine/surface3drenderer_p.h10
-rw-r--r--src/datavisualization/utils/surfaceobject.cpp6
-rw-r--r--src/datavisualization/utils/surfaceobject_p.h4
12 files changed, 338 insertions, 159 deletions
diff --git a/examples/qmlsurface/qml/qmlsurface/data.qml b/examples/qmlsurface/qml/qmlsurface/data.qml
index ccafc5d2..2c6849eb 100644
--- a/examples/qmlsurface/qml/qmlsurface/data.qml
+++ b/examples/qmlsurface/qml/qmlsurface/data.qml
@@ -28,6 +28,13 @@ Item {
HeightMapSurfaceDataProxy {
id: heightMapProxy
heightMapFile: ":/heightmaps/image"
+ onArrayReset: {
+ // We don't want the default data values set by heightmap proxy.
+ minValueRows = 30
+ maxValueRows = 60
+ minValueColumns = 67
+ maxValueColumns = 97
+ }
}
SurfaceDataMapping {
diff --git a/examples/qmlsurface/qml/qmlsurface/main.qml b/examples/qmlsurface/qml/qmlsurface/main.qml
index b8c09b35..7d83c1a0 100644
--- a/examples/qmlsurface/qml/qmlsurface/main.qml
+++ b/examples/qmlsurface/qml/qmlsurface/main.qml
@@ -50,9 +50,7 @@ Item {
cameraPreset: Surface3D.PresetIsometricLeft
dataProxy: surfaceData.heightProxy
axisY.min: 0.0
- axisY.max: 255.0
- axisX.max: 40.0
- axisZ.max: 40.0
+ axisY.max: 250.0
axisX.segmentCount: 10
axisX.subSegmentCount: 2
axisX.labelFormat: "%i"
@@ -141,14 +139,10 @@ Item {
onClicked: {
if (surfaceplot.dataProxy === surfaceData.heightProxy) {
surfaceplot.axisY.max = 500.0
- surfaceplot.axisX.max = 99.0
- surfaceplot.axisZ.max = 99.0
surfaceplot.dataProxy = surfaceData.proxy
text = "Switch to Height Map Proxy"
} else {
- surfaceplot.axisY.max = 255.0
- surfaceplot.axisX.max = 40.0
- surfaceplot.axisZ.max = 40.0
+ surfaceplot.axisY.max = 250.0
surfaceplot.dataProxy = surfaceData.heightProxy
text = "Switch to Item Model Proxy"
}
diff --git a/examples/surfacechart/chartmodifier.cpp b/examples/surfacechart/chartmodifier.cpp
index 608f2701..41be0ecc 100644
--- a/examples/surfacechart/chartmodifier.cpp
+++ b/examples/surfacechart/chartmodifier.cpp
@@ -17,25 +17,36 @@
****************************************************************************/
#include "chartmodifier.h"
-#include <Q3DValueAxis>
-#include <QSurfaceDataProxy>
+#include <QtDataVisualization/Q3DValueAxis>
+#include <QtDataVisualization/QSurfaceDataProxy>
#include <qmath.h>
-
#include <QDebug>
QT_DATAVISUALIZATION_USE_NAMESPACE
ChartModifier::ChartModifier(Q3DSurface *chart)
: m_chart(chart),
- m_xCount(30),
- m_zCount(30),
+ m_gridSliderX(0),
+ m_gridSliderZ(0),
+ m_axisRangeSliderX(0),
+ m_axisRangeSliderZ(0),
+ m_axisMinSliderX(0),
+ m_axisMinSliderZ(0),
+ m_xCount(50),
+ m_zCount(50),
m_activeSample(0),
- m_fontSize(40.0f)
+ m_fontSize(40),
+ m_rangeX(16.0),
+ m_rangeZ(16.0),
+ m_minX(-8.0),
+ m_minZ(-8.0)
{
m_chart->setAxisX(new Q3DValueAxis);
m_chart->setAxisY(new Q3DValueAxis);
m_chart->setAxisZ(new Q3DValueAxis);
+ m_chart->axisX()->setRange(m_minX, m_minX + m_rangeX);
+ m_chart->axisZ()->setRange(m_minZ, m_minZ + m_rangeZ);
}
ChartModifier::~ChartModifier()
@@ -80,7 +91,7 @@ void ChartModifier::toggleSqrtSin(bool enable)
m_chart->axisX()->setLabelFormat("%.2f");
m_chart->axisZ()->setLabelFormat("%.2f");
- m_chart->activeDataProxy()->resetArray(dataArray, -8.0, 8.0, -8.0, 8.0);
+ resetArrayAndSliders(dataArray, -8.0, 8.0, -8.0, 8.0);
m_activeSample = ChartModifier::SqrtSin;
} else {
@@ -94,21 +105,20 @@ void ChartModifier::togglePlane(bool enable)
if (enable) {
QSurfaceDataArray *dataArray = new QSurfaceDataArray;
- qreal y = 2.0 / qreal(m_zCount - 1);
+ qreal y = 1.0 / (qreal(m_zCount - 1) + qreal(m_xCount - 1));
dataArray->reserve(m_zCount);
for (int i = 0; i < m_zCount; i++) {
QSurfaceDataRow *newRow = new QSurfaceDataRow(m_xCount);
for (int j = 0; j < m_xCount; j++)
- (*newRow)[j] = i * y;
+ (*newRow)[j] = (i + j) * y;
*dataArray << newRow;
}
- m_chart->axisY()->setAutoAdjustRange(true);
- m_chart->axisX()->setSegmentCount(4);
+ m_chart->axisY()->setRange(0.0, 1.0);
m_chart->axisX()->setLabelFormat("%.2f");
m_chart->axisZ()->setLabelFormat("%.2f");
- m_chart->activeDataProxy()->resetArray(dataArray, -2.0, 10.0, 16.0, 22.0);
+ resetArrayAndSliders(dataArray, -10.0, 10.0, -10.0, 20.0);
m_activeSample = ChartModifier::Plane;
}
@@ -135,7 +145,7 @@ void ChartModifier::setHeightMapData(bool enable)
m_chart->axisX()->setLabelFormat("%.1f N");
m_chart->axisZ()->setLabelFormat("%.1f E");
- m_chart->activeDataProxy()->resetArray(dataArray, 34.0, 40.0, 18.0, 24.0);
+ resetArrayAndSliders(dataArray, 18.0, 24.0, 34.0, 40.0);
m_activeSample = ChartModifier::Map;
}
@@ -160,7 +170,7 @@ void ChartModifier::adjustXCount(int count)
updateSamples();
- qDebug() << "X count = " << count;
+ qDebug() << "X count =" << count;
}
void ChartModifier::adjustZCount(int count)
@@ -169,7 +179,39 @@ void ChartModifier::adjustZCount(int count)
updateSamples();
- qDebug() << "Z count = " << count;
+ qDebug() << "Z count =" << count;
+}
+
+void ChartModifier::adjustXRange(int range)
+{
+ m_rangeX = range;
+ m_chart->axisX()->setRange(m_minX, m_minX + m_rangeX);
+
+ qDebug() << "X Range =" << range;
+}
+
+void ChartModifier::adjustZRange(int range)
+{
+ m_rangeZ = range;
+ m_chart->axisZ()->setRange(m_minZ, m_minZ + m_rangeZ);
+
+ qDebug() << "Z Range =" << range;
+}
+
+void ChartModifier::adjustXMin(int min)
+{
+ m_minX = min;
+ m_chart->axisX()->setRange(m_minX, m_minX + m_rangeX);
+
+ qDebug() << "X Minimum =" << min;
+}
+
+void ChartModifier::adjustZMin(int min)
+{
+ m_minZ = min;
+ m_chart->axisZ()->setRange(m_minZ, m_minZ + m_rangeZ);
+
+ qDebug() << "Z Minimum =" << min;
}
void ChartModifier::colorPressed()
@@ -199,6 +241,16 @@ void ChartModifier::changeTheme(int theme)
m_chart->setTheme((QDataVis::ColorTheme)theme);
}
+void ChartModifier::resetArrayAndSliders(QSurfaceDataArray *array, qreal minZ, qreal maxZ, qreal minX, qreal maxX)
+{
+ m_axisMinSliderX->setValue(minX);
+ m_axisMinSliderZ->setValue(minZ);
+ m_axisRangeSliderX->setValue(maxX - minX);
+ m_axisRangeSliderZ->setValue(maxZ - minZ);
+
+ m_chart->activeDataProxy()->resetArray(array, minZ, maxZ, minX, maxX);
+}
+
void ChartModifier::changeShadowQuality(int quality)
{
QDataVis::ShadowQuality sq = QDataVis::ShadowQuality(quality);
diff --git a/examples/surfacechart/chartmodifier.h b/examples/surfacechart/chartmodifier.h
index ad0ea162..8d121976 100644
--- a/examples/surfacechart/chartmodifier.h
+++ b/examples/surfacechart/chartmodifier.h
@@ -20,6 +20,7 @@
#define CHARTMODIFIER_H
#include <QtDataVisualization/Q3DSurface>
+#include <QtDataVisualization/QSurfaceDataProxy>
#include <QSlider>
using namespace QtDataVisualization;
@@ -45,8 +46,16 @@ public:
void toggleGridSliderLock(bool enable);
void setGridSliderX(QSlider *slider) { m_gridSliderX = slider; }
void setGridSliderZ(QSlider *slider) { m_gridSliderZ = slider; }
+ void setAxisRangeSliderX(QSlider *slider) { m_axisRangeSliderX = slider; }
+ void setAxisRangeSliderZ(QSlider *slider) { m_axisRangeSliderZ = slider; }
+ void setAxisMinSliderX(QSlider *slider) { m_axisMinSliderX = slider; }
+ void setAxisMinSliderZ(QSlider *slider) { m_axisMinSliderZ = slider; }
void adjustXCount(int count);
void adjustZCount(int count);
+ void adjustXRange(int range);
+ void adjustZRange(int range);
+ void adjustXMin(int min);
+ void adjustZMin(int min);
void updateSamples();
void colorPressed();
void changeFont(const QFont &font);
@@ -57,14 +66,25 @@ public slots:
void changeTheme(int theme);
private:
+ void resetArrayAndSliders(QSurfaceDataArray *array, qreal minZ, qreal maxZ, qreal minX,
+ qreal maxX);
+
Q3DSurface *m_chart;
QSlider *m_gridSliderX;
QSlider *m_gridSliderZ;
+ QSlider *m_axisRangeSliderX;
+ QSlider *m_axisRangeSliderZ;
+ QSlider *m_axisMinSliderX;
+ QSlider *m_axisMinSliderZ;
bool m_gridSlidersLocked;
int m_xCount;
int m_zCount;
int m_activeSample;
int m_fontSize;
+ qreal m_rangeX;
+ qreal m_rangeZ;
+ qreal m_minX;
+ qreal m_minZ;
};
#endif // CHARTMODIFIER_H
diff --git a/examples/surfacechart/main.cpp b/examples/surfacechart/main.cpp
index 3b6ece67..00f3a1c9 100644
--- a/examples/surfacechart/main.cpp
+++ b/examples/surfacechart/main.cpp
@@ -19,7 +19,6 @@
#include "chartmodifier.h"
#include <QApplication>
-#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
@@ -96,6 +95,32 @@ int main(int argc, char *argv[])
gridSliderZ->setMaximum(200);
gridSliderZ->setEnabled(true);
+ QSlider *axisRangeSliderX = new QSlider(Qt::Horizontal, widget);
+ axisRangeSliderX->setTickInterval(1);
+ axisRangeSliderX->setMinimum(2);
+ axisRangeSliderX->setValue(16);
+ axisRangeSliderX->setMaximum(100);
+ axisRangeSliderX->setEnabled(true);
+ QSlider *axisRangeSliderZ = new QSlider(Qt::Horizontal, widget);
+ axisRangeSliderZ->setTickInterval(1);
+ axisRangeSliderZ->setMinimum(2);
+ axisRangeSliderZ->setValue(16);
+ axisRangeSliderZ->setMaximum(100);
+ axisRangeSliderZ->setEnabled(true);
+
+ QSlider *axisMinSliderX = new QSlider(Qt::Horizontal, widget);
+ axisMinSliderX->setTickInterval(1);
+ axisMinSliderX->setMinimum(-50);
+ axisMinSliderX->setValue(-8);
+ axisMinSliderX->setMaximum(50);
+ axisMinSliderX->setEnabled(true);
+ QSlider *axisMinSliderZ = new QSlider(Qt::Horizontal, widget);
+ axisMinSliderZ->setTickInterval(1);
+ axisMinSliderZ->setMinimum(-50);
+ axisMinSliderZ->setValue(-8);
+ axisMinSliderZ->setMaximum(50);
+ axisMinSliderZ->setEnabled(true);
+
QLinearGradient gr(0, 0, 100, 1);
gr.setColorAt(0.0, Qt::blue);
gr.setColorAt(0.5, Qt::yellow);
@@ -126,15 +151,15 @@ int main(int argc, char *argv[])
themeList->addItem(QStringLiteral("Isabelle"));
themeList->setCurrentIndex(0);
- QComboBox *shadowQuality = new QComboBox(widget);
- shadowQuality->addItem(QStringLiteral("None"));
- shadowQuality->addItem(QStringLiteral("Low"));
- shadowQuality->addItem(QStringLiteral("Medium"));
- shadowQuality->addItem(QStringLiteral("High"));
- shadowQuality->addItem(QStringLiteral("Low Soft"));
- shadowQuality->addItem(QStringLiteral("Medium Soft"));
- shadowQuality->addItem(QStringLiteral("High Soft"));
- shadowQuality->setCurrentIndex(3);
+// QComboBox *shadowQuality = new QComboBox(widget);
+// shadowQuality->addItem(QStringLiteral("None"));
+// shadowQuality->addItem(QStringLiteral("Low"));
+// shadowQuality->addItem(QStringLiteral("Medium"));
+// shadowQuality->addItem(QStringLiteral("High"));
+// shadowQuality->addItem(QStringLiteral("Low Soft"));
+// shadowQuality->addItem(QStringLiteral("Medium Soft"));
+// shadowQuality->addItem(QStringLiteral("High Soft"));
+// shadowQuality->setCurrentIndex(3);
// Add controls to the layout
vLayout->addWidget(smoothCB);
@@ -147,14 +172,20 @@ int main(int argc, char *argv[])
vLayout->addWidget(gridSlidersLockCB);
vLayout->addWidget(gridSliderX);
vLayout->addWidget(gridSliderZ);
+ vLayout->addWidget(new QLabel(QStringLiteral("Adjust axis range")));
+ vLayout->addWidget(axisRangeSliderX);
+ vLayout->addWidget(axisRangeSliderZ);
+ vLayout->addWidget(new QLabel(QStringLiteral("Adjust axis minimum")));
+ vLayout->addWidget(axisMinSliderX);
+ vLayout->addWidget(axisMinSliderZ);
vLayout->addWidget(colorPB);
vLayout->addWidget(new QLabel(QStringLiteral("Change font")));
vLayout->addWidget(fontList);
vLayout->addWidget(labelButton);
vLayout->addWidget(new QLabel(QStringLiteral("Change theme")));
vLayout->addWidget(themeList);
- vLayout->addWidget(new QLabel(QStringLiteral("Adjust shadow quality")));
- vLayout->addWidget(shadowQuality);
+// vLayout->addWidget(new QLabel(QStringLiteral("Adjust shadow quality")));
+// vLayout->addWidget(shadowQuality);
widget->show();
@@ -177,6 +208,14 @@ int main(int argc, char *argv[])
modifier, &ChartModifier::adjustXCount);
QObject::connect(gridSliderZ, &QSlider::valueChanged,
modifier, &ChartModifier::adjustZCount);
+ QObject::connect(axisRangeSliderX, &QSlider::valueChanged,
+ modifier, &ChartModifier::adjustXRange);
+ QObject::connect(axisRangeSliderZ, &QSlider::valueChanged,
+ modifier, &ChartModifier::adjustZRange);
+ QObject::connect(axisMinSliderX, &QSlider::valueChanged,
+ modifier, &ChartModifier::adjustXMin);
+ QObject::connect(axisMinSliderZ, &QSlider::valueChanged,
+ modifier, &ChartModifier::adjustZMin);
QObject::connect(colorPB, &QPushButton::pressed,
modifier, &ChartModifier::colorPressed);
QObject::connect(fontList, &QFontComboBox::currentFontChanged,
@@ -185,12 +224,17 @@ int main(int argc, char *argv[])
modifier, &ChartModifier::changeTransparency);
QObject::connect(themeList, SIGNAL(currentIndexChanged(int)),
modifier, SLOT(changeTheme(int)));
- QObject::connect(shadowQuality, SIGNAL(currentIndexChanged(int)),
- modifier, SLOT(changeShadowQuality(int)));
+// QObject::connect(shadowQuality, SIGNAL(currentIndexChanged(int)),
+// modifier, SLOT(changeShadowQuality(int)));
modifier->setGridSliderZ(gridSliderZ);
modifier->setGridSliderX(gridSliderX);
+ modifier->setAxisRangeSliderX(axisRangeSliderX);
+ modifier->setAxisRangeSliderZ(axisRangeSliderZ);
+ modifier->setAxisMinSliderX(axisMinSliderX);
+ modifier->setAxisMinSliderZ(axisMinSliderZ);
modifier->toggleGridSliderLock(gridSlidersLockCB->checkState());
+ sqrtSinCB->setChecked(true);
return app.exec();
}
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
index 293eb9eb..f40fa395 100644
--- a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
@@ -82,7 +82,7 @@ QHeightMapSurfaceDataProxy::QHeightMapSurfaceDataProxy(QObject *parent) :
* \sa heightMap
*/
QHeightMapSurfaceDataProxy::QHeightMapSurfaceDataProxy(const QImage &image, QObject *parent) :
- QSurfaceDataProxy(new QHeightMapSurfaceDataProxyPrivate(this, image), parent)
+ QSurfaceDataProxy(new QHeightMapSurfaceDataProxyPrivate(this), parent)
{
setHeightMap(image);
}
@@ -118,50 +118,17 @@ QHeightMapSurfaceDataProxy::~QHeightMapSurfaceDataProxy()
* grayscale images may improve data conversion speed for large images.
*
* Not recommended formats: all mono formats (for example QImage::Format_Mono).
+ *
+ * The height map is resolved asynchronously. QSurfaceDataProxy::arrayReset() is emitted when the
+ * data has been resolved.
*/
void QHeightMapSurfaceDataProxy::setHeightMap(const QImage &image)
{
dptr()->m_heightMap = image;
- QImage heightImage = image;
- // Convert to RGB32 to be sure we're reading the right bytes
- if (heightImage.format() != QImage::Format_RGB32)
- heightImage = image.convertToFormat(QImage::Format_RGB32);
-
- uchar *bits = heightImage.bits();
-
- int imageHeight = heightImage.height();
- int imageWidth = heightImage.width();
- int bitCount = imageWidth * 4 * (imageHeight - 1);
- int widthBits = imageWidth * 4;
- qreal height = 0;
-
- QSurfaceDataArray *dataArray = new QSurfaceDataArray;
- dataArray->reserve(imageHeight);
- if (heightImage.isGrayscale()) {
- // Grayscale, it's enough to read Red byte
- for (int i = imageHeight; i > 0; i--, bitCount -= widthBits) {
- QSurfaceDataRow *newRow = new QSurfaceDataRow(imageWidth);
- for (int j = 0; j < imageWidth; j++)
- (*newRow)[j] = qreal(bits[bitCount + (j * 4)]) + 0.1; // Add 0.1 to raise it above ground to avoid glimmering at 0 height
- *dataArray << newRow;
- }
- } else {
- // Not grayscale, we'll need to calculate height from RGB
- for (int i = imageHeight; i > 0; i--, bitCount -= widthBits) {
- QSurfaceDataRow *newRow = new QSurfaceDataRow(imageWidth);
- 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) + 0.1; // Add 0.1 to raise it above ground to avoid glimmering at 0 height
- }
- *dataArray << newRow;
- }
- }
-
- resetArray(dataArray, 0.0, imageHeight, 0.0, imageWidth);
+ // We do resolving asynchronously to make qml onArrayReset handlers actually get the initial reset
+ if (!dptr()->m_resolveTimer.isActive())
+ dptr()->m_resolveTimer.start(0);
}
QImage QHeightMapSurfaceDataProxy::heightMap() const
@@ -210,17 +177,61 @@ const QHeightMapSurfaceDataProxyPrivate *QHeightMapSurfaceDataProxy::dptrc() con
QHeightMapSurfaceDataProxyPrivate::QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q)
: QSurfaceDataProxyPrivate(q)
{
+ m_resolveTimer.setSingleShot(true);
+ QObject::connect(&m_resolveTimer, &QTimer::timeout,
+ this, &QHeightMapSurfaceDataProxyPrivate::handlePendingResolve);
}
-QHeightMapSurfaceDataProxyPrivate::QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q,
- const QImage &image)
- : QSurfaceDataProxyPrivate(q),
- m_heightMap(image)
+QHeightMapSurfaceDataProxyPrivate::~QHeightMapSurfaceDataProxyPrivate()
{
}
-QHeightMapSurfaceDataProxyPrivate::~QHeightMapSurfaceDataProxyPrivate()
+QHeightMapSurfaceDataProxy *QHeightMapSurfaceDataProxyPrivate::qptr()
{
+ return static_cast<QHeightMapSurfaceDataProxy *>(q_ptr);
+}
+
+void QHeightMapSurfaceDataProxyPrivate::handlePendingResolve()
+{
+ QImage heightImage = m_heightMap;
+ // Convert to RGB32 to be sure we're reading the right bytes
+ if (heightImage.format() != QImage::Format_RGB32)
+ heightImage = heightImage.convertToFormat(QImage::Format_RGB32);
+
+ uchar *bits = heightImage.bits();
+
+ int imageHeight = heightImage.height();
+ int imageWidth = heightImage.width();
+ int bitCount = imageWidth * 4 * (imageHeight - 1);
+ int widthBits = imageWidth * 4;
+ qreal height = 0;
+
+ QSurfaceDataArray *dataArray = new QSurfaceDataArray;
+ dataArray->reserve(imageHeight);
+ if (heightImage.isGrayscale()) {
+ // Grayscale, it's enough to read Red byte
+ for (int i = imageHeight; i > 0; i--, bitCount -= widthBits) {
+ QSurfaceDataRow *newRow = new QSurfaceDataRow(imageWidth);
+ for (int j = 0; j < imageWidth; j++)
+ (*newRow)[j] = qreal(bits[bitCount + (j * 4)]) + 0.1; // Add 0.1 to raise it above ground to avoid glimmering at 0 height
+ *dataArray << newRow;
+ }
+ } else {
+ // Not grayscale, we'll need to calculate height from RGB
+ for (int i = imageHeight; i > 0; i--, bitCount -= widthBits) {
+ QSurfaceDataRow *newRow = new QSurfaceDataRow(imageWidth);
+ 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) + 0.1; // Add 0.1 to raise it above ground to avoid glimmering at 0 height
+ }
+ *dataArray << newRow;
+ }
+ }
+
+ qptr()->resetArray(dataArray, 0.0, imageHeight, 0.0, imageWidth);
}
QT_DATAVISUALIZATION_END_NAMESPACE
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy_p.h b/src/datavisualization/data/qheightmapsurfacedataproxy_p.h
index 3cccb4ed..7140c8ef 100644
--- a/src/datavisualization/data/qheightmapsurfacedataproxy_p.h
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy_p.h
@@ -31,6 +31,7 @@
#include "qheightmapsurfacedataproxy.h"
#include "qsurfacedataproxy_p.h"
+#include <QTimer>
QT_DATAVISUALIZATION_BEGIN_NAMESPACE
@@ -40,14 +41,15 @@ class QHeightMapSurfaceDataProxyPrivate : public QSurfaceDataProxyPrivate
public:
QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q);
- QHeightMapSurfaceDataProxyPrivate(QHeightMapSurfaceDataProxy *q, const QImage &image);
virtual ~QHeightMapSurfaceDataProxyPrivate();
private:
QHeightMapSurfaceDataProxy *qptr();
+ void handlePendingResolve();
QImage m_heightMap;
QString m_heightMapFile;
+ QTimer m_resolveTimer;
friend class QHeightMapSurfaceDataProxy;
};
diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp
index 30cc84f1..bd3688dc 100644
--- a/src/datavisualization/data/qsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qsurfacedataproxy.cpp
@@ -39,6 +39,9 @@ const qreal defaultMaxValue = 10.0;
*
* All rows must have same number of values.
*
+ * \note Surfaces with less than two rows or columns are not considered valid surfaces and will
+ * not get rendered.
+ *
* QSurfaceDataProxy supports the following format tags for QAbstractDataProxy::setItemLabelFormat():
* \table
* \row
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index 9fea6ddb..67f12b0a 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -76,6 +76,16 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller)
m_scaleZ(0.0f),
m_scaleXWithBackground(0.0f),
m_scaleZWithBackground(0.0f),
+ m_surfaceScaleX(0.0f),
+ m_surfaceScaleZ(0.0f),
+ m_surfaceOffsetX(0.0f),
+ m_surfaceOffsetZ(0.0f),
+ m_minVisibleColumnValue(0.0f),
+ m_maxVisibleColumnValue(0.0f),
+ m_minVisibleRowValue(0.0f),
+ m_maxVisibleRowValue(0.0f),
+ m_dataStepX(0.0f),
+ m_dataStepZ(0.0f),
m_backgroundObj(0),
m_gridLineObj(0),
m_labelObj(0),
@@ -196,45 +206,17 @@ void Surface3DRenderer::initializeOpenGL()
void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy)
{
- // Make a copy of data array.
for (int i = 0; i < m_dataArray.size(); i++)
delete m_dataArray.at(i);
m_dataArray.clear();
- const QSurfaceDataArray *array = dataProxy->array();
-
- QRect sampleSpace = calculateSampleRect(dataProxy);
-
- m_dataArray.reserve(sampleSpace.height());
- for (int i = 0; i < sampleSpace.height(); i++) {
- QSurfaceDataRow *newRow = new QSurfaceDataRow();
- newRow->resize(sampleSpace.width());
- for (int j = 0; j < sampleSpace.width(); j++)
- (*newRow)[j] = array->at(i + sampleSpace.y())->at(j + sampleSpace.x());
- m_dataArray << newRow;
- }
-
- // If data contains only one row, duplicate it to make surface
- if (sampleSpace.height() == 1) {
- QSurfaceDataRow *newRow = new QSurfaceDataRow(*m_dataArray.at(0));
- m_dataArray << newRow;
- sampleSpace.setHeight(2);
- }
-
- // If data contains only one column, duplicate the value to make surface
- if (sampleSpace.width() == 1) {
- for (int i = 0; i < sampleSpace.height(); i++)
- (*m_dataArray.at(i)) << m_dataArray.at(i)->at(0);
- sampleSpace.setWidth(2);
- }
-
calculateSceneScalingFactors();
- if (m_dataArray.size() > 0) {
- if (!m_surfaceObj)
- loadSurfaceObj();
+ const QSurfaceDataArray *array = dataProxy->array();
- sampleSpace.moveTo(0, 0);
+ // Need minimum of 2x2 array to draw a surface
+ if (array->size() >= 2 && array->at(0)->size() >= 2) {
+ QRect sampleSpace = calculateSampleRect(dataProxy);
bool dimensionChanged = false;
if (m_sampleSpace != sampleSpace) {
@@ -242,13 +224,31 @@ void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy)
m_sampleSpace = sampleSpace;
}
- if (m_cachedSmoothSurface)
- m_surfaceObj->setUpSmoothData(m_dataArray, m_sampleSpace, m_heightNormalizer, dimensionChanged);
- else
- m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, dimensionChanged);
+ // TODO: Handle partial surface grids on the graph edges
+ if (sampleSpace.width() >= 2 && sampleSpace.height() >= 2) {
+ m_dataArray.reserve(sampleSpace.height());
+ for (int i = 0; i < sampleSpace.height(); i++) {
+ QSurfaceDataRow *newRow = new QSurfaceDataRow();
+ newRow->resize(sampleSpace.width());
+ for (int j = 0; j < sampleSpace.width(); j++)
+ (*newRow)[j] = array->at(i + sampleSpace.y())->at(j + sampleSpace.x());
+ m_dataArray << newRow;
+ }
+
+ if (m_dataArray.size() > 0) {
+ if (!m_surfaceObj)
+ loadSurfaceObj();
- if (dimensionChanged)
- updateSelectionTexture();
+ // 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);
+ else
+ m_surfaceObj->setUpData(m_dataArray, m_sampleSpace, m_heightNormalizer, dimensionChanged);
+
+ if (dimensionChanged)
+ updateSelectionTexture();
+ }
+ }
}
Abstract3DRenderer::updateDataModel(dataProxy);
@@ -256,19 +256,57 @@ void Surface3DRenderer::updateDataModel(QSurfaceDataProxy *dataProxy)
QRect Surface3DRenderer::calculateSampleRect(QSurfaceDataProxy *dataProxy)
{
- QRect sampleSpace(0, 0, dataProxy->columnCount(), dataProxy->rowCount());
-
- // TODO: Calculate the actual sample rect, for now it is required data and axis ranges are the same
-#if 0
- if (m_axisCacheX.min() != dataProxy->minValueColumns() || m_axisCacheX.max() != dataProxy->maxValueColumns()
- || m_axisCacheZ.min() != dataProxy->minValueRows() || m_axisCacheZ.max() != dataProxy->maxValueRows()) {
- qWarning() << "Warning: Technology preview doesn't support axis ranges that are different from data ranges -"
- << m_axisCacheX.min() << dataProxy->minValueColumns() << "-"
- << m_axisCacheX.max() << dataProxy->maxValueColumns() << "-"
- << m_axisCacheZ.min() << dataProxy->minValueRows() << "-"
- << m_axisCacheZ.max() << dataProxy->maxValueRows();
+ 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()) {
+ sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
}
-#endif
+
+ int index = 0;
+ while (m_minVisibleColumnValue < m_axisCacheX.min()) {
+ m_minVisibleColumnValue += m_dataStepX;
+ index++;
+ }
+ sampleSpace.setLeft(index);
+
+ index = dataProxy->columnCount() - 1;
+ while (m_maxVisibleColumnValue > m_axisCacheX.max()) {
+ m_maxVisibleColumnValue -= m_dataStepX;
+ index--;
+ }
+ sampleSpace.setRight(index);
+
+ index = 0;
+ while (m_minVisibleRowValue < m_axisCacheZ.min()) {
+ m_minVisibleRowValue += m_dataStepZ;
+ index++;
+ }
+ sampleSpace.setTop(index);
+
+ index = dataProxy->rowCount() - 1;
+ while (m_maxVisibleRowValue > m_axisCacheZ.max()) {
+ m_maxVisibleRowValue -= m_dataStepZ;
+ index--;
+ }
+ 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);
+ m_surfaceOffsetX = m_scaleX * (data2XCenterX - axis2XCenterX) / m_areaSize.width();
+ m_surfaceOffsetZ = -m_scaleZ * (data2XCenterZ - axis2XCenterZ) / m_areaSize.height() + zComp;
+
return sampleSpace;
}
@@ -361,6 +399,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
// Do the surface drawing
//
+ QVector3D surfaceScaler(m_surfaceScaleX, 1.0f, m_surfaceScaleZ);
+ QVector3D surfaceOffset(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ);
+
// Draw depth buffer
#if !defined(QT_OPENGL_ES_2)
if (m_cachedShadowQuality > QDataVis::ShadowNone && m_surfaceObj) {
@@ -405,8 +446,8 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
- modelMatrix.translate(0.0f, 0.0f, zComp);
- modelMatrix.scale(QVector3D(m_scaleX, 1.0f, m_scaleZ));
+ modelMatrix.translate(surfaceOffset);
+ modelMatrix.scale(surfaceScaler);
MVPMatrix = depthProjectionViewMatrix * modelMatrix;
@@ -469,7 +510,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glEnable(GL_TEXTURE_2D);
// Draw selection buffer
- if (m_querySelection && m_surfaceObj) {
+ if (m_querySelection && m_surfaceObj && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) {
m_selectionShader->bind();
glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer);
glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used
@@ -482,8 +523,8 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
- modelMatrix.translate(0.0f, 0.0f, zComp);
- modelMatrix.scale(QVector3D(m_scaleX, 1.0f, m_scaleZ));
+ modelMatrix.translate(surfaceOffset);
+ modelMatrix.scale(surfaceScaler);
MVPMatrix = projectionViewMatrix * modelMatrix;
@@ -516,8 +557,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glEnable(GL_CULL_FACE);
}
- // Draw surface
- if (m_surfaceObj) {
+ if (m_surfaceObj && m_sampleSpace.width() >= 2 && m_sampleSpace.height() >= 2) {
m_surfaceShader->bind();
// m_selectionShader->bind(); // IFDEF print selection
@@ -529,9 +569,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
QMatrix4x4 depthMVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(0.0f, 0.0f, zComp);
- modelMatrix.scale(QVector3D(m_scaleX, 1.0f, m_scaleZ));
- itModelMatrix.scale(QVector3D(m_scaleX, 1.0f, m_scaleZ));
+ modelMatrix.translate(surfaceOffset);
+ modelMatrix.scale(surfaceScaler);
+ itModelMatrix.scale(surfaceScaler);
#ifdef SHOW_DEPTH_TEXTURE_SCENE
MVPMatrix = depthProjectionViewMatrix * modelMatrix;
@@ -1372,7 +1412,6 @@ void Surface3DRenderer::loadSurfaceObj()
if (m_surfaceObj)
delete m_surfaceObj;
m_surfaceObj = new SurfaceObject();
- //m_surfaceObj->setUpData();
}
void Surface3DRenderer::loadGridLineMesh()
@@ -1405,8 +1444,11 @@ void Surface3DRenderer::surfacePointSelected(int id)
if (!m_selectionPointer)
m_selectionPointer = new SelectionPointer(m_controller, m_drawer);
- m_selectionPointer->setPosition(normalize(float(column), value, float(row)));
- m_selectionPointer->setScaling(QVector3D(m_scaleX, 1.0f, m_scaleZ));
+ QVector3D pos(normalize(float(column), value, float(row)));
+ pos += QVector3D(m_surfaceOffsetX, 0.0f, m_surfaceOffsetZ - zComp);
+
+ m_selectionPointer->setPosition(pos);
+ m_selectionPointer->setScaling(QVector3D(m_surfaceScaleX, 1.0f, m_surfaceScaleZ));
m_selectionPointer->setLabel(createSelectionLabel(value, column, row));
m_selectionPointer->updateBoundingRect(m_mainViewPort);
m_selectionPointer->updateScene(m_cachedScene);
@@ -1457,19 +1499,13 @@ QString Surface3DRenderer::createSelectionLabel(qreal value, int column, int row
// Transforms the model column coordinate to axis coordinate
qreal Surface3DRenderer::columnInRange(int column)
{
- // At this point we'll work only with fixed grid and demand that the user uses proper steps on
- // value axis. Zero prevented when doing duplicate from the data.
- qreal stepInRange = (m_axisCacheX.max() - m_axisCacheX.min()) / qreal(m_dataArray.at(0)->size() - 1);
- return stepInRange * qreal(column) + m_axisCacheX.min();
+ return m_dataStepX * qreal(column) + m_minVisibleColumnValue;
}
// Transforms the model row coordinate to axis coordinate
qreal Surface3DRenderer::rowInRange(int row)
{
- // At this point we'll work only with fixed grid and demand that the user uses proper steps on
- // value axis. Zero prevented when doing duplicate from the data.
- qreal stepInRange = (m_axisCacheZ.max() - m_axisCacheZ.min()) / qreal(m_dataArray.size() - 1);
- return stepInRange * qreal(row) + m_axisCacheZ.min();
+ return m_dataStepZ * qreal(row) + m_minVisibleRowValue;
}
QVector3D Surface3DRenderer::normalize(float x, float y, float z)
diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h
index b612cd34..c209e454 100644
--- a/src/datavisualization/engine/surface3drenderer_p.h
+++ b/src/datavisualization/engine/surface3drenderer_p.h
@@ -89,6 +89,16 @@ private:
GLfloat m_scaleZ;
GLfloat m_scaleXWithBackground;
GLfloat m_scaleZWithBackground;
+ GLfloat m_surfaceScaleX;
+ 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;
ObjectHelper *m_backgroundObj;
ObjectHelper *m_gridLineObj;
ObjectHelper *m_labelObj;
diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp
index a0ed292a..d28ad447 100644
--- a/src/datavisualization/utils/surfaceobject.cpp
+++ b/src/datavisualization/utils/surfaceobject.cpp
@@ -29,13 +29,14 @@ QT_DATAVISUALIZATION_BEGIN_NAMESPACE
SurfaceObject::SurfaceObject()
{
m_indicesType = GL_UNSIGNED_INT;
+ initializeOpenGLFunctions();
}
SurfaceObject::~SurfaceObject()
{
}
-void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry)
+void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, bool changeGeometry)
{
int columns = space.width();
int rows = space.height();
@@ -129,7 +130,7 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, QRect sp
}
-void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry)
+void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, bool changeGeometry)
{
int columns = space.width();
int rows = space.height();
@@ -226,7 +227,6 @@ void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVec
const QVector<QVector3D> &normals, const GLint *indices,
const GLint *gridIndices, bool changeGeometry)
{
- initializeOpenGLFunctions();
if (m_meshDataLoaded) {
// Delete old data
glDeleteBuffers(1, &m_vertexbuffer);
diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h
index e9057f88..f19fffc0 100644
--- a/src/datavisualization/utils/surfaceobject_p.h
+++ b/src/datavisualization/utils/surfaceobject_p.h
@@ -44,8 +44,8 @@ public:
SurfaceObject();
~SurfaceObject();
- void setUpData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry);
- void setUpSmoothData(const QSurfaceDataArray &dataArray, QRect space, GLfloat yRange, bool changeGeometry);
+ void setUpData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, bool changeGeometry);
+ void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange, bool changeGeometry);
GLuint gridElementBuf();
GLuint gridIndexCount();