diff options
-rw-r--r-- | examples/qmlscatter/qml/qmlscatter/main.qml | 2 | ||||
-rw-r--r-- | examples/scatterchart/scatterchart.cpp | 24 | ||||
-rw-r--r-- | src/datavis3d/axis/qvalueaxis.h | 1 | ||||
-rw-r--r-- | src/datavis3d/data/qscatterdataproxy.cpp | 20 | ||||
-rw-r--r-- | src/datavis3d/data/qscatterdataproxy_p.h | 3 | ||||
-rw-r--r-- | src/datavis3d/engine/q3dscatter.cpp | 46 | ||||
-rw-r--r-- | src/datavis3d/engine/q3dscatter.h | 22 | ||||
-rw-r--r-- | src/datavis3d/engine/scatter3dcontroller.cpp | 60 | ||||
-rw-r--r-- | src/datavis3d/engine/scatter3dcontroller_p.h | 13 | ||||
-rw-r--r-- | src/datavis3d/engine/scatter3drenderer.cpp | 759 | ||||
-rw-r--r-- | src/datavis3d/engine/scatter3drenderer_p.h | 11 | ||||
-rw-r--r-- | src/datavis3dqml2/declarativescatter.cpp | 24 | ||||
-rw-r--r-- | src/datavis3dqml2/declarativescatter.h | 5 | ||||
-rw-r--r-- | src/datavis3dqml2/declarativescatter_p.h | 5 |
14 files changed, 487 insertions, 508 deletions
diff --git a/examples/qmlscatter/qml/qmlscatter/main.qml b/examples/qmlscatter/qml/qmlscatter/main.qml index dadf9aa4..9c4e341a 100644 --- a/examples/qmlscatter/qml/qmlscatter/main.qml +++ b/examples/qmlscatter/qml/qmlscatter/main.qml @@ -25,7 +25,7 @@ import com.digia.QtDataVis3D 1.0 Item { id: mainview width: 800 - height: 500 + height: 700 visible: true Item { diff --git a/examples/scatterchart/scatterchart.cpp b/examples/scatterchart/scatterchart.cpp index 20c88e59..eeccf533 100644 --- a/examples/scatterchart/scatterchart.cpp +++ b/examples/scatterchart/scatterchart.cpp @@ -40,7 +40,7 @@ #include "scatterchart.h" #include "qscatterdataproxy.h" -#include "qcategoryaxis.h" +#include "qvalueaxis.h" using namespace QtDataVis3D; @@ -70,24 +70,10 @@ void ScatterDataModifier::start() void ScatterDataModifier::addData() { - QStringList rowLabels; - rowLabels << "something -1.0" << "something -0.8" << "something -0.6" << "something -0.4" - << "something -0.2" << "something 0.0" << "something 0.2" << "something 0.4" - << "something 0.6" << "something 0.8" << "something 1.0"; - QStringList columnLabels; - columnLabels << "other -1.0" << "other -0.8" << "other -0.6" << "other -0.4" << "other -0.2" - << "other 0.0" << "other 0.2" << "other 0.4" << "other 0.6" << "other 0.8" - << "other 1.0"; - - // Set segment count and step - m_chart->setSegmentCount(10, 0.1f, -1.0f); - // Add labels - m_chart->rowAxis()->setTitle("Somethings"); - m_chart->columnAxis()->setTitle("Others"); - m_chart->valueAxis()->setTitle("Values"); - m_chart->rowAxis()->setCategoryLabels(columnLabels); - m_chart->columnAxis()->setCategoryLabels(rowLabels); + m_chart->valueAxisX()->setTitle("Somethings"); + m_chart->valueAxisY()->setTitle("Values"); + m_chart->valueAxisZ()->setTitle("Others"); QScatterDataArray *dataArray = new QScatterDataArray; dataArray->resize(numberOfItems); @@ -154,7 +140,7 @@ void ScatterDataModifier::changeTransparency() m_chart->setLabelTransparency((LabelTransparency)transparency); if (++transparency > TransparencyNoBackground) - transparency = TransparencyFromTheme; + transparency = TransparencyNone; } void ScatterDataModifier::changeFont(const QFont &font) diff --git a/src/datavis3d/axis/qvalueaxis.h b/src/datavis3d/axis/qvalueaxis.h index 0efc762b..473088e6 100644 --- a/src/datavis3d/axis/qvalueaxis.h +++ b/src/datavis3d/axis/qvalueaxis.h @@ -92,6 +92,7 @@ protected: private: Q_DISABLE_COPY(QValueAxis) friend class Bars3dController; + friend class Scatter3DController; }; QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/data/qscatterdataproxy.cpp b/src/datavis3d/data/qscatterdataproxy.cpp index 72d676f6..0c2c99f1 100644 --- a/src/datavis3d/data/qscatterdataproxy.cpp +++ b/src/datavis3d/data/qscatterdataproxy.cpp @@ -65,7 +65,6 @@ void QScatterDataProxy::resetArray(QScatterDataArray *newArray) emit arrayReset(); } - // Mutexing data accessors should be done by user, if needed int QScatterDataProxy::itemCount() { @@ -123,18 +122,23 @@ bool QScatterDataProxyPrivate::resetArray(QScatterDataArray *newArray) // Protected & private functions. Do not mutex as these are used from mutexed functions. -QPair<GLfloat, GLfloat> QScatterDataProxyPrivate::limitValues() +QVector3D QScatterDataProxyPrivate::limitValues() { QMutexLocker locker(&m_mutex); - QPair<GLfloat, GLfloat> limits = qMakePair(100.0f, -100.0f); + QVector3D limits; for (int i = 0; i < m_dataArray.size(); i++) { const QScatterDataItem &item = m_dataArray.at(i); - qreal itemValue = item.position().y(); - if (limits.second < itemValue) - limits.second = itemValue; - if (limits.first > itemValue) - limits.first = itemValue; + float xValue = qAbs(item.position().x()); + if (limits.x() < xValue) + limits.setX(xValue); + float yValue = qAbs(item.position().y()); + if (limits.y() < yValue) + limits.setY(yValue); + float zValue = qAbs(item.position().z()); + if (limits.z() < zValue) + limits.setZ(zValue); } + //qDebug() << __FUNCTION__ << limits << m_dataArray.size(); return limits; } diff --git a/src/datavis3d/data/qscatterdataproxy_p.h b/src/datavis3d/data/qscatterdataproxy_p.h index 821ceff2..6a46a7b9 100644 --- a/src/datavis3d/data/qscatterdataproxy_p.h +++ b/src/datavis3d/data/qscatterdataproxy_p.h @@ -67,13 +67,12 @@ public: bool resetArray(QScatterDataArray *newArray); - QPair<GLfloat, GLfloat> limitValues(); + QVector3D limitValues(); private: QScatterDataArray m_dataArray; QString m_itemLabelFormat; -private: friend class QScatterDataProxy; }; diff --git a/src/datavis3d/engine/q3dscatter.cpp b/src/datavis3d/engine/q3dscatter.cpp index bb90f47e..9705decd 100644 --- a/src/datavis3d/engine/q3dscatter.cpp +++ b/src/datavis3d/engine/q3dscatter.cpp @@ -42,6 +42,7 @@ #include "q3dscatter.h" #include "q3dscatter_p.h" #include "scatter3dcontroller_p.h" +#include "qvalueaxis.h" #include <QMouseEvent> @@ -423,26 +424,40 @@ ShadowQuality Q3DScatter::shadowQuality() return d_ptr->m_shared->shadowQuality(); } -QCategoryAxis *Q3DScatter::rowAxis() +void Q3DScatter::setValueAxisX(QValueAxis *axis) { - return reinterpret_cast<QCategoryAxis *>(d_ptr->m_shared->axisX()); + Q_ASSERT(axis); + + return d_ptr->m_shared->setAxisX(axis); } -QCategoryAxis *Q3DScatter::columnAxis() +QValueAxis *Q3DScatter::valueAxisX() { - return reinterpret_cast<QCategoryAxis *>(d_ptr->m_shared->axisZ()); + return static_cast<QValueAxis *>(d_ptr->m_shared->axisX()); } -void Q3DScatter::setValueAxis(QAbstractAxis *axis) +void Q3DScatter::setValueAxisY(QValueAxis *axis) { Q_ASSERT(axis); return d_ptr->m_shared->setAxisY(axis); } -QAbstractAxis *Q3DScatter::valueAxis() +QValueAxis *Q3DScatter::valueAxisY() +{ + return static_cast<QValueAxis *>(d_ptr->m_shared->axisY()); +} + +void Q3DScatter::setValueAxisZ(QValueAxis *axis) +{ + Q_ASSERT(axis); + + return d_ptr->m_shared->setAxisZ(axis); +} + +QValueAxis *Q3DScatter::valueAxisZ() { - return d_ptr->m_shared->axisY(); + return static_cast<QValueAxis *>(d_ptr->m_shared->axisZ()); } void Q3DScatter::setDataProxy(QScatterDataProxy *proxy) @@ -455,23 +470,6 @@ QScatterDataProxy *Q3DScatter::dataProxy() return d_ptr->m_shared->dataProxy(); } -/*! - * \a segmentCount How many segments will be drawn in addition to the start line. \c 5 by default. - * \n There will be segmentCount + 1 lines drawn, as there is always the start line. - * - * \a step How large a step each segment is. - * - * \a minimum Minimum value a bar in data set can have. Setting this correctly is especially - * important if values can be negative, or autoscaling won't work correctly. - * - * Sets segment count and step. Note; segmentCount * step should be the maximum possible value of data - * set. - */ -void Q3DScatter::setSegmentCount(int segmentCount, qreal step, qreal minimum) -{ - d_ptr->m_shared->setSegmentCount(GLint(segmentCount), GLfloat(step), GLfloat(minimum)); -} - Q3DScatterPrivate::Q3DScatterPrivate(Q3DScatter *q, QRect rect) : q_ptr(q), m_shared(new Scatter3DController(rect)) diff --git a/src/datavis3d/engine/q3dscatter.h b/src/datavis3d/engine/q3dscatter.h index f85a5c5f..d34342da 100644 --- a/src/datavis3d/engine/q3dscatter.h +++ b/src/datavis3d/engine/q3dscatter.h @@ -50,7 +50,7 @@ QT_DATAVIS3D_BEGIN_NAMESPACE class Q3DScatterPrivate; class LabelItem; -class QAbstractAxis; +class QValueAxis; class QCategoryAxis; class QScatterDataProxy; @@ -104,11 +104,6 @@ public: void setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, bool uniform = true); - // Set segment count and step. Note; segmentCount * step should be the maximum possible value of data - // set. Minimum is the absolute minimum possible value a bar can have. This is especially - // important to set if values can be negative. - void setSegmentCount(int segmentCount, qreal step, qreal minimum = 0.0f); - // override bar type with own mesh void setMeshFileName(const QString &objFileName); // TODO: light placement API @@ -150,12 +145,15 @@ public: void setShadowQuality(ShadowQuality quality); ShadowQuality shadowQuality(); - // Axes - row & column axes are fixed to category axes, value axis can be - // customized. - QCategoryAxis *rowAxis(); - QCategoryAxis *columnAxis(); - void setValueAxis(QAbstractAxis *axis); - QAbstractAxis *valueAxis(); + // Axes + void setValueAxisX(QValueAxis *axis); + QValueAxis *valueAxisX(); + + void setValueAxisY(QValueAxis *axis); + QValueAxis *valueAxisY(); + + void setValueAxisZ(QValueAxis *axis); + QValueAxis *valueAxisZ(); // Sets the data proxy. Assumes ownership of the data proxy. Deletes old proxy. void setDataProxy(QtDataVis3D::QScatterDataProxy *proxy); diff --git a/src/datavis3d/engine/scatter3dcontroller.cpp b/src/datavis3d/engine/scatter3dcontroller.cpp index 67f6c18f..add0751b 100644 --- a/src/datavis3d/engine/scatter3dcontroller.cpp +++ b/src/datavis3d/engine/scatter3dcontroller.cpp @@ -44,8 +44,7 @@ #include "camerahelper_p.h" #include "utils_p.h" #include "qabstractaxis_p.h" -#include "qvalueaxis.h" -#include "qcategoryaxis.h" +#include "qvalueaxis_p.h" #include "qscatterdataproxy_p.h" #include <QMatrix4x4> @@ -67,17 +66,14 @@ Scatter3DController::Scatter3DController(QRect boundRect) m_font(QFont(QStringLiteral("Arial"))), m_isGridEnabled(true), m_isBackgroundEnabled(true), - m_segmentCount(0), - m_segmentStep(0), - m_segmentMinimum(0.0f), m_renderer(0), m_data(0), m_valuesDirty(false) { - // Default axes. Only Y axis can actually be changed by user. - setAxisX(new QCategoryAxis()); + // Default axes + setAxisX(new QValueAxis()); setAxisY(new QValueAxis()); - setAxisZ(new QCategoryAxis()); + setAxisZ(new QValueAxis()); setDataProxy(new QScatterDataProxy); } @@ -269,7 +265,8 @@ void Scatter3DController::setDataProxy(QScatterDataProxy *proxy) QObject::connect(m_data, &QScatterDataProxy::itemsInserted, this, &Scatter3DController::handleItemsInserted); - // emit something? Renderer might be interested? + adjustValueAxisRange(); + m_valuesDirty = true; } QScatterDataProxy *Scatter3DController::dataProxy() @@ -280,6 +277,7 @@ QScatterDataProxy *Scatter3DController::dataProxy() void Scatter3DController::handleArrayReset() { setSlicingActive(false); + adjustValueAxisRange(); m_valuesDirty = true; } @@ -288,6 +286,7 @@ void Scatter3DController::handleItemsAdded(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) // TODO should dirty only affected values? + adjustValueAxisRange(); m_valuesDirty = true; } @@ -296,6 +295,7 @@ void Scatter3DController::handleItemsChanged(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) // TODO should dirty only affected values? + adjustValueAxisRange(); m_valuesDirty = true; } @@ -304,6 +304,7 @@ void Scatter3DController::handleItemsRemoved(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) // TODO should dirty only affected values? + adjustValueAxisRange(); m_valuesDirty = true; } @@ -312,9 +313,16 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) // TODO should dirty only affected values? + adjustValueAxisRange(); m_valuesDirty = true; } +void Scatter3DController::handleAxisAutoAdjustRangeChanged(bool autoAdjust) +{ + Q_UNUSED(autoAdjust) + adjustValueAxisRange(); +} + QString Scatter3DController::objFile() { return m_objFile; @@ -406,16 +414,34 @@ bool Scatter3DController::backgroundEnabled() return m_isBackgroundEnabled; } -void Scatter3DController::setSegmentCount(GLint segmentCount, GLfloat step, GLfloat minimum) +void Scatter3DController::adjustValueAxisRange() { - if (segmentCount <= 0) { - qCritical("Invalid segment count. It must be positive."); - return; + if (m_data) { + QVector3D limits = m_data->dptr()->limitValues(); + QValueAxis *valueAxis = static_cast<QValueAxis *>(m_axisX); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (limits.x() > 0) + valueAxis->dptr()->setRange(-limits.x(), limits.x()); + else + valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default. + } + + valueAxis = static_cast<QValueAxis *>(m_axisY); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (limits.y() > 0) + valueAxis->dptr()->setRange(-limits.y(), limits.y()); + else + valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default. + } + + valueAxis = static_cast<QValueAxis *>(m_axisZ); + if (valueAxis && valueAxis->isAutoAdjustRange()) { + if (limits.z() > 0) + valueAxis->dptr()->setRange(-limits.z(), limits.z()); + else + valueAxis->dptr()->setRange(-1.0, 1.0); // Only zero value values in data set, set range to default. + } } - m_segmentCount = segmentCount; - m_segmentStep = step; - m_segmentMinimum = minimum; - emit segmentCountChanged(m_segmentCount, m_segmentStep, m_segmentMinimum); } QT_DATAVIS3D_END_NAMESPACE diff --git a/src/datavis3d/engine/scatter3dcontroller_p.h b/src/datavis3d/engine/scatter3dcontroller_p.h index 7150c8b9..37e9fe38 100644 --- a/src/datavis3d/engine/scatter3dcontroller_p.h +++ b/src/datavis3d/engine/scatter3dcontroller_p.h @@ -97,9 +97,6 @@ private: QFont m_font; bool m_isGridEnabled; bool m_isBackgroundEnabled; - GLint m_segmentCount; - GLfloat m_segmentStep; - GLfloat m_segmentMinimum; Scatter3DRenderer *m_renderer; QScatterDataProxy *m_data; @@ -128,11 +125,6 @@ public: // override bar type with own mesh void setMeshFileName(const QString &objFileName); - // Set segment count and step. Note; segmentCount * step should be the maximum possible value of data - // set. Minimum is the absolute minimum possible value a bar can have. This is especially - // important to set if values can be negative. - void setSegmentCount(GLint segmentCount, GLfloat step, GLfloat minimum = 0.0f); - // TODO: light placement API // Change selection mode; single bar, bar and row, bar and column, or all @@ -175,6 +167,8 @@ public slots: void handleItemsRemoved(int startIndex, int count); void handleItemsInserted(int startIndex, int count); + virtual void handleAxisAutoAdjustRangeChanged(bool autoAdjust); + signals: void selectionModeChanged(SelectionMode mode); void slicingActiveChanged(bool isSlicing); @@ -182,10 +176,9 @@ signals: void fontChanged(QFont font); void gridEnabledChanged(bool enable); void backgroundEnabledChanged(bool enable); - void segmentCountChanged(GLint segmentCount, GLfloat step, GLfloat minimum); private: - void handleLimitChange(); + void adjustValueAxisRange(); Q_DISABLE_COPY(Scatter3DController) diff --git a/src/datavis3d/engine/scatter3drenderer.cpp b/src/datavis3d/engine/scatter3drenderer.cpp index 4184abc9..d03473e3 100644 --- a/src/datavis3d/engine/scatter3drenderer.cpp +++ b/src/datavis3d/engine/scatter3drenderer.cpp @@ -83,8 +83,6 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_controller(controller), m_selectedItem(0), m_previouslySelectedItem(0), - m_segmentCount(5), - m_segmentStep(0.2f), m_xFlipped(false), m_zFlipped(false), m_updateLabels(false), @@ -105,11 +103,9 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller) m_selectionDepthBuffer(0), m_shadowQualityToShader(33.3f), m_heightNormalizer(1.0f), - m_yAdjustment(0.0f), m_scaleFactor(0), m_selection(selectionSkipColor), m_areaSize(QSizeF(0.0f, 0.0f)), - m_autoAdjust(true), m_hasHeightAdjustmentChanged(true), m_dataProxy(0), m_valueUpdateNeeded(false), @@ -158,8 +154,6 @@ void Scatter3DRenderer::initializePreOpenGL() &Scatter3DRenderer::updateGridEnabled); QObject::connect(m_controller, &Scatter3DController::backgroundEnabledChanged, this, &Scatter3DRenderer::updateBackgroundEnabled); - QObject::connect(m_controller, &Scatter3DController::segmentCountChanged, this, - &Scatter3DRenderer::updateSegmentCount); QObject::connect(m_controller, &Scatter3DController::zoomLevelChanged, this, &Scatter3DRenderer::updateZoomLevel); @@ -171,7 +165,6 @@ void Scatter3DRenderer::initializePreOpenGL() updateBackgroundEnabled(m_controller->backgroundEnabled()); } - void Scatter3DRenderer::initializeOpenGL() { //qDebug() << __FUNCTION__; @@ -252,12 +245,13 @@ void Scatter3DRenderer::render(QScatterDataProxy *dataProxy, m_dataProxy = dataProxy; - // Update cached data window // TODO Should data changes be notified via signal instead of reading data in render? // TODO this cache initialization assumes data window starts at 0,0 offset from array // Update cached values - if (valuesDirty) { + if (valuesDirty|| m_valueUpdateNeeded) { + m_valueUpdateNeeded = false; const QScatterDataArray &dataArray = *m_dataProxy->array(); + calculateSceneScalingFactors(); int dataSize = dataArray.size(); m_renderItemArray.resize(dataSize); for (int i = 0; i < dataSize ; i++) { @@ -266,9 +260,6 @@ void Scatter3DRenderer::render(QScatterDataProxy *dataProxy, m_renderItemArray[i].setPosition(dataArray.at(i).position()); //m_renderItemArray[i].setHeight(value / m_heightNormalizer); //m_renderItemArray[i].setItemLabel(dataArray.at(i).label()); - calculateSceneScalingFactors(dataArray.at(i).position()); - } - for (int i = 0; i < dataSize ; i++) { calculateTranslation(m_renderItemArray[i]); m_renderItemArray[i].setRenderer(this); } @@ -290,7 +281,7 @@ void Scatter3DRenderer::render(QScatterDataProxy *dataProxy, if (m_hasHeightAdjustmentChanged) { // Set initial camera position. Also update if height adjustment has changed. camera->setDefaultCameraOrientation(QVector3D(0.0f, 0.0f, 6.0f + zComp), - QVector3D(0.0f, -m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, zComp), QVector3D(0.0f, 1.0f, 0.0f)); m_hasHeightAdjustmentChanged = false; } @@ -418,14 +409,14 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, // Get the depth view matrix // It may be possible to hack lightPos here if we want to make some tweaks to shadow - depthViewMatrix.lookAt(lightPos, QVector3D(0.0f, -m_yAdjustment, zComp), + depthViewMatrix.lookAt(lightPos, QVector3D(0.0f, 0.0f, zComp), QVector3D(0.0f, 1.0f, 0.0f)); // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above? That causes the scene to be not drawn from above -> must be fixed //qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3); // Set the depth projection matrix #ifndef USE_WIDER_SHADOWS // Use this for perspective shadows - depthProjectionMatrix.perspective(15.0f, (GLfloat)m_mainViewPort.width() + depthProjectionMatrix.perspective(20.0f, (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height(), 3.0f, 100.0f); #else // Use these for orthographic shadows @@ -741,7 +732,7 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, QMatrix4x4 depthMVPMatrix; QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, -m_yAdjustment, zComp); + modelMatrix.translate(0.0f, 0.0f, zComp); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z modelMatrix.scale( QVector3D( @@ -806,7 +797,6 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, // Disable textures glDisable(GL_TEXTURE_2D); - // TODO: Grid lines cannot be done as in bars; we need configurable lines. Let's use segments for now. // Draw grid lines if (m_cachedIsGridEnabled && m_heightNormalizer) { // Bind bar shader @@ -819,262 +809,283 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, m_dotShader->setUniformValue(m_dotShader->color(), barColor); m_dotShader->setUniformValue(m_dotShader->ambientS(), m_cachedTheme.m_ambientStrength); - // Floor lines: rows -#ifdef USE_UNIFORM_SCALING - GLfloat lineStep = (2.0f * m_scaleFactor * aspectRatio) / m_segmentCount; - GLfloat startLine = -m_scaleFactor * aspectRatio; + // Floor lines: rows (= Z) + if (m_axisCacheZ.segmentCount() > 0) { +#ifndef USE_UNIFORM_SCALING + GLfloat lineStep = aspectRatio * m_axisCacheZ.subSegmentStep(); + GLfloat linePos = aspectRatio * m_axisCacheZ.min(); // Start line #else - GLfloat lineStep = (2.0f * m_areaSize.height() * aspectRatio) / m_segmentCount; - GLfloat startLine = -m_areaSize.height() * aspectRatio; + GLfloat lineStep = aspectRatio * qMax(m_axisCacheX.subSegmentStep(), + m_axisCacheZ.subSegmentStep()); + GLfloat linePos = -aspectRatio * m_scaleFactor; // Start line #endif + int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount(); - for (GLfloat linePos = startLine; linePos <= -startLine; linePos += lineStep) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; - modelMatrix.translate(0.0f, - -m_yAdjustment - backgroundMargin, - linePos / m_scaleFactor + zComp); + modelMatrix.translate(0.0f, + -backgroundMargin, + linePos / m_scaleFactor + zComp); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - modelMatrix.scale( - QVector3D( - (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, - gridLineWidth, gridLineWidth)); - itModelMatrix.scale( - QVector3D( - (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, - gridLineWidth, gridLineWidth)); + modelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, + gridLineWidth, gridLineWidth)); + itModelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width()) / m_scaleFactor, + gridLineWidth, gridLineWidth)); #else // ..and this if we want uniform scaling based on largest dimension - modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin), - gridLineWidth, gridLineWidth)); - itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin, - gridLineWidth, gridLineWidth)); + modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin), + gridLineWidth, gridLineWidth)); + itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin, + gridLineWidth, gridLineWidth)); #endif - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - // Set the rest of the shader bindings - m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); - m_dotShader->setUniformValue(m_dotShader->nModel(), - itModelMatrix.inverted().transposed()); - m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); + // Set the rest of the shader bindings + m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); + m_dotShader->setUniformValue(m_dotShader->nModel(), + itModelMatrix.inverted().transposed()); + m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); #if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > ShadowNone) { - // Set shadow shader bindings - m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); - m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); - m_dotShader->setUniformValue(m_dotShader->lightS(), - m_cachedTheme.m_lightStrength / 10.0f); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); - } else + if (m_cachedShadowQuality > ShadowNone) { + // Set shadow shader bindings + m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); + m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); + m_dotShader->setUniformValue(m_dotShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); + } else #endif - { - // Set shadowless shader bindings - m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj); + { + // Set shadowless shader bindings + m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj); + } + linePos += lineStep; } } - // Floor lines: columns + // Floor lines: columns (= X) + if (m_axisCacheX.segmentCount() > 0) { #ifndef USE_UNIFORM_SCALING - lineStep = (2.0f * m_areaSize.width() * aspectRatio) / m_segmentCount; - startLine = -m_areaSize.width() * aspectRatio; + GLfloat lineStep = aspectRatio * m_axisCacheX.subSegmentStep(); + GLfloat linePos = aspectRatio * m_axisCacheX.min(); +#else + GLfloat lineStep = aspectRatio * qMax(m_axisCacheX.subSegmentStep(), + m_axisCacheZ.subSegmentStep()); + GLfloat linePos = -aspectRatio * m_scaleFactor; #endif + int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount(); - for (GLfloat linePos = startLine; linePos <= -startLine; linePos += lineStep) { - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; + for (int segment = 0; segment <= lastSegment; segment++) { + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; - modelMatrix.translate(linePos / m_scaleFactor, - -m_yAdjustment - backgroundMargin, - zComp); + modelMatrix.translate(linePos / m_scaleFactor, + -backgroundMargin, + zComp); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - modelMatrix.scale( - QVector3D( - gridLineWidth, gridLineWidth, - (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); - itModelMatrix.scale( - QVector3D( - gridLineWidth, gridLineWidth, - (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + modelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + itModelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); #else // ..and this if we want uniform scaling based on largest dimension - modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - (aspectRatio * backgroundMargin))); - itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - aspectRatio * backgroundMargin))); + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + aspectRatio * backgroundMargin)); + itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + aspectRatio * backgroundMargin)); #endif - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - // Set the rest of the shader bindings - m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); - m_dotShader->setUniformValue(m_dotShader->nModel(), - itModelMatrix.inverted().transposed()); - m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); + // Set the rest of the shader bindings + m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); + m_dotShader->setUniformValue(m_dotShader->nModel(), + itModelMatrix.inverted().transposed()); + m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); #if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > ShadowNone) { - // Set shadow shader bindings - m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); - m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); - m_dotShader->setUniformValue(m_dotShader->lightS(), - m_cachedTheme.m_lightStrength / 10.0f); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); - } else + if (m_cachedShadowQuality > ShadowNone) { + // Set shadow shader bindings + m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); + m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); + m_dotShader->setUniformValue(m_dotShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); + } else #endif - { - // Set shadowless shader bindings - m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj); + { + // Set shadowless shader bindings + m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj); + } + linePos += lineStep; } } // Wall lines: back wall - lineStep = 2.0f * m_segmentStep; - startLine = -m_heightNormalizer; + if (m_axisCacheY.segmentCount() > 0) { + GLfloat lineStep = m_axisCacheY.subSegmentStep(); + GLfloat linePos = m_axisCacheY.min(); + int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); - for (GLfloat linePos = startLine; linePos <= -startLine; linePos += lineStep) { + for (int segment = 0; segment <= lastSegment; segment++) { #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat lineZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat lineZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat lineZTrans = aspectRatio * backgroundMargin; + GLfloat lineZTrans = aspectRatio * backgroundMargin; #endif - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; - if (!m_zFlipped) - lineZTrans = -lineZTrans; + if (!m_zFlipped) + lineZTrans = -lineZTrans; - modelMatrix.translate(0.0f, - linePos / m_heightNormalizer - m_yAdjustment, - lineZTrans + zComp); + modelMatrix.translate(0.0f, + linePos / m_heightNormalizer, + lineZTrans + zComp); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - modelMatrix.scale( - QVector3D( - (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor), - gridLineWidth, gridLineWidth)); - itModelMatrix.scale( - QVector3D( - (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor), - gridLineWidth, gridLineWidth)); + modelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor), + gridLineWidth, gridLineWidth)); + itModelMatrix.scale( + QVector3D( + (aspectRatio * backgroundMargin * m_areaSize.width() / m_scaleFactor), + gridLineWidth, gridLineWidth)); #else // ..and this if we want uniform scaling based on largest dimension - modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin), - gridLineWidth, gridLineWidth)); - itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin, - gridLineWidth, gridLineWidth)); + modelMatrix.scale(QVector3D((aspectRatio * backgroundMargin), + gridLineWidth, gridLineWidth)); + itModelMatrix.scale(QVector3D(aspectRatio * backgroundMargin, + gridLineWidth, gridLineWidth)); #endif - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - // Set the rest of the shader bindings - m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); - m_dotShader->setUniformValue(m_dotShader->nModel(), - itModelMatrix.inverted().transposed()); - m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); + // Set the rest of the shader bindings + m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); + m_dotShader->setUniformValue(m_dotShader->nModel(), + itModelMatrix.inverted().transposed()); + m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); #if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > ShadowNone) { - // Set shadow shader bindings - m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); - m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); - m_dotShader->setUniformValue(m_dotShader->lightS(), - m_cachedTheme.m_lightStrength / 10.0f); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); - } else + if (m_cachedShadowQuality > ShadowNone) { + // Set shadow shader bindings + m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); + m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); + m_dotShader->setUniformValue(m_dotShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); + } else #endif - { - // Set shadowless shader bindings - m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj); + { + // Set shadowless shader bindings + m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj); + } + linePos += lineStep; } - } - // Wall lines: side wall - for (GLfloat linePos = startLine; linePos <= -startLine; linePos += lineStep) { + // Wall lines: side wall + linePos = m_axisCacheY.min(); + lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount(); + + for (int segment = 0; segment <= lastSegment; segment++) { #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat lineXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) - / m_scaleFactor; + GLfloat lineXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat lineXTrans = aspectRatio * backgroundMargin; + GLfloat lineXTrans = aspectRatio * backgroundMargin; #endif - QMatrix4x4 modelMatrix; - QMatrix4x4 MVPMatrix; - QMatrix4x4 depthMVPMatrix; - QMatrix4x4 itModelMatrix; + QMatrix4x4 modelMatrix; + QMatrix4x4 MVPMatrix; + QMatrix4x4 depthMVPMatrix; + QMatrix4x4 itModelMatrix; - if (!m_xFlipped) - lineXTrans = -lineXTrans; + if (!m_xFlipped) + lineXTrans = -lineXTrans; - modelMatrix.translate(lineXTrans, - linePos / m_heightNormalizer - m_yAdjustment, - zComp); + modelMatrix.translate(lineXTrans, + linePos / m_heightNormalizer, + zComp); #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - modelMatrix.scale( - QVector3D( - gridLineWidth, gridLineWidth, - (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); - itModelMatrix.scale( - QVector3D( - gridLineWidth, gridLineWidth, - (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + modelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); + itModelMatrix.scale( + QVector3D( + gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin * m_areaSize.height()) / m_scaleFactor)); #else // ..and this if we want uniform scaling based on largest dimension - modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - (aspectRatio * backgroundMargin))); - itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, - aspectRatio * backgroundMargin)); + modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + (aspectRatio * backgroundMargin))); + itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth, + aspectRatio * backgroundMargin)); #endif - MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; - depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; + MVPMatrix = projectionMatrix * viewMatrix * modelMatrix; + depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix; - // Set the rest of the shader bindings - m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); - m_dotShader->setUniformValue(m_dotShader->nModel(), - itModelMatrix.inverted().transposed()); - m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); + // Set the rest of the shader bindings + m_dotShader->setUniformValue(m_dotShader->model(), modelMatrix); + m_dotShader->setUniformValue(m_dotShader->nModel(), + itModelMatrix.inverted().transposed()); + m_dotShader->setUniformValue(m_dotShader->MVP(), MVPMatrix); #if !defined(QT_OPENGL_ES_2) - if (m_cachedShadowQuality > ShadowNone) { - // Set shadow shader bindings - m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); - m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); - m_dotShader->setUniformValue(m_dotShader->lightS(), - m_cachedTheme.m_lightStrength / 10.0f); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); - } else + if (m_cachedShadowQuality > ShadowNone) { + // Set shadow shader bindings + m_dotShader->setUniformValue(m_dotShader->shadowQ(), m_shadowQualityToShader); + m_dotShader->setUniformValue(m_dotShader->depth(), depthMVPMatrix); + m_dotShader->setUniformValue(m_dotShader->lightS(), + m_cachedTheme.m_lightStrength / 10.0f); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj, 0, m_depthTexture); + } else #endif - { - // Set shadowless shader bindings - m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); - - // Draw the object - m_drawer->drawObject(m_dotShader, m_gridLineObj); + { + // Set shadowless shader bindings + m_dotShader->setUniformValue(m_dotShader->lightS(), m_cachedTheme.m_lightStrength); + + // Draw the object + m_drawer->drawObject(m_dotShader, m_gridLineObj); + } + linePos += lineStep; } } @@ -1111,7 +1122,8 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, #else // Draw the value string followed by row label and column label LabelItem &labelItem = m_selectedItem->selectionLabel(); - if (m_previouslySelectedItem != m_selectedItem || m_updateLabels || !labelItem.textureId()) { + if (m_previouslySelectedItem != m_selectedItem || m_updateLabels + || !labelItem.textureId()) { QString labelText = m_selectedItem->label(); // TODO More elaborate label? m_drawer->generateLabelItem(labelItem, labelText); @@ -1119,7 +1131,7 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, } m_drawer->drawLabel(*m_selectedItem, labelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, m_yAdjustment, zComp), + QVector3D(0.0f, 0.0f, zComp), QVector3D(0.0f, 0.0f, 0.0f), m_selectedItem->height(), m_cachedSelectionMode, m_labelShader, m_labelObj, camera, true, false, LabelMid); @@ -1149,159 +1161,172 @@ void Scatter3DRenderer::drawScene(CameraHelper *camera, } // Z Labels -#ifdef USE_UNIFORM_SCALING - GLfloat posStep = (2.0f * m_scaleFactor * aspectRatio) / m_segmentCount; - GLfloat startPos = -m_scaleFactor * aspectRatio; + if (m_axisCacheZ.segmentCount() > 0) { +#ifndef USE_UNIFORM_SCALING + GLfloat posStep = aspectRatio * m_axisCacheZ.segmentStep(); + GLfloat labelPos = aspectRatio * m_axisCacheZ.min(); #else - GLfloat posStep = (2.0f * m_areaSize.height() * aspectRatio) / m_segmentCount; - GLfloat startPos = -m_areaSize.height() * aspectRatio; + // TODO: When using uniform scaling, we need to use labels from the larger dimension axis + // -> Check which axis is "bigger" and set it to a temp axis. Then use the temp for + // steps and labels. + GLfloat posStep = aspectRatio * qMax(m_axisCacheX.segmentStep(), + m_axisCacheZ.segmentStep()); + GLfloat labelPos = -aspectRatio * m_scaleFactor; #endif - int labelNbr = 0; - for (GLfloat labelPos = startPos; labelPos <= -startPos; labelPos += posStep) { - if (m_axisCacheX.labelItems().size() > labelNbr) { + int labelNbr = 0; + for (int segment = 0; segment <= m_axisCacheZ.segmentCount(); segment++) { + if (m_axisCacheZ.labelItems().size() > labelNbr) { #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) - / m_scaleFactor; + GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat labelXTrans = aspectRatio * backgroundMargin; + GLfloat labelXTrans = aspectRatio * backgroundMargin; #endif - GLfloat rotLabelX = -90.0f; - GLfloat rotLabelY = 0.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignRight; - if (m_zFlipped) - rotLabelY = 180.0f; - if (m_xFlipped) { - labelXTrans = -labelXTrans; - alignment = Qt::AlignLeft; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 0.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + if (m_xFlipped) { + labelXTrans = -labelXTrans; + alignment = Qt::AlignLeft; + } + QVector3D labelTrans = QVector3D(labelXTrans, + -backgroundMargin, + labelPos / m_scaleFactor + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr); + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, camera, true, true, LabelMid, + alignment); } - QVector3D labelTrans = QVector3D( - labelXTrans, - -m_yAdjustment - (m_heightNormalizer * backgroundMargin), - labelPos / m_scaleFactor + zComp); - - // TODO: Try it; draw the label here - m_dummyRenderItem.setTranslation(labelTrans); - const LabelItem &axisLabelItem = - *m_axisCacheZ.labelItems().at(labelNbr); - - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, m_yAdjustment, zComp), - QVector3D(rotLabelX, rotLabelY, rotLabelZ), - 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, camera, true, true, LabelMid, - alignment); + labelNbr++; + labelPos += posStep; } - labelNbr++; } // X Labels + if (m_axisCacheX.segmentCount() > 0) { #ifndef USE_UNIFORM_SCALING - posStep = (2.0f * m_areaSize.width() * aspectRatio) / m_segmentCount; - startPos = -m_areaSize.width() * aspectRatio; + GLfloat posStep = aspectRatio * m_axisCacheX.segmentStep(); + GLfloat labelPos = aspectRatio * m_axisCacheX.min(); +#else + GLfloat posStep = aspectRatio * qMax(m_axisCacheX.segmentStep(), + m_axisCacheZ.segmentStep()); + GLfloat labelPos = -aspectRatio * m_scaleFactor; #endif - labelNbr = 0; - for (GLfloat labelPos = startPos; labelPos <= -startPos; labelPos += posStep) { - if (m_axisCacheX.labelItems().size() > labelNbr) { + int labelNbr = 0; + for (int segment = 0; segment <= m_axisCacheX.segmentCount(); segment++) { + if (m_axisCacheX.labelItems().size() > labelNbr) { #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat labelZTrans = aspectRatio * backgroundMargin; + GLfloat labelZTrans = aspectRatio * backgroundMargin; #endif - GLfloat rotLabelX = -90.0f; - GLfloat rotLabelY = 90.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignLeft; - if (m_xFlipped) - rotLabelY = -90.0f; - if (m_zFlipped) { - labelZTrans = -labelZTrans; - alignment = Qt::AlignRight; + GLfloat rotLabelX = -90.0f; + GLfloat rotLabelY = 90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (m_xFlipped) + rotLabelY = -90.0f; + if (m_zFlipped) { + labelZTrans = -labelZTrans; + alignment = Qt::AlignRight; + } + QVector3D labelTrans = QVector3D(labelPos / m_scaleFactor, + -backgroundMargin, + labelZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); + + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, camera, true, true, LabelMid, + alignment); } - QVector3D labelTrans = QVector3D( - labelPos / m_scaleFactor, - -m_yAdjustment - (m_heightNormalizer * backgroundMargin), - labelZTrans + zComp); - - // TODO: Try it; draw the label here - m_dummyRenderItem.setTranslation(labelTrans); - const LabelItem &axisLabelItem = - *m_axisCacheX.labelItems().at(labelNbr); - - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, m_yAdjustment, zComp), - QVector3D(rotLabelX, rotLabelY, rotLabelZ), - 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, camera, true, true, LabelMid, - alignment); + labelNbr++; + labelPos += posStep; } - labelNbr++; } // Y Labels - posStep = 2.0f * m_segmentStep; - startPos = -m_heightNormalizer; - labelNbr = 0; - for (GLfloat labelPos = startPos; labelPos <= -startPos; labelPos += posStep) { - // TODO: Test with x labels - if (m_axisCacheX.labelItems().size() > labelNbr) { + if (m_axisCacheY.segmentCount() > 0) { + GLfloat posStep = m_axisCacheY.segmentStep(); + GLfloat labelPos = m_axisCacheY.min(); + int labelNbr = 0; + for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) { + if (m_axisCacheY.labelItems().size() > labelNbr) { #ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z - GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) - / m_scaleFactor; - GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) - / m_scaleFactor; + GLfloat labelXTrans = (aspectRatio * backgroundMargin * m_areaSize.width()) + / m_scaleFactor; + GLfloat labelZTrans = (aspectRatio * backgroundMargin * m_areaSize.height()) + / m_scaleFactor; #else // ..and this if we want uniform scaling based on largest dimension - GLfloat labelXTrans = aspectRatio * backgroundMargin; - GLfloat labelZTrans = labelXTrans; + GLfloat labelXTrans = aspectRatio * backgroundMargin; + GLfloat labelZTrans = labelXTrans; #endif - GLfloat labelYTrans = labelPos / m_heightNormalizer - m_yAdjustment; - GLfloat rotLabelX = 0.0f; - GLfloat rotLabelY = -90.0f; - GLfloat rotLabelZ = 0.0f; - Qt::AlignmentFlag alignment = Qt::AlignLeft; - if (!m_xFlipped) { - labelXTrans = -labelXTrans; - rotLabelY = 90.0f; + GLfloat labelYTrans = labelPos / m_heightNormalizer; + GLfloat rotLabelX = 0.0f; + GLfloat rotLabelY = -90.0f; + GLfloat rotLabelZ = 0.0f; + Qt::AlignmentFlag alignment = Qt::AlignLeft; + if (!m_xFlipped) { + labelXTrans = -labelXTrans; + rotLabelY = 90.0f; + } + if (m_zFlipped) { + labelZTrans = -labelZTrans; + alignment = Qt::AlignRight; + } + + const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr); + + // Back wall + QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, labelZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, camera, true, true, LabelMid, + alignment); + + // Side wall + if (m_xFlipped) + alignment = Qt::AlignLeft; + else + alignment = Qt::AlignRight; + if (m_zFlipped) + rotLabelY = 180.0f; + else + rotLabelY = 0.0f; + + labelTrans = QVector3D(-labelXTrans, labelYTrans, -labelZTrans + zComp); + + // Draw the label here + m_dummyRenderItem.setTranslation(labelTrans); + m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, + QVector3D(0.0f, 0.0f, zComp), + QVector3D(rotLabelX, rotLabelY, rotLabelZ), + 0, m_cachedSelectionMode, + m_labelShader, m_labelObj, camera, true, true, LabelMid, + alignment); } - if (m_zFlipped) { - labelZTrans = -labelZTrans; - alignment = Qt::AlignRight; - } - - // TODO: Test with x labels - const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr); - - // Back wall - QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, labelZTrans + zComp); - - m_dummyRenderItem.setTranslation(labelTrans); - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, m_yAdjustment, zComp), - QVector3D(rotLabelX, rotLabelY, rotLabelZ), - 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, camera, true, true, LabelMid, - alignment); - - // Side wall - if (m_xFlipped) - alignment = Qt::AlignLeft; - else - alignment = Qt::AlignRight; - if (m_zFlipped) - rotLabelY = 180.0f; - else - rotLabelY = 0.0f; - - labelTrans = QVector3D(-labelXTrans, labelYTrans, -labelZTrans + zComp); - - m_dummyRenderItem.setTranslation(labelTrans); - m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix, - QVector3D(0.0f, m_yAdjustment, zComp), - QVector3D(rotLabelX, rotLabelY, rotLabelZ), - 0, m_cachedSelectionMode, - m_labelShader, m_labelObj, camera, true, true, LabelMid, - alignment); + labelNbr++; + labelPos += posStep; } - labelNbr++; } glDisable(GL_TEXTURE_2D); if (m_cachedLabelTransparency > TransparencyNone) @@ -1418,19 +1443,6 @@ void Scatter3DRenderer::updateShadowQuality(ShadowQuality quality) #endif } -void Scatter3DRenderer::updateSegmentCount(GLint segmentCount, GLfloat step, GLfloat minimum) -{ - //qDebug() << __FUNCTION__; - m_segmentCount = segmentCount; - m_segmentStep = step; - if (segmentCount > 0 && step > 0) { - m_autoAdjust = false; - m_heightNormalizer = segmentCount * step; - calculateHeightAdjustment(QPair<float, float>(minimum, m_heightNormalizer)); - m_valueUpdateNeeded = true; - } -} - void Scatter3DRenderer::loadBarMesh() { //qDebug() << __FUNCTION__; @@ -1475,6 +1487,14 @@ void Scatter3DRenderer::updateTextures() m_updateLabels = true; } +void Scatter3DRenderer::updateAxisRange(QAbstractAxis::AxisOrientation orientation, + qreal min, qreal max) +{ + Abstract3DRenderer::updateAxisRange(orientation, min, max); + // If this function is called, then value update is also needed + m_valueUpdateNeeded = true; +} + void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item) { //qDebug() << __FUNCTION__; @@ -1490,25 +1510,14 @@ void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item) //qDebug() << item.translation(); } -void Scatter3DRenderer::calculateSceneScalingFactors(const QVector3D &limits) +void Scatter3DRenderer::calculateSceneScalingFactors() { - if (m_autoAdjust) { - m_heightNormalizer = (GLfloat)qMax((qreal)m_heightNormalizer, qFabs(limits.y())); - m_segmentStep = m_heightNormalizer / m_segmentCount; - } - // Auto-adjust these anyway (until axis -based segments are taken into use) - m_areaSize.setHeight(qMax(m_areaSize.height(), (qreal)limits.z())); - m_areaSize.setWidth(qMax(m_areaSize.width(), (qreal)limits.x())); - m_scaleFactor = qMax(qMax((qreal)m_scaleFactor, m_areaSize.width()), m_areaSize.height()); - //qDebug() << m_heightNormalizer << m_areaSize << m_scaleFactor << m_segmentStep; -} - -void Scatter3DRenderer::calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits) -{ - //qDebug() << __FUNCTION__; - // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer - m_yAdjustment = 2.0f - ((limits.second - limits.first) / m_heightNormalizer); - //qDebug() << limits << m_yAdjustment; + m_heightNormalizer = (GLfloat)m_axisCacheY.max(); + // TODO: Get rid of m_areaSize and use m_axisCaches directly? + m_areaSize.setHeight(m_axisCacheZ.max()); + m_areaSize.setWidth(m_axisCacheX.max()); + m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()); + //qDebug() << m_heightNormalizer << m_areaSize << m_scaleFactor << m_axisCacheY.max() << m_axisCacheX.max() << m_axisCacheZ.max(); } Scatter3DController::SelectionType Scatter3DRenderer::isSelected(GLint bar, diff --git a/src/datavis3d/engine/scatter3drenderer_p.h b/src/datavis3d/engine/scatter3drenderer_p.h index 830cd062..6d2b6e1d 100644 --- a/src/datavis3d/engine/scatter3drenderer_p.h +++ b/src/datavis3d/engine/scatter3drenderer_p.h @@ -105,8 +105,6 @@ private: // Internal state ScatterRenderItem *m_selectedItem; // points to renderitem array ScatterRenderItem *m_previouslySelectedItem; // points to renderitem array - GLint m_segmentCount; - GLfloat m_segmentStep; bool m_xFlipped; bool m_zFlipped; QRect m_mainViewPort; @@ -129,7 +127,6 @@ private: GLuint m_selectionDepthBuffer; GLfloat m_shadowQualityToShader; GLfloat m_heightNormalizer; - GLfloat m_yAdjustment; GLfloat m_scaleFactor; QVector3D m_selection; QSizeF m_areaSize; @@ -138,7 +135,6 @@ private: QPoint m_selectionPointRequest; bool m_isSelectionPointRequestActive; - bool m_autoAdjust; bool m_hasHeightAdjustmentChanged; ScatterRenderItem m_dummyRenderItem; QScatterDataProxy *m_dataProxy; // Only valid during render @@ -166,9 +162,11 @@ public slots: void updateZoomLevel(int newZoomLevel); void updateGridEnabled(bool enable); void updateBackgroundEnabled(bool enable); - void updateSegmentCount(GLint segmentCount, GLfloat step, GLfloat minimum = 0.0f); void updateMeshFileName(const QString &objFileName); + // Overloaded from abstract renderer + virtual void updateAxisRange(QAbstractAxis::AxisOrientation orientation, qreal min, qreal max); + // Requests that upon next render pass the column and row under the given point is inspected for selection. // Only one request can be queued per render pass at this point. New request will override any pending requests. // After inspection the selectionUpdated signal is emitted. @@ -200,8 +198,7 @@ private: void updateDepthBuffer(); #endif void calculateTranslation(ScatterRenderItem &item); - void calculateSceneScalingFactors(const QVector3D &limits); - void calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits); + void calculateSceneScalingFactors(); Scatter3DController::SelectionType isSelected(GLint bar, const QVector3D &selection); Q_DISABLE_COPY(Scatter3DRenderer) diff --git a/src/datavis3dqml2/declarativescatter.cpp b/src/datavis3dqml2/declarativescatter.cpp index 0e062dea..86b74a48 100644 --- a/src/datavis3dqml2/declarativescatter.cpp +++ b/src/datavis3dqml2/declarativescatter.cpp @@ -121,14 +121,6 @@ QSGNode *DeclarativeScatter::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa m_cachedState->m_isGridSet = false; } - if (m_cachedState->m_isSegmentCountSet) { - m_shared->setSegmentCount(GLint(m_cachedState->m_segmentCount), - GLfloat(m_cachedState->m_segmentStep), - GLfloat(m_cachedState->m_segmentMin)); - m_cachedState->m_isSegmentCountSet = false; - } - - // If old node exists and has right size, reuse it. if (oldNode && m_initialisedSize == boundingRect().size().toSize()) { // Update bounding rectangle (that has same size as before). @@ -233,16 +225,6 @@ bool DeclarativeScatter::isBackgroundVisible() return m_shared->backgroundEnabled(); } -void DeclarativeScatter::setSegmentCount(int segmentCount, qreal step, qreal minimum) -{ - m_cachedState->m_isSegmentCountSet = true; - m_cachedState->m_segmentCount = segmentCount; - m_cachedState->m_segmentStep = step; - m_cachedState->m_segmentMin = minimum; - - update(); -} - void DeclarativeScatter::setData(QAbstractItemModel *data) { static_cast<QItemModelScatterDataProxy *>(m_shared->dataProxy())->setItemModel(data); @@ -384,11 +366,7 @@ DeclarativeScatterCachedStatePrivate::DeclarativeScatterCachedStatePrivate() : m_isShadowQualitySet(false), m_shadowQuality(ShadowNone), m_isGridSet(false), - m_isGridEnabled(true), - m_isSegmentCountSet(false), - m_segmentCount(5), - m_segmentStep(1), - m_segmentMin(0) + m_isGridEnabled(true) { } diff --git a/src/datavis3dqml2/declarativescatter.h b/src/datavis3dqml2/declarativescatter.h index 1fd73ed6..9363b9bf 100644 --- a/src/datavis3dqml2/declarativescatter.h +++ b/src/datavis3dqml2/declarativescatter.h @@ -148,11 +148,6 @@ public: Q_INVOKABLE void setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, bool uniform = true); - // Set segment count and step. Note; segmentCount * step should be the maximum possible value of data - // set. Minimum is the absolute minimum possible value a bar can have. This is especially - // important to set if values can be negative. - Q_INVOKABLE void setSegmentCount(int segmentCount, qreal step, qreal minimum); - // TODO: light placement API // Change selection mode; single bar, bar and row, bar and column, or all diff --git a/src/datavis3dqml2/declarativescatter_p.h b/src/datavis3dqml2/declarativescatter_p.h index fbc1987b..c5433944 100644 --- a/src/datavis3dqml2/declarativescatter_p.h +++ b/src/datavis3dqml2/declarativescatter_p.h @@ -78,11 +78,6 @@ public: bool m_isGridSet; bool m_isGridEnabled; - - bool m_isSegmentCountSet; - int m_segmentCount; - qreal m_segmentStep; - qreal m_segmentMin; }; QT_DATAVIS3D_END_NAMESPACE |