summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/datavisualization/axis/axis.pri10
-rw-r--r--src/datavisualization/axis/qabstract3daxis.cpp201
-rw-r--r--src/datavisualization/axis/qabstract3daxis.h15
-rw-r--r--src/datavisualization/axis/qabstract3daxis_p.h17
-rw-r--r--src/datavisualization/axis/qcategory3daxis.cpp21
-rw-r--r--src/datavisualization/axis/qcategory3daxis_p.h12
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter.cpp432
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter.h72
-rw-r--r--src/datavisualization/axis/qlogvalue3daxisformatter_p.h71
-rw-r--r--src/datavisualization/axis/qvalue3daxis.cpp112
-rw-r--r--src/datavisualization/axis/qvalue3daxis.h13
-rw-r--r--src/datavisualization/axis/qvalue3daxis_p.h21
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter.cpp419
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter.h86
-rw-r--r--src/datavisualization/axis/qvalue3daxisformatter_p.h91
-rw-r--r--src/datavisualization/common.pri3
-rw-r--r--src/datavisualization/data/abstractitemmodelhandler.cpp4
-rw-r--r--src/datavisualization/data/abstractitemmodelhandler_p.h6
-rw-r--r--src/datavisualization/data/abstractrenderitem_p.h2
-rw-r--r--src/datavisualization/data/baritemmodelhandler.cpp162
-rw-r--r--src/datavisualization/data/baritemmodelhandler_p.h12
-rw-r--r--src/datavisualization/data/barrenderitem.cpp7
-rw-r--r--src/datavisualization/data/barrenderitem_p.h8
-rw-r--r--src/datavisualization/data/customrenderitem.cpp42
-rw-r--r--src/datavisualization/data/customrenderitem_p.h93
-rw-r--r--src/datavisualization/data/data.pri12
-rw-r--r--src/datavisualization/data/labelitem_p.h1
-rw-r--r--src/datavisualization/data/qabstract3dseries.cpp140
-rw-r--r--src/datavisualization/data/qabstract3dseries.h8
-rw-r--r--src/datavisualization/data/qabstract3dseries_p.h26
-rw-r--r--src/datavisualization/data/qabstractdataproxy.cpp5
-rw-r--r--src/datavisualization/data/qabstractdataproxy_p.h6
-rw-r--r--src/datavisualization/data/qbar3dseries.cpp53
-rw-r--r--src/datavisualization/data/qbar3dseries_p.h1
-rw-r--r--src/datavisualization/data/qbardataitem.cpp2
-rw-r--r--src/datavisualization/data/qbardataitem_p.h3
-rw-r--r--src/datavisualization/data/qbardataproxy.cpp12
-rw-r--r--src/datavisualization/data/qbardataproxy_p.h1
-rw-r--r--src/datavisualization/data/qcustom3ditem.cpp422
-rw-r--r--src/datavisualization/data/qcustom3ditem.h102
-rw-r--r--src/datavisualization/data/qcustom3ditem_p.h99
-rw-r--r--src/datavisualization/data/qcustom3dlabel.cpp358
-rw-r--r--src/datavisualization/data/qcustom3dlabel.h93
-rw-r--r--src/datavisualization/data/qcustom3dlabel_p.h73
-rw-r--r--src/datavisualization/data/qheightmapsurfacedataproxy.cpp2
-rw-r--r--src/datavisualization/data/qitemmodelbardataproxy.cpp403
-rw-r--r--src/datavisualization/data/qitemmodelbardataproxy.h66
-rw-r--r--src/datavisualization/data/qitemmodelbardataproxy_p.h12
-rw-r--r--src/datavisualization/data/qitemmodelscatterdataproxy.cpp326
-rw-r--r--src/datavisualization/data/qitemmodelscatterdataproxy.h47
-rw-r--r--src/datavisualization/data/qitemmodelscatterdataproxy_p.h10
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedataproxy.cpp503
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedataproxy.h80
-rw-r--r--src/datavisualization/data/qitemmodelsurfacedataproxy_p.h14
-rw-r--r--src/datavisualization/data/qscatter3dseries.cpp47
-rw-r--r--src/datavisualization/data/qscatter3dseries_p.h1
-rw-r--r--src/datavisualization/data/qscatterdataitem.cpp2
-rw-r--r--src/datavisualization/data/qscatterdataitem_p.h3
-rw-r--r--src/datavisualization/data/qscatterdataproxy.cpp3
-rw-r--r--src/datavisualization/data/qsurface3dseries.cpp49
-rw-r--r--src/datavisualization/data/qsurface3dseries_p.h1
-rw-r--r--src/datavisualization/data/qsurfacedataitem.cpp2
-rw-r--r--src/datavisualization/data/qsurfacedataitem_p.h3
-rw-r--r--src/datavisualization/data/qsurfacedataproxy.cpp36
-rw-r--r--src/datavisualization/data/scatteritemmodelhandler.cpp76
-rw-r--r--src/datavisualization/data/scatteritemmodelhandler_p.h12
-rw-r--r--src/datavisualization/data/scatterrenderitem.cpp6
-rw-r--r--src/datavisualization/data/scatterrenderitem_p.h4
-rw-r--r--src/datavisualization/data/surfaceitemmodelhandler.cpp199
-rw-r--r--src/datavisualization/data/surfaceitemmodelhandler_p.h16
-rw-r--r--src/datavisualization/doc/qtdatavisualization.qdocconf10
-rw-r--r--src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp8
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc180
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization-qml-color.qdoc35
-rw-r--r--src/datavisualization/doc/src/qtdatavisualization.qdoc59
-rw-r--r--src/datavisualization/engine/abstract3dcontroller.cpp563
-rw-r--r--src/datavisualization/engine/abstract3dcontroller_p.h141
-rw-r--r--src/datavisualization/engine/abstract3drenderer.cpp797
-rw-r--r--src/datavisualization/engine/abstract3drenderer_p.h123
-rw-r--r--src/datavisualization/engine/axisrendercache.cpp89
-rw-r--r--src/datavisualization/engine/axisrendercache_p.h81
-rw-r--r--src/datavisualization/engine/bars3dcontroller.cpp133
-rw-r--r--src/datavisualization/engine/bars3dcontroller_p.h23
-rw-r--r--src/datavisualization/engine/bars3drenderer.cpp2245
-rw-r--r--src/datavisualization/engine/bars3drenderer_p.h51
-rw-r--r--src/datavisualization/engine/barseriesrendercache.cpp42
-rw-r--r--src/datavisualization/engine/barseriesrendercache_p.h61
-rw-r--r--src/datavisualization/engine/drawer.cpp174
-rw-r--r--src/datavisualization/engine/drawer_p.h12
-rw-r--r--src/datavisualization/engine/engine.pri8
-rw-r--r--src/datavisualization/engine/engine.qrc5
-rw-r--r--src/datavisualization/engine/meshes/backgroundNoFloor.obj (renamed from src/datavisualization/engine/meshes/backgroundNegatives.obj)20
-rw-r--r--src/datavisualization/engine/q3dbars.cpp8
-rw-r--r--src/datavisualization/engine/q3dcamera.cpp23
-rw-r--r--src/datavisualization/engine/q3dlight.cpp4
-rw-r--r--src/datavisualization/engine/q3dobject.cpp3
-rw-r--r--src/datavisualization/engine/q3dscatter.cpp6
-rw-r--r--src/datavisualization/engine/q3dscene.cpp17
-rw-r--r--src/datavisualization/engine/q3dscene.h2
-rw-r--r--src/datavisualization/engine/q3dscene_p.h1
-rw-r--r--src/datavisualization/engine/q3dsurface.cpp6
-rw-r--r--src/datavisualization/engine/qabstract3dgraph.cpp355
-rw-r--r--src/datavisualization/engine/qabstract3dgraph.h65
-rw-r--r--src/datavisualization/engine/qabstract3dgraph_p.h5
-rw-r--r--src/datavisualization/engine/scatter3dcontroller.cpp85
-rw-r--r--src/datavisualization/engine/scatter3dcontroller_p.h13
-rw-r--r--src/datavisualization/engine/scatter3drenderer.cpp1924
-rw-r--r--src/datavisualization/engine/scatter3drenderer_p.h53
-rw-r--r--src/datavisualization/engine/scatterseriesrendercache.cpp50
-rw-r--r--src/datavisualization/engine/scatterseriesrendercache_p.h77
-rw-r--r--src/datavisualization/engine/selectionpointer.cpp37
-rw-r--r--src/datavisualization/engine/selectionpointer_p.h12
-rw-r--r--src/datavisualization/engine/seriesrendercache.cpp112
-rw-r--r--src/datavisualization/engine/seriesrendercache_p.h33
-rw-r--r--src/datavisualization/engine/shaders/colorOnY.frag6
-rw-r--r--src/datavisualization/engine/shaders/colorOnY_ES2.frag10
-rw-r--r--src/datavisualization/engine/shaders/default.frag8
-rw-r--r--src/datavisualization/engine/shaders/default.vert10
-rw-r--r--src/datavisualization/engine/shaders/default_ES2.frag12
-rw-r--r--src/datavisualization/engine/shaders/plainColor.frag5
-rw-r--r--src/datavisualization/engine/shaders/shadow.frag6
-rw-r--r--src/datavisualization/engine/shaders/shadow.vert8
-rw-r--r--src/datavisualization/engine/shaders/shadowNoTex.frag8
-rw-r--r--src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag6
-rw-r--r--src/datavisualization/engine/shaders/surface.frag6
-rw-r--r--src/datavisualization/engine/shaders/surfaceFlat.frag6
-rw-r--r--src/datavisualization/engine/shaders/surfaceFlat.vert8
-rw-r--r--src/datavisualization/engine/shaders/surfaceShadowFlat.frag6
-rw-r--r--src/datavisualization/engine/shaders/surfaceShadowFlat.vert8
-rw-r--r--src/datavisualization/engine/shaders/surfaceShadowNoTex.frag6
-rw-r--r--src/datavisualization/engine/shaders/surface_ES2.frag10
-rw-r--r--src/datavisualization/engine/shaders/texture.frag37
-rw-r--r--src/datavisualization/engine/shaders/texture.vert28
-rw-r--r--src/datavisualization/engine/shaders/texture_ES2.frag40
-rw-r--r--src/datavisualization/engine/surface3dcontroller.cpp100
-rw-r--r--src/datavisualization/engine/surface3dcontroller_p.h8
-rw-r--r--src/datavisualization/engine/surface3drenderer.cpp1543
-rw-r--r--src/datavisualization/engine/surface3drenderer_p.h44
-rw-r--r--src/datavisualization/engine/surfaceseriesrendercache.cpp39
-rw-r--r--src/datavisualization/engine/surfaceseriesrendercache_p.h28
-rw-r--r--src/datavisualization/global/datavisualizationglobal_p.h14
-rw-r--r--src/datavisualization/global/qdatavisualizationglobal.h4
-rw-r--r--src/datavisualization/input/q3dinputhandler.cpp16
-rw-r--r--src/datavisualization/input/qabstract3dinputhandler.cpp8
-rw-r--r--src/datavisualization/input/qabstract3dinputhandler_p.h3
-rw-r--r--src/datavisualization/input/qtouch3dinputhandler.cpp3
-rw-r--r--src/datavisualization/theme/q3dtheme.cpp4
-rw-r--r--src/datavisualization/utils/abstractobjecthelper_p.h1
-rw-r--r--src/datavisualization/utils/camerahelper_p.h2
-rw-r--r--src/datavisualization/utils/objecthelper.cpp107
-rw-r--r--src/datavisualization/utils/objecthelper_p.h24
-rw-r--r--src/datavisualization/utils/scatterobjectbufferhelper.cpp226
-rw-r--r--src/datavisualization/utils/scatterobjectbufferhelper_p.h50
-rw-r--r--src/datavisualization/utils/scatterpointbufferhelper.cpp113
-rw-r--r--src/datavisualization/utils/scatterpointbufferhelper_p.h61
-rw-r--r--src/datavisualization/utils/shaderhelper_p.h1
-rw-r--r--src/datavisualization/utils/surfaceobject.cpp211
-rw-r--r--src/datavisualization/utils/surfaceobject_p.h32
-rw-r--r--src/datavisualization/utils/texturehelper.cpp18
-rw-r--r--src/datavisualization/utils/texturehelper_p.h3
-rw-r--r--src/datavisualization/utils/utils.cpp46
-rw-r--r--src/datavisualization/utils/utils.pri8
-rw-r--r--src/datavisualization/utils/utils_p.h18
-rw-r--r--src/datavisualizationqml2/abstractdeclarative.cpp158
-rw-r--r--src/datavisualizationqml2/abstractdeclarative_p.h70
-rw-r--r--src/datavisualizationqml2/datavisualizationqml2_plugin.cpp32
-rw-r--r--src/datavisualizationqml2/datavisualizationqml2_plugin.h11
-rw-r--r--src/datavisualizationqml2/declarativebars.cpp6
-rw-r--r--src/datavisualizationqml2/declarativebars_p.h6
-rw-r--r--src/datavisualizationqml2/declarativerendernode.cpp26
-rw-r--r--src/datavisualizationqml2/declarativerendernode_p.h4
-rw-r--r--src/datavisualizationqml2/declarativescatter.cpp13
-rw-r--r--src/datavisualizationqml2/declarativescatter_p.h3
-rw-r--r--src/datavisualizationqml2/declarativeseries.cpp12
-rw-r--r--src/datavisualizationqml2/declarativesurface.cpp3
-rw-r--r--src/datavisualizationqml2/declarativesurface_p.h3
-rw-r--r--src/datavisualizationqml2/declarativetheme.cpp16
-rw-r--r--src/datavisualizationqml2/declarativetheme_p.h8
-rw-r--r--src/datavisualizationqml2/designer/Bars3DSpecifics.qml23
-rw-r--r--src/datavisualizationqml2/designer/Scatter3DSpecifics.qml37
-rw-r--r--src/datavisualizationqml2/designer/Surface3DSpecifics.qml38
-rw-r--r--src/datavisualizationqml2/enumtostringmap.cpp15
-rw-r--r--src/datavisualizationqml2/glstatestore.cpp47
-rw-r--r--src/datavisualizationqml2/glstatestore_p.h17
-rw-r--r--src/datavisualizationqml2/plugins.qmltypes450
185 files changed, 13131 insertions, 3859 deletions
diff --git a/src/datavisualization/axis/axis.pri b/src/datavisualization/axis/axis.pri
index 2c8bf70e..0173b597 100644
--- a/src/datavisualization/axis/axis.pri
+++ b/src/datavisualization/axis/axis.pri
@@ -4,9 +4,15 @@ HEADERS += \
$$PWD/qvalue3daxis.h \
$$PWD/qvalue3daxis_p.h \
$$PWD/qcategory3daxis.h \
- $$PWD/qcategory3daxis_p.h
+ $$PWD/qcategory3daxis_p.h \
+ $$PWD/qvalue3daxisformatter.h \
+ $$PWD/qvalue3daxisformatter_p.h \
+ $$PWD/qlogvalue3daxisformatter.h \
+ $$PWD/qlogvalue3daxisformatter_p.h
SOURCES += \
$$PWD/qabstract3daxis.cpp \
$$PWD/qvalue3daxis.cpp \
- $$PWD/qcategory3daxis.cpp
+ $$PWD/qcategory3daxis.cpp \
+ $$PWD/qvalue3daxisformatter.cpp \
+ $$PWD/qlogvalue3daxisformatter.cpp
diff --git a/src/datavisualization/axis/qabstract3daxis.cpp b/src/datavisualization/axis/qabstract3daxis.cpp
index 3a327caa..9fd5a832 100644
--- a/src/datavisualization/axis/qabstract3daxis.cpp
+++ b/src/datavisualization/axis/qabstract3daxis.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "qabstract3daxis.h"
#include "qabstract3daxis_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -25,7 +24,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QAbstract3DAxis
* \inmodule QtDataVisualization
* \brief QAbstract3DAxis is base class for axes of a graph.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* You should not need to use this class directly, but one of its subclasses instead.
*
@@ -42,12 +41,15 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* This type is uncreatable, but contains properties that are exposed via subtypes.
*
- * For AbstractAxis3D enums, see \l QAbstract3DAxis::AxisOrientation and \l QAbstract3DAxis::AxisType
+ * For AbstractAxis3D enums, see \l QAbstract3DAxis::AxisOrientation and
+ * \l{QAbstract3DAxis::AxisType}.
*/
/*!
* \qmlproperty string AbstractAxis3D::title
* Defines the title for the axis.
+ *
+ * \sa titleVisible, titleFixed
*/
/*!
@@ -88,6 +90,36 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* If set, the axis will automatically adjust the range so that all data fits in it.
*/
+/*!
+ * \qmlproperty real AbstractAxis3D::labelAutoRotation
+ *
+ * Defines the maximum \a angle the labels can autorotate when the camera angle changes.
+ * The \a angle can be between 0 and 90, inclusive. The default value is 0.
+ * If the value is 0, axis labels do not automatically rotate.
+ * If the value is greater than zero, labels attempt to orient themselves toward the camera, up to
+ * the specified angle.
+ */
+
+/*!
+ * \qmlproperty bool AbstractAxis3D::titleVisible
+ *
+ * Defines if the axis title is visible in the primary graph view. The default value is \c{false}.
+ *
+ * \sa title, titleFixed
+ */
+
+/*!
+ * \qmlproperty bool AbstractAxis3D::titleFixed
+ *
+ * If \c{true}, axis titles in the primary graph view will be rotated towards the camera similarly
+ * to the axis labels.
+ * If \c{false}, axis titles are only rotated around their axis but are not otherwise oriented
+ * towards the camera.
+ * This property doesn't have any effect if labelAutoRotation property value is zero.
+ * Default value is \c{true}.
+ *
+ * \sa labelAutoRotation, title, titleVisible
+ */
/*!
* \enum QAbstract3DAxis::AxisOrientation
@@ -150,6 +182,8 @@ QAbstract3DAxis::AxisType QAbstract3DAxis::type() const
* \property QAbstract3DAxis::title
*
* Defines the title for the axis.
+ *
+ * \sa titleVisible, titleFixed
*/
void QAbstract3DAxis::setTitle(const QString &title)
{
@@ -193,6 +227,77 @@ void QAbstract3DAxis::setRange(float min, float max)
}
/*!
+ * \property QAbstract3DAxis::labelAutoRotation
+ *
+ * Defines the maximum \a angle the labels can autorotate when the camera angle changes.
+ * The \a angle can be between 0 and 90, inclusive. The default value is 0.
+ * If the value is 0, axis labels do not automatically rotate.
+ * If the value is greater than zero, labels attempt to orient themselves toward the camera, up to
+ * the specified angle.
+ */
+void QAbstract3DAxis::setLabelAutoRotation(float angle)
+{
+ if (angle < 0.0f)
+ angle = 0.0f;
+ if (angle > 90.0f)
+ angle = 90.0f;
+ if (d_ptr->m_labelAutoRotation != angle) {
+ d_ptr->m_labelAutoRotation = angle;
+ emit labelAutoRotationChanged(angle);
+ }
+}
+
+float QAbstract3DAxis::labelAutoRotation() const
+{
+ return d_ptr->m_labelAutoRotation;
+}
+
+/*!
+ * \property QAbstract3DAxis::titleVisible
+ *
+ * Defines if the axis title is visible in the primary graph view. The default value is \c{false}.
+ *
+ * \sa title, titleFixed
+ */
+void QAbstract3DAxis::setTitleVisible(bool visible)
+{
+ if (d_ptr->m_titleVisible != visible) {
+ d_ptr->m_titleVisible = visible;
+ emit titleVisibilityChanged(visible);
+ }
+}
+
+bool QAbstract3DAxis::isTitleVisible() const
+{
+ return d_ptr->m_titleVisible;
+}
+
+/*!
+ * \property QAbstract3DAxis::titleFixed
+ *
+ * If \c{true}, axis titles in the primary graph view will be rotated towards the camera similarly
+ * to the axis labels.
+ * If \c{false}, axis titles are only rotated around their axis but are not otherwise oriented
+ * towards the camera.
+ * This property doesn't have any effect if labelAutoRotation property value is zero.
+ * Default value is \c{true}.
+ *
+ * \sa labelAutoRotation, title, titleVisible
+ */
+void QAbstract3DAxis::setTitleFixed(bool fixed)
+{
+ if (d_ptr->m_titleFixed != fixed) {
+ d_ptr->m_titleFixed = fixed;
+ emit titleFixedChanged(fixed);
+ }
+}
+
+bool QAbstract3DAxis::isTitleFixed() const
+{
+ return d_ptr->m_titleFixed;
+}
+
+/*!
* \property QAbstract3DAxis::min
*
* Defines the minimum value on the axis.
@@ -266,8 +371,9 @@ QAbstract3DAxisPrivate::QAbstract3DAxisPrivate(QAbstract3DAxis *q, QAbstract3DAx
m_min(0.0f),
m_max(10.0f),
m_autoAdjust(true),
- m_onlyPositiveValues(false),
- m_allowMinMaxSame(false)
+ m_labelAutoRotation(0.0f),
+ m_titleVisible(false),
+ m_titleFixed(true)
{
}
@@ -290,17 +396,28 @@ void QAbstract3DAxisPrivate::updateLabels()
// Default implementation does nothing
}
-void QAbstract3DAxisPrivate::setRange(float min, float max)
+void QAbstract3DAxisPrivate::setRange(float min, float max, bool suppressWarnings)
{
bool adjusted = false;
- if (m_onlyPositiveValues) {
- if (min < 0.0f) {
- min = 0.0f;
- adjusted = true;
- }
- if (max < 0.0f) {
- max = 0.0f;
- adjusted = true;
+ if (!allowNegatives()) {
+ if (allowZero()) {
+ if (min < 0.0f) {
+ min = 0.0f;
+ adjusted = true;
+ }
+ if (max < 0.0f) {
+ max = 0.0f;
+ adjusted = true;
+ }
+ } else {
+ if (min <= 0.0f) {
+ min = 1.0f;
+ adjusted = true;
+ }
+ if (max <= 0.0f) {
+ max = 1.0f;
+ adjusted = true;
+ }
}
}
// If min >= max, we adjust ranges so that
@@ -312,8 +429,8 @@ void QAbstract3DAxisPrivate::setRange(float min, float max)
m_min = min;
minDirty = true;
}
- if (m_max != max || min > max || (!m_allowMinMaxSame && min == max)) {
- if (min > max || (!m_allowMinMaxSame && min == max)) {
+ if (m_max != max || min > max || (!allowMinMaxSame() && min == max)) {
+ if (min > max || (!allowMinMaxSame() && min == max)) {
m_max = min + 1.0f;
adjusted = true;
} else {
@@ -323,7 +440,7 @@ void QAbstract3DAxisPrivate::setRange(float min, float max)
}
if (minDirty || maxDirty) {
- if (adjusted) {
+ if (adjusted && !suppressWarnings) {
qWarning() << "Warning: Tried to set invalid range for axis."
" Range automatically adjusted to a valid one:"
<< min << "-" << max << "-->" << m_min << "-" << m_max;
@@ -339,17 +456,25 @@ void QAbstract3DAxisPrivate::setRange(float min, float max)
void QAbstract3DAxisPrivate::setMin(float min)
{
- if (m_onlyPositiveValues) {
- if (min < 0.0f) {
- min = 0.0f;
- qWarning() << "Warning: Tried to set negative minimum for an axis that only supports"
- " positive values:" << min;
+ if (!allowNegatives()) {
+ if (allowZero()) {
+ if (min < 0.0f) {
+ min = 0.0f;
+ qWarning() << "Warning: Tried to set negative minimum for an axis that only"
+ "supports positive values and zero:" << min;
+ }
+ } else {
+ if (min <= 0.0f) {
+ min = 1.0f;
+ qWarning() << "Warning: Tried to set negative or zero minimum for an axis that only"
+ "supports positive values:" << min;
+ }
}
}
if (m_min != min) {
bool maxChanged = false;
- if (min > m_max || (!m_allowMinMaxSame && min == m_max)) {
+ if (min > m_max || (!allowMinMaxSame() && min == m_max)) {
float oldMax = m_max;
m_max = min + 1.0f;
qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for"
@@ -368,22 +493,34 @@ void QAbstract3DAxisPrivate::setMin(float min)
void QAbstract3DAxisPrivate::setMax(float max)
{
- if (m_onlyPositiveValues) {
- if (max < 0.0f) {
- max = 0.0f;
- qWarning() << "Warning: Tried to set negative maximum for an axis that only supports"
- " positive values:" << max;
+ if (!allowNegatives()) {
+ if (allowZero()) {
+ if (max < 0.0f) {
+ max = 0.0f;
+ qWarning() << "Warning: Tried to set negative maximum for an axis that only"
+ "supports positive values and zero:" << max;
+ }
+ } else {
+ if (max <= 0.0f) {
+ max = 1.0f;
+ qWarning() << "Warning: Tried to set negative or zero maximum for an axis that only"
+ "supports positive values:" << max;
+ }
}
}
if (m_max != max) {
bool minChanged = false;
- if (m_min > max || (!m_allowMinMaxSame && m_min == max)) {
+ if (m_min > max || (!allowMinMaxSame() && m_min == max)) {
float oldMin = m_min;
m_min = max - 1.0f;
- if (m_onlyPositiveValues && m_min < 0.0f) {
- m_min = 0.0f;
- if (!m_allowMinMaxSame && max == 0.0f) {
+ if (!allowNegatives() && m_min < 0.0f) {
+ if (allowZero())
+ m_min = 0.0f;
+ else
+ m_min = max / 2.0f; // Need some positive value smaller than max
+
+ if (!allowMinMaxSame() && max == 0.0f) {
m_min = oldMin;
qWarning() << "Unable to set maximum value to zero.";
return;
diff --git a/src/datavisualization/axis/qabstract3daxis.h b/src/datavisualization/axis/qabstract3daxis.h
index 2b2be229..a9f75550 100644
--- a/src/datavisualization/axis/qabstract3daxis.h
+++ b/src/datavisualization/axis/qabstract3daxis.h
@@ -40,6 +40,9 @@ class QT_DATAVISUALIZATION_EXPORT QAbstract3DAxis : public QObject
Q_PROPERTY(float min READ min WRITE setMin NOTIFY minChanged)
Q_PROPERTY(float max READ max WRITE setMax NOTIFY maxChanged)
Q_PROPERTY(bool autoAdjustRange READ isAutoAdjustRange WRITE setAutoAdjustRange NOTIFY autoAdjustRangeChanged)
+ Q_PROPERTY(float labelAutoRotation READ labelAutoRotation WRITE setLabelAutoRotation NOTIFY labelAutoRotationChanged REVISION 1)
+ Q_PROPERTY(bool titleVisible READ isTitleVisible WRITE setTitleVisible NOTIFY titleVisibilityChanged REVISION 1)
+ Q_PROPERTY(bool titleFixed READ isTitleFixed WRITE setTitleFixed NOTIFY titleFixedChanged REVISION 1)
public:
enum AxisOrientation {
@@ -81,6 +84,15 @@ public:
void setRange(float min, float max);
+ void setLabelAutoRotation(float angle);
+ float labelAutoRotation() const;
+
+ void setTitleVisible(bool visible);
+ bool isTitleVisible() const;
+
+ void setTitleFixed(bool fixed);
+ bool isTitleFixed() const;
+
signals:
void titleChanged(const QString &newTitle);
void labelsChanged();
@@ -89,6 +101,9 @@ signals:
void maxChanged(float value);
void rangeChanged(float min, float max);
void autoAdjustRangeChanged(bool autoAdjust);
+ Q_REVISION(1) void labelAutoRotationChanged(float angle);
+ Q_REVISION(1) void titleVisibilityChanged(bool visible);
+ Q_REVISION(1) void titleFixedChanged(bool fixed);
protected:
QScopedPointer<QAbstract3DAxisPrivate> d_ptr;
diff --git a/src/datavisualization/axis/qabstract3daxis_p.h b/src/datavisualization/axis/qabstract3daxis_p.h
index 4eb8de68..7181362f 100644
--- a/src/datavisualization/axis/qabstract3daxis_p.h
+++ b/src/datavisualization/axis/qabstract3daxis_p.h
@@ -26,13 +26,12 @@
//
// We mean it.
-#include "datavisualizationglobal_p.h"
-#include "qabstract3daxis.h"
-#include "abstract3dcontroller_p.h"
-
#ifndef QABSTRACT3DAXIS_P_H
#define QABSTRACT3DAXIS_P_H
+#include "datavisualizationglobal_p.h"
+#include "qabstract3daxis.h"
+
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QAbstract3DAxisPrivate : public QObject
@@ -47,12 +46,15 @@ public:
inline bool isDefaultAxis() { return m_isDefaultAxis; }
inline void setDefaultAxis(bool isDefault) { m_isDefaultAxis = isDefault; }
- virtual void setRange(float min, float max);
+ virtual void setRange(float min, float max, bool suppressWarnings = false);
virtual void setMin(float min);
virtual void setMax (float max);
protected:
virtual void updateLabels();
+ virtual bool allowZero() = 0;
+ virtual bool allowNegatives() = 0;
+ virtual bool allowMinMaxSame() = 0;
QAbstract3DAxis *q_ptr;
@@ -64,8 +66,9 @@ protected:
float m_min;
float m_max;
bool m_autoAdjust;
- bool m_onlyPositiveValues;
- bool m_allowMinMaxSame;
+ float m_labelAutoRotation;
+ bool m_titleVisible;
+ bool m_titleFixed;
friend class QAbstract3DAxis;
friend class QValue3DAxis;
diff --git a/src/datavisualization/axis/qcategory3daxis.cpp b/src/datavisualization/axis/qcategory3daxis.cpp
index c11a65eb..f2cd0a84 100644
--- a/src/datavisualization/axis/qcategory3daxis.cpp
+++ b/src/datavisualization/axis/qcategory3daxis.cpp
@@ -16,10 +16,8 @@
**
****************************************************************************/
-#include "qcategory3daxis.h"
#include "qcategory3daxis_p.h"
#include "bars3dcontroller_p.h"
-#include "qbardataproxy.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -27,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QCategory3DAxis
* \inmodule QtDataVisualization
* \brief The QCategory3DAxis class is used for manipulating an axis of a graph.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QCategory3DAxis provides an axis that can be given labels. The axis is divided into equal-sized
* categories based on the data window size defined by setting the axis range.
@@ -121,8 +119,6 @@ QCategory3DAxisPrivate::QCategory3DAxisPrivate(QCategory3DAxis *q)
: QAbstract3DAxisPrivate(q, QAbstract3DAxis::AxisTypeCategory),
m_labelsExplicitlySet(false)
{
- m_onlyPositiveValues = true;
- m_allowMinMaxSame = true;
}
QCategory3DAxisPrivate::~QCategory3DAxisPrivate()
@@ -142,6 +138,21 @@ void QCategory3DAxisPrivate::setDataLabels(const QStringList &labels)
}
}
+bool QCategory3DAxisPrivate::allowZero()
+{
+ return true;
+}
+
+bool QCategory3DAxisPrivate::allowNegatives()
+{
+ return false;
+}
+
+bool QCategory3DAxisPrivate::allowMinMaxSame()
+{
+ return true;
+}
+
QCategory3DAxis *QCategory3DAxisPrivate::qptr()
{
return static_cast<QCategory3DAxis *>(q_ptr);
diff --git a/src/datavisualization/axis/qcategory3daxis_p.h b/src/datavisualization/axis/qcategory3daxis_p.h
index 1ba5ccb0..27126620 100644
--- a/src/datavisualization/axis/qcategory3daxis_p.h
+++ b/src/datavisualization/axis/qcategory3daxis_p.h
@@ -26,13 +26,12 @@
//
// We mean it.
-#include "qcategory3daxis.h"
-#include "qabstract3daxis_p.h"
-#include "qbardataitem.h"
-
#ifndef QCATEGORY3DAXIS_P_H
#define QCATEGORY3DAXIS_P_H
+#include "qcategory3daxis.h"
+#include "qabstract3daxis_p.h"
+
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QCategory3DAxisPrivate : public QAbstract3DAxisPrivate
@@ -45,6 +44,11 @@ public:
void setDataLabels(const QStringList &labels);
+protected:
+ virtual bool allowZero();
+ virtual bool allowNegatives();
+ virtual bool allowMinMaxSame();
+
private:
QCategory3DAxis *qptr();
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter.cpp b/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
new file mode 100644
index 00000000..7367e7c5
--- /dev/null
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qlogvalue3daxisformatter_p.h"
+#include "qvalue3daxis_p.h"
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QLogValue3DAxisFormatter
+ * \inmodule QtDataVisualization
+ * \brief QLogValue3DAxisFormatter implements logarithmic value axis formatter.
+ * \since QtDataVisualization 1.1
+ *
+ * This class provides formatting rules for a logarithmic QValue3DAxis.
+ *
+ * When a QLogValue3DAxisFormatter is attached to a QValue3DAxis, the axis range
+ * cannot include negative values or the zero.
+ *
+ * \sa QValue3DAxisFormatter
+ */
+
+/*!
+ * \qmltype LogValueAxis3DFormatter
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.1
+ * \ingroup datavisualization_qml
+ * \instantiates QLogValue3DAxisFormatter
+ * \brief LogValueAxis3DFormatter implements logarithmic value axis formatter.
+ *
+ * This type provides formatting rules for a logarithmic ValueAxis3D.
+ * When a LogValueAxis3DFormatter is attached to a ValueAxis3D, the axis range
+ * cannot include negative values or the zero.
+ */
+
+/*!
+ * \qmlproperty real LogValueAxis3DFormatter::base
+ *
+ * The \a base of the logarithm used to map axis values. If the base is non-zero, the parent axis
+ * segment count will be ignored when the grid line and label positions are calculated.
+ * If you want the range to be divided into equal segments like normal value axis, set this
+ * property value to zero.
+ *
+ * The \a base has to be zero or positive value and not equal to one.
+ * Defaults to ten.
+ *
+ * \sa ValueAxis3D::segmentCount
+ */
+
+/*!
+ * \qmlproperty bool LogValueAxis3DFormatter::autoSubGrid
+ *
+ * If this property value is set to \c true, the parent axis sub-segment count is ignored
+ * when calculating sub-grid line positions. The sub-grid positions are generated automatically
+ * according to the base property value.
+ * The number of sub-grid lines is set to base value minus one, rounded down.
+ * This property is ignored when base property value is zero.
+ * Defaults to \c true.
+ *
+ * \sa base, ValueAxis3D::subSegmentCount
+ */
+
+/*!
+ * \qmlproperty bool LogValueAxis3DFormatter::showEdgeLabels
+ *
+ * When the base property value is non-zero, the whole axis range is often not equally divided into
+ * segments. The first and last segments are often smaller than the other segments.
+ * In extreme cases this can lead to overlapping labels on the first and last two grid lines.
+ * By setting this property to \c false, you can suppress showing the minimum and maximum labels
+ * for the axis in cases where the segments do not exactly fit the axis.
+ * Defaults to \c true.
+ *
+ * \sa base, AbstractAxis3D::labels
+ */
+
+/*!
+ * \internal
+ */
+QLogValue3DAxisFormatter::QLogValue3DAxisFormatter(QLogValue3DAxisFormatterPrivate *d,
+ QObject *parent) :
+ QValue3DAxisFormatter(d, parent)
+{
+ setAllowNegatives(false);
+ setAllowZero(false);
+}
+
+/*!
+ * Constructs a new QLogValue3DAxisFormatter instance with optional \a parent.
+ */
+QLogValue3DAxisFormatter::QLogValue3DAxisFormatter(QObject *parent) :
+ QValue3DAxisFormatter(new QLogValue3DAxisFormatterPrivate(this), parent)
+{
+ setAllowNegatives(false);
+ setAllowZero(false);
+}
+
+/*!
+ * Destroys QLogValue3DAxisFormatter.
+ */
+QLogValue3DAxisFormatter::~QLogValue3DAxisFormatter()
+{
+}
+
+/*!
+ * \property QLogValue3DAxisFormatter::base
+ *
+ * The \a base of the logarithm used to map axis values. If the base is non-zero, the parent axis
+ * segment count will be ignored when the grid line and label positions are calculated.
+ * If you want the range to be divided into equal segments like normal value axis, set this
+ * property value to zero.
+ *
+ * The \a base has to be zero or positive value and not equal to one.
+ * Defaults to ten.
+ *
+ * \sa QValue3DAxis::segmentCount
+ */
+void QLogValue3DAxisFormatter::setBase(qreal base)
+{
+ if (base < 0.0f || base == 1.0f) {
+ qWarning() << "Warning: The logarithm base must be greater than 0 and not equal to 1,"
+ << "attempted:" << base;
+ return;
+ }
+ if (dptr()->m_base != base) {
+ dptr()->m_base = base;
+ markDirty(true);
+ emit baseChanged(base);
+ }
+}
+
+qreal QLogValue3DAxisFormatter::base() const
+{
+ return dptrc()->m_base;
+}
+
+/*!
+ * \property QLogValue3DAxisFormatter::autoSubGrid
+ *
+ * If this property value is set to \c true, the parent axis sub-segment count is ignored
+ * when calculating sub-grid line positions. The sub-grid positions are generated automatically
+ * according to the base property value.
+ * The number of sub-grid lines is set to base value minus one, rounded down.
+ * This property is ignored when base property value is zero.
+ * Defaults to \c true.
+ *
+ * \sa base, QValue3DAxis::subSegmentCount
+ */
+void QLogValue3DAxisFormatter::setAutoSubGrid(bool enabled)
+{
+ if (dptr()->m_autoSubGrid != enabled) {
+ dptr()->m_autoSubGrid = enabled;
+ markDirty(false);
+ emit autoSubGridChanged(enabled);
+ }
+}
+
+bool QLogValue3DAxisFormatter::autoSubGrid() const
+{
+ return dptrc()->m_autoSubGrid;
+}
+
+/*!
+ * \property QLogValue3DAxisFormatter::showEdgeLabels
+ *
+ * When the base property value is non-zero, the whole axis range is often not equally divided into
+ * segments. The first and last segments are often smaller than the other segments.
+ * In extreme cases this can lead to overlapping labels on the first and last two grid lines.
+ * By setting this property to \c false, you can suppress showing the minimum and maximum labels
+ * for the axis in cases where the segments do not exactly fit the axis.
+ * Defaults to \c true.
+ *
+ * \sa base, QAbstract3DAxis::labels
+ */
+void QLogValue3DAxisFormatter::setShowEdgeLabels(bool enabled)
+{
+ if (dptr()->m_showEdgeLabels != enabled) {
+ dptr()->m_showEdgeLabels = enabled;
+ markDirty(true);
+ emit showEdgeLabelsChanged(enabled);
+ }
+}
+
+bool QLogValue3DAxisFormatter::showEdgeLabels() const
+{
+ return dptrc()->m_showEdgeLabels;
+}
+
+/*!
+ * \internal
+ */
+QValue3DAxisFormatter *QLogValue3DAxisFormatter::createNewInstance() const
+{
+ return new QLogValue3DAxisFormatter();
+}
+
+/*!
+ * \internal
+ */
+void QLogValue3DAxisFormatter::recalculate()
+{
+ dptr()->recalculate();
+}
+
+/*!
+ * \internal
+ */
+float QLogValue3DAxisFormatter::positionAt(float value) const
+{
+ return dptrc()->positionAt(value);
+}
+
+/*!
+ * \internal
+ */
+float QLogValue3DAxisFormatter::valueAt(float position) const
+{
+ return dptrc()->valueAt(position);
+}
+
+/*!
+ * \internal
+ */
+void QLogValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter &copy) const
+{
+ QValue3DAxisFormatter::populateCopy(copy);
+ dptrc()->populateCopy(copy);
+}
+
+/*!
+ * \internal
+ */
+QLogValue3DAxisFormatterPrivate *QLogValue3DAxisFormatter::dptr()
+{
+ return static_cast<QLogValue3DAxisFormatterPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QLogValue3DAxisFormatterPrivate *QLogValue3DAxisFormatter::dptrc() const
+{
+ return static_cast<const QLogValue3DAxisFormatterPrivate *>(d_ptr.data());
+}
+
+// QLogValue3DAxisFormatterPrivate
+QLogValue3DAxisFormatterPrivate::QLogValue3DAxisFormatterPrivate(QLogValue3DAxisFormatter *q)
+ : QValue3DAxisFormatterPrivate(q),
+ m_base(10.0),
+ m_logMin(0.0),
+ m_logMax(0.0),
+ m_logRangeNormalizer(0.0),
+ m_autoSubGrid(true),
+ m_showEdgeLabels(true),
+ m_evenMinSegment(true),
+ m_evenMaxSegment(true)
+{
+}
+
+QLogValue3DAxisFormatterPrivate::~QLogValue3DAxisFormatterPrivate()
+{
+}
+
+void QLogValue3DAxisFormatterPrivate::recalculate()
+{
+ // When doing position/value mappings, base doesn't matter, so just use natural logarithm
+ m_logMin = qLn(qreal(m_min));
+ m_logMax = qLn(qreal(m_max));
+ m_logRangeNormalizer = m_logMax - m_logMin;
+
+ int subGridCount = m_axis->subSegmentCount() - 1;
+ int segmentCount = m_axis->segmentCount();
+ QString labelFormat = m_axis->labelFormat();
+ qreal segmentStep;
+ if (m_base > 0.0) {
+ // Update parent axis segment counts
+ qreal logMin = qLn(qreal(m_min)) / qLn(m_base);
+ qreal logMax = qLn(qreal(m_max)) / qLn(m_base);
+ qreal logRangeNormalizer = logMax - logMin;
+
+ qreal minDiff = qCeil(logMin) - logMin;
+ qreal maxDiff = logMax - qFloor(logMax);
+
+ m_evenMinSegment = qFuzzyCompare(0.0, minDiff);
+ m_evenMaxSegment = qFuzzyCompare(0.0, maxDiff);
+
+ segmentCount = qRound(logRangeNormalizer - minDiff - maxDiff);
+
+ if (!m_evenMinSegment)
+ segmentCount++;
+ if (!m_evenMaxSegment)
+ segmentCount++;
+
+ segmentStep = 1.0 / logRangeNormalizer;
+
+ if (m_autoSubGrid) {
+ subGridCount = qCeil(m_base) - 2; // -2 for subgrid because subsegment count is base - 1
+ if (subGridCount < 0)
+ subGridCount = 0;
+ }
+
+ m_gridPositions.resize(segmentCount + 1);
+ m_subGridPositions.resize(segmentCount * subGridCount);
+ m_labelPositions.resize(segmentCount + 1);
+ m_labelStrings.clear();
+ m_labelStrings.reserve(segmentCount + 1);
+
+ // Calculate segment positions
+ int index = 0;
+ if (!m_evenMinSegment) {
+ m_gridPositions[0] = 0.0f;
+ m_labelPositions[0] = 0.0f;
+ if (m_showEdgeLabels)
+ m_labelStrings << qptr()->stringForValue(qreal(m_min), labelFormat);
+ else
+ m_labelStrings << QString();
+ index++;
+ }
+ for (int i = 0; i < segmentCount; i++) {
+ float gridValue = float((minDiff + qreal(i)) / qreal(logRangeNormalizer));
+ m_gridPositions[index] = gridValue;
+ m_labelPositions[index] = gridValue;
+ m_labelStrings << qptr()->stringForValue(qPow(m_base, minDiff + qreal(i) + logMin),
+ labelFormat);
+ index++;
+ }
+ // Ensure max value doesn't suffer from any rounding errors
+ m_gridPositions[segmentCount] = 1.0f;
+ m_labelPositions[segmentCount] = 1.0f;
+ QString finalLabel;
+ if (m_showEdgeLabels || m_evenMaxSegment)
+ finalLabel = qptr()->stringForValue(qreal(m_max), labelFormat);
+
+ if (m_labelStrings.size() > segmentCount)
+ m_labelStrings.replace(segmentCount, finalLabel);
+ else
+ m_labelStrings << finalLabel;
+ } else {
+ // Grid lines and label positions are the same as the parent class, so call parent impl
+ // first to populate those
+ QValue3DAxisFormatterPrivate::doRecalculate();
+
+ // Label string list needs to be repopulated
+ segmentStep = 1.0 / qreal(segmentCount);
+
+ m_labelStrings << qptr()->stringForValue(qreal(m_min), labelFormat);
+ for (int i = 1; i < m_labelPositions.size() - 1; i++)
+ m_labelStrings[i] = qptr()->stringForValue(qExp(segmentStep * qreal(i)
+ * m_logRangeNormalizer + m_logMin),
+ labelFormat);
+ m_labelStrings << qptr()->stringForValue(qreal(m_max), labelFormat);
+
+ m_evenMaxSegment = true;
+ m_evenMinSegment = true;
+ }
+
+ // Subgrid line positions are logarithmically spaced
+ if (subGridCount > 0) {
+ float oneSegmentRange = valueAt(float(segmentStep)) - m_min;
+ float subSegmentStep = oneSegmentRange / float(subGridCount + 1);
+
+ // Since the logarithm has the same curvature across whole axis range, we can just calculate
+ // subgrid positions for the first segment and replicate them to other segments.
+ QVector<float> actualSubSegmentSteps(subGridCount);
+
+ for (int i = 0; i < subGridCount; i++) {
+ float currentSubPosition = positionAt(m_min + ((i + 1) * subSegmentStep));
+ actualSubSegmentSteps[i] = currentSubPosition;
+ }
+
+ float firstPartialSegmentAdjustment = float(segmentStep) - m_gridPositions.at(1);
+ for (int i = 0; i < segmentCount; i++) {
+ for (int j = 0; j < subGridCount; j++) {
+ float position = m_gridPositions.at(i) + actualSubSegmentSteps.at(j);
+ if (!m_evenMinSegment && i == 0)
+ position -= firstPartialSegmentAdjustment;
+ if (position > 1.0f)
+ position = 1.0f;
+ if (position < 0.0f)
+ position = 0.0f;
+ m_subGridPositions[i * subGridCount + j] = position;
+ }
+ }
+ }
+}
+
+void QLogValue3DAxisFormatterPrivate::populateCopy(QValue3DAxisFormatter &copy) const
+{
+ QLogValue3DAxisFormatter *logFormatter = static_cast<QLogValue3DAxisFormatter *>(&copy);
+ QLogValue3DAxisFormatterPrivate *priv = logFormatter->dptr();
+
+ priv->m_base = m_base;
+ priv->m_logMin = m_logMin;
+ priv->m_logMax = m_logMax;
+ priv->m_logRangeNormalizer = m_logRangeNormalizer;
+}
+
+float QLogValue3DAxisFormatterPrivate::positionAt(float value) const
+{
+ qreal logValue = qLn(qreal(value));
+ float retval = float((logValue - m_logMin) / m_logRangeNormalizer);
+
+ return retval;
+}
+
+float QLogValue3DAxisFormatterPrivate::valueAt(float position) const
+{
+ qreal logValue = (qreal(position) * m_logRangeNormalizer) + m_logMin;
+ return float(qExp(logValue));
+}
+
+QLogValue3DAxisFormatter *QLogValue3DAxisFormatterPrivate::qptr()
+{
+ return static_cast<QLogValue3DAxisFormatter *>(q_ptr);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter.h b/src/datavisualization/axis/qlogvalue3daxisformatter.h
new file mode 100644
index 00000000..62714a7d
--- /dev/null
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef QLOGVALUE3DAXISFORMATTER_H
+#define QLOGVALUE3DAXISFORMATTER_H
+
+#include <QtDataVisualization/qvalue3daxisformatter.h>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QLogValue3DAxisFormatterPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QLogValue3DAxisFormatter : public QValue3DAxisFormatter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal base READ base WRITE setBase NOTIFY baseChanged)
+ Q_PROPERTY(bool autoSubGrid READ autoSubGrid WRITE setAutoSubGrid NOTIFY autoSubGridChanged)
+ Q_PROPERTY(bool showEdgeLabels READ showEdgeLabels WRITE setShowEdgeLabels NOTIFY showEdgeLabelsChanged)
+
+protected:
+ explicit QLogValue3DAxisFormatter(QLogValue3DAxisFormatterPrivate *d, QObject *parent = 0);
+public:
+ explicit QLogValue3DAxisFormatter(QObject *parent = 0);
+ virtual ~QLogValue3DAxisFormatter();
+
+ void setBase(qreal base);
+ qreal base() const;
+ void setAutoSubGrid(bool enabled);
+ bool autoSubGrid() const;
+ void setShowEdgeLabels(bool enabled);
+ bool showEdgeLabels() const;
+
+signals:
+ void baseChanged(qreal base);
+ void autoSubGridChanged(bool enabled);
+ void showEdgeLabelsChanged(bool enabled);
+
+protected:
+ virtual QValue3DAxisFormatter *createNewInstance() const;
+ virtual void recalculate();
+ virtual float positionAt(float value) const;
+ virtual float valueAt(float position) const;
+ virtual void populateCopy(QValue3DAxisFormatter &copy) const;
+
+ QLogValue3DAxisFormatterPrivate *dptr();
+ const QLogValue3DAxisFormatterPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QLogValue3DAxisFormatter)
+
+ friend class QLogValue3DAxisFormatterPrivate;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/axis/qlogvalue3daxisformatter_p.h b/src/datavisualization/axis/qlogvalue3daxisformatter_p.h
new file mode 100644
index 00000000..df2d41d1
--- /dev/null
+++ b/src/datavisualization/axis/qlogvalue3daxisformatter_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QLOGVALUE3DAXISFORMATTER_P_H
+#define QLOGVALUE3DAXISFORMATTER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "qlogvalue3daxisformatter.h"
+#include "qvalue3daxisformatter_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QLogValue3DAxisFormatterPrivate : public QValue3DAxisFormatterPrivate
+{
+ Q_OBJECT
+
+public:
+ QLogValue3DAxisFormatterPrivate(QLogValue3DAxisFormatter *q);
+ virtual ~QLogValue3DAxisFormatterPrivate();
+
+ void recalculate();
+ void populateCopy(QValue3DAxisFormatter &copy) const;
+
+ float positionAt(float value) const;
+ float valueAt(float position) const;
+
+protected:
+ QLogValue3DAxisFormatter *qptr();
+
+ qreal m_base;
+ qreal m_logMin;
+ qreal m_logMax;
+ qreal m_logRangeNormalizer;
+ bool m_autoSubGrid;
+ bool m_showEdgeLabels;
+
+private:
+ bool m_evenMinSegment;
+ bool m_evenMaxSegment;
+
+ friend class QLogValue3DAxisFormatter;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/axis/qvalue3daxis.cpp b/src/datavisualization/axis/qvalue3daxis.cpp
index 0d53291d..8207174f 100644
--- a/src/datavisualization/axis/qvalue3daxis.cpp
+++ b/src/datavisualization/axis/qvalue3daxis.cpp
@@ -16,9 +16,8 @@
**
****************************************************************************/
-#include "qvalue3daxis.h"
#include "qvalue3daxis_p.h"
-#include "utils_p.h"
+#include "qvalue3daxisformatter_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QValue3DAxis
* \inmodule QtDataVisualization
* \brief The QValue3DAxis class is used for manipulating an axis of a graph.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QValue3DAxis provides an axis that can be given a range of values and segment and subsegment
* counts to divide the range into.
@@ -74,11 +73,30 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ * \qmlproperty ValueAxis3DFormatter ValueAxis3D::formatter
+ * \since QtDataVisualization 1.1
+ *
+ * Defines the axis \a formatter to be used. Any existing formatter is deleted when a new formatter
+ * is set.
+ *
+ */
+
+/*!
+ * \qmlproperty bool ValueAxis3D::reversed
+ * \since QtDataVisualization 1.1
+ *
+ * If \c{true}, the axis will be rendered in reverse, i.e. the positions of minimum and maximum
+ * values are swapped when the graph is rendered. This property doesn't affect the actual
+ * minimum and maximum values of the axis.
+ */
+
+/*!
* Constructs QValue3DAxis with the given \a parent.
*/
QValue3DAxis::QValue3DAxis(QObject *parent) :
QAbstract3DAxis(new QValue3DAxisPrivate(this), parent)
{
+ setFormatter(new QValue3DAxisFormatter);
}
/*!
@@ -88,7 +106,6 @@ QValue3DAxis::~QValue3DAxis()
{
}
-
/*!
* \property QValue3DAxis::segmentCount
*
@@ -105,7 +122,7 @@ void QValue3DAxis::setSegmentCount(int count)
<< count << "-> 1";
count = 1;
}
- if (dptr()->m_segmentCount != count){
+ if (dptr()->m_segmentCount != count) {
dptr()->m_segmentCount = count;
dptr()->emitLabelsChanged();
emit segmentCountChanged(count);
@@ -169,6 +186,53 @@ QString QValue3DAxis::labelFormat() const
}
/*!
+ * \property QValue3DAxis::formatter
+ * \since QtDataVisualization 1.1
+ *
+ * Defines the axis \a formatter to be used. Any existing formatter is deleted when a new formatter
+ * is set.
+ */
+void QValue3DAxis::setFormatter(QValue3DAxisFormatter *formatter)
+{
+ Q_ASSERT(formatter);
+
+ if (formatter != dptr()->m_formatter) {
+ delete dptr()->m_formatter;
+ dptr()->m_formatter = formatter;
+ formatter->setParent(this);
+ formatter->d_ptr->setAxis(this);
+ emit formatterChanged(formatter);
+ emit dptr()->formatterDirty();
+ }
+}
+
+QValue3DAxisFormatter *QValue3DAxis::formatter() const
+{
+ return dptrc()->m_formatter;
+}
+
+/*!
+ * \property QValue3DAxis::reversed
+ * \since QtDataVisualization 1.1
+ *
+ * If \c{true}, the axis will be rendered in reverse, i.e. the positions of minimum and maximum
+ * values are swapped when the graph is rendered. This property doesn't affect the actual
+ * minimum and maximum values of the axis.
+ */
+void QValue3DAxis::setReversed(bool enable)
+{
+ if (dptr()->m_reversed != enable) {
+ dptr()->m_reversed = enable;
+ emit reversedChanged(enable);
+ }
+}
+
+bool QValue3DAxis::reversed() const
+{
+ return dptrc()->m_reversed;
+}
+
+/*!
* \internal
*/
QValue3DAxisPrivate *QValue3DAxis::dptr()
@@ -189,7 +253,9 @@ QValue3DAxisPrivate::QValue3DAxisPrivate(QValue3DAxis *q)
m_segmentCount(5),
m_subSegmentCount(1),
m_labelFormat(Utils::defaultLabelFormat()),
- m_labelsDirty(true)
+ m_labelsDirty(true),
+ m_formatter(0),
+ m_reversed(false)
{
}
@@ -197,11 +263,11 @@ QValue3DAxisPrivate::~QValue3DAxisPrivate()
{
}
-void QValue3DAxisPrivate::setRange(float min, float max)
+void QValue3DAxisPrivate::setRange(float min, float max, bool suppressWarnings)
{
bool dirty = (min != m_min || max != m_max);
- QAbstract3DAxisPrivate::setRange(min, max);
+ QAbstract3DAxisPrivate::setRange(min, max, suppressWarnings);
if (dirty)
emitLabelsChanged();
@@ -240,26 +306,24 @@ void QValue3DAxisPrivate::updateLabels()
m_labelsDirty = false;
- QStringList newLabels;
- newLabels.reserve(m_segmentCount + 1);
-
- // First label is at axis min, which is an extra segment
- float segmentStep = (m_max - m_min) / m_segmentCount;
+ m_formatter->d_ptr->recalculate();
- QString formatString(m_labelFormat);
- Utils::ParamType paramType = Utils::findFormatParamType(formatString);
- QByteArray formatArray = formatString.toUtf8();
+ m_labels = m_formatter->labelStrings();
+}
- for (int i = 0; i < m_segmentCount; i++) {
- float value = m_min + (segmentStep * i);
- newLabels.append(Utils::formatLabel(formatArray, paramType, value));
- }
+bool QValue3DAxisPrivate::allowZero()
+{
+ return m_formatter->allowZero();
+}
- // Ensure max label doesn't suffer from any rounding errors
- newLabels.append(Utils::formatLabel(formatArray, paramType, m_max));
+bool QValue3DAxisPrivate::allowNegatives()
+{
+ return m_formatter->allowNegatives();
+}
- if (m_labels != newLabels)
- m_labels = newLabels;
+bool QValue3DAxisPrivate::allowMinMaxSame()
+{
+ return false;
}
QValue3DAxis *QValue3DAxisPrivate::qptr()
diff --git a/src/datavisualization/axis/qvalue3daxis.h b/src/datavisualization/axis/qvalue3daxis.h
index f0af759b..f552269c 100644
--- a/src/datavisualization/axis/qvalue3daxis.h
+++ b/src/datavisualization/axis/qvalue3daxis.h
@@ -20,6 +20,7 @@
#define QVALUE3DAXIS_H
#include <QtDataVisualization/qabstract3daxis.h>
+#include <QtDataVisualization/qvalue3daxisformatter.h>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -31,6 +32,8 @@ class QT_DATAVISUALIZATION_EXPORT QValue3DAxis : public QAbstract3DAxis
Q_PROPERTY(int segmentCount READ segmentCount WRITE setSegmentCount NOTIFY segmentCountChanged)
Q_PROPERTY(int subSegmentCount READ subSegmentCount WRITE setSubSegmentCount NOTIFY subSegmentCountChanged)
Q_PROPERTY(QString labelFormat READ labelFormat WRITE setLabelFormat NOTIFY labelFormatChanged)
+ Q_PROPERTY(QValue3DAxisFormatter* formatter READ formatter WRITE setFormatter NOTIFY formatterChanged REVISION 1)
+ Q_PROPERTY(bool reversed READ reversed WRITE setReversed NOTIFY reversedChanged REVISION 1)
public:
explicit QValue3DAxis(QObject *parent = 0);
@@ -45,10 +48,18 @@ public:
void setLabelFormat(const QString &format);
QString labelFormat() const;
+ void setFormatter(QValue3DAxisFormatter *formatter);
+ QValue3DAxisFormatter *formatter() const;
+
+ void setReversed(bool enable);
+ bool reversed() const;
+
signals:
void segmentCountChanged(int count);
void subSegmentCountChanged(int count);
void labelFormatChanged(const QString &format);
+ Q_REVISION(1) void formatterChanged(QValue3DAxisFormatter *formatter);
+ Q_REVISION(1) void reversedChanged(bool enable);
protected:
QValue3DAxisPrivate *dptr();
@@ -56,9 +67,11 @@ protected:
private:
Q_DISABLE_COPY(QValue3DAxis)
+ friend class Abstract3DController;
friend class Bars3DController;
friend class Scatter3DController;
friend class Surface3DController;
+ friend class QValue3DAxisFormatterPrivate;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/axis/qvalue3daxis_p.h b/src/datavisualization/axis/qvalue3daxis_p.h
index 21fd78ab..b7394c0a 100644
--- a/src/datavisualization/axis/qvalue3daxis_p.h
+++ b/src/datavisualization/axis/qvalue3daxis_p.h
@@ -26,12 +26,12 @@
//
// We mean it.
-#include "qvalue3daxis.h"
-#include "qabstract3daxis_p.h"
-
#ifndef QVALUE3DAXIS_P_H
#define QVALUE3DAXIS_P_H
+#include "qvalue3daxis.h"
+#include "qabstract3daxis_p.h"
+
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QValue3DAxisPrivate : public QAbstract3DAxisPrivate
@@ -42,23 +42,34 @@ public:
QValue3DAxisPrivate(QValue3DAxis *q);
virtual ~QValue3DAxisPrivate();
- virtual void setRange(float min, float max);
+ virtual void setRange(float min, float max, bool suppressWarnings = false);
virtual void setMin(float min);
virtual void setMax (float max);
-protected:
void emitLabelsChanged();
+
+signals:
+ void formatterDirty();
+
+protected:
virtual void updateLabels();
+ virtual bool allowZero();
+ virtual bool allowNegatives();
+ virtual bool allowMinMaxSame();
+
int m_segmentCount;
int m_subSegmentCount;
QString m_labelFormat;
bool m_labelsDirty;
+ QValue3DAxisFormatter *m_formatter;
+ bool m_reversed;
private:
QValue3DAxis *qptr();
friend class QValue3DAxis;
+ friend class Abstract3DController;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/axis/qvalue3daxisformatter.cpp b/src/datavisualization/axis/qvalue3daxisformatter.cpp
new file mode 100644
index 00000000..56ca3b0f
--- /dev/null
+++ b/src/datavisualization/axis/qvalue3daxisformatter.cpp
@@ -0,0 +1,419 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qvalue3daxisformatter_p.h"
+#include "qvalue3daxis_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QValue3DAxisFormatter
+ * \inmodule QtDataVisualization
+ * \brief QValue3DAxisFormatter is base class for value axis formatters.
+ * \since QtDataVisualization 1.1
+ *
+ * This class provides formatting rules for a linear QValue3DAxis. Subclass it if you
+ * want to implement custom value axes.
+ *
+ * The base class has no public API beyond constructors and destructors. It is meant to be only
+ * used internally. However, subclasses may implement public properties as needed.
+ *
+ * \sa QLogValue3DAxisFormatter
+ */
+
+/*!
+ * \qmltype ValueAxis3DFormatter
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.1
+ * \ingroup datavisualization_qml
+ * \instantiates QValue3DAxisFormatter
+ * \brief ValueAxis3DFormatter is base type for value axis formatters.
+ *
+ * This type provides formatting rules for a linear ValueAxis3D.
+ * This type is the default type for ValueAxis3D and thus never needs to be explicitly created.
+ * This type has not public functionality.
+ */
+
+/*!
+ * \internal
+ */
+QValue3DAxisFormatter::QValue3DAxisFormatter(QValue3DAxisFormatterPrivate *d, QObject *parent) :
+ QObject(parent),
+ d_ptr(d)
+{
+}
+
+/*!
+ * Constructs a new QValue3DAxisFormatter instance with an optional \a parent.
+ */
+QValue3DAxisFormatter::QValue3DAxisFormatter(QObject *parent) :
+ QObject(parent),
+ d_ptr(new QValue3DAxisFormatterPrivate(this))
+{
+}
+
+/*!
+ * Destroys QValue3DAxisFormatter.
+ */
+QValue3DAxisFormatter::~QValue3DAxisFormatter()
+{
+}
+
+/*!
+ * Allow the parent axis to have negative values if \a allow is true.
+ */
+void QValue3DAxisFormatter::setAllowNegatives(bool allow)
+{
+ d_ptr->m_allowNegatives = allow;
+}
+
+/*!
+ * \return \c true if negative values are valid values for parent axis.
+ * The default implementation always returns true.
+ */
+bool QValue3DAxisFormatter::allowNegatives() const
+{
+ return d_ptr->m_allowNegatives;
+}
+
+/*!
+ * Allow the parent axis to have zero value if \a allow is true.
+ */
+void QValue3DAxisFormatter::setAllowZero(bool allow)
+{
+ d_ptr->m_allowZero = allow;
+}
+
+/*!
+ * \return \c true if zero is a valid value for parent axis.
+ * The default implementation always returns true.
+ */
+bool QValue3DAxisFormatter::allowZero() const
+{
+ return d_ptr->m_allowZero;
+}
+
+/*!
+ * Creates a new empty instance of this formatter. Must be reimplemented in a subclass.
+ *
+ * \return the new instance. The renderer uses this method to cache a copy of the
+ * the formatter. The ownership of the new copy transfers to the caller.
+ */
+QValue3DAxisFormatter *QValue3DAxisFormatter::createNewInstance() const
+{
+ return new QValue3DAxisFormatter();
+}
+
+/*!
+ * This method resizes and populates the label and grid line position arrays and the label strings
+ * array, as well as calculates any values needed for mapping between value and position.
+ * It is allowed to access the parent axis from inside this function.
+ *
+ * This method must be reimplemented in a subclass if the default array contents are not suitable.
+ *
+ * See gridPositions(), subGridPositions(), labelPositions(), and labelStrings() methods for
+ * documentation about the arrays that need to be resized and populated.
+ *
+ * \sa gridPositions(), subGridPositions(), labelPositions(), labelStrings(), axis()
+ */
+void QValue3DAxisFormatter::recalculate()
+{
+ d_ptr->doRecalculate();
+}
+
+/*!
+ * This method is used to format a string using the specified value and the specified format.
+ * Reimplement this method in a subclass to resolve the formatted string for a given \a value
+ * if the default formatting rules specified for QValue3DAxis::labelFormat property are not
+ * sufficient.
+ *
+ * \return the formatted label string using a \a value and a \a format.
+ *
+ * \sa recalculate(), labelStrings(), QValue3DAxis::labelFormat
+ */
+QString QValue3DAxisFormatter::stringForValue(qreal value, const QString &format) const
+{
+ return d_ptr->stringForValue(value, format);
+}
+
+/*!
+ * Reimplement this method if the position cannot be resolved by linear interpolation
+ * between the parent axis minimum and maximum values.
+ *
+ * \return the normalized position along the axis for the given \a value.
+ * The returned value should be between 0.0 (for minimum value) and 1.0 (for maximum value),
+ * inclusive, if the value is within the parent axis range.
+ *
+ * \sa recalculate(), valueAt()
+ */
+float QValue3DAxisFormatter::positionAt(float value) const
+{
+ return d_ptr->positionAt(value);
+}
+
+/*!
+ * Reimplement this method if the value cannot be resolved by linear interpolation
+ * between the parent axis minimum and maximum values.
+ *
+ * \return the value at the normalized \a position along the axis.
+ * The \a position value should be between 0.0 (for minimum value) and 1.0 (for maximum value),
+ * inclusive to obtain values within the parent axis range.
+ *
+ * \sa recalculate(), positionAt()
+ */
+float QValue3DAxisFormatter::valueAt(float position) const
+{
+ return d_ptr->valueAt(position);
+}
+
+/*!
+ * Copies all necessary values for resolving positions, values, and strings with this formatter
+ * from this formatter to the \a copy.
+ * When reimplementing this method in a subclass, call the the superclass version at some point.
+ * The renderer uses this method to cache a copy of the the formatter.
+ *
+ * \return the new copy. The ownership of the new copy transfers to the caller.
+ */
+void QValue3DAxisFormatter::populateCopy(QValue3DAxisFormatter &copy) const
+{
+ d_ptr->doPopulateCopy(*(copy.d_ptr.data()));
+}
+
+/*!
+ * Marks this formatter dirty, prompting the renderer to make a new copy of its cache on the next
+ * renderer synchronization. This method should be called by a subclass whenever the formatter
+ * is changed in a way that affects the resolved values. Specify \c true for \a labelsChange
+ * parameter if the change was such that it requires regenerating the parent axis label strings.
+ */
+void QValue3DAxisFormatter::markDirty(bool labelsChange)
+{
+ d_ptr->markDirty(labelsChange);
+}
+
+/*!
+ * \return the parent axis. The parent axis must only be accessed in recalculate()
+ * method to maintain thread safety in environments using a threaded renderer.
+ *
+ * \sa recalculate()
+ */
+QValue3DAxis *QValue3DAxisFormatter::axis() const
+{
+ return d_ptr->m_axis;
+}
+
+/*!
+ * \return a reference to the array of normalized grid line positions.
+ * The default array size is equal to the segment count of the parent axis plus one, but
+ * a subclassed implementation of recalculate method may resize the array differently.
+ * The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive.
+ *
+ * \sa QValue3DAxis::segmentCount, recalculate()
+ */
+QVector<float> &QValue3DAxisFormatter::gridPositions() const
+{
+ return d_ptr->m_gridPositions;
+}
+
+/*!
+ * \return a reference to the array of normalized subgrid line positions.
+ * The default array size is equal to segment count of the parent axis times sub-segment count
+ * of the parent axis minus one, but a subclassed implementation of recalculate method may resize
+ * the array differently.
+ * The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive.
+ *
+ * \sa QValue3DAxis::segmentCount, QValue3DAxis::subSegmentCount, recalculate()
+ */
+QVector<float> &QValue3DAxisFormatter::subGridPositions() const
+{
+ return d_ptr->m_subGridPositions;
+}
+
+/*!
+ * \return a reference to the array of normalized label positions.
+ * The default array size is equal to the segment count of the parent axis plus one, but
+ * a subclassed implementation of recalculate method may resize the array differently.
+ * The values should be between 0.0 (for minimum value) and 1.0 (for maximum value), inclusive.
+ * The default behavior is that the label at the index zero corresponds to the minimum value
+ * of the axis.
+ *
+ * \sa QValue3DAxis::segmentCount, QAbstract3DAxis::labels, recalculate()
+ */
+QVector<float> &QValue3DAxisFormatter::labelPositions() const
+{
+ return d_ptr->m_labelPositions;
+}
+
+/*!
+ * \return a reference to the string list containing formatter label strings.
+ * The array size must be equal to the size of the label positions array and
+ * the indexes correspond to that array as well.
+ *
+ * \sa labelPositions()
+ */
+QStringList &QValue3DAxisFormatter::labelStrings() const
+{
+ return d_ptr->m_labelStrings;
+}
+
+// QValue3DAxisFormatterPrivate
+QValue3DAxisFormatterPrivate::QValue3DAxisFormatterPrivate(QValue3DAxisFormatter *q)
+ : QObject(0),
+ q_ptr(q),
+ m_needsRecalculate(true),
+ m_min(0.0f),
+ m_max(0.0f),
+ m_rangeNormalizer(0.0f),
+ m_axis(0),
+ m_preparsedParamType(Utils::ParamTypeUnknown),
+ m_allowNegatives(true),
+ m_allowZero(true)
+{
+}
+
+QValue3DAxisFormatterPrivate::~QValue3DAxisFormatterPrivate()
+{
+}
+
+void QValue3DAxisFormatterPrivate::recalculate()
+{
+ // Only recalculate if we need to and have m_axis pointer. If we do not have
+ // m_axis, either we are not attached to an axis or this is a renderer cache.
+ if (m_axis && m_needsRecalculate) {
+ m_min = m_axis->min();
+ m_max = m_axis->max();
+ m_rangeNormalizer = (m_max - m_min);
+
+ q_ptr->recalculate();
+ m_needsRecalculate = false;
+ }
+}
+
+void QValue3DAxisFormatterPrivate::doRecalculate()
+{
+ int segmentCount = m_axis->segmentCount();
+ int subGridCount = m_axis->subSegmentCount() - 1;
+ QString labelFormat = m_axis->labelFormat();
+
+ m_gridPositions.resize(segmentCount + 1);
+ m_subGridPositions.resize(segmentCount * subGridCount);
+
+ m_labelPositions.resize(segmentCount + 1);
+ m_labelStrings.clear();
+ m_labelStrings.reserve(segmentCount + 1);
+
+ // Use qreals for intermediate calculations for better accuracy on label values
+ qreal segmentStep = 1.0 / qreal(segmentCount);
+ qreal subSegmentStep = 0;
+ if (subGridCount > 0)
+ subSegmentStep = segmentStep / qreal(subGridCount + 1);
+
+ // Calculate positions
+ qreal rangeNormalizer = qreal(m_max - m_min);
+ for (int i = 0; i < segmentCount; i++) {
+ qreal gridValue = segmentStep * qreal(i);
+ m_gridPositions[i] = float(gridValue);
+ m_labelPositions[i] = float(gridValue);
+ m_labelStrings << q_ptr->stringForValue(gridValue * rangeNormalizer + qreal(m_min),
+ labelFormat);
+ if (m_subGridPositions.size()) {
+ for (int j = 0; j < subGridCount; j++)
+ m_subGridPositions[i * subGridCount + j] = gridValue + subSegmentStep * (j + 1);
+ }
+ }
+
+ // Ensure max value doesn't suffer from any rounding errors
+ m_gridPositions[segmentCount] = 1.0f;
+ m_labelPositions[segmentCount] = 1.0f;
+ m_labelStrings << q_ptr->stringForValue(qreal(m_max), labelFormat);
+}
+
+void QValue3DAxisFormatterPrivate::populateCopy(QValue3DAxisFormatter &copy)
+{
+ recalculate();
+ q_ptr->populateCopy(copy);
+}
+
+void QValue3DAxisFormatterPrivate::doPopulateCopy(QValue3DAxisFormatterPrivate &copy)
+{
+ copy.m_min = m_min;
+ copy.m_max = m_max;
+ copy.m_rangeNormalizer = m_rangeNormalizer;
+
+ copy.m_gridPositions = m_gridPositions;
+ copy.m_labelPositions = m_labelPositions;
+ copy.m_subGridPositions = m_subGridPositions;
+}
+
+QString QValue3DAxisFormatterPrivate::stringForValue(qreal value, const QString &format)
+{
+ if (m_previousLabelFormat.compare(format)) {
+ // Format string different than the previous one used, reparse it
+ m_previousLabelFormat = format;
+ m_preparsedParamType = Utils::findFormatParamType(format);
+ m_labelFormatArray = format.toUtf8();
+ }
+
+ return Utils::formatLabel(m_labelFormatArray, m_preparsedParamType, value);
+}
+
+float QValue3DAxisFormatterPrivate::positionAt(float value) const
+{
+ return ((value - m_min) / m_rangeNormalizer);
+}
+
+float QValue3DAxisFormatterPrivate::valueAt(float position) const
+{
+ return ((position * m_rangeNormalizer) + m_min);
+}
+
+void QValue3DAxisFormatterPrivate::setAxis(QValue3DAxis *axis)
+{
+ Q_ASSERT(axis);
+
+ // These signals are all connected to markDirtyNoLabelChange slot, even though most of them
+ // do require labels to be regenerated. This is because the label regeneration is triggered
+ // elsewhere in these cases.
+ connect(axis, &QValue3DAxis::segmentCountChanged,
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
+ connect(axis, &QValue3DAxis::subSegmentCountChanged,
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
+ connect(axis, &QValue3DAxis::labelFormatChanged,
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
+ connect(axis, &QAbstract3DAxis::rangeChanged,
+ this, &QValue3DAxisFormatterPrivate::markDirtyNoLabelChange);
+
+ m_axis = axis;
+}
+
+void QValue3DAxisFormatterPrivate::markDirty(bool labelsChange)
+{
+ m_needsRecalculate = true;
+ if (m_axis) {
+ if (labelsChange)
+ m_axis->dptr()->emitLabelsChanged();
+ if (m_axis && m_axis->orientation() != QAbstract3DAxis::AxisOrientationNone)
+ emit m_axis->dptr()->formatterDirty();
+ }
+}
+
+void QValue3DAxisFormatterPrivate::markDirtyNoLabelChange()
+{
+ markDirty(false);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/axis/qvalue3daxisformatter.h b/src/datavisualization/axis/qvalue3daxisformatter.h
new file mode 100644
index 00000000..c7b0bac5
--- /dev/null
+++ b/src/datavisualization/axis/qvalue3daxisformatter.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef QVALUE3DAXISFORMATTER_H
+#define QVALUE3DAXISFORMATTER_H
+
+#include <QtDataVisualization/qdatavisualizationglobal.h>
+#include <QtCore/QObject>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QVector>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QValue3DAxisFormatterPrivate;
+class QValue3DAxis;
+
+class QT_DATAVISUALIZATION_EXPORT QValue3DAxisFormatter : public QObject
+{
+ Q_OBJECT
+protected:
+ explicit QValue3DAxisFormatter(QValue3DAxisFormatterPrivate *d, QObject *parent = 0);
+public:
+ explicit QValue3DAxisFormatter(QObject *parent = 0);
+ virtual ~QValue3DAxisFormatter();
+
+protected:
+ void setAllowNegatives(bool allow);
+ bool allowNegatives() const;
+ void setAllowZero(bool allow);
+ bool allowZero() const;
+
+ virtual QValue3DAxisFormatter *createNewInstance() const;
+ virtual void recalculate();
+ virtual QString stringForValue(qreal value, const QString &format) const;
+ virtual float positionAt(float value) const;
+ virtual float valueAt(float position) const;
+ virtual void populateCopy(QValue3DAxisFormatter &copy) const;
+
+ void markDirty(bool labelsChange = false);
+ QValue3DAxis *axis() const;
+
+ QVector<float> &gridPositions() const;
+ QVector<float> &subGridPositions() const;
+ QVector<float> &labelPositions() const;
+ QStringList &labelStrings() const;
+
+ QScopedPointer<QValue3DAxisFormatterPrivate> d_ptr;
+
+private:
+ Q_DISABLE_COPY(QValue3DAxisFormatter)
+
+ friend class Abstract3DController;
+ friend class Abstract3DRenderer;
+ friend class Bars3DRenderer;
+ friend class Scatter3DRenderer;
+ friend class Surface3DRenderer;
+ friend class SurfaceObject;
+ friend class QValue3DAxisFormatterPrivate;
+ friend class QLogValue3DAxisFormatter;
+ friend class QValue3DAxis;
+ friend class QValue3DAxisPrivate;
+ friend class AxisRenderCache;
+ friend class QBar3DSeriesPrivate;
+ friend class QScatter3DSeriesPrivate;
+ friend class QSurface3DSeriesPrivate;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/axis/qvalue3daxisformatter_p.h b/src/datavisualization/axis/qvalue3daxisformatter_p.h
new file mode 100644
index 00000000..2d1dc920
--- /dev/null
+++ b/src/datavisualization/axis/qvalue3daxisformatter_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QVALUE3DAXISFORMATTER_P_H
+#define QVALUE3DAXISFORMATTER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "qvalue3daxisformatter.h"
+#include "utils_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QValue3DAxis;
+
+class QValue3DAxisFormatterPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QValue3DAxisFormatterPrivate(QValue3DAxisFormatter *q);
+ virtual ~QValue3DAxisFormatterPrivate();
+
+ void recalculate();
+ void doRecalculate();
+ void populateCopy(QValue3DAxisFormatter &copy);
+ void doPopulateCopy(QValue3DAxisFormatterPrivate &copy);
+
+ QString stringForValue(qreal value, const QString &format);
+ float positionAt(float value) const;
+ float valueAt(float position) const;
+
+ void setAxis(QValue3DAxis *axis);
+ void markDirty(bool labelsChange);
+
+public slots:
+ void markDirtyNoLabelChange();
+
+protected:
+ QValue3DAxisFormatter *q_ptr;
+
+ bool m_needsRecalculate;
+
+ float m_min;
+ float m_max;
+ float m_rangeNormalizer;
+
+ QVector<float> m_gridPositions;
+ QVector<float> m_subGridPositions;
+ QVector<float> m_labelPositions;
+ QStringList m_labelStrings;
+
+ QValue3DAxis *m_axis;
+
+ QString m_previousLabelFormat;
+ QByteArray m_labelFormatArray;
+ Utils::ParamType m_preparsedParamType;
+
+ bool m_allowNegatives;
+ bool m_allowZero;
+
+ friend class QValue3DAxisFormatter;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/common.pri b/src/datavisualization/common.pri
index 4ffa5646..9a497c2c 100644
--- a/src/datavisualization/common.pri
+++ b/src/datavisualization/common.pri
@@ -1,6 +1,3 @@
-# This qmake file is included by all Patternist projects and contains common Qt defines,
-# compiler warnings, and include paths.
-
INCLUDEPATH += $$PWD/engine \
$$PWD/global \
$$PWD/utils \
diff --git a/src/datavisualization/data/abstractitemmodelhandler.cpp b/src/datavisualization/data/abstractitemmodelhandler.cpp
index 9f2ccd86..f8ddf7b7 100644
--- a/src/datavisualization/data/abstractitemmodelhandler.cpp
+++ b/src/datavisualization/data/abstractitemmodelhandler.cpp
@@ -34,7 +34,7 @@ AbstractItemModelHandler::~AbstractItemModelHandler()
{
}
-void AbstractItemModelHandler::setItemModel(const QAbstractItemModel *itemModel)
+void AbstractItemModelHandler::setItemModel(QAbstractItemModel *itemModel)
{
if (itemModel != m_itemModel.data()) {
if (!m_itemModel.isNull())
@@ -69,7 +69,7 @@ void AbstractItemModelHandler::setItemModel(const QAbstractItemModel *itemModel)
}
}
-const QAbstractItemModel *AbstractItemModelHandler::itemModel() const
+QAbstractItemModel *AbstractItemModelHandler::itemModel() const
{
return m_itemModel.data();
}
diff --git a/src/datavisualization/data/abstractitemmodelhandler_p.h b/src/datavisualization/data/abstractitemmodelhandler_p.h
index ecbfe61c..e11d229a 100644
--- a/src/datavisualization/data/abstractitemmodelhandler_p.h
+++ b/src/datavisualization/data/abstractitemmodelhandler_p.h
@@ -43,8 +43,8 @@ public:
AbstractItemModelHandler(QObject *parent = 0);
virtual ~AbstractItemModelHandler();
- virtual void setItemModel(const QAbstractItemModel *itemModel);
- virtual const QAbstractItemModel *itemModel() const;
+ virtual void setItemModel(QAbstractItemModel *itemModel);
+ virtual QAbstractItemModel *itemModel() const;
public slots:
virtual void handleColumnsInserted(const QModelIndex &parent, int start, int end);
@@ -71,7 +71,7 @@ signals:
protected:
virtual void resolveModel() = 0;
- QPointer<const QAbstractItemModel> m_itemModel; // Not owned
+ QPointer<QAbstractItemModel> m_itemModel; // Not owned
bool resolvePending;
QTimer m_resolveTimer;
bool m_fullReset;
diff --git a/src/datavisualization/data/abstractrenderitem_p.h b/src/datavisualization/data/abstractrenderitem_p.h
index 912a09f3..57977a3c 100644
--- a/src/datavisualization/data/abstractrenderitem_p.h
+++ b/src/datavisualization/data/abstractrenderitem_p.h
@@ -32,8 +32,6 @@
#include "datavisualizationglobal_p.h"
#include "labelitem_p.h"
-#include <QtCore/QString>
-#include <QtGui/QOpenGLFunctions>
#include <QtGui/QVector3D>
#include <QtGui/QQuaternion>
diff --git a/src/datavisualization/data/baritemmodelhandler.cpp b/src/datavisualization/data/baritemmodelhandler.cpp
index 4f44fe1d..62e6390d 100644
--- a/src/datavisualization/data/baritemmodelhandler.cpp
+++ b/src/datavisualization/data/baritemmodelhandler.cpp
@@ -26,7 +26,11 @@ BarItemModelHandler::BarItemModelHandler(QItemModelBarDataProxy *proxy, QObject
: AbstractItemModelHandler(parent),
m_proxy(proxy),
m_proxyArray(0),
- m_columnCount(0)
+ m_columnCount(0),
+ m_valueRole(noRoleIndex),
+ m_rotationRole(noRoleIndex),
+ m_haveValuePattern(false),
+ m_haveRotationPattern(false)
{
}
@@ -34,6 +38,50 @@ BarItemModelHandler::~BarItemModelHandler()
{
}
+void BarItemModelHandler::handleDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QVector<int> &roles)
+{
+ // Do nothing if full reset already pending
+ if (!m_fullReset) {
+ if (!m_proxy->useModelCategories()) {
+ // If the data model doesn't directly map rows and columns, we cannot optimize
+ AbstractItemModelHandler::handleDataChanged(topLeft, bottomRight, roles);
+ } else {
+ int startRow = qMin(topLeft.row(), bottomRight.row());
+ int endRow = qMax(topLeft.row(), bottomRight.row());
+ int startCol = qMin(topLeft.column(), bottomRight.column());
+ int endCol = qMax(topLeft.column(), bottomRight.column());
+
+ for (int i = startRow; i <= endRow; i++) {
+ for (int j = startCol; j <= endCol; j++) {
+ QModelIndex index = m_itemModel->index(i, j);
+ QBarDataItem item;
+ QVariant valueVar = index.data(m_valueRole);
+ float value;
+ if (m_haveValuePattern)
+ value = valueVar.toString().replace(m_valuePattern, m_valueReplace).toFloat();
+ else
+ value = valueVar.toFloat();
+ item.setValue(value);
+ if (m_rotationRole != noRoleIndex) {
+ QVariant rotationVar = index.data(m_rotationRole);
+ float rotation;
+ if (m_haveRotationPattern) {
+ rotation = rotationVar.toString().replace(m_rotationPattern,
+ m_rotationReplace).toFloat();
+ } else {
+ rotation = rotationVar.toFloat();
+ }
+ item.setRotation(rotation);
+ }
+ m_proxy->setItem(i, j, item);
+ }
+ }
+ }
+ }
+}
+
// Resolve entire item model into QBarDataArray.
void BarItemModelHandler::resolveModel()
{
@@ -48,14 +96,29 @@ void BarItemModelHandler::resolveModel()
return;
}
+ // Value and rotation patterns can be reused on single item changes,
+ // so store them to member variables.
+ QRegExp rowPattern(m_proxy->rowRolePattern());
+ QRegExp colPattern(m_proxy->columnRolePattern());
+ m_valuePattern = m_proxy->valueRolePattern();
+ m_rotationPattern = m_proxy->rotationRolePattern();
+ QString rowReplace = m_proxy->rowRoleReplace();
+ QString colReplace = m_proxy->columnRoleReplace();
+ m_valueReplace = m_proxy->valueRoleReplace();
+ m_rotationReplace = m_proxy->rotationRoleReplace();
+ bool haveRowPattern = !rowPattern.isEmpty() && rowPattern.isValid();
+ bool haveColPattern = !colPattern.isEmpty() && colPattern.isValid();
+ m_haveValuePattern = !m_valuePattern.isEmpty() && m_valuePattern.isValid();
+ m_haveRotationPattern = !m_rotationPattern.isEmpty() && m_rotationPattern.isValid();
+
QStringList rowLabels;
QStringList columnLabels;
QHash<int, QByteArray> roleHash = m_itemModel->roleNames();
// Default value role to display role if no mapping
- int valueRole = roleHash.key(m_proxy->valueRole().toLatin1(), Qt::DisplayRole);
- int rotationRole = roleHash.key(m_proxy->rotationRole().toLatin1(), noRoleIndex);
+ m_valueRole = roleHash.key(m_proxy->valueRole().toLatin1(), Qt::DisplayRole);
+ m_rotationRole = roleHash.key(m_proxy->rotationRole().toLatin1(), noRoleIndex);
int rowCount = m_itemModel->rowCount();
int columnCount = m_itemModel->columnCount();
@@ -71,9 +134,25 @@ void BarItemModelHandler::resolveModel()
for (int i = 0; i < rowCount; i++) {
QBarDataRow &newProxyRow = *m_proxyArray->at(i);
for (int j = 0; j < columnCount; j++) {
- newProxyRow[j].setValue(m_itemModel->index(i, j).data(valueRole).toReal());
- if (rotationRole != noRoleIndex)
- newProxyRow[j].setRotation(m_itemModel->index(i, j).data(rotationRole).toReal());
+ QModelIndex index = m_itemModel->index(i, j);
+ QVariant valueVar = index.data(m_valueRole);
+ float value;
+ if (m_haveValuePattern)
+ value = valueVar.toString().replace(m_valuePattern, m_valueReplace).toFloat();
+ else
+ value = valueVar.toFloat();
+ newProxyRow[j].setValue(value);
+ if (m_rotationRole != noRoleIndex) {
+ QVariant rotationVar = index.data(m_rotationRole);
+ float rotation;
+ if (m_haveRotationPattern) {
+ rotation = rotationVar.toString().replace(m_rotationPattern,
+ m_rotationReplace).toFloat();
+ } else {
+ rotation = rotationVar.toFloat();
+ }
+ newProxyRow[j].setRotation(rotation);
+ }
}
}
// Generate labels from headers if using model rows/columns
@@ -97,16 +176,62 @@ void BarItemModelHandler::resolveModel()
// Sort values into rows and columns
typedef QHash<QString, float> ColumnValueMap;
- QHash <QString, ColumnValueMap> itemValueMap;
- QHash <QString, ColumnValueMap> itemRotationMap;
+ QHash<QString, ColumnValueMap> itemValueMap;
+ QHash<QString, ColumnValueMap> itemRotationMap;
+
+ bool cumulative = m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBAverage
+ || m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBCumulative;
+ bool countMatches = m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBAverage;
+ bool takeFirst = m_proxy->multiMatchBehavior() == QItemModelBarDataProxy::MMBFirst;
+ QHash<QString, QHash<QString, int> > *matchCountMap = 0;
+ if (countMatches)
+ matchCountMap = new QHash<QString, QHash<QString, int> >;
+
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < columnCount; j++) {
QModelIndex index = m_itemModel->index(i, j);
QString rowRoleStr = index.data(rowRole).toString();
+ if (haveRowPattern)
+ rowRoleStr.replace(rowPattern, rowReplace);
QString columnRoleStr = index.data(columnRole).toString();
- itemValueMap[rowRoleStr][columnRoleStr] = index.data(valueRole).toReal();
- if (rotationRole != noRoleIndex)
- itemRotationMap[rowRoleStr][columnRoleStr] = index.data(rotationRole).toReal();
+ if (haveColPattern)
+ columnRoleStr.replace(colPattern, colReplace);
+ QVariant valueVar = index.data(m_valueRole);
+ float value;
+ if (m_haveValuePattern)
+ value = valueVar.toString().replace(m_valuePattern, m_valueReplace).toFloat();
+ else
+ value = valueVar.toFloat();
+ if (countMatches)
+ (*matchCountMap)[rowRoleStr][columnRoleStr]++;
+
+ if (cumulative) {
+ itemValueMap[rowRoleStr][columnRoleStr] += value;
+ } else {
+ if (takeFirst && itemValueMap.contains(rowRoleStr)) {
+ if (itemValueMap.value(rowRoleStr).contains(columnRoleStr))
+ continue; // We already have a value for this row/column combo
+ }
+ itemValueMap[rowRoleStr][columnRoleStr] = value;
+ }
+
+ if (m_rotationRole != noRoleIndex) {
+ QVariant rotationVar = index.data(m_rotationRole);
+ float rotation;
+ if (m_haveRotationPattern) {
+ rotation = rotationVar.toString().replace(m_rotationPattern,
+ m_rotationReplace).toFloat();
+ } else {
+ rotation = rotationVar.toFloat();
+ }
+ if (cumulative) {
+ itemRotationMap[rowRoleStr][columnRoleStr] += rotation;
+ } else {
+ // We know we are in take last mode if we get here,
+ // as take first mode skips to next loop already earlier
+ itemRotationMap[rowRoleStr][columnRoleStr] = rotation;
+ }
+ }
if (generateRows && !rowListHash.value(rowRoleStr, false)) {
rowListHash.insert(rowRoleStr, true);
rowList << rowRoleStr;
@@ -141,15 +266,24 @@ void BarItemModelHandler::resolveModel()
QString rowKey = rowList.at(i);
QBarDataRow &newProxyRow = *m_proxyArray->at(i);
for (int j = 0; j < columnList.size(); j++) {
- newProxyRow[j].setValue(itemValueMap[rowKey][columnList.at(j)]);
- if (rotationRole != noRoleIndex)
- newProxyRow[j].setRotation(itemRotationMap[rowKey][columnList.at(j)]);
+ float value = itemValueMap[rowKey][columnList.at(j)];
+ if (countMatches)
+ value /= float((*matchCountMap)[rowKey][columnList.at(j)]);
+ newProxyRow[j].setValue(value);
+ if (m_rotationRole != noRoleIndex) {
+ float angle = itemRotationMap[rowKey][columnList.at(j)];
+ if (countMatches)
+ angle /= float((*matchCountMap)[rowKey][columnList.at(j)]);
+ newProxyRow[j].setRotation(angle);
+ }
}
}
rowLabels = rowList;
columnLabels = columnList;
m_columnCount = columnList.size();
+
+ delete matchCountMap;
}
m_proxy->resetArray(m_proxyArray, rowLabels, columnLabels);
diff --git a/src/datavisualization/data/baritemmodelhandler_p.h b/src/datavisualization/data/baritemmodelhandler_p.h
index 7bf7b0a1..6dea906e 100644
--- a/src/datavisualization/data/baritemmodelhandler_p.h
+++ b/src/datavisualization/data/baritemmodelhandler_p.h
@@ -41,12 +41,24 @@ public:
BarItemModelHandler(QItemModelBarDataProxy *proxy, QObject *parent = 0);
virtual ~BarItemModelHandler();
+public slots:
+ virtual void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QVector<int> &roles = QVector<int> ());
+
protected:
void virtual resolveModel();
QItemModelBarDataProxy *m_proxy; // Not owned
QBarDataArray *m_proxyArray; // Not owned
int m_columnCount;
+ int m_valueRole;
+ int m_rotationRole;
+ QRegExp m_valuePattern;
+ QRegExp m_rotationPattern;
+ QString m_valueReplace;
+ QString m_rotationReplace;
+ bool m_haveValuePattern;
+ bool m_haveRotationPattern;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/barrenderitem.cpp b/src/datavisualization/data/barrenderitem.cpp
index 50d2a4b4..eab5178b 100644
--- a/src/datavisualization/data/barrenderitem.cpp
+++ b/src/datavisualization/data/barrenderitem.cpp
@@ -17,15 +17,13 @@
****************************************************************************/
#include "barrenderitem_p.h"
-#include "bars3drenderer_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
BarRenderItem::BarRenderItem()
: AbstractRenderItem(),
m_value(0),
- m_height(0.0f),
- m_seriesIndex(0)
+ m_height(0.0f)
{
}
@@ -35,7 +33,6 @@ BarRenderItem::BarRenderItem(const BarRenderItem &other)
m_value = other.m_value;
m_position = other.m_position;
m_height = other.m_height;
- m_seriesIndex = other.m_seriesIndex;
}
BarRenderItem::~BarRenderItem()
@@ -67,8 +64,8 @@ void BarRenderSliceItem::setItem(const BarRenderItem &renderItem)
m_value = renderItem.value();
m_position = renderItem.position();
m_height = renderItem.height();
- m_seriesIndex = renderItem.seriesIndex();
m_sliceLabel = QString();
+ delete m_sliceLabelItem;
m_sliceLabelItem = 0;
}
diff --git a/src/datavisualization/data/barrenderitem_p.h b/src/datavisualization/data/barrenderitem_p.h
index 1122053d..72c5abc1 100644
--- a/src/datavisualization/data/barrenderitem_p.h
+++ b/src/datavisualization/data/barrenderitem_p.h
@@ -33,8 +33,6 @@
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-class Bars3DRenderer;
-
class BarRenderItem : public AbstractRenderItem
{
public:
@@ -54,16 +52,10 @@ public:
inline void setHeight(GLfloat height) { m_height = height; }
inline GLfloat height() const { return m_height; }
- // Series index in visual series that this item belongs to.
- // This is only utilized by slicing, so it may not be up to date on all items.
- inline void setSeriesIndex(int seriesIndex) { m_seriesIndex = seriesIndex; }
- inline int seriesIndex() const { return m_seriesIndex; }
-
protected:
float m_value;
QPoint m_position; // x = row, y = column
GLfloat m_height;
- int m_seriesIndex;
friend class QBarDataItem;
};
diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp
new file mode 100644
index 00000000..a1c70057
--- /dev/null
+++ b/src/datavisualization/data/customrenderitem.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "customrenderitem_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+CustomRenderItem::CustomRenderItem()
+ : AbstractRenderItem(),
+ m_texture(0),
+ m_object(0),
+ m_visible(true),
+ m_renderer(0)
+{
+}
+
+CustomRenderItem::~CustomRenderItem()
+{
+ ObjectHelper::releaseObjectHelper(m_renderer, m_object);
+}
+
+void CustomRenderItem::setMesh(const QString &meshFile)
+{
+ ObjectHelper::resetObjectHelper(m_renderer, m_object, meshFile);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h
new file mode 100644
index 00000000..4fb94276
--- /dev/null
+++ b/src/datavisualization/data/customrenderitem_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CUSTOMRENDERITEM_P_H
+#define CUSTOMRENDERITEM_P_H
+
+#include "abstractrenderitem_p.h"
+#include "objecthelper_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QCustom3DItem;
+class Abstract3DRenderer;
+
+class CustomRenderItem : public AbstractRenderItem
+{
+public:
+ CustomRenderItem();
+ virtual ~CustomRenderItem();
+
+ inline void setTexture(GLuint texture) { m_texture = texture; }
+ inline GLuint texture() const { return m_texture; }
+ void setMesh(const QString &meshFile);
+ inline ObjectHelper *mesh() const { return m_object; }
+ inline void setScaling(const QVector3D &scaling) { m_scaling = scaling; }
+ inline QVector3D scaling() const { return m_scaling; }
+ inline void setPosition(const QVector3D &position) { m_position = position; }
+ inline QVector3D position() const { return m_position; }
+ inline void setPositionAbsolute(bool absolute) { m_absolute = absolute; }
+ inline bool isPositionAbsolute() const { return m_absolute; }
+ inline void setBlendNeeded(bool blend) { m_needBlend = blend; }
+ inline bool isBlendNeeded() const { return m_needBlend; }
+ inline void setVisible(bool visible) { m_visible = visible; }
+ inline bool isVisible() const { return m_visible; }
+ inline void setItemPointer(QCustom3DItem *item) { m_item = item; }
+ inline QCustom3DItem *itemPointer() const { return m_item; }
+ inline void setValid(bool valid) { m_valid = valid; }
+ inline bool isValid() const { return m_valid; }
+ inline void setIndex(int index) { m_index = index; }
+ inline int index() const { return m_index; }
+ inline void setShadowCasting(bool shadowCasting) { m_shadowCasting = shadowCasting; }
+ inline bool isShadowCasting() const { return m_shadowCasting; }
+ inline void setFacingCamera(bool facing) { m_isFacingCamera = facing; }
+ inline bool isFacingCamera() const { return m_isFacingCamera; }
+ inline void setRenderer(Abstract3DRenderer *renderer) { m_renderer = renderer; }
+
+private:
+ Q_DISABLE_COPY(CustomRenderItem)
+
+ GLuint m_texture;
+ QVector3D m_scaling;
+ QVector3D m_position;
+ bool m_absolute;
+ ObjectHelper *m_object; // shared reference
+ bool m_needBlend;
+ bool m_visible;
+ bool m_valid;
+ int m_index;
+ bool m_shadowCasting;
+ bool m_isFacingCamera;
+ QCustom3DItem *m_item;
+ Abstract3DRenderer *m_renderer;
+};
+typedef QHash<QCustom3DItem *, CustomRenderItem *> CustomRenderItemArray;
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/data.pri b/src/datavisualization/data/data.pri
index 6ebfed6b..73f398bf 100644
--- a/src/datavisualization/data/data.pri
+++ b/src/datavisualization/data/data.pri
@@ -36,7 +36,12 @@ HEADERS += \
$$PWD/qscatter3dseries.h \
$$PWD/qscatter3dseries_p.h \
$$PWD/qsurface3dseries.h \
- $$PWD/qsurface3dseries_p.h
+ $$PWD/qsurface3dseries_p.h \
+ $$PWD/customrenderitem_p.h \
+ $$PWD/qcustom3ditem.h \
+ $$PWD/qcustom3ditem_p.h \
+ $$PWD/qcustom3dlabel.h \
+ $$PWD/qcustom3dlabel_p.h
SOURCES += \
$$PWD/labelitem.cpp \
@@ -61,4 +66,7 @@ SOURCES += \
$$PWD/qabstract3dseries.cpp \
$$PWD/qbar3dseries.cpp \
$$PWD/qscatter3dseries.cpp \
- $$PWD/qsurface3dseries.cpp
+ $$PWD/qsurface3dseries.cpp \
+ $$PWD/customrenderitem.cpp \
+ $$PWD/qcustom3ditem.cpp \
+ $$PWD/qcustom3dlabel.cpp
diff --git a/src/datavisualization/data/labelitem_p.h b/src/datavisualization/data/labelitem_p.h
index 3a2c1eb1..89b6cc56 100644
--- a/src/datavisualization/data/labelitem_p.h
+++ b/src/datavisualization/data/labelitem_p.h
@@ -30,7 +30,6 @@
#define LABELITEM_P_H
#include "datavisualizationglobal_p.h"
-#include <QtGui/QOpenGLFunctions>
#include <QtCore/QSize>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qabstract3dseries.cpp b/src/datavisualization/data/qabstract3dseries.cpp
index e593a1d9..f8fe6b4f 100644
--- a/src/datavisualization/data/qabstract3dseries.cpp
+++ b/src/datavisualization/data/qabstract3dseries.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "qabstract3dseries.h"
#include "qabstract3dseries_p.h"
#include "qabstractdataproxy_p.h"
#include "abstract3dcontroller_p.h"
@@ -27,7 +26,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QAbstract3DSeries
* \inmodule QtDataVisualization
* \brief Base class for all QtDataVisualization series.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* You use the visualization type specific inherited classes instead of the base class.
* \sa QBar3DSeries, QScatter3DSeries, QSurface3DSeries, {Qt Data Visualization Data Handling}
@@ -53,7 +52,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* This type is uncreatable, but contains properties that are exposed via subtypes.
*
- * For Abstract3DSeries enums, see \l QAbstract3DSeries::SeriesType and \l QAbstract3DSeries::Mesh
+ * For Abstract3DSeries enums, see \l QAbstract3DSeries::SeriesType and \l{QAbstract3DSeries::Mesh}.
*
* \sa Bar3DSeries, Scatter3DSeries, Surface3DSeries, {Qt Data Visualization Data Handling}
*/
@@ -102,7 +101,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* Arrow pointing upwards.
* \value MeshPoint
* 2D point. Usable only with Q3DScatter.
- * \b Note: Shadows and color gradients do not affect this style.
+ * \b Note: Shadows do not affect this style. Color style Q3DTheme::ColorStyleObjectGradient
+ * is not supported by this style.
*/
/*!
@@ -240,6 +240,27 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ * \qmlproperty string Abstract3DSeries::itemLabel
+ * \since QtDataVisualization 1.1
+ *
+ * Contains the formatted item label. If there is no selected item or the selected item is not
+ * visible, returns an empty string.
+ *
+ * \sa itemLabelFormat
+ */
+
+/*!
+ * \qmlproperty bool Abstract3DSeries::itemLabelVisible
+ * \since QtDataVisualization 1.1
+ *
+ * If \c true, item labels are drawn as floating labels in the graph. Otherwise item labels are not
+ * drawn. If you prefer to show the item label in an external control, set this property to
+ * \c false. Defaults to \c true.
+ *
+ * \sa itemLabelFormat, itemLabel
+ */
+
+/*!
* \qmlmethod void Abstract3DSeries::setMeshAxisAndAngle(vector3d axis, real angle)
*
* A convenience function to construct mesh rotation quaternion from axis and angle.
@@ -586,9 +607,47 @@ QString QAbstract3DSeries::name() const
return d_ptr->m_name;
}
+/*!
+ * \property QAbstract3DSeries::itemLabel
+ * \since QtDataVisualization 1.1
+ *
+ * Contains the formatted item label. If there is no selected item or the selected item is not
+ * visible, returns an empty string.
+ *
+ * \sa itemLabelFormat
+ */
+QString QAbstract3DSeries::itemLabel() const
+{
+ return d_ptr->itemLabel();
+}
+
+/*!
+ * \property QAbstract3DSeries::itemLabelVisible
+ * \since QtDataVisualization 1.1
+ *
+ * If \c true, item labels are drawn as floating labels in the graph. Otherwise item labels are not
+ * drawn. If you prefer to show the item label in an external control, set this property to
+ * \c false. Defaults to \c true.
+ *
+ * \sa itemLabelFormat, itemLabel
+ */
+void QAbstract3DSeries::setItemLabelVisible(bool visible)
+{
+ if (d_ptr->m_itemLabelVisible != visible) {
+ d_ptr->setItemLabelVisible(visible);
+ emit itemLabelVisibilityChanged(visible);
+ }
+}
+
+bool QAbstract3DSeries::isItemLabelVisible() const
+{
+ return d_ptr->m_itemLabelVisible;
+}
+
// QAbstract3DSeriesPrivate
-QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q, QAbstract3DSeries::SeriesType type)
+QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q,
+ QAbstract3DSeries::SeriesType type)
: QObject(0),
q_ptr(q),
m_type(type),
@@ -597,7 +656,9 @@ QAbstract3DSeriesPrivate::QAbstract3DSeriesPrivate(QAbstract3DSeries *q, QAbstra
m_controller(0),
m_mesh(QAbstract3DSeries::MeshCube),
m_meshSmooth(false),
- m_colorStyle(Q3DTheme::ColorStyleUniform)
+ m_colorStyle(Q3DTheme::ColorStyleUniform),
+ m_itemLabelDirty(true),
+ m_itemLabelVisible(true)
{
}
@@ -630,53 +691,67 @@ void QAbstract3DSeriesPrivate::setController(Abstract3DController *controller)
connectControllerAndProxy(controller);
m_controller = controller;
q_ptr->setParent(controller);
+ markItemLabelDirty();
}
void QAbstract3DSeriesPrivate::setItemLabelFormat(const QString &format)
{
m_itemLabelFormat = format;
- m_changeTracker.itemLabelFormatChanged = true;
- if (m_controller)
- m_controller->markSeriesVisualsDirty();
+ markItemLabelDirty();
}
void QAbstract3DSeriesPrivate::setVisible(bool visible)
{
m_visible = visible;
- if (m_controller)
- m_controller->markSeriesVisualsDirty();
+ markItemLabelDirty();
}
void QAbstract3DSeriesPrivate::setMesh(QAbstract3DSeries::Mesh mesh)
{
m_mesh = mesh;
m_changeTracker.meshChanged = true;
- if (m_controller)
+ if (m_controller) {
m_controller->markSeriesVisualsDirty();
+
+ if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic))
+ m_controller->markDataDirty();
+ }
}
void QAbstract3DSeriesPrivate::setMeshSmooth(bool enable)
{
m_meshSmooth = enable;
m_changeTracker.meshSmoothChanged = true;
- if (m_controller)
+ if (m_controller) {
m_controller->markSeriesVisualsDirty();
+
+ if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic))
+ m_controller->markDataDirty();
+ }
}
void QAbstract3DSeriesPrivate::setMeshRotation(const QQuaternion &rotation)
{
m_meshRotation = rotation;
m_changeTracker.meshRotationChanged = true;
- if (m_controller)
+ if (m_controller) {
m_controller->markSeriesVisualsDirty();
+
+ if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic))
+ m_controller->markDataDirty();
+ }
}
void QAbstract3DSeriesPrivate::setUserDefinedMesh(const QString &meshFile)
{
m_userDefinedMesh = meshFile;
m_changeTracker.userDefinedMeshChanged = true;
- if (m_controller)
+ if (m_controller) {
m_controller->markSeriesVisualsDirty();
+
+ if (m_controller->optimizationHints().testFlag(QAbstract3DGraph::OptimizationStatic))
+ m_controller->markDataDirty();
+ }
}
void QAbstract3DSeriesPrivate::setColorStyle(Q3DTheme::ColorStyle style)
@@ -738,9 +813,8 @@ void QAbstract3DSeriesPrivate::setMultiHighlightGradient(const QLinearGradient &
void QAbstract3DSeriesPrivate::setName(const QString &name)
{
m_name = name;
+ markItemLabelDirty();
m_changeTracker.nameChanged = true;
- if (m_controller)
- m_controller->markSeriesVisualsDirty();
}
void QAbstract3DSeriesPrivate::resetToTheme(const Q3DTheme &theme, int seriesIndex, bool force)
@@ -780,4 +854,36 @@ void QAbstract3DSeriesPrivate::resetToTheme(const Q3DTheme &theme, int seriesInd
}
}
+QString QAbstract3DSeriesPrivate::itemLabel()
+{
+ if (m_itemLabelDirty) {
+ QString oldLabel = m_itemLabel;
+ if (m_controller && m_visible)
+ createItemLabel();
+ else
+ m_itemLabel = QString();
+ m_itemLabelDirty = false;
+
+ if (oldLabel != m_itemLabel)
+ emit q_ptr->itemLabelChanged(m_itemLabel);
+ }
+
+ return m_itemLabel;
+}
+
+void QAbstract3DSeriesPrivate::markItemLabelDirty()
+{
+ m_itemLabelDirty = true;
+ m_changeTracker.itemLabelChanged = true;
+ if (m_controller)
+ m_controller->markSeriesVisualsDirty();
+}
+
+void QAbstract3DSeriesPrivate::setItemLabelVisible(bool visible)
+{
+ m_itemLabelVisible = visible;
+ markItemLabelDirty();
+ m_changeTracker.itemLabelVisibilityChanged = true;
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qabstract3dseries.h b/src/datavisualization/data/qabstract3dseries.h
index bf56422f..87c4f3c1 100644
--- a/src/datavisualization/data/qabstract3dseries.h
+++ b/src/datavisualization/data/qabstract3dseries.h
@@ -50,6 +50,8 @@ class QT_DATAVISUALIZATION_EXPORT QAbstract3DSeries : public QObject
Q_PROPERTY(QColor multiHighlightColor READ multiHighlightColor WRITE setMultiHighlightColor NOTIFY multiHighlightColorChanged)
Q_PROPERTY(QLinearGradient multiHighlightGradient READ multiHighlightGradient WRITE setMultiHighlightGradient NOTIFY multiHighlightGradientChanged)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QString itemLabel READ itemLabel NOTIFY itemLabelChanged REVISION 1)
+ Q_PROPERTY(bool itemLabelVisible READ isItemLabelVisible WRITE setItemLabelVisible NOTIFY itemLabelVisibilityChanged REVISION 1)
public:
enum SeriesType {
@@ -119,6 +121,10 @@ public:
void setName(const QString &name);
QString name() const;
+ QString itemLabel() const;
+ void setItemLabelVisible(bool visible);
+ bool isItemLabelVisible() const;
+
signals:
void itemLabelFormatChanged(const QString &format);
void visibilityChanged(bool visible);
@@ -134,6 +140,8 @@ signals:
void multiHighlightColorChanged(const QColor &color);
void multiHighlightGradientChanged(const QLinearGradient &gradient);
void nameChanged(const QString &name);
+ Q_REVISION(1) void itemLabelChanged(const QString &label);
+ Q_REVISION(1) void itemLabelVisibilityChanged(bool visible);
protected:
QScopedPointer<QAbstract3DSeriesPrivate> d_ptr;
diff --git a/src/datavisualization/data/qabstract3dseries_p.h b/src/datavisualization/data/qabstract3dseries_p.h
index a803e99b..dd574e03 100644
--- a/src/datavisualization/data/qabstract3dseries_p.h
+++ b/src/datavisualization/data/qabstract3dseries_p.h
@@ -26,19 +26,18 @@
//
// We mean it.
-#include "datavisualizationglobal_p.h"
-#include "qabstract3dseries.h"
-
#ifndef QABSTRACT3DSERIES_P_H
#define QABSTRACT3DSERIES_P_H
+#include "datavisualizationglobal_p.h"
+#include "qabstract3dseries.h"
+
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QAbstractDataProxy;
class Abstract3DController;
struct QAbstract3DSeriesChangeBitField {
- bool itemLabelFormatChanged : 1;
bool meshChanged : 1;
bool meshSmoothChanged : 1;
bool meshRotationChanged : 1;
@@ -51,10 +50,12 @@ struct QAbstract3DSeriesChangeBitField {
bool multiHighlightColorChanged : 1;
bool multiHighlightGradientChanged : 1;
bool nameChanged : 1;
+ bool itemLabelChanged : 1;
+ bool itemLabelVisibilityChanged : 1;
+ bool visibilityChanged : 1;
QAbstract3DSeriesChangeBitField()
- : itemLabelFormatChanged(true),
- meshChanged(true),
+ : meshChanged(true),
meshSmoothChanged(true),
meshRotationChanged(true),
userDefinedMeshChanged(true),
@@ -65,7 +66,10 @@ struct QAbstract3DSeriesChangeBitField {
singleHighlightGradientChanged(true),
multiHighlightColorChanged(true),
multiHighlightGradientChanged(true),
- nameChanged(true)
+ nameChanged(true),
+ itemLabelChanged(true),
+ itemLabelVisibilityChanged(true),
+ visibilityChanged(true)
{
}
};
@@ -102,6 +106,7 @@ public:
virtual void setDataProxy(QAbstractDataProxy *proxy);
virtual void setController(Abstract3DController *controller);
virtual void connectControllerAndProxy(Abstract3DController *newController) = 0;
+ virtual void createItemLabel() = 0;
void setItemLabelFormat(const QString &format);
void setVisible(bool visible);
@@ -120,6 +125,10 @@ public:
void setName(const QString &name);
void resetToTheme(const Q3DTheme &theme, int seriesIndex, bool force);
+ QString itemLabel();
+ void markItemLabelDirty();
+ inline bool itemLabelDirty() const { return m_itemLabelDirty; }
+ void setItemLabelVisible(bool visible);
QAbstract3DSeriesChangeBitField m_changeTracker;
QAbstract3DSeriesThemeOverrideBitField m_themeTracker;
@@ -143,6 +152,9 @@ public:
QLinearGradient m_multiHighlightGradient;
QString m_name;
+ QString m_itemLabel;
+ bool m_itemLabelDirty;
+ bool m_itemLabelVisible;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qabstractdataproxy.cpp b/src/datavisualization/data/qabstractdataproxy.cpp
index 18d88971..eb15cec8 100644
--- a/src/datavisualization/data/qabstractdataproxy.cpp
+++ b/src/datavisualization/data/qabstractdataproxy.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "qabstractdataproxy.h"
#include "qabstractdataproxy_p.h"
#include "qabstract3dseries_p.h"
@@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QAbstractDataProxy
* \inmodule QtDataVisualization
* \brief Base class for all QtDataVisualization data proxies.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* You use the visualization type specific inherited classes instead of the base class.
* \sa QBarDataProxy, QScatterDataProxy, QSurfaceDataProxy, {Qt Data Visualization Data Handling}
@@ -42,7 +41,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* This type is uncreatable, but contains properties that are exposed via subtypes.
*
- * For AbstractDataProxy enums, see \l QAbstractDataProxy::DataType
+ * For AbstractDataProxy enums, see \l{QAbstractDataProxy::DataType}.
*
* \sa BarDataProxy, ScatterDataProxy, SurfaceDataProxy, {Qt Data Visualization Data Handling}
*/
diff --git a/src/datavisualization/data/qabstractdataproxy_p.h b/src/datavisualization/data/qabstractdataproxy_p.h
index eb901f4c..c2f53369 100644
--- a/src/datavisualization/data/qabstractdataproxy_p.h
+++ b/src/datavisualization/data/qabstractdataproxy_p.h
@@ -26,12 +26,12 @@
//
// We mean it.
-#include "datavisualizationglobal_p.h"
-#include "qabstractdataproxy.h"
-
#ifndef QABSTRACTDATAPROXY_P_H
#define QABSTRACTDATAPROXY_P_H
+#include "datavisualizationglobal_p.h"
+#include "qabstractdataproxy.h"
+
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QAbstract3DSeries;
diff --git a/src/datavisualization/data/qbar3dseries.cpp b/src/datavisualization/data/qbar3dseries.cpp
index ed4ffaba..3440a3db 100644
--- a/src/datavisualization/data/qbar3dseries.cpp
+++ b/src/datavisualization/data/qbar3dseries.cpp
@@ -26,7 +26,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QBar3DSeries
* \inmodule QtDataVisualization
* \brief Base series class for Q3DBars.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QBar3DSeries manages the series specific visual elements, as well as series data
* (via data proxy).
@@ -317,6 +317,56 @@ void QBar3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *newCon
}
}
+void QBar3DSeriesPrivate::createItemLabel()
+{
+ static const QString rowIndexTag(QStringLiteral("@rowIdx"));
+ static const QString rowLabelTag(QStringLiteral("@rowLabel"));
+ static const QString rowTitleTag(QStringLiteral("@rowTitle"));
+ static const QString colIndexTag(QStringLiteral("@colIdx"));
+ static const QString colLabelTag(QStringLiteral("@colLabel"));
+ static const QString colTitleTag(QStringLiteral("@colTitle"));
+ static const QString valueTitleTag(QStringLiteral("@valueTitle"));
+ static const QString valueLabelTag(QStringLiteral("@valueLabel"));
+ static const QString seriesNameTag(QStringLiteral("@seriesName"));
+
+ if (m_selectedBar == QBar3DSeries::invalidSelectionPosition()) {
+ m_itemLabel = QString();
+ return;
+ }
+
+ QCategory3DAxis *categoryAxisZ = static_cast<QCategory3DAxis *>(m_controller->axisZ());
+ QCategory3DAxis *categoryAxisX = static_cast<QCategory3DAxis *>(m_controller->axisX());
+ QValue3DAxis *valueAxis = static_cast<QValue3DAxis *>(m_controller->axisY());
+ qreal selectedBarValue = qreal(qptr()->dataProxy()->itemAt(m_selectedBar)->value());
+
+ // Custom format expects printf format specifier. There is no tag for it.
+ m_itemLabel = valueAxis->formatter()->stringForValue(selectedBarValue, m_itemLabelFormat);
+
+ int selBarPosRow = m_selectedBar.x();
+ int selBarPosCol = m_selectedBar.y();
+ m_itemLabel.replace(rowIndexTag, QString::number(selBarPosRow));
+ if (categoryAxisZ->labels().size() > selBarPosRow)
+ m_itemLabel.replace(rowLabelTag, categoryAxisZ->labels().at(selBarPosRow));
+ else
+ m_itemLabel.replace(rowLabelTag, QString());
+ m_itemLabel.replace(rowTitleTag, categoryAxisZ->title());
+ m_itemLabel.replace(colIndexTag, QString::number(selBarPosCol));
+ if (categoryAxisX->labels().size() > selBarPosCol)
+ m_itemLabel.replace(colLabelTag, categoryAxisX->labels().at(selBarPosCol));
+ else
+ m_itemLabel.replace(colLabelTag, QString());
+ m_itemLabel.replace(colTitleTag, categoryAxisX->title());
+ m_itemLabel.replace(valueTitleTag, valueAxis->title());
+
+ if (m_itemLabel.contains(valueLabelTag)) {
+ QString valueLabelText = valueAxis->formatter()->stringForValue(selectedBarValue,
+ valueAxis->labelFormat());
+ m_itemLabel.replace(valueLabelTag, valueLabelText);
+ }
+
+ m_itemLabel.replace(seriesNameTag, m_name);
+}
+
void QBar3DSeriesPrivate::handleMeshRotationChanged(const QQuaternion &rotation)
{
emit qptr()->meshAngleChanged(quaternionAngle(rotation));
@@ -325,6 +375,7 @@ void QBar3DSeriesPrivate::handleMeshRotationChanged(const QQuaternion &rotation)
void QBar3DSeriesPrivate::setSelectedBar(const QPoint &position)
{
if (position != m_selectedBar) {
+ markItemLabelDirty();
m_selectedBar = position;
emit qptr()->selectedBarChanged(m_selectedBar);
}
diff --git a/src/datavisualization/data/qbar3dseries_p.h b/src/datavisualization/data/qbar3dseries_p.h
index 718f1237..c5b51108 100644
--- a/src/datavisualization/data/qbar3dseries_p.h
+++ b/src/datavisualization/data/qbar3dseries_p.h
@@ -43,6 +43,7 @@ public:
virtual void setDataProxy(QAbstractDataProxy *proxy);
virtual void connectControllerAndProxy(Abstract3DController *newController);
+ virtual void createItemLabel();
void handleMeshRotationChanged(const QQuaternion &rotation);
diff --git a/src/datavisualization/data/qbardataitem.cpp b/src/datavisualization/data/qbardataitem.cpp
index 37c2033f..8f370e24 100644
--- a/src/datavisualization/data/qbardataitem.cpp
+++ b/src/datavisualization/data/qbardataitem.cpp
@@ -24,7 +24,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QBarDataItem
* \inmodule QtDataVisualization
* \brief The QBarDataItem class provides a container for resolved data to be added to bar graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* A QBarDataItem holds data for a single rendered bar in a graph.
* Bar data proxies parse data into QBarDataItem instances for visualizing.
diff --git a/src/datavisualization/data/qbardataitem_p.h b/src/datavisualization/data/qbardataitem_p.h
index c06ddea9..623c4012 100644
--- a/src/datavisualization/data/qbardataitem_p.h
+++ b/src/datavisualization/data/qbardataitem_p.h
@@ -39,9 +39,6 @@ class QBarDataItemPrivate
public:
QBarDataItemPrivate();
virtual ~QBarDataItemPrivate();
-
-protected:
- friend class QBarDataItem;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qbardataproxy.cpp b/src/datavisualization/data/qbardataproxy.cpp
index 1c1170ff..8e4f25de 100644
--- a/src/datavisualization/data/qbardataproxy.cpp
+++ b/src/datavisualization/data/qbardataproxy.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "qbardataproxy.h"
#include "qbardataproxy_p.h"
#include "qbar3dseries_p.h"
@@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QBarDataProxy
* \inmodule QtDataVisualization
* \brief Base proxy class for Q3DBars.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QBarDataProxy handles adding, inserting, changing and removing rows of data.
*
@@ -554,7 +553,8 @@ void QBarDataProxyPrivate::setRow(int rowIndex, QBarDataRow *row, const QString
}
}
-void QBarDataProxyPrivate::setRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels)
+void QBarDataProxyPrivate::setRows(int rowIndex, const QBarDataArray &rows,
+ const QStringList *labels)
{
QBarDataArray &dataArray = *m_dataArray;
Q_ASSERT(rowIndex >= 0 && (rowIndex + rows.size()) <= dataArray.size());
@@ -604,7 +604,8 @@ void QBarDataProxyPrivate::insertRow(int rowIndex, QBarDataRow *row, const QStri
m_dataArray->insert(rowIndex, row);
}
-void QBarDataProxyPrivate::insertRows(int rowIndex, const QBarDataArray &rows, const QStringList *labels)
+void QBarDataProxyPrivate::insertRows(int rowIndex, const QBarDataArray &rows,
+ const QStringList *labels)
{
Q_ASSERT(rowIndex >= 0 && rowIndex <= m_dataArray->size());
if (labels)
@@ -656,7 +657,8 @@ void QBarDataProxyPrivate::clearArray()
* \internal
* Fixes the row label array to include specified labels.
*/
-void QBarDataProxyPrivate::fixRowLabels(int startIndex, int count, const QStringList &newLabels, bool isInsert)
+void QBarDataProxyPrivate::fixRowLabels(int startIndex, int count, const QStringList &newLabels,
+ bool isInsert)
{
bool changed = false;
int currentSize = m_rowLabels.size();
diff --git a/src/datavisualization/data/qbardataproxy_p.h b/src/datavisualization/data/qbardataproxy_p.h
index eb0a0873..4d1489d9 100644
--- a/src/datavisualization/data/qbardataproxy_p.h
+++ b/src/datavisualization/data/qbardataproxy_p.h
@@ -31,7 +31,6 @@
#include "qbardataproxy.h"
#include "qabstractdataproxy_p.h"
-#include "qbardataitem.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp
new file mode 100644
index 00000000..f5d8470f
--- /dev/null
+++ b/src/datavisualization/data/qcustom3ditem.cpp
@@ -0,0 +1,422 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qcustom3ditem_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QCustom3DItem
+ * \inmodule QtDataVisualization
+ * \brief The QCustom3DItem class is for creating custom items to be added to a graph.
+ * \since QtDataVisualization 1.1
+ *
+ * This class is for creating custom items to be added to a graph. The item has a custom mesh,
+ * position, scaling, rotation, and an optional texture.
+ *
+ * \sa QAbstract3DGraph::addCustomItem()
+ */
+
+/*!
+ * \qmltype Custom3DItem
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.1
+ * \ingroup datavisualization_qml
+ * \instantiates QCustom3DItem
+ * \brief The Custom3DItem type is for creating custom items to be added to a graph.
+ *
+ * This type is for creating custom items to be added to a graph. The item has a custom mesh,
+ * position, scaling, rotation, and an optional texture.
+ */
+
+/*! \qmlproperty string Custom3DItem::meshFile
+ *
+ * Holds item mesh file name. Item in the file must be in Wavefront obj format and include
+ * vertices, normals, and UVs. It also needs to be in triangles.
+ */
+
+/*! \qmlproperty string Custom3DItem::textureFile
+ *
+ * Holds the texture file name for the item. If left unset, a solid gray texture will be
+ * used.
+ *
+ * \note To conserve memory the Image loaded from the file is cleared after a texture is created.
+ */
+
+/*! \qmlproperty vector3d Custom3DItem::position
+ *
+ * Holds the item \a position as a vector3d. Defaults to \c {vector3d(0.0, 0.0, 0.0)}.
+ *
+ * Item position is either in data coordinates or in absolute coordinates, depending on
+ * positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are
+ * within axis ranges.
+ *
+ * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}.
+ *
+ * \sa positionAbsolute
+ */
+
+/*! \qmlproperty bool Custom3DItem::positionAbsolute
+ *
+ * This property dictates if item position is to be handled in data coordinates or in absolute
+ * coordinates. Defaults to \c{false}. Items with absolute coordinates will always be rendered,
+ * whereas items with data coordinates are only rendered if they are within axis ranges.
+ *
+ * \sa position
+ */
+
+/*! \qmlproperty vector3d Custom3DItem::scaling
+ *
+ * Holds the item \a scaling as a vector3d. Defaults to \c {vector3d(0.1, 0.1, 0.1)}.
+ * The default value sets the item to 10% of the height of the graph, provided the item size is
+ * normalized.
+ */
+
+/*! \qmlproperty quaternion Custom3DItem::rotation
+ *
+ * Holds the item \a rotation as a quaternion. Defaults to \c {quaternion(0.0, 0.0, 0.0, 0.0)}.
+ */
+
+/*! \qmlproperty bool Custom3DItem::visible
+ *
+ * Sets the item \a visible. Defaults to \c{true}.
+ */
+
+/*! \qmlproperty bool Custom3DItem::shadowCasting
+ *
+ * Sets shadow casting for the item to \a enabled. Defaults to \c{true}.
+ * If set \c{false}, the item does not cast shadows regardless of
+ * \l{QAbstract3DGraph::ShadowQuality}{ShadowQuality}.
+ */
+
+/*!
+ * \qmlmethod void Custom3DItem::setRotationAxisAndAngle(vector3d axis, real angle)
+ *
+ * A convenience function to construct rotation quaternion from \a axis and \a angle.
+ *
+ * \sa rotation
+ */
+
+/*!
+ * Constructs QCustom3DItem with given \a parent.
+ */
+QCustom3DItem::QCustom3DItem(QObject *parent) :
+ QObject(parent),
+ d_ptr(new QCustom3DItemPrivate(this))
+{
+ setTextureImage(QImage());
+}
+
+/*!
+ * \internal
+ */
+QCustom3DItem::QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent) :
+ QObject(parent),
+ d_ptr(d)
+{
+ setTextureImage(QImage());
+}
+
+/*!
+ * Constructs QCustom3DItem with given \a meshFile, \a position, \a scaling,
+ * \a rotation, \a texture image, and optional \a parent.
+ */
+QCustom3DItem::QCustom3DItem(const QString &meshFile, const QVector3D &position,
+ const QVector3D &scaling, const QQuaternion &rotation,
+ const QImage &texture, QObject *parent) :
+ QObject(parent),
+ d_ptr(new QCustom3DItemPrivate(this, meshFile, position, scaling, rotation))
+{
+ setTextureImage(texture);
+}
+
+/*!
+ * Destroys QCustom3DItem.
+ */
+QCustom3DItem::~QCustom3DItem()
+{
+}
+
+/*! \property QCustom3DItem::meshFile
+ *
+ * Holds item mesh file name. Item in the file must be in Wavefront obj format and include
+ * vertices, normals, and UVs. It also needs to be in triangles.
+ */
+void QCustom3DItem::setMeshFile(const QString &meshFile)
+{
+ if (d_ptr->m_meshFile != meshFile) {
+ d_ptr->m_meshFile = meshFile;
+ d_ptr->m_dirtyBits.meshDirty = true;
+ emit meshFileChanged(meshFile);
+ emit d_ptr->needUpdate();
+ }
+}
+
+QString QCustom3DItem::meshFile() const
+{
+ return d_ptr->m_meshFile;
+}
+
+/*! \property QCustom3DItem::position
+ *
+ * Holds the item \a position as a QVector3D. Defaults to \c {QVector3D(0.0, 0.0, 0.0)}.
+ *
+ * Item position is either in data coordinates or in absolute coordinates, depending on
+ * positionAbsolute property. When using absolute coordinates, values between \c{-1.0...1.0} are
+ * within axis ranges.
+ *
+ * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}.
+ *
+ * \sa positionAbsolute
+ */
+void QCustom3DItem::setPosition(const QVector3D &position)
+{
+ if (d_ptr->m_position != position) {
+ d_ptr->m_position = position;
+ d_ptr->m_dirtyBits.positionDirty = true;
+ emit positionChanged(position);
+ emit d_ptr->needUpdate();
+ }
+}
+
+QVector3D QCustom3DItem::position() const
+{
+ return d_ptr->m_position;
+}
+
+/*! \property QCustom3DItem::positionAbsolute
+ *
+ * This property dictates if item position is to be handled in data coordinates or in absolute
+ * coordinates. Defaults to \c{false}. Items with absolute coordinates will always be rendered,
+ * whereas items with data coordinates are only rendered if they are within axis ranges.
+ *
+ * \sa position
+ */
+void QCustom3DItem::setPositionAbsolute(bool positionAbsolute)
+{
+ if (d_ptr->m_positionAbsolute != positionAbsolute) {
+ d_ptr->m_positionAbsolute = positionAbsolute;
+ d_ptr->m_dirtyBits.positionAbsoluteDirty = true;
+ emit positionAbsoluteChanged(positionAbsolute);
+ emit d_ptr->needUpdate();
+ }
+}
+
+bool QCustom3DItem::isPositionAbsolute() const
+{
+ return d_ptr->m_positionAbsolute;
+}
+
+/*! \property QCustom3DItem::scaling
+ *
+ * Holds the item \a scaling as a QVector3D. Defaults to \c {QVector3D(0.1, 0.1, 0.1)}.
+ * The default value sets the item to 10% of the height of the graph, provided the item size is
+ * normalized.
+ */
+void QCustom3DItem::setScaling(const QVector3D &scaling)
+{
+ if (d_ptr->m_scaling != scaling) {
+ d_ptr->m_scaling = scaling;
+ d_ptr->m_dirtyBits.scalingDirty = true;
+ emit scalingChanged(scaling);
+ emit d_ptr->needUpdate();
+ }
+}
+
+QVector3D QCustom3DItem::scaling() const
+{
+ return d_ptr->m_scaling;
+}
+
+/*! \property QCustom3DItem::rotation
+ *
+ * Holds the item \a rotation as a QQuaternion. Defaults to \c {QQuaternion(0.0, 0.0, 0.0, 0.0)}.
+ */
+void QCustom3DItem::setRotation(const QQuaternion &rotation)
+{
+ if (d_ptr->m_rotation != rotation) {
+ d_ptr->m_rotation = rotation;
+ d_ptr->m_dirtyBits.rotationDirty = true;
+ emit rotationChanged(rotation);
+ emit d_ptr->needUpdate();
+ }
+}
+
+QQuaternion QCustom3DItem::rotation()
+{
+ return d_ptr->m_rotation;
+}
+
+/*! \property QCustom3DItem::visible
+ *
+ * Sets the item \a visible. Defaults to \c{true}.
+ */
+void QCustom3DItem::setVisible(bool visible)
+{
+ if (d_ptr->m_visible != visible) {
+ d_ptr->m_visible = visible;
+ d_ptr->m_dirtyBits.visibleDirty = true;
+ emit visibleChanged(visible);
+ emit d_ptr->needUpdate();
+ }
+}
+
+bool QCustom3DItem::isVisible() const
+{
+ return d_ptr->m_visible;
+}
+
+
+/*! \property QCustom3DItem::shadowCasting
+ *
+ * Sets shadow casting for the item to \a enabled. Defaults to \c{true}.
+ * If set \c{false}, the item does not cast shadows regardless of QAbstract3DGraph::ShadowQuality.
+ */
+void QCustom3DItem::setShadowCasting(bool enabled)
+{
+ if (d_ptr->m_shadowCasting != enabled) {
+ d_ptr->m_shadowCasting = enabled;
+ d_ptr->m_dirtyBits.shadowCastingDirty = true;
+ emit shadowCastingChanged(enabled);
+ emit d_ptr->needUpdate();
+ }
+}
+
+bool QCustom3DItem::isShadowCasting() const
+{
+ return d_ptr->m_shadowCasting;
+}
+
+/*!
+ * A convenience function to construct rotation quaternion from \a axis and \a angle.
+ *
+ * \sa rotation
+ */
+void QCustom3DItem::setRotationAxisAndAngle(const QVector3D &axis, float angle)
+{
+ setRotation(QQuaternion::fromAxisAndAngle(axis, angle));
+}
+
+/*!
+ * Set the \a textureImage as a QImage for the item. Texture defaults to solid gray.
+ *
+ * \note To conserve memory the given QImage is cleared after a texture is created.
+ */
+void QCustom3DItem::setTextureImage(const QImage &textureImage)
+{
+ if (textureImage != d_ptr->m_textureImage) {
+ if (textureImage.isNull()) {
+ // Make a solid gray texture
+ d_ptr->m_textureImage = QImage(2, 2, QImage::Format_RGB32);
+ d_ptr->m_textureImage.fill(Qt::gray);
+ } else {
+ d_ptr->m_textureImage = textureImage;
+ }
+
+ if (!d_ptr->m_textureFile.isEmpty()) {
+ d_ptr->m_textureFile.clear();
+ emit textureFileChanged(d_ptr->m_textureFile);
+ }
+ d_ptr->m_dirtyBits.textureDirty = true;
+ emit d_ptr->needUpdate();
+ }
+}
+
+/*! \property QCustom3DItem::textureFile
+ *
+ * Holds the texture file name for the item. If both this and texture image are unset, a solid
+ * gray texture will be used.
+ *
+ * \note To conserve memory the QImage loaded from the file is cleared after a texture is created.
+ */
+void QCustom3DItem::setTextureFile(const QString &textureFile)
+{
+ if (d_ptr->m_textureFile != textureFile) {
+ d_ptr->m_textureFile = textureFile;
+ if (!textureFile.isEmpty()) {
+ d_ptr->m_textureImage = QImage(textureFile);
+ } else {
+ d_ptr->m_textureImage = QImage(2, 2, QImage::Format_RGB32);
+ d_ptr->m_textureImage.fill(Qt::gray);
+ }
+ emit textureFileChanged(textureFile);
+ d_ptr->m_dirtyBits.textureDirty = true;
+ emit d_ptr->needUpdate();
+ }
+}
+
+QString QCustom3DItem::textureFile() const
+{
+ return d_ptr->m_textureFile;
+}
+
+QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) :
+ q_ptr(q),
+ m_position(QVector3D(0.0f, 0.0f, 0.0f)),
+ m_positionAbsolute(false),
+ m_scaling(QVector3D(0.1f, 0.1f, 0.1f)),
+ m_rotation(QQuaternion(0.0f, 0.0f, 0.0f, 0.0f)),
+ m_visible(true),
+ m_shadowCasting(true),
+ m_isLabelItem(false)
+{
+}
+
+QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q, const QString &meshFile,
+ const QVector3D &position, const QVector3D &scaling,
+ const QQuaternion &rotation) :
+ q_ptr(q),
+ m_meshFile(meshFile),
+ m_position(position),
+ m_positionAbsolute(false),
+ m_scaling(scaling),
+ m_rotation(rotation),
+ m_visible(true),
+ m_shadowCasting(true),
+ m_isLabelItem(false)
+{
+}
+
+QCustom3DItemPrivate::~QCustom3DItemPrivate()
+{
+}
+
+QImage QCustom3DItemPrivate::textureImage()
+{
+ return m_textureImage;
+}
+
+void QCustom3DItemPrivate::clearTextureImage()
+{
+ m_textureImage = QImage();
+ m_textureFile.clear();
+}
+
+void QCustom3DItemPrivate::resetDirtyBits()
+{
+ m_dirtyBits.textureDirty = false;
+ m_dirtyBits.meshDirty = false;
+ m_dirtyBits.positionDirty = false;
+ m_dirtyBits.positionAbsoluteDirty = false;
+ m_dirtyBits.scalingDirty = false;
+ m_dirtyBits.rotationDirty = false;
+ m_dirtyBits.visibleDirty = false;
+ m_dirtyBits.shadowCastingDirty = false;
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qcustom3ditem.h b/src/datavisualization/data/qcustom3ditem.h
new file mode 100644
index 00000000..2f7f37cf
--- /dev/null
+++ b/src/datavisualization/data/qcustom3ditem.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef QCUSTOM3DITEM_H
+#define QCUSTOM3DITEM_H
+
+#include <QtDataVisualization/qdatavisualizationglobal.h>
+#include <QtGui/QImage>
+#include <QtGui/QVector3D>
+#include <QtGui/QQuaternion>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QCustom3DItemPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QCustom3DItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString meshFile READ meshFile WRITE setMeshFile NOTIFY meshFileChanged)
+ Q_PROPERTY(QString textureFile READ textureFile WRITE setTextureFile NOTIFY textureFileChanged)
+ Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
+ Q_PROPERTY(bool positionAbsolute READ isPositionAbsolute WRITE setPositionAbsolute NOTIFY positionAbsoluteChanged)
+ Q_PROPERTY(QVector3D scaling READ scaling WRITE setScaling NOTIFY scalingChanged)
+ Q_PROPERTY(QQuaternion rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(bool shadowCasting READ isShadowCasting WRITE setShadowCasting NOTIFY shadowCastingChanged)
+
+public:
+ explicit QCustom3DItem(QObject *parent = 0);
+ explicit QCustom3DItem(const QString &meshFile, const QVector3D &position,
+ const QVector3D &scaling, const QQuaternion &rotation,
+ const QImage &texture, QObject *parent = 0);
+ virtual ~QCustom3DItem();
+
+ void setMeshFile(const QString &meshFile);
+ QString meshFile() const;
+
+ void setTextureFile(const QString &textureFile);
+ QString textureFile() const;
+
+ void setPosition(const QVector3D &position);
+ QVector3D position() const;
+
+ void setPositionAbsolute(bool positionAbsolute);
+ bool isPositionAbsolute() const;
+
+ void setScaling(const QVector3D &scaling);
+ QVector3D scaling() const;
+
+ void setRotation(const QQuaternion &rotation);
+ QQuaternion rotation();
+
+ void setVisible(bool visible);
+ bool isVisible() const;
+
+ void setShadowCasting(bool enabled);
+ bool isShadowCasting() const;
+
+ Q_INVOKABLE void setRotationAxisAndAngle(const QVector3D &axis, float angle);
+
+ void setTextureImage(const QImage &textureImage);
+
+signals:
+ void meshFileChanged(const QString &meshFile);
+ void textureFileChanged(const QString &textureFile);
+ void positionChanged(const QVector3D &position);
+ void positionAbsoluteChanged(bool positionAbsolute);
+ void scalingChanged(const QVector3D &scaling);
+ void rotationChanged(const QQuaternion &rotation);
+ void visibleChanged(bool visible);
+ void shadowCastingChanged(bool shadowCasting);
+
+protected:
+ QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent = 0);
+
+ QScopedPointer<QCustom3DItemPrivate> d_ptr;
+
+private:
+ Q_DISABLE_COPY(QCustom3DItem)
+
+ friend class Abstract3DRenderer;
+ friend class Abstract3DController;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/qcustom3ditem_p.h b/src/datavisualization/data/qcustom3ditem_p.h
new file mode 100644
index 00000000..c1ce5996
--- /dev/null
+++ b/src/datavisualization/data/qcustom3ditem_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QCUSTOM3DITEM_P_H
+#define QCUSTOM3DITEM_P_H
+
+#include "qcustom3ditem.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+struct QCustomItemDirtyBitField {
+ bool textureDirty : 1;
+ bool meshDirty : 1;
+ bool positionDirty : 1;
+ bool positionAbsoluteDirty : 1;
+ bool scalingDirty : 1;
+ bool rotationDirty : 1;
+ bool visibleDirty : 1;
+ bool shadowCastingDirty : 1;
+
+ QCustomItemDirtyBitField()
+ : textureDirty(false),
+ meshDirty(false),
+ positionDirty(false),
+ positionAbsoluteDirty(false),
+ scalingDirty(false),
+ rotationDirty(false),
+ visibleDirty(false),
+ shadowCastingDirty(false)
+ {
+ }
+};
+
+class QCustom3DItemPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QCustom3DItemPrivate(QCustom3DItem *q);
+ QCustom3DItemPrivate(QCustom3DItem *q, const QString &meshFile, const QVector3D &position,
+ const QVector3D &scaling, const QQuaternion &rotation);
+ virtual ~QCustom3DItemPrivate();
+
+ QImage textureImage();
+ void clearTextureImage();
+ void resetDirtyBits();
+
+public:
+ QCustom3DItem *q_ptr;
+ QImage m_textureImage;
+ QString m_textureFile;
+ QString m_meshFile;
+ QVector3D m_position;
+ bool m_positionAbsolute;
+ QVector3D m_scaling;
+ QQuaternion m_rotation;
+ bool m_visible;
+ bool m_shadowCasting;
+
+ bool m_isLabelItem;
+
+ QCustomItemDirtyBitField m_dirtyBits;
+
+signals:
+ void needUpdate();
+
+private:
+ QCustom3DItemPrivate(QCustom3DItemPrivate *d);
+
+ friend class QCustom3DItem;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/qcustom3dlabel.cpp b/src/datavisualization/data/qcustom3dlabel.cpp
new file mode 100644
index 00000000..85a37e2d
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dlabel.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qcustom3dlabel_p.h"
+#include "utils_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+/*!
+ * \class QCustom3DLabel
+ * \inmodule QtDataVisualization
+ * \brief The QCustom3DLabel class is for creating custom labels to be added to a graph.
+ * \since QtDataVisualization 1.1
+ *
+ * This class is for creating custom labels to be added to a graph. You can set text, font,
+ * position, scaling, rotation, and colors. You can also toggle borders and background for the
+ * label. Colors, borders and background are used from active theme unless any of them is set
+ * explicitly.
+ *
+ * \note In scaling, z has no effect. Setting the same x and y retains the original
+ * font dimensions.
+ *
+ * \sa QAbstract3DGraph::addCustomItem()
+ */
+
+/*!
+ * \qmltype Custom3DLabel
+ * \inqmlmodule QtDataVisualization
+ * \since QtDataVisualization 1.1
+ * \ingroup datavisualization_qml
+ * \instantiates QCustom3DLabel
+ * \brief The Custom3DLabel type is for creating custom labels to be added to a graph.
+ *
+ * This type is for creating custom labels to be added to a graph. You can set text, font,
+ * position, scaling, rotation, and colors. You can also toggle borders and background for the
+ * label. Colors, borders and background are used from active theme unless any of them is set
+ * explicitly.
+ *
+ * \note In scaling, z has no effect. Setting the same x and y retains the original
+ * font dimensions.
+ */
+
+/*! \qmlproperty string Custom3DLabel::text
+ *
+ * The text for the label. Rich text is not supported.
+ */
+
+/*! \qmlproperty font Custom3DLabel::font
+ *
+ * The font to be used for the label. Defaults to \c{Font {family: "Arial"; pointSize: 20}}.
+ * Special formatting (for example outlined) is not supported.
+ */
+
+/*! \qmlproperty color Custom3DLabel::textColor
+ *
+ * Color for the label text. Also affects label border, if enabled. Defaults to \c{"white"}.
+ *
+ * \sa borderEnabled
+ */
+
+/*! \qmlproperty color Custom3DLabel::backgroundColor
+ *
+ * Color for the label background, if enabled. Defaults to \c{"gray"}.
+ *
+ * \sa backgroundEnabled
+ */
+
+/*! \qmlproperty bool Custom3DLabel::backgroundEnabled
+ *
+ * Enable label background. If set to \c{false}, backgroundColor has no effect. Defaults
+ * to \c{true}.
+ */
+
+/*! \qmlproperty bool Custom3DLabel::borderEnabled
+ *
+ * Enable label borders. Defaults to \c{true}.
+ */
+
+/*! \qmlproperty bool Custom3DLabel::facingCamera
+ *
+ * Forces the label to face camera always. Defaults to \c{false}. If set to \c{true}, rotation()
+ * has no effect.
+ */
+
+/*!
+ * Constructs QCustom3DLabel with given \a parent.
+ */
+QCustom3DLabel::QCustom3DLabel(QObject *parent) :
+ QCustom3DItem(new QCustom3DLabelPrivate(this), parent)
+{
+}
+
+/*!
+ * Constructs QCustom3DLabel with given \a text, \a font, \a position, \a scaling,
+ * \a rotation, and optional \a parent.
+ *
+ * \note Setting the same x and y for \a scaling retains the original font dimensions.
+ */
+QCustom3DLabel::QCustom3DLabel(const QString &text, const QFont &font,
+ const QVector3D &position, const QVector3D &scaling,
+ const QQuaternion &rotation, QObject *parent) :
+ QCustom3DItem(new QCustom3DLabelPrivate(this, text, font, position, scaling, rotation),
+ parent)
+{
+}
+
+/*!
+ * Destroys QCustom3DLabel.
+ */
+QCustom3DLabel::~QCustom3DLabel()
+{
+}
+
+/*! \property QCustom3DLabel::text
+ *
+ * The text for the label. Rich text is not supported.
+ */
+void QCustom3DLabel::setText(const QString &text)
+{
+ if (dptr()->m_text != text) {
+ dptr()->m_text = text;
+ dptr()->handleTextureChange();
+ emit textChanged(text);
+ emit dptr()->needUpdate();
+ }
+}
+
+QString QCustom3DLabel::text() const
+{
+ return dptrc()->m_text;
+}
+
+/*! \property QCustom3DLabel::font
+ *
+ * The font to be used for the label. Defaults to \c{QFont("Arial", 20)}. Special formatting
+ * (for example outlined) is not supported.
+ */
+void QCustom3DLabel::setFont(const QFont &font)
+{
+ if (dptr()->m_font != font) {
+ dptr()->m_font = font;
+ dptr()->handleTextureChange();
+ emit fontChanged(font);
+ emit dptr()->needUpdate();
+ }
+}
+
+QFont QCustom3DLabel::font() const
+{
+ return dptrc()->m_font;
+}
+
+/*! \property QCustom3DLabel::textColor
+ *
+ * Color for the label text. Also affects label border, if enabled. Defaults to \c{Qt::white}.
+ *
+ * \sa borderEnabled
+ */
+void QCustom3DLabel::setTextColor(const QColor &color)
+{
+ if (dptr()->m_txtColor != color) {
+ dptr()->m_txtColor = color;
+ dptr()->m_customVisuals = true;
+ dptr()->handleTextureChange();
+ emit textColorChanged(color);
+ emit dptr()->needUpdate();
+ }
+}
+
+QColor QCustom3DLabel::textColor() const
+{
+ return dptrc()->m_txtColor;
+}
+
+/*! \property QCustom3DLabel::backgroundColor
+ *
+ * Color for the label background, if enabled. Defaults to \c{Qt::gray}.
+ *
+ * \sa backgroundEnabled
+ */
+void QCustom3DLabel::setBackgroundColor(const QColor &color)
+{
+ if (dptr()->m_bgrColor != color) {
+ dptr()->m_bgrColor = color;
+ dptr()->m_customVisuals = true;
+ dptr()->handleTextureChange();
+ emit backgroundColorChanged(color);
+ emit dptr()->needUpdate();
+ }
+}
+
+QColor QCustom3DLabel::backgroundColor() const
+{
+ return dptrc()->m_bgrColor;
+}
+
+/*! \property QCustom3DLabel::borderEnabled
+ *
+ * Enable label borders. Defaults to \c{true}.
+ */
+void QCustom3DLabel::setBorderEnabled(bool enabled)
+{
+ if (dptr()->m_borders != enabled) {
+ dptr()->m_borders = enabled;
+ dptr()->m_customVisuals = true;
+ dptr()->handleTextureChange();
+ emit borderEnabledChanged(enabled);
+ emit dptr()->needUpdate();
+ }
+}
+
+bool QCustom3DLabel::isBorderEnabled() const
+{
+ return dptrc()->m_borders;
+}
+
+/*! \property QCustom3DLabel::backgroundEnabled
+ *
+ * Enable label background. If set to \c{false}, backgroundColor() has no effect. Defaults
+ * to \c{true}.
+ */
+void QCustom3DLabel::setBackgroundEnabled(bool enabled)
+{
+ if (dptr()->m_background != enabled) {
+ dptr()->m_background = enabled;
+ dptr()->m_customVisuals = true;
+ dptr()->handleTextureChange();
+ emit backgroundEnabledChanged(enabled);
+ emit dptr()->needUpdate();
+ }
+}
+
+bool QCustom3DLabel::isBackgroundEnabled() const
+{
+ return dptrc()->m_background;
+}
+
+/*! \property QCustom3DLabel::facingCamera
+ *
+ * Forces the label to face camera always. Defaults to \c{false}. If set to \c{true}, rotation()
+ * has no effect.
+ */
+void QCustom3DLabel::setFacingCamera(bool enabled)
+{
+ if (dptr()->m_facingCamera != enabled) {
+ dptr()->m_facingCamera = enabled;
+ dptr()->m_facingCameraDirty = true;
+ emit facingCameraChanged(enabled);
+ emit dptr()->needUpdate();
+ }
+}
+
+bool QCustom3DLabel::isFacingCamera() const
+{
+ return dptrc()->m_facingCamera;
+}
+
+/*!
+ * \internal
+ */
+QCustom3DLabelPrivate *QCustom3DLabel::dptr()
+{
+ return static_cast<QCustom3DLabelPrivate *>(d_ptr.data());
+}
+
+/*!
+ * \internal
+ */
+const QCustom3DLabelPrivate *QCustom3DLabel::dptrc() const
+{
+ return static_cast<const QCustom3DLabelPrivate *>(d_ptr.data());
+}
+
+QCustom3DLabelPrivate::QCustom3DLabelPrivate(QCustom3DLabel *q) :
+ QCustom3DItemPrivate(q),
+ m_font(QFont(QStringLiteral("Arial"), 20)),
+ m_bgrColor(Qt::gray),
+ m_txtColor(Qt::white),
+ m_background(true),
+ m_borders(true),
+ m_facingCamera(false),
+ m_customVisuals(false),
+ m_facingCameraDirty(false)
+{
+ m_isLabelItem = true;
+ m_shadowCasting = false;
+ m_meshFile = QStringLiteral(":/defaultMeshes/plane");
+ createTextureImage();
+}
+
+QCustom3DLabelPrivate::QCustom3DLabelPrivate(QCustom3DLabel *q, const QString &text,
+ const QFont &font, const QVector3D &position,
+ const QVector3D &scaling,
+ const QQuaternion &rotation) :
+ QCustom3DItemPrivate(q, QStringLiteral(":/defaultMeshes/plane"), position, scaling, rotation),
+ m_text(text),
+ m_font(font),
+ m_bgrColor(Qt::gray),
+ m_txtColor(Qt::white),
+ m_background(true),
+ m_borders(true),
+ m_facingCamera(false),
+ m_customVisuals(false),
+ m_facingCameraDirty(false)
+{
+ m_isLabelItem = true;
+ m_shadowCasting = false;
+ createTextureImage();
+}
+
+QCustom3DLabelPrivate::~QCustom3DLabelPrivate()
+{
+}
+
+void QCustom3DLabelPrivate::resetDirtyBits()
+{
+ QCustom3DItemPrivate::resetDirtyBits();
+ m_facingCameraDirty = false;
+}
+
+void QCustom3DLabelPrivate::createTextureImage()
+{
+ createTextureImage(m_bgrColor, m_txtColor, m_background, m_borders);
+}
+
+void QCustom3DLabelPrivate::createTextureImage(const QColor &bgrColor, const QColor &txtColor,
+ bool background, bool borders)
+{
+ m_textureImage = Utils::printTextToImage(m_font, m_text, bgrColor, txtColor, background,
+ borders, 0);
+}
+
+void QCustom3DLabelPrivate::handleTextureChange()
+{
+ createTextureImage();
+ m_dirtyBits.textureDirty = true;
+ if (!m_textureFile.isEmpty()) {
+ m_textureFile.clear();
+ emit q_ptr->textureFileChanged(m_textureFile);
+ }
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qcustom3dlabel.h b/src/datavisualization/data/qcustom3dlabel.h
new file mode 100644
index 00000000..f42ee378
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dlabel.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#ifndef QCUSTOMLABELITEM_H
+#define QCUSTOMLABELITEM_H
+
+#include <QtDataVisualization/qdatavisualizationglobal.h>
+#include <QtDataVisualization/QCustom3DItem>
+#include <QtGui/QVector3D>
+#include <QtGui/QQuaternion>
+#include <QtGui/QFont>
+#include <QtGui/QColor>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QCustom3DLabelPrivate;
+
+class QT_DATAVISUALIZATION_EXPORT QCustom3DLabel : public QCustom3DItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor NOTIFY textColorChanged)
+ Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged)
+ Q_PROPERTY(bool borderEnabled READ isBorderEnabled WRITE setBorderEnabled NOTIFY borderEnabledChanged)
+ Q_PROPERTY(bool backgroundEnabled READ isBackgroundEnabled WRITE setBackgroundEnabled NOTIFY backgroundEnabledChanged)
+ Q_PROPERTY(bool facingCamera READ isFacingCamera WRITE setFacingCamera NOTIFY facingCameraChanged)
+
+public:
+ explicit QCustom3DLabel(QObject *parent = 0);
+ explicit QCustom3DLabel(const QString &text, const QFont &font, const QVector3D &position,
+ const QVector3D &scaling, const QQuaternion &rotation,
+ QObject *parent = 0);
+ virtual ~QCustom3DLabel();
+
+ void setText(const QString &text);
+ QString text() const;
+
+ void setFont(const QFont &font);
+ QFont font() const;
+
+ void setTextColor(const QColor &color);
+ QColor textColor() const;
+
+ void setBackgroundColor(const QColor &color);
+ QColor backgroundColor() const;
+
+ void setBorderEnabled(bool enabled);
+ bool isBorderEnabled() const;
+
+ void setBackgroundEnabled(bool enabled);
+ bool isBackgroundEnabled() const;
+
+ void setFacingCamera(bool enabled);
+ bool isFacingCamera() const;
+
+signals:
+ void textChanged(const QString &text);
+ void fontChanged(const QFont &font);
+ void textColorChanged(const QColor &color);
+ void backgroundColorChanged(const QColor &color);
+ void borderEnabledChanged(bool enabled);
+ void backgroundEnabledChanged(bool enabled);
+ void facingCameraChanged(bool enabled);
+
+protected:
+ QCustom3DLabelPrivate *dptr();
+ const QCustom3DLabelPrivate *dptrc() const;
+
+private:
+ Q_DISABLE_COPY(QCustom3DLabel)
+
+ friend class Abstract3DRenderer;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/qcustom3dlabel_p.h b/src/datavisualization/data/qcustom3dlabel_p.h
new file mode 100644
index 00000000..0bb0e017
--- /dev/null
+++ b/src/datavisualization/data/qcustom3dlabel_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QCUSTOMLABELITEM_P_H
+#define QCUSTOMLABELITEM_P_H
+
+#include "qcustom3dlabel.h"
+#include "qcustom3ditem_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class QCustom3DLabelPrivate : public QCustom3DItemPrivate
+{
+ Q_OBJECT
+
+public:
+ QCustom3DLabelPrivate(QCustom3DLabel *q);
+ QCustom3DLabelPrivate(QCustom3DLabel *q, const QString &text, const QFont &font,
+ const QVector3D &position, const QVector3D &scaling,
+ const QQuaternion &rotation);
+ virtual ~QCustom3DLabelPrivate();
+
+ void resetDirtyBits();
+ void createTextureImage();
+ void createTextureImage(const QColor &bgrColor, const QColor &txtColor, bool background,
+ bool borders);
+ void handleTextureChange();
+
+public:
+ QString m_text;
+ QFont m_font;
+ QColor m_bgrColor;
+ QColor m_txtColor;
+ bool m_background;
+ bool m_borders;
+ bool m_facingCamera;
+
+ bool m_customVisuals;
+
+ bool m_facingCameraDirty;
+
+private:
+ friend class QCustom3DLabel;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
index 56fcf5d1..d64046be 100644
--- a/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qheightmapsurfacedataproxy.cpp
@@ -28,7 +28,7 @@ const float defaultMaxValue = 10.0f;
* \class QHeightMapSurfaceDataProxy
* \inmodule QtDataVisualization
* \brief Base proxy class for Q3DSurface.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QHeightMapSurfaceDataProxy takes care of surface related height map data handling. It provides a
* way to give a height map to be visualized as a surface plot.
diff --git a/src/datavisualization/data/qitemmodelbardataproxy.cpp b/src/datavisualization/data/qitemmodelbardataproxy.cpp
index 2281e33f..3d4a980a 100644
--- a/src/datavisualization/data/qitemmodelbardataproxy.cpp
+++ b/src/datavisualization/data/qitemmodelbardataproxy.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QItemModelBarDataProxy
* \inmodule QtDataVisualization
* \brief Proxy class for presenting data in item models with Q3DBars.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QItemModelBarDataProxy allows you to use QAbstractItemModel derived models as a data source
* for Q3DBars. It uses the defined mappings to map data from the model to rows, columns, and
@@ -33,6 +33,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* The data is resolved asynchronously whenever mappings or the model changes.
* QBarDataProxy::arrayReset() is emitted when the data has been resolved.
+ * However, when useModelCategories property is set to true, single item changes are resolved
+ * synchronously, unless the same frame also contains a change that causes the whole model to be
+ * resolved.
*
* There are three ways to use mappings:
*
@@ -50,12 +53,22 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* and in which order by defining an explicit list of categories for either or both of rows and
* columns.
*
- * For example, assume that you have a custom QAbstractItemModel for storing various monthly values
- * related to a business.
- * Each item in the model has the roles "year", "month", "income", and "expenses".
- * You could do the following to display the data in a bar graph:
+ * For example, assume that you have a custom QAbstractItemModel for storing various monthly values
+ * related to a business.
+ * Each item in the model has the roles "year", "month", "income", and "expenses".
+ * You could do the following to display the data in a bar graph:
+ *
+ * \snippet doc_src_qtdatavisualization.cpp 3
+ *
+ * If the fields of the model do not contain the data in the exact format you need, you can specify
+ * a search pattern regular expression and a replace rule for each role to get the value in a
+ * format you need. For more information how the replace using regular expressions works, see
+ * QString::replace(const QRegExp &rx, const QString &after) function documentation. Note that
+ * using regular expressions has an impact on the performance, so it's more efficient to utilize
+ * item models where doing search and replace is not necessary to get the desired values.
*
- * \snippet doc_src_qtdatavisualization.cpp 3
+ * For example about using the search patterns in conjunction with the roles, see
+ * \l{Qt Quick 2 Bars Example}.
*
* \sa {Qt Data Visualization Data Handling}
*/
@@ -74,6 +87,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* Data is resolved asynchronously whenever the mapping or the model changes.
* QBarDataProxy::arrayReset() is emitted when the data has been resolved.
*
+ * For ItemModelBarDataProxy enums, see \l{QItemModelBarDataProxy::MultiMatchBehavior}.
+ *
* For more details, see QItemModelBarDataProxy documentation.
*
* Usage example:
@@ -90,35 +105,36 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*!
* \qmlproperty string ItemModelBarDataProxy::rowRole
- * The row role of the mapping.
+ * Defines the item model role to map into row category.
*/
/*!
* \qmlproperty string ItemModelBarDataProxy::columnRole
- * The column role of the mapping.
+ * Defines the item model role to map into column category.
*/
/*!
* \qmlproperty string ItemModelBarDataProxy::valueRole
- * The value role of the mapping.
+ * Defines the item model role to map into bar value.
*/
/*!
* \qmlproperty string ItemModelBarDataProxy::rotationRole
- *
- * Defines the rotation role for the mapping.
+ * Defines the item model role to map into bar rotation angle.
*/
/*!
* \qmlproperty list<String> ItemModelBarDataProxy::rowCategories
- * The row categories of the mapping. Only items with row roles that are found in this list are
- * included when the data is resolved. The rows are ordered in the same order as they are in this list.
+ * The row categories of the mapping. Only items with row role values that are found in this list
+ * are included when the data is resolved. The rows are ordered in the same order as they are in
+ * this list.
*/
/*!
* \qmlproperty list<String> ItemModelBarDataProxy::columnCategories
- * The column categories of the mapping. Only items with column roles that are found in this list are
- * included when the data is resolved. The columns are ordered in the same order as they are in this list.
+ * The column categories of the mapping. Only items with column role values that are found in this
+ * list are included when the data is resolved. The columns are ordered in the same order as they
+ * are in this list.
*/
/*!
@@ -143,6 +159,117 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ * \qmlproperty regExp ItemModelBarDataProxy::rowRolePattern
+ * When set, a search and replace is done on the value mapped by row role before it is used as
+ * a row category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and rowRoleReplace property contains the replacement string.
+ * This is useful for example in parsing row and column categories from a single
+ * timestamp field in the item model.
+ *
+ * \sa rowRole, rowRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelBarDataProxy::columnRolePattern
+ * When set, a search and replace is done on the value mapped by column role before it is used
+ * as a column category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and columnRoleReplace property contains the replacement string.
+ * This is useful for example in parsing row and column categories from
+ * a single timestamp field in the item model.
+ *
+ * \sa columnRole, columnRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelBarDataProxy::valueRolePattern
+ * When set, a search and replace is done on the value mapped by value role before it is used as
+ * a bar value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and valueRoleReplace property contains the replacement string.
+ *
+ * \sa valueRole, valueRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelBarDataProxy::rotationRolePattern
+ * When set, a search and replace is done on the value mapped by rotation role before it is used
+ * as a bar rotation angle. This property specifies the regular expression to find the portion
+ * of the mapped value to replace and rotationRoleReplace property contains the replacement string.
+ *
+ * \sa rotationRole, rotationRoleReplace
+ */
+
+/*!
+ * \qmlproperty string ItemModelBarDataProxy::rowRoleReplace
+ * This property defines the replace content to be used in conjunction with rowRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rowRole, rowRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelBarDataProxy::columnRoleReplace
+ * This property defines the replace content to be used in conjunction with columnRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa columnRole, columnRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelBarDataProxy::valueRoleReplace
+ * This property defines the replace content to be used in conjunction with valueRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa valueRole, valueRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelBarDataProxy::rotationRoleReplace
+ * This property defines the replace content to be used in conjunction with rotationRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rotationRole, rotationRolePattern
+ */
+
+/*!
+ * \qmlproperty ItemModelBarDataProxy.MultiMatchBehavior ItemModelBarDataProxy::multiMatchBehavior
+ * This property defines how multiple matches for each row/column combination are handled.
+ * Defaults to ItemModelBarDataProxy.MMBLast. The chosen behavior affects both bar value
+ * and rotation.
+ *
+ * For example, you might have an item model with timestamped data taken at irregular intervals
+ * and you want to visualize total value of data items on each day with a bar graph.
+ * This can be done by specifying row and column categories so that each bar represents a day,
+ * and setting multiMatchBehavior to ItemModelBarDataProxy.MMBCumulative.
+ */
+
+/*!
+ * \enum QItemModelBarDataProxy::MultiMatchBehavior
+ *
+ * Behavior types for QItemModelBarDataProxy::multiMatchBehavior property.
+ *
+ * \value MMBFirst
+ * The value is taken from the first item in the item model that matches
+ * each row/column combination.
+ * \value MMBLast
+ * The value is taken from the last item in the item model that matches
+ * each row/column combination.
+ * \value MMBAverage
+ * The values from all items matching each row/column combination are
+ * averaged together and the average is used as the bar value.
+ * \value MMBCumulative
+ * The values from all items matching each row/column combination are
+ * added together and the total is used as the bar value.
+ */
+
+/*!
* Constructs QItemModelBarDataProxy with optional \a parent.
*/
QItemModelBarDataProxy::QItemModelBarDataProxy(QObject *parent)
@@ -155,7 +282,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(QObject *parent)
* Constructs QItemModelBarDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
* ownership of the \a itemModel, as typically item models are owned by other controls.
*/
-QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel, QObject *parent)
+QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel, QObject *parent)
: QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
setItemModel(itemModel);
@@ -169,7 +296,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod
* This constructor is meant to be used with models that have data properly sorted
* in rows and columns already, so it also sets useModelCategories property to true.
*/
-QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
const QString &valueRole, QObject *parent)
: QBarDataProxy(new QItemModelBarDataProxyPrivate(this), parent)
{
@@ -184,7 +311,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod
* ownership of the \a itemModel, as typically item models are owned by other controls.
* The role mappings are set with \a rowRole, \a columnRole, and \a valueRole.
*/
-QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &valueRole, QObject *parent)
@@ -202,7 +329,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod
* ownership of the \a itemModel, as typically item models are owned by other controls.
* The role mappings are set with \a rowRole, \a columnRole, \a valueRole, and \a rotationRole.
*/
-QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &valueRole,
@@ -225,7 +352,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod
* Row and column categories are set with \a rowCategories and \a columnCategories.
* This constructor also sets autoRowCategories and autoColumnCategories to false.
*/
-QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &valueRole,
@@ -252,7 +379,7 @@ QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemMod
* Row and column categories are set with \a rowCategories and \a columnCategories.
* This constructor also sets autoRowCategories and autoColumnCategories to false.
*/
-QItemModelBarDataProxy::QItemModelBarDataProxy(const QAbstractItemModel *itemModel,
+QItemModelBarDataProxy::QItemModelBarDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &valueRole,
@@ -287,12 +414,12 @@ QItemModelBarDataProxy::~QItemModelBarDataProxy()
* Defines item model. Does not take ownership of the model, but does connect to it to listen for
* changes.
*/
-void QItemModelBarDataProxy::setItemModel(const QAbstractItemModel *itemModel)
+void QItemModelBarDataProxy::setItemModel(QAbstractItemModel *itemModel)
{
dptr()->m_itemModelHandler->setItemModel(itemModel);
}
-const QAbstractItemModel *QItemModelBarDataProxy::itemModel() const
+QAbstractItemModel *QItemModelBarDataProxy::itemModel() const
{
return dptrc()->m_itemModelHandler->itemModel();
}
@@ -506,6 +633,215 @@ int QItemModelBarDataProxy::columnCategoryIndex(const QString &category)
}
/*!
+ * \property QItemModelBarDataProxy::rowRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by row role before it is used as
+ * a row category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and rowRoleReplace property contains the replacement string.
+ * This is useful for example in parsing row and column categories from a single
+ * timestamp field in the item model.
+ *
+ * \sa rowRole, rowRoleReplace
+ */
+void QItemModelBarDataProxy::setRowRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_rowRolePattern != pattern) {
+ dptr()->m_rowRolePattern = pattern;
+ emit rowRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelBarDataProxy::rowRolePattern() const
+{
+ return dptrc()->m_rowRolePattern;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::columnRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by column role before it is used
+ * as a column category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and columnRoleReplace property contains the replacement string.
+ * This is useful for example in parsing row and column categories from
+ * a single timestamp field in the item model.
+ *
+ * \sa columnRole, columnRoleReplace
+ */
+void QItemModelBarDataProxy::setColumnRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_columnRolePattern != pattern) {
+ dptr()->m_columnRolePattern = pattern;
+ emit columnRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelBarDataProxy::columnRolePattern() const
+{
+ return dptrc()->m_columnRolePattern;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::valueRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by value role before it is used as
+ * a bar value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and valueRoleReplace property contains the replacement string.
+ *
+ * \sa valueRole, valueRoleReplace
+ */
+void QItemModelBarDataProxy::setValueRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_valueRolePattern != pattern) {
+ dptr()->m_valueRolePattern = pattern;
+ emit valueRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelBarDataProxy::valueRolePattern() const
+{
+ return dptrc()->m_valueRolePattern;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::rotationRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by rotation role before it is used
+ * as a bar rotation angle. This property specifies the regular expression to find the portion
+ * of the mapped value to replace and rotationRoleReplace property contains the replacement string.
+ *
+ * \sa rotationRole, rotationRoleReplace
+ */
+void QItemModelBarDataProxy::setRotationRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_rotationRolePattern != pattern) {
+ dptr()->m_rotationRolePattern = pattern;
+ emit rotationRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelBarDataProxy::rotationRolePattern() const
+{
+ return dptrc()->m_rotationRolePattern;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::rowRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with rowRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rowRole, rowRolePattern
+ */
+void QItemModelBarDataProxy::setRowRoleReplace(const QString &replace)
+{
+ if (dptr()->m_rowRoleReplace != replace) {
+ dptr()->m_rowRoleReplace = replace;
+ emit rowRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelBarDataProxy::rowRoleReplace() const
+{
+ return dptrc()->m_rowRoleReplace;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::columnRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with columnRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa columnRole, columnRolePattern
+ */
+void QItemModelBarDataProxy::setColumnRoleReplace(const QString &replace)
+{
+ if (dptr()->m_columnRoleReplace != replace) {
+ dptr()->m_columnRoleReplace = replace;
+ emit columnRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelBarDataProxy::columnRoleReplace() const
+{
+ return dptrc()->m_columnRoleReplace;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::valueRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with valueRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa valueRole, valueRolePattern
+ */
+void QItemModelBarDataProxy::setValueRoleReplace(const QString &replace)
+{
+ if (dptr()->m_valueRoleReplace != replace) {
+ dptr()->m_valueRoleReplace = replace;
+ emit valueRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelBarDataProxy::valueRoleReplace() const
+{
+ return dptrc()->m_valueRoleReplace;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::rotationRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with rotationRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rotationRole, rotationRolePattern
+ */
+void QItemModelBarDataProxy::setRotationRoleReplace(const QString &replace)
+{
+ if (dptr()->m_rotationRoleReplace != replace) {
+ dptr()->m_rotationRoleReplace = replace;
+ emit rotationRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelBarDataProxy::rotationRoleReplace() const
+{
+ return dptrc()->m_rotationRoleReplace;
+}
+
+/*!
+ * \property QItemModelBarDataProxy::multiMatchBehavior
+ *
+ * This property defines how multiple matches for each row/column combination are handled.
+ * Defaults to QItemModelBarDataProxy::MMBLast. The chosen behavior affects both bar value
+ * and rotation.
+ *
+ * For example, you might have an item model with timestamped data taken at irregular intervals
+ * and you want to visualize total value of data items on each day with a bar graph.
+ * This can be done by specifying row and column categories so that each bar represents a day,
+ * and setting multiMatchBehavior to QItemModelBarDataProxy::MMBCumulative.
+ */
+void QItemModelBarDataProxy::setMultiMatchBehavior(QItemModelBarDataProxy::MultiMatchBehavior behavior)
+{
+ if (dptr()->m_multiMatchBehavior != behavior) {
+ dptr()->m_multiMatchBehavior = behavior;
+ emit multiMatchBehaviorChanged(behavior);
+ }
+}
+
+QItemModelBarDataProxy::MultiMatchBehavior QItemModelBarDataProxy::multiMatchBehavior() const
+{
+ return dptrc()->m_multiMatchBehavior;
+}
+
+/*!
* \internal
*/
QItemModelBarDataProxyPrivate *QItemModelBarDataProxy::dptr()
@@ -528,7 +864,8 @@ QItemModelBarDataProxyPrivate::QItemModelBarDataProxyPrivate(QItemModelBarDataPr
m_itemModelHandler(new BarItemModelHandler(q)),
m_useModelCategories(false),
m_autoRowCategories(true),
- m_autoColumnCategories(true)
+ m_autoColumnCategories(true),
+ m_multiMatchBehavior(QItemModelBarDataProxy::MMBLast)
{
}
@@ -564,6 +901,24 @@ void QItemModelBarDataProxyPrivate::connectItemModelHandler()
m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
QObject::connect(qptr(), &QItemModelBarDataProxy::autoColumnCategoriesChanged,
m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::rowRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::columnRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::valueRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::rowRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::columnRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::valueRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::rotationRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelBarDataProxy::multiMatchBehaviorChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
}
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qitemmodelbardataproxy.h b/src/datavisualization/data/qitemmodelbardataproxy.h
index f19b4445..d7394dcf 100644
--- a/src/datavisualization/data/qitemmodelbardataproxy.h
+++ b/src/datavisualization/data/qitemmodelbardataproxy.h
@@ -21,6 +21,7 @@
#include <QtDataVisualization/qbardataproxy.h>
#include <QtCore/QAbstractItemModel>
+#include <QtCore/QRegExp>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -29,7 +30,8 @@ class QItemModelBarDataProxyPrivate;
class QT_DATAVISUALIZATION_EXPORT QItemModelBarDataProxy : public QBarDataProxy
{
Q_OBJECT
- Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged)
+ Q_ENUMS(MultiMatchBehavior)
+ Q_PROPERTY(QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged)
Q_PROPERTY(QString rowRole READ rowRole WRITE setRowRole NOTIFY rowRoleChanged)
Q_PROPERTY(QString columnRole READ columnRole WRITE setColumnRole NOTIFY columnRoleChanged)
Q_PROPERTY(QString valueRole READ valueRole WRITE setValueRole NOTIFY valueRoleChanged)
@@ -39,30 +41,46 @@ class QT_DATAVISUALIZATION_EXPORT QItemModelBarDataProxy : public QBarDataProxy
Q_PROPERTY(bool useModelCategories READ useModelCategories WRITE setUseModelCategories NOTIFY useModelCategoriesChanged)
Q_PROPERTY(bool autoRowCategories READ autoRowCategories WRITE setAutoRowCategories NOTIFY autoRowCategoriesChanged)
Q_PROPERTY(bool autoColumnCategories READ autoColumnCategories WRITE setAutoColumnCategories NOTIFY autoColumnCategoriesChanged)
+ Q_PROPERTY(QRegExp rowRolePattern READ rowRolePattern WRITE setRowRolePattern NOTIFY rowRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp columnRolePattern READ columnRolePattern WRITE setColumnRolePattern NOTIFY columnRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp valueRolePattern READ valueRolePattern WRITE setValueRolePattern NOTIFY valueRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp rotationRolePattern READ rotationRolePattern WRITE setRotationRolePattern NOTIFY rotationRolePatternChanged REVISION 1)
+ Q_PROPERTY(QString rowRoleReplace READ rowRoleReplace WRITE setRowRoleReplace NOTIFY rowRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString columnRoleReplace READ columnRoleReplace WRITE setColumnRoleReplace NOTIFY columnRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString valueRoleReplace READ valueRoleReplace WRITE setValueRoleReplace NOTIFY valueRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString rotationRoleReplace READ rotationRoleReplace WRITE setRotationRoleReplace NOTIFY rotationRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(MultiMatchBehavior multiMatchBehavior READ multiMatchBehavior WRITE setMultiMatchBehavior NOTIFY multiMatchBehaviorChanged REVISION 1)
public:
+ enum MultiMatchBehavior {
+ MMBFirst = 0,
+ MMBLast = 1,
+ MMBAverage = 2,
+ MMBCumulative = 3
+ };
+
explicit QItemModelBarDataProxy(QObject *parent = 0);
- QItemModelBarDataProxy(const QAbstractItemModel *itemModel, QObject *parent = 0);
- QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &valueRole,
+ QItemModelBarDataProxy(QAbstractItemModel *itemModel, QObject *parent = 0);
+ QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &valueRole,
QObject *parent = 0);
- QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &valueRole,
QObject *parent = 0);
- QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &valueRole,
const QString &rotationRole, QObject *parent = 0);
- QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &valueRole,
const QStringList &rowCategories, const QStringList &columnCategories,
QObject *parent = 0);
- QItemModelBarDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelBarDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &valueRole,
const QString &rotationRole, const QStringList &rowCategories,
const QStringList &columnCategories, QObject *parent = 0);
virtual ~QItemModelBarDataProxy();
- void setItemModel(const QAbstractItemModel *itemModel);
- const QAbstractItemModel *itemModel() const;
+ void setItemModel(QAbstractItemModel *itemModel);
+ QAbstractItemModel *itemModel() const;
void setRowRole(const QString &role);
QString rowRole() const;
@@ -93,6 +111,27 @@ public:
Q_INVOKABLE int rowCategoryIndex(const QString& category);
Q_INVOKABLE int columnCategoryIndex(const QString& category);
+ void setRowRolePattern(const QRegExp &pattern);
+ QRegExp rowRolePattern() const;
+ void setColumnRolePattern(const QRegExp &pattern);
+ QRegExp columnRolePattern() const;
+ void setValueRolePattern(const QRegExp &pattern);
+ QRegExp valueRolePattern() const;
+ void setRotationRolePattern(const QRegExp &pattern);
+ QRegExp rotationRolePattern() const;
+
+ void setRowRoleReplace(const QString &replace);
+ QString rowRoleReplace() const;
+ void setColumnRoleReplace(const QString &replace);
+ QString columnRoleReplace() const;
+ void setValueRoleReplace(const QString &replace);
+ QString valueRoleReplace() const;
+ void setRotationRoleReplace(const QString &replace);
+ QString rotationRoleReplace() const;
+
+ void setMultiMatchBehavior(MultiMatchBehavior behavior);
+ MultiMatchBehavior multiMatchBehavior() const;
+
signals:
void itemModelChanged(const QAbstractItemModel* itemModel);
void rowRoleChanged(const QString &role);
@@ -104,6 +143,15 @@ signals:
void useModelCategoriesChanged(bool enable);
void autoRowCategoriesChanged(bool enable);
void autoColumnCategoriesChanged(bool enable);
+ Q_REVISION(1) void rowRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void columnRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void valueRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void rotationRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void rowRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void columnRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void valueRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void rotationRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void multiMatchBehaviorChanged(MultiMatchBehavior behavior);
protected:
QItemModelBarDataProxyPrivate *dptr();
diff --git a/src/datavisualization/data/qitemmodelbardataproxy_p.h b/src/datavisualization/data/qitemmodelbardataproxy_p.h
index 2fd74bb2..84564d02 100644
--- a/src/datavisualization/data/qitemmodelbardataproxy_p.h
+++ b/src/datavisualization/data/qitemmodelbardataproxy_p.h
@@ -63,6 +63,18 @@ private:
bool m_autoRowCategories;
bool m_autoColumnCategories;
+ QRegExp m_rowRolePattern;
+ QRegExp m_columnRolePattern;
+ QRegExp m_valueRolePattern;
+ QRegExp m_rotationRolePattern;
+
+ QString m_rowRoleReplace;
+ QString m_columnRoleReplace;
+ QString m_valueRoleReplace;
+ QString m_rotationRoleReplace;
+
+ QItemModelBarDataProxy::MultiMatchBehavior m_multiMatchBehavior;
+
friend class BarItemModelHandler;
friend class QItemModelBarDataProxy;
};
diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy.cpp b/src/datavisualization/data/qitemmodelscatterdataproxy.cpp
index 16a7b8b5..4e6464ea 100644
--- a/src/datavisualization/data/qitemmodelscatterdataproxy.cpp
+++ b/src/datavisualization/data/qitemmodelscatterdataproxy.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QItemModelScatterDataProxy
* \inmodule QtDataVisualization
* \brief Proxy class for presenting data in item models with Q3DScatter.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QItemModelScatterDataProxy allows you to use QAbstractItemModel derived models as a data source
* for Q3DScatter. It maps roles of QAbstractItemModel to the XYZ-values of Q3DScatter points.
@@ -36,7 +36,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* unless the same frame also contains a change that causes the whole model to be resolved.
*
* Mapping ignores rows and columns of the QAbstractItemModel and treats
- * all items equally. It requires the model to provide at least three roles for the data items
+ * all items equally. It requires the model to provide roles for the data items
* that can be mapped to X, Y, and Z-values for the scatter points.
*
* For example, assume that you have a custom QAbstractItemModel for storing various measurements
@@ -45,6 +45,16 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* \snippet doc_src_qtdatavisualization.cpp 4
*
+ * If the fields of the model do not contain the data in the exact format you need, you can specify
+ * a search pattern regular expression and a replace rule for each role to get the value in a
+ * format you need. For more information how the replace using regular expressions works, see
+ * QString::replace(const QRegExp &rx, const QString &after) function documentation. Note that
+ * using regular expressions has an impact on the performance, so it's more efficient to utilize
+ * item models where doing search and replace is not necessary to get the desired values.
+ *
+ * For example about using the search patterns in conjunction with the roles, see
+ * ItemModelBarDataProxy usage in \l{Qt Quick 2 Bars Example}.
+ *
* \sa {Qt Data Visualization Data Handling}
*/
@@ -78,27 +88,109 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*!
* \qmlproperty string ItemModelScatterDataProxy::xPosRole
- * The X position role of the mapping.
+ * Defines the item model role to map into X position.
*/
/*!
* \qmlproperty string ItemModelScatterDataProxy::yPosRole
- * The Y position role of the mapping.
+ * Defines the item model role to map into Y position.
*/
/*!
* \qmlproperty string ItemModelScatterDataProxy::zPosRole
- * The Z position role of the mapping.
+ * Defines the item model role to map into Z position.
*/
/*!
* \qmlproperty string ItemModelScatterDataProxy::rotationRole
*
- * Defines the rotation role for the mapping.
+ * Defines the item model role to map into item rotation.
* The model may supply the value for rotation as either variant that is directly convertible
- * to QQuaternion, or as one of the string representations: \c{"scalar,x,y,z"} or \c{"@angle,x,y,z"}. The first
- * will construct the quaternion directly with given values, and the second one will construct
- * the quaternion using QQuaternion::fromAxisAndAngle() method.
+ * to QQuaternion, or as one of the string representations: \c{"scalar,x,y,z"} or
+ * \c{"@angle,x,y,z"}. The first format will construct the quaternion directly with given values,
+ * and the second one will construct the quaternion using QQuaternion::fromAxisAndAngle() method.
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelScatterDataProxy::xPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by xPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and xPosRoleReplace property contains the replacement string.
+ *
+ * \sa xPosRole, xPosRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelScatterDataProxy::yPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by yPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and yPosRoleReplace property contains the replacement string.
+ *
+ * \sa yPosRole, yPosRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelScatterDataProxy::zPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by zPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and zPosRoleReplace property contains the replacement string.
+ *
+ * \sa zPosRole, zPosRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelScatterDataProxy::rotationRolePattern
+ * When set, a search and replace is done on the value mapped by rotation role before it is used
+ * as a item rotation. This property specifies the regular expression to find the portion
+ * of the mapped value to replace and rotationRoleReplace property contains the replacement string.
+ *
+ * \sa rotationRole, rotationRoleReplace
+ */
+
+/*!
+ * \qmlproperty string ItemModelScatterDataProxy::xPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with xPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa xPosRole, xPosRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelScatterDataProxy::yPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with yPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa yPosRole, yPosRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelScatterDataProxy::zPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with zPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa zPosRole, zPosRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelScatterDataProxy::rotationRoleReplace
+ * This property defines the replace content to be used in conjunction with rotationRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rotationRole, rotationRolePattern
*/
/*!
@@ -114,7 +206,7 @@ QItemModelScatterDataProxy::QItemModelScatterDataProxy(QObject *parent)
* Constructs QItemModelScatterDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
* ownership of the \a itemModel, as typically item models are owned by other controls.
*/
-QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+QItemModelScatterDataProxy::QItemModelScatterDataProxy(QAbstractItemModel *itemModel,
QObject *parent)
: QScatterDataProxy(new QItemModelScatterDataProxyPrivate(this), parent)
{
@@ -128,7 +220,7 @@ QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel
* The xPosRole property is set to \a xPosRole, yPosRole property to \a yPosRole, and zPosRole property
* to \a zPosRole.
*/
-QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+QItemModelScatterDataProxy::QItemModelScatterDataProxy(QAbstractItemModel *itemModel,
const QString &xPosRole,
const QString &yPosRole,
const QString &zPosRole,
@@ -148,7 +240,7 @@ QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel
* The xPosRole property is set to \a xPosRole, yPosRole property to \a yPosRole, zPosRole property
* to \a zPosRole, and rotationRole property to \a rotationRole.
*/
-QItemModelScatterDataProxy::QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+QItemModelScatterDataProxy::QItemModelScatterDataProxy(QAbstractItemModel *itemModel,
const QString &xPosRole,
const QString &yPosRole,
const QString &zPosRole,
@@ -177,12 +269,12 @@ QItemModelScatterDataProxy::~QItemModelScatterDataProxy()
* Defines the item model. Does not take ownership of the model, but does connect to it to listen for
* changes.
*/
-void QItemModelScatterDataProxy::setItemModel(const QAbstractItemModel *itemModel)
+void QItemModelScatterDataProxy::setItemModel(QAbstractItemModel *itemModel)
{
dptr()->m_itemModelHandler->setItemModel(itemModel);
}
-const QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const
+QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const
{
return dptrc()->m_itemModelHandler->itemModel();
}
@@ -190,7 +282,7 @@ const QAbstractItemModel *QItemModelScatterDataProxy::itemModel() const
/*!
* \property QItemModelScatterDataProxy::xPosRole
*
- * Defines the X position \a role for the mapping.
+ * Defines the item model role to map into X position.
*/
void QItemModelScatterDataProxy::setXPosRole(const QString &role)
{
@@ -208,7 +300,7 @@ QString QItemModelScatterDataProxy::xPosRole() const
/*!
* \property QItemModelScatterDataProxy::yPosRole
*
- * Defines the Y position \a role for the mapping.
+ * Defines the item model role to map into Y position.
*/
void QItemModelScatterDataProxy::setYPosRole(const QString &role)
{
@@ -226,7 +318,7 @@ QString QItemModelScatterDataProxy::yPosRole() const
/*!
* \property QItemModelScatterDataProxy::zPosRole
*
- * Defines the Z position \a role for the mapping.
+ * Defines the item model role to map into Z position.
*/
void QItemModelScatterDataProxy::setZPosRole(const QString &role)
{
@@ -244,7 +336,7 @@ QString QItemModelScatterDataProxy::zPosRole() const
/*!
* \property QItemModelScatterDataProxy::rotationRole
*
- * Defines the rotation \a role for the mapping.
+ * Defines the item model role to map into item rotation.
*
* The model may supply the value for rotation as either variant that is directly convertible
* to QQuaternion, or as one of the string representations: \c{"scalar,x,y,z"} or \c{"@angle,x,y,z"}.
@@ -265,6 +357,186 @@ QString QItemModelScatterDataProxy::rotationRole() const
}
/*!
+ * \property QItemModelScatterDataProxy::xPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by xPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and xPosRoleReplace property contains the replacement string.
+ *
+ * \sa xPosRole, xPosRoleReplace
+ */
+void QItemModelScatterDataProxy::setXPosRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_xPosRolePattern != pattern) {
+ dptr()->m_xPosRolePattern = pattern;
+ emit xPosRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelScatterDataProxy::xPosRolePattern() const
+{
+ return dptrc()->m_xPosRolePattern;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::yPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by yPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and yPosRoleReplace property contains the replacement string.
+ *
+ * \sa yPosRole, yPosRoleReplace
+ */
+void QItemModelScatterDataProxy::setYPosRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_yPosRolePattern != pattern) {
+ dptr()->m_yPosRolePattern = pattern;
+ emit yPosRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelScatterDataProxy::yPosRolePattern() const
+{
+ return dptrc()->m_yPosRolePattern;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::zPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by zPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and zPosRoleReplace property contains the replacement string.
+ *
+ * \sa zPosRole, zPosRoleReplace
+ */
+void QItemModelScatterDataProxy::setZPosRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_zPosRolePattern != pattern) {
+ dptr()->m_zPosRolePattern = pattern;
+ emit zPosRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelScatterDataProxy::zPosRolePattern() const
+{
+ return dptrc()->m_zPosRolePattern;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::rotationRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by rotation role before it is used
+ * as a item rotation. This property specifies the regular expression to find the portion
+ * of the mapped value to replace and rotationRoleReplace property contains the replacement string.
+ *
+ * \sa rotationRole, rotationRoleReplace
+ */
+void QItemModelScatterDataProxy::setRotationRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_rotationRolePattern != pattern) {
+ dptr()->m_rotationRolePattern = pattern;
+ emit rotationRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelScatterDataProxy::rotationRolePattern() const
+{
+ return dptrc()->m_rotationRolePattern;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::xPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with xPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa xPosRole, xPosRolePattern
+ */
+void QItemModelScatterDataProxy::setXPosRoleReplace(const QString &replace)
+{
+ if (dptr()->m_xPosRoleReplace != replace) {
+ dptr()->m_xPosRoleReplace = replace;
+ emit xPosRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelScatterDataProxy::xPosRoleReplace() const
+{
+ return dptrc()->m_xPosRoleReplace;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::yPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with yPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa yPosRole, yPosRolePattern
+ */
+void QItemModelScatterDataProxy::setYPosRoleReplace(const QString &replace)
+{
+ if (dptr()->m_yPosRoleReplace != replace) {
+ dptr()->m_yPosRoleReplace = replace;
+ emit yPosRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelScatterDataProxy::yPosRoleReplace() const
+{
+ return dptrc()->m_yPosRoleReplace;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::zPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with zPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa zPosRole, zPosRolePattern
+ */
+void QItemModelScatterDataProxy::setZPosRoleReplace(const QString &replace)
+{
+ if (dptr()->m_zPosRoleReplace != replace) {
+ dptr()->m_zPosRoleReplace = replace;
+ emit zPosRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelScatterDataProxy::zPosRoleReplace() const
+{
+ return dptrc()->m_zPosRoleReplace;
+}
+
+/*!
+ * \property QItemModelScatterDataProxy::rotationRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with rotationRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rotationRole, rotationRolePattern
+ */
+void QItemModelScatterDataProxy::setRotationRoleReplace(const QString &replace)
+{
+ if (dptr()->m_rotationRoleReplace != replace) {
+ dptr()->m_rotationRoleReplace = replace;
+ emit rotationRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelScatterDataProxy::rotationRoleReplace() const
+{
+ return dptrc()->m_rotationRoleReplace;
+}
+
+/*!
* Changes \a xPosRole, \a yPosRole, \a zPosRole, and \a rotationRole mapping.
*/
void QItemModelScatterDataProxy::remap(const QString &xPosRole, const QString &yPosRole,
@@ -320,6 +592,24 @@ void QItemModelScatterDataProxyPrivate::connectItemModelHandler()
m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
QObject::connect(qptr(), &QItemModelScatterDataProxy::zPosRoleChanged,
m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::rotationRoleChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::xPosRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::yPosRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::zPosRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::rotationRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::xPosRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::yPosRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::zPosRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelScatterDataProxy::rotationRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
}
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy.h b/src/datavisualization/data/qitemmodelscatterdataproxy.h
index c6d2245d..3215c688 100644
--- a/src/datavisualization/data/qitemmodelscatterdataproxy.h
+++ b/src/datavisualization/data/qitemmodelscatterdataproxy.h
@@ -22,6 +22,7 @@
#include <QtDataVisualization/qscatterdataproxy.h>
#include <QtCore/QAbstractItemModel>
#include <QtCore/QString>
+#include <QtCore/QRegExp>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -30,26 +31,34 @@ class QItemModelScatterDataProxyPrivate;
class QT_DATAVISUALIZATION_EXPORT QItemModelScatterDataProxy : public QScatterDataProxy
{
Q_OBJECT
- Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged)
+ Q_PROPERTY(QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged)
Q_PROPERTY(QString xPosRole READ xPosRole WRITE setXPosRole NOTIFY xPosRoleChanged)
Q_PROPERTY(QString yPosRole READ yPosRole WRITE setYPosRole NOTIFY yPosRoleChanged)
Q_PROPERTY(QString zPosRole READ zPosRole WRITE setZPosRole NOTIFY zPosRoleChanged)
Q_PROPERTY(QString rotationRole READ rotationRole WRITE setRotationRole NOTIFY rotationRoleChanged)
+ Q_PROPERTY(QRegExp xPosRolePattern READ xPosRolePattern WRITE setXPosRolePattern NOTIFY xPosRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp yPosRolePattern READ yPosRolePattern WRITE setYPosRolePattern NOTIFY yPosRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp zPosRolePattern READ zPosRolePattern WRITE setZPosRolePattern NOTIFY zPosRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp rotationRolePattern READ rotationRolePattern WRITE setRotationRolePattern NOTIFY rotationRolePatternChanged REVISION 1)
+ Q_PROPERTY(QString xPosRoleReplace READ xPosRoleReplace WRITE setXPosRoleReplace NOTIFY xPosRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString yPosRoleReplace READ yPosRoleReplace WRITE setYPosRoleReplace NOTIFY yPosRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString zPosRoleReplace READ zPosRoleReplace WRITE setZPosRoleReplace NOTIFY zPosRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString rotationRoleReplace READ rotationRoleReplace WRITE setRotationRoleReplace NOTIFY rotationRoleReplaceChanged REVISION 1)
public:
explicit QItemModelScatterDataProxy(QObject *parent = 0);
- QItemModelScatterDataProxy(const QAbstractItemModel *itemModel, QObject *parent = 0);
- QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelScatterDataProxy(QAbstractItemModel *itemModel, QObject *parent = 0);
+ QItemModelScatterDataProxy(QAbstractItemModel *itemModel,
const QString &xPosRole, const QString &yPosRole,
const QString &zPosRole, QObject *parent = 0);
- QItemModelScatterDataProxy(const QAbstractItemModel *itemModel,
+ QItemModelScatterDataProxy(QAbstractItemModel *itemModel,
const QString &xPosRole, const QString &yPosRole,
const QString &zPosRole, const QString &rotationRole,
QObject *parent = 0);
virtual ~QItemModelScatterDataProxy();
- void setItemModel(const QAbstractItemModel *itemModel);
- const QAbstractItemModel *itemModel() const;
+ void setItemModel(QAbstractItemModel *itemModel);
+ QAbstractItemModel *itemModel() const;
void setXPosRole(const QString &role);
QString xPosRole() const;
@@ -63,12 +72,38 @@ public:
void remap(const QString &xPosRole, const QString &yPosRole, const QString &zPosRole,
const QString &rotationRole);
+ void setXPosRolePattern(const QRegExp &pattern);
+ QRegExp xPosRolePattern() const;
+ void setYPosRolePattern(const QRegExp &pattern);
+ QRegExp yPosRolePattern() const;
+ void setZPosRolePattern(const QRegExp &pattern);
+ QRegExp zPosRolePattern() const;
+ void setRotationRolePattern(const QRegExp &pattern);
+ QRegExp rotationRolePattern() const;
+
+ void setXPosRoleReplace(const QString &replace);
+ QString xPosRoleReplace() const;
+ void setYPosRoleReplace(const QString &replace);
+ QString yPosRoleReplace() const;
+ void setZPosRoleReplace(const QString &replace);
+ QString zPosRoleReplace() const;
+ void setRotationRoleReplace(const QString &replace);
+ QString rotationRoleReplace() const;
+
signals:
void itemModelChanged(const QAbstractItemModel* itemModel);
void xPosRoleChanged(const QString &role);
void yPosRoleChanged(const QString &role);
void zPosRoleChanged(const QString &role);
void rotationRoleChanged(const QString &role);
+ Q_REVISION(1) void xPosRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void yPosRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void zPosRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void rotationRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void rotationRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void xPosRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void yPosRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void zPosRoleReplaceChanged(const QString &replace);
protected:
QItemModelScatterDataProxyPrivate *dptr();
diff --git a/src/datavisualization/data/qitemmodelscatterdataproxy_p.h b/src/datavisualization/data/qitemmodelscatterdataproxy_p.h
index 4e1f321f..733cbb1e 100644
--- a/src/datavisualization/data/qitemmodelscatterdataproxy_p.h
+++ b/src/datavisualization/data/qitemmodelscatterdataproxy_p.h
@@ -54,6 +54,16 @@ private:
QString m_zPosRole;
QString m_rotationRole;
+ QRegExp m_xPosRolePattern;
+ QRegExp m_yPosRolePattern;
+ QRegExp m_zPosRolePattern;
+ QRegExp m_rotationRolePattern;
+
+ QString m_xPosRoleReplace;
+ QString m_yPosRoleReplace;
+ QString m_zPosRoleReplace;
+ QString m_rotationRoleReplace;
+
friend class ScatterItemModelHandler;
friend class QItemModelScatterDataProxy;
};
diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp
index 440ce2d6..5117d386 100644
--- a/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QItemModelSurfaceDataProxy
* \inmodule QtDataVisualization
* \brief Proxy class for presenting data in item models with Q3DSurface.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QItemModelSurfaceDataProxy allows you to use QAbstractItemModel derived models as a data source
* for Q3DSurface. It uses the defined mappings to map data from the model to rows, columns, and
@@ -33,6 +33,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* Data is resolved asynchronously whenever the mapping or the model changes.
* QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved.
+ * However, when useModelCategories property is set to true, single item changes are resolved
+ * synchronously, unless the same frame also contains a change that causes the whole model to be
+ * resolved.
*
* There are three ways to use mappings:
*
@@ -54,13 +57,24 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* and in which order by defining an explicit list of categories for either or both of rows and
* columns.
*
- * For example, assume that you have a custom QAbstractItemModel storing surface topography data.
- * Each item in the model has the roles "longitude", "latitude", and "height". The item model already
- * contains the data properly sorted so that longitudes and latitudes are first encountered in
- * correct order, which enables us to utilize the row and column category autogeneration.
- * You could do the following to display the data in a surface graph:
+ * For example, assume that you have a custom QAbstractItemModel storing surface topography data.
+ * Each item in the model has the roles "longitude", "latitude", and "height".
+ * The item model already contains the data properly sorted so that longitudes and latitudes are
+ * first encountered in correct order, which enables us to utilize the row and column category
+ * autogeneration.
+ * You could do the following to display the data in a surface graph:
+ *
+ * \snippet doc_src_qtdatavisualization.cpp 5
*
- * \snippet doc_src_qtdatavisualization.cpp 5
+ * If the fields of the model do not contain the data in the exact format you need, you can specify
+ * a search pattern regular expression and a replace rule for each role to get the value in a
+ * format you need. For more information how the replace using regular expressions works, see
+ * QString::replace(const QRegExp &rx, const QString &after) function documentation. Note that
+ * using regular expressions has an impact on the performance, so it's more efficient to utilize
+ * item models where doing search and replace is not necessary to get the desired values.
+ *
+ * For example about using the search patterns in conjunction with the roles, see
+ * ItemModelBarDataProxy usage in \l{Qt Quick 2 Bars Example}.
*
* \sa {Qt Data Visualization Data Handling}
*/
@@ -79,6 +93,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* Data is resolved asynchronously whenever the mapping or the model changes.
* QSurfaceDataProxy::arrayReset() is emitted when the data has been resolved.
*
+ * For ItemModelSurfaceDataProxy enums, see \l{QItemModelSurfaceDataProxy::MultiMatchBehavior}.
+ *
* For more details, see QItemModelSurfaceDataProxy documentation.
*
* Usage example:
@@ -95,33 +111,35 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*!
* \qmlproperty string ItemModelSurfaceDataProxy::rowRole
- * The row role of the mapping.
+ * Defines the item model role to map into row category.
* In addition to defining which row the data belongs to, the value indicated by row role
- * is also set as the Z-coordinate value of the QSurfaceDataItem when model data is resolved.
+ * is also set as the Z-coordinate value of the QSurfaceDataItem when model data is resolved,
+ * unless a separate zPos role is also defined.
*/
/*!
* \qmlproperty string ItemModelSurfaceDataProxy::columnRole
- * The column role of the mapping.
+ * Defines the item model role to map into column category.
* In addition to defining which column the data belongs to, the value indicated by column role
- * is also set as the X-coordinate value of the QSurfaceDataItem when model data is resolved.
+ * is also set as the X-coordinate value of the QSurfaceDataItem when model data is resolved,
+ * unless a separate xPos role is also defined.
*/
/*!
* \qmlproperty string ItemModelSurfaceDataProxy::xPosRole
- * The X position role of the mapping. If this role is not defined, columnRole is used to
- * determine the X-coordinate value of resolved QSurfaceDataItems.
+ * Defines the item model role to map into X position. If this role is not defined, columnRole is
+ * used to determine the X-coordinate value of resolved QSurfaceDataItems.
*/
/*!
* \qmlproperty string ItemModelSurfaceDataProxy::yPosRole
- * The Y position role of the mapping.
+ * Defines the item model role to map into Y position.
*/
/*!
* \qmlproperty string ItemModelSurfaceDataProxy::zPosRole
- * The Z position role of the mapping. If this role is not defined, rowRole is used to
- * determine the Z-coordinate value of resolved QSurfaceDataItems.
+ * Defines the item model role to map into Z position. If this role is not defined, rowRole is
+ * used to determine the Z-coordinate value of resolved QSurfaceDataItems.
*/
/*!
@@ -132,8 +150,9 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*!
* \qmlproperty list<String> ItemModelSurfaceDataProxy::columnCategories
- * The column categories of the mapping. Only items with column roles that are found in this list are
- * included when data is resolved. The columns are ordered in the same order as they are in this list.
+ * The column categories of the mapping. Only items with column roles that are found in this
+ * list are included when data is resolved. The columns are ordered in the same order as they are
+ * in this list.
*/
/*!
@@ -159,6 +178,141 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ * \qmlproperty regExp ItemModelSurfaceDataProxy::rowRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by row role before it is used as
+ * a row category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and rowRoleReplace property contains the replacement string.
+ *
+ * \sa rowRole, rowRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelSurfaceDataProxy::columnRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by column role before it is used
+ * as a column category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and columnRoleReplace property contains the replacement string.
+ *
+ * \sa columnRole, columnRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelSurfaceDataProxy::xPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by xPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and xPosRoleReplace property contains the replacement string.
+ *
+ * \sa xPosRole, xPosRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelSurfaceDataProxy::yPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by yPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and yPosRoleReplace property contains the replacement string.
+ *
+ * \sa yPosRole, yPosRoleReplace
+ */
+
+/*!
+ * \qmlproperty regExp ItemModelSurfaceDataProxy::zPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by zPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and zPosRoleReplace property contains the replacement string.
+ *
+ * \sa zPosRole, zPosRoleReplace
+ */
+
+/*!
+ * \qmlproperty string ItemModelSurfaceDataProxy::rowRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with rowRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rowRole, rowRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelSurfaceDataProxy::columnRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with columnRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa columnRole, columnRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelSurfaceDataProxy::xPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with xPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa xPosRole, xPosRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelSurfaceDataProxy::yPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with yPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa yPosRole, yPosRolePattern
+ */
+
+/*!
+ * \qmlproperty string ItemModelSurfaceDataProxy::zPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with zPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa zPosRole, zPosRolePattern
+ */
+
+/*!
+ * \qmlproperty ItemModelSurfaceDataProxy.MultiMatchBehavior ItemModelSurfaceDataProxy::multiMatchBehavior
+ * This property defines how multiple matches for each row/column combination are handled.
+ * Defaults to ItemModelSurfaceDataProxy.MMBLast.
+ *
+ * For example, you might have an item model with timestamped data taken at irregular intervals
+ * and you want to visualize an average position of data items on each hour with a surface graph.
+ * This can be done by specifying row and column categories so that each surface point represents
+ * an hour, and setting multiMatchBehavior to ItemModelSurfaceDataProxy.MMBAverage.
+ */
+
+/*!
+ * \enum QItemModelSurfaceDataProxy::MultiMatchBehavior
+ *
+ * Behavior types for QItemModelSurfaceDataProxy::multiMatchBehavior property.
+ *
+ * \value MMBFirst
+ * The position values are taken from the first item in the item model that matches
+ * each row/column combination.
+ * \value MMBLast
+ * The position values are taken from the last item in the item model that matches
+ * each row/column combination.
+ * \value MMBAverage
+ * The position values from all items matching each row/column combination are
+ * averaged together and the averages are used as the surface point position.
+ * \value MMBCumulativeY
+ * For X and Z values this acts just like \c{MMBAverage}, but Y values are added together
+ * instead of averaged and the total is used as the surface point Y position.
+ */
+
+/*!
* Constructs QItemModelSurfaceDataProxy with optional \a parent.
*/
QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QObject *parent)
@@ -171,7 +325,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QObject *parent)
* Constructs QItemModelSurfaceDataProxy with \a itemModel and optional \a parent. Proxy doesn't take
* ownership of the \a itemModel, as typically item models are owned by other controls.
*/
-QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
QObject *parent)
: QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
{
@@ -186,7 +340,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel
* This constructor is meant to be used with models that have data properly sorted
* in rows and columns already, so it also sets useModelCategories property to true.
*/
-QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
const QString &yPosRole,
QObject *parent)
: QSurfaceDataProxy(new QItemModelSurfaceDataProxyPrivate(this), parent)
@@ -203,7 +357,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel
* The role mappings are set with \a rowRole, \a columnRole, and \a yPosRole.
* The zPosRole and the xPosRole are set to \a rowRole and \a columnRole, respectively.
*/
-QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &yPosRole,
@@ -225,7 +379,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel
* The role mappings are set with \a rowRole, \a columnRole, \a xPosRole, \a yPosRole, and
* \a zPosRole.
*/
-QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &xPosRole,
@@ -251,7 +405,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel
* Row and column categories are set with \a rowCategories and \a columnCategories.
* This constructor also sets autoRowCategories and autoColumnCategories to false.
*/
-QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &yPosRole,
@@ -281,7 +435,7 @@ QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel
* Row and column categories are set with \a rowCategories and \a columnCategories.
* This constructor also sets autoRowCategories and autoColumnCategories to false.
*/
-QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel,
+QItemModelSurfaceDataProxy::QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel,
const QString &rowRole,
const QString &columnRole,
const QString &xPosRole,
@@ -318,12 +472,12 @@ QItemModelSurfaceDataProxy::~QItemModelSurfaceDataProxy()
* Defines item model. Does not take ownership of the model, but does connect to it to listen for
* changes.
*/
-void QItemModelSurfaceDataProxy::setItemModel(const QAbstractItemModel *itemModel)
+void QItemModelSurfaceDataProxy::setItemModel(QAbstractItemModel *itemModel)
{
dptr()->m_itemModelHandler->setItemModel(itemModel);
}
-const QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const
+QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const
{
return dptrc()->m_itemModelHandler->itemModel();
}
@@ -331,7 +485,10 @@ const QAbstractItemModel *QItemModelSurfaceDataProxy::itemModel() const
/*!
* \property QItemModelSurfaceDataProxy::rowRole
*
- * Defines the row \a role for the mapping.
+ * Defines the item model role to map into row category.
+ * In addition to defining which row the data belongs to, the value indicated by row role
+ * is also set as the Z-coordinate value of the QSurfaceDataItem when model data is resolved,
+ * unless a separate zPos role is also defined.
*/
void QItemModelSurfaceDataProxy::setRowRole(const QString &role)
{
@@ -349,7 +506,10 @@ QString QItemModelSurfaceDataProxy::rowRole() const
/*!
* \property QItemModelSurfaceDataProxy::columnRole
*
- * Defines the column \a role for the mapping.
+ * Defines the item model role to map into column category.
+ * In addition to defining which column the data belongs to, the value indicated by column role
+ * is also set as the X-coordinate value of the QSurfaceDataItem when model data is resolved,
+ * unless a separate xPos role is also defined.
*/
void QItemModelSurfaceDataProxy::setColumnRole(const QString &role)
{
@@ -367,9 +527,8 @@ QString QItemModelSurfaceDataProxy::columnRole() const
/*!
* \property QItemModelSurfaceDataProxy::xPosRole
*
- * Defines the X position \a role for the mapping.
- * If this role is not defined, columnRole is used to determine the X-coordinate
- * value of resolved QSurfaceDataItems.
+ * Defines the item model role to map into X position. If this role is not defined, columnRole is
+ * used to determine the X-coordinate value of resolved QSurfaceDataItems.
*/
void QItemModelSurfaceDataProxy::setXPosRole(const QString &role)
{
@@ -387,7 +546,7 @@ QString QItemModelSurfaceDataProxy::xPosRole() const
/*!
* \property QItemModelSurfaceDataProxy::yPosRole
*
- * Defines the Y position \a role for the mapping.
+ * Defines the item model role to map into Y position.
*/
void QItemModelSurfaceDataProxy::setYPosRole(const QString &role)
{
@@ -405,9 +564,8 @@ QString QItemModelSurfaceDataProxy::yPosRole() const
/*!
* \property QItemModelSurfaceDataProxy::zPosRole
*
- * Defines the Z position \a role for the mapping.
- * If this role is not defined, rowRole is used to determine the Z-coordinate
- * value of resolved QSurfaceDataItems.
+ * Defines the item model role to map into Z position. If this role is not defined, rowRole is
+ * used to determine the Z-coordinate value of resolved QSurfaceDataItems.
*/
void QItemModelSurfaceDataProxy::setZPosRole(const QString &role)
{
@@ -561,6 +719,256 @@ int QItemModelSurfaceDataProxy::columnCategoryIndex(const QString &category)
}
/*!
+ * \property QItemModelSurfaceDataProxy::rowRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by row role before it is used as
+ * a row category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and rowRoleReplace property contains the replacement string.
+ *
+ * \sa rowRole, rowRoleReplace
+ */
+void QItemModelSurfaceDataProxy::setRowRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_rowRolePattern != pattern) {
+ dptr()->m_rowRolePattern = pattern;
+ emit rowRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelSurfaceDataProxy::rowRolePattern() const
+{
+ return dptrc()->m_rowRolePattern;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::columnRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by column role before it is used
+ * as a column category. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and columnRoleReplace property contains the replacement string.
+ *
+ * \sa columnRole, columnRoleReplace
+ */
+void QItemModelSurfaceDataProxy::setColumnRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_columnRolePattern != pattern) {
+ dptr()->m_columnRolePattern = pattern;
+ emit columnRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelSurfaceDataProxy::columnRolePattern() const
+{
+ return dptrc()->m_columnRolePattern;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::xPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by xPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and xPosRoleReplace property contains the replacement string.
+ *
+ * \sa xPosRole, xPosRoleReplace
+ */
+void QItemModelSurfaceDataProxy::setXPosRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_xPosRolePattern != pattern) {
+ dptr()->m_xPosRolePattern = pattern;
+ emit xPosRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelSurfaceDataProxy::xPosRolePattern() const
+{
+ return dptrc()->m_xPosRolePattern;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::yPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by yPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and yPosRoleReplace property contains the replacement string.
+ *
+ * \sa yPosRole, yPosRoleReplace
+ */
+void QItemModelSurfaceDataProxy::setYPosRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_yPosRolePattern != pattern) {
+ dptr()->m_yPosRolePattern = pattern;
+ emit yPosRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelSurfaceDataProxy::yPosRolePattern() const
+{
+ return dptrc()->m_yPosRolePattern;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::zPosRolePattern
+ *
+ * When set, a search and replace is done on the value mapped by zPos role before it is used as
+ * a item position value. This property specifies the regular expression to find the portion of the
+ * mapped value to replace and zPosRoleReplace property contains the replacement string.
+ *
+ * \sa zPosRole, zPosRoleReplace
+ */
+void QItemModelSurfaceDataProxy::setZPosRolePattern(const QRegExp &pattern)
+{
+ if (dptr()->m_zPosRolePattern != pattern) {
+ dptr()->m_zPosRolePattern = pattern;
+ emit zPosRolePatternChanged(pattern);
+ }
+}
+
+QRegExp QItemModelSurfaceDataProxy::zPosRolePattern() const
+{
+ return dptrc()->m_zPosRolePattern;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::rowRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with rowRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa rowRole, rowRolePattern
+ */
+void QItemModelSurfaceDataProxy::setRowRoleReplace(const QString &replace)
+{
+ if (dptr()->m_rowRoleReplace != replace) {
+ dptr()->m_rowRoleReplace = replace;
+ emit rowRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelSurfaceDataProxy::rowRoleReplace() const
+{
+ return dptrc()->m_rowRoleReplace;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::columnRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with columnRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa columnRole, columnRolePattern
+ */
+void QItemModelSurfaceDataProxy::setColumnRoleReplace(const QString &replace)
+{
+ if (dptr()->m_columnRoleReplace != replace) {
+ dptr()->m_columnRoleReplace = replace;
+ emit columnRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelSurfaceDataProxy::columnRoleReplace() const
+{
+ return dptrc()->m_columnRoleReplace;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::xPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with xPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa xPosRole, xPosRolePattern
+ */
+void QItemModelSurfaceDataProxy::setXPosRoleReplace(const QString &replace)
+{
+ if (dptr()->m_xPosRoleReplace != replace) {
+ dptr()->m_xPosRoleReplace = replace;
+ emit xPosRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelSurfaceDataProxy::xPosRoleReplace() const
+{
+ return dptrc()->m_xPosRoleReplace;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::yPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with yPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa yPosRole, yPosRolePattern
+ */
+void QItemModelSurfaceDataProxy::setYPosRoleReplace(const QString &replace)
+{
+ if (dptr()->m_yPosRoleReplace != replace) {
+ dptr()->m_yPosRoleReplace = replace;
+ emit yPosRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelSurfaceDataProxy::yPosRoleReplace() const
+{
+ return dptrc()->m_yPosRoleReplace;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::zPosRoleReplace
+ *
+ * This property defines the replace content to be used in conjunction with zPosRolePattern.
+ * Defaults to empty string. For more information on how the search and replace using regular
+ * expressions works, see QString::replace(const QRegExp &rx, const QString &after)
+ * function documentation.
+ *
+ * \sa zPosRole, zPosRolePattern
+ */
+void QItemModelSurfaceDataProxy::setZPosRoleReplace(const QString &replace)
+{
+ if (dptr()->m_zPosRoleReplace != replace) {
+ dptr()->m_zPosRoleReplace = replace;
+ emit zPosRoleReplaceChanged(replace);
+ }
+}
+
+QString QItemModelSurfaceDataProxy::zPosRoleReplace() const
+{
+ return dptrc()->m_zPosRoleReplace;
+}
+
+/*!
+ * \property QItemModelSurfaceDataProxy::multiMatchBehavior
+ *
+ * This property defines how multiple matches for each row/column combination are handled.
+ * Defaults to QItemModelSurfaceDataProxy::MMBLast.
+ *
+ * For example, you might have an item model with timestamped data taken at irregular intervals
+ * and you want to visualize an average position of data items on each hour with a surface graph.
+ * This can be done by specifying row and column categories so that each surface point represents
+ * an hour, and setting multiMatchBehavior to QItemModelSurfaceDataProxy::MMBAverage.
+ */
+
+void QItemModelSurfaceDataProxy::setMultiMatchBehavior(QItemModelSurfaceDataProxy::MultiMatchBehavior behavior)
+{
+ if (dptr()->m_multiMatchBehavior != behavior) {
+ dptr()->m_multiMatchBehavior = behavior;
+ emit multiMatchBehaviorChanged(behavior);
+ }
+}
+
+QItemModelSurfaceDataProxy::MultiMatchBehavior QItemModelSurfaceDataProxy::multiMatchBehavior() const
+{
+ return dptrc()->m_multiMatchBehavior;
+}
+
+/*!
* \internal
*/
QItemModelSurfaceDataProxyPrivate *QItemModelSurfaceDataProxy::dptr()
@@ -583,7 +991,8 @@ QItemModelSurfaceDataProxyPrivate::QItemModelSurfaceDataProxyPrivate(QItemModelS
m_itemModelHandler(new SurfaceItemModelHandler(q)),
m_useModelCategories(false),
m_autoRowCategories(true),
- m_autoColumnCategories(true)
+ m_autoColumnCategories(true),
+ m_multiMatchBehavior(QItemModelSurfaceDataProxy::MMBLast)
{
}
@@ -621,6 +1030,28 @@ void QItemModelSurfaceDataProxyPrivate::connectItemModelHandler()
m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
QObject::connect(qptr(), &QItemModelSurfaceDataProxy::autoColumnCategoriesChanged,
m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::rowRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::columnRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::xPosRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::yPosRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::zPosRolePatternChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::rowRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::columnRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::xPosRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::yPosRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::zPosRoleReplaceChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
+ QObject::connect(qptr(), &QItemModelSurfaceDataProxy::multiMatchBehaviorChanged,
+ m_itemModelHandler, &AbstractItemModelHandler::handleMappingChanged);
}
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy.h b/src/datavisualization/data/qitemmodelsurfacedataproxy.h
index b1ebbeed..1b95ed90 100644
--- a/src/datavisualization/data/qitemmodelsurfacedataproxy.h
+++ b/src/datavisualization/data/qitemmodelsurfacedataproxy.h
@@ -22,6 +22,7 @@
#include <QtDataVisualization/qsurfacedataproxy.h>
#include <QtCore/QAbstractItemModel>
#include <QtCore/QStringList>
+#include <QtCore/QRegExp>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -30,7 +31,8 @@ class QItemModelSurfaceDataProxyPrivate;
class QT_DATAVISUALIZATION_EXPORT QItemModelSurfaceDataProxy : public QSurfaceDataProxy
{
Q_OBJECT
- Q_PROPERTY(const QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged)
+ Q_ENUMS(MultiMatchBehavior)
+ Q_PROPERTY(QAbstractItemModel* itemModel READ itemModel WRITE setItemModel NOTIFY itemModelChanged)
Q_PROPERTY(QString rowRole READ rowRole WRITE setRowRole NOTIFY rowRoleChanged)
Q_PROPERTY(QString columnRole READ columnRole WRITE setColumnRole NOTIFY columnRoleChanged)
Q_PROPERTY(QString xPosRole READ xPosRole WRITE setXPosRole NOTIFY xPosRoleChanged)
@@ -41,32 +43,52 @@ class QT_DATAVISUALIZATION_EXPORT QItemModelSurfaceDataProxy : public QSurfaceDa
Q_PROPERTY(bool useModelCategories READ useModelCategories WRITE setUseModelCategories NOTIFY useModelCategoriesChanged)
Q_PROPERTY(bool autoRowCategories READ autoRowCategories WRITE setAutoRowCategories NOTIFY autoRowCategoriesChanged)
Q_PROPERTY(bool autoColumnCategories READ autoColumnCategories WRITE setAutoColumnCategories NOTIFY autoColumnCategoriesChanged)
+ Q_PROPERTY(QRegExp rowRolePattern READ rowRolePattern WRITE setRowRolePattern NOTIFY rowRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp columnRolePattern READ columnRolePattern WRITE setColumnRolePattern NOTIFY columnRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp xPosRolePattern READ xPosRolePattern WRITE setXPosRolePattern NOTIFY xPosRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp yPosRolePattern READ yPosRolePattern WRITE setYPosRolePattern NOTIFY yPosRolePatternChanged REVISION 1)
+ Q_PROPERTY(QRegExp zPosRolePattern READ zPosRolePattern WRITE setZPosRolePattern NOTIFY zPosRolePatternChanged REVISION 1)
+ Q_PROPERTY(QString rowRoleReplace READ rowRoleReplace WRITE setRowRoleReplace NOTIFY rowRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString columnRoleReplace READ columnRoleReplace WRITE setColumnRoleReplace NOTIFY columnRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString xPosRoleReplace READ xPosRoleReplace WRITE setXPosRoleReplace NOTIFY xPosRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString yPosRoleReplace READ yPosRoleReplace WRITE setYPosRoleReplace NOTIFY yPosRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(QString zPosRoleReplace READ zPosRoleReplace WRITE setZPosRoleReplace NOTIFY zPosRoleReplaceChanged REVISION 1)
+ Q_PROPERTY(MultiMatchBehavior multiMatchBehavior READ multiMatchBehavior WRITE setMultiMatchBehavior NOTIFY multiMatchBehaviorChanged REVISION 1)
public:
+ enum MultiMatchBehavior {
+ MMBFirst = 0,
+ MMBLast = 1,
+ MMBAverage = 2,
+ MMBCumulativeY = 3
+ };
+
explicit QItemModelSurfaceDataProxy(QObject *parent = 0);
- QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, QObject *parent = 0);
- QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &yPosRole,
+ QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, QObject *parent = 0);
+ QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &yPosRole,
QObject *parent = 0);
- QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &yPosRole,
QObject *parent = 0);
- QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &xPosRole,
const QString &yPosRole, const QString &zPosRole,
QObject *parent = 0);
- QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &yPosRole,
- const QStringList &rowCategories, const QStringList &columnCategories,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories,
QObject *parent = 0);
- QItemModelSurfaceDataProxy(const QAbstractItemModel *itemModel, const QString &rowRole,
+ QItemModelSurfaceDataProxy(QAbstractItemModel *itemModel, const QString &rowRole,
const QString &columnRole, const QString &xPosRole,
const QString &yPosRole, const QString &zPosRole,
- const QStringList &rowCategories, const QStringList &columnCategories,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories,
QObject *parent = 0);
virtual ~QItemModelSurfaceDataProxy();
- void setItemModel(const QAbstractItemModel *itemModel);
- const QAbstractItemModel *itemModel() const;
+ void setItemModel(QAbstractItemModel *itemModel);
+ QAbstractItemModel *itemModel() const;
void setRowRole(const QString &role);
QString rowRole() const;
@@ -99,6 +121,31 @@ public:
Q_INVOKABLE int rowCategoryIndex(const QString& category);
Q_INVOKABLE int columnCategoryIndex(const QString& category);
+ void setRowRolePattern(const QRegExp &pattern);
+ QRegExp rowRolePattern() const;
+ void setColumnRolePattern(const QRegExp &pattern);
+ QRegExp columnRolePattern() const;
+ void setXPosRolePattern(const QRegExp &pattern);
+ QRegExp xPosRolePattern() const;
+ void setYPosRolePattern(const QRegExp &pattern);
+ QRegExp yPosRolePattern() const;
+ void setZPosRolePattern(const QRegExp &pattern);
+ QRegExp zPosRolePattern() const;
+
+ void setRowRoleReplace(const QString &replace);
+ QString rowRoleReplace() const;
+ void setColumnRoleReplace(const QString &replace);
+ QString columnRoleReplace() const;
+ void setXPosRoleReplace(const QString &replace);
+ QString xPosRoleReplace() const;
+ void setYPosRoleReplace(const QString &replace);
+ QString yPosRoleReplace() const;
+ void setZPosRoleReplace(const QString &replace);
+ QString zPosRoleReplace() const;
+
+ void setMultiMatchBehavior(MultiMatchBehavior behavior);
+ MultiMatchBehavior multiMatchBehavior() const;
+
signals:
void itemModelChanged(const QAbstractItemModel* itemModel);
void rowRoleChanged(const QString &role);
@@ -111,6 +158,17 @@ signals:
void useModelCategoriesChanged(bool enable);
void autoRowCategoriesChanged(bool enable);
void autoColumnCategoriesChanged(bool enable);
+ Q_REVISION(1) void rowRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void columnRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void xPosRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void yPosRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void zPosRolePatternChanged(const QRegExp &pattern);
+ Q_REVISION(1) void rowRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void columnRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void xPosRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void yPosRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void zPosRoleReplaceChanged(const QString &replace);
+ Q_REVISION(1) void multiMatchBehaviorChanged(MultiMatchBehavior behavior);
protected:
QItemModelSurfaceDataProxyPrivate *dptr();
diff --git a/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h b/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h
index 0aaea8fd..9a79dca2 100644
--- a/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h
+++ b/src/datavisualization/data/qitemmodelsurfacedataproxy_p.h
@@ -64,6 +64,20 @@ private:
bool m_autoRowCategories;
bool m_autoColumnCategories;
+ QRegExp m_rowRolePattern;
+ QRegExp m_columnRolePattern;
+ QRegExp m_xPosRolePattern;
+ QRegExp m_yPosRolePattern;
+ QRegExp m_zPosRolePattern;
+
+ QString m_rowRoleReplace;
+ QString m_columnRoleReplace;
+ QString m_xPosRoleReplace;
+ QString m_yPosRoleReplace;
+ QString m_zPosRoleReplace;
+
+ QItemModelSurfaceDataProxy::MultiMatchBehavior m_multiMatchBehavior;
+
friend class SurfaceItemModelHandler;
friend class QItemModelSurfaceDataProxy;
};
diff --git a/src/datavisualization/data/qscatter3dseries.cpp b/src/datavisualization/data/qscatter3dseries.cpp
index 43bde4dd..e81933ed 100644
--- a/src/datavisualization/data/qscatter3dseries.cpp
+++ b/src/datavisualization/data/qscatter3dseries.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QScatter3DSeries
* \inmodule QtDataVisualization
* \brief Base series class for Q3DScatter.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QScatter3DSeries manages the series specific visual elements, as well as series data
* (via data proxy).
@@ -298,9 +298,54 @@ void QScatter3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne
}
}
+void QScatter3DSeriesPrivate::createItemLabel()
+{
+ static const QString xTitleTag(QStringLiteral("@xTitle"));
+ static const QString yTitleTag(QStringLiteral("@yTitle"));
+ static const QString zTitleTag(QStringLiteral("@zTitle"));
+ static const QString xLabelTag(QStringLiteral("@xLabel"));
+ static const QString yLabelTag(QStringLiteral("@yLabel"));
+ static const QString zLabelTag(QStringLiteral("@zLabel"));
+ static const QString seriesNameTag(QStringLiteral("@seriesName"));
+
+ if (m_selectedItem == QScatter3DSeries::invalidSelectionIndex()) {
+ m_itemLabel = QString();
+ return;
+ }
+
+ QValue3DAxis *axisX = static_cast<QValue3DAxis *>(m_controller->axisX());
+ QValue3DAxis *axisY = static_cast<QValue3DAxis *>(m_controller->axisY());
+ QValue3DAxis *axisZ = static_cast<QValue3DAxis *>(m_controller->axisZ());
+ QVector3D selectedPosition = qptr()->dataProxy()->itemAt(m_selectedItem)->position();
+
+ m_itemLabel = m_itemLabelFormat;
+
+ m_itemLabel.replace(xTitleTag, axisX->title());
+ m_itemLabel.replace(yTitleTag, axisY->title());
+ m_itemLabel.replace(zTitleTag, axisZ->title());
+
+ if (m_itemLabel.contains(xLabelTag)) {
+ QString valueLabelText = axisX->formatter()->stringForValue(
+ qreal(selectedPosition.x()), axisX->labelFormat());
+ m_itemLabel.replace(xLabelTag, valueLabelText);
+ }
+ if (m_itemLabel.contains(yLabelTag)) {
+ QString valueLabelText = axisY->formatter()->stringForValue(
+ qreal(selectedPosition.y()), axisY->labelFormat());
+ m_itemLabel.replace(yLabelTag, valueLabelText);
+ }
+ if (m_itemLabel.contains(zLabelTag)) {
+ QString valueLabelText = axisZ->formatter()->stringForValue(
+ qreal(selectedPosition.z()), axisZ->labelFormat());
+ m_itemLabel.replace(zLabelTag, valueLabelText);
+ }
+ m_itemLabel.replace(seriesNameTag, m_name);
+}
+
void QScatter3DSeriesPrivate::setSelectedItem(int index)
{
if (index != m_selectedItem) {
+ markItemLabelDirty();
m_selectedItem = index;
emit qptr()->selectedItemChanged(m_selectedItem);
}
diff --git a/src/datavisualization/data/qscatter3dseries_p.h b/src/datavisualization/data/qscatter3dseries_p.h
index 1abbd406..8717a616 100644
--- a/src/datavisualization/data/qscatter3dseries_p.h
+++ b/src/datavisualization/data/qscatter3dseries_p.h
@@ -43,6 +43,7 @@ public:
virtual void setDataProxy(QAbstractDataProxy *proxy);
virtual void connectControllerAndProxy(Abstract3DController *newController);
+ virtual void createItemLabel();
void setSelectedItem(int index);
void setItemSize(float size);
diff --git a/src/datavisualization/data/qscatterdataitem.cpp b/src/datavisualization/data/qscatterdataitem.cpp
index 9751dfeb..e45b22f3 100644
--- a/src/datavisualization/data/qscatterdataitem.cpp
+++ b/src/datavisualization/data/qscatterdataitem.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \inmodule QtDataVisualization
* \brief The QScatterDataItem class provides a container for resolved data to be added to scatter
* graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* A QScatterDataItem holds data for a single rendered item in a scatter graph.
* Scatter data proxies parse data into QScatterDataItem instances for visualizing.
diff --git a/src/datavisualization/data/qscatterdataitem_p.h b/src/datavisualization/data/qscatterdataitem_p.h
index efb1cc5c..2884c2e3 100644
--- a/src/datavisualization/data/qscatterdataitem_p.h
+++ b/src/datavisualization/data/qscatterdataitem_p.h
@@ -39,9 +39,6 @@ class QScatterDataItemPrivate
public:
QScatterDataItemPrivate();
virtual ~QScatterDataItemPrivate();
-
-protected:
- friend class QScatterDataItem;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qscatterdataproxy.cpp b/src/datavisualization/data/qscatterdataproxy.cpp
index 84bb57e7..cc2e3bd8 100644
--- a/src/datavisualization/data/qscatterdataproxy.cpp
+++ b/src/datavisualization/data/qscatterdataproxy.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "qscatterdataproxy.h"
#include "qscatterdataproxy_p.h"
#include "qscatter3dseries_p.h"
@@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QScatterDataProxy
* \inmodule QtDataVisualization
* \brief Base proxy class for Q3DScatter.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QScatterDataProxy handles adding, inserting, changing, and removing data items.
*
diff --git a/src/datavisualization/data/qsurface3dseries.cpp b/src/datavisualization/data/qsurface3dseries.cpp
index 72967bae..1107d721 100644
--- a/src/datavisualization/data/qsurface3dseries.cpp
+++ b/src/datavisualization/data/qsurface3dseries.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QSurface3DSeries
* \inmodule QtDataVisualization
* \brief Base series class for Q3DSurface.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QSurface3DSeries manages the series specific visual elements, as well as series data
* (via data proxy).
@@ -75,7 +75,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* This type manages the series specific visual elements, as well as series data
* (via data proxy).
*
- * For Surface3DSeries enums, see \l QSurface3DSeries::DrawFlag
+ * For Surface3DSeries enums, see \l{QSurface3DSeries::DrawFlag}.
*
* For more complete description, see QSurface3DSeries.
*
@@ -373,9 +373,54 @@ void QSurface3DSeriesPrivate::connectControllerAndProxy(Abstract3DController *ne
}
}
+void QSurface3DSeriesPrivate::createItemLabel()
+{
+ static const QString xTitleTag(QStringLiteral("@xTitle"));
+ static const QString yTitleTag(QStringLiteral("@yTitle"));
+ static const QString zTitleTag(QStringLiteral("@zTitle"));
+ static const QString xLabelTag(QStringLiteral("@xLabel"));
+ static const QString yLabelTag(QStringLiteral("@yLabel"));
+ static const QString zLabelTag(QStringLiteral("@zLabel"));
+ static const QString seriesNameTag(QStringLiteral("@seriesName"));
+
+ if (m_selectedPoint == QSurface3DSeries::invalidSelectionPosition()) {
+ m_itemLabel = QString();
+ return;
+ }
+
+ QValue3DAxis *axisX = static_cast<QValue3DAxis *>(m_controller->axisX());
+ QValue3DAxis *axisY = static_cast<QValue3DAxis *>(m_controller->axisY());
+ QValue3DAxis *axisZ = static_cast<QValue3DAxis *>(m_controller->axisZ());
+ QVector3D selectedPosition = qptr()->dataProxy()->itemAt(m_selectedPoint)->position();
+
+ m_itemLabel = m_itemLabelFormat;
+
+ m_itemLabel.replace(xTitleTag, axisX->title());
+ m_itemLabel.replace(yTitleTag, axisY->title());
+ m_itemLabel.replace(zTitleTag, axisZ->title());
+
+ if (m_itemLabel.contains(xLabelTag)) {
+ QString valueLabelText = axisX->formatter()->stringForValue(
+ qreal(selectedPosition.x()), axisX->labelFormat());
+ m_itemLabel.replace(xLabelTag, valueLabelText);
+ }
+ if (m_itemLabel.contains(yLabelTag)) {
+ QString valueLabelText = axisY->formatter()->stringForValue(
+ qreal(selectedPosition.y()), axisY->labelFormat());
+ m_itemLabel.replace(yLabelTag, valueLabelText);
+ }
+ if (m_itemLabel.contains(zLabelTag)) {
+ QString valueLabelText = axisZ->formatter()->stringForValue(
+ qreal(selectedPosition.z()), axisZ->labelFormat());
+ m_itemLabel.replace(zLabelTag, valueLabelText);
+ }
+ m_itemLabel.replace(seriesNameTag, m_name);
+}
+
void QSurface3DSeriesPrivate::setSelectedPoint(const QPoint &position)
{
if (position != m_selectedPoint) {
+ markItemLabelDirty();
m_selectedPoint = position;
emit qptr()->selectedPointChanged(m_selectedPoint);
}
diff --git a/src/datavisualization/data/qsurface3dseries_p.h b/src/datavisualization/data/qsurface3dseries_p.h
index bc8157bd..d4cc2820 100644
--- a/src/datavisualization/data/qsurface3dseries_p.h
+++ b/src/datavisualization/data/qsurface3dseries_p.h
@@ -43,6 +43,7 @@ public:
virtual void setDataProxy(QAbstractDataProxy *proxy);
virtual void connectControllerAndProxy(Abstract3DController *newController);
+ virtual void createItemLabel();
void setSelectedPoint(const QPoint &position);
void setFlatShadingEnabled(bool enabled);
diff --git a/src/datavisualization/data/qsurfacedataitem.cpp b/src/datavisualization/data/qsurfacedataitem.cpp
index c8a76a67..cd3819c7 100644
--- a/src/datavisualization/data/qsurfacedataitem.cpp
+++ b/src/datavisualization/data/qsurfacedataitem.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \inmodule QtDataVisualization
* \brief The QSurfaceDataItem class provides a container for resolved data to be added to surface
* graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* A QSurfaceDataItem holds data for a single vertex in surface graph.
* Surface data proxies parse data into QSurfaceDataItem instances for visualizing.
diff --git a/src/datavisualization/data/qsurfacedataitem_p.h b/src/datavisualization/data/qsurfacedataitem_p.h
index 0cec7eab..e00134e3 100644
--- a/src/datavisualization/data/qsurfacedataitem_p.h
+++ b/src/datavisualization/data/qsurfacedataitem_p.h
@@ -39,9 +39,6 @@ class QSurfaceDataItemPrivate
public:
QSurfaceDataItemPrivate();
virtual ~QSurfaceDataItemPrivate();
-
-protected:
- friend class QSurfaceDataItem;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/qsurfacedataproxy.cpp b/src/datavisualization/data/qsurfacedataproxy.cpp
index 2e66bb5b..dbe7cc49 100644
--- a/src/datavisualization/data/qsurfacedataproxy.cpp
+++ b/src/datavisualization/data/qsurfacedataproxy.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "qsurfacedataproxy.h"
#include "qsurfacedataproxy_p.h"
#include "qsurface3dseries_p.h"
@@ -26,10 +25,10 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QSurfaceDataProxy
* \inmodule QtDataVisualization
* \brief Base proxy class for Q3DSurface.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
- * QSurfaceDataProxy takes care of surface related data handling. The QSurfaceDataProxy handles the data
- * in rows and for this it provides two auxiliary typedefs. QSurfaceDataArray is a QList for
+ * QSurfaceDataProxy takes care of surface related data handling. The QSurfaceDataProxy handles the
+ * data in rows and for this it provides two auxiliary typedefs. QSurfaceDataArray is a QList for
* controlling the rows. For rows there is a QVector QSurfaceDataRow which contains QSurfaceDataItem
* objects. See Q3DSurface documentation and basic sample code there how to feed the data for the
* QSurfaceDataProxy.
@@ -41,17 +40,18 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* If you use QSurfaceDataRow pointers to directly modify data after adding the array to the proxy,
* you must also emit proper signal to make the graph update.
*
- * To make a sensible surface, the X-value of each successive item in the same row must be greater than the
- * previous item in that row, and the the Z-value of each successive item in a column must be greater than
- * the previous item in that column.
+ * To make a sensible surface, the X-value of each successive item in all rows must be
+ * either ascending or descending throughout the row.
+ * Similarly, the Z-value of each successive item in all columns must be either ascending or
+ * descending throughout the column.
*
- * \note In the initial release, only surfaces with straight rows and columns are fully supported. Any row
- * with items that do not have the exact same Z-value or any columns with items that do not have the exact
- * same X-value may get clipped incorrectly if the whole surface doesn't fit to the visible X or Z axis
- * ranges.
+ * \note Currently only surfaces with straight rows and columns are fully supported. Any row
+ * with items that do not have the exact same Z-value or any column with items that do not have
+ * the exact same X-value may get clipped incorrectly if the whole surface doesn't completely fit
+ * in the visible X or Z axis ranges.
*
* \note Surfaces with less than two rows or columns are not considered valid surfaces and will
- * not get rendered.
+ * not be rendered.
*
* \sa {Qt Data Visualization Data Handling}
*/
@@ -520,10 +520,14 @@ void QSurfaceDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxV
minValues.setY(min);
maxValues.setY(max);
if (columns) {
- minValues.setX(m_dataArray->at(0)->at(0).x());
- minValues.setZ(m_dataArray->at(0)->at(0).z());
- maxValues.setX(m_dataArray->at(0)->last().x());
- maxValues.setZ(m_dataArray->last()->at(0).z());
+ float xLow = m_dataArray->at(0)->at(0).x();
+ float xHigh = m_dataArray->at(0)->last().x();
+ float zLow = m_dataArray->at(0)->at(0).z();
+ float zHigh = m_dataArray->last()->at(0).z();
+ minValues.setX(qMin(xLow, xHigh));
+ minValues.setZ(qMin(zLow, zHigh));
+ maxValues.setX(qMax(xLow, xHigh));
+ maxValues.setZ(qMax(zLow, zHigh));
} else {
minValues.setX(0.0f);
minValues.setZ(0.0f);
diff --git a/src/datavisualization/data/scatteritemmodelhandler.cpp b/src/datavisualization/data/scatteritemmodelhandler.cpp
index 08ed12f3..8b4a6f89 100644
--- a/src/datavisualization/data/scatteritemmodelhandler.cpp
+++ b/src/datavisualization/data/scatteritemmodelhandler.cpp
@@ -25,7 +25,15 @@ static const int noRoleIndex = -1;
ScatterItemModelHandler::ScatterItemModelHandler(QItemModelScatterDataProxy *proxy, QObject *parent)
: AbstractItemModelHandler(parent),
m_proxy(proxy),
- m_proxyArray(0)
+ m_proxyArray(0),
+ m_xPosRole(noRoleIndex),
+ m_yPosRole(noRoleIndex),
+ m_zPosRole(noRoleIndex),
+ m_rotationRole(noRoleIndex),
+ m_haveXPosPattern(false),
+ m_haveYPosPattern(false),
+ m_haveZPosPattern(false),
+ m_haveRotationPattern(false)
{
}
@@ -130,17 +138,48 @@ void ScatterItemModelHandler::modelPosToScatterItem(int modelRow, int modelColum
QScatterDataItem &item)
{
QModelIndex index = m_itemModel->index(modelRow, modelColumn);
- float xPos(0.0f);
- float yPos(0.0f);
- float zPos(0.0f);
- if (m_xPosRole != noRoleIndex)
- xPos = index.data(m_xPosRole).toFloat();
- if (m_yPosRole != noRoleIndex)
- yPos = index.data(m_yPosRole).toFloat();
- if (m_zPosRole != noRoleIndex)
- zPos = index.data(m_zPosRole).toFloat();
- if (m_rotationRole != noRoleIndex)
- item.setRotation(toQuaternion(index.data(m_rotationRole)));
+ float xPos;
+ float yPos;
+ float zPos;
+ if (m_xPosRole != noRoleIndex) {
+ QVariant xValueVar = index.data(m_xPosRole);
+ if (m_haveXPosPattern)
+ xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat();
+ else
+ xPos = xValueVar.toFloat();
+ } else {
+ xPos = 0.0f;
+ }
+ if (m_yPosRole != noRoleIndex) {
+ QVariant yValueVar = index.data(m_yPosRole);
+ if (m_haveYPosPattern)
+ yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat();
+ else
+ yPos = yValueVar.toFloat();
+ } else {
+ yPos = 0.0f;
+ }
+ if (m_zPosRole != noRoleIndex) {
+ QVariant zValueVar = index.data(m_zPosRole);
+ if (m_haveZPosPattern)
+ zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat();
+ else
+ zPos = zValueVar.toFloat();
+ } else {
+ zPos = 0.0f;
+ }
+ if (m_rotationRole != noRoleIndex) {
+ QVariant rotationVar = index.data(m_rotationRole);
+ if (m_haveRotationPattern) {
+ item.setRotation(
+ toQuaternion(
+ QVariant(rotationVar.toString().replace(m_rotationPattern,
+ m_rotationReplace))));
+ } else {
+ item.setRotation(toQuaternion(rotationVar));
+ }
+ }
+
item.setPosition(QVector3D(xPos, yPos, zPos));
}
@@ -153,6 +192,19 @@ void ScatterItemModelHandler::resolveModel()
return;
}
+ m_xPosPattern = m_proxy->xPosRolePattern();
+ m_yPosPattern = m_proxy->yPosRolePattern();
+ m_zPosPattern = m_proxy->zPosRolePattern();
+ m_rotationPattern = m_proxy->rotationRolePattern();
+ m_xPosReplace = m_proxy->xPosRoleReplace();
+ m_yPosReplace = m_proxy->yPosRoleReplace();
+ m_zPosReplace = m_proxy->zPosRoleReplace();
+ m_rotationReplace = m_proxy->rotationRoleReplace();
+ m_haveXPosPattern = !m_xPosPattern.isEmpty() && m_xPosPattern.isValid();
+ m_haveYPosPattern = !m_yPosPattern.isEmpty() && m_yPosPattern.isValid();
+ m_haveZPosPattern = !m_zPosPattern.isEmpty() && m_zPosPattern.isValid();
+ m_haveRotationPattern = !m_rotationPattern.isEmpty() && m_rotationPattern.isValid();
+
QHash<int, QByteArray> roleHash = m_itemModel->roleNames();
m_xPosRole = roleHash.key(m_proxy->xPosRole().toLatin1(), noRoleIndex);
m_yPosRole = roleHash.key(m_proxy->yPosRole().toLatin1(), noRoleIndex);
diff --git a/src/datavisualization/data/scatteritemmodelhandler_p.h b/src/datavisualization/data/scatteritemmodelhandler_p.h
index 0661d734..817b245d 100644
--- a/src/datavisualization/data/scatteritemmodelhandler_p.h
+++ b/src/datavisualization/data/scatteritemmodelhandler_p.h
@@ -59,6 +59,18 @@ private:
int m_yPosRole;
int m_zPosRole;
int m_rotationRole;
+ QRegExp m_xPosPattern;
+ QRegExp m_yPosPattern;
+ QRegExp m_zPosPattern;
+ QRegExp m_rotationPattern;
+ QString m_xPosReplace;
+ QString m_yPosReplace;
+ QString m_zPosReplace;
+ QString m_rotationReplace;
+ bool m_haveXPosPattern;
+ bool m_haveYPosPattern;
+ bool m_haveZPosPattern;
+ bool m_haveRotationPattern;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/data/scatterrenderitem.cpp b/src/datavisualization/data/scatterrenderitem.cpp
index 3b2e64c5..0b5398f1 100644
--- a/src/datavisualization/data/scatterrenderitem.cpp
+++ b/src/datavisualization/data/scatterrenderitem.cpp
@@ -17,8 +17,6 @@
****************************************************************************/
#include "scatterrenderitem_p.h"
-#include "scatter3drenderer_p.h"
-#include "qscatterdataproxy.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -29,10 +27,10 @@ ScatterRenderItem::ScatterRenderItem()
}
ScatterRenderItem::ScatterRenderItem(const ScatterRenderItem &other)
- : AbstractRenderItem(other),
- m_visible(false)
+ : AbstractRenderItem(other)
{
m_position = other.m_position;
+ m_visible = other.m_visible;
}
ScatterRenderItem::~ScatterRenderItem()
diff --git a/src/datavisualization/data/scatterrenderitem_p.h b/src/datavisualization/data/scatterrenderitem_p.h
index eb070682..d754a8ca 100644
--- a/src/datavisualization/data/scatterrenderitem_p.h
+++ b/src/datavisualization/data/scatterrenderitem_p.h
@@ -33,8 +33,6 @@
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-class Scatter3DRenderer;
-
class ScatterRenderItem : public AbstractRenderItem
{
public:
@@ -55,8 +53,6 @@ public:
protected:
QVector3D m_position;
bool m_visible;
-
- friend class QScatterDataItem;
};
typedef QVector<ScatterRenderItem> ScatterRenderItemArray;
diff --git a/src/datavisualization/data/surfaceitemmodelhandler.cpp b/src/datavisualization/data/surfaceitemmodelhandler.cpp
index f4383dbf..e6d1e70d 100644
--- a/src/datavisualization/data/surfaceitemmodelhandler.cpp
+++ b/src/datavisualization/data/surfaceitemmodelhandler.cpp
@@ -25,7 +25,13 @@ static const int noRoleIndex = -1;
SurfaceItemModelHandler::SurfaceItemModelHandler(QItemModelSurfaceDataProxy *proxy, QObject *parent)
: AbstractItemModelHandler(parent),
m_proxy(proxy),
- m_proxyArray(0)
+ m_proxyArray(0),
+ m_xPosRole(noRoleIndex),
+ m_yPosRole(noRoleIndex),
+ m_zPosRole(noRoleIndex),
+ m_haveXPosPattern(false),
+ m_haveYPosPattern(false),
+ m_haveZPosPattern(false)
{
}
@@ -33,6 +39,62 @@ SurfaceItemModelHandler::~SurfaceItemModelHandler()
{
}
+void SurfaceItemModelHandler::handleDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QVector<int> &roles)
+{
+ // Do nothing if full reset already pending
+ if (!m_fullReset) {
+ if (!m_proxy->useModelCategories()) {
+ // If the data model doesn't directly map rows and columns, we cannot optimize
+ AbstractItemModelHandler::handleDataChanged(topLeft, bottomRight, roles);
+ } else {
+ int startRow = qMin(topLeft.row(), bottomRight.row());
+ int endRow = qMax(topLeft.row(), bottomRight.row());
+ int startCol = qMin(topLeft.column(), bottomRight.column());
+ int endCol = qMax(topLeft.column(), bottomRight.column());
+
+ for (int i = startRow; i <= endRow; i++) {
+ for (int j = startCol; j <= endCol; j++) {
+ QModelIndex index = m_itemModel->index(i, j);
+ QSurfaceDataItem item;
+ QVariant xValueVar = index.data(m_xPosRole);
+ QVariant yValueVar = index.data(m_yPosRole);
+ QVariant zValueVar = index.data(m_zPosRole);
+ const QSurfaceDataItem *oldItem = m_proxy->itemAt(i, j);
+ float xPos;
+ float yPos;
+ float zPos;
+ if (m_xPosRole != noRoleIndex) {
+ if (m_haveXPosPattern)
+ xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat();
+ else
+ xPos = xValueVar.toFloat();
+ } else {
+ xPos = oldItem->x();
+ }
+
+ if (m_haveYPosPattern)
+ yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat();
+ else
+ yPos = yValueVar.toFloat();
+
+ if (m_zPosRole != noRoleIndex) {
+ if (m_haveZPosPattern)
+ zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat();
+ else
+ zPos = zValueVar.toFloat();
+ } else {
+ zPos = oldItem->z();
+ }
+ item.setPosition(QVector3D(xPos, yPos, zPos));
+ m_proxy->setItem(i, j, item);
+ }
+ }
+ }
+ }
+}
+
// Resolve entire item model into QSurfaceDataArray.
void SurfaceItemModelHandler::resolveModel()
{
@@ -49,12 +111,29 @@ void SurfaceItemModelHandler::resolveModel()
return;
}
+ // Position patterns can be reused on single item changes, so store them to member variables.
+ QRegExp rowPattern(m_proxy->rowRolePattern());
+ QRegExp colPattern(m_proxy->columnRolePattern());
+ m_xPosPattern = m_proxy->xPosRolePattern();
+ m_yPosPattern = m_proxy->yPosRolePattern();
+ m_zPosPattern = m_proxy->zPosRolePattern();
+ QString rowReplace = m_proxy->rowRoleReplace();
+ QString colReplace = m_proxy->columnRoleReplace();
+ m_xPosReplace = m_proxy->xPosRoleReplace();
+ m_yPosReplace = m_proxy->yPosRoleReplace();
+ m_zPosReplace = m_proxy->zPosRoleReplace();
+ bool haveRowPattern = !rowPattern.isEmpty() && rowPattern.isValid();
+ bool haveColPattern = !colPattern.isEmpty() && colPattern.isValid();
+ m_haveXPosPattern = !m_xPosPattern.isEmpty() && m_xPosPattern.isValid();
+ m_haveYPosPattern = !m_yPosPattern.isEmpty() && m_yPosPattern.isValid();
+ m_haveZPosPattern = !m_zPosPattern.isEmpty() && m_zPosPattern.isValid();
+
QHash<int, QByteArray> roleHash = m_itemModel->roleNames();
// Default to display role if no mapping
- int xPosRole = roleHash.key(m_proxy->xPosRole().toLatin1(), noRoleIndex);
- int yPosRole = roleHash.key(m_proxy->yPosRole().toLatin1(), Qt::DisplayRole);
- int zPosRole = roleHash.key(m_proxy->zPosRole().toLatin1(), noRoleIndex);
+ m_xPosRole = roleHash.key(m_proxy->xPosRole().toLatin1(), noRoleIndex);
+ m_yPosRole = roleHash.key(m_proxy->yPosRole().toLatin1(), Qt::DisplayRole);
+ m_zPosRole = roleHash.key(m_proxy->zPosRole().toLatin1(), noRoleIndex);
int rowCount = m_itemModel->rowCount();
int columnCount = m_itemModel->columnCount();
@@ -70,41 +149,58 @@ void SurfaceItemModelHandler::resolveModel()
for (int i = 0; i < rowCount; i++) {
QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i);
for (int j = 0; j < columnCount; j++) {
- float xPos = j;
- float zPos = i;
- if (xPosRole != noRoleIndex) {
- xPos = m_itemModel->index(i, j).data(xPosRole).toFloat();
+ QModelIndex index = m_itemModel->index(i, j);
+ QVariant xValueVar = index.data(m_xPosRole);
+ QVariant yValueVar = index.data(m_yPosRole);
+ QVariant zValueVar = index.data(m_zPosRole);
+ float xPos;
+ float yPos;
+ float zPos;
+ if (m_xPosRole != noRoleIndex) {
+ if (m_haveXPosPattern)
+ xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat();
+ else
+ xPos = xValueVar.toFloat();
} else {
QString header = m_itemModel->headerData(j, Qt::Horizontal).toString();
bool ok = false;
float headerValue = header.toFloat(&ok);
if (ok)
xPos = headerValue;
+ else
+ xPos = float(j);
}
- if (zPosRole != noRoleIndex) {
- zPos = m_itemModel->index(i, j).data(zPosRole).toFloat();
+ if (m_haveYPosPattern)
+ yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat();
+ else
+ yPos = yValueVar.toFloat();
+
+ if (m_zPosRole != noRoleIndex) {
+ if (m_haveZPosPattern)
+ zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat();
+ else
+ zPos = zValueVar.toFloat();
} else {
QString header = m_itemModel->headerData(i, Qt::Vertical).toString();
bool ok = false;
float headerValue = header.toFloat(&ok);
if (ok)
zPos = headerValue;
+ else
+ zPos = float(i);
}
- newProxyRow[j].setPosition(
- QVector3D(xPos,
- m_itemModel->index(i, j).data(yPosRole).toFloat(),
- zPos));
+ newProxyRow[j].setPosition(QVector3D(xPos, yPos, zPos));
}
}
} else {
int rowRole = roleHash.key(m_proxy->rowRole().toLatin1());
int columnRole = roleHash.key(m_proxy->columnRole().toLatin1());
- if (xPosRole == noRoleIndex)
- xPosRole = columnRole;
- if (zPosRole == noRoleIndex)
- zPosRole = rowRole;
+ if (m_xPosRole == noRoleIndex)
+ m_xPosRole = columnRole;
+ if (m_zPosRole == noRoleIndex)
+ m_zPosRole = rowRole;
bool generateRows = m_proxy->autoRowCategories();
bool generateColumns = m_proxy->autoColumnCategories();
@@ -116,6 +212,14 @@ void SurfaceItemModelHandler::resolveModel()
QHash<QString, bool> rowListHash;
QHash<QString, bool> columnListHash;
+ bool cumulative = m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBAverage
+ || m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBCumulativeY;
+ bool average = m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBAverage;
+ bool takeFirst = m_proxy->multiMatchBehavior() == QItemModelSurfaceDataProxy::MMBFirst;
+ QHash<QString, QHash<QString, int> > *matchCountMap = 0;
+ if (cumulative)
+ matchCountMap = new QHash<QString, QHash<QString, int> >;
+
// Sort values into rows and columns
typedef QHash<QString, QVector3D> ColumnValueMap;
QHash <QString, ColumnValueMap> itemValueMap;
@@ -123,11 +227,45 @@ void SurfaceItemModelHandler::resolveModel()
for (int j = 0; j < columnCount; j++) {
QModelIndex index = m_itemModel->index(i, j);
QString rowRoleStr = index.data(rowRole).toString();
+ if (haveRowPattern)
+ rowRoleStr.replace(rowPattern, rowReplace);
QString columnRoleStr = index.data(columnRole).toString();
- QVector3D itemPos(index.data(xPosRole).toReal(),
- index.data(yPosRole).toReal(),
- index.data(zPosRole).toReal());
- itemValueMap[rowRoleStr][columnRoleStr] = itemPos;
+ if (haveColPattern)
+ columnRoleStr.replace(colPattern, colReplace);
+ QVariant xValueVar = index.data(m_xPosRole);
+ QVariant yValueVar = index.data(m_yPosRole);
+ QVariant zValueVar = index.data(m_zPosRole);
+ float xPos;
+ float yPos;
+ float zPos;
+ if (m_haveXPosPattern)
+ xPos = xValueVar.toString().replace(m_xPosPattern, m_xPosReplace).toFloat();
+ else
+ xPos = xValueVar.toFloat();
+ if (m_haveYPosPattern)
+ yPos = yValueVar.toString().replace(m_yPosPattern, m_yPosReplace).toFloat();
+ else
+ yPos = yValueVar.toFloat();
+ if (m_haveZPosPattern)
+ zPos = zValueVar.toString().replace(m_zPosPattern, m_zPosReplace).toFloat();
+ else
+ zPos = zValueVar.toFloat();
+
+ QVector3D itemPos(xPos, yPos, zPos);
+
+ if (cumulative)
+ (*matchCountMap)[rowRoleStr][columnRoleStr]++;
+
+ if (cumulative) {
+ itemValueMap[rowRoleStr][columnRoleStr] += itemPos;
+ } else {
+ if (takeFirst && itemValueMap.contains(rowRoleStr)) {
+ if (itemValueMap.value(rowRoleStr).contains(columnRoleStr))
+ continue; // We already have a value for this row/column combo
+ }
+ itemValueMap[rowRoleStr][columnRoleStr] = itemPos;
+ }
+
if (generateRows && !rowListHash.value(rowRoleStr, false)) {
rowListHash.insert(rowRoleStr, true);
rowList << rowRoleStr;
@@ -161,9 +299,22 @@ void SurfaceItemModelHandler::resolveModel()
for (int i = 0; i < rowList.size(); i++) {
QString rowKey = rowList.at(i);
QSurfaceDataRow &newProxyRow = *m_proxyArray->at(i);
- for (int j = 0; j < columnList.size(); j++)
- newProxyRow[j].setPosition(itemValueMap[rowKey][columnList.at(j)]);
+ for (int j = 0; j < columnList.size(); j++) {
+ QVector3D &itemPos = itemValueMap[rowKey][columnList.at(j)];
+ if (cumulative) {
+ if (average) {
+ itemPos /= float((*matchCountMap)[rowKey][columnList.at(j)]);
+ } else { // cumulativeY
+ float divisor = float((*matchCountMap)[rowKey][columnList.at(j)]);
+ itemPos.setX(itemPos.x() / divisor);
+ itemPos.setZ(itemPos.z() / divisor);
+ }
+ }
+ newProxyRow[j].setPosition(itemPos);
+ }
}
+
+ delete matchCountMap;
}
m_proxy->resetArray(m_proxyArray);
diff --git a/src/datavisualization/data/surfaceitemmodelhandler_p.h b/src/datavisualization/data/surfaceitemmodelhandler_p.h
index ae426433..572788d6 100644
--- a/src/datavisualization/data/surfaceitemmodelhandler_p.h
+++ b/src/datavisualization/data/surfaceitemmodelhandler_p.h
@@ -41,11 +41,27 @@ public:
SurfaceItemModelHandler(QItemModelSurfaceDataProxy *proxy, QObject *parent = 0);
virtual ~SurfaceItemModelHandler();
+public slots:
+ virtual void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QVector<int> &roles = QVector<int> ());
+
protected:
void virtual resolveModel();
QItemModelSurfaceDataProxy *m_proxy; // Not owned
QSurfaceDataArray *m_proxyArray; // Not owned
+ int m_xPosRole;
+ int m_yPosRole;
+ int m_zPosRole;
+ QRegExp m_xPosPattern;
+ QRegExp m_yPosPattern;
+ QRegExp m_zPosPattern;
+ QString m_xPosReplace;
+ QString m_yPosReplace;
+ QString m_zPosReplace;
+ bool m_haveXPosPattern;
+ bool m_haveYPosPattern;
+ bool m_haveZPosPattern;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/doc/qtdatavisualization.qdocconf b/src/datavisualization/doc/qtdatavisualization.qdocconf
index 5c871b5a..6e9f09b4 100644
--- a/src/datavisualization/doc/qtdatavisualization.qdocconf
+++ b/src/datavisualization/doc/qtdatavisualization.qdocconf
@@ -6,7 +6,7 @@ include($QT_INSTALL_DOCS/global/qt-html-templates-offline.qdocconf)
project = QtDataVisualization
description = Qt Data Visualization Reference Documentation
-version = 1.0.0
+version = 1.1.0
exampledirs += ../../../examples/datavisualization \
snippets
@@ -27,14 +27,14 @@ indexes += $QT_INSTALL_DOCS/qtcore/qtcore.index \
qhp.projects = QtDataVisualization
qhp.QtDataVisualization.file = qtdatavisualization.qhp
-qhp.QtDataVisualization.namespace = com.digia.qtdatavisualization.100
+qhp.QtDataVisualization.namespace = com.digia.qtdatavisualization.110
qhp.QtDataVisualization.virtualFolder = qtdatavisualization
qhp.QtDataVisualization.indexTitle = Qt Data Visualization
qhp.QtDataVisualization.indexRoot =
-qhp.QtDataVisualization.filterAttributes = qtdatavisualization 1.0.0 qtrefdoc
-qhp.QtDataVisualization.customFilters.Qt.name = QtDataVisualization 1.0.0
-qhp.QtDataVisualization.customFilters.Qt.filterAttributes = qtdatavisualization 1.0.0
+qhp.QtDataVisualization.filterAttributes = qtdatavisualization 1.1.0 qtrefdoc
+qhp.QtDataVisualization.customFilters.Qt.name = QtDataVisualization 1.1.0
+qhp.QtDataVisualization.customFilters.Qt.filterAttributes = qtdatavisualization 1.1.0
qhp.QtDataVisualization.subprojects = gettingstarted examples classes types
qhp.QtDataVisualization.subprojects.gettingstarted.title = Getting Started
qhp.QtDataVisualization.subprojects.gettingstarted.indexTitle = Qt Data Visualization Getting Started
diff --git a/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp b/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp
index 0c54c2fe..56bfc5ee 100644
--- a/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp
+++ b/src/datavisualization/doc/snippets/doc_src_qmldatavisualization.cpp
@@ -17,12 +17,12 @@
****************************************************************************/
//! [0]
-import QtDataVisualization 1.0
+import QtDataVisualization 1.1
//! [0]
//! [1]
import QtQuick 2.0
-import QtDataVisualization 1.0
+import QtDataVisualization 1.1
Item {
width: 640
@@ -61,7 +61,7 @@ Item {
//! [2]
import QtQuick 2.0
-import QtDataVisualization 1.0
+import QtDataVisualization 1.1
Item {
width: 640
@@ -94,7 +94,7 @@ Item {
//! [3]
import QtQuick 2.0
-import QtDataVisualization 1.0
+import QtDataVisualization 1.1
Item {
width: 640
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc
index 891cc5c1..ba3173b0 100644
--- a/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-abstractdeclarative.qdoc
@@ -28,8 +28,9 @@
Note that this type is uncreatable, but contains properties that are shared between
the 3D visualizations.
- For AbstractGraph3D enums, see \l QAbstract3DGraph::SelectionFlag and
- \l QAbstract3DGraph::ShadowQuality
+ For AbstractGraph3D enums, see \l{QAbstract3DGraph::SelectionFlag},
+ \l{QAbstract3DGraph::ShadowQuality}, \l{QAbstract3DGraph::ElementType}, and
+ \l{QAbstract3DGraph::OptimizationHint}.
\sa Bars3D, Scatter3D, Surface3D, {Qt Data Visualization C++ Classes}
*/
@@ -57,7 +58,7 @@
/*!
\qmlproperty AbstractInputHandler3D AbstractGraph3D::inputHandler
- Input handler. You can disable default input handlers by setting this property to \c null.
+ Input handler. You can disable default input handlers by setting this property to \c {null}.
*/
/*!
@@ -119,13 +120,184 @@
When renderingMode is \c RenderDirectToBackground or \c RenderDirectToBackground_NoClear, this
property value is read-only and returns the number of samples specified by the window surface
format.
- Defaults to 4.
+ Defaults to \c{4}.
\sa renderingMode
*/
/*!
+ * \qmlproperty bool AbstractGraph3D::measureFps
+ * \since QtDataVisualization 1.1
+ *
+ * If \c {true}, the rendering is done continuously instead of on demand, and currentFps property
+ * is updated. Defaults to \c{false}.
+ *
+ * \sa currentFps
+ */
+
+/*!
+ * \qmlproperty int AbstractGraph3D::currentFps
+ * \since QtDataVisualization 1.1
+ *
+ * When fps measuring is enabled, the results for the last second are stored in this read-only
+ * property. It takes at least a second before this value updates after measurement is activated.
+ *
+ * \sa measureFps
+ */
+
+/*!
* \qmlmethod void AbstractGraph3D::clearSelection()
* Clears selection from all attached series.
*/
+/*!
+ * \qmlmethod int AbstractGraph3D::addCustomItem(Custom3DItem item)
+ *
+ * Adds a Custom3DItem \a item to the graph. Graph takes ownership of the added item.
+ *
+ * \return index to the added item if add was successful, -1 if trying to add a null item, and
+ * index of the item if trying to add an already added item.
+ *
+ * \sa removeCustomItems(), removeCustomItem(), removeCustomItemAt()
+ *
+ * \since QtDataVisualization 1.1
+ */
+
+/*!
+ * \qmlmethod void AbstractGraph3D::removeCustomItems()
+ *
+ * Removes all custom items. Deletes the resources allocated to them.
+ *
+ * \since QtDataVisualization 1.1
+ */
+
+/*!
+ * \qmlmethod void AbstractGraph3D::removeCustomItem(Custom3DItem item)
+ *
+ * Removes the custom \a {item}. Deletes the resources allocated to it.
+ *
+ * \since QtDataVisualization 1.1
+ */
+
+/*!
+ * \qmlmethod void AbstractGraph3D::removeCustomItemAt(vector3d position)
+ *
+ * Removes all custom items at \a {position}. Deletes the resources allocated to them.
+ *
+ * \since QtDataVisualization 1.1
+ */
+
+/*!
+ * \qmlmethod void AbstractGraph3D::releaseCustomItem(Custom3DItem item)
+ *
+ * Gets ownership of \a item back and removes the \a item from the graph.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \note If the same item is added back to the graph, the texture file needs to be re-set.
+ *
+ * \sa Custom3DItem::textureFile
+ */
+
+/*!
+ * \qmlmethod int AbstractGraph3D::selectedLabelIndex()
+ *
+ * Can be used to query the index of the selected label after receiving \c selectedElementChanged
+ * signal with any label type. Selection is valid until the next \c selectedElementChanged signal.
+ *
+ * \return index of the selected label, or -1.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+
+/*!
+ * \qmlmethod Abstract3DAxis AbstractGraph3D::selectedAxis()
+ *
+ * Can be used to get the selected axis after receiving \c selectedElementChanged signal with any label
+ * type. Selection is valid until the next \c selectedElementChanged signal.
+ *
+ * \return the selected axis, or null.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+
+/*!
+ * \qmlmethod int AbstractGraph3D::selectedCustomItemIndex()
+ *
+ * Can be used to query the index of the selected custom item after receiving \c selectedElementChanged
+ * signal with \l{QAbstract3DGraph::ElementCustomItem}{ElementCustomItem} type. Selection is valid
+ * until the next \c selectedElementChanged signal.
+ *
+ * \return index of the selected custom item, or -1.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+
+/*!
+ * \qmlmethod Custom3DItem AbstractGraph3D::selectedCustomItem()
+ *
+ * Can be used to get the selected custom item after receiving \c selectedElementChanged signal with
+ * \l{QAbstract3DGraph::ElementCustomItem}{ElementCustomItem} type. Ownership of the item remains
+ * with the graph. Selection is valid until the next \c selectedElementChanged signal.
+ *
+ * \return the selected custom item, or null.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+
+/*!
+ * \qmlproperty AbstractGraph3D.ElementType AbstractGraph3D::selectedElement
+ *
+ * Can be used to query the selected element type.
+ * Type is valid until the next \c selectedElementChanged signal.
+ *
+ * \c selectedElementChanged signal is emitted when a selection is made in the graph.
+ *
+ * Signal can be used for example for implementing customized input handling, as demonstrated in
+ * this \l {Qt Quick 2 Axis Dragging Example}{example}.
+ *
+ * \sa selectedLabelIndex(), selectedAxis(), selectedCustomItemIndex(), selectedCustomItem(),
+ * Bars3D::selectedSeries, Scatter3D::selectedSeries, Scene3D::selectionQueryPosition
+ *
+ * \since QtDataVisualization 1.1
+ */
+
+/*!
+ * \qmlproperty bool AbstractGraph3D::orthoProjection
+ * \since QtDataVisualization 1.1
+ *
+ * If \c {true}, orthographic projection will be used for displaying the graph. Defaults to \c{false}.
+ * \note Shadows will be disabled when set to \c{true}.
+ */
+
+/*!
+ * \qmlproperty real AbstractGraph3D::aspectRatio
+ * \since QtDataVisualization 1.1
+ *
+ * Aspect ratio of the graph data. This is the ratio of data scaling between horizontal and
+ * vertical axes. Defaults to \c{2.0}.
+ *
+ * \note Has no effect on Bars3D.
+ */
+
+/*!
+ * \qmlproperty AbstractGraph3D.OptimizationHints AbstractGraph3D::optimizationHints
+ * \since Qt Data Visualization 1.1
+ *
+ * Defines if the rendering optimization is default or static. Default mode provides the full feature set at
+ * reasonable performance. Static is a beta level feature and currently supports only a subset of the
+ * features on the Scatter graph. Missing features are object gradient for mesh objects, both gradients
+ * for points, and diffuse and specular color on rotations. At this point static is intended just for
+ * introducing a new feature. It optimizes graph rendering and is ideal for large non-changing data
+ * sets. It is slower with dynamic data changes and item rotations. Selection is not optimized, so using it
+ * with massive data sets is not advisable.
+ * Defaults to \c{OptimizationDefault}
+ */
diff --git a/src/datavisualization/doc/src/qtdatavisualization-qml-color.qdoc b/src/datavisualization/doc/src/qtdatavisualization-qml-color.qdoc
new file mode 100644
index 00000000..e845adea
--- /dev/null
+++ b/src/datavisualization/doc/src/qtdatavisualization-qml-color.qdoc
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+/*!
+ \qmltype ThemeColor
+ \inqmlmodule QtDataVisualization
+ \since QtDataVisualization 1.0
+ \ingroup datavisualization_qml
+ \brief Defines the color in a Theme3D.
+
+ Defines a color in Theme3D::baseColors property of Theme3D.
+*/
+
+/*!
+ \qmlproperty color ThemeColor::color
+
+ The color property describes the color of this ThemeColor.
+
+ The default color is black.
+*/
diff --git a/src/datavisualization/doc/src/qtdatavisualization.qdoc b/src/datavisualization/doc/src/qtdatavisualization.qdoc
index 836823e6..af419814 100644
--- a/src/datavisualization/doc/src/qtdatavisualization.qdoc
+++ b/src/datavisualization/doc/src/qtdatavisualization.qdoc
@@ -37,7 +37,7 @@
*/
/*!
- \qmlmodule QtDataVisualization 1.0
+ \qmlmodule QtDataVisualization 1.1
\title Qt Data Visualization QML Types
\ingroup qmlmodules
@@ -73,8 +73,8 @@
in the package manager.
After installation Qt Data Visualization documentation and examples are available in Qt Creator.
- You can find all Qt Data Visualization examples by typing \c visualization in the
- \c {Search in Examples...} field.
+ Examples can be found on the examples page of Qt Creator by selecting the Qt Data Visualization
+ component from the drop-down menu.
The source code is installed into the QtDataVisualization folder under EnterpriseAddOns.
@@ -238,9 +238,18 @@
and which role specifies the value of the item. When the proxy resolves the data from the model,
it uses these mappings to generate the rows and columns of the bar graph.
+ Often the item models will have a single role that contains information you want to map to
+ multiple values. A typical example of this is a timestamp field when generating a bar graph
+ with two time related axes, for example years and months. To enable mapping a single item
+ model role to more than one data field, pattern matching and replacing mechanism is provided
+ by item model proxies. You can also use this mechanism to reformat data even in one-to-one
+ mapping cases.
+
Depending on the visualization type, proxies may support other functionalities as well,
such as QItemModelBarDataProxy optionally mapping QAbstractItemModel rows and columns directly
- into bar graph rows and columns. See individual proxy classes for more information and examples
+ into bar graph rows and columns.
+
+ See individual proxy classes for more information and examples
about how to use them: QItemModelBarDataProxy, QItemModelScatterDataProxy, and
QItemModelSurfaceDataProxy.
@@ -257,28 +266,27 @@
When you have a data set that updates rapidly, it is important to handle data properly to
ensure good performance. Since memory allocation is a costly operation, always use
- QList::reserve() and QVector::resize() where possible to avoid reallocations when constructing
- the array to give to the proxy. If you need to change the entire data set for each frame,
- it is in most cases best to reuse the existing array - especially if the array dimensions do not
- change. If you need to add, insert, remove, or change several rows or items for each frame, it
- is always more efficient to do it with one method call instead of multiple calls affecting
- a single row or item each. For example, adding ten rows with a single QBarDataProxy::addRows() call
- is much more efficient than ten separate QBarDataProxy::addRow() calls.
-
- Bars renderer is optimized to access only data that is within the data window and thus should not
- suffer noticeable slowdown even if more data is continually added to the proxy.
+ QList::reserve() and QVector::resize() where possible to avoid unnecessary reallocations when
+ constructing the array to give to the proxy. If you need to change the entire data set
+ for each frame, it is in most cases best to reuse the existing array - especially if the
+ array dimensions do not change. If you need to add, insert, remove, or change several
+ rows or items for each frame, it is always more efficient to do it with one method call
+ instead of multiple calls affecting a single row or item each. For example, adding ten
+ rows with a single QBarDataProxy::addRows() call is much more efficient than ten
+ separate QBarDataProxy::addRow() calls.
+
+ Bars renderer is optimized to access only data that is within the data window and thus
+ should not suffer noticeable slowdown even if more data is continually added to the proxy.
Due to the unsorted nature of the scatter data, any change in the data window ranges requires
all data points to be checked for visibility, which can cause increasing slowdown if data is
- continually added to the proxy.
+ continually added to the proxy. For the best performance with the scatter graphs, only keep
+ the data you need in the proxy.
Surface data, while on item level similar to scatter data, is already assigned into rows and
- columns, so the surface renderer can do some optimization by making the assumption that the data in
- rows and columns is sorted along their respective axes, but it is nowhere near as efficient
- as in the bars case. Surface rendering can suffer significant slowdown if the data size grows unchecked.
-
- For the best performance with the scatter and surface graphs, only keep the data you need in the
- proxy.
+ columns, so the surface renderer can optimize drawing by making the assumption that
+ the data in the rows and columns is sorted along their respective axes. It is not quite as
+ efficient as in the bars case, but nearly so.
*/
/*!
@@ -303,7 +311,8 @@
a single row or column.
Bar graph additionally supports simply highlighting the whole row and/or column of the selected bar
- without opening the slice view.
+ without opening the slice view. Bar graph also supports selecting/slicing a whole row and/or
+ column by clicking the axis label, based on selection mode.
When multiple series are added to a graph, selecting an item in one of them will clear the selection
on other series.
@@ -322,10 +331,12 @@
\li Q3DLight class (and Light3D QML item) are currently not usable for anything.
\li Changing any of Q3DScene properties affecting subviewports currently has no effect.
\li The color style Q3DTheme::ColorStyleObjectGradient doesn't work for surface graphs.
- \li Scatter "point" meshes (QAbstract3DSeries::MeshPoint) do not support gradients, they
- always use the base color.
\li Widget based examples layout incorrectly in iOS.
\li Reparenting a graph to an item in another QQuickWindow is not supported.
+ \li There is a low-impact binary break between 1.0 and 1.1. The break is due to a QML type
+ registration conflict with QAbstractItemModel between QtDataVisualization and
+ QtCommercial.Charts. Introducing the binary break makes it possible to use both
+ Charts and Data Visualization in the same QML application.
\endlist
*/
diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp
index ec18a850..8658d463 100644
--- a/src/datavisualization/engine/abstract3dcontroller.cpp
+++ b/src/datavisualization/engine/abstract3dcontroller.cpp
@@ -17,22 +17,16 @@
****************************************************************************/
#include "abstract3dcontroller_p.h"
-#include "camerahelper_p.h"
#include "qabstract3daxis_p.h"
-#include "qvalue3daxis.h"
-#include "qcategory3daxis.h"
+#include "qvalue3daxis_p.h"
#include "abstract3drenderer_p.h"
-#include "q3dcamera.h"
-#include "q3dlight.h"
-#include "qabstractdataproxy_p.h"
#include "qabstract3dinputhandler_p.h"
#include "qtouch3dinputhandler.h"
-#include "qabstract3dseries_p.h"
#include "thememanager_p.h"
#include "q3dtheme_p.h"
-#include "q3dscene_p.h"
-#include "q3dscene.h"
+#include "qcustom3ditem_p.h"
#include <QtCore/QThread>
+#include <QtGui/QOpenGLFramebufferObject>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -42,6 +36,9 @@ Abstract3DController::Abstract3DController(QRect initialViewport, Q3DScene *scen
m_themeManager(new ThemeManager(this)),
m_selectionMode(QAbstract3DGraph::SelectionItem),
m_shadowQuality(QAbstract3DGraph::ShadowQualityMedium),
+ m_useOrthoProjection(false),
+ m_aspectRatio(2.0f),
+ m_optimizationHints(QAbstract3DGraph::OptimizationDefault),
m_scene(scene),
m_activeInputHandler(0),
m_axisX(0),
@@ -49,9 +46,13 @@ Abstract3DController::Abstract3DController(QRect initialViewport, Q3DScene *scen
m_axisZ(0),
m_renderer(0),
m_isDataDirty(true),
- m_isSeriesVisibilityDirty(true),
+ m_isCustomDataDirty(true),
+ m_isCustomItemDirty(true),
m_isSeriesVisualsDirty(true),
- m_renderPending(false)
+ m_renderPending(false),
+ m_measureFps(false),
+ m_numFrames(0),
+ m_currentFps(0.0)
{
if (!m_scene)
m_scene = new Q3DScene;
@@ -84,6 +85,9 @@ Abstract3DController::~Abstract3DController()
destroyRenderer();
delete m_scene;
delete m_themeManager;
+ foreach (QCustom3DItem *item, m_customItems)
+ delete item;
+ m_customItems.clear();
}
void Abstract3DController::destroyRenderer()
@@ -142,7 +146,7 @@ void Abstract3DController::removeSeries(QAbstract3DSeries *series)
this, &Abstract3DController::handleSeriesVisibilityChanged);
series->d_ptr->setController(0);
m_isDataDirty = true;
- m_isSeriesVisibilityDirty = true;
+ m_isSeriesVisualsDirty = true;
emitNeedRender();
}
}
@@ -182,6 +186,46 @@ void Abstract3DController::synchDataToRenderer()
m_changeTracker.selectionModeChanged = false;
}
+ if (m_changeTracker.projectionChanged) {
+ m_renderer->m_useOrthoProjection = m_useOrthoProjection;
+ m_changeTracker.projectionChanged = false;
+ }
+
+ if (m_changeTracker.aspectRatioChanged) {
+ m_renderer->updateAspectRatio(m_aspectRatio);
+ m_changeTracker.aspectRatioChanged = false;
+ }
+
+ if (m_changeTracker.optimizationHintChanged) {
+ m_renderer->updateOptimizationHint(m_optimizationHints);
+ m_changeTracker.optimizationHintChanged = false;
+ }
+
+ if (m_changeTracker.axisXFormatterChanged) {
+ m_changeTracker.axisXFormatterChanged = false;
+ if (m_axisX->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX);
+ m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationX,
+ valueAxisX->formatter());
+ }
+ }
+ if (m_changeTracker.axisYFormatterChanged) {
+ m_changeTracker.axisYFormatterChanged = false;
+ if (m_axisY->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY);
+ m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationY,
+ valueAxisY->formatter());
+ }
+ }
+ if (m_changeTracker.axisZFormatterChanged) {
+ m_changeTracker.axisZFormatterChanged = false;
+ if (m_axisZ->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisZ = static_cast<QValue3DAxis *>(m_axisZ);
+ m_renderer->updateAxisFormatter(QAbstract3DAxis::AxisOrientationZ,
+ valueAxisZ->formatter());
+ }
+ }
+
if (m_changeTracker.axisXTypeChanged) {
m_renderer->updateAxisType(QAbstract3DAxis::AxisOrientationX, m_axisX->type());
m_changeTracker.axisXTypeChanged = false;
@@ -325,9 +369,89 @@ void Abstract3DController::synchDataToRenderer()
}
}
- if (m_isSeriesVisibilityDirty || m_isSeriesVisualsDirty) {
- m_renderer->updateSeries(m_seriesList, m_isSeriesVisibilityDirty);
- m_isSeriesVisibilityDirty = false;
+ if (m_changeTracker.axisXReversedChanged) {
+ m_changeTracker.axisXReversedChanged = false;
+ if (m_axisX->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX);
+ m_renderer->updateAxisReversed(QAbstract3DAxis::AxisOrientationX,
+ valueAxisX->reversed());
+ }
+ }
+
+ if (m_changeTracker.axisYReversedChanged) {
+ m_changeTracker.axisYReversedChanged = false;
+ if (m_axisY->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY);
+ m_renderer->updateAxisReversed(QAbstract3DAxis::AxisOrientationY,
+ valueAxisY->reversed());
+ }
+ }
+
+ if (m_changeTracker.axisZReversedChanged) {
+ m_changeTracker.axisZReversedChanged = false;
+ if (m_axisZ->type() & QAbstract3DAxis::AxisTypeValue) {
+ QValue3DAxis *valueAxisZ = static_cast<QValue3DAxis *>(m_axisZ);
+ m_renderer->updateAxisReversed(QAbstract3DAxis::AxisOrientationZ,
+ valueAxisZ->reversed());
+ }
+ }
+
+ if (m_changeTracker.axisXLabelAutoRotationChanged) {
+ m_renderer->updateAxisLabelAutoRotation(QAbstract3DAxis::AxisOrientationX,
+ m_axisX->labelAutoRotation());
+ m_changeTracker.axisXLabelAutoRotationChanged = false;
+ }
+
+ if (m_changeTracker.axisYLabelAutoRotationChanged) {
+ m_renderer->updateAxisLabelAutoRotation(QAbstract3DAxis::AxisOrientationY,
+ m_axisY->labelAutoRotation());
+ m_changeTracker.axisYLabelAutoRotationChanged = false;
+ }
+
+ if (m_changeTracker.axisZLabelAutoRotationChanged) {
+ m_renderer->updateAxisLabelAutoRotation(QAbstract3DAxis::AxisOrientationZ,
+ m_axisZ->labelAutoRotation());
+ m_changeTracker.axisZLabelAutoRotationChanged = false;
+ }
+
+ if (m_changeTracker.axisXTitleVisibilityChanged) {
+ m_renderer->updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientationX,
+ m_axisX->isTitleVisible());
+ m_changeTracker.axisXTitleVisibilityChanged = false;
+ }
+ if (m_changeTracker.axisYTitleVisibilityChanged) {
+ m_renderer->updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientationY,
+ m_axisY->isTitleVisible());
+ m_changeTracker.axisYTitleVisibilityChanged = false;
+ }
+ if (m_changeTracker.axisZTitleVisibilityChanged) {
+ m_renderer->updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientationZ,
+ m_axisZ->isTitleVisible());
+ m_changeTracker.axisZTitleVisibilityChanged = false;
+ }
+ if (m_changeTracker.axisXTitleFixedChanged) {
+ m_renderer->updateAxisTitleFixed(QAbstract3DAxis::AxisOrientationX,
+ m_axisX->isTitleFixed());
+ m_changeTracker.axisXTitleFixedChanged = false;
+ }
+ if (m_changeTracker.axisYTitleFixedChanged) {
+ m_renderer->updateAxisTitleFixed(QAbstract3DAxis::AxisOrientationY,
+ m_axisY->isTitleFixed());
+ m_changeTracker.axisYTitleFixedChanged = false;
+ }
+ if (m_changeTracker.axisZTitleFixedChanged) {
+ m_renderer->updateAxisTitleFixed(QAbstract3DAxis::AxisOrientationZ,
+ m_axisZ->isTitleFixed());
+ m_changeTracker.axisZTitleFixedChanged = false;
+ }
+
+ if (m_changedSeriesList.size()) {
+ m_renderer->modifiedSeriesList(m_changedSeriesList);
+ m_changedSeriesList.clear();
+ }
+
+ if (m_isSeriesVisualsDirty) {
+ m_renderer->updateSeries(m_seriesList);
m_isSeriesVisualsDirty = false;
}
@@ -337,6 +461,16 @@ void Abstract3DController::synchDataToRenderer()
m_renderer->updateData();
m_isDataDirty = false;
}
+
+ if (m_isCustomDataDirty) {
+ m_renderer->updateCustomData(m_customItems);
+ m_isCustomDataDirty = false;
+ }
+
+ if (m_isCustomItemDirty) {
+ m_renderer->updateCustomItems();
+ m_isCustomItemDirty = false;
+ }
}
void Abstract3DController::render(const GLuint defaultFboHandle)
@@ -347,12 +481,21 @@ void Abstract3DController::render(const GLuint defaultFboHandle)
if (!m_renderer)
return;
- m_renderer->render(defaultFboHandle);
+ if (m_measureFps) {
+ // Measure speed (as milliseconds per frame)
+ m_numFrames++;
+ int elapsed = m_frameTimer.elapsed();
+ if (elapsed >= 1000) {
+ m_currentFps = qreal(m_numFrames) * 1000.0 / qreal(elapsed);
+ emit currentFpsChanged(m_currentFps);
+ m_numFrames = 0;
+ m_frameTimer.restart();
+ }
+ // To get meaningful framerate, don't just do render on demand.
+ emitNeedRender();
+ }
-#ifdef DISPLAY_RENDER_SPEED
- // To get meaningful framerate, don't just do render on demand.
- emitNeedRender();
-#endif
+ m_renderer->render(defaultFboHandle);
}
void Abstract3DController::mouseDoubleClickEvent(QMouseEvent *event)
@@ -445,7 +588,8 @@ void Abstract3DController::handleThemeSingleHighlightColorChanged(const QColor &
markSeriesVisualsDirty();
}
-void Abstract3DController::handleThemeSingleHighlightGradientChanged(const QLinearGradient &gradient)
+void Abstract3DController::handleThemeSingleHighlightGradientChanged(
+ const QLinearGradient &gradient)
{
// Set value for series that have not explicitly set this value
foreach (QAbstract3DSeries *series, m_seriesList) {
@@ -503,7 +647,7 @@ void Abstract3DController::setAxisX(QAbstract3DAxis *axis)
}
}
-QAbstract3DAxis *Abstract3DController::axisX()
+QAbstract3DAxis *Abstract3DController::axisX() const
{
return m_axisX;
}
@@ -517,7 +661,7 @@ void Abstract3DController::setAxisY(QAbstract3DAxis *axis)
}
}
-QAbstract3DAxis *Abstract3DController::axisY()
+QAbstract3DAxis *Abstract3DController::axisY() const
{
return m_axisY;
}
@@ -531,7 +675,7 @@ void Abstract3DController::setAxisZ(QAbstract3DAxis *axis)
}
}
-QAbstract3DAxis *Abstract3DController::axisZ()
+QAbstract3DAxis *Abstract3DController::axisZ() const
{
return m_axisZ;
}
@@ -648,19 +792,6 @@ QList<QAbstract3DInputHandler *> Abstract3DController::inputHandlers() const
return m_inputHandlers;
}
-int Abstract3DController::zoomLevel()
-{
- return m_scene->activeCamera()->zoomLevel();
-}
-
-void Abstract3DController::setZoomLevel(int zoomLevel)
-{
- m_scene->activeCamera()->setZoomLevel(zoomLevel);
-
- m_changeTracker.zoomLevelChanged = true;
- emitNeedRender();
-}
-
void Abstract3DController::addTheme(Q3DTheme *theme)
{
m_themeManager->addTheme(theme);
@@ -675,12 +806,13 @@ void Abstract3DController::releaseTheme(Q3DTheme *theme)
if (oldTheme != m_themeManager->activeTheme())
emit activeThemeChanged(m_themeManager->activeTheme());
}
+
QList<Q3DTheme *> Abstract3DController::themes() const
{
return m_themeManager->themes();
}
-void Abstract3DController::setActiveTheme(Q3DTheme *theme)
+void Abstract3DController::setActiveTheme(Q3DTheme *theme, bool force)
{
if (theme != m_themeManager->activeTheme()) {
m_themeManager->setActiveTheme(theme);
@@ -689,7 +821,7 @@ void Abstract3DController::setActiveTheme(Q3DTheme *theme)
Q3DTheme *newActiveTheme = m_themeManager->activeTheme();
// Reset all attached series to the new theme
for (int i = 0; i < m_seriesList.size(); i++)
- m_seriesList.at(i)->d_ptr->resetToTheme(*newActiveTheme, i, true);
+ m_seriesList.at(i)->d_ptr->resetToTheme(*newActiveTheme, i, force);
markSeriesVisualsDirty();
emit activeThemeChanged(newActiveTheme);
}
@@ -717,6 +849,12 @@ QAbstract3DGraph::SelectionFlags Abstract3DController::selectionMode() const
void Abstract3DController::setShadowQuality(QAbstract3DGraph::ShadowQuality quality)
{
+ if (!m_useOrthoProjection)
+ doSetShadowQuality(quality);
+}
+
+void Abstract3DController::doSetShadowQuality(QAbstract3DGraph::ShadowQuality quality)
+{
if (quality != m_shadowQuality) {
m_shadowQuality = quality;
m_changeTracker.shadowQualityChanged = true;
@@ -730,6 +868,22 @@ QAbstract3DGraph::ShadowQuality Abstract3DController::shadowQuality() const
return m_shadowQuality;
}
+void Abstract3DController::setOptimizationHints(QAbstract3DGraph::OptimizationHints hints)
+{
+ if (hints != m_optimizationHints) {
+ m_optimizationHints = hints;
+ m_changeTracker.optimizationHintChanged = true;
+ m_isDataDirty = true;
+ emit optimizationHintsChanged(hints);
+ emitNeedRender();
+ }
+}
+
+QAbstract3DGraph::OptimizationHints Abstract3DController::optimizationHints() const
+{
+ return m_optimizationHints;
+}
+
bool Abstract3DController::shadowsSupported() const
{
#if defined(QT_OPENGL_ES_2)
@@ -747,7 +901,6 @@ bool Abstract3DController::isSlicingActive() const
void Abstract3DController::setSlicingActive(bool isSlicing)
{
m_scene->setSlicingActive(isSlicing);
- emitNeedRender();
}
Q3DScene *Abstract3DController::scene()
@@ -758,6 +911,8 @@ Q3DScene *Abstract3DController::scene()
void Abstract3DController::markDataDirty()
{
m_isDataDirty = true;
+
+ markSeriesItemLabelsDirty();
emitNeedRender();
}
@@ -767,6 +922,79 @@ void Abstract3DController::markSeriesVisualsDirty()
emitNeedRender();
}
+void Abstract3DController::requestRender(QOpenGLFramebufferObject *fbo)
+{
+ m_renderer->render(fbo->handle());
+}
+
+int Abstract3DController::addCustomItem(QCustom3DItem *item)
+{
+ if (!item)
+ return -1;
+
+ int index = m_customItems.indexOf(item);
+
+ if (index != -1)
+ return index;
+
+ item->setParent(this);
+ connect(item->d_ptr.data(), &QCustom3DItemPrivate::needUpdate,
+ this, &Abstract3DController::updateCustomItem);
+ m_customItems.append(item);
+ item->d_ptr->resetDirtyBits();
+ m_isCustomDataDirty = true;
+ emitNeedRender();
+ return m_customItems.count() - 1;
+}
+
+void Abstract3DController::deleteCustomItems()
+{
+ foreach (QCustom3DItem *item, m_customItems)
+ delete item;
+ m_customItems.clear();
+ m_isCustomDataDirty = true;
+ emitNeedRender();
+}
+
+void Abstract3DController::deleteCustomItem(QCustom3DItem *item)
+{
+ if (!item)
+ return;
+
+ m_customItems.removeOne(item);
+ delete item;
+ item = 0;
+ m_isCustomDataDirty = true;
+ emitNeedRender();
+}
+
+void Abstract3DController::deleteCustomItem(const QVector3D &position)
+{
+ // Get the item for the position
+ foreach (QCustom3DItem *item, m_customItems) {
+ if (item->position() == position)
+ deleteCustomItem(item);
+ }
+}
+
+void Abstract3DController::releaseCustomItem(QCustom3DItem *item)
+{
+ if (item && m_customItems.contains(item)) {
+ disconnect(item->d_ptr.data(), &QCustom3DItemPrivate::needUpdate,
+ this, &Abstract3DController::updateCustomItem);
+ m_customItems.removeOne(item);
+ item->setParent(0);
+ m_isCustomDataDirty = true;
+ emitNeedRender();
+ }
+}
+
+void Abstract3DController::updateCustomItem()
+{
+ m_isCustomItemDirty = true;
+ emitNeedRender();
+}
+
void Abstract3DController::handleAxisTitleChanged(const QString &title)
{
Q_UNUSED(title)
@@ -783,6 +1011,8 @@ void Abstract3DController::handleAxisTitleChangedBySender(QObject *sender)
m_changeTracker.axisZTitleChanged = true;
else
qWarning() << __FUNCTION__ << "invoked for invalid axis";
+
+ markSeriesItemLabelsDirty();
emitNeedRender();
}
@@ -801,6 +1031,8 @@ void Abstract3DController::handleAxisLabelsChangedBySender(QObject *sender)
m_changeTracker.axisZLabelsChanged = true;
else
qWarning() << __FUNCTION__ << "invoked for invalid axis";
+
+ markSeriesItemLabelsDirty();
emitNeedRender();
}
@@ -882,6 +1114,35 @@ void Abstract3DController::handleAxisLabelFormatChanged(const QString &format)
handleAxisLabelFormatChangedBySender(sender());
}
+void Abstract3DController::handleAxisReversedChanged(bool enable)
+{
+ Q_UNUSED(enable)
+ handleAxisReversedChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisFormatterDirty()
+{
+ handleAxisFormatterDirtyBySender(sender());
+}
+
+void Abstract3DController::handleAxisLabelAutoRotationChanged(float angle)
+{
+ Q_UNUSED(angle)
+ handleAxisLabelAutoRotationChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisTitleVisibilityChanged(bool visible)
+{
+ Q_UNUSED(visible)
+ handleAxisTitleVisibilityChangedBySender(sender());
+}
+
+void Abstract3DController::handleAxisTitleFixedChanged(bool fixed)
+{
+ Q_UNUSED(fixed)
+ handleAxisTitleFixedChangedBySender(sender());
+}
+
void Abstract3DController::handleInputViewChanged(QAbstract3DInputHandler::InputView view)
{
// When in automatic slicing mode, input view change to primary disables slice mode
@@ -890,15 +1151,12 @@ void Abstract3DController::handleInputViewChanged(QAbstract3DInputHandler::Input
setSlicingActive(false);
}
- m_changeTracker.inputViewChanged = true;
emitNeedRender();
}
void Abstract3DController::handleInputPositionChanged(const QPoint &position)
{
Q_UNUSED(position)
-
- m_changeTracker.inputPositionChanged = true;
emitNeedRender();
}
@@ -914,6 +1172,21 @@ void Abstract3DController::handleRequestShadowQuality(QAbstract3DGraph::ShadowQu
setShadowQuality(quality);
}
+void Abstract3DController::setMeasureFps(bool enable)
+{
+ if (m_measureFps != enable) {
+ m_measureFps = enable;
+ m_currentFps = 0.0;
+
+ if (enable) {
+ m_frameTimer.start();
+ m_numFrames = -1;
+ emitNeedRender();
+ }
+ emit measureFpsChanged(enable);
+ }
+}
+
void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender)
{
// Label format changing needs to dirty the data so that labels are reset.
@@ -932,15 +1205,104 @@ void Abstract3DController::handleAxisLabelFormatChangedBySender(QObject *sender)
emitNeedRender();
}
+void Abstract3DController::handleAxisReversedChangedBySender(QObject *sender)
+{
+ // Reversing change needs to dirty the data so item positions are recalculated
+ if (sender == m_axisX) {
+ m_isDataDirty = true;
+ m_changeTracker.axisXReversedChanged = true;
+ } else if (sender == m_axisY) {
+ m_isDataDirty = true;
+ m_changeTracker.axisYReversedChanged = true;
+ } else if (sender == m_axisZ) {
+ m_isDataDirty = true;
+ m_changeTracker.axisZReversedChanged = true;
+ } else {
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ }
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisFormatterDirtyBySender(QObject *sender)
+{
+ // Sender is QValue3DAxisPrivate
+ QValue3DAxis *valueAxis = static_cast<QValue3DAxisPrivate *>(sender)->qptr();
+ if (valueAxis == m_axisX) {
+ m_isDataDirty = true;
+ m_changeTracker.axisXFormatterChanged = true;
+ } else if (valueAxis == m_axisY) {
+ m_isDataDirty = true;
+ m_changeTracker.axisYFormatterChanged = true;
+ } else if (valueAxis == m_axisZ) {
+ m_isDataDirty = true;
+ m_changeTracker.axisZFormatterChanged = true;
+ } else {
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+ }
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisLabelAutoRotationChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXLabelAutoRotationChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYLabelAutoRotationChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZLabelAutoRotationChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisTitleVisibilityChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXTitleVisibilityChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYTitleVisibilityChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZTitleVisibilityChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+
+ emitNeedRender();
+}
+
+void Abstract3DController::handleAxisTitleFixedChangedBySender(QObject *sender)
+{
+ if (sender == m_axisX)
+ m_changeTracker.axisXTitleFixedChanged = true;
+ else if (sender == m_axisY)
+ m_changeTracker.axisYTitleFixedChanged = true;
+ else if (sender == m_axisZ)
+ m_changeTracker.axisZTitleFixedChanged = true;
+ else
+ qWarning() << __FUNCTION__ << "invoked for invalid axis";
+
+ emitNeedRender();
+}
+
void Abstract3DController::handleSeriesVisibilityChangedBySender(QObject *sender)
{
- Q_UNUSED(sender)
+ QAbstract3DSeries *series = static_cast<QAbstract3DSeries *>(sender);
+ series->d_ptr->m_changeTracker.visibilityChanged = true;
m_isDataDirty = true;
- m_isSeriesVisibilityDirty = true;
+ m_isSeriesVisualsDirty = true;
+
+ adjustAxisRanges();
+
emitNeedRender();
}
+void Abstract3DController::markSeriesItemLabelsDirty()
+{
+ for (int i = 0; i < m_seriesList.size(); i++)
+ m_seriesList.at(i)->d_ptr->markItemLabelDirty();
+}
+
void Abstract3DController::setAxisHelper(QAbstract3DAxis::AxisOrientation orientation,
QAbstract3DAxis *axis, QAbstract3DAxis **axisPtr)
{
@@ -978,6 +1340,12 @@ void Abstract3DController::setAxisHelper(QAbstract3DAxis::AxisOrientation orient
this, &Abstract3DController::handleAxisRangeChanged);
QObject::connect(axis, &QAbstract3DAxis::autoAdjustRangeChanged,
this, &Abstract3DController::handleAxisAutoAdjustRangeChanged);
+ QObject::connect(axis, &QAbstract3DAxis::labelAutoRotationChanged,
+ this, &Abstract3DController::handleAxisLabelAutoRotationChanged);
+ QObject::connect(axis, &QAbstract3DAxis::titleVisibilityChanged,
+ this, &Abstract3DController::handleAxisTitleVisibilityChanged);
+ QObject::connect(axis, &QAbstract3DAxis::titleFixedChanged,
+ this, &Abstract3DController::handleAxisTitleFixedChanged);
if (orientation == QAbstract3DAxis::AxisOrientationX)
m_changeTracker.axisXTypeChanged = true;
@@ -991,6 +1359,9 @@ void Abstract3DController::setAxisHelper(QAbstract3DAxis::AxisOrientation orient
handleAxisRangeChangedBySender(axis);
handleAxisAutoAdjustRangeChangedInOrientation(axis->orientation(),
axis->isAutoAdjustRange());
+ handleAxisLabelAutoRotationChangedBySender(axis);
+ handleAxisTitleVisibilityChangedBySender(axis);
+ handleAxisTitleFixedChangedBySender(axis);
if (axis->type() & QAbstract3DAxis::AxisTypeValue) {
QValue3DAxis *valueAxis = static_cast<QValue3DAxis *>(axis);
@@ -1000,14 +1371,21 @@ void Abstract3DController::setAxisHelper(QAbstract3DAxis::AxisOrientation orient
this, &Abstract3DController::handleAxisSubSegmentCountChanged);
QObject::connect(valueAxis, &QValue3DAxis::labelFormatChanged,
this, &Abstract3DController::handleAxisLabelFormatChanged);
+ QObject::connect(valueAxis, &QValue3DAxis::reversedChanged,
+ this, &Abstract3DController::handleAxisReversedChanged);
+ QObject::connect(valueAxis->dptr(), &QValue3DAxisPrivate::formatterDirty,
+ this, &Abstract3DController::handleAxisFormatterDirty);
handleAxisSegmentCountChangedBySender(valueAxis);
handleAxisSubSegmentCountChangedBySender(valueAxis);
handleAxisLabelFormatChangedBySender(valueAxis);
+ handleAxisReversedChangedBySender(valueAxis);
+ handleAxisFormatterDirtyBySender(valueAxis->dptr());
}
}
-QAbstract3DAxis *Abstract3DController::createDefaultAxis(QAbstract3DAxis::AxisOrientation orientation)
+QAbstract3DAxis *Abstract3DController::createDefaultAxis(
+ QAbstract3DAxis::AxisOrientation orientation)
{
Q_UNUSED(orientation)
@@ -1047,4 +1425,97 @@ void Abstract3DController::emitNeedRender()
}
}
+void Abstract3DController::handlePendingClick()
+{
+ QAbstract3DGraph::ElementType type = m_renderer->clickedType();
+ emit elementSelected(type);
+}
+
+int Abstract3DController::selectedLabelIndex() const
+{
+ int index = m_renderer->m_selectedLabelIndex;
+ QAbstract3DAxis *axis = selectedAxis();
+ if (axis && axis->labels().count() <= index)
+ index = -1;
+ return index;
+}
+
+QAbstract3DAxis *Abstract3DController::selectedAxis() const
+{
+ QAbstract3DAxis *axis = 0;
+ QAbstract3DGraph::ElementType type = m_renderer->clickedType();
+ switch (type) {
+ case QAbstract3DGraph::ElementAxisXLabel:
+ axis = axisX();
+ break;
+ case QAbstract3DGraph::ElementAxisYLabel:
+ axis = axisY();
+ break;
+ case QAbstract3DGraph::ElementAxisZLabel:
+ axis = axisZ();
+ break;
+ default:
+ axis = 0;
+ break;
+ }
+
+ return axis;
+}
+
+int Abstract3DController::selectedCustomItemIndex() const
+{
+ int index = m_renderer->m_selectedCustomItemIndex;
+ if (m_customItems.count() <= index)
+ index = -1;
+ return index;
+}
+
+QCustom3DItem *Abstract3DController::selectedCustomItem() const
+{
+ QCustom3DItem *item = 0;
+ int index = selectedCustomItemIndex();
+ if (index >= 0)
+ item = m_customItems[index];
+ return item;
+}
+
+QAbstract3DGraph::ElementType Abstract3DController::selectedElement() const
+{
+ return m_renderer->clickedType();
+}
+
+void Abstract3DController::setOrthoProjection(bool enable)
+{
+ if (enable != m_useOrthoProjection) {
+ m_useOrthoProjection = enable;
+ m_changeTracker.projectionChanged = true;
+ emit orthoProjectionChanged(m_useOrthoProjection);
+ // If changed to ortho, disable shadows
+ if (m_useOrthoProjection)
+ doSetShadowQuality(QAbstract3DGraph::ShadowQualityNone);
+ emitNeedRender();
+ }
+}
+
+bool Abstract3DController::isOrthoProjection() const
+{
+ return m_useOrthoProjection;
+}
+
+void Abstract3DController::setAspectRatio(float ratio)
+{
+ if (m_aspectRatio != ratio) {
+ m_aspectRatio = ratio;
+ m_changeTracker.aspectRatioChanged = true;
+ emit aspectRatioChanged(m_aspectRatio);
+ m_isDataDirty = true;
+ emitNeedRender();
+ }
+}
+
+float Abstract3DController::aspectRatio()
+{
+ return m_aspectRatio;
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/abstract3dcontroller_p.h b/src/datavisualization/engine/abstract3dcontroller_p.h
index 06be450e..0e4d1add 100644
--- a/src/datavisualization/engine/abstract3dcontroller_p.h
+++ b/src/datavisualization/engine/abstract3dcontroller_p.h
@@ -33,25 +33,25 @@
#include "qabstract3daxis.h"
#include "drawer_p.h"
#include "qabstract3dinputhandler.h"
-#include "qabstractdataproxy.h"
+#include "qabstract3dgraph.h"
#include "q3dscene_p.h"
+#include "qcustom3ditem.h"
#include <QtGui/QLinearGradient>
+#include <QtCore/QTime>
-class QFont;
+class QOpenGLFramebufferObject;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-class CameraHelper;
class Abstract3DRenderer;
class QAbstract3DSeries;
class ThemeManager;
struct Abstract3DChangeBitField {
- bool zoomLevelChanged : 1;
bool themeChanged : 1;
bool shadowQualityChanged : 1;
bool selectionModeChanged : 1;
- bool objFileChanged : 1;
+ bool optimizationHintChanged : 1;
bool axisXTypeChanged : 1;
bool axisYTypeChanged : 1;
bool axisZTypeChanged : 1;
@@ -73,15 +73,29 @@ struct Abstract3DChangeBitField {
bool axisXLabelFormatChanged : 1;
bool axisYLabelFormatChanged : 1;
bool axisZLabelFormatChanged : 1;
- bool inputViewChanged : 1;
- bool inputPositionChanged : 1;
+ bool axisXReversedChanged : 1;
+ bool axisYReversedChanged : 1;
+ bool axisZReversedChanged : 1;
+ bool axisXFormatterChanged : 1;
+ bool axisYFormatterChanged : 1;
+ bool axisZFormatterChanged : 1;
+ bool projectionChanged : 1;
+ bool axisXLabelAutoRotationChanged : 1;
+ bool axisYLabelAutoRotationChanged : 1;
+ bool axisZLabelAutoRotationChanged : 1;
+ bool aspectRatioChanged : 1;
+ bool axisXTitleVisibilityChanged : 1;
+ bool axisYTitleVisibilityChanged : 1;
+ bool axisZTitleVisibilityChanged : 1;
+ bool axisXTitleFixedChanged : 1;
+ bool axisYTitleFixedChanged : 1;
+ bool axisZTitleFixedChanged : 1;
Abstract3DChangeBitField() :
- zoomLevelChanged(true),
themeChanged(true),
shadowQualityChanged(true),
selectionModeChanged(true),
- objFileChanged(true),
+ optimizationHintChanged(true),
axisXTypeChanged(true),
axisYTypeChanged(true),
axisZTypeChanged(true),
@@ -102,7 +116,24 @@ struct Abstract3DChangeBitField {
axisZSubSegmentCountChanged(true),
axisXLabelFormatChanged(true),
axisYLabelFormatChanged(true),
- axisZLabelFormatChanged(true)
+ axisZLabelFormatChanged(true),
+ axisXReversedChanged(true),
+ axisYReversedChanged(true),
+ axisZReversedChanged(true),
+ axisXFormatterChanged(true),
+ axisYFormatterChanged(true),
+ axisZFormatterChanged(true),
+ projectionChanged(true),
+ axisXLabelAutoRotationChanged(true),
+ axisYLabelAutoRotationChanged(true),
+ axisZLabelAutoRotationChanged(true),
+ aspectRatioChanged(true),
+ axisXTitleVisibilityChanged(true),
+ axisYTitleVisibilityChanged(true),
+ axisZTitleVisibilityChanged(true),
+ axisXTitleFixedChanged(true),
+ axisYTitleFixedChanged(true),
+ axisZTitleFixedChanged(true)
{
}
};
@@ -119,28 +150,19 @@ public:
SelectionColumn
};
- enum MouseState {
- MouseNone = 0,
- MouseOnScene,
- MouseOnOverview,
- MouseOnZoom,
- MouseRotating,
- MouseOnPinch
- };
-
private:
Abstract3DChangeBitField m_changeTracker;
- GLfloat m_horizontalRotation;
- GLfloat m_verticalRotation;
ThemeManager *m_themeManager;
QAbstract3DGraph::SelectionFlags m_selectionMode;
QAbstract3DGraph::ShadowQuality m_shadowQuality;
+ bool m_useOrthoProjection;
+ float m_aspectRatio;
+ QAbstract3DGraph::OptimizationHints m_optimizationHints;
protected:
Q3DScene *m_scene;
QList<QAbstract3DInputHandler *> m_inputHandlers; // List of all added input handlers
QAbstract3DInputHandler *m_activeInputHandler;
- CameraHelper *m_cameraHelper;
// Active axes
QAbstract3DAxis *m_axisX;
QAbstract3DAxis *m_axisY;
@@ -149,12 +171,22 @@ protected:
QList<QAbstract3DAxis *> m_axes; // List of all added axes
Abstract3DRenderer *m_renderer;
bool m_isDataDirty;
- bool m_isSeriesVisibilityDirty;
+ bool m_isCustomDataDirty;
+ bool m_isCustomItemDirty;
bool m_isSeriesVisualsDirty;
bool m_renderPending;
QList<QAbstract3DSeries *> m_seriesList;
+ bool m_measureFps;
+ QTime m_frameTimer;
+ int m_numFrames;
+ qreal m_currentFps;
+
+ QVector<QAbstract3DSeries *> m_changedSeriesList;
+
+ QList<QCustom3DItem *> m_customItems;
+
explicit Abstract3DController(QRect initialViewport, Q3DScene *scene, QObject *parent = 0);
public:
@@ -173,11 +205,11 @@ public:
QList<QAbstract3DSeries *> seriesList();
virtual void setAxisX(QAbstract3DAxis *axis);
- virtual QAbstract3DAxis *axisX();
+ virtual QAbstract3DAxis *axisX() const;
virtual void setAxisY(QAbstract3DAxis *axis);
- virtual QAbstract3DAxis *axisY();
+ virtual QAbstract3DAxis *axisY() const;
virtual void setAxisZ(QAbstract3DAxis *axis);
- virtual QAbstract3DAxis *axisZ();
+ virtual QAbstract3DAxis *axisZ() const;
virtual void addAxis(QAbstract3DAxis *axis);
virtual void releaseAxis(QAbstract3DAxis *axis);
virtual QList<QAbstract3DAxis *> axes() const; // Omits default axes
@@ -188,12 +220,9 @@ public:
virtual QAbstract3DInputHandler *activeInputHandler();
virtual QList<QAbstract3DInputHandler *> inputHandlers() const;
- virtual int zoomLevel();
- virtual void setZoomLevel(int zoomLevel);
-
virtual void addTheme(Q3DTheme *theme);
virtual void releaseTheme(Q3DTheme *theme);
- virtual void setActiveTheme(Q3DTheme *theme);
+ virtual void setActiveTheme(Q3DTheme *theme, bool force = true);
virtual Q3DTheme *activeTheme() const;
virtual QList<Q3DTheme *> themes() const;
@@ -201,9 +230,13 @@ public:
virtual QAbstract3DGraph::SelectionFlags selectionMode() const;
virtual void setShadowQuality(QAbstract3DGraph::ShadowQuality quality);
+ virtual void doSetShadowQuality(QAbstract3DGraph::ShadowQuality quality);
virtual QAbstract3DGraph::ShadowQuality shadowQuality() const;
virtual bool shadowsSupported() const;
+ void setOptimizationHints(QAbstract3DGraph::OptimizationHints hints);
+ QAbstract3DGraph::OptimizationHints optimizationHints() const;
+
bool isSlicingActive() const;
void setSlicingActive(bool isSlicing);
@@ -212,6 +245,22 @@ public:
void markDataDirty();
void markSeriesVisualsDirty();
+ void requestRender(QOpenGLFramebufferObject *fbo);
+
+ int addCustomItem(QCustom3DItem *item);
+ void deleteCustomItems();
+ void deleteCustomItem(QCustom3DItem *item);
+ void deleteCustomItem(const QVector3D &position);
+ void releaseCustomItem(QCustom3DItem *item);
+
+ int selectedLabelIndex() const;
+ QAbstract3DAxis *selectedAxis() const;
+ int selectedCustomItemIndex() const;
+ QCustom3DItem *selectedCustomItem() const;
+
+ void setOrthoProjection(bool enable);
+ bool isOrthoProjection() const;
+
void emitNeedRender();
virtual void clearSelection() = 0;
@@ -231,8 +280,16 @@ public:
virtual void handleAxisAutoAdjustRangeChangedInOrientation(
QAbstract3DAxis::AxisOrientation orientation, bool autoAdjust) = 0;
virtual void handleAxisLabelFormatChangedBySender(QObject *sender);
+ virtual void handleAxisReversedChangedBySender(QObject *sender);
+ virtual void handleAxisFormatterDirtyBySender(QObject *sender);
+ virtual void handleAxisLabelAutoRotationChangedBySender(QObject *sender);
+ virtual void handleAxisTitleVisibilityChangedBySender(QObject *sender);
+ virtual void handleAxisTitleFixedChangedBySender(QObject *sender);
virtual void handleSeriesVisibilityChangedBySender(QObject *sender);
virtual void handlePendingClick() = 0;
+ virtual void adjustAxisRanges() = 0;
+
+ void markSeriesItemLabelsDirty();
public slots:
void handleAxisTitleChanged(const QString &title);
@@ -242,6 +299,11 @@ public slots:
void handleAxisSubSegmentCountChanged(int count);
void handleAxisAutoAdjustRangeChanged(bool autoAdjust);
void handleAxisLabelFormatChanged(const QString &format);
+ void handleAxisReversedChanged(bool enable);
+ void handleAxisFormatterDirty();
+ void handleAxisLabelAutoRotationChanged(float angle);
+ void handleAxisTitleVisibilityChanged(bool visible);
+ void handleAxisTitleFixedChanged(bool fixed);
void handleInputViewChanged(QAbstract3DInputHandler::InputView view);
void handleInputPositionChanged(const QPoint &position);
void handleSeriesVisibilityChanged(bool visible);
@@ -258,6 +320,17 @@ public slots:
// Renderer callback handlers
void handleRequestShadowQuality(QAbstract3DGraph::ShadowQuality quality);
+ void setMeasureFps(bool enable);
+ inline bool measureFps() const { return m_measureFps; }
+ inline qreal currentFps() const { return m_currentFps; }
+
+ QAbstract3DGraph::ElementType selectedElement() const;
+
+ void updateCustomItem();
+
+ void setAspectRatio(float ratio);
+ float aspectRatio();
+
signals:
void shadowQualityChanged(QAbstract3DGraph::ShadowQuality quality);
void activeInputHandlerChanged(QAbstract3DInputHandler *inputHandler);
@@ -267,6 +340,12 @@ signals:
void axisXChanged(QAbstract3DAxis *axis);
void axisYChanged(QAbstract3DAxis *axis);
void axisZChanged(QAbstract3DAxis *axis);
+ void elementSelected(QAbstract3DGraph::ElementType type);
+ void measureFpsChanged(bool enabled);
+ void currentFpsChanged(qreal fps);
+ void orthoProjectionChanged(bool enabled);
+ void aspectRatioChanged(float ratio);
+ void optimizationHintsChanged(QAbstract3DGraph::OptimizationHints hints);
protected:
virtual QAbstract3DAxis *createDefaultAxis(QAbstract3DAxis::AxisOrientation orientation);
@@ -278,7 +357,9 @@ private:
void setAxisHelper(QAbstract3DAxis::AxisOrientation orientation, QAbstract3DAxis *axis,
QAbstract3DAxis **axisPtr);
+ friend class AbstractDeclarative;
friend class Bars3DController;
+ friend class QAbstract3DGraphPrivate;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp
index 3122cf76..5d97a6ca 100644
--- a/src/datavisualization/engine/abstract3drenderer.cpp
+++ b/src/datavisualization/engine/abstract3drenderer.cpp
@@ -17,15 +17,13 @@
****************************************************************************/
#include "abstract3drenderer_p.h"
-#include "qvalue3daxis.h"
#include "texturehelper_p.h"
-#include "utils_p.h"
-#include "q3dscene_p.h"
#include "q3dcamera_p.h"
-#include "q3dlight_p.h"
-#include "qabstract3dseries_p.h"
#include "q3dtheme_p.h"
-#include "objecthelper_p.h"
+#include "qvalue3daxisformatter_p.h"
+#include "shaderhelper_p.h"
+#include "qcustom3ditem_p.h"
+#include "qcustom3dlabel_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -37,6 +35,7 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller)
m_cachedShadowQuality(QAbstract3DGraph::ShadowQualityMedium),
m_autoScaleAdjustment(1.0f),
m_cachedSelectionMode(QAbstract3DGraph::SelectionNone),
+ m_cachedOptimizationHint(QAbstract3DGraph::OptimizationDefault),
m_textureHelper(0),
m_cachedScene(new Q3DScene()),
m_selectionDirty(true),
@@ -45,12 +44,18 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller)
m_selectionLabelDirty(true),
m_clickPending(false),
m_clickedSeries(0),
- m_selectionLabelItem(0)
-#ifdef DISPLAY_RENDER_SPEED
- , m_isFirstFrame(true),
- m_numFrames(0)
-#endif
-
+ m_clickedType(QAbstract3DGraph::ElementNone),
+ m_selectionLabelItem(0),
+ m_visibleSeriesCount(0),
+ m_customItemShader(0),
+ m_useOrthoProjection(false),
+ m_xFlipped(false),
+ m_yFlipped(false),
+ m_zFlipped(false),
+ m_backgroundObj(0),
+ m_gridLineObj(0),
+ m_labelObj(0),
+ m_graphAspectRatio(2.0f)
{
QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Abstract3DRenderer::updateTextures);
QObject::connect(this, &Abstract3DRenderer::needRender, controller,
@@ -61,14 +66,30 @@ Abstract3DRenderer::Abstract3DRenderer(Abstract3DController *controller)
Abstract3DRenderer::~Abstract3DRenderer()
{
- for (int i = 0; i < m_visibleSeriesList.size(); i++)
- m_visibleSeriesList[i].cleanup(m_textureHelper);
-
delete m_drawer;
- delete m_textureHelper;
delete m_cachedScene;
delete m_cachedTheme;
delete m_selectionLabelItem;
+ delete m_customItemShader;
+
+ foreach (SeriesRenderCache *cache, m_renderCacheList) {
+ cache->cleanup(m_textureHelper);
+ delete cache;
+ }
+ m_renderCacheList.clear();
+
+ foreach (CustomRenderItem *item, m_customRenderCache) {
+ GLuint texture = item->texture();
+ m_textureHelper->deleteTexture(&texture);
+ delete item;
+ }
+ m_customRenderCache.clear();
+
+ ObjectHelper::releaseObjectHelper(this, m_backgroundObj);
+ ObjectHelper::releaseObjectHelper(this, m_gridLineObj);
+ ObjectHelper::releaseObjectHelper(this, m_labelObj);
+
+ delete m_textureHelper;
}
void Abstract3DRenderer::initializeOpenGL()
@@ -95,23 +116,6 @@ void Abstract3DRenderer::initializeOpenGL()
void Abstract3DRenderer::render(const GLuint defaultFboHandle)
{
-#ifdef DISPLAY_RENDER_SPEED
- // For speed computation
- if (m_isFirstFrame) {
- m_lastFrameTime.start();
- m_isFirstFrame = false;
- }
-
- // Measure speed (as milliseconds per frame)
- m_numFrames++;
- if (m_lastFrameTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago
- qDebug() << float(m_lastFrameTime.elapsed()) / float(m_numFrames) << "ms/frame (="
- << float(m_numFrames) << "fps)";
- m_numFrames = 0;
- m_lastFrameTime.restart();
- }
-#endif
-
if (defaultFboHandle) {
glDepthMask(true);
glEnable(GL_DEPTH_TEST);
@@ -131,20 +135,12 @@ void Abstract3DRenderer::render(const GLuint defaultFboHandle)
m_viewport.width(),
m_viewport.height());
glEnable(GL_SCISSOR_TEST);
- QVector3D clearColor = Utils::vectorFromColor(m_cachedTheme->windowColor());
+ QVector4D clearColor = Utils::vectorFromColor(m_cachedTheme->windowColor());
glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
}
-QString Abstract3DRenderer::generateValueLabel(const QString &format, float value)
-{
- QString valueLabelFormat = format;
- Utils::ParamType valueParamType = Utils::findFormatParamType(valueLabelFormat);
- QByteArray valueFormatArray = valueLabelFormat.toUtf8();
- return Utils::formatLabel(valueFormatArray, valueParamType, value);
-}
-
void Abstract3DRenderer::updateSelectionState(SelectionState state)
{
m_selectionState = state;
@@ -163,6 +159,15 @@ void Abstract3DRenderer::initGradientShaders(const QString &vertexShader,
Q_UNUSED(fragmentShader)
}
+void Abstract3DRenderer::initCustomItemShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ if (m_customItemShader)
+ delete m_customItemShader;
+ m_customItemShader = new ShaderHelper(this, vertexShader, fragmentShader);
+ m_customItemShader->initialize();
+}
+
void Abstract3DRenderer::updateTheme(Q3DTheme *theme)
{
// Synchronize the controller theme with renderer
@@ -229,6 +234,8 @@ void Abstract3DRenderer::reInitShaders()
QStringLiteral(":/shaders/fragmentShadowNoTex"));
initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"),
QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ initCustomItemShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadow"));
} else {
initGradientShaders(QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragmentColorOnY"));
@@ -236,6 +243,8 @@ void Abstract3DRenderer::reInitShaders()
QStringLiteral(":/shaders/fragment"));
initBackgroundShaders(QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragment"));
+ initCustomItemShaders(QStringLiteral(":/shaders/vertexTexture"),
+ QStringLiteral(":/shaders/fragmentTexture"));
}
#else
initGradientShaders(QStringLiteral(":/shaders/vertex"),
@@ -244,6 +253,8 @@ void Abstract3DRenderer::reInitShaders()
QStringLiteral(":/shaders/fragmentES2"));
initBackgroundShaders(QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragmentES2"));
+ initCustomItemShaders(QStringLiteral(":/shaders/vertexTexture"),
+ QStringLiteral(":/shaders/fragmentTextureES2"));
#endif
}
@@ -266,18 +277,28 @@ void Abstract3DRenderer::updateSelectionMode(QAbstract3DGraph::SelectionFlags mo
m_selectionDirty = true;
}
+void Abstract3DRenderer::updateAspectRatio(float ratio)
+{
+ m_graphAspectRatio = ratio;
+ calculateZoomLevel();
+ m_cachedScene->activeCamera()->d_ptr->updateViewMatrix(m_autoScaleAdjustment);
+ foreach (SeriesRenderCache *cache, m_renderCacheList)
+ cache->setDataDirty(true);
+ updateCustomItemPositions();
+}
+
+void Abstract3DRenderer::updateOptimizationHint(QAbstract3DGraph::OptimizationHints hint)
+{
+ m_cachedOptimizationHint = hint;
+}
+
void Abstract3DRenderer::handleResize()
{
if (m_primarySubViewport.width() == 0 || m_primarySubViewport.height() == 0)
return;
- // Calculate zoom level based on aspect ratio
- GLfloat div;
- GLfloat zoomAdjustment;
- div = qMin(m_primarySubViewport.width(), m_primarySubViewport.height());
- zoomAdjustment = defaultRatio * ((m_primarySubViewport.width() / div)
- / (m_primarySubViewport.height() / div));
- m_autoScaleAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f
+ // Recalculate zoom
+ calculateZoomLevel();
// Re-init selection buffer
initSelectionBuffer();
@@ -288,6 +309,18 @@ void Abstract3DRenderer::handleResize()
#endif
}
+void Abstract3DRenderer::calculateZoomLevel()
+{
+ // Calculate zoom level based on aspect ratio
+ GLfloat div;
+ GLfloat zoomAdjustment;
+ div = qMin(m_primarySubViewport.width(), m_primarySubViewport.height());
+ zoomAdjustment = 2.0f * defaultRatio
+ * ((m_primarySubViewport.width() / div)
+ / (m_primarySubViewport.height() / div)) / m_graphAspectRatio;
+ m_autoScaleAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f
+}
+
void Abstract3DRenderer::updateAxisType(QAbstract3DAxis::AxisOrientation orientation,
QAbstract3DAxis::AxisType type)
{
@@ -312,18 +345,25 @@ void Abstract3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orient
AxisRenderCache &cache = axisCacheForOrientation(orientation);
cache.setMin(min);
cache.setMax(max);
+
+ foreach (SeriesRenderCache *cache, m_renderCacheList)
+ cache->setDataDirty(true);
+
+ updateCustomItemPositions();
}
void Abstract3DRenderer::updateAxisSegmentCount(QAbstract3DAxis::AxisOrientation orientation,
int count)
{
- axisCacheForOrientation(orientation).setSegmentCount(count);
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ cache.setSegmentCount(count);
}
void Abstract3DRenderer::updateAxisSubSegmentCount(QAbstract3DAxis::AxisOrientation orientation,
int count)
{
- axisCacheForOrientation(orientation).setSubSegmentCount(count);
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ cache.setSubSegmentCount(count);
}
void Abstract3DRenderer::updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation orientation,
@@ -332,6 +372,67 @@ void Abstract3DRenderer::updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation
axisCacheForOrientation(orientation).setLabelFormat(format);
}
+void Abstract3DRenderer::updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation,
+ bool enable)
+{
+ axisCacheForOrientation(orientation).setReversed(enable);
+ foreach (SeriesRenderCache *cache, m_renderCacheList)
+ cache->setDataDirty(true);
+
+ updateCustomItemPositions();
+}
+
+void Abstract3DRenderer::updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation,
+ QValue3DAxisFormatter *formatter)
+{
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ if (cache.ctrlFormatter() != formatter) {
+ delete cache.formatter();
+ cache.setFormatter(formatter->createNewInstance());
+ cache.setCtrlFormatter(formatter);
+ }
+ formatter->d_ptr->populateCopy(*(cache.formatter()));
+ cache.markPositionsDirty();
+
+ foreach (SeriesRenderCache *cache, m_renderCacheList)
+ cache->setDataDirty(true);
+
+ updateCustomItemPositions();
+}
+
+void Abstract3DRenderer::updateAxisLabelAutoRotation(QAbstract3DAxis::AxisOrientation orientation,
+ float angle)
+{
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ if (cache.labelAutoRotation() != angle)
+ cache.setLabelAutoRotation(angle);
+}
+
+void Abstract3DRenderer::updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientation orientation,
+ bool visible)
+{
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ if (cache.isTitleVisible() != visible)
+ cache.setTitleVisible(visible);
+}
+
+void Abstract3DRenderer::updateAxisTitleFixed(QAbstract3DAxis::AxisOrientation orientation,
+ bool fixed)
+{
+ AxisRenderCache &cache = axisCacheForOrientation(orientation);
+ if (cache.isTitleFixed() != fixed)
+ cache.setTitleFixed(fixed);
+}
+
+void Abstract3DRenderer::modifiedSeriesList(const QVector<QAbstract3DSeries *> &seriesList)
+{
+ foreach (QAbstract3DSeries *series, seriesList) {
+ SeriesRenderCache *cache = m_renderCacheList.value(series, 0);
+ if (cache)
+ cache->setDataDirty(true);
+ }
+}
+
void Abstract3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh mesh)
{
// Default implementation does nothing.
@@ -339,41 +440,84 @@ void Abstract3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::M
Q_UNUSED(mesh)
}
-void Abstract3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList,
- bool updateVisibility)
+void Abstract3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList)
{
- int visibleCount = 0;
- if (updateVisibility) {
- int oldSize = m_visibleSeriesList.size();
- foreach (QAbstract3DSeries *current, seriesList) {
- if (current->isVisible())
- visibleCount++;
- }
+ foreach (SeriesRenderCache *cache, m_renderCacheList)
+ cache->setValid(false);
- // Clean up series caches that are about to be permanently deleted.
- // Can't just use cache destructor, as resize will call that to all items.
- if (visibleCount < oldSize) {
- for (int i = visibleCount; i < oldSize; i++)
- m_visibleSeriesList[i].cleanup(m_textureHelper);
+ m_visibleSeriesCount = 0;
+ int seriesCount = seriesList.size();
+ for (int i = 0; i < seriesCount; i++) {
+ QAbstract3DSeries *series = seriesList.at(i);
+ SeriesRenderCache *cache = m_renderCacheList.value(series);
+ bool newSeries = false;
+ if (!cache) {
+ cache = createNewCache(series);
+ m_renderCacheList[series] = cache;
+ newSeries = true;
}
+ cache->setValid(true);
+ cache->populate(newSeries);
+ if (cache->isVisible())
+ m_visibleSeriesCount++;
+ }
+
+ // Remove non-valid objects from the cache list
+ foreach (SeriesRenderCache *cache, m_renderCacheList) {
+ if (!cache->isValid())
+ cleanCache(cache);
+ }
+}
+
+void Abstract3DRenderer::updateCustomData(const QList<QCustom3DItem *> &customItems)
+{
+ if (customItems.isEmpty() && m_customRenderCache.isEmpty())
+ return;
- if (visibleCount != oldSize)
- m_visibleSeriesList.resize(visibleCount);
+ foreach (CustomRenderItem *item, m_customRenderCache)
+ item->setValid(false);
- visibleCount = 0;
+ int itemCount = customItems.size();
+ // Check custom item list for items that are not yet in render item cache
+ for (int i = 0; i < itemCount; i++) {
+ QCustom3DItem *item = customItems.at(i);
+ CustomRenderItem *renderItem = m_customRenderCache.value(item);
+ if (!renderItem)
+ renderItem = addCustomItem(item);
+ renderItem->setValid(true);
+ renderItem->setIndex(i); // always update index, as it must match the custom item index
}
- foreach (QAbstract3DSeries *current, seriesList) {
- if (current->isVisible()) {
- // Item selection label may need update
- if (current->d_ptr->m_changeTracker.nameChanged
- || current->d_ptr->m_changeTracker.itemLabelFormatChanged) {
- m_selectionLabelDirty = true;
- }
- m_visibleSeriesList[visibleCount++].populate(current, this);
+
+ // Check render item cache and remove items that are not in customItems list anymore
+ foreach (CustomRenderItem *renderItem, m_customRenderCache) {
+ if (!renderItem->isValid()) {
+ m_customRenderCache.remove(renderItem->itemPointer());
+ GLuint texture = renderItem->texture();
+ m_textureHelper->deleteTexture(&texture);
+ delete renderItem;
}
}
}
+void Abstract3DRenderer::updateCustomItems()
+{
+ // Check all items
+ foreach (CustomRenderItem *item, m_customRenderCache)
+ updateCustomItem(item);
+}
+
+SeriesRenderCache *Abstract3DRenderer::createNewCache(QAbstract3DSeries *series)
+{
+ return new SeriesRenderCache(series, this);
+}
+
+void Abstract3DRenderer::cleanCache(SeriesRenderCache *cache)
+{
+ m_renderCacheList.remove(cache->series());
+ cache->cleanup(m_textureHelper);
+ delete cache;
+}
+
AxisRenderCache &Abstract3DRenderer::axisCacheForOrientation(
QAbstract3DAxis::AxisOrientation orientation)
{
@@ -428,26 +572,243 @@ void Abstract3DRenderer::lowerShadowQuality()
updateShadowQuality(newQuality);
}
-void Abstract3DRenderer::generateBaseColorTexture(const QColor &color, GLuint *texture)
+void Abstract3DRenderer::drawAxisTitleY(const QVector3D &sideLabelRotation,
+ const QVector3D &backLabelRotation,
+ const QVector3D &sideLabelTrans,
+ const QVector3D &backLabelTrans,
+ const QQuaternion &totalSideRotation,
+ const QQuaternion &totalBackRotation,
+ AbstractRenderItem &dummyItem,
+ const Q3DCamera *activeCamera,
+ float labelsMaxWidth,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionMatrix,
+ ShaderHelper *shader)
{
- if (*texture) {
- m_textureHelper->deleteTexture(texture);
- *texture = 0;
+ float scaleFactor = m_drawer->scaledFontSize() / m_axisCacheY.titleItem().size().height();
+ float titleOffset = 2.0f * (labelMargin + (labelsMaxWidth * scaleFactor));
+ float yRotation;
+ QVector3D titleTrans;
+ QQuaternion totalRotation;
+ if (m_xFlipped == m_zFlipped) {
+ yRotation = backLabelRotation.y();
+ titleTrans = backLabelTrans;
+ totalRotation = totalBackRotation;
+ } else {
+ yRotation = sideLabelRotation.y();
+ titleTrans = sideLabelTrans;
+ totalRotation = totalSideRotation;
+ }
+
+ QQuaternion offsetRotator = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation);
+ QVector3D titleOffsetVector =
+ offsetRotator.rotatedVector(QVector3D(-titleOffset, 0.0f, 0.0f));
+
+ QQuaternion titleRotation;
+ if (m_axisCacheY.isTitleFixed()) {
+ titleRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation)
+ * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, 90.0f);
+ } else {
+ titleRotation = totalRotation
+ * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, 90.0f);
}
+ dummyItem.setTranslation(titleTrans + titleOffsetVector);
+
+ m_drawer->drawLabel(dummyItem, m_axisCacheY.titleItem(), viewMatrix,
+ projectionMatrix, zeroVector, titleRotation, 0,
+ m_cachedSelectionMode, shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, Qt::AlignBottom);
+}
+void Abstract3DRenderer::drawAxisTitleX(const QVector3D &labelRotation,
+ const QVector3D &labelTrans,
+ const QQuaternion &totalRotation,
+ AbstractRenderItem &dummyItem,
+ const Q3DCamera *activeCamera,
+ float labelsMaxWidth,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionMatrix,
+ ShaderHelper *shader)
+{
+ float scaleFactor = m_drawer->scaledFontSize() / m_axisCacheX.titleItem().size().height();
+ float titleOffset = 2.0f * (labelMargin + (labelsMaxWidth * scaleFactor));
+ float zRotation = 0.0f;
+ float yRotation = 0.0f;
+ float xRotation = -90.0f + labelRotation.z();
+ float offsetRotation = labelRotation.z();
+ float extraRotation = -90.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignTop;
+ if (m_yFlipped) {
+ alignment = Qt::AlignBottom;
+ if (m_zFlipped) {
+ zRotation = 180.0f;
+ titleOffset = -titleOffset;
+ if (m_xFlipped) {
+ offsetRotation = -offsetRotation;
+ extraRotation = -extraRotation;
+ } else {
+ xRotation = -90.0f - labelRotation.z();
+ }
+ } else {
+ zRotation = 180.0f;
+ yRotation = 180.0f;
+ if (m_xFlipped) {
+ offsetRotation = -offsetRotation;
+ xRotation = -90.0f - labelRotation.z();
+ } else {
+ extraRotation = -extraRotation;
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ titleOffset = -titleOffset;
+ if (m_xFlipped) {
+ yRotation = 180.0f;
+ offsetRotation = -offsetRotation;
+ } else {
+ yRotation = 180.0f;
+ xRotation = -90.0f - labelRotation.z();
+ extraRotation = -extraRotation;
+ }
+ } else {
+ if (m_xFlipped) {
+ offsetRotation = -offsetRotation;
+ xRotation = -90.0f - labelRotation.z();
+ extraRotation = -extraRotation;
+ }
+ }
+ }
+
+ if (offsetRotation == 180.0f || offsetRotation == -180.0f)
+ offsetRotation = 0.0f;
+ QQuaternion offsetRotator = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, offsetRotation);
+ QVector3D titleOffsetVector =
+ offsetRotator.rotatedVector(QVector3D(0.0f, 0.0f, titleOffset));
+
+ QQuaternion titleRotation;
+ if (m_axisCacheX.isTitleFixed()) {
+ titleRotation = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, zRotation)
+ * QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation)
+ * QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, xRotation);
+ } else {
+ titleRotation = totalRotation
+ * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, extraRotation);
+ }
+ dummyItem.setTranslation(labelTrans + titleOffsetVector);
+
+ m_drawer->drawLabel(dummyItem, m_axisCacheX.titleItem(), viewMatrix,
+ projectionMatrix, zeroVector, titleRotation, 0,
+ m_cachedSelectionMode, shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, alignment);
+}
+
+void Abstract3DRenderer::drawAxisTitleZ(const QVector3D &labelRotation,
+ const QVector3D &labelTrans,
+ const QQuaternion &totalRotation,
+ AbstractRenderItem &dummyItem,
+ const Q3DCamera *activeCamera,
+ float labelsMaxWidth,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionMatrix,
+ ShaderHelper *shader)
+{
+ float scaleFactor = m_drawer->scaledFontSize() / m_axisCacheZ.titleItem().size().height();
+ float titleOffset = 2.0f * (labelMargin + (labelsMaxWidth * scaleFactor));
+ float zRotation = labelRotation.z();
+ float yRotation = -90.0f;
+ float xRotation = -90.0f;
+ float extraRotation = 90.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignTop;
+ if (m_yFlipped) {
+ alignment = Qt::AlignBottom;
+ xRotation = -xRotation;
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ titleOffset = -titleOffset;
+ zRotation = -zRotation;
+ extraRotation = -extraRotation;
+ } else {
+ zRotation = -zRotation;
+ yRotation = -yRotation;
+ }
+ } else {
+ if (m_xFlipped) {
+ titleOffset = -titleOffset;
+ } else {
+ extraRotation = -extraRotation;
+ yRotation = -yRotation;
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ zRotation = -zRotation;
+ if (m_xFlipped) {
+ titleOffset = -titleOffset;
+ } else {
+ extraRotation = -extraRotation;
+ yRotation = -yRotation;
+ }
+ } else {
+ if (m_xFlipped) {
+ titleOffset = -titleOffset;
+ extraRotation = -extraRotation;
+ } else {
+ yRotation = -yRotation;
+ }
+ }
+ }
+
+ float offsetRotation = zRotation;
+ if (offsetRotation == 180.0f || offsetRotation == -180.0f)
+ offsetRotation = 0.0f;
+ QQuaternion offsetRotator = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, offsetRotation);
+ QVector3D titleOffsetVector =
+ offsetRotator.rotatedVector(QVector3D(titleOffset, 0.0f, 0.0f));
+
+ QQuaternion titleRotation;
+ if (m_axisCacheZ.isTitleFixed()) {
+ titleRotation = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, zRotation)
+ * QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, yRotation)
+ * QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, xRotation);
+ } else {
+ titleRotation = totalRotation
+ * QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, extraRotation);
+ }
+ dummyItem.setTranslation(labelTrans + titleOffsetVector);
+
+ m_drawer->drawLabel(dummyItem, m_axisCacheZ.titleItem(), viewMatrix,
+ projectionMatrix, zeroVector, titleRotation, 0,
+ m_cachedSelectionMode, shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, alignment);
+}
+
+void Abstract3DRenderer::loadGridLineMesh()
+{
+ ObjectHelper::resetObjectHelper(this, m_gridLineObj,
+ QStringLiteral(":/defaultMeshes/plane"));
+}
+
+void Abstract3DRenderer::loadLabelMesh()
+{
+ ObjectHelper::resetObjectHelper(this, m_labelObj,
+ QStringLiteral(":/defaultMeshes/plane"));
+}
+
+
+void Abstract3DRenderer::generateBaseColorTexture(const QColor &color, GLuint *texture)
+{
+ m_textureHelper->deleteTexture(texture);
*texture = m_textureHelper->createUniformTexture(color);
}
-void Abstract3DRenderer::fixGradientAndGenerateTexture(QLinearGradient *gradient, GLuint *gradientTexture)
+void Abstract3DRenderer::fixGradientAndGenerateTexture(QLinearGradient *gradient,
+ GLuint *gradientTexture)
{
// Readjust start/stop to match gradient texture size
gradient->setStart(qreal(gradientTextureWidth), qreal(gradientTextureHeight));
gradient->setFinalStop(0.0, 0.0);
- if (*gradientTexture) {
- m_textureHelper->deleteTexture(gradientTexture);
- *gradientTexture = 0;
- }
+ m_textureHelper->deleteTexture(gradientTexture);
*gradientTexture = m_textureHelper->createGradientTexture(*gradient);
}
@@ -471,4 +832,270 @@ QString &Abstract3DRenderer::selectionLabel()
return m_selectionLabel;
}
+QVector4D Abstract3DRenderer::indexToSelectionColor(GLint index)
+{
+ GLubyte idxRed = index & 0xff;
+ GLubyte idxGreen = (index & 0xff00) >> 8;
+ GLubyte idxBlue = (index & 0xff0000) >> 16;
+
+ return QVector4D(idxRed, idxGreen, idxBlue, 0);
+}
+
+CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item)
+{
+ CustomRenderItem *newItem = new CustomRenderItem();
+ newItem->setRenderer(this);
+ newItem->setItemPointer(item); // Store pointer for render item updates
+ newItem->setMesh(item->meshFile());
+ QVector3D scaling = item->scaling();
+ QImage textureImage = item->d_ptr->textureImage();
+ bool facingCamera = false;
+ if (item->d_ptr->m_isLabelItem) {
+ QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item);
+ float pointSize = labelItem->font().pointSizeF();
+ // Check do we have custom visuals or need to use theme
+ if (!labelItem->dptr()->m_customVisuals) {
+ // Recreate texture using theme
+ labelItem->dptr()->createTextureImage(m_cachedTheme->labelBackgroundColor(),
+ m_cachedTheme->labelTextColor(),
+ m_cachedTheme->isLabelBackgroundEnabled(),
+ m_cachedTheme->isLabelBorderEnabled());
+ pointSize = m_cachedTheme->font().pointSizeF();
+ textureImage = item->d_ptr->textureImage();
+ }
+ // Calculate scaling based on text (texture size), font size and asked scaling
+ float scaledFontSize = (0.05f + pointSize / 500.0f) / float(textureImage.height());
+ scaling.setX(scaling.x() * textureImage.width() * scaledFontSize);
+ scaling.setY(scaling.y() * textureImage.height() * scaledFontSize);
+ // Check if facing camera
+ facingCamera = labelItem->isFacingCamera();
+ }
+ newItem->setScaling(scaling);
+ newItem->setRotation(item->rotation());
+ newItem->setPosition(item->position());
+ newItem->setPositionAbsolute(item->isPositionAbsolute());
+ newItem->setBlendNeeded(textureImage.hasAlphaChannel());
+ GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true);
+ newItem->setTexture(texture);
+ item->d_ptr->clearTextureImage();
+ QVector3D translation = convertPositionToTranslation(item->position(),
+ item->isPositionAbsolute());
+ newItem->setTranslation(translation);
+ newItem->setVisible(item->isVisible());
+ newItem->setShadowCasting(item->isShadowCasting());
+ newItem->setFacingCamera(facingCamera);
+ m_customRenderCache.insert(item, newItem);
+ return newItem;
+}
+
+void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem)
+{
+ QCustom3DItem *item = renderItem->itemPointer();
+ if (item->d_ptr->m_dirtyBits.meshDirty) {
+ renderItem->setMesh(item->meshFile());
+ item->d_ptr->m_dirtyBits.meshDirty = false;
+ }
+ if (item->d_ptr->m_dirtyBits.scalingDirty) {
+ QVector3D scaling = item->scaling();
+ // In case we have label item, we need to recreate texture for scaling adjustment
+ if (item->d_ptr->m_isLabelItem) {
+ QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item);
+ float pointSize = labelItem->font().pointSizeF();
+ // Check do we have custom visuals or need to use theme
+ if (labelItem->dptr()->m_customVisuals) {
+ // Recreate texture
+ labelItem->dptr()->createTextureImage();
+ } else {
+ // Recreate texture using theme
+ labelItem->dptr()->createTextureImage(m_cachedTheme->labelBackgroundColor(),
+ m_cachedTheme->labelTextColor(),
+ m_cachedTheme->isLabelBackgroundEnabled(),
+ m_cachedTheme->isLabelBorderEnabled());
+ pointSize = m_cachedTheme->font().pointSizeF();
+ }
+ QImage textureImage = item->d_ptr->textureImage();
+ // Calculate scaling based on text (texture size), font size and asked scaling
+ float scaledFontSize = (0.05f + pointSize / 500.0f) / float(textureImage.height());
+ scaling.setX(scaling.x() * textureImage.width() * scaledFontSize);
+ scaling.setY(scaling.y() * textureImage.height() * scaledFontSize);
+ item->d_ptr->clearTextureImage();
+ }
+ renderItem->setScaling(scaling);
+ item->d_ptr->m_dirtyBits.scalingDirty = false;
+ }
+ if (item->d_ptr->m_dirtyBits.rotationDirty) {
+ renderItem->setRotation(item->rotation());
+ item->d_ptr->m_dirtyBits.rotationDirty = false;
+ }
+ if (item->d_ptr->m_dirtyBits.textureDirty) {
+ QImage textureImage = item->d_ptr->textureImage();
+ if (item->d_ptr->m_isLabelItem) {
+ QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item);
+ // Check do we have custom visuals or need to use theme
+ if (!labelItem->dptr()->m_customVisuals) {
+ // Recreate texture using theme
+ labelItem->dptr()->createTextureImage(m_cachedTheme->labelBackgroundColor(),
+ m_cachedTheme->labelTextColor(),
+ m_cachedTheme->isLabelBackgroundEnabled(),
+ m_cachedTheme->isLabelBorderEnabled());
+ textureImage = item->d_ptr->textureImage();
+ }
+ }
+ renderItem->setBlendNeeded(textureImage.hasAlphaChannel());
+ GLuint oldTexture = renderItem->texture();
+ m_textureHelper->deleteTexture(&oldTexture);
+ GLuint texture = m_textureHelper->create2DTexture(textureImage, true, true, true);
+ renderItem->setTexture(texture);
+ item->d_ptr->clearTextureImage();
+ item->d_ptr->m_dirtyBits.textureDirty = false;
+ }
+ if (item->d_ptr->m_dirtyBits.positionDirty || item->d_ptr->m_dirtyBits.positionAbsoluteDirty) {
+ renderItem->setPosition(item->position());
+ renderItem->setPositionAbsolute(item->isPositionAbsolute());
+ QVector3D translation = convertPositionToTranslation(item->position(),
+ item->isPositionAbsolute());
+ renderItem->setTranslation(translation);
+ item->d_ptr->m_dirtyBits.positionDirty = false;
+ item->d_ptr->m_dirtyBits.positionAbsoluteDirty = false;
+ }
+ if (item->d_ptr->m_dirtyBits.visibleDirty) {
+ renderItem->setVisible(item->isVisible());
+ item->d_ptr->m_dirtyBits.visibleDirty = false;
+ }
+ if (item->d_ptr->m_dirtyBits.shadowCastingDirty) {
+ renderItem->setShadowCasting(item->isShadowCasting());
+ item->d_ptr->m_dirtyBits.shadowCastingDirty = false;
+ }
+ if (item->d_ptr->m_isLabelItem) {
+ QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item);
+ if (labelItem->dptr()->m_facingCameraDirty) {
+ renderItem->setFacingCamera(labelItem->isFacingCamera());
+ labelItem->dptr()->m_facingCameraDirty = false;
+ }
+ }
+}
+
+void Abstract3DRenderer::updateCustomItemPositions()
+{
+ foreach (CustomRenderItem *renderItem, m_customRenderCache) {
+ QVector3D translation = convertPositionToTranslation(renderItem->position(),
+ renderItem->isPositionAbsolute());
+ renderItem->setTranslation(translation);
+ }
+}
+
+void Abstract3DRenderer::drawCustomItems(RenderingState state,
+ ShaderHelper *shader,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionViewMatrix,
+ const QMatrix4x4 &depthProjectionViewMatrix,
+ GLuint depthTexture,
+ GLfloat shadowQuality)
+{
+ if (m_customRenderCache.isEmpty())
+ return;
+
+ if (RenderingNormal == state) {
+ shader->bind();
+ shader->setUniformValue(shader->lightP(), m_cachedScene->activeLight()->position());
+ shader->setUniformValue(shader->ambientS(), m_cachedTheme->ambientLightStrength());
+ shader->setUniformValue(shader->lightColor(),
+ Utils::vectorFromColor(m_cachedTheme->lightColor()));
+ shader->setUniformValue(shader->view(), viewMatrix);
+
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ // Draw custom items
+ foreach (CustomRenderItem *item, m_customRenderCache) {
+ // Check that the render item is visible, and skip drawing if not
+ if (!item->isVisible())
+ continue;
+
+ // Check if the render item is in data coordinates and not within axis ranges, and skip drawing if it is
+ if (!item->isPositionAbsolute()
+ && (item->position().x() < m_axisCacheX.min()
+ || item->position().x() > m_axisCacheX.max()
+ || item->position().z() < m_axisCacheZ.min()
+ || item->position().z() > m_axisCacheZ.max()
+ || item->position().y() < m_axisCacheY.min()
+ || item->position().y() > m_axisCacheY.max())) {
+ continue;
+ }
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 itModelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ QQuaternion rotation = item->rotation();
+ // Check if the (label) item should be facing camera, and adjust rotation accordingly
+ if (item->isFacingCamera()) {
+ float camRotationX = m_cachedScene->activeCamera()->xRotation();
+ float camRotationY = m_cachedScene->activeCamera()->yRotation();
+ rotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, -camRotationX)
+ * QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -camRotationY);
+ }
+
+ modelMatrix.translate(item->translation());
+ modelMatrix.rotate(rotation);
+ modelMatrix.scale(item->scaling());
+ itModelMatrix.rotate(rotation);
+ if (!item->isFacingCamera())
+ itModelMatrix.scale(item->scaling());
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ if (RenderingNormal == state) {
+ // Normal render
+ shader->setUniformValue(shader->model(), modelMatrix);
+ shader->setUniformValue(shader->MVP(), MVPMatrix);
+ shader->setUniformValue(shader->nModel(), itModelMatrix.inverted().transposed());
+
+ if (item->isBlendNeeded()) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ } else {
+ glDisable(GL_BLEND);
+ glEnable(GL_CULL_FACE);
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ // Set shadow shader bindings
+ shader->setUniformValue(shader->shadowQ(), shadowQuality);
+ shader->setUniformValue(shader->depth(), depthProjectionViewMatrix * modelMatrix);
+ shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength() / 10.0f);
+ m_drawer->drawObject(shader, item->mesh(), item->texture(), depthTexture);
+ } else
+#else
+ Q_UNUSED(depthTexture)
+ Q_UNUSED(shadowQuality)
+#endif
+ {
+ // Set shadowless shader bindings
+ shader->setUniformValue(shader->lightS(), m_cachedTheme->lightStrength());
+ m_drawer->drawObject(shader, item->mesh(), item->texture());
+ }
+ } else if (RenderingSelection == state) {
+ // Selection render
+ shader->setUniformValue(shader->MVP(), MVPMatrix);
+ QVector4D itemColor = indexToSelectionColor(item->index());
+ itemColor.setW(customItemAlpha);
+ itemColor /= 255.0f;
+ shader->setUniformValue(shader->color(), itemColor);
+ m_drawer->drawObject(shader, item->mesh());
+ } else if (item->isShadowCasting()) {
+ // Depth render
+ shader->setUniformValue(shader->MVP(), depthProjectionViewMatrix * modelMatrix);
+ m_drawer->drawObject(shader, item->mesh());
+ }
+ }
+
+ if (RenderingNormal == state) {
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glEnable(GL_CULL_FACE);
+ }
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h
index 4eb8426f..0dfc7367 100644
--- a/src/datavisualization/engine/abstract3drenderer_p.h
+++ b/src/datavisualization/engine/abstract3drenderer_p.h
@@ -29,18 +29,13 @@
#ifndef ABSTRACT3DRENDERER_P_H
#define ABSTRACT3DRENDERER_P_H
-//#define DISPLAY_RENDER_SPEED
-
#include <QtGui/QOpenGLFunctions>
-#ifdef DISPLAY_RENDER_SPEED
-#include <QtCore/QTime>
-#endif
#include "datavisualizationglobal_p.h"
#include "abstract3dcontroller_p.h"
#include "axisrendercache_p.h"
-#include "qabstractdataproxy.h"
#include "seriesrendercache_p.h"
+#include "customrenderitem_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -60,18 +55,27 @@ protected:
SelectOnSlice
};
- QString generateValueLabel(const QString &format, float value);
+ enum RenderingState {
+ RenderingNormal = 0,
+ RenderingSelection,
+ RenderingDepth
+ };
public:
virtual ~Abstract3DRenderer();
virtual void updateData() = 0;
- virtual void updateSeries(const QList<QAbstract3DSeries *> &seriesList, bool updateVisibility);
-
+ virtual void updateSeries(const QList<QAbstract3DSeries *> &seriesList);
+ virtual void updateCustomData(const QList<QCustom3DItem *> &customItems);
+ virtual void updateCustomItems();
+ virtual void updateCustomItemPositions();
+ virtual SeriesRenderCache *createNewCache(QAbstract3DSeries *series);
+ virtual void cleanCache(SeriesRenderCache *cache);
virtual void render(GLuint defaultFboHandle);
virtual void updateTheme(Q3DTheme *theme);
virtual void updateSelectionMode(QAbstract3DGraph::SelectionFlags newMode);
+ virtual void updateOptimizationHint(QAbstract3DGraph::OptimizationHints hint);
virtual void updateScene(Q3DScene *scene);
virtual void updateTextures() = 0;
virtual void initSelectionBuffer() = 0;
@@ -84,27 +88,64 @@ public:
virtual void updateShadowQuality(QAbstract3DGraph::ShadowQuality quality) = 0;
virtual void initShaders(const QString &vertexShader, const QString &fragmentShader) = 0;
virtual void initGradientShaders(const QString &vertexShader, const QString &fragmentShader);
- virtual void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader) = 0;
- virtual void updateAxisType(QAbstract3DAxis::AxisOrientation orientation, QAbstract3DAxis::AxisType type);
- virtual void updateAxisTitle(QAbstract3DAxis::AxisOrientation orientation, const QString &title);
- virtual void updateAxisLabels(QAbstract3DAxis::AxisOrientation orientation, const QStringList &labels);
- virtual void updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min, float max);
+ virtual void initBackgroundShaders(const QString &vertexShader,
+ const QString &fragmentShader) = 0;
+ virtual void initCustomItemShaders(const QString &vertexShader,
+ const QString &fragmentShader);
+ virtual void updateAxisType(QAbstract3DAxis::AxisOrientation orientation,
+ QAbstract3DAxis::AxisType type);
+ virtual void updateAxisTitle(QAbstract3DAxis::AxisOrientation orientation,
+ const QString &title);
+ virtual void updateAxisLabels(QAbstract3DAxis::AxisOrientation orientation,
+ const QStringList &labels);
+ virtual void updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min,
+ float max);
virtual void updateAxisSegmentCount(QAbstract3DAxis::AxisOrientation orientation, int count);
- virtual void updateAxisSubSegmentCount(QAbstract3DAxis::AxisOrientation orientation, int count);
- virtual void updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation orientation, const QString &format);
+ virtual void updateAxisSubSegmentCount(QAbstract3DAxis::AxisOrientation orientation,
+ int count);
+ virtual void updateAxisLabelFormat(QAbstract3DAxis::AxisOrientation orientation,
+ const QString &format);
+ virtual void updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation,
+ bool enable);
+ virtual void updateAxisFormatter(QAbstract3DAxis::AxisOrientation orientation,
+ QValue3DAxisFormatter *formatter);
+ virtual void updateAxisLabelAutoRotation(QAbstract3DAxis::AxisOrientation orientation,
+ float angle);
+ virtual void updateAxisTitleVisibility(QAbstract3DAxis::AxisOrientation orientation,
+ bool visible);
+ virtual void updateAxisTitleFixed(QAbstract3DAxis::AxisOrientation orientation,
+ bool fixed);
+ virtual void modifiedSeriesList(const QVector<QAbstract3DSeries *> &seriesList);
virtual void fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh mesh);
+
+ virtual CustomRenderItem *addCustomItem(QCustom3DItem *item);
+ virtual void updateCustomItem(CustomRenderItem *renderItem);
+
+ virtual void updateAspectRatio(float ratio);
+
+ virtual QVector3D convertPositionToTranslation(const QVector3D &position,
+ bool isAbsolute) = 0;
+
void generateBaseColorTexture(const QColor &color, GLuint *texture);
void fixGradientAndGenerateTexture(QLinearGradient *gradient, GLuint *gradientTexture);
inline bool isClickPending() { return m_clickPending; }
inline void clearClickPending() { m_clickPending = false; }
inline QAbstract3DSeries *clickedSeries() const { return m_clickedSeries; }
+ inline QAbstract3DGraph::ElementType clickedType() { return m_clickedType; }
LabelItem &selectionLabelItem();
void setSelectionLabel(const QString &label);
QString &selectionLabel();
+ void drawCustomItems(RenderingState state, ShaderHelper *shader,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionViewMatrix,
+ const QMatrix4x4 &depthProjectionViewMatrix,
+ GLuint depthTexture, GLfloat shadowQuality);
+ QVector4D indexToSelectionColor(GLint index);
+
signals:
void needRender(); // Emit this if something in renderer causes need for another render pass.
void requestShadowQuality(QAbstract3DGraph::ShadowQuality quality); // For automatic quality adjustments
@@ -124,6 +165,28 @@ protected:
void fixGradient(QLinearGradient *gradient, GLuint *gradientTexture);
+ void calculateZoomLevel();
+ void drawAxisTitleY(const QVector3D &sideLabelRotation, const QVector3D &backLabelRotation,
+ const QVector3D &sideLabelTrans, const QVector3D &backLabelTrans,
+ const QQuaternion &totalSideRotation, const QQuaternion &totalBackRotation,
+ AbstractRenderItem &dummyItem, const Q3DCamera *activeCamera,
+ float labelsMaxWidth,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix,
+ ShaderHelper *shader);
+ void drawAxisTitleX(const QVector3D &labelRotation, const QVector3D &labelTrans,
+ const QQuaternion &totalRotation, AbstractRenderItem &dummyItem,
+ const Q3DCamera *activeCamera, float labelsMaxWidth,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix,
+ ShaderHelper *shader);
+ void drawAxisTitleZ(const QVector3D &labelRotation, const QVector3D &labelTrans,
+ const QQuaternion &totalRotation, AbstractRenderItem &dummyItem,
+ const Q3DCamera *activeCamera, float labelsMaxWidth,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix,
+ ShaderHelper *shader);
+
+ void loadGridLineMesh();
+ void loadLabelMesh();
+
bool m_hasNegativeValues;
Q3DTheme *m_cachedTheme;
Drawer *m_drawer;
@@ -132,6 +195,7 @@ protected:
GLfloat m_autoScaleAdjustment;
QAbstract3DGraph::SelectionFlags m_cachedSelectionMode;
+ QAbstract3DGraph::OptimizationHints m_cachedOptimizationHint;
AxisRenderCache m_axisCacheX;
AxisRenderCache m_axisCacheY;
@@ -142,22 +206,37 @@ protected:
bool m_selectionDirty;
SelectionState m_selectionState;
QPoint m_inputPosition;
- QVector<SeriesRenderCache> m_visibleSeriesList;
+ QHash<QAbstract3DSeries *, SeriesRenderCache *> m_renderCacheList;
+ CustomRenderItemArray m_customRenderCache;
QRect m_primarySubViewport;
QRect m_secondarySubViewport;
float m_devicePixelRatio;
bool m_selectionLabelDirty;
bool m_clickPending;
QAbstract3DSeries *m_clickedSeries;
+ QAbstract3DGraph::ElementType m_clickedType;
+ int m_selectedLabelIndex;
+ int m_selectedCustomItemIndex;
QString m_selectionLabel;
LabelItem *m_selectionLabelItem;
+ int m_visibleSeriesCount;
-#ifdef DISPLAY_RENDER_SPEED
- bool m_isFirstFrame;
- QTime m_lastFrameTime;
- GLint m_numFrames;
-#endif
+ ShaderHelper *m_customItemShader;
+
+ bool m_useOrthoProjection;
+ bool m_xFlipped;
+ bool m_yFlipped;
+ bool m_zFlipped;
+
+ ObjectHelper *m_backgroundObj; // Shared reference
+ ObjectHelper *m_gridLineObj; // Shared reference
+ ObjectHelper *m_labelObj; // Shared reference
+
+ float m_graphAspectRatio;
+
+private:
+ friend class Abstract3DController;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/axisrendercache.cpp b/src/datavisualization/engine/axisrendercache.cpp
index a107dd23..0b7a5c7a 100644
--- a/src/datavisualization/engine/axisrendercache.cpp
+++ b/src/datavisualization/engine/axisrendercache.cpp
@@ -18,7 +18,6 @@
#include "axisrendercache_p.h"
-#include <QtCore/qmath.h>
#include <QtGui/QFontMetrics>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -29,10 +28,17 @@ AxisRenderCache::AxisRenderCache()
m_max(10.0f),
m_segmentCount(5),
m_subSegmentCount(1),
+ m_reversed(false),
m_font(QFont(QStringLiteral("Arial"))),
+ m_formatter(0),
+ m_ctrlFormatter(0),
m_drawer(0),
- m_segmentStep(10.0f),
- m_subSegmentStep(10.0f)
+ m_positionsDirty(true),
+ m_translate(0.0f),
+ m_scale(1.0f),
+ m_labelAutoRotation(0.0f),
+ m_titleVisible(false),
+ m_titleFixed(false)
{
}
@@ -40,6 +46,8 @@ AxisRenderCache::~AxisRenderCache()
{
foreach (LabelItem *label, m_labelItems)
delete label;
+
+ delete m_formatter;
}
void AxisRenderCache::setDrawer(Drawer *drawer)
@@ -69,8 +77,6 @@ void AxisRenderCache::setType(QAbstract3DAxis::AxisType type)
foreach (LabelItem *label, m_labelItems)
delete label;
m_labelItems.clear();
- m_segmentStep = 10.0f;
- m_subSegmentStep = 10.0f;
}
void AxisRenderCache::setTitle(const QString &title)
@@ -110,28 +116,44 @@ void AxisRenderCache::setLabels(const QStringList &labels)
}
}
-void AxisRenderCache::setMin(float min)
-{
- m_min = min;
- updateSegmentStep();
-}
-
-void AxisRenderCache::setMax(float max)
+void AxisRenderCache::updateAllPositions()
{
- m_max = max;
- updateSegmentStep();
-}
-
-void AxisRenderCache::setSegmentCount(int count)
-{
- m_segmentCount = count;
- updateSegmentStep();
-}
+ // As long as grid and subgrid lines are drawn identically, we can further optimize
+ // by caching all grid and subgrid positions into a single vector.
+ // If subgrid lines are ever themed separately, this array will probably become obsolete.
+ if (m_formatter) {
+ int gridCount = m_formatter->gridPositions().size();
+ int subGridCount = m_formatter->subGridPositions().size();
+ int labelCount = m_formatter->labelPositions().size();
+ int fullSize = gridCount + subGridCount;
+
+ m_adjustedGridLinePositions.resize(fullSize);
+ m_adjustedLabelPositions.resize(labelCount);
+ int index = 0;
+ int grid = 0;
+ int label = 0;
+ float position = 0.0f;
+ for (; label < labelCount; label++) {
+ position = m_formatter->labelPositions().at(label);
+ if (m_reversed)
+ position = 1.0f - position;
+ m_adjustedLabelPositions[label] = position * m_scale + m_translate;
+ }
+ for (; grid < gridCount; grid++) {
+ position = m_formatter->gridPositions().at(grid);
+ if (m_reversed)
+ position = 1.0f - position;
+ m_adjustedGridLinePositions[index++] = position * m_scale + m_translate;
+ }
+ for (int subGrid = 0; subGrid < subGridCount; subGrid++) {
+ position = m_formatter->subGridPositions().at(subGrid);
+ if (m_reversed)
+ position = 1.0f - position;
+ m_adjustedGridLinePositions[index++] = position * m_scale + m_translate;
+ }
-void AxisRenderCache::setSubSegmentCount(int count)
-{
- m_subSegmentCount = count;
- updateSubSegmentStep();
+ m_positionsDirty = false;
+ }
}
void AxisRenderCache::updateTextures()
@@ -153,23 +175,6 @@ void AxisRenderCache::updateTextures()
}
}
-void AxisRenderCache::updateSegmentStep()
-{
- if (m_segmentCount > 0)
- m_segmentStep = qFabs((m_max - m_min) / m_segmentCount);
- else
- m_segmentStep = 0.0f; // Irrelevant
- updateSubSegmentStep();
-}
-
-void AxisRenderCache::updateSubSegmentStep()
-{
- if (m_subSegmentCount > 1)
- m_subSegmentStep = m_segmentStep / m_subSegmentCount;
- else
- m_subSegmentStep = m_segmentStep;
-}
-
int AxisRenderCache::maxLabelWidth(const QStringList &labels) const
{
int labelWidth = 0;
diff --git a/src/datavisualization/engine/axisrendercache_p.h b/src/datavisualization/engine/axisrendercache_p.h
index e1c51e7c..90321740 100644
--- a/src/datavisualization/engine/axisrendercache_p.h
+++ b/src/datavisualization/engine/axisrendercache_p.h
@@ -30,9 +30,8 @@
#define AXISRENDERCACHE_P_H
#include "datavisualizationglobal_p.h"
-#include "labelitem_p.h"
-#include "qabstract3daxis_p.h"
#include "drawer_p.h"
+#include <QtCore/QPointer>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -48,31 +47,70 @@ public:
void setType(QAbstract3DAxis::AxisType type);
inline QAbstract3DAxis::AxisType type() const { return m_type; }
void setTitle(const QString &title);
- inline const QString &title() { return m_title; }
+ inline const QString &title() const { return m_title; }
void setLabels(const QStringList &labels);
- inline const QStringList &labels() { return m_labels; }
- void setMin(float min);
- inline float min() { return m_min; }
- void setMax(float max);
- inline float max() { return m_max; }
- void setSegmentCount(int count);
+ inline const QStringList &labels() const { return m_labels; }
+ inline void setMin(float min) { m_min = min; }
+ inline float min() const { return m_min; }
+ inline void setMax(float max) { m_max = max; }
+ inline float max() const { return m_max; }
+ inline void setSegmentCount(int count) { m_segmentCount = count; m_positionsDirty = true; }
inline int segmentCount() const { return m_segmentCount; }
- void setSubSegmentCount(int count);
+ inline void setSubSegmentCount(int count) { m_subSegmentCount = count; m_positionsDirty = true; }
inline int subSegmentCount() const { return m_subSegmentCount; }
inline void setLabelFormat(const QString &format) { m_labelFormat = format; }
- inline const QString &labelFormat() { return m_labelFormat; }
+ inline const QString &labelFormat() const { return m_labelFormat; }
+ inline void setReversed(bool enable) { m_reversed = enable; m_positionsDirty = true; }
+ inline bool reversed() const { return m_reversed; }
+ inline void setFormatter(QValue3DAxisFormatter *formatter)
+ {
+ m_formatter = formatter; m_positionsDirty = true;
+ }
+ inline QValue3DAxisFormatter *formatter() const { return m_formatter; }
+ inline void setCtrlFormatter(QValue3DAxisFormatter *formatter)
+ {
+ m_ctrlFormatter = formatter;
+ }
+ inline QValue3DAxisFormatter *ctrlFormatter() const { return m_ctrlFormatter; }
inline LabelItem &titleItem() { return m_titleItem; }
inline QList<LabelItem *> &labelItems() { return m_labelItems; }
- inline GLfloat segmentStep() const { return m_segmentStep; }
- inline GLfloat subSegmentStep() const { return m_subSegmentStep; }
+ inline float gridLinePosition(int index) { return m_adjustedGridLinePositions.at(index); }
+ inline int gridLineCount() { return m_adjustedGridLinePositions.size(); }
+ inline float labelPosition(int index) { return m_adjustedLabelPositions.at(index); }
+ inline int labelCount() {
+ // Some value axis formatters may opt to not show all labels,
+ // so use positions array for determining count in that case.
+ if (m_type == QAbstract3DAxis::AxisTypeValue)
+ return m_adjustedLabelPositions.size();
+ else
+ return m_labels.size();
+ }
+ void updateAllPositions();
+ inline bool positionsDirty() const { return m_positionsDirty; }
+ inline void markPositionsDirty() { m_positionsDirty = true; }
+ inline void setTranslate(float translate) { m_translate = translate; m_positionsDirty = true; }
+ inline float translate() { return m_translate; }
+ inline void setScale(float scale) { m_scale = scale; m_positionsDirty = true; }
+ inline float scale() { return m_scale; }
+ inline float positionAt(float value)
+ {
+ if (m_reversed)
+ return (1.0f - m_formatter->positionAt(value)) * m_scale + m_translate;
+ else
+ return m_formatter->positionAt(value) * m_scale + m_translate;
+ }
+ inline float labelAutoRotation() const { return m_labelAutoRotation; }
+ inline void setLabelAutoRotation(float angle) { m_labelAutoRotation = angle; }
+ inline bool isTitleVisible() const { return m_titleVisible; }
+ inline void setTitleVisible(bool visible) { m_titleVisible = visible; }
+ inline bool isTitleFixed() const { return m_titleFixed; }
+ inline void setTitleFixed(bool fixed) { m_titleFixed = fixed; }
public slots:
void updateTextures();
private:
- void updateSegmentStep();
- void updateSubSegmentStep();
int maxLabelWidth(const QStringList &labels) const;
// Cached axis values
@@ -84,14 +122,23 @@ private:
int m_segmentCount;
int m_subSegmentCount;
QString m_labelFormat;
+ bool m_reversed;
QFont m_font;
+ QValue3DAxisFormatter *m_formatter;
+ QPointer<QValue3DAxisFormatter> m_ctrlFormatter;
// Renderer items
Drawer *m_drawer; // Not owned
LabelItem m_titleItem;
QList<LabelItem *> m_labelItems;
- GLfloat m_segmentStep;
- GLfloat m_subSegmentStep;
+ QVector<float> m_adjustedGridLinePositions;
+ QVector<float> m_adjustedLabelPositions;
+ bool m_positionsDirty;
+ float m_translate;
+ float m_scale;
+ float m_labelAutoRotation;
+ bool m_titleVisible;
+ bool m_titleFixed;
Q_DISABLE_COPY(AxisRenderCache)
};
diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp
index 91240259..3a240c24 100644
--- a/src/datavisualization/engine/bars3dcontroller.cpp
+++ b/src/datavisualization/engine/bars3dcontroller.cpp
@@ -18,8 +18,6 @@
#include "bars3dcontroller_p.h"
#include "bars3drenderer_p.h"
-#include "camerahelper_p.h"
-#include "qabstract3daxis_p.h"
#include "qvalue3daxis_p.h"
#include "qcategory3daxis_p.h"
#include "qbardataproxy_p.h"
@@ -27,9 +25,6 @@
#include "thememanager_p.h"
#include "q3dtheme_p.h"
-#include <QtGui/QMatrix4x4>
-#include <QtCore/qmath.h>
-
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
Bars3DController::Bars3DController(QRect boundRect, Q3DScene *scene)
@@ -81,9 +76,28 @@ void Bars3DController::synchDataToRenderer()
series->d_ptr->m_changeTracker.meshChanged = true;
}
+ // If y range or reverse changed, scene needs to be updated to update camera limits
+ bool needSceneUpdate = false;
+ if (Abstract3DController::m_changeTracker.axisYRangeChanged
+ || Abstract3DController::m_changeTracker.axisYReversedChanged) {
+ needSceneUpdate = true;
+ }
+
Abstract3DController::synchDataToRenderer();
// Notify changes to renderer
+ if (m_changeTracker.rowsChanged) {
+ m_renderer->updateRows(m_changedRows);
+ m_changeTracker.rowsChanged = false;
+ m_changedRows.clear();
+ }
+
+ if (m_changeTracker.itemChanged) {
+ m_renderer->updateItems(m_changedItems);
+ m_changeTracker.itemChanged = false;
+ m_changedItems.clear();
+ }
+
if (m_changeTracker.multiSeriesScalingChanged) {
m_renderer->updateMultiSeriesScaling(m_isMultiSeriesUniform);
m_changeTracker.multiSeriesScalingChanged = false;
@@ -99,6 +113,13 @@ void Bars3DController::synchDataToRenderer()
m_renderer->updateSelectedBar(m_selectedBar, m_selectedBarSeries);
m_changeTracker.selectedBarChanged = false;
}
+
+ if (needSceneUpdate) {
+ // Since scene is updated before axis updates are handled,
+ // do another render pass for scene update
+ m_scene->d_ptr->m_sceneDirty = true;
+ emitNeedRender();
+ }
}
void Bars3DController::handleArrayReset()
@@ -107,7 +128,10 @@ void Bars3DController::handleArrayReset()
if (series->isVisible()) {
adjustAxisRanges();
m_isDataDirty = true;
+ series->d_ptr->markItemLabelDirty();
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
// Clear selection unless still valid
setSelectedBar(m_selectedBar, m_selectedBarSeries, false);
emitNeedRender();
@@ -122,19 +146,45 @@ void Bars3DController::handleRowsAdded(int startIndex, int count)
adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
void Bars3DController::handleRowsChanged(int startIndex, int count)
{
- Q_UNUSED(startIndex)
- Q_UNUSED(count)
QBar3DSeries *series = static_cast<QBarDataProxy *>(sender())->series();
- if (series->isVisible()) {
- adjustAxisRanges();
- m_isDataDirty = true;
+ int oldChangeCount = m_changedRows.size();
+ if (!oldChangeCount)
+ m_changedRows.reserve(count);
+
+ for (int i = 0; i < count; i++) {
+ bool newItem = true;
+ int candidate = startIndex + i;
+ for (int j = 0; j < oldChangeCount; j++) {
+ const ChangeRow &oldChangeItem = m_changedRows.at(j);
+ if (oldChangeItem.row == candidate && series == oldChangeItem.series) {
+ newItem = false;
+ break;
+ }
+ }
+ if (newItem) {
+ ChangeRow newChangeItem = {series, candidate};
+ m_changedRows.append(newChangeItem);
+ if (series == m_selectedBarSeries && m_selectedBar.x() == candidate)
+ series->d_ptr->markItemLabelDirty();
+ }
+ }
+ if (count) {
+ m_changeTracker.rowsChanged = true;
+
+ if (series->isVisible())
+ adjustAxisRanges();
+
+ // Clear selection unless still valid (row length might have changed)
+ setSelectedBar(m_selectedBar, m_selectedBarSeries, false);
+ emitNeedRender();
}
- emitNeedRender();
}
void Bars3DController::handleRowsRemoved(int startIndex, int count)
@@ -160,6 +210,8 @@ void Bars3DController::handleRowsRemoved(int startIndex, int count)
adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
@@ -182,20 +234,36 @@ void Bars3DController::handleRowsInserted(int startIndex, int count)
adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
void Bars3DController::handleItemChanged(int rowIndex, int columnIndex)
{
- Q_UNUSED(rowIndex)
- Q_UNUSED(columnIndex)
QBar3DSeries *series = static_cast<QBarDataProxy *>(sender())->series();
- if (series->isVisible()) {
- adjustAxisRanges();
- m_isDataDirty = true;
+
+ bool newItem = true;
+ QPoint candidate(rowIndex, columnIndex);
+ foreach (ChangeItem item, m_changedItems) {
+ if (item.point == candidate && item.series == series) {
+ newItem = false;
+ break;
+ }
+ }
+
+ if (newItem) {
+ ChangeItem newItem = {series, candidate};
+ m_changedItems.append(newItem);
+ m_changeTracker.itemChanged = true;
+
+ if (series == m_selectedBarSeries && m_selectedBar == candidate)
+ series->d_ptr->markItemLabelDirty();
+ if (series->isVisible())
+ adjustAxisRanges();
+ emitNeedRender();
}
- emitNeedRender();
}
void Bars3DController::handleDataRowLabelsChanged()
@@ -238,8 +306,6 @@ void Bars3DController::handleSeriesVisibilityChangedBySender(QObject *sender)
{
Abstract3DController::handleSeriesVisibilityChangedBySender(sender);
- adjustAxisRanges();
-
// Visibility changes may require disabling slicing,
// so just reset selection to ensure everything is still valid.
setSelectedBar(m_selectedBar, m_selectedBarSeries, false);
@@ -253,6 +319,8 @@ void Bars3DController::handlePendingClick()
setSelectedBar(position, series, true);
+ Abstract3DController::handlePendingClick();
+
m_renderer->resetClickedStatus();
}
@@ -337,9 +405,6 @@ void Bars3DController::insertSeries(int index, QAbstract3DSeries *series)
Abstract3DController::insertSeries(index, series);
if (oldSize != m_seriesList.size()) {
- if (series->isVisible())
- adjustAxisRanges();
-
QBar3DSeries *barSeries = static_cast<QBar3DSeries *>(series);
if (!oldSize) {
m_primarySeries = barSeries;
@@ -460,7 +525,8 @@ void Bars3DController::setSelectedBar(const QPoint &position, QBar3DSeries *seri
adjustSelectionPosition(pos, series);
if (selectionMode().testFlag(QAbstract3DGraph::SelectionSlice)) {
- // If the selected bar is outside data window, or there is no visible selected bar, disable slicing
+ // If the selected bar is outside data window, or there is no visible selected bar,
+ // disable slicing.
if (pos.x() < m_axisZ->min() || pos.x() > m_axisZ->max()
|| pos.y() < m_axisX->min() || pos.y() > m_axisX->max()
|| !series->isVisible()) {
@@ -518,7 +584,8 @@ void Bars3DController::adjustAxisRanges()
int seriesCount = m_seriesList.size();
if (adjustZ || adjustX) {
for (int series = 0; series < seriesCount; series++) {
- const QBar3DSeries *barSeries = static_cast<QBar3DSeries *>(m_seriesList.at(series));
+ const QBar3DSeries *barSeries =
+ static_cast<QBar3DSeries *>(m_seriesList.at(series));
if (barSeries->isVisible()) {
const QBarDataProxy *proxy = barSeries->dataProxy();
@@ -546,22 +613,24 @@ void Bars3DController::adjustAxisRanges()
}
// Call private implementations of setRange to avoid unsetting auto adjust flag
if (adjustZ)
- categoryAxisZ->dptr()->setRange(0.0f, float(maxRowCount));
+ categoryAxisZ->dptr()->setRange(0.0f, float(maxRowCount), true);
if (adjustX)
- categoryAxisX->dptr()->setRange(0.0f, float(maxColumnCount));
+ categoryAxisX->dptr()->setRange(0.0f, float(maxColumnCount), true);
}
// Now that we know the row and column ranges, figure out the value axis range
if (adjustY) {
for (int series = 0; series < seriesCount; series++) {
- const QBar3DSeries *barSeries = static_cast<QBar3DSeries *>(m_seriesList.at(series));
+ const QBar3DSeries *barSeries =
+ static_cast<QBar3DSeries *>(m_seriesList.at(series));
if (barSeries->isVisible()) {
const QBarDataProxy *proxy = barSeries->dataProxy();
if (adjustY && proxy) {
- QPair<GLfloat, GLfloat> limits = proxy->dptrc()->limitValues(categoryAxisZ->min(),
- categoryAxisZ->max(),
- categoryAxisX->min(),
- categoryAxisX->max());
+ QPair<GLfloat, GLfloat> limits =
+ proxy->dptrc()->limitValues(categoryAxisZ->min(),
+ categoryAxisZ->max(),
+ categoryAxisX->min(),
+ categoryAxisX->max());
if (!series) {
// First series initializes the values
minValue = limits.first;
@@ -583,7 +652,7 @@ void Bars3DController::adjustAxisRanges()
minValue = 0.0f;
maxValue = 1.0f;
}
- valueAxis->dptr()->setRange(minValue, maxValue);
+ valueAxis->dptr()->setRange(minValue, maxValue, true);
}
}
}
diff --git a/src/datavisualization/engine/bars3dcontroller_p.h b/src/datavisualization/engine/bars3dcontroller_p.h
index 9ea59c89..4f0e1f20 100644
--- a/src/datavisualization/engine/bars3dcontroller_p.h
+++ b/src/datavisualization/engine/bars3dcontroller_p.h
@@ -38,16 +38,18 @@ class Bars3DRenderer;
class QBar3DSeries;
struct Bars3DChangeBitField {
- bool slicingActiveChanged : 1;
bool multiSeriesScalingChanged : 1;
bool barSpecsChanged : 1;
bool selectedBarChanged : 1;
+ bool rowsChanged : 1;
+ bool itemChanged : 1;
Bars3DChangeBitField() :
- slicingActiveChanged(true),
multiSeriesScalingChanged(true),
barSpecsChanged(true),
- selectedBarChanged(true)
+ selectedBarChanged(true),
+ rowsChanged(false),
+ itemChanged(false)
{
}
};
@@ -56,8 +58,20 @@ class QT_DATAVISUALIZATION_EXPORT Bars3DController : public Abstract3DController
{
Q_OBJECT
+public:
+ struct ChangeItem {
+ QBar3DSeries *series;
+ QPoint point;
+ };
+ struct ChangeRow {
+ QBar3DSeries *series;
+ int row;
+ };
+
private:
Bars3DChangeBitField m_changeTracker;
+ QVector<ChangeItem> m_changedItems;
+ QVector<ChangeRow> m_changedRows;
// Interaction
QPoint m_selectedBar; // Points to row & column in data window.
@@ -118,6 +132,7 @@ public:
virtual QList<QBar3DSeries *> barSeriesList();
virtual void handleAxisRangeChangedBySender(QObject *sender);
+ virtual void adjustAxisRanges();
public slots:
void handleArrayReset();
@@ -137,11 +152,9 @@ protected:
virtual QAbstract3DAxis *createDefaultAxis(QAbstract3DAxis::AxisOrientation orientation);
private:
- void adjustAxisRanges();
void adjustSelectionPosition(QPoint &pos, const QBar3DSeries *series);
Q_DISABLE_COPY(Bars3DController)
-
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/bars3drenderer.cpp b/src/datavisualization/engine/bars3drenderer.cpp
index a7f9e2b3..3805e760 100644
--- a/src/datavisualization/engine/bars3drenderer.cpp
+++ b/src/datavisualization/engine/bars3drenderer.cpp
@@ -17,20 +17,12 @@
****************************************************************************/
#include "bars3drenderer_p.h"
-#include "bars3dcontroller_p.h"
#include "q3dcamera_p.h"
#include "shaderhelper_p.h"
-#include "objecthelper_p.h"
#include "texturehelper_p.h"
#include "utils_p.h"
-#include "drawer_p.h"
-#include "qbardataitem.h"
-#include "q3dlight.h"
-#include "qbar3dseries_p.h"
-
-#include <QtGui/QMatrix4x4>
-#include <QtGui/QMouseEvent>
-#include <QtCore/QThread>
+#include "barseriesrendercache_p.h"
+
#include <QtCore/qmath.h>
// You can verify that depth buffer drawing works correctly by uncommenting this.
@@ -39,9 +31,7 @@
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-const GLfloat labelMargin = 0.05f;
const GLfloat gridLineWidth = 0.005f;
-
const bool sliceGridLabels = true;
Bars3DRenderer::Bars3DRenderer(Bars3DController *controller)
@@ -52,9 +42,6 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller)
m_selectedBar(0),
m_sliceCache(0),
m_sliceTitleItem(0),
- m_xFlipped(false),
- m_zFlipped(false),
- m_yFlipped(false),
m_updateLabels(false),
m_barShader(0),
m_barGradientShader(0),
@@ -62,9 +49,6 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller)
m_selectionShader(0),
m_backgroundShader(0),
m_labelShader(0),
- m_backgroundObj(0),
- m_gridLineObj(0),
- m_labelObj(0),
m_bgrTexture(0),
m_depthTexture(0),
m_selectionTexture(0),
@@ -74,7 +58,7 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller)
m_shadowQualityToShader(100.0f),
m_shadowQualityMultiplier(3),
m_heightNormalizer(1.0f),
- m_negativeBackgroundAdjustment(0.0f),
+ m_backgroundAdjustment(0.0f),
m_rowWidth(0),
m_columnDepth(0),
m_maxDimension(0),
@@ -83,18 +67,23 @@ Bars3DRenderer::Bars3DRenderer(Bars3DController *controller)
m_scaleFactor(0),
m_maxSceneSize(40.0f),
m_visualSelectedBarPos(Bars3DController::invalidSelectionPosition()),
- m_visualSelectedBarSeriesIndex(-1),
- m_hasHeightAdjustmentChanged(true),
+ m_resetCameraBaseOrientation(true),
m_selectedBarPos(Bars3DController::invalidSelectionPosition()),
- m_selectedBarSeries(0),
+ m_selectedSeriesCache(0),
m_noZeroInRange(false),
m_seriesScaleX(0.0f),
m_seriesScaleZ(0.0f),
m_seriesStep(0.0f),
m_seriesStart(0.0f),
m_clickedPosition(Bars3DController::invalidSelectionPosition()),
- m_keepSeriesUniform(false)
+ m_keepSeriesUniform(false),
+ m_haveUniformColorSeries(false),
+ m_haveGradientSeries(false),
+ m_zeroPosition(0.0f)
{
+ m_axisCacheY.setScale(2.0f);
+ m_axisCacheY.setTranslate(-1.0f);
+
initializeOpenGLFunctions();
initializeOpenGL();
}
@@ -114,9 +103,6 @@ Bars3DRenderer::~Bars3DRenderer()
delete m_depthShader;
delete m_selectionShader;
delete m_backgroundShader;
- delete m_backgroundObj;
- delete m_gridLineObj;
- delete m_labelObj;
delete m_labelShader;
}
@@ -148,23 +134,18 @@ void Bars3DRenderer::initializeOpenGL()
void Bars3DRenderer::updateData()
{
- int seriesCount = m_visibleSeriesList.size();
int minRow = m_axisCacheZ.min();
int maxRow = m_axisCacheZ.max();
int minCol = m_axisCacheX.min();
int maxCol = m_axisCacheX.max();
int newRows = maxRow - minRow + 1;
int newColumns = maxCol - minCol + 1;
- int updateSize = 0;
int dataRowCount = 0;
int maxDataRowCount = 0;
- if (m_renderingArrays.size() != seriesCount) {
- m_renderingArrays.resize(seriesCount);
- m_seriesScaleX = 1.0f / float(seriesCount);
- m_seriesStep = 1.0f / float(seriesCount);
- m_seriesStart = -((float(seriesCount) - 1.0f) / 2.0f) * m_seriesStep;
- }
+ m_seriesScaleX = 1.0f / float(m_visibleSeriesCount);
+ m_seriesStep = 1.0f / float(m_visibleSeriesCount);
+ m_seriesStart = -((float(m_visibleSeriesCount) - 1.0f) / 2.0f) * m_seriesStep;
if (m_keepSeriesUniform)
m_seriesScaleZ = m_seriesScaleX;
@@ -175,7 +156,6 @@ void Bars3DRenderer::updateData()
// Force update for selection related items
m_sliceCache = 0;
m_sliceTitleItem = 0;
- m_sliceSelection.clear();
m_cachedColumnCount = newColumns;
m_cachedRowCount = newRows;
@@ -187,88 +167,235 @@ void Bars3DRenderer::updateData()
calculateSceneScalingFactors();
}
- for (int series = 0; series < seriesCount; series++) {
- BarRenderItemArray &renderArray = m_renderingArrays[series];
- if (newRows != renderArray.size()
- || newColumns != renderArray.at(0).size()) {
- // Destroy old render items and reallocate new array
- renderArray.resize(newRows);
- for (int i = 0; i < newRows; i++)
- renderArray[i].resize(newColumns);
- }
+ m_zeroPosition = m_axisCacheY.formatter()->positionAt(0.0f);
+
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ if (cache->isVisible()) {
+ const QBar3DSeries *currentSeries = cache->series();
+ BarRenderItemArray &renderArray = cache->renderArray();
+ bool dimensionsChanged = false;
+ if (newRows != renderArray.size()
+ || newColumns != renderArray.at(0).size()) {
+ // Destroy old render items and reallocate new array
+ dimensionsChanged = true;
+ renderArray.resize(newRows);
+ for (int i = 0; i < newRows; i++)
+ renderArray[i].resize(newColumns);
+ cache->sliceArray().clear();
+ }
- // Update cached data window
- QBarDataProxy *dataProxy =
- static_cast<QBar3DSeries *>(m_visibleSeriesList.at(series).series())->dataProxy();
- dataRowCount = dataProxy->rowCount();
- if (maxDataRowCount < dataRowCount)
- maxDataRowCount = qMin(dataRowCount, newRows);
- int dataRowIndex = minRow;
- GLfloat heightValue = 0.0f;
- for (int i = 0; i < newRows; i++) {
- int j = 0;
- BarRenderItemRow &renderRow = renderArray[i];
- if (dataRowIndex < dataRowCount) {
- const QBarDataRow *dataRow = dataProxy->rowAt(dataRowIndex);
- updateSize = qMin((dataRow->size() - minCol), renderRow.size());
- if (dataRow) {
- int dataColIndex = minCol;
- for (; j < updateSize ; j++) {
- float value = dataRow->at(dataColIndex).value();
- if (!m_noZeroInRange) {
- heightValue = GLfloat(value);
- } else {
- // Adjust height to range
- if (!m_hasNegativeValues) {
- heightValue = value - m_axisCacheY.min();
- if (heightValue < 0.0f)
- heightValue = 0.0f;
- } else if (m_axisCacheY.max() < 0.0f) {
- heightValue = value - m_axisCacheY.max();
- if (heightValue > 0.0f)
- heightValue = 0.0f;
- }
- }
- renderRow[j].setValue(value);
- renderRow[j].setHeight(heightValue / m_heightNormalizer);
- float angle = dataRow->at(dataColIndex).rotation();
- if (angle) {
- renderRow[j].setRotation(
- QQuaternion::fromAxisAndAngle(
- upVector, angle));
- } else {
- renderRow[j].setRotation(identityQuaternion);
- }
- dataColIndex++;
- }
+ if (cache->dataDirty() || dimensionsChanged) {
+ QBarDataProxy *dataProxy = currentSeries->dataProxy();
+ dataRowCount = dataProxy->rowCount();
+ if (maxDataRowCount < dataRowCount)
+ maxDataRowCount = qMin(dataRowCount, newRows);
+ int dataRowIndex = minRow;
+ for (int i = 0; i < newRows; i++) {
+ BarRenderItemRow &renderRow = renderArray[i];
+ const QBarDataRow *dataRow = 0;
+ if (dataRowIndex < dataRowCount)
+ dataRow = dataProxy->rowAt(dataRowIndex);
+ updateRenderRow(dataRow, renderRow);
+ dataRowIndex++;
}
+ cache->setDataDirty(false);
}
- for (; j < m_renderingArrays.at(series).at(i).size(); j++) {
- renderRow[j].setValue(0.0f);
- renderRow[j].setHeight(0.0f);
- renderRow[j].setRotation(identityQuaternion);
- }
- dataRowIndex++;
}
}
// Reset selected bar to update selection
- updateSelectedBar(m_selectedBarPos, m_selectedBarSeries);
+ updateSelectedBar(m_selectedBarPos,
+ m_selectedSeriesCache ? m_selectedSeriesCache->series() : 0);
+}
+
+void Bars3DRenderer::updateRenderRow(const QBarDataRow *dataRow, BarRenderItemRow &renderRow)
+{
+ int j = 0;
+ int renderRowSize = renderRow.size();
+ int startIndex = m_axisCacheX.min();
+
+ if (dataRow) {
+ int updateSize = qMin((dataRow->size() - startIndex), renderRowSize);
+ int dataColIndex = startIndex;
+ for (; j < updateSize ; j++) {
+ updateRenderItem(dataRow->at(dataColIndex), renderRow[j]);
+ dataColIndex++;
+ }
+ }
+ for (; j < renderRowSize; j++) {
+ renderRow[j].setValue(0.0f);
+ renderRow[j].setHeight(0.0f);
+ renderRow[j].setRotation(identityQuaternion);
+ }
+}
+
+void Bars3DRenderer::updateRenderItem(const QBarDataItem &dataItem, BarRenderItem &renderItem)
+{
+ float value = dataItem.value();
+ float heightValue = m_axisCacheY.formatter()->positionAt(value);
+ if (m_noZeroInRange) {
+ if (m_hasNegativeValues) {
+ heightValue = -1.0f + heightValue;
+ if (heightValue > 0.0f)
+ heightValue = 0.0f;
+ } else {
+ if (heightValue < 0.0f)
+ heightValue = 0.0f;
+ }
+ } else {
+ heightValue -= m_zeroPosition;
+ }
+ if (m_axisCacheY.reversed())
+ heightValue = -heightValue;
+
+ renderItem.setValue(value);
+ renderItem.setHeight(heightValue);
+
+ float angle = dataItem.rotation();
+ if (angle) {
+ renderItem.setRotation(
+ QQuaternion::fromAxisAndAngle(
+ upVector, angle));
+ } else {
+ renderItem.setRotation(identityQuaternion);
+ }
+}
+
+void Bars3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList)
+{
+ Abstract3DRenderer::updateSeries(seriesList);
+
+ bool noSelection = true;
+ int seriesCount = seriesList.size();
+ int visualIndex = 0;
+ m_haveUniformColorSeries = false;
+ m_haveGradientSeries = false;
+ for (int i = 0; i < seriesCount; i++) {
+ QBar3DSeries *barSeries = static_cast<QBar3DSeries *>(seriesList[i]);
+ BarSeriesRenderCache *cache =
+ static_cast<BarSeriesRenderCache *>(m_renderCacheList.value(barSeries));
+ if (barSeries->isVisible()) {
+ if (noSelection
+ && barSeries->selectedBar() != QBar3DSeries::invalidSelectionPosition()) {
+ if (selectionLabel() != cache->itemLabel())
+ m_selectionLabelDirty = true;
+ noSelection = false;
+ }
+ cache->setVisualIndex(visualIndex++);
+ if (cache->colorStyle() == Q3DTheme::ColorStyleUniform)
+ m_haveUniformColorSeries = true;
+ else
+ m_haveGradientSeries = true;
+ } else {
+ cache->setVisualIndex(-1);
+ }
+
+ }
+ if (noSelection) {
+ if (!selectionLabel().isEmpty())
+ m_selectionLabelDirty = true;
+ m_selectedSeriesCache = 0;
+ }
+}
+
+SeriesRenderCache *Bars3DRenderer::createNewCache(QAbstract3DSeries *series)
+{
+ return new BarSeriesRenderCache(series, this);
+}
+
+void Bars3DRenderer::updateRows(const QVector<Bars3DController::ChangeRow> &rows)
+{
+ int minRow = m_axisCacheZ.min();
+ int maxRow = m_axisCacheZ.max();
+ BarSeriesRenderCache *cache = 0;
+ const QBar3DSeries *prevSeries = 0;
+ const QBarDataArray *dataArray = 0;
+
+ foreach (Bars3DController::ChangeRow item, rows) {
+ const int row = item.row;
+ if (row < minRow || row > maxRow)
+ continue;
+ QBar3DSeries *currentSeries = item.series;
+ if (currentSeries != prevSeries) {
+ cache = static_cast<BarSeriesRenderCache *>(m_renderCacheList.value(currentSeries));
+ prevSeries = currentSeries;
+ dataArray = item.series->dataProxy()->array();
+ // Invisible series render caches are not updated, but instead just marked dirty, so that
+ // they can be completely recalculated when they are turned visible.
+ if (!cache->isVisible() && !cache->dataDirty())
+ cache->setDataDirty(true);
+ }
+ if (cache->isVisible()) {
+ updateRenderRow(dataArray->at(row), cache->renderArray()[row - minRow]);
+ if (m_cachedIsSlicingActivated
+ && cache == m_selectedSeriesCache
+ && m_selectedBarPos.x() == row) {
+ m_selectionDirty = true; // Need to update slice view
+ }
+ }
+ }
+}
+
+void Bars3DRenderer::updateItems(const QVector<Bars3DController::ChangeItem> &items)
+{
+ int minRow = m_axisCacheZ.min();
+ int maxRow = m_axisCacheZ.max();
+ int minCol = m_axisCacheX.min();
+ int maxCol = m_axisCacheX.max();
+ BarSeriesRenderCache *cache = 0;
+ const QBar3DSeries *prevSeries = 0;
+ const QBarDataArray *dataArray = 0;
+
+ foreach (Bars3DController::ChangeItem item, items) {
+ const int row = item.point.x();
+ const int col = item.point.y();
+ if (row < minRow || row > maxRow || col < minCol || col > maxCol)
+ continue;
+ QBar3DSeries *currentSeries = item.series;
+ if (currentSeries != prevSeries) {
+ cache = static_cast<BarSeriesRenderCache *>(m_renderCacheList.value(currentSeries));
+ prevSeries = currentSeries;
+ dataArray = item.series->dataProxy()->array();
+ // Invisible series render caches are not updated, but instead just marked dirty, so that
+ // they can be completely recalculated when they are turned visible.
+ if (!cache->isVisible() && !cache->dataDirty())
+ cache->setDataDirty(true);
+ }
+ if (cache->isVisible()) {
+ updateRenderItem(dataArray->at(row)->at(col),
+ cache->renderArray()[row - minRow][col - minCol]);
+ if (m_cachedIsSlicingActivated
+ && cache == m_selectedSeriesCache
+ && m_selectedBarPos == QPoint(row, col)) {
+ m_selectionDirty = true; // Need to update slice view
+ }
+ }
+ }
}
void Bars3DRenderer::updateScene(Q3DScene *scene)
{
- if (m_hasNegativeValues)
+ if (!m_noZeroInRange) {
scene->activeCamera()->d_ptr->setMinYRotation(-90.0);
- else
- scene->activeCamera()->d_ptr->setMinYRotation(0.0f);
+ scene->activeCamera()->d_ptr->setMaxYRotation(90.0);
+ } else {
+ if ((m_hasNegativeValues && !m_axisCacheY.reversed())
+ || (!m_hasNegativeValues && m_axisCacheY.reversed())) {
+ scene->activeCamera()->d_ptr->setMinYRotation(-90.0f);
+ scene->activeCamera()->d_ptr->setMaxYRotation(0.0);
+ } else {
+ scene->activeCamera()->d_ptr->setMinYRotation(0.0f);
+ scene->activeCamera()->d_ptr->setMaxYRotation(90.0);
+ }
+ }
- if (m_hasHeightAdjustmentChanged) {
+ if (m_resetCameraBaseOrientation) {
// Set initial camera position. Also update if height adjustment has changed.
scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector,
zeroVector,
upVector);
- m_hasHeightAdjustmentChanged = false;
+ m_resetCameraBaseOrientation = false;
}
Abstract3DRenderer::updateScene(scene);
@@ -281,6 +408,9 @@ void Bars3DRenderer::render(GLuint defaultFboHandle)
// Handle GL state setup for FBO buffers and clearing of the render surface
Abstract3DRenderer::render(defaultFboHandle);
+ if (m_axisCacheY.positionsDirty())
+ m_axisCacheY.updateAllPositions();
+
drawScene(defaultFboHandle);
if (m_cachedIsSlicingActivated)
drawSlicedScene();
@@ -290,7 +420,7 @@ void Bars3DRenderer::drawSlicedScene()
{
GLfloat barPosX = 0;
QVector3D lightPos;
- QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
+ QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
static QQuaternion ninetyDegreeRotation = QQuaternion::fromAxisAndAngle(upVector, 90.0f);
// Specify viewport
@@ -301,8 +431,16 @@ void Bars3DRenderer::drawSlicedScene()
// Set up projection matrix
QMatrix4x4 projectionMatrix;
- projectionMatrix.perspective(35.0f, (GLfloat)m_secondarySubViewport.width()
- / (GLfloat)m_secondarySubViewport.height(), 0.1f, 100.0f);
+ GLfloat viewPortRatio = (GLfloat)m_primarySubViewport.width()
+ / (GLfloat)m_primarySubViewport.height();
+ if (m_useOrthoProjection) {
+ GLfloat orthoRatio = 2.0f / m_autoScaleAdjustment;
+ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
+ -orthoRatio, orthoRatio,
+ 0.0f, 100.0f);
+ } else {
+ projectionMatrix.perspective(35.0f, viewPortRatio, 0.1f, 100.0f);
+ }
// Set view matrix
QMatrix4x4 viewMatrix;
@@ -323,27 +461,37 @@ void Bars3DRenderer::drawSlicedScene()
bool itemMode = m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionItem);
GLfloat barPosYAdjustment = -0.8f; // Translate to -1.0 + 0.2 for row/column labels
+ GLfloat gridAdjustment = 1.0f + barPosYAdjustment - m_backgroundAdjustment;
GLfloat scaleFactor = 0.0f;
if (rowMode)
scaleFactor = (1.1f * m_rowWidth) / m_scaleFactor;
else
scaleFactor = (1.1f * m_columnDepth) / m_scaleFactor;
- GLfloat barLabelYPos = barPosYAdjustment - 0.4f - labelMargin; // 0.4 for labels
+ GLfloat barLabelYPos = barPosYAdjustment - labelMargin;
GLfloat zeroPosAdjustment = 0.0f;
- if (!m_noZeroInRange)
- zeroPosAdjustment = 2.0f * m_axisCacheY.min() / m_heightNormalizer;
- else if (m_hasNegativeValues)
- zeroPosAdjustment = -2.0f;
+ GLfloat directionMultiplier = 2.0f;
+ GLfloat directionBase = 0.0f;
+ if (m_axisCacheY.reversed()) {
+ directionMultiplier = -2.0f;
+ directionBase = -2.0f;
+ }
+ zeroPosAdjustment = directionBase +
+ directionMultiplier * m_axisCacheY.min() / m_heightNormalizer;
+ zeroPosAdjustment = qBound(-2.0f, zeroPosAdjustment, 0.0f);
// Draw grid lines
if (m_cachedTheme->isGridEnabled()) {
glDisable(GL_DEPTH_TEST);
+#if !(defined QT_OPENGL_ES_2)
ShaderHelper *lineShader = m_backgroundShader;
+#else
+ ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES
+#endif
// Bind line shader
lineShader->bind();
// Set unchanging shader bindings
- QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
+ QVector4D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
lineShader->setUniformValue(lineShader->lightP(), lightPos);
lineShader->setUniformValue(lineShader->view(), viewMatrix);
lineShader->setUniformValue(lineShader->color(), lineColor);
@@ -352,20 +500,18 @@ void Bars3DRenderer::drawSlicedScene()
lineShader->setUniformValue(lineShader->lightS(), 0.0f);
lineShader->setUniformValue(lineShader->lightColor(), lightColor);
- GLfloat gridStep = (2.0f * m_axisCacheY.subSegmentStep()) / m_heightNormalizer;
- GLfloat gridPos = barPosYAdjustment;
- int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
- // Use the position of the bottom grid line as the base y position for bar labels
-
// Horizontal lines
if (m_axisCacheY.segmentCount() > 0) {
+ int gridLineCount = m_axisCacheY.gridLineCount();
+
QVector3D gridLineScale(scaleFactor, gridLineWidth, gridLineWidth);
bool noZero = true;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
+ GLfloat gridPos = m_axisCacheY.gridLinePosition(line) + gridAdjustment;
modelMatrix.translate(0.0f, gridPos, 0.0f);
modelMatrix.scale(gridLineScale);
itModelMatrix = modelMatrix;
@@ -378,14 +524,17 @@ void Bars3DRenderer::drawSlicedScene()
lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
// Draw the object
+#if !(defined QT_OPENGL_ES_2)
m_drawer->drawObject(lineShader, m_gridLineObj);
+#else
+ m_drawer->drawLine(lineShader);
+#endif
// Check if we have a line at zero position already
if (gridPos == (barPosYAdjustment + zeroPosAdjustment))
noZero = false;
-
- gridPos += gridStep;
}
+
// Draw a line at zero, if none exists
if (!m_noZeroInRange && noZero) {
QMatrix4x4 modelMatrix;
@@ -400,10 +549,15 @@ void Bars3DRenderer::drawSlicedScene()
itModelMatrix.inverted().transposed());
lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
lineShader->setUniformValue(lineShader->color(),
- Utils::vectorFromColor(m_cachedTheme->backgroundColor()));
+ Utils::vectorFromColor(
+ m_cachedTheme->labelTextColor()));
// Draw the object
+#if !(defined QT_OPENGL_ES_2)
m_drawer->drawObject(lineShader, m_gridLineObj);
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
@@ -417,24 +571,21 @@ void Bars3DRenderer::drawSlicedScene()
// Draw grid labels
int labelNbr = 0;
- int labelCount = m_axisCacheY.labels().size();
- gridStep = (2.0f * m_axisCacheY.segmentStep()) / m_heightNormalizer;
- gridPos = barPosYAdjustment;
- QVector3D backLabelRotation(0.0f, 0.0f, 0.0f);
+ int labelCount = m_axisCacheY.labelCount();
QVector3D labelTrans = QVector3D(scaleFactor + labelMargin, 0.0f, 0.0f);
for (int i = 0; i < labelCount; i++) {
if (m_axisCacheY.labelItems().size() > labelNbr) {
const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+ GLfloat gridPos = m_axisCacheY.labelPosition(i) + gridAdjustment;
labelTrans.setY(gridPos);
m_dummyBarRenderItem.setTranslation(labelTrans);
m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix,
- projectionMatrix, zeroVector, backLabelRotation, 0,
+ projectionMatrix, zeroVector, identityQuaternion, 0,
m_cachedSelectionMode, m_labelShader, m_labelObj,
- activeCamera, true, true, Drawer::LabelMid, Qt::AlignRight);
+ activeCamera, true, true, Drawer::LabelMid, Qt::AlignLeft);
}
labelNbr++;
- gridPos += gridStep;
}
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
@@ -470,37 +621,40 @@ void Bars3DRenderer::drawSlicedScene()
ShaderHelper *barShader = m_barShader;
barShader->bind();
- int currentSeriesIndex = -1;
Q3DTheme::ColorStyle previousColorStyle = Q3DTheme::ColorStyleUniform;
Q3DTheme::ColorStyle colorStyle = Q3DTheme::ColorStyleUniform;
ObjectHelper *barObj = 0;
- QVector3D highlightColor;
- QVector3D baseColor;
+ QVector4D highlightColor;
+ QVector4D baseColor;
GLuint highlightGradientTexture = 0;
GLuint baseGradientTexture = 0;
- const SeriesRenderCache *currentSeries = 0;
bool colorStyleIsUniform = true;
+ int firstVisualIndex = m_renderCacheList.size();
+ QVector<BarRenderSliceItem> *firstVisualSliceArray = 0;
+ BarRenderSliceItem *selectedItem = 0;
+
+ QQuaternion seriesRotation;
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()
+ && (baseCache == m_selectedSeriesCache
+ || m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries))) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ QVector<BarRenderSliceItem> &sliceArray = cache->sliceArray();
+ int sliceCount = sliceArray.size();
+ if (firstVisualIndex > cache->visualIndex()) {
+ firstVisualIndex = cache->visualIndex();
+ firstVisualSliceArray = &sliceArray;
+ }
- int sliceItemCount = m_sliceSelection.size();
- for (int bar = 0; bar < sliceItemCount; bar++) {
- const BarRenderSliceItem &item = m_sliceSelection.at(bar);
- if (!item.value())
- continue;
-
- QQuaternion seriesRotation;
-
- if (item.seriesIndex() != currentSeriesIndex) {
- currentSeriesIndex = item.seriesIndex();
- currentSeries = &(m_visibleSeriesList.at(currentSeriesIndex));
- barObj = currentSeries->object();
- colorStyle = currentSeries->colorStyle();
+ barObj = cache->object();
+ colorStyle = cache->colorStyle();
colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform);
if (colorStyleIsUniform) {
- highlightColor = currentSeries->singleHighlightColor();
- baseColor = currentSeries->baseColor();
+ highlightColor = cache->singleHighlightColor();
+ baseColor = cache->baseColor();
} else {
- highlightGradientTexture = currentSeries->singleHighlightGradientTexture();
- baseGradientTexture = currentSeries->baseGradientTexture();
+ highlightGradientTexture = cache->singleHighlightGradientTexture();
+ baseGradientTexture = cache->baseGradientTexture();
}
// Rebind shader if it has changed
@@ -510,7 +664,6 @@ void Bars3DRenderer::drawSlicedScene()
else
barShader = m_barGradientShader;
barShader->bind();
-
}
if (!colorStyleIsUniform && (previousColorStyle != colorStyle)
@@ -519,76 +672,88 @@ void Bars3DRenderer::drawSlicedScene()
}
previousColorStyle = colorStyle;
- seriesRotation = currentSeries->meshRotation();
- }
+ seriesRotation = cache->meshRotation();
+ bool selectedSeries = (cache == m_selectedSeriesCache);
+
+ for (int bar = 0; bar < sliceCount; bar++) {
+ BarRenderSliceItem &item = cache->sliceArray()[bar];
+ if (selectedSeries && itemMode && sliceGridLabels
+ && m_visualSelectedBarPos.x() == item.position().x()
+ && m_visualSelectedBarPos.y() == item.position().y()) {
+ selectedItem = &item;
+ }
+ if (!item.value())
+ continue;
- if (item.height() < 0)
- glCullFace(GL_FRONT);
- else
- glCullFace(GL_BACK);
+ if (item.height() < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
- QMatrix4x4 MVPMatrix;
- QMatrix4x4 modelMatrix;
- QMatrix4x4 itModelMatrix;
- QQuaternion barRotation = item.rotation();
- GLfloat barPosY = item.translation().y() + barPosYAdjustment - zeroPosAdjustment;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 itModelMatrix;
+ QQuaternion barRotation = item.rotation();
+ GLfloat barPosY = item.translation().y() + barPosYAdjustment - zeroPosAdjustment;
+
+ if (rowMode) {
+ barPosX = item.translation().x();
+ } else {
+ barPosX = -(item.translation().z()); // flip z; frontmost bar to the left
+ barRotation *= ninetyDegreeRotation;
+ }
- if (rowMode) {
- barPosX = item.translation().x();
- } else {
- barPosX = -(item.translation().z()); // flip z; frontmost bar to the left
- barRotation *= ninetyDegreeRotation;
- }
+ modelMatrix.translate(barPosX, barPosY, 0.0f);
+ modelMatrixScaler.setY(item.height());
- modelMatrix.translate(barPosX, barPosY, 0.0f);
- modelMatrixScaler.setY(item.height());
+ if (!seriesRotation.isIdentity())
+ barRotation *= seriesRotation;
- if (!seriesRotation.isIdentity())
- barRotation *= seriesRotation;
+ if (!barRotation.isIdentity()) {
+ modelMatrix.rotate(barRotation);
+ itModelMatrix.rotate(barRotation);
+ }
- if (!barRotation.isIdentity()) {
- modelMatrix.rotate(barRotation);
- itModelMatrix.rotate(barRotation);
- }
+ modelMatrix.scale(modelMatrixScaler);
+ itModelMatrix.scale(modelMatrixScaler);
- modelMatrix.scale(modelMatrixScaler);
- itModelMatrix.scale(modelMatrixScaler);
+ MVPMatrix = projectionViewMatrix * modelMatrix;
- MVPMatrix = projectionViewMatrix * modelMatrix;
+ QVector4D barColor;
+ GLuint gradientTexture = 0;
- QVector3D barColor;
- GLuint gradientTexture = 0;
+ if (itemMode && m_visualSelectedBarPos.x() == item.position().x()
+ && m_visualSelectedBarPos.y() == item.position().y()) {
+ if (colorStyleIsUniform)
+ barColor = highlightColor;
+ else
+ gradientTexture = highlightGradientTexture;
+ } else {
+ if (colorStyleIsUniform)
+ barColor = baseColor;
+ else
+ gradientTexture = baseGradientTexture;
+ }
- if (itemMode && m_visualSelectedBarPos.x() == item.position().x()
- && m_visualSelectedBarPos.y() == item.position().y()) {
- if (colorStyleIsUniform)
- barColor = highlightColor;
- else
- gradientTexture = highlightGradientTexture;
- } else {
- if (colorStyleIsUniform)
- barColor = baseColor;
- else
- gradientTexture = baseGradientTexture;
- }
+ if (item.height() != 0) {
+ // Set shader bindings
+ barShader->setUniformValue(barShader->model(), modelMatrix);
+ barShader->setUniformValue(barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ barShader->setUniformValue(barShader->MVP(), MVPMatrix);
+ if (colorStyleIsUniform) {
+ barShader->setUniformValue(barShader->color(), barColor);
+ } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
+ barShader->setUniformValue(barShader->gradientHeight(),
+ (qAbs(item.height()) / m_gradientFraction));
+ }
- if (item.height() != 0) {
- // Set shader bindings
- barShader->setUniformValue(barShader->model(), modelMatrix);
- barShader->setUniformValue(barShader->nModel(),
- itModelMatrix.inverted().transposed());
- barShader->setUniformValue(barShader->MVP(), MVPMatrix);
- if (colorStyleIsUniform) {
- barShader->setUniformValue(barShader->color(), barColor);
- } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
- barShader->setUniformValue(barShader->gradientHeight(),
- (qAbs(item.height()) / m_gradientFraction));
+ // Draw the object
+ m_drawer->drawObject(barShader,
+ barObj,
+ gradientTexture);
+ }
}
-
- // Draw the object
- m_drawer->drawObject(barShader,
- barObj,
- gradientTexture);
}
}
@@ -607,97 +772,111 @@ void Bars3DRenderer::drawSlicedScene()
// Draw labels for bars
QVector3D sliceValueRotation(0.0f, 0.0f, 90.0f);
QVector3D sliceLabelRotation(0.0f, 0.0f, -45.0f);
+ QQuaternion totalSliceValueRotation = Utils::calculateRotation(sliceValueRotation);
+ QQuaternion totalSliceLabelRotation = Utils::calculateRotation(sliceLabelRotation);
- int lastLabel = m_sliceCache->labelItems().size() - 1;
+ int labelCount = m_sliceCache->labelItems().size();
- for (int labelNo = 0; labelNo <= lastLabel; labelNo++) {
+ for (int labelNo = 0; labelNo < labelCount; labelNo++) {
// Get labels from first series only
- const BarRenderSliceItem &item = m_sliceSelection.at(labelNo);
+ const BarRenderSliceItem &item = firstVisualSliceArray->at(labelNo);
m_dummyBarRenderItem.setTranslation(QVector3D(item.translation().x(),
barLabelYPos,
item.translation().z()));
+
// Draw labels
m_drawer->drawLabel(m_dummyBarRenderItem, *m_sliceCache->labelItems().at(labelNo),
- viewMatrix, projectionMatrix, positionComp, sliceLabelRotation,
+ viewMatrix, projectionMatrix, positionComp, totalSliceLabelRotation,
0, m_cachedSelectionMode, m_labelShader,
m_labelObj, activeCamera, false, false, Drawer::LabelMid,
- Qt::AlignRight, true);
+ Qt::AlignmentFlag(Qt::AlignLeft | Qt::AlignTop), true);
}
- for (int col = 0; col < sliceItemCount; col++) {
- BarRenderSliceItem &item = m_sliceSelection[col];
-
- if (!sliceGridLabels) {
- // Draw values
- if (item.height() != 0.0f || (!m_noZeroInRange && item.value() == 0.0f)) {
- // Create label texture if we need it
- if (item.sliceLabel().isNull() || m_updateLabels) {
- item.setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(),
- item.value()));
- m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel());
- m_updateLabels = false;
- }
- Qt::AlignmentFlag alignment = (item.height() < 0) ? Qt::AlignBottom : Qt::AlignTop;
- Drawer::LabelPosition labelPos = (item.height() < 0) ? Drawer::LabelBelow : Drawer::LabelOver;
- m_dummyBarRenderItem.setTranslation(QVector3D(item.translation().x(),
- barPosYAdjustment - zeroPosAdjustment
- + item.height(),
- item.translation().z()));
-
- m_drawer->drawLabel(m_dummyBarRenderItem, item.sliceLabelItem(), viewMatrix,
- projectionMatrix, zeroVector, sliceValueRotation,
- item.height(), m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, false, false, labelPos,
- alignment, true);
- }
- } else {
- // Only draw value for selected item when grid labels are on
- if (itemMode && m_visualSelectedBarPos.x() == item.position().x()
- && m_visualSelectedBarPos.y() == item.position().y()
- && item.seriesIndex() == m_visualSelectedBarSeriesIndex) {
- // Create label texture if we need it
- if (item.sliceLabel().isNull() || m_updateLabels) {
- item.setSliceLabel(generateValueLabel(m_axisCacheY.labelFormat(),
- item.value()));
- m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel());
- m_updateLabels = false;
+ if (!sliceGridLabels) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ QVector<BarRenderSliceItem> &sliceArray = cache->sliceArray();
+ int sliceCount = sliceArray.size();
+ for (int col = 0; col < sliceCount; col++) {
+ BarRenderSliceItem &item = sliceArray[col];
+
+ // Draw values
+ if (item.height() != 0.0f || (!m_noZeroInRange && item.value() == 0.0f)) {
+ // Create label texture if we need it
+ if (item.sliceLabel().isNull() || m_updateLabels) {
+ QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
+ qreal(item.value()), m_axisCacheY.labelFormat());
+ item.setSliceLabel(valueLabelText);
+ m_drawer->generateLabelItem(item.sliceLabelItem(), item.sliceLabel());
+ m_updateLabels = false;
+ }
+ Qt::AlignmentFlag alignment =
+ (item.height() > 0) ? Qt::AlignLeft : Qt::AlignRight;
+ Drawer::LabelPosition labelPos =
+ (item.height() < 0) ? Drawer::LabelBelow : Drawer::LabelOver;
+ m_dummyBarRenderItem.setTranslation(QVector3D(item.translation().x(),
+ barPosYAdjustment
+ - zeroPosAdjustment
+ + item.height(),
+ item.translation().z()));
+
+ m_drawer->drawLabel(m_dummyBarRenderItem, item.sliceLabelItem(), viewMatrix,
+ projectionMatrix, zeroVector, totalSliceValueRotation,
+ item.height(), m_cachedSelectionMode, m_labelShader,
+ m_labelObj, activeCamera, false, false, labelPos,
+ alignment, true);
+ }
}
- Qt::AlignmentFlag alignment = (item.height() < 0) ? Qt::AlignBottom : Qt::AlignTop;
- Drawer::LabelPosition labelPos = (item.height() < 0) ? Drawer::LabelBelow : Drawer::LabelOver;
- m_dummyBarRenderItem.setTranslation(QVector3D(item.translation().x(),
- barPosYAdjustment - zeroPosAdjustment
- + item.height(),
- item.translation().z()));
-
- m_drawer->drawLabel(m_dummyBarRenderItem, item.sliceLabelItem(), viewMatrix,
- projectionMatrix, zeroVector, sliceValueRotation,
- item.height(), m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, false, false, labelPos,
- alignment, true);
}
}
+ } else if (selectedItem) {
+ // Only draw value for selected item when grid labels are on
+ // Create label texture if we need it
+ if (selectedItem->sliceLabel().isNull() || m_updateLabels) {
+ QString valueLabelText = m_axisCacheY.formatter()->stringForValue(
+ qreal(selectedItem->value()), m_axisCacheY.labelFormat());
+ selectedItem->setSliceLabel(valueLabelText);
+ m_drawer->generateLabelItem(selectedItem->sliceLabelItem(), selectedItem->sliceLabel());
+ m_updateLabels = false;
+ }
+ Qt::AlignmentFlag alignment = (selectedItem->height() > 0) ? Qt::AlignLeft : Qt::AlignRight;
+ Drawer::LabelPosition labelPos =
+ (selectedItem->height() < 0) ? Drawer::LabelBelow : Drawer::LabelOver;
+ m_dummyBarRenderItem.setTranslation(QVector3D(selectedItem->translation().x(),
+ barPosYAdjustment - zeroPosAdjustment
+ + selectedItem->height(),
+ selectedItem->translation().z()));
+
+ m_drawer->drawLabel(m_dummyBarRenderItem, selectedItem->sliceLabelItem(), viewMatrix,
+ projectionMatrix, zeroVector, totalSliceValueRotation,
+ selectedItem->height(), m_cachedSelectionMode, m_labelShader,
+ m_labelObj, activeCamera, false, false, labelPos,
+ alignment, true);
}
// Draw labels for axes
if (rowMode) {
if (m_sliceTitleItem) {
m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix,
- positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, false, false, Drawer::LabelTop,
- Qt::AlignCenter, true);
+ positionComp, identityQuaternion, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, activeCamera, false, false,
+ Drawer::LabelTop, Qt::AlignCenter, true);
}
m_drawer->drawLabel(*dummyItem, m_axisCacheX.titleItem(), viewMatrix, projectionMatrix,
- positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, false, false, Drawer::LabelBottom,
- Qt::AlignCenter, true);
+ positionComp, identityQuaternion, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, activeCamera, false, false,
+ Drawer::LabelBottom, Qt::AlignCenter, true);
} else {
m_drawer->drawLabel(*dummyItem, m_axisCacheZ.titleItem(), viewMatrix, projectionMatrix,
- positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader,
+ positionComp, identityQuaternion, 0, m_cachedSelectionMode,
+ m_labelShader,
m_labelObj, activeCamera, false, false, Drawer::LabelBottom,
Qt::AlignCenter, true);
if (m_sliceTitleItem) {
m_drawer->drawLabel(*dummyItem, sliceSelectionLabel, viewMatrix, projectionMatrix,
- positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader,
+ positionComp, identityQuaternion, 0, m_cachedSelectionMode,
+ m_labelShader,
m_labelObj, activeCamera, false, false, Drawer::LabelTop,
Qt::AlignCenter, true);
}
@@ -706,9 +885,9 @@ void Bars3DRenderer::drawSlicedScene()
QVector3D labelTrans = QVector3D(-scaleFactor - labelMargin, 0.2f, 0.0f); // y = 0.2 for row/column labels (see barPosYAdjustment)
m_dummyBarRenderItem.setTranslation(labelTrans);
m_drawer->drawLabel(m_dummyBarRenderItem, m_axisCacheY.titleItem(), viewMatrix,
- projectionMatrix, zeroVector, QVector3D(0.0f, 0.0f, 90.0f), 0,
+ projectionMatrix, zeroVector, totalSliceValueRotation, 0,
m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera,
- false, false, Drawer::LabelMid, Qt::AlignHCenter);
+ false, false, Drawer::LabelMid, Qt::AlignBottom);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
@@ -733,9 +912,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
GLfloat colPos = 0;
GLfloat rowPos = 0;
- QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
-
- int seriesCount = m_visibleSeriesList.size();
+ QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
const Q3DCamera *activeCamera = m_cachedScene->activeCamera();
@@ -748,7 +925,14 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
QMatrix4x4 projectionMatrix;
GLfloat viewPortRatio = (GLfloat)m_primarySubViewport.width()
/ (GLfloat)m_primarySubViewport.height();
- projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
+ if (m_useOrthoProjection) {
+ GLfloat orthoRatio = 2.0f;
+ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
+ -orthoRatio, orthoRatio,
+ 0.0f, 100.0f);
+ } else {
+ projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
+ }
// Get the view matrix
QMatrix4x4 viewMatrix = activeCamera->d_ptr->viewMatrix();
@@ -808,6 +992,11 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
bool rowMode = m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow);
+ GLfloat rowScaleFactor = m_rowWidth / m_scaleFactor;
+ GLfloat columnScaleFactor = m_columnDepth / m_scaleFactor;
+
+ BarRenderItem *selectedBar(0);
+
#if !defined(QT_OPENGL_ES_2)
if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
// Render scene into a depth texture for using with shadow mapping
@@ -837,72 +1026,80 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
// Draw bars to depth buffer
QVector3D shadowScaler(m_scaleX * m_seriesScaleX * 0.9f, 0.0f,
m_scaleZ * m_seriesScaleZ * 0.9f);
- float seriesPos = m_seriesStart;
- for (int series = 0; series < seriesCount; series++) {
- ObjectHelper *barObj = m_visibleSeriesList.at(series).object();
- QQuaternion seriesRotation(m_visibleSeriesList.at(series).meshRotation());
- for (int row = startRow; row != stopRow; row += stepRow) {
- for (int bar = startBar; bar != stopBar; bar += stepBar) {
- GLfloat shadowOffset = 0.0f;
- const BarRenderItem &item = m_renderingArrays.at(series).at(row).at(bar);
- if (!item.value())
- continue;
- // Set front face culling for negative valued bars and back face culling for
- // positive valued bars to remove peter-panning issues
- if (item.height() > 0) {
- glCullFace(GL_BACK);
- if (m_yFlipped)
- shadowOffset = 0.015f;
- } else {
- glCullFace(GL_FRONT);
- if (!m_yFlipped)
- shadowOffset = -0.015f;
- }
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ float seriesPos = m_seriesStart + m_seriesStep * cache->visualIndex() + 0.5f;
+ ObjectHelper *barObj = cache->object();
+ QQuaternion seriesRotation(cache->meshRotation());
+ const BarRenderItemArray &renderArray = cache->renderArray();
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ const BarRenderItemRow &renderRow = renderArray.at(row);
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ const BarRenderItem &item = renderRow.at(bar);
+ if (!item.value())
+ continue;
+ GLfloat shadowOffset = 0.0f;
+ // Set front face culling for negative valued bars and back face culling
+ // for positive valued bars to remove peter-panning issues
+ if (item.height() > 0) {
+ glCullFace(GL_BACK);
+ if (m_yFlipped)
+ shadowOffset = 0.015f;
+ } else {
+ glCullFace(GL_FRONT);
+ if (!m_yFlipped)
+ shadowOffset = -0.015f;
+ }
- QMatrix4x4 modelMatrix;
- QMatrix4x4 MVPMatrix;
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
- colPos = (bar + 0.5f + seriesPos) * (m_cachedBarSpacing.width());
- rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
+ colPos = (bar + seriesPos) * (m_cachedBarSpacing.width());
+ rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
- // Draw shadows for bars "on the other side" a bit off ground to avoid seeing
- // shadows through the ground
- modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
- item.height() + shadowOffset,
- (m_columnDepth - rowPos) / m_scaleFactor);
- // Scale the bars down in X and Z to reduce self-shadowing issues
- shadowScaler.setY(item.height());
- if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
- modelMatrix.rotate(seriesRotation * item.rotation());
- modelMatrix.scale(shadowScaler);
+ // Draw shadows for bars "on the other side" a bit off ground to avoid
+ // seeing shadows through the ground
+ modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
+ item.height() + shadowOffset,
+ (m_columnDepth - rowPos) / m_scaleFactor);
+ // Scale the bars down in X and Z to reduce self-shadowing issues
+ shadowScaler.setY(item.height());
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
+ modelMatrix.rotate(seriesRotation * item.rotation());
+ modelMatrix.scale(shadowScaler);
- MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
- m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
+ m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
- // 1st attribute buffer : vertices
- glEnableVertexAttribArray(m_depthShader->posAtt());
- glBindBuffer(GL_ARRAY_BUFFER, barObj->vertexBuf());
- glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
- (void *)0);
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, barObj->vertexBuf());
+ glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
- // Index buffer
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, barObj->elementBuf());
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, barObj->elementBuf());
- // Draw the triangles
- glDrawElements(GL_TRIANGLES, barObj->indexCount(), GL_UNSIGNED_SHORT,
- (void *)0);
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, barObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
- // Free buffers
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDisableVertexAttribArray(m_depthShader->posAtt());
+ glDisableVertexAttribArray(m_depthShader->posAtt());
+ }
}
}
- seriesPos += m_seriesStep;
}
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
// Disable drawing to depth framebuffer (= enable drawing to screen)
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
@@ -919,7 +1116,8 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
// Skip selection mode drawing if we're slicing or have no selection mode
if (!m_cachedIsSlicingActivated && m_cachedSelectionMode > QAbstract3DGraph::SelectionNone
- && m_selectionState == SelectOnScene && seriesCount > 0) {
+ && m_selectionState == SelectOnScene
+ && (m_visibleSeriesCount > 0 || !m_customRenderCache.isEmpty())) {
// Bind selection shader
m_selectionShader->bind();
@@ -933,71 +1131,65 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white (= selectionSkipColor)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
- float seriesPos = m_seriesStart;
- for (int series = 0; series < seriesCount; series++) {
- ObjectHelper *barObj = m_visibleSeriesList.at(series).object();
- QQuaternion seriesRotation(m_visibleSeriesList.at(series).meshRotation());
- for (int row = startRow; row != stopRow; row += stepRow) {
- for (int bar = startBar; bar != stopBar; bar += stepBar) {
- const BarRenderItem &item = m_renderingArrays.at(series).at(row).at(bar);
- if (!item.value())
- continue;
-
- if (item.height() < 0)
- glCullFace(GL_FRONT);
- else
- glCullFace(GL_BACK);
-
- QMatrix4x4 modelMatrix;
- QMatrix4x4 MVPMatrix;
-
- colPos = (bar + 0.5f + seriesPos) * (m_cachedBarSpacing.width());
- rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
-
- modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
- item.height(),
- (m_columnDepth - rowPos) / m_scaleFactor);
- if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
- modelMatrix.rotate(seriesRotation * item.rotation());
- modelMatrix.scale(QVector3D(m_scaleX * m_seriesScaleX,
- item.height(),
- m_scaleZ * m_seriesScaleZ));
-
- MVPMatrix = projectionViewMatrix * modelMatrix;
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ float seriesPos = m_seriesStart + m_seriesStep * cache->visualIndex() + 0.5f;
+ ObjectHelper *barObj = cache->object();
+ QQuaternion seriesRotation(cache->meshRotation());
+ const BarRenderItemArray &renderArray = cache->renderArray();
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ const BarRenderItemRow &renderRow = renderArray.at(row);
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ const BarRenderItem &item = renderRow.at(bar);
+ if (!item.value())
+ continue;
+
+ if (item.height() < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
- QVector3D barColor = QVector3D(GLfloat(row) / 255.0f,
- GLfloat(bar) / 255.0f,
- GLfloat(series) / 255.0f);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
- m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix);
- m_selectionShader->setUniformValue(m_selectionShader->color(), barColor);
+ colPos = (bar + seriesPos) * (m_cachedBarSpacing.width());
+ rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
- // 1st attribute buffer : vertices
- glEnableVertexAttribArray(m_selectionShader->posAtt());
- glBindBuffer(GL_ARRAY_BUFFER, barObj->vertexBuf());
- glVertexAttribPointer(m_selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
- (void *)0);
+ modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
+ item.height(),
+ (m_columnDepth - rowPos) / m_scaleFactor);
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
+ modelMatrix.rotate(seriesRotation * item.rotation());
+ modelMatrix.scale(QVector3D(m_scaleX * m_seriesScaleX,
+ item.height(),
+ m_scaleZ * m_seriesScaleZ));
- // Index buffer
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, barObj->elementBuf());
+ MVPMatrix = projectionViewMatrix * modelMatrix;
- // Draw the triangles
- glDrawElements(GL_TRIANGLES, barObj->indexCount(), GL_UNSIGNED_SHORT,
- (void *)0);
+ QVector4D barColor = QVector4D(GLfloat(row) / 255.0f,
+ GLfloat(bar) / 255.0f,
+ GLfloat(cache->visualIndex()) / 255.0f,
+ itemAlpha);
- // Free buffers
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+ m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix);
+ m_selectionShader->setUniformValue(m_selectionShader->color(), barColor);
- glDisableVertexAttribArray(m_selectionShader->posAtt());
+ m_drawer->drawSelectionObject(m_selectionShader, barObj);
+ }
}
}
- seriesPos += m_seriesStep;
}
+ glCullFace(GL_BACK);
+ Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+ drawLabels(true, activeCamera, viewMatrix, projectionMatrix, rowScaleFactor,
+ columnScaleFactor);
glEnable(GL_DITHER);
// Read color under cursor
- QVector3D clickedColor = Utils::getSelection(m_inputPosition,
+ QVector4D clickedColor = Utils::getSelection(m_inputPosition,
m_viewport.height());
m_clickedPosition = selectionColorToArrayPosition(clickedColor);
m_clickedSeries = selectionColorToSeries(clickedColor);
@@ -1018,18 +1210,9 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
ShaderHelper *barShader = 0;
GLuint gradientTexture = 0;
Q3DTheme::ColorStyle previousColorStyle = Q3DTheme::ColorStyleUniform;
- bool haveUniformColorSeries = false;
- bool haveGradientSeries = false;
-
- for (int i = 0; i < seriesCount; i++) {
- if (m_visibleSeriesList.at(i).colorStyle() == Q3DTheme::ColorStyleUniform)
- haveUniformColorSeries = true;
- else
- haveGradientSeries = true;
- }
// Set unchanging shader bindings
- if (haveGradientSeries) {
+ if (m_haveGradientSeries) {
m_barGradientShader->bind();
m_barGradientShader->setUniformValue(m_barGradientShader->lightP(), lightPos);
m_barGradientShader->setUniformValue(m_barGradientShader->view(), viewMatrix);
@@ -1039,7 +1222,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
m_barGradientShader->setUniformValue(m_barGradientShader->lightColor(), lightColor);
}
- if (haveUniformColorSeries) {
+ if (m_haveUniformColorSeries) {
m_barShader->bind();
m_barShader->setUniformValue(m_barShader->lightP(), lightPos);
m_barShader->setUniformValue(m_barShader->view(), viewMatrix);
@@ -1052,17 +1235,13 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
previousColorStyle = Q3DTheme::ColorStyleRangeGradient;
}
+ int sliceReserveAmount = 0;
if (m_selectionDirty && m_cachedIsSlicingActivated) {
// Slice doesn't own its items, no need to delete them - just clear
- m_sliceSelection.clear();
- int reserveAmount;
if (rowMode)
- reserveAmount = m_cachedColumnCount;
+ sliceReserveAmount = m_cachedColumnCount;
else
- reserveAmount = m_cachedRowCount;
- if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries))
- reserveAmount *= m_visibleSeriesList.size();
- m_sliceSelection.resize(reserveAmount);
+ sliceReserveAmount = m_cachedRowCount;
// Set slice cache, i.e. axis cache from where slice labels are taken
if (rowMode)
@@ -1073,259 +1252,253 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
}
// Draw bars
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(0.5f, 1.0f);
GLfloat adjustedLightStrength = m_cachedTheme->lightStrength() / 10.0f;
GLfloat adjustedHighlightStrength = m_cachedTheme->highlightLightStrength() / 10.0f;
bool barSelectionFound = false;
- BarRenderItem *selectedBar(0);
- QVector3D baseColor;
- QVector3D barColor;
+ QVector4D baseColor;
+ QVector4D barColor;
QVector3D modelScaler(m_scaleX * m_seriesScaleX, 0.0f, m_scaleZ * m_seriesScaleZ);
- bool somethingSelected = (m_visualSelectedBarPos != Bars3DController::invalidSelectionPosition());
- float seriesPos = m_seriesStart;
- for (int series = 0; series < seriesCount; series++) {
- const SeriesRenderCache &currentSeries = m_visibleSeriesList.at(series);
- QQuaternion seriesRotation(currentSeries.meshRotation());
- ObjectHelper *barObj = currentSeries.object();
- Q3DTheme::ColorStyle colorStyle = currentSeries.colorStyle();
- bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform);
-
- // Rebind shader if it has changed
- if (colorStyleIsUniform != (previousColorStyle == Q3DTheme::ColorStyleUniform)) {
- if (colorStyleIsUniform)
- barShader = m_barShader;
- else
- barShader = m_barGradientShader;
- barShader->bind();
- }
+ bool somethingSelected =
+ (m_visualSelectedBarPos != Bars3DController::invalidSelectionPosition());
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ float seriesPos = m_seriesStart + m_seriesStep * cache->visualIndex() + 0.5f;
+ ObjectHelper *barObj = cache->object();
+ QQuaternion seriesRotation(cache->meshRotation());
+ Q3DTheme::ColorStyle colorStyle = cache->colorStyle();
+ BarRenderItemArray &renderArray = cache->renderArray();
+ bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform);
+ if (sliceReserveAmount)
+ cache->sliceArray().resize(sliceReserveAmount);
- if (colorStyleIsUniform) {
- baseColor = currentSeries.baseColor();
- } else if ((previousColorStyle != colorStyle)
- && (colorStyle == Q3DTheme::ColorStyleObjectGradient)) {
- m_barGradientShader->setUniformValue(m_barGradientShader->gradientHeight(), 0.5f);
- }
+ // Rebind shader if it has changed
+ if (colorStyleIsUniform != (previousColorStyle == Q3DTheme::ColorStyleUniform)) {
+ if (colorStyleIsUniform)
+ barShader = m_barShader;
+ else
+ barShader = m_barGradientShader;
+ barShader->bind();
+ }
- // Always use base color when no selection mode
- if (m_cachedSelectionMode == QAbstract3DGraph::SelectionNone) {
- if (colorStyleIsUniform)
- barColor = baseColor;
- else
- gradientTexture = currentSeries.baseGradientTexture();
- }
+ if (colorStyleIsUniform) {
+ baseColor = cache->baseColor();
+ } else if ((previousColorStyle != colorStyle)
+ && (colorStyle == Q3DTheme::ColorStyleObjectGradient)) {
+ m_barGradientShader->setUniformValue(m_barGradientShader->gradientHeight(), 0.5f);
+ }
- previousColorStyle = colorStyle;
- int sliceSeriesAdjust = 0;
- if (m_selectionDirty && m_cachedIsSlicingActivated) {
- int seriesMultiplier = 0;
- if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries))
- seriesMultiplier = series;
- if (rowMode)
- sliceSeriesAdjust = seriesMultiplier * m_cachedColumnCount;
- else
- sliceSeriesAdjust = seriesMultiplier * m_cachedRowCount;
- }
+ // Always use base color when no selection mode
+ if (m_cachedSelectionMode == QAbstract3DGraph::SelectionNone) {
+ if (colorStyleIsUniform)
+ barColor = baseColor;
+ else
+ gradientTexture = cache->baseGradientTexture();
+ }
- for (int row = startRow; row != stopRow; row += stepRow) {
- for (int bar = startBar; bar != stopBar; bar += stepBar) {
- BarRenderItem &item = m_renderingArrays[series][row][bar];
+ previousColorStyle = colorStyle;
- if (item.height() < 0)
- glCullFace(GL_FRONT);
- else
- glCullFace(GL_BACK);
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ BarRenderItemRow &renderRow = renderArray[row];
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ BarRenderItem &item = renderRow[bar];
+ if (item.height() < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
- QMatrix4x4 modelMatrix;
- QMatrix4x4 itModelMatrix;
- QMatrix4x4 MVPMatrix;
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 itModelMatrix;
+ QMatrix4x4 MVPMatrix;
- colPos = (bar + 0.5f + seriesPos) * (m_cachedBarSpacing.width());
- rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
-
- modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
- item.height(),
- (m_columnDepth - rowPos) / m_scaleFactor);
- modelScaler.setY(item.height());
- if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) {
- QQuaternion totalRotation = seriesRotation * item.rotation();
- modelMatrix.rotate(totalRotation);
- itModelMatrix.rotate(totalRotation);
- }
- modelMatrix.scale(modelScaler);
- itModelMatrix.scale(modelScaler);
+ colPos = (bar + seriesPos) * (m_cachedBarSpacing.width());
+ rowPos = (row + 0.5f) * (m_cachedBarSpacing.height());
+
+ modelMatrix.translate((colPos - m_rowWidth) / m_scaleFactor,
+ item.height(),
+ (m_columnDepth - rowPos) / m_scaleFactor);
+ modelScaler.setY(item.height());
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) {
+ QQuaternion totalRotation = seriesRotation * item.rotation();
+ modelMatrix.rotate(totalRotation);
+ itModelMatrix.rotate(totalRotation);
+ }
+ modelMatrix.scale(modelScaler);
+ itModelMatrix.scale(modelScaler);
#ifdef SHOW_DEPTH_TEXTURE_SCENE
- MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
#else
- MVPMatrix = projectionViewMatrix * modelMatrix;
+ MVPMatrix = projectionViewMatrix * modelMatrix;
#endif
- GLfloat lightStrength = m_cachedTheme->lightStrength();
- GLfloat shadowLightStrength = adjustedLightStrength;
-
- if (m_cachedSelectionMode > QAbstract3DGraph::SelectionNone) {
- Bars3DController::SelectionType selectionType = Bars3DController::SelectionNone;
- if (somethingSelected)
- selectionType = isSelected(row, bar, series);
-
- switch (selectionType) {
- case Bars3DController::SelectionItem: {
- if (colorStyleIsUniform)
- barColor = currentSeries.singleHighlightColor();
- else
- gradientTexture = currentSeries.singleHighlightGradientTexture();
-
- lightStrength = m_cachedTheme->highlightLightStrength();
- shadowLightStrength = adjustedHighlightStrength;
- // Insert position data into render item. We have no ownership, don't delete the previous one
- if (!m_cachedIsSlicingActivated
- && m_visualSelectedBarSeriesIndex == series) {
- selectedBar = &item;
- selectedBar->setPosition(QPoint(row, bar));
- item.setTranslation(modelMatrix.column(3).toVector3D());
- barSelectionFound = true;
- }
- if (m_selectionDirty && m_cachedIsSlicingActivated) {
- QVector3D translation = modelMatrix.column(3).toVector3D();
- if (m_cachedSelectionMode & QAbstract3DGraph::SelectionColumn
- && seriesCount > 1) {
- translation.setZ((m_columnDepth - ((row + 0.5f + seriesPos)
- * (m_cachedBarSpacing.height())))
- / m_scaleFactor);
- }
- item.setTranslation(translation);
- item.setPosition(QPoint(row, bar));
- item.setSeriesIndex(series);
- if (rowMode)
- m_sliceSelection[sliceSeriesAdjust + bar].setItem(item);
+ GLfloat lightStrength = m_cachedTheme->lightStrength();
+ GLfloat shadowLightStrength = adjustedLightStrength;
+
+ if (m_cachedSelectionMode > QAbstract3DGraph::SelectionNone) {
+ Bars3DController::SelectionType selectionType =
+ Bars3DController::SelectionNone;
+ if (somethingSelected)
+ selectionType = isSelected(row, bar, cache);
+
+ switch (selectionType) {
+ case Bars3DController::SelectionItem: {
+ if (colorStyleIsUniform)
+ barColor = cache->singleHighlightColor();
else
- m_sliceSelection[sliceSeriesAdjust + row].setItem(item);
- }
- break;
- }
- case Bars3DController::SelectionRow: {
- // Current bar is on the same row as the selected bar
- if (colorStyleIsUniform)
- barColor = currentSeries.multiHighlightColor();
- else
- gradientTexture = currentSeries.multiHighlightGradientTexture();
-
- lightStrength = m_cachedTheme->highlightLightStrength();
- shadowLightStrength = adjustedHighlightStrength;
- if (m_cachedIsSlicingActivated) {
- item.setTranslation(modelMatrix.column(3).toVector3D());
- item.setPosition(QPoint(row, bar));
- if (m_selectionDirty) {
- item.setSeriesIndex(series);
- if (!m_sliceTitleItem && m_axisCacheZ.labelItems().size() > row)
- m_sliceTitleItem = m_axisCacheZ.labelItems().at(row);
- m_sliceSelection[sliceSeriesAdjust + bar].setItem(item);
+ gradientTexture = cache->singleHighlightGradientTexture();
+
+ lightStrength = m_cachedTheme->highlightLightStrength();
+ shadowLightStrength = adjustedHighlightStrength;
+ // Insert position data into render item
+ // We have no ownership, don't delete the previous one
+ if (!m_cachedIsSlicingActivated
+ && m_selectedSeriesCache == cache) {
+ selectedBar = &item;
+ selectedBar->setPosition(QPoint(row, bar));
+ item.setTranslation(modelMatrix.column(3).toVector3D());
+ barSelectionFound = true;
+ }
+ if (m_selectionDirty && m_cachedIsSlicingActivated) {
+ QVector3D translation = modelMatrix.column(3).toVector3D();
+ if (m_cachedSelectionMode & QAbstract3DGraph::SelectionColumn
+ && m_visibleSeriesCount > 1) {
+ translation.setZ((m_columnDepth
+ - ((row + seriesPos)
+ * (m_cachedBarSpacing.height())))
+ / m_scaleFactor);
+ }
+ item.setTranslation(translation);
+ item.setPosition(QPoint(row, bar));
+ if (rowMode)
+ cache->sliceArray()[bar].setItem(item);
+ else
+ cache->sliceArray()[row].setItem(item);
}
+ break;
}
- break;
- }
- case Bars3DController::SelectionColumn: {
- // Current bar is on the same column as the selected bar
- if (colorStyleIsUniform)
- barColor = currentSeries.multiHighlightColor();
- else
- gradientTexture = currentSeries.multiHighlightGradientTexture();
-
- lightStrength = m_cachedTheme->highlightLightStrength();
- shadowLightStrength = adjustedHighlightStrength;
- if (m_cachedIsSlicingActivated) {
- QVector3D translation = modelMatrix.column(3).toVector3D();
- if (seriesCount > 1) {
- translation.setZ((m_columnDepth - ((row + 0.5f + seriesPos)
- * (m_cachedBarSpacing.height())))
- / m_scaleFactor);
+ case Bars3DController::SelectionRow: {
+ // Current bar is on the same row as the selected bar
+ if (colorStyleIsUniform)
+ barColor = cache->multiHighlightColor();
+ else
+ gradientTexture = cache->multiHighlightGradientTexture();
+
+ lightStrength = m_cachedTheme->highlightLightStrength();
+ shadowLightStrength = adjustedHighlightStrength;
+ if (m_cachedIsSlicingActivated) {
+ item.setTranslation(modelMatrix.column(3).toVector3D());
+ item.setPosition(QPoint(row, bar));
+ if (m_selectionDirty) {
+ if (!m_sliceTitleItem && m_axisCacheZ.labelItems().size() > row)
+ m_sliceTitleItem = m_axisCacheZ.labelItems().at(row);
+ cache->sliceArray()[bar].setItem(item);
+ }
}
- item.setTranslation(translation);
- item.setPosition(QPoint(row, bar));
- if (m_selectionDirty) {
- item.setSeriesIndex(series);
- if (!m_sliceTitleItem && m_axisCacheX.labelItems().size() > bar)
- m_sliceTitleItem = m_axisCacheX.labelItems().at(bar);
- m_sliceSelection[sliceSeriesAdjust + row].setItem(item);
+ break;
+ }
+ case Bars3DController::SelectionColumn: {
+ // Current bar is on the same column as the selected bar
+ if (colorStyleIsUniform)
+ barColor = cache->multiHighlightColor();
+ else
+ gradientTexture = cache->multiHighlightGradientTexture();
+
+ lightStrength = m_cachedTheme->highlightLightStrength();
+ shadowLightStrength = adjustedHighlightStrength;
+ if (m_cachedIsSlicingActivated) {
+ QVector3D translation = modelMatrix.column(3).toVector3D();
+ if (m_visibleSeriesCount > 1) {
+ translation.setZ((m_columnDepth
+ - ((row + seriesPos)
+ * (m_cachedBarSpacing.height())))
+ / m_scaleFactor);
+ }
+ item.setTranslation(translation);
+ item.setPosition(QPoint(row, bar));
+ if (m_selectionDirty) {
+ if (!m_sliceTitleItem && m_axisCacheX.labelItems().size() > bar)
+ m_sliceTitleItem = m_axisCacheX.labelItems().at(bar);
+ cache->sliceArray()[row].setItem(item);
+ }
}
+ break;
+ }
+ case Bars3DController::SelectionNone: {
+ // Current bar is not selected, nor on a row or column
+ if (colorStyleIsUniform)
+ barColor = baseColor;
+ else
+ gradientTexture = cache->baseGradientTexture();
+ break;
+ }
}
- break;
- }
- case Bars3DController::SelectionNone: {
- // Current bar is not selected, nor on a row or column
- if (colorStyleIsUniform)
- barColor = baseColor;
- else
- gradientTexture = currentSeries.baseGradientTexture();
- break;
- }
}
- }
- // Skip drawing of 0-height bars
- if (item.height() != 0) {
- // Set shader bindings
- barShader->setUniformValue(barShader->model(), modelMatrix);
- barShader->setUniformValue(barShader->nModel(),
- itModelMatrix.transposed().inverted());
- barShader->setUniformValue(barShader->MVP(), MVPMatrix);
- if (colorStyleIsUniform) {
- barShader->setUniformValue(barShader->color(), barColor);
- } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
- barShader->setUniformValue(barShader->gradientHeight(),
- qAbs(item.height()) / m_gradientFraction);
- }
+ // Skip drawing of 0-height bars
+ if (item.height() != 0) {
+ // Set shader bindings
+ barShader->setUniformValue(barShader->model(), modelMatrix);
+ barShader->setUniformValue(barShader->nModel(),
+ itModelMatrix.transposed().inverted());
+ barShader->setUniformValue(barShader->MVP(), MVPMatrix);
+ if (colorStyleIsUniform) {
+ barShader->setUniformValue(barShader->color(), barColor);
+ } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
+ barShader->setUniformValue(barShader->gradientHeight(),
+ qAbs(item.height()) / m_gradientFraction);
+ }
#if !defined(QT_OPENGL_ES_2)
- if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
- // Set shadow shader bindings
- QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
- barShader->setUniformValue(barShader->shadowQ(), m_shadowQualityToShader);
- barShader->setUniformValue(barShader->depth(), depthMVPMatrix);
- barShader->setUniformValue(barShader->lightS(), shadowLightStrength);
- barShader->setUniformValue(barShader->lightColor(), lightColor);
-
- // Draw the object
- m_drawer->drawObject(barShader, barObj, gradientTexture, m_depthTexture);
- } else
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ // Set shadow shader bindings
+ QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ barShader->setUniformValue(barShader->shadowQ(),
+ m_shadowQualityToShader);
+ barShader->setUniformValue(barShader->depth(), depthMVPMatrix);
+ barShader->setUniformValue(barShader->lightS(), shadowLightStrength);
+ barShader->setUniformValue(barShader->lightColor(), lightColor);
+
+ // Draw the object
+ m_drawer->drawObject(barShader, barObj, gradientTexture,
+ m_depthTexture);
+ } else
#else
- Q_UNUSED(shadowLightStrength);
+ Q_UNUSED(shadowLightStrength);
#endif
- {
- // Set shadowless shader bindings
- barShader->setUniformValue(barShader->lightS(), lightStrength);
+ {
+ // Set shadowless shader bindings
+ barShader->setUniformValue(barShader->lightS(), lightStrength);
- // Draw the object
- m_drawer->drawObject(barShader, barObj, gradientTexture);
+ // Draw the object
+ m_drawer->drawObject(barShader, barObj, gradientTexture);
+ }
}
}
}
}
- seriesPos += m_seriesStep;
}
- // Bind background shader
- m_backgroundShader->bind();
+ glDisable(GL_POLYGON_OFFSET_FILL);
// Reset culling
glCullFace(GL_BACK);
- // Draw background
- GLfloat rowScaleFactor = m_rowWidth / m_scaleFactor;
- GLfloat columnScaleFactor = m_columnDepth / m_scaleFactor;
+ // Bind background shader
+ m_backgroundShader->bind();
+ // Draw background
if (m_cachedTheme->isBackgroundEnabled() && m_backgroundObj) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
QVector3D backgroundScaler(rowScaleFactor, 1.0f, columnScaleFactor);
- if (m_hasNegativeValues) {
- backgroundScaler.setY(0.5f);
- modelMatrix.translate(0.0f, m_negativeBackgroundAdjustment, 0.0f);
- } else {
- modelMatrix.translate(0.0f, 1.0f, 0.0f);
- }
+ modelMatrix.translate(0.0f, m_backgroundAdjustment, 0.0f);
+
modelMatrix.scale(backgroundScaler);
itModelMatrix.scale(backgroundScaler);
modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f);
@@ -1336,7 +1509,7 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
#else
MVPMatrix = projectionViewMatrix * modelMatrix;
#endif
- QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor());
+ QVector4D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor());
// Set shader bindings
m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos);
@@ -1373,44 +1546,42 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
m_drawer->drawObject(m_backgroundShader, m_backgroundObj);
}
- // Draw floor for graph with negatives
- if (m_hasNegativeValues) {
- modelMatrix = QMatrix4x4();
- itModelMatrix = QMatrix4x4();
+ // Draw floor
+ modelMatrix = QMatrix4x4();
+ itModelMatrix = QMatrix4x4();
- modelMatrix.scale(backgroundScaler);
+ modelMatrix.scale(backgroundScaler);
- if (m_yFlipped)
- modelMatrix.rotate(90.0f, 1.0f, 0.0f, 0.0f);
- else
- modelMatrix.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
+ if (m_yFlipped)
+ modelMatrix.rotate(90.0f, 1.0f, 0.0f, 0.0f);
+ else
+ modelMatrix.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
- itModelMatrix = modelMatrix;
+ itModelMatrix = modelMatrix;
#ifdef SHOW_DEPTH_TEXTURE_SCENE
- MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
#else
- MVPMatrix = projectionViewMatrix * modelMatrix;
+ MVPMatrix = projectionViewMatrix * modelMatrix;
#endif
- // Set changed shader bindings
- m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix);
- m_backgroundShader->setUniformValue(m_backgroundShader->nModel(),
- itModelMatrix.inverted().transposed());
- m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix);
+ // Set changed shader bindings
+ m_backgroundShader->setUniformValue(m_backgroundShader->model(), modelMatrix);
+ m_backgroundShader->setUniformValue(m_backgroundShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ m_backgroundShader->setUniformValue(m_backgroundShader->MVP(), MVPMatrix);
#if !defined(QT_OPENGL_ES_2)
- if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
- // Set shadow shader bindings
- QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
- m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix);
- // Draw the object
- m_drawer->drawObject(m_backgroundShader, m_gridLineObj, 0, m_depthTexture);
- } else
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ // Set shadow shader bindings
+ QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ m_backgroundShader->setUniformValue(m_backgroundShader->depth(), depthMVPMatrix);
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_gridLineObj, 0, m_depthTexture);
+ } else
#endif
- {
- // Draw the object
- m_drawer->drawObject(m_backgroundShader, m_gridLineObj);
- }
+ {
+ // Draw the object
+ m_drawer->drawObject(m_backgroundShader, m_gridLineObj);
}
}
@@ -1418,15 +1589,19 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
glDisable(GL_TEXTURE_2D);
// Draw grid lines
- if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) {
+ if (m_cachedTheme->isGridEnabled()) {
+#if !(defined QT_OPENGL_ES_2)
ShaderHelper *lineShader = m_backgroundShader;
+#else
+ ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES
+#endif
QQuaternion lineRotation;
// Bind bar shader
lineShader->bind();
// Set unchanging shader bindings
- QVector3D barColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
+ QVector4D barColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
lineShader->setUniformValue(lineShader->lightP(), lightPos);
lineShader->setUniformValue(lineShader->view(), viewMatrix);
lineShader->setUniformValue(lineShader->color(), barColor);
@@ -1446,11 +1621,9 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
m_cachedTheme->lightStrength() / 2.5f);
}
- GLfloat yFloorLinePosition = 0.0f;
+ GLfloat yFloorLinePosition = gridLineOffset;
if (m_yFlipped)
- yFloorLinePosition -= gridLineOffset;
- else
- yFloorLinePosition += gridLineOffset;
+ yFloorLinePosition = -yFloorLinePosition;
QVector3D gridLineScaler(rowScaleFactor, gridLineWidth, gridLineWidth);
@@ -1488,15 +1661,19 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Floor lines: columns
+#if defined(QT_OPENGL_ES_2)
+ lineRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f);
+#endif
gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, columnScaleFactor);
for (GLfloat bar = 0.0f; bar <= m_cachedColumnCount; bar++) {
QMatrix4x4 modelMatrix;
@@ -1526,40 +1703,31 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
if (m_axisCacheY.segmentCount() > 0) {
// Wall lines: back wall
- GLfloat heightStep = m_axisCacheY.subSegmentStep();
- GLfloat startLine = 0.0f;
- int segmentCount = m_axisCacheY.segmentCount() * m_axisCacheY.subSegmentCount();
+ int gridLineCount = m_axisCacheY.gridLineCount();
GLfloat zWallLinePosition = -columnScaleFactor + gridLineOffset;
if (m_zFlipped)
zWallLinePosition = -zWallLinePosition;
- if (m_hasNegativeValues) {
- if (m_noZeroInRange)
- startLine = m_axisCacheY.min() - m_axisCacheY.max();
- else
- startLine = m_axisCacheY.min();
- }
-
- GLfloat lineHeight = startLine;
gridLineScaler = QVector3D(rowScaleFactor, gridLineWidth, gridLineWidth);
- for (int segment = 0; segment <= segmentCount; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
modelMatrix.translate(0.0f,
- 2.0f * lineHeight / m_heightNormalizer,
+ m_axisCacheY.gridLinePosition(line),
zWallLinePosition);
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
@@ -1583,13 +1751,13 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- lineHeight += heightStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Wall lines: side wall
@@ -1602,15 +1770,14 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
else
lineRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f);
- lineHeight = startLine;
gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, columnScaleFactor);
- for (int segment = 0; segment <= segmentCount; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
modelMatrix.translate(xWallLinePosition,
- 2.0f * lineHeight / m_heightNormalizer,
+ m_axisCacheY.gridLinePosition(line),
0.0f);
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
@@ -1632,251 +1799,457 @@ void Bars3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- lineHeight += heightStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
}
- // Bind label shader
- m_labelShader->bind();
+ Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
+ drawLabels(false, activeCamera, viewMatrix, projectionMatrix, rowScaleFactor,
+ columnScaleFactor);
+
+ // Handle selected bar label generation
+ if (barSelectionFound) {
+ // Print value of selected bar
+ glDisable(GL_DEPTH_TEST);
+ // Draw the selection label
+ LabelItem &labelItem = selectionLabelItem();
+ if (m_selectedBar != selectedBar || m_updateLabels || !labelItem.textureId()
+ || m_selectionLabelDirty) {
+ QString labelText = selectionLabel();
+ if (labelText.isNull() || m_selectionLabelDirty) {
+ labelText = m_selectedSeriesCache->itemLabel();
+ setSelectionLabel(labelText);
+ m_selectionLabelDirty = false;
+ }
+ m_drawer->generateLabelItem(labelItem, labelText);
+ m_selectedBar = selectedBar;
+ }
+
+ Drawer::LabelPosition position =
+ m_selectedBar->height() >= 0 ? Drawer::LabelOver : Drawer::LabelBelow;
+
+ m_drawer->drawLabel(*selectedBar, labelItem, viewMatrix, projectionMatrix,
+ zeroVector, identityQuaternion, selectedBar->height(),
+ m_cachedSelectionMode, m_labelShader,
+ m_labelObj, activeCamera, true, false, position);
+
+ // Reset label update flag; they should have been updated when we get here
+ m_updateLabels = false;
+
+ glEnable(GL_DEPTH_TEST);
+ } else {
+ m_selectedBar = 0;
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ // Release shader
+ glUseProgram(0);
+ m_selectionDirty = false;
+}
+
+void Bars3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCamera,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix,
+ GLfloat rowScaleFactor, GLfloat columnScaleFactor) {
+ ShaderHelper *shader = 0;
+ GLfloat alphaForValueSelection = labelValueAlpha / 255.0f;
+ GLfloat alphaForRowSelection = labelRowAlpha / 255.0f;
+ GLfloat alphaForColumnSelection = labelColumnAlpha / 255.0f;
+ if (drawSelection) {
+ shader = m_selectionShader;
+ // m_selectionShader is already bound
+ } else {
+ shader = m_labelShader;
+ shader->bind();
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POLYGON_OFFSET_FILL);
+ float labelAutoAngle = m_axisCacheY.labelAutoRotation();
+ float labelAngleFraction = labelAutoAngle / 90.0f;
+ float fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ float fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ float labelsMaxWidth = 0.0f;
+
+ int startIndex;
+ int endIndex;
+ int indexStep;
+
// Y Labels
- int labelNbr = 0;
- GLfloat heightStep = m_axisCacheY.segmentStep();
- GLfloat startLine = 0.0f;
- int labelCount = m_axisCacheY.labels().size();
- if (m_hasNegativeValues) {
- if (m_noZeroInRange)
- startLine = m_axisCacheY.min() - m_axisCacheY.max();
- else
- startLine = m_axisCacheY.min();
- }
- GLfloat labelPos = startLine;
+ int labelCount = m_axisCacheY.labelCount();
GLfloat labelMarginXTrans = labelMargin;
GLfloat labelMarginZTrans = labelMargin;
GLfloat labelXTrans = rowScaleFactor;
GLfloat labelZTrans = columnScaleFactor;
QVector3D backLabelRotation(0.0f, -90.0f, 0.0f);
QVector3D sideLabelRotation(0.0f, 0.0f, 0.0f);
- Qt::AlignmentFlag backAlignment = Qt::AlignLeft;
- Qt::AlignmentFlag sideAlignment = Qt::AlignLeft;
+ Qt::AlignmentFlag backAlignment = (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ Qt::AlignmentFlag sideAlignment = (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+
if (!m_xFlipped) {
labelXTrans = -labelXTrans;
labelMarginXTrans = -labelMargin;
- backLabelRotation.setY(90.0f);
- sideAlignment = Qt::AlignRight;
}
if (m_zFlipped) {
labelZTrans = -labelZTrans;
labelMarginZTrans = -labelMargin;
- backAlignment = Qt::AlignRight;
- sideLabelRotation.setY(180.f);
}
+
+ if (labelAutoAngle == 0.0f) {
+ if (!m_xFlipped)
+ backLabelRotation.setY(90.0f);
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.f);
+ } else {
+ // Orient side labels somewhat towards the camera
+ if (m_xFlipped) {
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.0f + (2.0f * labelAutoAngle) - fractionCamX);
+ else
+ sideLabelRotation.setY(-fractionCamX);
+ backLabelRotation.setY(-90.0f + labelAutoAngle - fractionCamX);
+ } else {
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.0f - (2.0f * labelAutoAngle) - fractionCamX);
+ else
+ sideLabelRotation.setY(-fractionCamX);
+ backLabelRotation.setY(90.0f - labelAutoAngle - fractionCamX);
+ }
+ }
+ sideLabelRotation.setX(-fractionCamY);
+ backLabelRotation.setX(-fractionCamY);
+
+ QQuaternion totalSideRotation = Utils::calculateRotation(sideLabelRotation);
+ QQuaternion totalBackRotation = Utils::calculateRotation(backLabelRotation);
+
QVector3D backLabelTrans = QVector3D(labelXTrans, 0.0f,
labelZTrans + labelMarginZTrans);
QVector3D sideLabelTrans = QVector3D(-labelXTrans - labelMarginXTrans,
0.0f, -labelZTrans);
- for (int i = 0; i < labelCount; i++) {
- if (m_axisCacheY.labelItems().size() > labelNbr) {
- backLabelTrans.setY(2.0f * labelPos / m_heightNormalizer);
- sideLabelTrans.setY(backLabelTrans.y());
-
- glPolygonOffset(GLfloat(i) / -10.0f, 1.0f);
+ if (m_yFlipped) {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ } else {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
+ }
+ for (int i = startIndex; i != endIndex; i = i + indexStep) {
+ backLabelTrans.setY(m_axisCacheY.labelPosition(i));
+ sideLabelTrans.setY(backLabelTrans.y());
- const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
+ glPolygonOffset(GLfloat(i) / -10.0f, 1.0f);
- // Back wall
- m_dummyBarRenderItem.setTranslation(backLabelTrans);
- m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, backLabelRotation, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, backAlignment);
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(i);
- // Side wall
- m_dummyBarRenderItem.setTranslation(sideLabelTrans);
- m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, sideLabelRotation, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, sideAlignment);
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(0.0f, 0.0f, i / 255.0f,
+ alphaForValueSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- labelNbr++;
- labelPos += heightStep;
+
+ // Back wall
+ m_dummyBarRenderItem.setTranslation(backLabelTrans);
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalBackRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, backAlignment, false, drawSelection);
+
+ // Side wall
+ m_dummyBarRenderItem.setTranslation(sideLabelTrans);
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalSideRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, sideAlignment, false, drawSelection);
+
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+
+ if (!drawSelection && m_axisCacheY.isTitleVisible()) {
+ sideLabelTrans.setY(m_backgroundAdjustment);
+ backLabelTrans.setY(m_backgroundAdjustment);
+ drawAxisTitleY(sideLabelRotation, backLabelRotation, sideLabelTrans, backLabelTrans,
+ totalSideRotation, totalBackRotation, m_dummyBarRenderItem, activeCamera,
+ labelsMaxWidth, viewMatrix, projectionMatrix, shader);
}
+ // Z labels
// Calculate the positions for row and column labels and store them
+ labelsMaxWidth = 0.0f;
+ labelAutoAngle = m_axisCacheZ.labelAutoRotation();
+ labelAngleFraction = labelAutoAngle / 90.0f;
+ fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ fractionCamX = activeCamera->xRotation() * labelAngleFraction;
GLfloat labelYAdjustment = 0.005f;
GLfloat scaledRowWidth = rowScaleFactor;
GLfloat scaledColumnDepth = columnScaleFactor;
GLfloat colPosValue = scaledRowWidth + labelMargin;
GLfloat rowPosValue = scaledColumnDepth + labelMargin;
- QVector3D labelRotation(-90.0f, 0.0f, 0.0f);
- if (m_zFlipped)
- labelRotation.setY(180.0f);
- if (m_yFlipped) {
+ GLfloat rowPos = 0.0f;
+ GLfloat colPos = 0.0f;
+ Qt::AlignmentFlag alignment = (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ QVector3D labelRotation;
+
+ if (labelAutoAngle == 0.0f) {
+ labelRotation.setX(-90.0f);
if (m_zFlipped)
- labelRotation.setY(0.0f);
- else
labelRotation.setY(180.0f);
- labelRotation.setZ(180.0f);
- }
-
- Qt::AlignmentFlag alignment = m_xFlipped ? Qt::AlignLeft : Qt::AlignRight;
- for (int row = 0; row != m_cachedRowCount; row++) {
- if (m_axisCacheZ.labelItems().size() > row) {
- // Go through all rows and get position of max+1 or min-1 column, depending on x flip
- // We need only positions for them, labels have already been generated
- rowPos = (row + 0.5f) * m_cachedBarSpacing.height();
- if (m_xFlipped)
- colPos = -colPosValue;
+ if (m_yFlipped) {
+ if (m_zFlipped)
+ labelRotation.setY(0.0f);
else
- colPos = colPosValue;
-
- glPolygonOffset(GLfloat(row) / -10.0f, 1.0f);
-
- QVector3D labelPos = QVector3D(colPos,
- labelYAdjustment, // raise a bit over background to avoid depth "glimmering"
- (m_columnDepth - rowPos) / m_scaleFactor);
-
- m_dummyBarRenderItem.setTranslation(labelPos);
- const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(row);
-
- m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, labelRotation, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, alignment, m_cachedIsSlicingActivated);
+ labelRotation.setY(180.0f);
+ labelRotation.setZ(180.0f);
+ }
+ } else {
+ if (m_zFlipped)
+ labelRotation.setY(180.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f - (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(90.0f + (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f + (labelAutoAngle - fractionCamX)
+ * -(labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f + (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f - (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f - (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ }
+ }
}
}
- labelRotation = QVector3D(-90.0f, 90.0f, 0.0f);
- if (m_xFlipped)
- labelRotation.setY(-90.0f);
- if (m_yFlipped) {
+
+ QQuaternion totalRotation = Utils::calculateRotation(labelRotation);
+ labelCount = qMin(m_axisCacheZ.labelCount(), m_cachedRowCount);
+ if (m_zFlipped) {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
+ } else {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ }
+ for (int row = startIndex; row != endIndex; row = row + indexStep) {
+ // Go through all rows and get position of max+1 or min-1 column, depending on x flip
+ // We need only positions for them, labels have already been generated
+ rowPos = (row + 0.5f) * m_cachedBarSpacing.height();
if (m_xFlipped)
- labelRotation.setY(90.0f);
+ colPos = -colPosValue;
else
- labelRotation.setY(-90.0f);
- labelRotation.setZ(180.0f);
- }
-
- alignment = m_zFlipped ? Qt::AlignRight : Qt::AlignLeft;
- for (int column = 0; column != m_cachedColumnCount; column++) {
- if (m_axisCacheX.labelItems().size() > column) {
- // Go through all columns and get position of max+1 or min-1 row, depending on z flip
- // We need only positions for them, labels have already been generated
- colPos = (column + 0.5f) * m_cachedBarSpacing.width();
- if (m_zFlipped)
- rowPos = -rowPosValue;
- else
- rowPos = rowPosValue;
+ colPos = colPosValue;
- glPolygonOffset(GLfloat(column) / -10.0f, 1.0f);
+ glPolygonOffset(GLfloat(row) / -10.0f, 1.0f);
- QVector3D labelPos = QVector3D((colPos - m_rowWidth) / m_scaleFactor,
- labelYAdjustment, // raise a bit over background to avoid depth "glimmering"
- rowPos);
+ QVector3D labelPos = QVector3D(colPos,
+ labelYAdjustment, // raise a bit over background to avoid depth "glimmering"
+ (m_columnDepth - rowPos) / m_scaleFactor);
- m_dummyBarRenderItem.setTranslation(labelPos);
- const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(column);
+ m_dummyBarRenderItem.setTranslation(labelPos);
+ const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(row);
- m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, labelRotation, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, alignment);
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(row / 255.0f, 0.0f, 0.0f, alphaForRowSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
+
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, alignment,
+ false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
}
- glDisable(GL_POLYGON_OFFSET_FILL);
+ if (!drawSelection && m_axisCacheZ.isTitleVisible()) {
+ QVector3D titleTrans(colPos, 0.0f, 0.0f);
+ drawAxisTitleZ(labelRotation, titleTrans, totalRotation, m_dummyBarRenderItem,
+ activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader);
+ }
- // Handle selected bar label generation
- if (barSelectionFound) {
- // Print value of selected bar
- glDisable(GL_DEPTH_TEST);
- // Draw the selection label
- LabelItem &labelItem = selectionLabelItem();
- if (m_selectedBar != selectedBar || m_updateLabels || !labelItem.textureId()
- || m_selectionLabelDirty) {
- QString labelText = selectionLabel();
- if (labelText.isNull() || m_selectionLabelDirty) {
- static const QString rowIndexTag(QStringLiteral("@rowIdx"));
- static const QString rowLabelTag(QStringLiteral("@rowLabel"));
- static const QString rowTitleTag(QStringLiteral("@rowTitle"));
- static const QString colIndexTag(QStringLiteral("@colIdx"));
- static const QString colLabelTag(QStringLiteral("@colLabel"));
- static const QString colTitleTag(QStringLiteral("@colTitle"));
- static const QString valueTitleTag(QStringLiteral("@valueTitle"));
- static const QString valueLabelTag(QStringLiteral("@valueLabel"));
- static const QString seriesNameTag(QStringLiteral("@seriesName"));
-
- // Custom format expects printf format specifier. There is no tag for it.
- labelText = generateValueLabel(
- m_visibleSeriesList[m_visualSelectedBarSeriesIndex].itemLabelFormat(),
- selectedBar->value());
-
- int selBarPosRow = selectedBar->position().x();
- int selBarPosCol = selectedBar->position().y();
- labelText.replace(rowIndexTag, QString::number(selBarPosRow));
- if (m_axisCacheZ.labels().size() > selBarPosRow)
- labelText.replace(rowLabelTag, m_axisCacheZ.labels().at(selBarPosRow));
- else
- labelText.replace(rowLabelTag, QString());
- labelText.replace(rowTitleTag, m_axisCacheZ.title());
- labelText.replace(colIndexTag, QString::number(selBarPosCol));
- if (m_axisCacheX.labels().size() > selBarPosCol)
- labelText.replace(colLabelTag, m_axisCacheX.labels().at(selBarPosCol));
- else
- labelText.replace(colLabelTag, QString());
- labelText.replace(colTitleTag, m_axisCacheX.title());
- labelText.replace(valueTitleTag, m_axisCacheY.title());
-
- if (labelText.contains(valueLabelTag)) {
- QString labelFormat = m_axisCacheY.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat, selectedBar->value());
- labelText.replace(valueLabelTag, valueLabelText);
+ // X labels
+ labelsMaxWidth = 0.0f;
+ labelAutoAngle = m_axisCacheX.labelAutoRotation();
+ labelAngleFraction = labelAutoAngle / 90.0f;
+ fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ alignment = (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ if (labelAutoAngle == 0.0f) {
+ labelRotation = QVector3D(-90.0f, 90.0f, 0.0f);
+ if (m_xFlipped)
+ labelRotation.setY(-90.0f);
+ if (m_yFlipped) {
+ if (m_xFlipped)
+ labelRotation.setY(90.0f);
+ else
+ labelRotation.setY(-90.0f);
+ labelRotation.setZ(180.0f);
+ }
+ } else {
+ if (m_xFlipped)
+ labelRotation.setY(-90.0f);
+ else
+ labelRotation.setY(90.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f - (2.0f * labelAutoAngle - fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - (2.0f * labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f + fractionCamX
+ * -(labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - fractionCamX
+ * (-labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f + (2.0f * labelAutoAngle - fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + (2.0f * labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f - fractionCamX
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + fractionCamX
+ * -(labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
}
-
- labelText.replace(seriesNameTag,
- m_visibleSeriesList[m_visualSelectedBarSeriesIndex].name());
-
- setSelectionLabel(labelText);
- m_selectionLabelDirty = false;
}
- m_drawer->generateLabelItem(labelItem, labelText);
- m_selectedBar = selectedBar;
}
+ }
- m_drawer->drawLabel(*selectedBar, labelItem, viewMatrix, projectionMatrix,
- zeroVector, zeroVector, selectedBar->height(),
- m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, true, false);
-
- // Reset label update flag; they should have been updated when we get here
- m_updateLabels = false;
-
- glEnable(GL_DEPTH_TEST);
+ totalRotation = Utils::calculateRotation(labelRotation);
+ labelCount = qMin(m_axisCacheX.labelCount(), m_cachedColumnCount);
+ if (m_xFlipped) {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
} else {
- m_selectedBar = 0;
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
}
+ for (int column = startIndex; column != endIndex; column = column + indexStep) {
+ // Go through all columns and get position of max+1 or min-1 row, depending on z flip
+ // We need only positions for them, labels have already been generated
+ colPos = (column + 0.5f) * m_cachedBarSpacing.width();
+ if (m_zFlipped)
+ rowPos = -rowPosValue;
+ else
+ rowPos = rowPosValue;
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
+ glPolygonOffset(GLfloat(column) / -10.0f, 1.0f);
- // Release shader
- glUseProgram(0);
+ QVector3D labelPos = QVector3D((colPos - m_rowWidth) / m_scaleFactor,
+ labelYAdjustment, // raise a bit over background to avoid depth "glimmering"
+ rowPos);
- m_selectionDirty = false;
+ m_dummyBarRenderItem.setTranslation(labelPos);
+ const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(column);
+
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(0.0f, column / 255.0f, 0.0f,
+ alphaForColumnSelection);
+ shader->setUniformValue(shader->color(), labelColor);
+ }
+
+ m_drawer->drawLabel(m_dummyBarRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, alignment, false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+
+ if (!drawSelection && m_axisCacheX.isTitleVisible()) {
+ QVector3D titleTrans(0.0f, 0.0f, rowPos);
+ drawAxisTitleX(labelRotation, titleTrans, totalRotation, m_dummyBarRenderItem,
+ activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader);
+ }
+
+#if 0 // Debug label
+ static LabelItem debugLabelItem;
+ QString debugLabelString(QStringLiteral("Flips: x:%1 y:%2 z:%3 xr:%4 yr:%5"));
+ QString finalDebugString = debugLabelString.arg(m_xFlipped).arg(m_yFlipped).arg(m_zFlipped)
+ .arg(activeCamera->xRotation()).arg(activeCamera->yRotation());
+ m_dummyBarRenderItem.setTranslation(QVector3D(m_xFlipped ? -1.5f : 1.5f,
+ m_yFlipped ? 1.5f : -1.5f,
+ m_zFlipped ? -1.5f : 1.5f));
+
+ m_drawer->generateLabelItem(debugLabelItem, finalDebugString);
+ m_drawer->drawLabel(m_dummyBarRenderItem, debugLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, identityQuaternion, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, false, Drawer::LabelMid, Qt::AlignHCenter, false, drawSelection);
+#endif
+ glDisable(GL_POLYGON_OFFSET_FILL);
}
void Bars3DRenderer::updateMultiSeriesScaling(bool uniform)
@@ -1884,7 +2257,7 @@ void Bars3DRenderer::updateMultiSeriesScaling(bool uniform)
m_keepSeriesUniform = uniform;
// Recalculate scale factors
- m_seriesScaleX = 1.0f / float(m_visibleSeriesList.size());
+ m_seriesScaleX = 1.0f / float(m_visibleSeriesCount);
if (m_keepSeriesUniform)
m_seriesScaleZ = m_seriesScaleX;
else
@@ -1920,46 +2293,41 @@ void Bars3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orientatio
Abstract3DRenderer::updateAxisRange(orientation, min, max);
if (orientation == QAbstract3DAxis::AxisOrientationY) {
- calculateHeightAdjustment();
// Check if we have negative values
- if (min < 0 && !m_hasNegativeValues) {
+ if (min < 0)
m_hasNegativeValues = true;
- // Reload background
- loadBackgroundMesh();
- emit needRender();
- } else if (min >= 0 && m_hasNegativeValues) {
+ else if (min >= 0)
m_hasNegativeValues = false;
- // Reload background
- loadBackgroundMesh();
- emit needRender();
- }
+ calculateHeightAdjustment();
}
}
-void Bars3DRenderer::updateSelectedBar(const QPoint &position, const QBar3DSeries *series)
+void Bars3DRenderer::updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation, bool enable)
+{
+ Abstract3DRenderer::updateAxisReversed(orientation, enable);
+ if (orientation == QAbstract3DAxis::AxisOrientationY)
+ calculateHeightAdjustment();
+}
+
+
+void Bars3DRenderer::updateSelectedBar(const QPoint &position, QBar3DSeries *series)
{
m_selectedBarPos = position;
- m_selectedBarSeries = series;
+ m_selectedSeriesCache = static_cast<BarSeriesRenderCache *>(m_renderCacheList.value(series, 0));
m_selectionDirty = true;
m_selectionLabelDirty = true;
- m_visualSelectedBarSeriesIndex = -1;
- if (m_renderingArrays.isEmpty()) {
+ if (!m_selectedSeriesCache
+ || !m_selectedSeriesCache->isVisible()
+ || m_selectedSeriesCache->renderArray().isEmpty()) {
m_visualSelectedBarPos = Bars3DController::invalidSelectionPosition();
return;
}
int adjustedZ = m_selectedBarPos.x() - int(m_axisCacheZ.min());
int adjustedX = m_selectedBarPos.y() - int(m_axisCacheX.min());
- int maxZ = m_renderingArrays.at(0).size() - 1;
- int maxX = maxZ >= 0 ? m_renderingArrays.at(0).at(0).size() - 1 : -1;
-
- for (int i = 0; i < m_visibleSeriesList.size(); i++) {
- if (m_visibleSeriesList.at(i).series() == series) {
- m_visualSelectedBarSeriesIndex = i;
- break;
- }
- }
+ int maxZ = m_selectedSeriesCache->renderArray().size() - 1;
+ int maxX = maxZ >= 0 ? m_selectedSeriesCache->renderArray().at(0).size() - 1 : -1;
if (m_selectedBarPos == Bars3DController::invalidSelectionPosition()
|| adjustedZ < 0 || adjustedZ > maxZ
@@ -2020,29 +2388,8 @@ void Bars3DRenderer::updateShadowQuality(QAbstract3DGraph::ShadowQuality quality
void Bars3DRenderer::loadBackgroundMesh()
{
- if (m_backgroundObj)
- delete m_backgroundObj;
- if (m_hasNegativeValues)
- m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/negativeBackground"));
- else
- m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
- m_backgroundObj->load();
-}
-
-void Bars3DRenderer::loadGridLineMesh()
-{
- if (m_gridLineObj)
- delete m_gridLineObj;
- m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_gridLineObj->load();
-}
-
-void Bars3DRenderer::loadLabelMesh()
-{
- if (m_labelObj)
- delete m_labelObj;
- m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_labelObj->load();
+ ObjectHelper::resetObjectHelper(this, m_backgroundObj,
+ QStringLiteral(":/defaultMeshes/backgroundNoFloor"));
}
void Bars3DRenderer::updateTextures()
@@ -2075,7 +2422,7 @@ void Bars3DRenderer::calculateSceneScalingFactors()
void Bars3DRenderer::calculateHeightAdjustment()
{
- GLfloat newAdjustment = 0.0f;
+ GLfloat newAdjustment = 1.0f;
GLfloat maxAbs = qFabs(m_axisCacheY.max());
if (m_axisCacheY.max() < 0.0f) {
@@ -2086,7 +2433,8 @@ void Bars3DRenderer::calculateHeightAdjustment()
}
// Height fractions are used in gradient calculations and are therefore doubled
- if (m_axisCacheY.max() < 0.0f || m_axisCacheY.min() > 0.0f) {
+ // Note that if max or min is exactly zero, we still consider it outside the range
+ if (m_axisCacheY.max() <= 0.0f || m_axisCacheY.min() >= 0.0f) {
m_noZeroInRange = true;
m_gradientFraction = 2.0f;
} else {
@@ -2095,22 +2443,24 @@ void Bars3DRenderer::calculateHeightAdjustment()
m_gradientFraction = qMax(minAbs, maxAbs) / m_heightNormalizer * 2.0f;
}
- // Calculate translation adjustment for negative background
- newAdjustment = qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) * 2.0f - 0.5f;
+ // Calculate translation adjustment for background floor
+ newAdjustment = (qBound(0.0f, (maxAbs / m_heightNormalizer), 1.0f) - 0.5f) * 2.0f;
+ if (m_axisCacheY.reversed())
+ newAdjustment = -newAdjustment;
- if (newAdjustment != m_negativeBackgroundAdjustment) {
- m_hasHeightAdjustmentChanged = true;
- m_negativeBackgroundAdjustment = newAdjustment;
+ if (newAdjustment != m_backgroundAdjustment) {
+ m_backgroundAdjustment = newAdjustment;
+ m_axisCacheY.setTranslate(m_backgroundAdjustment - 1.0f);
}
}
-Bars3DController::SelectionType Bars3DRenderer::isSelected(int row, int bar, int seriesIndex)
+Bars3DController::SelectionType Bars3DRenderer::isSelected(int row, int bar,
+ const BarSeriesRenderCache *cache)
{
Bars3DController::SelectionType isSelectedType = Bars3DController::SelectionNone;
if ((m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries)
- && m_visualSelectedBarSeriesIndex >= 0)
- || seriesIndex == m_visualSelectedBarSeriesIndex) {
+ && m_selectedSeriesCache) || cache == m_selectedSeriesCache) {
if (row == m_visualSelectedBarPos.x() && bar == m_visualSelectedBarPos.y()
&& (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionItem))) {
isSelectedType = Bars3DController::SelectionItem;
@@ -2126,24 +2476,68 @@ Bars3DController::SelectionType Bars3DRenderer::isSelected(int row, int bar, int
return isSelectedType;
}
-QPoint Bars3DRenderer::selectionColorToArrayPosition(const QVector3D &selectionColor)
+QPoint Bars3DRenderer::selectionColorToArrayPosition(const QVector4D &selectionColor)
{
- QPoint position;
- if (selectionColor == selectionSkipColor) {
- position = Bars3DController::invalidSelectionPosition();
- } else {
+ QPoint position = Bars3DController::invalidSelectionPosition();
+ m_clickedType = QAbstract3DGraph::ElementNone;
+ m_selectedLabelIndex = -1;
+ m_selectedCustomItemIndex = -1;
+ if (selectionColor.w() == itemAlpha) {
+ // Normal selection item
position = QPoint(int(selectionColor.x() + int(m_axisCacheZ.min())),
int(selectionColor.y()) + int(m_axisCacheX.min()));
+ // Pass item clicked info to input handler
+ m_clickedType = QAbstract3DGraph::ElementSeries;
+ } else if (selectionColor.w() == labelRowAlpha) {
+ // Row selection
+ if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow)) {
+ // Use column from previous selection in case we have row + column mode
+ GLint previousCol = qMax(0, m_selectedBarPos.y()); // Use 0 if previous is invalid
+ position = QPoint(int(selectionColor.x() + int(m_axisCacheZ.min())), previousCol);
+ }
+ m_selectedLabelIndex = selectionColor.x();
+ // Pass label clicked info to input handler
+ m_clickedType = QAbstract3DGraph::ElementAxisZLabel;
+ } else if (selectionColor.w() == labelColumnAlpha) {
+ // Column selection
+ if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionColumn)) {
+ // Use row from previous selection in case we have row + column mode
+ GLint previousRow = qMax(0, m_selectedBarPos.x()); // Use 0 if previous is invalid
+ position = QPoint(previousRow, int(selectionColor.y()) + int(m_axisCacheX.min()));
+ }
+ m_selectedLabelIndex = selectionColor.y();
+ // Pass label clicked info to input handler
+ m_clickedType = QAbstract3DGraph::ElementAxisXLabel;
+ } else if (selectionColor.w() == labelValueAlpha) {
+ // Value selection
+ position = Bars3DController::invalidSelectionPosition();
+ m_selectedLabelIndex = selectionColor.z();
+ // Pass label clicked info to input handler
+ m_clickedType = QAbstract3DGraph::ElementAxisYLabel;
+ } else if (selectionColor.w() == customItemAlpha) {
+ // Custom item selection
+ position = Bars3DController::invalidSelectionPosition();
+ m_selectedCustomItemIndex = int(selectionColor.x())
+ + (int(selectionColor.y()) << 8)
+ + (int(selectionColor.z()) << 16);
+ m_clickedType = QAbstract3DGraph::ElementCustomItem;
}
return position;
}
-QBar3DSeries *Bars3DRenderer::selectionColorToSeries(const QVector3D &selectionColor)
+QBar3DSeries *Bars3DRenderer::selectionColorToSeries(const QVector4D &selectionColor)
{
- if (selectionColor == selectionSkipColor)
+ if (selectionColor == selectionSkipColor) {
return 0;
- else
- return static_cast<QBar3DSeries *>(m_visibleSeriesList.at(int(selectionColor.z())).series());
+ } else {
+ int seriesIndexFromColor(selectionColor.z());
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ BarSeriesRenderCache *cache = static_cast<BarSeriesRenderCache *>(baseCache);
+ if (cache->visualIndex() == seriesIndexFromColor)
+ return cache->series();
+ }
+ }
+ return 0;
}
void Bars3DRenderer::updateSlicingActive(bool isSlicing)
@@ -2190,10 +2584,7 @@ void Bars3DRenderer::initSelectionShader()
void Bars3DRenderer::initSelectionBuffer()
{
- if (m_selectionTexture) {
- m_textureHelper->deleteTexture(&m_selectionTexture);
- m_selectionTexture = 0;
- }
+ m_textureHelper->deleteTexture(&m_selectionTexture);
if (m_cachedIsSlicingActivated || m_primarySubViewport.size().isEmpty())
return;
@@ -2215,10 +2606,7 @@ void Bars3DRenderer::initDepthShader()
void Bars3DRenderer::updateDepthBuffer()
{
- if (m_depthTexture) {
- m_textureHelper->deleteTexture(&m_depthTexture);
- m_depthTexture = 0;
- }
+ m_textureHelper->deleteTexture(&m_depthTexture);
if (m_primarySubViewport.size().isEmpty())
return;
@@ -2250,4 +2638,29 @@ void Bars3DRenderer::initLabelShaders(const QString &vertexShader, const QString
m_labelShader->initialize();
}
+QVector3D Bars3DRenderer::convertPositionToTranslation(const QVector3D &position, bool isAbsolute)
+{
+ float xTrans = 0.0f;
+ float yTrans = 0.0f;
+ float zTrans = 0.0f;
+ if (!isAbsolute) {
+ // Convert row and column to translation on graph
+ xTrans = (((position.x() + 0.5f) * m_cachedBarSpacing.width()) - m_rowWidth)
+ / m_scaleFactor;
+ zTrans = (m_columnDepth - ((position.z() + 0.5f) * m_cachedBarSpacing.height()))
+ / m_scaleFactor;
+ yTrans = m_axisCacheY.positionAt(position.y());
+ } else {
+ xTrans = position.x() * m_scaleX;
+ yTrans = position.y() + m_backgroundAdjustment;
+ zTrans = position.z() * m_scaleZ;
+ }
+ return QVector3D(xTrans, yTrans, zTrans);
+}
+
+void Bars3DRenderer::updateAspectRatio(float ratio)
+{
+ Q_UNUSED(ratio)
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/bars3drenderer_p.h b/src/datavisualization/engine/bars3drenderer_p.h
index 37ac2b76..3a0ab3b8 100644
--- a/src/datavisualization/engine/bars3drenderer_p.h
+++ b/src/datavisualization/engine/bars3drenderer_p.h
@@ -32,19 +32,17 @@
#include "datavisualizationglobal_p.h"
#include "bars3dcontroller_p.h"
#include "abstract3drenderer_p.h"
-#include "qbardataproxy.h"
#include "barrenderitem_p.h"
class QPoint;
class QSizeF;
-class QOpenGLShaderProgram;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class ShaderHelper;
-class ObjectHelper;
class LabelItem;
class Q3DScene;
+class BarSeriesRenderCache;
class QT_DATAVISUALIZATION_EXPORT Bars3DRenderer : public Abstract3DRenderer
{
@@ -60,12 +58,8 @@ private:
// Internal state
BarRenderItem *m_selectedBar; // points to renderitem array
- QVector<BarRenderSliceItem> m_sliceSelection;
AxisRenderCache *m_sliceCache; // not owned
const LabelItem *m_sliceTitleItem; // not owned
- bool m_xFlipped;
- bool m_zFlipped;
- bool m_yFlipped;
bool m_updateLabels;
ShaderHelper *m_barShader;
ShaderHelper *m_barGradientShader;
@@ -73,9 +67,6 @@ private:
ShaderHelper *m_selectionShader;
ShaderHelper *m_backgroundShader;
ShaderHelper *m_labelShader;
- ObjectHelper *m_backgroundObj;
- ObjectHelper *m_gridLineObj;
- ObjectHelper *m_labelObj;
GLuint m_bgrTexture;
GLuint m_depthTexture;
GLuint m_selectionTexture;
@@ -86,7 +77,7 @@ private:
GLint m_shadowQualityMultiplier;
GLfloat m_heightNormalizer;
GLfloat m_gradientFraction;
- GLfloat m_negativeBackgroundAdjustment;
+ GLfloat m_backgroundAdjustment;
GLfloat m_rowWidth;
GLfloat m_columnDepth;
GLfloat m_maxDimension;
@@ -95,12 +86,10 @@ private:
GLfloat m_scaleFactor;
GLfloat m_maxSceneSize;
QPoint m_visualSelectedBarPos;
- int m_visualSelectedBarSeriesIndex;
- bool m_hasHeightAdjustmentChanged;
+ bool m_resetCameraBaseOrientation;
QPoint m_selectedBarPos;
- const QBar3DSeries *m_selectedBarSeries;
+ BarSeriesRenderCache *m_selectedSeriesCache;
BarRenderItem m_dummyBarRenderItem;
- QVector<BarRenderItemArray> m_renderingArrays;
bool m_noZeroInRange;
float m_seriesScaleX;
float m_seriesScaleZ;
@@ -108,15 +97,26 @@ private:
float m_seriesStart;
QPoint m_clickedPosition;
bool m_keepSeriesUniform;
+ bool m_haveUniformColorSeries;
+ bool m_haveGradientSeries;
+ float m_zeroPosition;
public:
explicit Bars3DRenderer(Bars3DController *controller);
~Bars3DRenderer();
void updateData();
+ void updateSeries(const QList<QAbstract3DSeries *> &seriesList);
+ SeriesRenderCache *createNewCache(QAbstract3DSeries *series);
+ void updateRows(const QVector<Bars3DController::ChangeRow> &rows);
+ void updateItems(const QVector<Bars3DController::ChangeItem> &items);
void updateScene(Q3DScene *scene);
void render(GLuint defaultFboHandle = 0);
+ QVector3D convertPositionToTranslation(const QVector3D &position, bool isAbsolute);
+
+ void updateAspectRatio(float ratio);
+
protected:
virtual void initializeOpenGL();
@@ -126,13 +126,15 @@ public slots:
const QSizeF &spacing = QSizeF(1.0, 1.0),
bool relative = true);
void updateSlicingActive(bool isSlicing);
- void updateSelectedBar(const QPoint &position, const QBar3DSeries *series);
+ void updateSelectedBar(const QPoint &position, QBar3DSeries *series);
inline QPoint clickedPosition() const { return m_clickedPosition; }
void resetClickedStatus();
// Overloaded from abstract renderer
virtual void updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min,
float max);
+ virtual void updateAxisReversed(QAbstract3DAxis::AxisOrientation orientation,
+ bool enable);
private:
virtual void initShaders(const QString &vertexShader, const QString &fragmentShader);
@@ -143,10 +145,11 @@ private:
void drawSlicedScene();
void drawScene(GLuint defaultFboHandle);
+ void drawLabels(bool drawSelection, const Q3DCamera *activeCamera,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix,
+ GLfloat rowScaleFactor, GLfloat columnScaleFactor);
void loadBackgroundMesh();
- void loadGridLineMesh();
- void loadLabelMesh();
void initSelectionShader();
void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
@@ -157,13 +160,15 @@ private:
#endif
void calculateSceneScalingFactors();
void calculateHeightAdjustment();
- Abstract3DController::SelectionType isSelected(int row, int bar, int seriesIndex);
- QPoint selectionColorToArrayPosition(const QVector3D &selectionColor);
- QBar3DSeries *selectionColorToSeries(const QVector3D &selectionColor);
+ Abstract3DController::SelectionType isSelected(int row, int bar,
+ const BarSeriesRenderCache *cache);
+ QPoint selectionColorToArrayPosition(const QVector4D &selectionColor);
+ QBar3DSeries *selectionColorToSeries(const QVector4D &selectionColor);
- Q_DISABLE_COPY(Bars3DRenderer)
+ inline void updateRenderRow(const QBarDataRow *dataRow, BarRenderItemRow &renderRow);
+ inline void updateRenderItem(const QBarDataItem &dataItem, BarRenderItem &renderItem);
- friend class BarRenderItem;
+ Q_DISABLE_COPY(Bars3DRenderer)
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/barseriesrendercache.cpp b/src/datavisualization/engine/barseriesrendercache.cpp
new file mode 100644
index 00000000..95da3680
--- /dev/null
+++ b/src/datavisualization/engine/barseriesrendercache.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "barseriesrendercache_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+BarSeriesRenderCache::BarSeriesRenderCache(QAbstract3DSeries *series,
+ Abstract3DRenderer *renderer)
+ : SeriesRenderCache(series, renderer),
+ m_visualIndex(-1)
+{
+}
+
+BarSeriesRenderCache::~BarSeriesRenderCache()
+{
+}
+
+void BarSeriesRenderCache::cleanup(TextureHelper *texHelper)
+{
+ m_renderArray.clear();
+ m_sliceArray.clear();
+
+ SeriesRenderCache::cleanup(texHelper);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/barseriesrendercache_p.h b/src/datavisualization/engine/barseriesrendercache_p.h
new file mode 100644
index 00000000..4e169300
--- /dev/null
+++ b/src/datavisualization/engine/barseriesrendercache_p.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef BARSERIESRENDERCACHE_P_H
+#define BARSERIESRENDERCACHE_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "seriesrendercache_p.h"
+#include "qbar3dseries_p.h"
+#include "barrenderitem_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class BarSeriesRenderCache : public SeriesRenderCache
+{
+public:
+ BarSeriesRenderCache(QAbstract3DSeries *series, Abstract3DRenderer *renderer);
+ virtual ~BarSeriesRenderCache();
+
+ void cleanup(TextureHelper *texHelper);
+
+ inline BarRenderItemArray &renderArray() { return m_renderArray; }
+ inline QBar3DSeries *series() const { return static_cast<QBar3DSeries *>(m_series); }
+ inline QVector<BarRenderSliceItem> &sliceArray() { return m_sliceArray; }
+ inline void setVisualIndex(int index) { m_visualIndex = index; }
+ inline int visualIndex() {return m_visualIndex; }
+
+protected:
+ BarRenderItemArray m_renderArray;
+ QVector<BarRenderSliceItem> m_sliceArray;
+ int m_visualIndex; // order of the series is relevant
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/engine/drawer.cpp b/src/datavisualization/engine/drawer.cpp
index 55a2c2a5..b8726840 100644
--- a/src/datavisualization/engine/drawer.cpp
+++ b/src/datavisualization/engine/drawer.cpp
@@ -18,13 +18,11 @@
#include "drawer_p.h"
#include "shaderhelper_p.h"
-#include "objecthelper_p.h"
-#include "abstractobjecthelper_p.h"
#include "surfaceobject_p.h"
-#include "q3dcamera.h"
#include "utils_p.h"
#include "texturehelper_p.h"
#include "abstract3drenderer_p.h"
+#include "scatterpointbufferhelper_p.h"
#include <QtGui/QMatrix4x4>
#include <QtCore/qmath.h>
@@ -45,18 +43,28 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
// Vertex array buffer for point
const GLfloat point_data[] = {0.0f, 0.0f, 0.0f};
+// Vertex array buffer for line
+const GLfloat line_data[] = {
+ -1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+};
+
Drawer::Drawer(Q3DTheme *theme)
: m_theme(theme),
m_textureHelper(0),
- m_pointbuffer(0)
+ m_pointbuffer(0),
+ m_linebuffer(0),
+ m_scaledFontSize(0.0f)
{
}
Drawer::~Drawer()
{
delete m_textureHelper;
- if (QOpenGLContext::currentContext())
+ if (QOpenGLContext::currentContext()) {
glDeleteBuffers(1, &m_pointbuffer);
+ glDeleteBuffers(1, &m_linebuffer);
+ }
}
void Drawer::initializeOpenGL()
@@ -70,6 +78,7 @@ void Drawer::initializeOpenGL()
void Drawer::setTheme(Q3DTheme *theme)
{
m_theme = theme;
+ m_scaledFontSize = 0.05f + m_theme->font().pointSizeF() / 500.0f;
emit drawerChanged();
}
@@ -140,6 +149,18 @@ void Drawer::drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLui
}
}
+void Drawer::drawSelectionObject(ShaderHelper *shader, AbstractObjectHelper *object)
+{
+ glEnableVertexAttribArray(shader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf());
+ glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->elementBuf());
+ glDrawElements(GL_TRIANGLES, object->indexCount(), GL_UNSIGNED_SHORT, (void *)0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDisableVertexAttribArray(shader->posAtt());
+}
+
void Drawer::drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object)
{
// 1st attribute buffer : vertices
@@ -162,6 +183,8 @@ void Drawer::drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object)
void Drawer::drawPoint(ShaderHelper *shader)
{
+ // Draw a single point
+
// Generate vertex buffer for point if it does not exist
if (!m_pointbuffer) {
glGenBuffers(1, &m_pointbuffer);
@@ -183,13 +206,55 @@ void Drawer::drawPoint(ShaderHelper *shader)
glDisableVertexAttribArray(shader->posAtt());
}
+void Drawer::drawPoints(ShaderHelper *shader, ScatterPointBufferHelper *object)
+{
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(shader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->pointBuf());
+ glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ // Draw the points
+ glDrawArrays(GL_POINTS, 0, object->indexCount());
+
+ // Free buffers
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(shader->posAtt());
+}
+
+void Drawer::drawLine(ShaderHelper *shader)
+{
+ // Draw a single line
+
+ // Generate vertex buffer for line if it does not exist
+ if (!m_linebuffer) {
+ glGenBuffers(1, &m_linebuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_linebuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(line_data), line_data, GL_STATIC_DRAW);
+ }
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(shader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, m_linebuffer);
+ glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ // Draw the line
+ glDrawArrays(GL_LINES, 0, 2);
+
+ // Free buffers
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(shader->posAtt());
+}
+
void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem,
const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix,
- const QVector3D &positionComp, const QVector3D &rotation,
+ const QVector3D &positionComp, const QQuaternion &rotation,
GLfloat itemHeight, QAbstract3DGraph::SelectionFlags mode,
ShaderHelper *shader, ObjectHelper *object,
const Q3DCamera *camera, bool useDepth, bool rotateAlong,
- LabelPosition position, Qt::AlignmentFlag alignment, bool isSlicing)
+ LabelPosition position, Qt::AlignmentFlag alignment, bool isSlicing,
+ bool isSelecting)
{
// Draw label
if (!labelItem.textureId())
@@ -246,68 +311,20 @@ void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelIte
}
// Calculate scale factor to get uniform font size
- GLfloat scaledFontSize = 0.05f + m_theme->font().pointSizeF() / 500.0f;
- GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height();
+ GLfloat scaleFactor = m_scaledFontSize / (GLfloat)textureSize.height();
// Apply alignment
- GLfloat xAlignment = 0.0f;
- GLfloat yAlignment = 0.0f;
- GLfloat zAlignment = 0.0f;
- GLfloat sinRotY = qFabs(qSin(qDegreesToRadians(rotation.y())));
- GLfloat cosRotY = qFabs(qCos(qDegreesToRadians(rotation.y())));
- GLfloat sinRotZ = 0.0f;
- GLfloat cosRotZ = 0.0f;
- if (rotation.z()) {
- sinRotZ = qFabs(qSin(qDegreesToRadians(rotation.z())));
- cosRotZ = qFabs(qCos(qDegreesToRadians(rotation.z())));
- }
- switch (alignment) {
- case Qt::AlignLeft: {
- if (rotation.z() && rotation.z() != 180.0f && !rotation.y()) {
- xAlignment = ((-(GLfloat)textureSize.width() * scaleFactor) * cosRotZ
- - ((GLfloat)textureSize.height() * scaleFactor) * sinRotZ) / 2.0f;
- yAlignment = (((GLfloat)textureSize.width() * scaleFactor) * sinRotZ
- + ((GLfloat)textureSize.height() * scaleFactor) * cosRotZ) / 2.0f;
- } else {
- xAlignment = (-(GLfloat)textureSize.width() * scaleFactor) * cosRotY;
- zAlignment = ((GLfloat)textureSize.width() * scaleFactor) * sinRotY;
- }
- break;
- }
- case Qt::AlignRight: {
- if (rotation.z() && rotation.z() != 180.0f && !rotation.y()) {
- xAlignment = (((GLfloat)textureSize.width() * scaleFactor) * cosRotZ
- + ((GLfloat)textureSize.height() * scaleFactor) * sinRotZ) / 2.0f;
- yAlignment = (((GLfloat)textureSize.width() * scaleFactor) * sinRotZ
- + ((GLfloat)textureSize.height() * scaleFactor) * cosRotZ) / 2.0f;
- } else {
- xAlignment = ((GLfloat)textureSize.width() * scaleFactor) * cosRotY;
- zAlignment = (-(GLfloat)textureSize.width() * scaleFactor) * sinRotY;
- }
- break;
- }
- case Qt::AlignTop: {
- yAlignment = ((GLfloat)textureSize.width() * scaleFactor) * cosRotY;
- break;
- }
- case Qt::AlignBottom: {
- yAlignment = (-(GLfloat)textureSize.width() * scaleFactor) * cosRotY;
- break;
- }
- case Qt::AlignHCenter: {
- xAlignment = (-(GLfloat)textureSize.width() * scaleFactor) * cosRotZ
- - ((GLfloat)textureSize.height() * scaleFactor) * sinRotZ;
- break;
- }
- case Qt::AlignVCenter: {
- yAlignment = ((GLfloat)textureSize.width() * scaleFactor) * cosRotZ
- + ((GLfloat)textureSize.height() * scaleFactor) * sinRotZ;
- break;
- }
- default: {
- break;
- }
- }
+ QVector3D anchorPoint;
+
+ if (alignment & Qt::AlignLeft)
+ anchorPoint.setX(float(textureSize.width()) * scaleFactor);
+ else if (alignment & Qt::AlignRight)
+ anchorPoint.setX(float(-textureSize.width()) * scaleFactor);
+
+ if (alignment & Qt::AlignTop)
+ anchorPoint.setY(float(-textureSize.height()) * scaleFactor);
+ else if (alignment & Qt::AlignBottom)
+ anchorPoint.setY(float(textureSize.height()) * scaleFactor);
if (position < LabelBottom) {
xPosition = item.translation().x();
@@ -318,15 +335,9 @@ void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelIte
}
// Position label
- modelMatrix.translate(xPosition + xAlignment, yPosition + yAlignment, zPosition + zAlignment);
+ modelMatrix.translate(xPosition, yPosition, zPosition);
// Rotate
- QQuaternion rotQuatX = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, rotation.x());
- QQuaternion rotQuatY = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, rotation.y());
- QQuaternion rotQuatZ = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, rotation.z());
- QQuaternion rotQuaternion = rotQuatY * rotQuatZ * rotQuatX;
- modelMatrix.rotate(rotQuaternion);
-
if (useDepth && !rotateAlong) {
float yComp = float(qRadiansToDegrees(qTan(positionComp.y() / cameraDistance)));
// Apply negative camera rotations to keep labels facing camera
@@ -334,20 +345,27 @@ void Drawer::drawLabel(const AbstractRenderItem &item, const LabelItem &labelIte
float camRotationY = camera->yRotation();
modelMatrix.rotate(-camRotationX, 0.0f, 1.0f, 0.0f);
modelMatrix.rotate(-camRotationY - yComp, 1.0f, 0.0f, 0.0f);
+ } else {
+ modelMatrix.rotate(rotation);
}
+ modelMatrix.translate(anchorPoint);
// Scale label based on text size
modelMatrix.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor,
- scaledFontSize,
+ m_scaledFontSize,
0.0f));
MVPMatrix = projectionmatrix * viewmatrix * modelMatrix;
- // Set shader bindings
shader->setUniformValue(shader->MVP(), MVPMatrix);
- // Draw the object
- drawObject(shader, object, labelItem.textureId());
+ if (isSelecting) {
+ // Draw the selection object
+ drawSelectionObject(shader, object);
+ } else {
+ // Draw the object
+ drawObject(shader, object, labelItem.textureId());
+ }
}
void Drawer::generateSelectionLabelTexture(Abstract3DRenderer *renderer)
diff --git a/src/datavisualization/engine/drawer_p.h b/src/datavisualization/engine/drawer_p.h
index 8e98aa3a..ffcea315 100644
--- a/src/datavisualization/engine/drawer_p.h
+++ b/src/datavisualization/engine/drawer_p.h
@@ -44,6 +44,7 @@ class SurfaceObject;
class TextureHelper;
class Q3DCamera;
class Abstract3DRenderer;
+class ScatterPointBufferHelper;
class Drawer : public QObject, public QOpenGLFunctions
{
@@ -71,18 +72,23 @@ public:
void setTheme(Q3DTheme *theme);
Q3DTheme *theme() const;
QFont font() const;
+ inline GLfloat scaledFontSize() const { return m_scaledFontSize; }
void drawObject(ShaderHelper *shader, AbstractObjectHelper *object, GLuint textureId = 0,
GLuint depthTextureId = 0);
+ void drawSelectionObject(ShaderHelper *shader, AbstractObjectHelper *object);
void drawSurfaceGrid(ShaderHelper *shader, SurfaceObject *object);
void drawPoint(ShaderHelper *shader);
+ void drawPoints(ShaderHelper *shader, ScatterPointBufferHelper *object);
+ void drawLine(ShaderHelper *shader);
void drawLabel(const AbstractRenderItem &item, const LabelItem &labelItem,
const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix,
- const QVector3D &positionComp, const QVector3D &rotation, GLfloat itemHeight,
+ const QVector3D &positionComp, const QQuaternion &rotation, GLfloat itemHeight,
QAbstract3DGraph::SelectionFlags mode, ShaderHelper *shader, ObjectHelper *object,
const Q3DCamera *camera, bool useDepth = false, bool rotateAlong = false,
LabelPosition position = LabelOver,
- Qt::AlignmentFlag alignment = Qt::AlignCenter, bool isSlicing = false);
+ Qt::AlignmentFlag alignment = Qt::AlignCenter, bool isSlicing = false,
+ bool isSelecting = false);
void generateSelectionLabelTexture(Abstract3DRenderer *item);
void generateLabelItem(LabelItem &item, const QString &text, int widestLabel = 0);
@@ -94,6 +100,8 @@ private:
Q3DTheme *m_theme;
TextureHelper *m_textureHelper;
GLuint m_pointbuffer;
+ GLuint m_linebuffer;
+ GLfloat m_scaledFontSize;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/engine.pri b/src/datavisualization/engine/engine.pri
index 9c2e71e4..96fa7fa9 100644
--- a/src/datavisualization/engine/engine.pri
+++ b/src/datavisualization/engine/engine.pri
@@ -26,7 +26,9 @@ HEADERS += $$PWD/qabstract3dgraph_p.h \
$$PWD/q3dobject.h \
$$PWD/q3dobject_p.h \
$$PWD/q3dscene_p.h \
- $$PWD/surfaceseriesrendercache_p.h
+ $$PWD/surfaceseriesrendercache_p.h \
+ $$PWD/barseriesrendercache_p.h \
+ $$PWD/scatterseriesrendercache_p.h
SOURCES += $$PWD/qabstract3dgraph.cpp \
$$PWD/q3dbars.cpp \
@@ -48,7 +50,9 @@ SOURCES += $$PWD/qabstract3dgraph.cpp \
$$PWD/q3dlight.cpp \
$$PWD/q3dobject.cpp \
$$PWD/q3dscene.cpp \
- $$PWD/surfaceseriesrendercache.cpp
+ $$PWD/surfaceseriesrendercache.cpp \
+ $$PWD/barseriesrendercache.cpp \
+ $$PWD/scatterseriesrendercache.cpp
RESOURCES += engine/engine.qrc
diff --git a/src/datavisualization/engine/engine.qrc b/src/datavisualization/engine/engine.qrc
index 18cba7fe..673b6ee0 100644
--- a/src/datavisualization/engine/engine.qrc
+++ b/src/datavisualization/engine/engine.qrc
@@ -24,7 +24,7 @@
<file alias="bevelbarSmoothFull">meshes/barFilledSmooth.obj</file>
<file alias="barFull">meshes/cubeFilledFlat.obj</file>
<file alias="barSmoothFull">meshes/cubeFilledSmooth.obj</file>
- <file alias="negativeBackground">meshes/backgroundNegatives.obj</file>
+ <file alias="backgroundNoFloor">meshes/backgroundNoFloor.obj</file>
<file alias="minimal">meshes/minimalFlat.obj</file>
<file alias="minimalSmooth">meshes/minimalSmooth.obj</file>
<file alias="arrow">meshes/arrowFlat.obj</file>
@@ -54,5 +54,8 @@
<file alias="fragmentSurfaceShadowNoTex">shaders/surfaceShadowNoTex.frag</file>
<file alias="fragmentSurfaceShadowFlat">shaders/surfaceShadowFlat.frag</file>
<file alias="vertexSurfaceShadowFlat">shaders/surfaceShadowFlat.vert</file>
+ <file alias="fragmentTexture">shaders/texture.frag</file>
+ <file alias="fragmentTextureES2">shaders/texture_ES2.frag</file>
+ <file alias="vertexTexture">shaders/texture.vert</file>
</qresource>
</RCC>
diff --git a/src/datavisualization/engine/meshes/backgroundNegatives.obj b/src/datavisualization/engine/meshes/backgroundNoFloor.obj
index 76c7c1d8..0b94617f 100644
--- a/src/datavisualization/engine/meshes/backgroundNegatives.obj
+++ b/src/datavisualization/engine/meshes/backgroundNoFloor.obj
@@ -1,18 +1,18 @@
# Blender v2.66 (sub 0) OBJ File: 'backgroudNegativesWall.blend'
# www.blender.org
o Cube
-v 0.999999 1.000000 1.000001
+v 1.000000 1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
-v 1.000000 -3.000000 1.000000
-v -1.000000 -3.000000 1.000000
-v -1.000000 -3.000000 -1.000000
-vt 0.000100 0.000100
-vt 0.500000 0.000100
-vt 0.500000 0.999900
-vt 0.999900 0.000100
-vt 0.999900 0.999900
-vt 0.000100 0.999900
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+vt 0.000000 0.000000
+vt 0.500000 0.000000
+vt 0.500000 1.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
vn 0.000000 -0.000000 -1.000000
vn 1.000000 0.000000 0.000000
s off
diff --git a/src/datavisualization/engine/q3dbars.cpp b/src/datavisualization/engine/q3dbars.cpp
index 7b37715f..a903d831 100644
--- a/src/datavisualization/engine/q3dbars.cpp
+++ b/src/datavisualization/engine/q3dbars.cpp
@@ -16,13 +16,7 @@
**
****************************************************************************/
-#include "q3dbars.h"
#include "q3dbars_p.h"
-#include "bars3dcontroller_p.h"
-#include "qvalue3daxis.h"
-#include "qcategory3daxis.h"
-#include "q3dcamera.h"
-#include "qbar3dseries_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -30,7 +24,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class Q3DBars
* \inmodule QtDataVisualization
* \brief The Q3DBars class provides methods for rendering 3D bar graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* This class enables developers to render bar graphs in 3D and to view them by rotating the scene
* freely. Rotation is done by holding down the right mouse button and moving the mouse. Zooming
diff --git a/src/datavisualization/engine/q3dcamera.cpp b/src/datavisualization/engine/q3dcamera.cpp
index 50f2e319..9866a34e 100644
--- a/src/datavisualization/engine/q3dcamera.cpp
+++ b/src/datavisualization/engine/q3dcamera.cpp
@@ -16,10 +16,7 @@
**
****************************************************************************/
-#include "q3dcamera.h"
#include "q3dcamera_p.h"
-#include "q3dscene.h"
-#include "q3dobject.h"
#include "utils_p.h"
#include <QtCore/qmath.h>
@@ -30,7 +27,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class Q3DCamera
* \inmodule QtDataVisualization
* \brief Representation of a camera in 3D space.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* Q3DCamera represents a basic orbit around centerpoint 3D camera that is used when rendering the
* data visualization. The class offers simple methods for rotating the camera around the origin
@@ -85,7 +82,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* data visualization. The type offers simple methods for rotating the camera around the origin
* and setting zoom level.
*
- * For Camera3D enums, see \l Q3DCamera::CameraPreset
+ * For Camera3D enums, see \l{Q3DCamera::CameraPreset}.
*/
/*!
@@ -208,10 +205,12 @@ float Q3DCamera::xRotation() const {
void Q3DCamera::setXRotation(float rotation)
{
- if (d_ptr->m_wrapXRotation)
+ if (d_ptr->m_wrapXRotation) {
rotation = Utils::wrapValue(rotation, d_ptr->m_minXRotation, d_ptr->m_maxXRotation);
- else
- rotation = qBound(float(d_ptr->m_minXRotation), float(rotation), float(d_ptr->m_maxXRotation));
+ } else {
+ rotation = qBound(float(d_ptr->m_minXRotation), float(rotation),
+ float(d_ptr->m_maxXRotation));
+ }
if (d_ptr->m_xRotation != rotation) {
d_ptr->setXRotation(rotation);
@@ -235,10 +234,12 @@ float Q3DCamera::yRotation() const {
void Q3DCamera::setYRotation(float rotation)
{
- if (d_ptr->m_wrapYRotation)
+ if (d_ptr->m_wrapYRotation) {
rotation = Utils::wrapValue(rotation, d_ptr->m_minYRotation, d_ptr->m_maxYRotation);
- else
- rotation = qBound(float(d_ptr->m_minYRotation), float(rotation), float(d_ptr->m_maxYRotation));
+ } else {
+ rotation = qBound(float(d_ptr->m_minYRotation), float(rotation),
+ float(d_ptr->m_maxYRotation));
+ }
if (d_ptr->m_yRotation != rotation) {
d_ptr->setYRotation(rotation);
diff --git a/src/datavisualization/engine/q3dlight.cpp b/src/datavisualization/engine/q3dlight.cpp
index 8ac9e3a0..03f094cb 100644
--- a/src/datavisualization/engine/q3dlight.cpp
+++ b/src/datavisualization/engine/q3dlight.cpp
@@ -16,8 +16,6 @@
**
****************************************************************************/
-#include "q3dlight.h"
-#include "q3dscene.h"
#include "q3dlight_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -26,7 +24,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class Q3DLight
* \inmodule QtDataVisualization
* \brief Representation of a light source in 3D space.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* Q3DLight represents a monochrome non variable light source in 3D space.
*/
diff --git a/src/datavisualization/engine/q3dobject.cpp b/src/datavisualization/engine/q3dobject.cpp
index 05edf287..56edb098 100644
--- a/src/datavisualization/engine/q3dobject.cpp
+++ b/src/datavisualization/engine/q3dobject.cpp
@@ -16,7 +16,6 @@
**
****************************************************************************/
-#include "q3dobject.h"
#include "q3dobject_p.h"
#include "q3dscene_p.h"
@@ -26,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
\class Q3DObject
\inmodule QtDataVisualization
\brief Simple baseclass for all the objects in the 3D scene.
- \since Qt Data Visualization 1.0
+ \since QtDataVisualization 1.0
Q3DObject is a baseclass that contains only position information for an object in 3D scene.
The object is considered to be a single point in the coordinate space without dimensions.
diff --git a/src/datavisualization/engine/q3dscatter.cpp b/src/datavisualization/engine/q3dscatter.cpp
index 7c7809f3..40bd5021 100644
--- a/src/datavisualization/engine/q3dscatter.cpp
+++ b/src/datavisualization/engine/q3dscatter.cpp
@@ -18,10 +18,6 @@
#include "q3dscatter.h"
#include "q3dscatter_p.h"
-#include "scatter3dcontroller_p.h"
-#include "qvalue3daxis.h"
-#include "q3dcamera.h"
-#include "qscatter3dseries_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -29,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class Q3DScatter
* \inmodule QtDataVisualization
* \brief The Q3DScatter class provides methods for rendering 3D scatter graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* This class enables developers to render scatter graphs in 3D and to view them by rotating the scene
* freely. Rotation is done by holding down the right mouse button and moving the mouse. Zooming
diff --git a/src/datavisualization/engine/q3dscene.cpp b/src/datavisualization/engine/q3dscene.cpp
index be64b928..9464bc8d 100644
--- a/src/datavisualization/engine/q3dscene.cpp
+++ b/src/datavisualization/engine/q3dscene.cpp
@@ -16,22 +16,17 @@
**
****************************************************************************/
-#include "datavisualizationglobal_p.h"
-
-#include "q3dscene.h"
#include "q3dscene_p.h"
#include "q3dcamera_p.h"
#include "q3dlight_p.h"
-#include <QtCore/qmath.h>
-
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*!
* \class Q3DScene
* \inmodule QtDataVisualization
* \brief Q3DScene class provides description of the 3D scene being visualized.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* The 3D scene contains a single active camera and a single active light source.
* Visualized data is assumed to be at a fixed location.
@@ -260,8 +255,12 @@ void Q3DScene::setSecondarySubViewport(const QRect &secondarySubViewport)
*
* This property contains the coordinates for the user input that should be processed
* by the scene as selection. If this is set to value other than invalidSelectionPoint() the
- * graph tries to select a data item at the given \a point within the primary viewport.
- * After the rendering pass the property is returned to its default state of invalidSelectionPoint().
+ * graph tries to select a data item, axis label, or a custom item at the given \a point within
+ * the primary viewport.
+ * After the rendering pass the property is returned to its default state of
+ * invalidSelectionPoint().
+ *
+ * \sa QAbstract3DGraph::selectedElement
*/
void Q3DScene::setSelectionQueryPosition(const QPoint &point)
{
@@ -411,6 +410,7 @@ void Q3DScene::setActiveLight(Q3DLight *light)
d_ptr->m_sceneDirty = true;
emit activeLightChanged(light);
+ emit d_ptr->needRender();
}
}
@@ -554,7 +554,6 @@ void Q3DScenePrivate::setWindowSize(const QSize &size)
m_windowSize = size;
updateGLViewport();
m_changeTracker.windowSizeChanged = true;
- m_sceneDirty = true;
emit needRender();
}
}
diff --git a/src/datavisualization/engine/q3dscene.h b/src/datavisualization/engine/q3dscene.h
index d663744e..1699b125 100644
--- a/src/datavisualization/engine/q3dscene.h
+++ b/src/datavisualization/engine/q3dscene.h
@@ -93,7 +93,9 @@ private:
friend class AbstractDeclarative;
friend class QAbstract3DGraph;
+ friend class QAbstract3DGraphPrivate;
friend class Abstract3DController;
+ friend class Bars3DController;
friend class Q3DScenePrivate;
friend class Abstract3DRenderer;
friend class Bars3DRenderer;
diff --git a/src/datavisualization/engine/q3dscene_p.h b/src/datavisualization/engine/q3dscene_p.h
index bc6a7223..2c69e5e0 100644
--- a/src/datavisualization/engine/q3dscene_p.h
+++ b/src/datavisualization/engine/q3dscene_p.h
@@ -36,7 +36,6 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class Q3DCamera;
class Q3DLight;
-class Q3DScene;
struct Q3DSceneChangeBitField {
bool viewportChanged : 1;
diff --git a/src/datavisualization/engine/q3dsurface.cpp b/src/datavisualization/engine/q3dsurface.cpp
index 7724cb24..162b7a67 100644
--- a/src/datavisualization/engine/q3dsurface.cpp
+++ b/src/datavisualization/engine/q3dsurface.cpp
@@ -18,10 +18,6 @@
#include "q3dsurface.h"
#include "q3dsurface_p.h"
-#include "qvalue3daxis.h"
-#include "qsurfacedataproxy.h"
-#include "q3dcamera.h"
-#include "qsurface3dseries_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -29,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class Q3DSurface
* \inmodule QtDataVisualization
* \brief The Q3DSurface class provides methods for rendering 3D surface plots.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* This class enables developers to render 3D surface plots and to view them by rotating the scene
* freely. The visual properties of the surface such as draw mode and shading can be controlled
diff --git a/src/datavisualization/engine/qabstract3dgraph.cpp b/src/datavisualization/engine/qabstract3dgraph.cpp
index bde5b585..dabec744 100644
--- a/src/datavisualization/engine/qabstract3dgraph.cpp
+++ b/src/datavisualization/engine/qabstract3dgraph.cpp
@@ -27,6 +27,8 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLPaintDevice>
#include <QtGui/QPainter>
+#include <QtGui/QOpenGLFramebufferObject>
+#include <QtGui/QOffscreenSurface>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -34,7 +36,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QAbstract3DGraph
* \inmodule QtDataVisualization
* \brief The QAbstract3DGraph class provides a window and render loop for graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* This class subclasses a QWindow and provides render loop for graphs inheriting it.
*
@@ -118,6 +120,38 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*/
/*!
+ \enum QAbstract3DGraph::ElementType
+ \since QtDataVisualization 1.1
+
+ Type of an element in the graph.
+
+ \value ElementNone
+ No defined element.
+ \value ElementSeries
+ A series (i.e. an item in a series).
+ \value ElementAxisXLabel
+ X axis label.
+ \value ElementAxisYLabel
+ Y axis label.
+ \value ElementAxisZLabel
+ Z axis label.
+ \value ElementCustomItem
+ Custom item.
+*/
+
+/*!
+ \enum QAbstract3DGraph::OptimizationHint
+ \since Qt Data Visualization 1.1
+
+ The optimization hint for rendering.
+
+ \value OptimizationDefault
+ Provides the full feature set at a reasonable performance.
+ \value OptimizationStatic
+ Beta level feature. Optimizes the rendering of static data sets at the expense of some features.
+*/
+
+/*!
* \internal
*/
QAbstract3DGraph::QAbstract3DGraph(QAbstract3DGraphPrivate *d, const QSurfaceFormat *format,
@@ -126,6 +160,7 @@ QAbstract3DGraph::QAbstract3DGraph(QAbstract3DGraphPrivate *d, const QSurfaceFor
d_ptr(d)
{
qRegisterMetaType<QAbstract3DGraph::ShadowQuality>("QAbstract3DGraph::ShadowQuality");
+ qRegisterMetaType<QAbstract3DGraph::ElementType>("QAbstract3DGraph::ElementType");
// Default to frameless window, as typically graphs are not toplevel
setFlags(flags() | Qt::FramelessWindowHint);
@@ -164,7 +199,8 @@ QAbstract3DGraph::QAbstract3DGraph(QAbstract3DGraphPrivate *d, const QSurfaceFor
#if !defined(QT_OPENGL_ES_2)
// If we have real OpenGL, GLSL version must be 1.2 or over. Quit if not.
- QStringList splitversionstr = QString::fromLatin1((const char *)shaderVersion).split(QChar::fromLatin1(' '));
+ QStringList splitversionstr =
+ QString::fromLatin1((const char *)shaderVersion).split(QChar::fromLatin1(' '));
if (splitversionstr[0].toFloat() < 1.2)
qFatal("GLSL version must be 1.20 or higher. Try installing latest display drivers.");
#else
@@ -342,7 +378,8 @@ bool QAbstract3DGraph::shadowsSupported() const
/*!
* \property QAbstract3DGraph::scene
*
- * This property contains the read only Q3DScene that can be used to access, for example, a camera object.
+ * This property contains the read only Q3DScene that can be used to access, for example, a camera
+ * object.
*/
Q3DScene *QAbstract3DGraph::scene() const
{
@@ -358,6 +395,257 @@ void QAbstract3DGraph::clearSelection()
}
/*!
+ * Adds a QCustom3DItem \a item to the graph. Graph takes ownership of the added item.
+ *
+ * \return index to the added item if add was successful, -1 if trying to add a null item, and
+ * index of the item if trying to add an already added item.
+ *
+ * \sa removeCustomItems(), removeCustomItem(), removeCustomItemAt()
+ *
+ * \since QtDataVisualization 1.1
+ */
+int QAbstract3DGraph::addCustomItem(QCustom3DItem *item)
+{
+ return d_ptr->m_visualController->addCustomItem(item);
+}
+
+/*!
+ * Removes all custom items. Deletes the resources allocated to them.
+ *
+ * \since QtDataVisualization 1.1
+ */
+void QAbstract3DGraph::removeCustomItems()
+{
+ d_ptr->m_visualController->deleteCustomItems();
+}
+
+/*!
+ * Removes the custom \a {item}. Deletes the resources allocated to it.
+ *
+ * \since QtDataVisualization 1.1
+ */
+void QAbstract3DGraph::removeCustomItem(QCustom3DItem *item)
+{
+ d_ptr->m_visualController->deleteCustomItem(item);
+}
+
+/*!
+ * Removes all custom items at \a {position}. Deletes the resources allocated to them.
+ *
+ * \since QtDataVisualization 1.1
+ */
+void QAbstract3DGraph::removeCustomItemAt(const QVector3D &position)
+{
+ d_ptr->m_visualController->deleteCustomItem(position);
+}
+
+/*!
+ * Gets ownership of given \a item back and removes the \a item from the graph.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \note If the same item is added back to the graph, the texture or the texture file needs to be
+ * re-set.
+ *
+ * \sa QCustom3DItem::setTextureImage(), QCustom3DItem::setTextureFile()
+ */
+void QAbstract3DGraph::releaseCustomItem(QCustom3DItem *item)
+{
+ return d_ptr->m_visualController->releaseCustomItem(item);
+}
+
+/*!
+ * Can be used to query the index of the selected label after receiving \c selectedElementChanged
+ * signal with any label type. Selection is valid until the next \c selectedElementChanged signal.
+ *
+ * \return index of the selected label, or -1.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+int QAbstract3DGraph::selectedLabelIndex() const
+{
+ return d_ptr->m_visualController->selectedLabelIndex();
+}
+
+/*!
+ * Can be used to get the selected axis after receiving \c selectedElementChanged signal with any label
+ * type. Selection is valid until the next \c selectedElementChanged signal.
+ *
+ * \return pointer to the selected axis, or null.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+QAbstract3DAxis *QAbstract3DGraph::selectedAxis() const
+{
+ return d_ptr->m_visualController->selectedAxis();
+}
+
+/*!
+ * Can be used to query the index of the selected custom item after receiving \c selectedElementChanged
+ * signal with QAbstract3DGraph::ElementCustomItem type. Selection is valid until the next
+ * \c selectedElementChanged signal.
+ *
+ * \return index of the selected custom item, or -1.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+int QAbstract3DGraph::selectedCustomItemIndex() const
+{
+ return d_ptr->m_visualController->selectedCustomItemIndex();
+}
+
+/*!
+ * Can be used to get the selected custom item after receiving \c selectedElementChanged signal with
+ * QAbstract3DGraph::ElementCustomItem type. Ownership of the item remains with the graph.
+ * Selection is valid until the next \c selectedElementChanged signal.
+ *
+ * \return pointer to the selected custom item, or null.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \sa selectedElement
+ */
+QCustom3DItem *QAbstract3DGraph::selectedCustomItem() const
+{
+ return d_ptr->m_visualController->selectedCustomItem();
+}
+
+/*!
+ * \property QAbstract3DGraph::selectedElement
+ *
+ * Can be used to query the selected element type.
+ * Type is valid until the next \c selectedElementChanged signal.
+ *
+ * \c selectedElementChanged signal is emitted when a selection is made in the graph.
+ *
+ * Signal can be used for example for implementing custom input handlers, as demonstrated in this
+ * \l {Axis Range Dragging With Labels Example}{example}.
+ *
+ * \sa selectedLabelIndex(), selectedAxis(), selectedCustomItemIndex(), selectedCustomItem(),
+ * Q3DBars::selectedSeries(), Q3DScatter::selectedSeries(), Q3DSurface::selectedSeries(),
+ * Q3DScene::setSelectionQueryPosition()
+ *
+ * \since QtDataVisualization 1.1
+ */
+QAbstract3DGraph::ElementType QAbstract3DGraph::selectedElement() const
+{
+ return d_ptr->m_visualController->selectedElement();
+}
+
+/*!
+ * Renders current frame to an image of \a imageSize. Default size is the window size. Image is
+ * rendered with antialiasing level given in \a msaaSamples. Default level is \c{0}.
+ *
+ * \since QtDataVisualization 1.1
+ *
+ * \return rendered image.
+ */
+QImage QAbstract3DGraph::renderToImage(int msaaSamples, const QSize &imageSize)
+{
+ QSize renderSize = imageSize;
+ if (renderSize.isEmpty())
+ renderSize = size();
+ return d_ptr->renderToImage(msaaSamples, renderSize);
+}
+
+/*!
+ * \property QAbstract3DGraph::measureFps
+ * \since QtDataVisualization 1.1
+ *
+ * If \c {true}, the rendering is done continuously instead of on demand, and currentFps property
+ * is updated. Defaults to \c{false}.
+ *
+ * \sa currentFps
+ */
+void QAbstract3DGraph::setMeasureFps(bool enable)
+{
+ d_ptr->m_visualController->setMeasureFps(enable);
+}
+
+bool QAbstract3DGraph::measureFps() const
+{
+ return d_ptr->m_visualController->measureFps();
+}
+
+/*!
+ * \property QAbstract3DGraph::currentFps
+ * \since QtDataVisualization 1.1
+ *
+ * When fps measuring is enabled, the results for the last second are stored in this read-only
+ * property. It takes at least a second before this value updates after measurement is activated.
+ *
+ * \sa measureFps
+ */
+qreal QAbstract3DGraph::currentFps() const
+{
+ return d_ptr->m_visualController->currentFps();
+}
+
+/*!
+ * \property QAbstract3DGraph::orthoProjection
+ * \since QtDataVisualization 1.1
+ *
+ * If \c {true}, orthographic projection will be used for displaying the graph. Defaults to \c{false}.
+ * \note Shadows will be disabled when set to \c{true}.
+ */
+void QAbstract3DGraph::setOrthoProjection(bool enable)
+{
+ d_ptr->m_visualController->setOrthoProjection(enable);
+}
+
+bool QAbstract3DGraph::isOrthoProjection() const
+{
+ return d_ptr->m_visualController->isOrthoProjection();
+}
+
+/*!
+ * \property QAbstract3DGraph::aspectRatio
+ * \since QtDataVisualization 1.1
+ *
+ * Aspect ratio of the graph data. This is the ratio of data scaling between horizontal and
+ * vertical axes. Defaults to \c{2.0}.
+ *
+ * \note Has no effect on Q3DBars.
+ */
+void QAbstract3DGraph::setAspectRatio(qreal ratio)
+{
+ d_ptr->m_visualController->setAspectRatio(float(ratio));
+}
+
+qreal QAbstract3DGraph::aspectRatio() const
+{
+ return d_ptr->m_visualController->aspectRatio();
+}
+
+/*!
+ * \property QAbstract3DGraph::optimizationHints
+ *
+ * Defines if the rendering optimization is default or static. Default mode provides the full feature set at
+ * reasonable performance. Static is a beta level feature and currently supports only a subset of the
+ * features on the Scatter graph. Missing features are object gradient for mesh objects, both gradients
+ * for points, and diffuse and specular color on rotations. At this point static is intended just for
+ * introducing a new feature. It optimizes graph rendering and is ideal for large non-changing data
+ * sets. It is slower with dynamic data changes and item rotations. Selection is not optimized, so using it
+ * with massive data sets is not advisable.
+ * Defaults to \c{OptimizationDefault}.
+ */
+void QAbstract3DGraph::setOptimizationHints(OptimizationHints hints)
+{
+ d_ptr->m_visualController->setOptimizationHints(hints);
+}
+
+QAbstract3DGraph::OptimizationHints QAbstract3DGraph::optimizationHints() const
+{
+ return d_ptr->m_visualController->optimizationHints();
+}
+
+/*!
* \internal
*/
bool QAbstract3DGraph::event(QEvent *event)
@@ -453,12 +741,17 @@ QAbstract3DGraphPrivate::QAbstract3DGraphPrivate(QAbstract3DGraph *q)
q_ptr(q),
m_updatePending(false),
m_visualController(0),
- m_devicePixelRatio(1.f)
+ m_devicePixelRatio(1.f),
+ m_offscreenSurface(0)
{
}
QAbstract3DGraphPrivate::~QAbstract3DGraphPrivate()
{
+ if (m_offscreenSurface) {
+ m_offscreenSurface->destroy();
+ delete m_offscreenSurface;
+ }
if (m_context)
m_context->makeCurrent(q_ptr);
@@ -477,6 +770,11 @@ void QAbstract3DGraphPrivate::setVisualController(Abstract3DController *controll
&QAbstract3DGraph::selectionModeChanged);
QObject::connect(m_visualController, &Abstract3DController::shadowQualityChanged, q_ptr,
&QAbstract3DGraph::shadowQualityChanged);
+ QObject::connect(m_visualController, &Abstract3DController::optimizationHintsChanged, q_ptr,
+ &QAbstract3DGraph::optimizationHintsChanged);
+ QObject::connect(m_visualController, &Abstract3DController::elementSelected, q_ptr,
+ &QAbstract3DGraph::selectedElementChanged);
+
QObject::connect(m_visualController, &Abstract3DController::needRender, this,
&QAbstract3DGraphPrivate::renderLater);
@@ -486,6 +784,17 @@ void QAbstract3DGraphPrivate::setVisualController(Abstract3DController *controll
&QAbstract3DGraphPrivate::handleAxisYChanged);
QObject::connect(m_visualController, &Abstract3DController::axisZChanged, this,
&QAbstract3DGraphPrivate::handleAxisZChanged);
+
+ QObject::connect(m_visualController, &Abstract3DController::measureFpsChanged, q_ptr,
+ &QAbstract3DGraph::measureFpsChanged);
+ QObject::connect(m_visualController, &Abstract3DController::currentFpsChanged, q_ptr,
+ &QAbstract3DGraph::currentFpsChanged);
+
+ QObject::connect(m_visualController, &Abstract3DController::orthoProjectionChanged, q_ptr,
+ &QAbstract3DGraph::orthoProjectionChanged);
+
+ QObject::connect(m_visualController, &Abstract3DController::aspectRatioChanged, q_ptr,
+ &QAbstract3DGraph::aspectRatioChanged);
}
void QAbstract3DGraphPrivate::handleDevicePixelRatioChange()
@@ -526,4 +835,42 @@ void QAbstract3DGraphPrivate::renderNow()
m_context->swapBuffers(q_ptr);
}
+QImage QAbstract3DGraphPrivate::renderToImage(int msaaSamples, const QSize &imageSize)
+{
+ QImage image;
+ QOpenGLFramebufferObject *fbo;
+ QOpenGLFramebufferObjectFormat fboFormat;
+ if (!m_offscreenSurface) {
+ // Create an offscreen surface for rendering to images without rendering on screen
+ m_offscreenSurface = new QOffscreenSurface(q_ptr->screen());
+ m_offscreenSurface->setFormat(q_ptr->requestedFormat());
+ m_offscreenSurface->create();
+ }
+ // Render the wanted frame offscreen
+ m_context->makeCurrent(m_offscreenSurface);
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fboFormat.setInternalTextureFormat(GL_RGB);
+ fboFormat.setSamples(msaaSamples);
+ fbo = new QOpenGLFramebufferObject(imageSize, fboFormat);
+ if (fbo->isValid()) {
+ QRect originalViewport = m_visualController->m_scene->viewport();
+ m_visualController->m_scene->d_ptr->setWindowSize(imageSize);
+ m_visualController->m_scene->d_ptr->setViewport(QRect(0, 0,
+ imageSize.width(),
+ imageSize.height()));
+ m_visualController->synchDataToRenderer();
+ fbo->bind();
+ m_context->swapBuffers(m_offscreenSurface);
+ m_visualController->requestRender(fbo);
+ image = fbo->toImage();
+ fbo->release();
+ m_visualController->m_scene->d_ptr->setWindowSize(originalViewport.size());
+ m_visualController->m_scene->d_ptr->setViewport(originalViewport);
+ }
+ delete fbo;
+ m_context->makeCurrent(q_ptr);
+
+ return image;
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/qabstract3dgraph.h b/src/datavisualization/engine/qabstract3dgraph.h
index 18eda7df..59f61aae 100644
--- a/src/datavisualization/engine/qabstract3dgraph.h
+++ b/src/datavisualization/engine/qabstract3dgraph.h
@@ -29,20 +29,31 @@
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QAbstract3DGraphPrivate;
+class QCustom3DItem;
+class QAbstract3DAxis;
class QT_DATAVISUALIZATION_EXPORT QAbstract3DGraph : public QWindow, protected QOpenGLFunctions
{
Q_OBJECT
Q_ENUMS(ShadowQuality)
+ Q_ENUMS(ElementType)
Q_FLAGS(SelectionFlag SelectionFlags)
+ Q_FLAGS(OptimizationHint OptimizationHints)
Q_PROPERTY(QAbstract3DInputHandler* activeInputHandler READ activeInputHandler WRITE setActiveInputHandler NOTIFY activeInputHandlerChanged)
Q_PROPERTY(Q3DTheme* activeTheme READ activeTheme WRITE setActiveTheme NOTIFY activeThemeChanged)
Q_PROPERTY(SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode NOTIFY selectionModeChanged)
Q_PROPERTY(ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality NOTIFY shadowQualityChanged)
Q_PROPERTY(Q3DScene* scene READ scene)
+ Q_PROPERTY(bool measureFps READ measureFps WRITE setMeasureFps NOTIFY measureFpsChanged)
+ Q_PROPERTY(qreal currentFps READ currentFps NOTIFY currentFpsChanged)
+ Q_PROPERTY(bool orthoProjection READ isOrthoProjection WRITE setOrthoProjection NOTIFY orthoProjectionChanged)
+ Q_PROPERTY(ElementType selectedElement READ selectedElement NOTIFY selectedElementChanged)
+ Q_PROPERTY(qreal aspectRatio READ aspectRatio WRITE setAspectRatio NOTIFY aspectRatioChanged)
+ Q_PROPERTY(OptimizationHints optimizationHints READ optimizationHints WRITE setOptimizationHints NOTIFY optimizationHintsChanged)
protected:
- explicit QAbstract3DGraph(QAbstract3DGraphPrivate *d, const QSurfaceFormat *format, QWindow *parent = 0);
+ explicit QAbstract3DGraph(QAbstract3DGraphPrivate *d, const QSurfaceFormat *format,
+ QWindow *parent = 0);
public:
enum SelectionFlag {
@@ -69,6 +80,21 @@ public:
ShadowQualitySoftHigh
};
+ enum ElementType {
+ ElementNone = 0,
+ ElementSeries,
+ ElementAxisXLabel,
+ ElementAxisYLabel,
+ ElementAxisZLabel,
+ ElementCustomItem
+ };
+
+ enum OptimizationHint {
+ OptimizationDefault = 0,
+ OptimizationStatic = 1
+ };
+ Q_DECLARE_FLAGS(OptimizationHints, OptimizationHint)
+
public:
virtual ~QAbstract3DGraph();
@@ -95,6 +121,35 @@ public:
void clearSelection();
+ int addCustomItem(QCustom3DItem *item);
+ void removeCustomItems();
+ void removeCustomItem(QCustom3DItem *item);
+ void removeCustomItemAt(const QVector3D &position);
+ void releaseCustomItem(QCustom3DItem *item);
+
+ int selectedLabelIndex() const;
+ QAbstract3DAxis *selectedAxis() const;
+
+ int selectedCustomItemIndex() const;
+ QCustom3DItem *selectedCustomItem() const;
+
+ QImage renderToImage(int msaaSamples = 0, const QSize &imageSize = QSize());
+
+ void setMeasureFps(bool enable);
+ bool measureFps() const;
+ qreal currentFps() const;
+
+ void setOrthoProjection(bool enable);
+ bool isOrthoProjection() const;
+
+ ElementType selectedElement() const;
+
+ void setAspectRatio(qreal ratio);
+ qreal aspectRatio() const;
+
+ void setOptimizationHints(OptimizationHints hints);
+ OptimizationHints optimizationHints() const;
+
protected:
bool event(QEvent *event);
void resizeEvent(QResizeEvent *event);
@@ -107,12 +162,17 @@ protected:
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
-
signals:
void activeInputHandlerChanged(QAbstract3DInputHandler *inputHandler);
void activeThemeChanged(Q3DTheme *theme);
void selectionModeChanged(QAbstract3DGraph::SelectionFlags mode);
void shadowQualityChanged(QAbstract3DGraph::ShadowQuality quality);
+ void selectedElementChanged(QAbstract3DGraph::ElementType type);
+ void measureFpsChanged(bool enabled);
+ void currentFpsChanged(qreal fps);
+ void orthoProjectionChanged(bool enabled);
+ void aspectRatioChanged(qreal ratio);
+ void optimizationHintsChanged(QAbstract3DGraph::OptimizationHints hints);
private:
Q_DISABLE_COPY(QAbstract3DGraph)
@@ -123,6 +183,7 @@ private:
friend class Q3DSurface;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstract3DGraph::SelectionFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstract3DGraph::OptimizationHints)
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/qabstract3dgraph_p.h b/src/datavisualization/engine/qabstract3dgraph_p.h
index d28495ab..a8b0965a 100644
--- a/src/datavisualization/engine/qabstract3dgraph_p.h
+++ b/src/datavisualization/engine/qabstract3dgraph_p.h
@@ -32,7 +32,7 @@
#include "datavisualizationglobal_p.h"
class QOpenGLContext;
-class QOpenGLPaintDevice;
+class QOffscreenSurface;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -52,6 +52,8 @@ public:
void render();
+ QImage renderToImage(int msaaSamples, const QSize &imageSize);
+
public slots:
void renderLater();
void renderNow();
@@ -67,6 +69,7 @@ public:
QOpenGLContext *m_context;
Abstract3DController *m_visualController;
float m_devicePixelRatio;
+ QOffscreenSurface *m_offscreenSurface;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/scatter3dcontroller.cpp b/src/datavisualization/engine/scatter3dcontroller.cpp
index 54292ac0..da40fc85 100644
--- a/src/datavisualization/engine/scatter3dcontroller.cpp
+++ b/src/datavisualization/engine/scatter3dcontroller.cpp
@@ -18,15 +18,10 @@
#include "scatter3dcontroller_p.h"
#include "scatter3drenderer_p.h"
-#include "camerahelper_p.h"
-#include "qabstract3daxis_p.h"
#include "qvalue3daxis_p.h"
#include "qscatterdataproxy_p.h"
#include "qscatter3dseries_p.h"
-#include <QtGui/QMatrix4x4>
-#include <QtCore/qmath.h>
-
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
static const int insertRemoveRecordReserveSize = 31;
@@ -71,6 +66,12 @@ void Scatter3DController::synchDataToRenderer()
Abstract3DController::synchDataToRenderer();
// Notify changes to renderer
+ if (m_changeTracker.itemChanged) {
+ m_renderer->updateItems(m_changedItems);
+ m_changeTracker.itemChanged = false;
+ m_changedItems.clear();
+ }
+
if (m_changeTracker.selectedItemChanged) {
m_renderer->updateSelectedItem(m_selectedItem, m_selectedItemSeries);
m_changeTracker.selectedItemChanged = false;
@@ -83,9 +84,6 @@ void Scatter3DController::addSeries(QAbstract3DSeries *series)
Abstract3DController::addSeries(series);
- if (series->isVisible())
- adjustValueAxisRange();
-
QScatter3DSeries *scatterSeries = static_cast<QScatter3DSeries *>(series);
if (scatterSeries->selectedItem() != invalidSelectionIndex())
setSelectedItem(scatterSeries->selectedItem(), scatterSeries);
@@ -101,7 +99,7 @@ void Scatter3DController::removeSeries(QAbstract3DSeries *series)
setSelectedItem(invalidSelectionIndex(), 0);
if (wasVisible)
- adjustValueAxisRange();
+ adjustAxisRanges();
}
QList<QScatter3DSeries *> Scatter3DController::scatterSeriesList()
@@ -121,10 +119,13 @@ void Scatter3DController::handleArrayReset()
{
QScatter3DSeries *series = static_cast<QScatterDataProxy *>(sender())->series();
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
setSelectedItem(m_selectedItem, m_selectedItemSeries);
+ series->d_ptr->markItemLabelDirty();
emitNeedRender();
}
@@ -134,22 +135,45 @@ void Scatter3DController::handleItemsAdded(int startIndex, int count)
Q_UNUSED(count)
QScatter3DSeries *series = static_cast<QScatterDataProxy *>(sender())->series();
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
void Scatter3DController::handleItemsChanged(int startIndex, int count)
{
- Q_UNUSED(startIndex)
- Q_UNUSED(count)
QScatter3DSeries *series = static_cast<QScatterDataProxy *>(sender())->series();
- if (series->isVisible()) {
- adjustValueAxisRange();
- m_isDataDirty = true;
+ int oldChangeCount = m_changedItems.size();
+ if (!oldChangeCount)
+ m_changedItems.reserve(count);
+
+ for (int i = 0; i < count; i++) {
+ bool newItem = true;
+ int candidate = startIndex + i;
+ for (int j = 0; j < oldChangeCount; j++) {
+ const ChangeItem &oldChangeItem = m_changedItems.at(j);
+ if (oldChangeItem.index == candidate && series == oldChangeItem.series) {
+ newItem = false;
+ break;
+ }
+ }
+ if (newItem) {
+ ChangeItem newChangeItem = {series, candidate};
+ m_changedItems.append(newChangeItem);
+ if (series == m_selectedItemSeries && m_selectedItem == candidate)
+ series->d_ptr->markItemLabelDirty();
+ }
+ }
+
+ if (count) {
+ m_changeTracker.itemChanged = true;
+ if (series->isVisible())
+ adjustAxisRanges();
+ emitNeedRender();
}
- emitNeedRender();
}
void Scatter3DController::handleItemsRemoved(int startIndex, int count)
@@ -171,9 +195,11 @@ void Scatter3DController::handleItemsRemoved(int startIndex, int count)
}
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
if (m_recordInsertsAndRemoves) {
InsertRemoveRecord record(false, startIndex, count, series);
@@ -198,9 +224,11 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count)
}
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
if (m_recordInsertsAndRemoves) {
InsertRemoveRecord record(true, startIndex, count, series);
@@ -229,7 +257,7 @@ void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation(
{
Q_UNUSED(orientation)
Q_UNUSED(autoAdjust)
- adjustValueAxisRange();
+ adjustAxisRanges();
}
void Scatter3DController::handleAxisRangeChangedBySender(QObject *sender)
@@ -240,13 +268,6 @@ void Scatter3DController::handleAxisRangeChangedBySender(QObject *sender)
setSelectedItem(m_selectedItem, m_selectedItemSeries);
}
-void Scatter3DController::handleSeriesVisibilityChangedBySender(QObject *sender)
-{
- Abstract3DController::handleSeriesVisibilityChangedBySender(sender);
-
- adjustValueAxisRange();
-}
-
void Scatter3DController::handlePendingClick()
{
int index = m_renderer->clickedIndex();
@@ -274,6 +295,8 @@ void Scatter3DController::handlePendingClick()
setSelectedItem(index, series);
+ Abstract3DController::handlePendingClick();
+
m_renderer->resetClickedStatus();
}
@@ -329,7 +352,7 @@ void Scatter3DController::clearSelection()
setSelectedItem(invalidSelectionIndex(), 0);
}
-void Scatter3DController::adjustValueAxisRange()
+void Scatter3DController::adjustAxisRanges()
{
QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX);
QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY);
@@ -407,7 +430,7 @@ void Scatter3DController::adjustValueAxisRange()
adjustment = defaultAdjustment;
}
}
- valueAxisX->dptr()->setRange(minValueX - adjustment, maxValueX + adjustment);
+ valueAxisX->dptr()->setRange(minValueX - adjustment, maxValueX + adjustment, true);
}
if (adjustY) {
// If all points at same coordinate, need to default to some valid range
@@ -415,7 +438,7 @@ void Scatter3DController::adjustValueAxisRange()
float adjustment = 0.0f;
if (minValueY == maxValueY)
adjustment = defaultAdjustment;
- valueAxisY->dptr()->setRange(minValueY - adjustment, maxValueY + adjustment);
+ valueAxisY->dptr()->setRange(minValueY - adjustment, maxValueY + adjustment, true);
}
if (adjustZ) {
// If all points at same coordinate, need to default to some valid range
@@ -434,7 +457,7 @@ void Scatter3DController::adjustValueAxisRange()
adjustment = defaultAdjustment;
}
}
- valueAxisZ->dptr()->setRange(minValueZ - adjustment, maxValueZ + adjustment);
+ valueAxisZ->dptr()->setRange(minValueZ - adjustment, maxValueZ + adjustment, true);
}
}
}
diff --git a/src/datavisualization/engine/scatter3dcontroller_p.h b/src/datavisualization/engine/scatter3dcontroller_p.h
index 53d24549..db5a95f5 100644
--- a/src/datavisualization/engine/scatter3dcontroller_p.h
+++ b/src/datavisualization/engine/scatter3dcontroller_p.h
@@ -40,9 +40,11 @@ class QScatter3DSeries;
struct Scatter3DChangeBitField {
bool selectedItemChanged : 1;
+ bool itemChanged : 1;
Scatter3DChangeBitField() :
- selectedItemChanged(true)
+ selectedItemChanged(true),
+ itemChanged(false)
{
}
};
@@ -51,8 +53,14 @@ class QT_DATAVISUALIZATION_EXPORT Scatter3DController : public Abstract3DControl
{
Q_OBJECT
+public:
+ struct ChangeItem {
+ QScatter3DSeries *series;
+ int index;
+ };
private:
Scatter3DChangeBitField m_changeTracker;
+ QVector<ChangeItem> m_changedItems;
// Rendering
Scatter3DRenderer *m_renderer;
@@ -108,8 +116,8 @@ public:
virtual void handleAxisAutoAdjustRangeChangedInOrientation(
QAbstract3DAxis::AxisOrientation orientation, bool autoAdjust);
virtual void handleAxisRangeChangedBySender(QObject *sender);
- virtual void handleSeriesVisibilityChangedBySender(QObject *sender);
virtual void handlePendingClick();
+ virtual void adjustAxisRanges();
public slots:
void handleArrayReset();
@@ -125,7 +133,6 @@ protected:
virtual void startRecordingRemovesAndInserts();
private:
- void adjustValueAxisRange();
Q_DISABLE_COPY(Scatter3DController)
};
diff --git a/src/datavisualization/engine/scatter3drenderer.cpp b/src/datavisualization/engine/scatter3drenderer.cpp
index de1a769a..21d86d03 100644
--- a/src/datavisualization/engine/scatter3drenderer.cpp
+++ b/src/datavisualization/engine/scatter3drenderer.cpp
@@ -17,25 +17,16 @@
****************************************************************************/
#include "scatter3drenderer_p.h"
-#include "scatter3dcontroller_p.h"
-#include "q3dcamera.h"
#include "q3dcamera_p.h"
#include "shaderhelper_p.h"
-#include "objecthelper_p.h"
#include "texturehelper_p.h"
#include "utils_p.h"
-#include "q3dlight.h"
-#include "qscatter3dseries_p.h"
+#include "scatterseriesrendercache_p.h"
+#include "scatterobjectbufferhelper_p.h"
+#include "scatterpointbufferhelper_p.h"
-#include <QtGui/QMatrix4x4>
-#include <QtGui/QMouseEvent>
-#include <QtCore/QThread>
#include <QtCore/qmath.h>
-// Commenting this draws the shadow map with perspective projection. Otherwise it's drawn in
-// orthographic projection.
-//#define USE_WIDER_SHADOWS
-
// You can verify that depth buffer drawing works correctly by uncommenting this.
// You should see the scene from where the light is
//#define SHOW_DEPTH_TEXTURE_SCENE
@@ -44,20 +35,14 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
//#define USE_UNIFORM_SCALING // Scale x and z uniformly, or based on autoscaled values
-const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd.
-const GLfloat labelMargin = 0.05f;
const GLfloat defaultMinSize = 0.01f;
const GLfloat defaultMaxSize = 0.1f;
-const GLfloat defaultMargin = 1.0f + defaultMaxSize; // Default margin for background
const GLfloat itemScaler = 3.0f;
const GLfloat gridLineWidth = 0.005f;
Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller)
: Abstract3DRenderer(controller),
m_selectedItem(0),
- m_xFlipped(false),
- m_zFlipped(false),
- m_yFlipped(false),
m_updateLabels(false),
m_dotShader(0),
m_dotGradientShader(0),
@@ -68,9 +53,6 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller)
m_selectionShader(0),
m_backgroundShader(0),
m_labelShader(0),
- m_backgroundObj(0),
- m_gridLineObj(0),
- m_labelObj(0),
m_bgrTexture(0),
m_depthTexture(0),
m_selectionTexture(0),
@@ -82,16 +64,22 @@ Scatter3DRenderer::Scatter3DRenderer(Scatter3DController *controller)
m_heightNormalizer(1.0f),
m_scaleFactor(0),
m_selectedItemIndex(Scatter3DController::invalidSelectionIndex()),
- m_selectedItemTotalIndex(Scatter3DController::invalidSelectionIndex()),
- m_selectedItemSeriesIndex(Scatter3DController::invalidSelectionIndex()),
- m_selectedSeries(0),
+ m_selectedSeriesCache(0),
+ m_oldSelectedSeriesCache(0),
m_areaSize(QSizeF(0.0, 0.0)),
m_dotSizeScale(1.0f),
m_hasHeightAdjustmentChanged(true),
- m_backgroundMargin(defaultMargin),
+ m_backgroundMargin(defaultMaxSize),
m_maxItemSize(0.0f),
- m_clickedIndex(Scatter3DController::invalidSelectionIndex())
+ m_clickedIndex(Scatter3DController::invalidSelectionIndex()),
+ m_havePointSeries(false),
+ m_haveMeshSeries(false),
+ m_haveUniformColorMeshSeries(false),
+ m_haveGradientMeshSeries(false)
{
+ m_axisCacheY.setScale(2.0f);
+ m_axisCacheY.setTranslate(-1.0f);
+
initializeOpenGLFunctions();
initializeOpenGL();
}
@@ -111,9 +99,6 @@ Scatter3DRenderer::~Scatter3DRenderer()
delete m_selectionShader;
delete m_backgroundShader;
delete m_labelShader;
- delete m_backgroundObj;
- delete m_gridLineObj;
- delete m_labelObj;
}
void Scatter3DRenderer::initializeOpenGL()
@@ -135,8 +120,10 @@ void Scatter3DRenderer::initializeOpenGL()
// Init selection shader
initSelectionShader();
+#if !defined(QT_OPENGL_ES_2)
// Load grid line mesh
loadGridLineMesh();
+#endif
// Load label mesh
loadLabelMesh();
@@ -151,78 +138,153 @@ void Scatter3DRenderer::initializeOpenGL()
loadBackgroundMesh();
}
-void Scatter3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList,
- bool updateVisibility)
+void Scatter3DRenderer::updateData()
{
- Abstract3DRenderer::updateSeries(seriesList, updateVisibility);
+ calculateSceneScalingFactors();
+ int totalDataSize = 0;
- int seriesCount = m_visibleSeriesList.size();
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ ScatterSeriesRenderCache *cache = static_cast<ScatterSeriesRenderCache *>(baseCache);
+ if (cache->isVisible() && cache->dataDirty()) {
+ const QScatter3DSeries *currentSeries = cache->series();
+ ScatterRenderItemArray &renderArray = cache->renderArray();
+ QScatterDataProxy *dataProxy = currentSeries->dataProxy();
+ const QScatterDataArray &dataArray = *dataProxy->array();
+ int dataSize = dataArray.size();
+ totalDataSize += dataSize;
+ if (dataSize != renderArray.size())
+ renderArray.resize(dataSize);
+
+ for (int i = 0; i < dataSize; i++)
+ updateRenderItem(dataArray.at(i), renderArray[i]);
+ cache->setDataDirty(false);
+ }
+ }
+
+ if (totalDataSize) {
+ m_dotSizeScale = GLfloat(qBound(defaultMinSize, 2.0f / float(qSqrt(qreal(totalDataSize))),
+ defaultMaxSize));
+ }
+
+ if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic)) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ ScatterSeriesRenderCache *cache = static_cast<ScatterSeriesRenderCache *>(baseCache);
+ if (cache->isVisible()) {
+ ScatterRenderItemArray &renderArray = cache->renderArray();
+ const int renderArraySize = renderArray.size();
+
+ if (cache->mesh() == QAbstract3DSeries::MeshPoint) {
+ ScatterPointBufferHelper *points = cache->bufferPoints();
+ if (!points) {
+ points = new ScatterPointBufferHelper();
+ cache->setBufferPoints(points);
+ }
+ points->load(cache);
+ } else {
+ ScatterObjectBufferHelper *object = cache->bufferObject();
+ if (!object) {
+ object = new ScatterObjectBufferHelper();
+ cache->setBufferObject(object);
+ }
+ if (renderArraySize != cache->oldArraySize()
+ || cache->object()->objectFile() != cache->oldMeshFileName()) {
+ object->fullLoad(cache, m_dotSizeScale);
+ cache->setOldArraySize(renderArraySize);
+ cache->setOldMeshFileName(cache->object()->objectFile());
+ } else {
+ object->update(cache, m_dotSizeScale);
+ }
+ }
+ }
+ }
+ }
+
+ updateSelectedItem(m_selectedItemIndex,
+ m_selectedSeriesCache ? m_selectedSeriesCache->series() : 0);
+}
+
+void Scatter3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList)
+{
+ Abstract3DRenderer::updateSeries(seriesList);
+
+ int seriesCount = seriesList.size();
float maxItemSize = 0.0f;
float itemSize = 0.0f;
+ bool noSelection = true;
- if (m_cachedItemSize.size() != seriesCount)
- m_cachedItemSize.resize(seriesCount);
+ m_havePointSeries = false;
+ m_haveMeshSeries = false;
+ m_haveUniformColorMeshSeries = false;
+ m_haveGradientMeshSeries = false;
- for (int series = 0; series < seriesCount; series++) {
- itemSize = static_cast<QScatter3DSeries *>(m_visibleSeriesList.at(series).series())->itemSize();
- if (maxItemSize < itemSize)
- maxItemSize = itemSize;
- if (m_cachedItemSize.at(series) != itemSize)
- m_cachedItemSize[series] = itemSize;
+ for (int i = 0; i < seriesCount; i++) {
+ QScatter3DSeries *scatterSeries = static_cast<QScatter3DSeries *>(seriesList[i]);
+ if (scatterSeries->isVisible()) {
+ ScatterSeriesRenderCache *cache =
+ static_cast<ScatterSeriesRenderCache *>(m_renderCacheList.value(scatterSeries));
+ itemSize = scatterSeries->itemSize();
+ if (maxItemSize < itemSize)
+ maxItemSize = itemSize;
+ if (cache->itemSize() != itemSize)
+ cache->setItemSize(itemSize);
+ if (noSelection
+ && scatterSeries->selectedItem() != QScatter3DSeries::invalidSelectionIndex()) {
+ if (m_selectionLabel != cache->itemLabel())
+ m_selectionLabelDirty = true;
+ noSelection = false;
+ }
+
+ if (cache->mesh() == QAbstract3DSeries::MeshPoint) {
+ m_havePointSeries = true;
+ } else {
+ m_haveMeshSeries = true;
+ if (cache->colorStyle() == Q3DTheme::ColorStyleUniform)
+ m_haveUniformColorMeshSeries = true;
+ else
+ m_haveGradientMeshSeries = true;
+ }
+ }
}
- m_backgroundMargin = defaultMargin;
m_maxItemSize = maxItemSize;
if (maxItemSize > defaultMaxSize)
- m_backgroundMargin += maxItemSize / itemScaler;
+ m_backgroundMargin = maxItemSize / itemScaler;
+ else
+ m_backgroundMargin = defaultMaxSize;
+
+ if (noSelection) {
+ if (!selectionLabel().isEmpty())
+ m_selectionLabelDirty = true;
+ m_selectedSeriesCache = 0;
+ }
}
-void Scatter3DRenderer::updateData()
+SeriesRenderCache *Scatter3DRenderer::createNewCache(QAbstract3DSeries *series)
{
- int seriesCount = m_visibleSeriesList.size();
- calculateSceneScalingFactors();
- float minX = float(m_axisCacheX.min());
- float maxX = float(m_axisCacheX.max());
- float minY = float(m_axisCacheY.min());
- float maxY = float(m_axisCacheY.max());
- float minZ = float(m_axisCacheZ.min());
- float maxZ = float(m_axisCacheZ.max());
- int totalDataSize = 0;
+ return new ScatterSeriesRenderCache(series, this);
+}
- if (m_renderingArrays.size() != seriesCount)
- m_renderingArrays.resize(seriesCount);
-
- for (int series = 0; series < seriesCount; series++) {
- QScatterDataProxy *dataProxy =
- static_cast<QScatter3DSeries *>(m_visibleSeriesList.at(series).series())->dataProxy();
- const QScatterDataArray &dataArray = *dataProxy->array();
- int dataSize = dataArray.size();
- totalDataSize += dataSize;
-
- if (dataSize != m_renderingArrays.at(series).size())
- m_renderingArrays[series].resize(dataSize);
-
- for (int i = 0; i < dataSize; i++) {
- QVector3D dotPos = dataArray.at(i).position();
- ScatterRenderItem &renderItem = m_renderingArrays[series][i];
- if ((dotPos.x() >= minX && dotPos.x() <= maxX )
- && (dotPos.y() >= minY && dotPos.y() <= maxY)
- && (dotPos.z() >= minZ && dotPos.z() <= maxZ)) {
- renderItem.setPosition(dotPos);
- renderItem.setVisible(true);
- if (!dataArray.at(i).rotation().isIdentity())
- renderItem.setRotation(dataArray.at(i).rotation().normalized());
- else
- renderItem.setRotation(identityQuaternion);
- calculateTranslation(renderItem);
- } else {
- renderItem.setVisible(false);
- }
+void Scatter3DRenderer::updateItems(const QVector<Scatter3DController::ChangeItem> &items)
+{
+ ScatterSeriesRenderCache *cache = 0;
+ const QScatter3DSeries *prevSeries = 0;
+ const QScatterDataArray *dataArray = 0;
+
+ foreach (Scatter3DController::ChangeItem item, items) {
+ QScatter3DSeries *currentSeries = item.series;
+ if (currentSeries != prevSeries) {
+ cache = static_cast<ScatterSeriesRenderCache *>(m_renderCacheList.value(currentSeries));
+ prevSeries = currentSeries;
+ dataArray = item.series->dataProxy()->array();
+ // Invisible series render caches are not updated, but instead just marked dirty, so that
+ // they can be completely recalculated when they are turned visible.
+ if (!cache->isVisible() && !cache->dataDirty())
+ cache->setDataDirty(true);
+ }
+ if (cache->isVisible()) {
+ const int index = item.index;
+ updateRenderItem(dataArray->at(index), cache->renderArray()[index]);
}
}
- m_dotSizeScale = GLfloat(qBound(defaultMinSize, 2.0f / float(qSqrt(qreal(totalDataSize))),
- defaultMaxSize));
-
- updateSelectedItem(m_selectedItemIndex, m_selectedSeries);
}
void Scatter3DRenderer::updateScene(Q3DScene *scene)
@@ -231,7 +293,8 @@ void Scatter3DRenderer::updateScene(Q3DScene *scene)
if (m_hasHeightAdjustmentChanged) {
// Set initial camera position. Also update if height adjustment has changed.
- scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector, zeroVector, upVector);
+ scene->activeCamera()->d_ptr->setBaseOrientation(cameraDistanceVector, zeroVector,
+ upVector);
m_hasHeightAdjustmentChanged = false;
}
@@ -249,6 +312,13 @@ void Scatter3DRenderer::render(GLuint defaultFboHandle)
// Handle GL state setup for FBO buffers and clearing of the render surface
Abstract3DRenderer::render(defaultFboHandle);
+ if (m_axisCacheX.positionsDirty())
+ m_axisCacheX.updateAllPositions();
+ if (m_axisCacheY.positionsDirty())
+ m_axisCacheY.updateAllPositions();
+ if (m_axisCacheZ.positionsDirty())
+ m_axisCacheZ.updateAllPositions();
+
// Draw dots scene
drawScene(defaultFboHandle);
}
@@ -258,9 +328,13 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
GLfloat backgroundRotation = 0;
GLfloat selectedItemSize = 0.0f;
+ // Get the optimization flag
+ const bool optimizationDefault =
+ !m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic);
+
const Q3DCamera *activeCamera = m_cachedScene->activeCamera();
- QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
+ QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
// Specify viewport
glViewport(m_primarySubViewport.x(),
@@ -272,14 +346,19 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
QMatrix4x4 projectionMatrix;
GLfloat viewPortRatio = (GLfloat)m_primarySubViewport.width()
/ (GLfloat)m_primarySubViewport.height();
- projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
+ if (m_useOrthoProjection) {
+ GLfloat orthoRatio = 2.0f;
+ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
+ -orthoRatio, orthoRatio,
+ 0.0f, 100.0f);
+ } else {
+ projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
+ }
// Calculate view matrix
QMatrix4x4 viewMatrix = activeCamera->d_ptr->viewMatrix();
QMatrix4x4 projectionViewMatrix = projectionMatrix * viewMatrix;
- int seriesCount = m_visibleSeriesList.size();
-
// Calculate label flipping
if (viewMatrix.row(0).x() > 0)
m_zFlipped = false;
@@ -314,25 +393,8 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
QMatrix4x4 depthProjectionMatrix;
QMatrix4x4 depthProjectionViewMatrix;
- // Check if we have any series with points
- bool havePointSeries = false;
- bool haveMeshSeries = false;
- bool haveUniformColorMeshSeries = false;
- bool haveGradientMeshSeries = false;
- for (int i = 0; i < seriesCount; i++) {
- if (m_visibleSeriesList.at(i).mesh() == QAbstract3DSeries::MeshPoint) {
- havePointSeries = true;
- } else {
- haveMeshSeries = true;
- if (m_visibleSeriesList.at(i).colorStyle() == Q3DTheme::ColorStyleUniform)
- haveUniformColorMeshSeries = true;
- else
- haveGradientMeshSeries = true;
- }
- }
-
#if !defined(QT_OPENGL_ES_2)
- if (havePointSeries) {
+ if (m_havePointSeries) {
glEnable(GL_POINT_SMOOTH);
glEnable(GL_PROGRAM_POINT_SIZE);
}
@@ -360,77 +422,107 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
zeroVector, 0.0f, 2.5f / m_autoScaleAdjustment);
depthViewMatrix.lookAt(depthLightPos, zeroVector, upVector);
// Set the depth projection matrix
-#ifndef USE_WIDER_SHADOWS
- // Use this for perspective shadows
depthProjectionMatrix.perspective(15.0f, viewPortRatio, 3.0f, 100.0f);
-#else
- // Use these for orthographic shadows
- GLfloat testAspectRatio = viewPortRatio;
- depthProjectionMatrix.ortho(-testAspectRatio * 2.0f, testAspectRatio * 2.0f,
- -m_heightNormalizer * 2.0f, m_heightNormalizer * 2.0f,
- 0.0f, 100.0f);
-#endif
depthProjectionViewMatrix = depthProjectionMatrix * depthViewMatrix;
// Draw dots to depth buffer
- for (int series = 0; series < seriesCount; series++) {
- ObjectHelper *dotObj = m_visibleSeriesList.at(series).object();
- QQuaternion seriesRotation = m_visibleSeriesList.at(series).meshRotation();
- bool drawingPoints = (m_visibleSeriesList.at(series).mesh() == QAbstract3DSeries::MeshPoint);
-
- float itemSize = m_cachedItemSize.at(series) / itemScaler;
- if (itemSize == 0.0f)
- itemSize = m_dotSizeScale;
- if (drawingPoints) {
- // Scale points based on shadow quality for shadows, not by zoom level
- glPointSize(itemSize * 100.0f * m_shadowQualityMultiplier);
- }
- QVector3D modelScaler(itemSize, itemSize, itemSize);
-
- for (int dot = 0; dot < m_renderingArrays.at(series).size(); dot++) {
- const ScatterRenderItem &item = m_renderingArrays.at(series).at(dot);
- if (!item.isVisible())
- continue;
-
- QMatrix4x4 modelMatrix;
- QMatrix4x4 MVPMatrix;
-
- modelMatrix.translate(item.translation());
- if (!drawingPoints) {
- if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
- modelMatrix.rotate(seriesRotation * item.rotation());
- modelMatrix.scale(modelScaler);
- }
-
- MVPMatrix = depthProjectionViewMatrix * modelMatrix;
-
- m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
-
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ ScatterSeriesRenderCache *cache =
+ static_cast<ScatterSeriesRenderCache *>(baseCache);
+ ObjectHelper *dotObj = cache->object();
+ QQuaternion seriesRotation(cache->meshRotation());
+ const ScatterRenderItemArray &renderArray = cache->renderArray();
+ const int renderArraySize = renderArray.size();
+ bool drawingPoints = (cache->mesh() == QAbstract3DSeries::MeshPoint);
+ float itemSize = cache->itemSize() / itemScaler;
+ if (itemSize == 0.0f)
+ itemSize = m_dotSizeScale;
if (drawingPoints) {
- m_drawer->drawPoint(m_depthShader);
- } else {
- // 1st attribute buffer : vertices
- glEnableVertexAttribArray(m_depthShader->posAtt());
- glBindBuffer(GL_ARRAY_BUFFER, dotObj->vertexBuf());
- glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
- (void *)0);
-
- // Index buffer
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dotObj->elementBuf());
-
- // Draw the triangles
- glDrawElements(GL_TRIANGLES, dotObj->indexCount(), GL_UNSIGNED_SHORT,
- (void *)0);
-
- // Free buffers
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- glDisableVertexAttribArray(m_depthShader->posAtt());
+ // Scale points based on shadow quality for shadows, not by zoom level
+ glPointSize(itemSize * 100.0f * m_shadowQualityMultiplier);
+ }
+ QVector3D modelScaler(itemSize, itemSize, itemSize);
+
+ int loopCount = 1;
+ if (optimizationDefault)
+ loopCount = renderArraySize;
+ for (int dot = 0; dot < loopCount; dot++) {
+ const ScatterRenderItem &item = renderArray.at(dot);
+ if (!item.isVisible() && optimizationDefault)
+ continue;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ if (optimizationDefault) {
+ modelMatrix.translate(item.translation());
+ if (!drawingPoints) {
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
+ modelMatrix.rotate(seriesRotation * item.rotation());
+ modelMatrix.scale(modelScaler);
+ }
+ }
+
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+
+ m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
+
+ if (drawingPoints) {
+ if (optimizationDefault)
+ m_drawer->drawPoint(m_depthShader);
+ else
+ m_drawer->drawPoints(m_depthShader, cache->bufferPoints());
+ } else {
+ if (optimizationDefault) {
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, dotObj->vertexBuf());
+ glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dotObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, dotObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_depthShader->posAtt());
+ } else {
+ ScatterObjectBufferHelper *object = cache->bufferObject();
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf());
+ glVertexAttribPointer(m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, object->indexCount(),
+ object->indicesType(), (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(m_depthShader->posAtt());
+ }
+ }
}
}
}
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
// Disable drawing to framebuffer (= enable drawing to screen)
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
@@ -446,14 +538,14 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
ShaderHelper *pointSelectionShader = m_selectionShader;
#else
- Q_UNUSED(havePointSeries);
ShaderHelper *pointSelectionShader = m_pointShader;
#endif
ShaderHelper *selectionShader = m_selectionShader;
// Skip selection mode drawing if we have no selection mode
if (m_cachedSelectionMode > QAbstract3DGraph::SelectionNone
- && SelectOnScene == m_selectionState && seriesCount > 0) {
+ && SelectOnScene == m_selectionState
+ && (m_visibleSeriesCount > 0 || !m_customRenderCache.isEmpty())) {
// Draw dots to selection buffer
glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer);
glViewport(0, 0,
@@ -465,94 +557,80 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
- int arraySize = 0;
- int totalArraySize = 0;
- int dotNo = 0;
-
- // Init previous to opposite of first to ensure we change binding for first series
- bool previousDrawingPoints = (m_visibleSeriesList.at(0).mesh() != QAbstract3DSeries::MeshPoint);
- for (int series = 0; series < seriesCount; series++) {
- ObjectHelper *dotObj = m_visibleSeriesList.at(series).object();
- QQuaternion seriesRotation = m_visibleSeriesList.at(series).meshRotation();
- bool drawingPoints = (m_visibleSeriesList.at(series).mesh() == QAbstract3DSeries::MeshPoint);
-
- float itemSize = m_cachedItemSize.at(series) / itemScaler;
- if (itemSize == 0.0f)
- itemSize = m_dotSizeScale;
+ bool previousDrawingPoints = false;
+ int totalIndex = 0;
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ ScatterSeriesRenderCache *cache =
+ static_cast<ScatterSeriesRenderCache *>(baseCache);
+ ObjectHelper *dotObj = cache->object();
+ QQuaternion seriesRotation(cache->meshRotation());
+ const ScatterRenderItemArray &renderArray = cache->renderArray();
+ const int renderArraySize = renderArray.size();
+ bool drawingPoints = (cache->mesh() == QAbstract3DSeries::MeshPoint);
+ float itemSize = cache->itemSize() / itemScaler;
+ if (itemSize == 0.0f)
+ itemSize = m_dotSizeScale;
#if !defined(QT_OPENGL_ES_2)
- if (drawingPoints)
- glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom
-#endif
- QVector3D modelScaler(itemSize, itemSize, itemSize);
-
- // Rebind selection shader if it has changed
- if (drawingPoints != previousDrawingPoints) {
- previousDrawingPoints = drawingPoints;
if (drawingPoints)
- selectionShader = pointSelectionShader;
- else
- selectionShader = m_selectionShader;
-
- selectionShader->bind();
- }
- arraySize = m_renderingArrays.at(series).size();
- totalArraySize += arraySize;
-
- if (totalArraySize > 0xfffffe) // Max possible different selection colors, 0xffffff being skipColor
- qFatal("Too many objects");
-
- for (int dot = 0; dot < arraySize; dot++) {
- const ScatterRenderItem &item = m_renderingArrays.at(series).at(dot);
- if (!item.isVisible())
- continue;
+ glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom
+#endif
+ QVector3D modelScaler(itemSize, itemSize, itemSize);
- QMatrix4x4 modelMatrix;
- QMatrix4x4 MVPMatrix;
+ // Rebind selection shader if it has changed
+ if (!totalIndex || drawingPoints != previousDrawingPoints) {
+ previousDrawingPoints = drawingPoints;
+ if (drawingPoints)
+ selectionShader = pointSelectionShader;
+ else
+ selectionShader = m_selectionShader;
- modelMatrix.translate(item.translation());
- if (!drawingPoints) {
- if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
- modelMatrix.rotate(seriesRotation * item.rotation());
- modelMatrix.scale(modelScaler);
+ selectionShader->bind();
}
-
- MVPMatrix = projectionViewMatrix * modelMatrix;
-
- QVector3D dotColor = indexToSelectionColor(dotNo);
- dotColor /= 255.0f;
-
- selectionShader->setUniformValue(selectionShader->MVP(), MVPMatrix);
- selectionShader->setUniformValue(selectionShader->color(), dotColor);
-
- if (drawingPoints) {
- m_drawer->drawPoint(selectionShader);
- } else {
- // 1st attribute buffer : vertices
- glEnableVertexAttribArray(selectionShader->posAtt());
- glBindBuffer(GL_ARRAY_BUFFER, dotObj->vertexBuf());
- glVertexAttribPointer(selectionShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
- (void *)0);
-
- // Index buffer
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dotObj->elementBuf());
-
- // Draw the triangles
- glDrawElements(GL_TRIANGLES, dotObj->indexCount(), GL_UNSIGNED_SHORT,
- (void *)0);
-
- // Free buffers
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- glDisableVertexAttribArray(selectionShader->posAtt());
+ cache->setSelectionIndexOffset(totalIndex);
+ for (int dot = 0; dot < renderArraySize; dot++) {
+ const ScatterRenderItem &item = renderArray.at(dot);
+ if (!item.isVisible()) {
+ totalIndex++;
+ continue;
+ }
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(item.translation());
+ if (!drawingPoints) {
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity())
+ modelMatrix.rotate(seriesRotation * item.rotation());
+ modelMatrix.scale(modelScaler);
+ }
+
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+
+ QVector4D dotColor = indexToSelectionColor(totalIndex++);
+ dotColor /= 255.0f;
+
+ selectionShader->setUniformValue(selectionShader->MVP(), MVPMatrix);
+ selectionShader->setUniformValue(selectionShader->color(), dotColor);
+
+ if (drawingPoints)
+ m_drawer->drawPoint(selectionShader);
+ else
+ m_drawer->drawSelectionObject(selectionShader, dotObj);
}
- dotNo++;
}
}
+
+ Abstract3DRenderer::drawCustomItems(RenderingSelection, m_selectionShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
+ drawLabels(true, activeCamera, viewMatrix, projectionMatrix);
+
glEnable(GL_DITHER);
// Read color under cursor
- QVector3D clickedColor = Utils::getSelection(m_inputPosition,
+ QVector4D clickedColor = Utils::getSelection(m_inputPosition,
m_viewport.height());
selectionColorToSeriesAndIndex(clickedColor, m_clickedIndex, m_clickedSeries);
@@ -571,15 +649,14 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
GLuint gradientTexture = 0;
bool dotSelectionFound = false;
ScatterRenderItem *selectedItem(0);
- int dotNo = 0;
- QVector3D baseColor;
- QVector3D dotColor;
+ QVector4D baseColor;
+ QVector4D dotColor;
bool previousDrawingPoints = false;
Q3DTheme::ColorStyle previousMeshColorStyle = Q3DTheme::ColorStyleUniform;
- if (haveMeshSeries) {
+ if (m_haveMeshSeries) {
// Set unchanging shader bindings
- if (haveGradientMeshSeries) {
+ if (m_haveGradientMeshSeries) {
m_dotGradientShader->bind();
m_dotGradientShader->setUniformValue(m_dotGradientShader->lightP(), lightPos);
m_dotGradientShader->setUniformValue(m_dotGradientShader->view(), viewMatrix);
@@ -587,7 +664,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
m_cachedTheme->ambientLightStrength());
m_dotGradientShader->setUniformValue(m_dotGradientShader->lightColor(), lightColor);
}
- if (haveUniformColorMeshSeries) {
+ if (m_haveUniformColorMeshSeries) {
m_dotShader->bind();
m_dotShader->setUniformValue(m_dotShader->lightP(), lightPos);
m_dotShader->setUniformValue(m_dotShader->view(), viewMatrix);
@@ -607,152 +684,281 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
dotShader->bind();
}
- for (int series = 0; series < seriesCount; series++) {
- const SeriesRenderCache &currentSeries = m_visibleSeriesList.at(series);
- QQuaternion seriesRotation = currentSeries.meshRotation();
- ObjectHelper *dotObj = currentSeries.object();
- bool drawingPoints = (currentSeries.mesh() == QAbstract3DSeries::MeshPoint);
- Q3DTheme::ColorStyle colorStyle = currentSeries.colorStyle();
- bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform);
- bool useColor = colorStyleIsUniform || drawingPoints;
-
- float itemSize = m_cachedItemSize.at(series) / itemScaler;
- if (itemSize == 0.0f)
- itemSize = m_dotSizeScale;
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ ScatterSeriesRenderCache *cache =
+ static_cast<ScatterSeriesRenderCache *>(baseCache);
+ ObjectHelper *dotObj = cache->object();
+ QQuaternion seriesRotation(cache->meshRotation());
+ ScatterRenderItemArray &renderArray = cache->renderArray();
+ const int renderArraySize = renderArray.size();
+ bool selectedSeries = m_cachedSelectionMode > QAbstract3DGraph::SelectionNone
+ && (m_selectedSeriesCache == cache);
+ bool drawingPoints = (cache->mesh() == QAbstract3DSeries::MeshPoint);
+ Q3DTheme::ColorStyle colorStyle = cache->colorStyle();
+ bool colorStyleIsUniform = (colorStyle == Q3DTheme::ColorStyleUniform);
+ bool useColor = colorStyleIsUniform || drawingPoints;
+ bool rangeGradientPoints = drawingPoints
+ && (colorStyle == Q3DTheme::ColorStyleRangeGradient);
+ float itemSize = cache->itemSize() / itemScaler;
+ if (itemSize == 0.0f)
+ itemSize = m_dotSizeScale;
#if !defined(QT_OPENGL_ES_2)
- if (drawingPoints)
- glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom
+ if (drawingPoints)
+ glPointSize(itemSize * activeCamera->zoomLevel()); // Scale points based on zoom
#endif
- QVector3D modelScaler(itemSize, itemSize, itemSize);
-
- // Rebind shader if it has changed
- if (drawingPoints != previousDrawingPoints
- || (!drawingPoints &&
- (colorStyleIsUniform != (previousMeshColorStyle == Q3DTheme::ColorStyleUniform)))) {
- previousDrawingPoints = drawingPoints;
- if (drawingPoints) {
- dotShader = pointSelectionShader;
- } else {
- if (colorStyleIsUniform)
- dotShader = m_dotShader;
- else
- dotShader = m_dotGradientShader;
+ QVector3D modelScaler(itemSize, itemSize, itemSize);
+
+ // Rebind shader if it has changed
+ if (drawingPoints != previousDrawingPoints
+ || (!drawingPoints &&
+ (colorStyleIsUniform != (previousMeshColorStyle
+ == Q3DTheme::ColorStyleUniform)))) {
+ previousDrawingPoints = drawingPoints;
+ if (drawingPoints) {
+ dotShader = pointSelectionShader;
+ } else {
+ if (colorStyleIsUniform)
+ dotShader = m_dotShader;
+ else
+ dotShader = m_dotGradientShader;
+ }
+ dotShader->bind();
}
- dotShader->bind();
- }
- if (!drawingPoints && !colorStyleIsUniform && previousMeshColorStyle != colorStyle) {
- if (colorStyle == Q3DTheme::ColorStyleObjectGradient) {
- m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientMin(), 0.0f);
- m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(), 0.5f);
- } else {
- // Each ball is of uniform color according to its Y-coordinate
- m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(), 0.0f);
+ if (!drawingPoints && !colorStyleIsUniform && previousMeshColorStyle != colorStyle) {
+ if (colorStyle == Q3DTheme::ColorStyleObjectGradient) {
+ m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientMin(), 0.0f);
+ m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(),
+ 0.5f);
+ } else {
+ // Each dot is of uniform color according to its Y-coordinate
+ m_dotGradientShader->setUniformValue(m_dotGradientShader->gradientHeight(),
+ 0.0f);
+ }
}
- }
- if (!drawingPoints)
- previousMeshColorStyle = colorStyle;
+ if (!drawingPoints)
+ previousMeshColorStyle = colorStyle;
- if (useColor) {
- baseColor = currentSeries.baseColor();
- dotColor = baseColor;
- }
+ if (useColor) {
+ baseColor = cache->baseColor();
+ dotColor = baseColor;
+ }
+ int loopCount = 1;
+ if (optimizationDefault)
+ loopCount = renderArraySize;
+ for (int i = 0; i < loopCount; i++) {
+ ScatterRenderItem &item = renderArray[i];
+ if (!item.isVisible() && optimizationDefault)
+ continue;
- int seriesSize = m_renderingArrays.at(series).size();
- for (int dot = 0; dot < seriesSize; dot++) {
- ScatterRenderItem &item = m_renderingArrays[series][dot];
- if (!item.isVisible())
- continue;
-
- QMatrix4x4 modelMatrix;
- QMatrix4x4 MVPMatrix;
- QMatrix4x4 itModelMatrix;
-
- modelMatrix.translate(item.translation());
- if (!drawingPoints) {
- if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) {
- QQuaternion totalRotation = seriesRotation * item.rotation();
- modelMatrix.rotate(totalRotation);
- itModelMatrix.rotate(totalRotation);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (optimizationDefault) {
+ modelMatrix.translate(item.translation());
+ if (!drawingPoints) {
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) {
+ QQuaternion totalRotation = seriesRotation * item.rotation();
+ modelMatrix.rotate(totalRotation);
+ itModelMatrix.rotate(totalRotation);
+ }
+ modelMatrix.scale(modelScaler);
+ itModelMatrix.scale(modelScaler);
+ }
}
- modelMatrix.scale(modelScaler);
- itModelMatrix.scale(modelScaler);
- }
#ifdef SHOW_DEPTH_TEXTURE_SCENE
- MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
#else
- MVPMatrix = projectionViewMatrix * modelMatrix;
+ MVPMatrix = projectionViewMatrix * modelMatrix;
#endif
- if (useColor)
- dotColor = baseColor;
- else
- gradientTexture = currentSeries.baseGradientTexture();
+ if (useColor) {
+ if (rangeGradientPoints) {
+ // Drawing points with range gradient
+ // Get color from gradient based on items y position converted to percent
+ int position = int(item.translation().y() * 50.0f) + 50;
+ dotColor = Utils::vectorFromColor(
+ cache->gradientImage().pixel(0, position));
+ } else {
+ dotColor = baseColor;
+ }
+ } else {
+ gradientTexture = cache->baseGradientTexture();
+ }
+
+ GLfloat lightStrength = m_cachedTheme->lightStrength();
+ if (optimizationDefault && selectedSeries && (m_selectedItemIndex == i)) {
+ if (useColor)
+ dotColor = cache->singleHighlightColor();
+ else
+ gradientTexture = cache->singleHighlightGradientTexture();
+ lightStrength = m_cachedTheme->highlightLightStrength();
+ // Insert data to ScatterRenderItem
+ // We don't have ownership, so don't delete the previous one
+ selectedItem = &item;
+ dotSelectionFound = true;
+ // Save selected item size (adjusted with font size) for selection label
+ // positioning
+ selectedItemSize = itemSize + (m_cachedTheme->font().pointSizeF() / 500.0f);
+ }
+
+ if (!drawingPoints) {
+ // Set shader bindings
+ dotShader->setUniformValue(dotShader->model(), modelMatrix);
+ dotShader->setUniformValue(dotShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ }
+
+ dotShader->setUniformValue(dotShader->MVP(), MVPMatrix);
+ if (useColor) {
+ dotShader->setUniformValue(dotShader->color(), dotColor);
+ } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
+ dotShader->setUniformValue(dotShader->gradientMin(),
+ (item.translation().y() + 1.0f) / 2.0f);
+ }
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ if (!drawingPoints) {
+ // Set shadow shader bindings
+ QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ dotShader->setUniformValue(dotShader->shadowQ(), m_shadowQualityToShader);
+ dotShader->setUniformValue(dotShader->depth(), depthMVPMatrix);
+ dotShader->setUniformValue(dotShader->lightS(), lightStrength / 10.0f);
+
+ // Draw the object
+ if (optimizationDefault) {
+ m_drawer->drawObject(dotShader, dotObj, gradientTexture,
+ m_depthTexture);
+ } else {
+ m_drawer->drawObject(dotShader, cache->bufferObject(), gradientTexture,
+ m_depthTexture);
+ }
+ } else {
+ // Draw the object
+ if (optimizationDefault)
+ m_drawer->drawPoint(dotShader);
+ else
+ m_drawer->drawPoints(dotShader, cache->bufferPoints());
+ }
+ } else
+#endif
+ {
+ if (!drawingPoints) {
+ // Set shadowless shader bindings
+ dotShader->setUniformValue(dotShader->lightS(), lightStrength);
+ // Draw the object
+ if (optimizationDefault)
+ m_drawer->drawObject(dotShader, dotObj, gradientTexture);
+ else
+ m_drawer->drawObject(dotShader, cache->bufferObject(), gradientTexture);
+ } else {
+ // Draw the object
+ if (optimizationDefault)
+ m_drawer->drawPoint(dotShader);
+ else
+ m_drawer->drawPoints(dotShader, cache->bufferPoints());
+ }
+ }
+ }
+
+ // Draw the selected item on static optimization
+ if (!optimizationDefault && selectedSeries
+ && m_selectedItemIndex != Scatter3DController::invalidSelectionIndex()) {
+ ScatterRenderItem &item = renderArray[m_selectedItemIndex];
+ ObjectHelper *dotObj = cache->object();
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(item.translation());
+ if (!drawingPoints) {
+ if (!seriesRotation.isIdentity() || !item.rotation().isIdentity()) {
+ QQuaternion totalRotation = seriesRotation * item.rotation();
+ modelMatrix.rotate(totalRotation);
+ itModelMatrix.rotate(totalRotation);
+ }
+ modelMatrix.scale(modelScaler);
+ itModelMatrix.scale(modelScaler);
+ }
+
+ QMatrix4x4 MVPMatrix;
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionViewMatrix * modelMatrix;
+#endif
- GLfloat lightStrength = m_cachedTheme->lightStrength();
- if (m_cachedSelectionMode > QAbstract3DGraph::SelectionNone
- && (m_selectedItemTotalIndex == dotNo)) {
if (useColor)
- dotColor = currentSeries.singleHighlightColor();
+ dotColor = cache->singleHighlightColor();
else
- gradientTexture = currentSeries.singleHighlightGradientTexture();
- lightStrength = m_cachedTheme->highlightLightStrength();
- // Insert data to ScatterRenderItem. We have no ownership, don't delete the previous one
+ gradientTexture = cache->singleHighlightGradientTexture();
+ GLfloat lightStrength = m_cachedTheme->highlightLightStrength();
+ // Save the reference to the item to be used on label drawing
selectedItem = &item;
dotSelectionFound = true;
- // Save selected item size (adjusted with font size) for selection label positioning
+ // Save selected item size (adjusted with font size) for selection label
+ // positioning
selectedItemSize = itemSize + (m_cachedTheme->font().pointSizeF() / 500.0f);
- }
- if (!drawingPoints) {
- // Set shader bindings
- dotShader->setUniformValue(dotShader->model(), modelMatrix);
- dotShader->setUniformValue(dotShader->nModel(),
- itModelMatrix.inverted().transposed());
- }
-
- dotShader->setUniformValue(dotShader->MVP(), MVPMatrix);
- if (useColor) {
- dotShader->setUniformValue(dotShader->color(), dotColor);
- } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
- dotShader->setUniformValue(dotShader->gradientMin(),
- (item.translation().y() + 1.0f) / 2.0f);
- }
-#if !defined(QT_OPENGL_ES_2)
- if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
if (!drawingPoints) {
- // Set shadow shader bindings
- QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
- dotShader->setUniformValue(dotShader->shadowQ(), m_shadowQualityToShader);
- dotShader->setUniformValue(dotShader->depth(), depthMVPMatrix);
- dotShader->setUniformValue(dotShader->lightS(), lightStrength / 10.0f);
+ // Set shader bindings
+ dotShader->setUniformValue(dotShader->model(), modelMatrix);
+ dotShader->setUniformValue(dotShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ }
- // Draw the object
- m_drawer->drawObject(dotShader, dotObj, gradientTexture, m_depthTexture);
- } else {
- // Draw the object
- m_drawer->drawPoint(dotShader);
+ dotShader->setUniformValue(dotShader->MVP(), MVPMatrix);
+ if (useColor) {
+ dotShader->setUniformValue(dotShader->color(), dotColor);
+ } else if (colorStyle == Q3DTheme::ColorStyleRangeGradient) {
+ dotShader->setUniformValue(dotShader->gradientMin(),
+ (item.translation().y() + 1.0f) / 2.0f);
}
- } else
-#endif
- {
+
if (!drawingPoints) {
- // Set shadowless shader bindings
- dotShader->setUniformValue(dotShader->lightS(), lightStrength);
- // Draw the object
- m_drawer->drawObject(dotShader, dotObj, gradientTexture);
- } else {
- // Draw the object
- m_drawer->drawPoint(dotShader);
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-0.5f, 1.0f);
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ if (!drawingPoints) {
+ // Set shadow shader bindings
+ QMatrix4x4 depthMVPMatrix = depthProjectionViewMatrix * modelMatrix;
+ dotShader->setUniformValue(dotShader->depth(), depthMVPMatrix);
+ dotShader->setUniformValue(dotShader->lightS(), lightStrength / 10.0f);
+
+ // Draw the object
+ m_drawer->drawObject(dotShader, dotObj, gradientTexture, m_depthTexture);
+ } else {
+ // Draw the object
+ m_drawer->drawPoint(dotShader);
+ }
+ } else
+#endif
+ {
+ if (!drawingPoints) {
+ // Set shadowless shader bindings
+ dotShader->setUniformValue(dotShader->lightS(), lightStrength);
+ // Draw the object
+ m_drawer->drawObject(dotShader, dotObj, gradientTexture);
+ } else {
+ // Draw the object
+ m_drawer->drawPoint(dotShader);
+ }
}
+
+ if (!drawingPoints)
+ glDisable(GL_POLYGON_OFFSET_FILL);
}
- dotNo++;
}
}
#if !defined(QT_OPENGL_ES_2)
- if (havePointSeries) {
+ if (m_havePointSeries) {
glDisable(GL_POINT_SMOOTH);
glDisable(GL_PROGRAM_POINT_SIZE);
}
@@ -770,17 +976,19 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
QMatrix4x4 itModelMatrix;
#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor;
- GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) / m_scaleFactor;
+ GLfloat xScale = (m_graphAspectRatio * m_areaSize.width()) / m_scaleFactor
+ + m_backgroundMargin;
+ GLfloat zScale = (m_graphAspectRatio * m_areaSize.height()) / m_scaleFactor
+ + m_backgroundMargin;
if (m_maxItemSize > xScale)
xScale = m_maxItemSize;
if (m_maxItemSize > zScale)
zScale = m_maxItemSize;
- QVector3D bgScale(xScale, m_backgroundMargin, zScale);
+ QVector3D bgScale(xScale, 1.0f + m_backgroundMargin, zScale);
#else // ..and this if we want uniform scaling based on largest dimension
- QVector3D bgScale((aspectRatio * m_backgroundMargin),
- m_backgroundMargin,
- (aspectRatio * m_backgroundMargin));
+ QVector3D bgScale((m_graphAspectRatio + m_backgroundMargin),
+ 1.0f + m_backgroundMargin,
+ (m_graphAspectRatio + m_backgroundMargin));
#endif
modelMatrix.scale(bgScale);
// If we're viewing from below, background object must be flipped
@@ -797,7 +1005,7 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
#else
MVPMatrix = projectionViewMatrix * modelMatrix;
#endif
- QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor());
+ QVector4D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor());
// Set shader bindings
m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos);
@@ -839,22 +1047,18 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
glDisable(GL_TEXTURE_2D);
// Draw grid lines
-#ifdef USE_UNIFORM_SCALING
- AxisRenderCache *axisCacheMax;
- if (m_axisCacheZ.max() > m_axisCacheX.max())
- axisCacheMax = &m_axisCacheZ;
- else
- axisCacheMax = &m_axisCacheX;
-#endif
-
- if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) {
+ if (m_cachedTheme->isGridEnabled()) {
+#if !(defined QT_OPENGL_ES_2)
ShaderHelper *lineShader = m_backgroundShader;
+#else
+ ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES
+#endif
// Bind line shader
lineShader->bind();
// Set unchanging shader bindings
- QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
+ QVector4D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
lineShader->setUniformValue(lineShader->lightP(), lightPos);
lineShader->setUniformValue(lineShader->view(), viewMatrix);
lineShader->setUniformValue(lineShader->color(), lineColor);
@@ -887,39 +1091,33 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
else
lineXRotation = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f);
- GLfloat yFloorLinePosition = -m_backgroundMargin + gridLineOffset;
+ GLfloat yFloorLinePosition = -1.0f - m_backgroundMargin + gridLineOffset;
if (m_yFlipped)
yFloorLinePosition = -yFloorLinePosition;
// Rows (= Z)
if (m_axisCacheZ.segmentCount() > 0) {
// Floor lines
-#ifndef USE_UNIFORM_SCALING
- GLfloat lineStep = aspectRatio * m_axisCacheZ.subSegmentStep();
- GLfloat linePos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); // Start line
- int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount();
-#else
- GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep();
- GLfloat linePos = -aspectRatio * m_scaleFactor; // Start line
- int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount();
-#endif
+ int gridLineCount = m_axisCacheZ.gridLineCount();
#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor;
+ GLfloat xScale = (m_graphAspectRatio * m_areaSize.width()) / m_scaleFactor
+ + m_backgroundMargin;
if (m_maxItemSize > xScale)
xScale = m_maxItemSize;
QVector3D gridLineScaler(xScale, gridLineWidth, gridLineWidth);
#else // ..and this if we want uniform scaling based on largest dimension
- QVector3D gridLineScaler((aspectRatio * m_backgroundMargin),
+ QVector3D gridLineScaler((m_graphAspectRatio + m_backgroundMargin),
gridLineWidth, gridLineWidth);
#endif
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(0.0f, yFloorLinePosition, linePos / m_scaleFactor);
+ modelMatrix.translate(0.0f, yFloorLinePosition,
+ m_axisCacheZ.gridLinePosition(line));
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
@@ -942,42 +1140,45 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos -= lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Side wall lines
- gridLineScaler = QVector3D(gridLineWidth, m_backgroundMargin, gridLineWidth);
+ gridLineScaler = QVector3D(gridLineWidth, 1.0f + m_backgroundMargin, gridLineWidth);
#ifndef USE_UNIFORM_SCALING
- GLfloat lineXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width())
- / m_scaleFactor - gridLineOffset;
+ GLfloat lineXTrans = (m_graphAspectRatio * m_areaSize.width())
+ / m_scaleFactor - gridLineOffset + m_backgroundMargin;
if (m_maxItemSize > lineXTrans)
lineXTrans = m_maxItemSize - gridLineOffset;
- linePos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z()); // Start line
#else
- GLfloat lineXTrans = aspectRatio * m_backgroundMargin - gridLineOffset;
- linePos = -aspectRatio * m_scaleFactor; // Start line
+ GLfloat lineXTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset;
#endif
if (!m_xFlipped)
lineXTrans = -lineXTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(lineXTrans, 0.0f, linePos / m_scaleFactor);
+ modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line));
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
+#if !defined(QT_OPENGL_ES_2)
modelMatrix.rotate(lineYRotation);
itModelMatrix.rotate(lineYRotation);
+#else
+ modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+ itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+#endif
MVPMatrix = projectionViewMatrix * modelMatrix;
@@ -994,41 +1195,42 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos -= lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
// Columns (= X)
if (m_axisCacheX.segmentCount() > 0) {
+#if defined(QT_OPENGL_ES_2)
+ lineXRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f);
+#endif
// Floor lines
+ int gridLineCount = m_axisCacheX.gridLineCount();
+
#ifndef USE_UNIFORM_SCALING
- GLfloat lineStep = aspectRatio * m_axisCacheX.subSegmentStep();
- GLfloat linePos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x());
- int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount();
- GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height()) / m_scaleFactor;
+ GLfloat zScale = (m_graphAspectRatio * m_areaSize.height()) / m_scaleFactor
+ + m_backgroundMargin;
if (m_maxItemSize > zScale)
zScale = m_maxItemSize;
QVector3D gridLineScaler(gridLineWidth, gridLineWidth, zScale);
#else
- GLfloat lineStep = aspectRatio * axisCacheMax->subSegmentStep();
- GLfloat linePos = -aspectRatio * m_scaleFactor;
- int lastSegment = axisCacheMax->subSegmentCount() * axisCacheMax->segmentCount();
QVector3D gridLineScaler(gridLineWidth, gridLineWidth,
- aspectRatio * m_backgroundMargin);
+ m_graphAspectRatio + m_backgroundMargin);
#endif
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(linePos / m_scaleFactor, yFloorLinePosition, 0.0f);
+ modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition,
+ 0.0f);
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
@@ -1051,45 +1253,48 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Back wall lines
#ifndef USE_UNIFORM_SCALING
- GLfloat lineZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height())
- / m_scaleFactor - gridLineOffset;
+ GLfloat lineZTrans = (m_graphAspectRatio * m_areaSize.height())
+ / m_scaleFactor - gridLineOffset + m_backgroundMargin;
if (m_maxItemSize > lineZTrans)
lineZTrans = m_maxItemSize - gridLineOffset;
- linePos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x());
#else
- GLfloat lineZTrans = aspectRatio * m_backgroundMargin - gridLineOffset;
- linePos = -aspectRatio * m_scaleFactor;
+ GLfloat lineZTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset;
#endif
if (!m_zFlipped)
lineZTrans = -lineZTrans;
- gridLineScaler = QVector3D(gridLineWidth, m_backgroundMargin, gridLineWidth);
+ gridLineScaler = QVector3D(gridLineWidth, 1.0f + m_backgroundMargin, gridLineWidth);
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(linePos / m_scaleFactor, 0.0f, lineZTrans);
+ modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans);
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
+#if !defined(QT_OPENGL_ES_2)
if (m_zFlipped) {
modelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f);
itModelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f);
}
+#else
+ modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+ itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+#endif
MVPMatrix = projectionViewMatrix * modelMatrix;
@@ -1106,46 +1311,45 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
// Horizontal wall lines
if (m_axisCacheY.segmentCount() > 0) {
// Back wall
- GLfloat lineStep = m_axisCacheY.subSegmentStep();
- GLfloat linePos = m_axisCacheY.min() - m_translationOffset.y();
- int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+ int gridLineCount = m_axisCacheY.gridLineCount();
#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- GLfloat lineZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height())
- / m_scaleFactor - gridLineOffset;
+ GLfloat lineZTrans = (m_graphAspectRatio * m_areaSize.height())
+ / m_scaleFactor - gridLineOffset + m_backgroundMargin;
if (m_maxItemSize > lineZTrans)
lineZTrans = m_maxItemSize - gridLineOffset;
- GLfloat xScale = (aspectRatio * m_backgroundMargin * m_areaSize.width()) / m_scaleFactor;
+ GLfloat xScale = (m_graphAspectRatio * m_areaSize.width()) / m_scaleFactor
+ + m_backgroundMargin;
if (m_maxItemSize > xScale)
xScale = m_maxItemSize;
QVector3D gridLineScaler(xScale, gridLineWidth, gridLineWidth);
#else // ..and this if we want uniform scaling based on largest dimension
- GLfloat lineZTrans = aspectRatio * m_backgroundMargin - gridLineOffset;
- QVector3D gridLineScaler((aspectRatio * m_backgroundMargin),
+ GLfloat lineZTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset;
+ QVector3D gridLineScaler((m_graphAspectRatio + m_backgroundMargin),
gridLineWidth, gridLineWidth);
#endif
if (!m_zFlipped)
lineZTrans = -lineZTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(0.0f, linePos / m_heightNormalizer, lineZTrans);
+ modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), lineZTrans);
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
@@ -1170,42 +1374,40 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Side wall
- linePos = m_axisCacheY.min() - m_translationOffset.y();
- lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- GLfloat lineXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width())
- / m_scaleFactor - gridLineOffset;
+ GLfloat lineXTrans = (m_graphAspectRatio * m_areaSize.width())
+ / m_scaleFactor - gridLineOffset + m_backgroundMargin;
if (m_maxItemSize > lineXTrans)
lineXTrans = m_maxItemSize - gridLineOffset;
- GLfloat zScale = (aspectRatio * m_backgroundMargin * m_areaSize.height())
- / m_scaleFactor;
+ GLfloat zScale = (m_graphAspectRatio * m_areaSize.height())
+ / m_scaleFactor + m_backgroundMargin;
if (m_maxItemSize > zScale)
zScale = m_maxItemSize;
gridLineScaler = QVector3D(gridLineWidth, gridLineWidth, zScale);
#else // ..and this if we want uniform scaling based on largest dimension
- GLfloat lineXTrans = aspectRatio * m_backgroundMargin - gridLineOffset;
+ GLfloat lineXTrans = m_graphAspectRatio + m_backgroundMargin - gridLineOffset;
gridLineScaler = QVector3D(gridLineWidth, gridLineWidth,
- aspectRatio * m_backgroundMargin);
+ m_graphAspectRatio + m_backgroundMargin);
#endif
if (!m_xFlipped)
lineXTrans = -lineXTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(lineXTrans, linePos / m_heightNormalizer, 0.0f);
+ modelMatrix.translate(lineXTrans, m_axisCacheY.gridLinePosition(line), 0.0f);
modelMatrix.scale(gridLineScaler);
itModelMatrix.scale(gridLineScaler);
@@ -1228,328 +1430,478 @@ void Scatter3DRenderer::drawScene(const GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
+ }
+ }
+ }
+
+ Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
+ drawLabels(false, activeCamera, viewMatrix, projectionMatrix);
+
+ // Handle selection clearing and selection label drawing
+ if (!dotSelectionFound) {
+ // We have no ownership, don't delete. Just NULL the pointer.
+ m_selectedItem = NULL;
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ // Draw the selection label
+ LabelItem &labelItem = selectionLabelItem();
+ if (m_selectedItem != selectedItem || m_updateLabels
+ || !labelItem.textureId() || m_selectionLabelDirty) {
+ QString labelText = selectionLabel();
+ if (labelText.isNull() || m_selectionLabelDirty) {
+ labelText = m_selectedSeriesCache->itemLabel();
+ setSelectionLabel(labelText);
+ m_selectionLabelDirty = false;
}
+ m_drawer->generateLabelItem(labelItem, labelText);
+ m_selectedItem = selectedItem;
}
+
+ m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix,
+ zeroVector, identityQuaternion, selectedItemSize, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, activeCamera, true, false,
+ Drawer::LabelOver);
+
+ // Reset label update flag; they should have been updated when we get here
+ m_updateLabels = false;
+ glEnable(GL_DEPTH_TEST);
}
- // Draw axis labels
- // Bind label shader
- m_labelShader->bind();
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+
+ // Release shader
+ glUseProgram(0);
+
+ m_selectionDirty = false;
+}
+
+void Scatter3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCamera,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionMatrix) {
+ ShaderHelper *shader = 0;
+ GLfloat alphaForValueSelection = labelValueAlpha / 255.0f;
+ GLfloat alphaForRowSelection = labelRowAlpha / 255.0f;
+ GLfloat alphaForColumnSelection = labelColumnAlpha / 255.0f;
+ if (drawSelection) {
+ shader = m_selectionShader;
+ // m_selectionShader is already bound
+ } else {
+ shader = m_labelShader;
+ shader->bind();
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POLYGON_OFFSET_FILL);
+ float labelAutoAngle = m_axisCacheZ.labelAutoRotation();
+ float labelAngleFraction = labelAutoAngle / 90.0f;
+ float fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ float fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ float labelsMaxWidth = 0.0f;
+
+ int startIndex;
+ int endIndex;
+ int indexStep;
+
// Z Labels
if (m_axisCacheZ.segmentCount() > 0) {
+ int labelCount = m_axisCacheZ.labelCount();
#ifndef USE_UNIFORM_SCALING
- GLfloat posStep = aspectRatio * m_axisCacheZ.segmentStep();
- GLfloat labelPos = -aspectRatio * (m_axisCacheZ.min() - m_translationOffset.z());
- int lastSegment = m_axisCacheZ.segmentCount();
- GLfloat labelXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width())
- / m_scaleFactor + labelMargin;
+ GLfloat labelXTrans = (m_graphAspectRatio * m_areaSize.width())
+ / m_scaleFactor + labelMargin + m_backgroundMargin;
if (m_maxItemSize > labelXTrans)
labelXTrans = m_maxItemSize + labelMargin;
#else
- GLfloat posStep = aspectRatio * axisCacheMax->segmentStep();
- GLfloat labelPos = aspectRatio * m_scaleFactor;
- int lastSegment = axisCacheMax->segmentCount();
- GLfloat labelXTrans = aspectRatio * m_backgroundMargin + labelMargin;
+ GLfloat labelXTrans = m_graphAspectRatio + m_backgroundMargin + labelMargin;
#endif
- int labelNbr = 0;
- GLfloat labelYTrans = -m_backgroundMargin;
- 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) {
+ GLfloat labelYTrans = -1.0f - m_backgroundMargin;
+ Qt::AlignmentFlag alignment = (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ QVector3D labelRotation;
+ if (m_xFlipped)
labelXTrans = -labelXTrans;
- alignment = Qt::AlignLeft;
- }
- if (m_yFlipped) {
- rotLabelZ += 180.0f;
- rotLabelY += 180.0f;
+ if (m_yFlipped)
labelYTrans = -labelYTrans;
+ if (labelAutoAngle == 0.0f) {
+ labelRotation.setX(-90.0f);
+ if (m_zFlipped)
+ labelRotation.setY(180.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped)
+ labelRotation.setY(0.0f);
+ else
+ labelRotation.setY(180.0f);
+ labelRotation.setZ(180.0f);
+ }
+ } else {
+ if (m_zFlipped)
+ labelRotation.setY(180.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f - (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(90.0f + (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f + (labelAutoAngle - fractionCamX)
+ * -(labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f + (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f - (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f - (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ }
+ }
+ }
}
- QVector3D labelRotateVector(rotLabelX, rotLabelY, rotLabelZ);
+ QQuaternion totalRotation = Utils::calculateRotation(labelRotation);
QVector3D labelTrans = QVector3D(labelXTrans, labelYTrans, 0.0f);
- for (int segment = 0; segment <= lastSegment; segment++) {
-#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- if (m_axisCacheZ.labelItems().size() > labelNbr) {
-#else // ..and this if we want uniform scaling based on largest dimension
- if (axisCacheMax->labelItems().size() > labelNbr) {
-#endif
- labelTrans.setZ(labelPos / m_scaleFactor);
+ if (m_zFlipped) {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
+ } else {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ }
+ for (int label = startIndex; label != endIndex; label = label + indexStep) {
+ labelTrans.setZ(m_axisCacheZ.labelPosition(label));
- glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f);
+ glPolygonOffset(GLfloat(label) / -10.0f, 1.0f);
- // Draw the label here
- m_dummyRenderItem.setTranslation(labelTrans);
-#ifndef USE_UNIFORM_SCALING
- const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr);
-#else
- const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr);
-#endif
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(label);
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, labelRotateVector, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera, true, true,
- Drawer::LabelMid, alignment);
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(label / 255.0f, 0.0f, 0.0f,
+ alphaForRowSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- labelNbr++;
- labelPos -= posStep;
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera, true, true,
+ Drawer::LabelMid, alignment, false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+ if (!drawSelection && m_axisCacheZ.isTitleVisible()) {
+ labelTrans.setZ(0.0f);
+ drawAxisTitleZ(labelRotation, labelTrans, totalRotation, m_dummyRenderItem,
+ activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader);
}
}
+
// X Labels
if (m_axisCacheX.segmentCount() > 0) {
+ labelsMaxWidth = 0.0f;
+ labelAutoAngle = m_axisCacheX.labelAutoRotation();
+ labelAngleFraction = labelAutoAngle / 90.0f;
+ fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ int labelCount = m_axisCacheX.labelCount();
#ifndef USE_UNIFORM_SCALING
- GLfloat posStep = aspectRatio * m_axisCacheX.segmentStep();
- GLfloat labelPos = aspectRatio * (m_axisCacheX.min() - m_translationOffset.x());
- int lastSegment = m_axisCacheX.segmentCount();
- GLfloat labelZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height())
- / m_scaleFactor + labelMargin;
+ GLfloat labelZTrans = (m_graphAspectRatio * m_areaSize.height())
+ / m_scaleFactor + labelMargin + m_backgroundMargin;
if (m_maxItemSize > labelZTrans)
labelZTrans = m_maxItemSize + labelMargin;
#else
- GLfloat posStep = aspectRatio * axisCacheMax->segmentStep();
- GLfloat labelPos = -aspectRatio * m_scaleFactor;
- int lastSegment = axisCacheMax->segmentCount();
- GLfloat labelZTrans = aspectRatio * m_backgroundMargin + labelMargin;
+ GLfloat labelZTrans = m_graphAspectRatio + m_backgroundMargin + labelMargin;
#endif
- int labelNbr = 0;
- GLfloat labelYTrans = -m_backgroundMargin;
- 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) {
+ GLfloat labelYTrans = -1.0f - m_backgroundMargin;
+ Qt::AlignmentFlag alignment = (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ QVector3D labelRotation;
+ if (m_zFlipped)
labelZTrans = -labelZTrans;
- alignment = Qt::AlignRight;
- }
- if (m_yFlipped) {
- rotLabelZ += 180.0f;
- rotLabelY += 180.0f;
+ if (m_yFlipped)
labelYTrans = -labelYTrans;
+ if (labelAutoAngle == 0.0f) {
+ labelRotation = QVector3D(-90.0f, 90.0f, 0.0f);
+ if (m_xFlipped)
+ labelRotation.setY(-90.0f);
+ if (m_yFlipped) {
+ if (m_xFlipped)
+ labelRotation.setY(90.0f);
+ else
+ labelRotation.setY(-90.0f);
+ labelRotation.setZ(180.0f);
+ }
+ } else {
+ if (m_xFlipped)
+ labelRotation.setY(-90.0f);
+ else
+ labelRotation.setY(90.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f - (2.0f * labelAutoAngle - fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - (2.0f * labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f + fractionCamX
+ * -(labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - fractionCamX
+ * (-labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f + (2.0f * labelAutoAngle - fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + (2.0f * labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f - fractionCamX
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + fractionCamX
+ * -(labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ }
+ }
+ }
}
- QVector3D labelRotateVector(rotLabelX, rotLabelY, rotLabelZ);
+
+ QQuaternion totalRotation = Utils::calculateRotation(labelRotation);
QVector3D labelTrans = QVector3D(0.0f, labelYTrans, labelZTrans);
- for (int segment = 0; segment <= lastSegment; segment++) {
-#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- if (m_axisCacheX.labelItems().size() > labelNbr) {
-#else // ..and this if we want uniform scaling based on largest dimension
- if (axisCacheMax->labelItems().size() > labelNbr) {
-#endif
- labelTrans.setX(labelPos / m_scaleFactor);
+ if (m_xFlipped) {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ } else {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
+ }
+ for (int label = startIndex; label != endIndex; label = label + indexStep) {
+ labelTrans.setX(m_axisCacheX.labelPosition(label));
- glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f);
+ glPolygonOffset(GLfloat(label) / -10.0f, 1.0f);
- // Draw the label here
- m_dummyRenderItem.setTranslation(labelTrans);
-#ifndef USE_UNIFORM_SCALING
- const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr);
-#else
- const LabelItem &axisLabelItem = *axisCacheMax->labelItems().at(labelNbr);
-#endif
+ // Draw the label here
+ m_dummyRenderItem.setTranslation(labelTrans);
+ const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(label);
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, labelRotateVector, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera, true, true,
- Drawer::LabelMid, alignment);
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(0.0f, label / 255.0f, 0.0f,
+ alphaForColumnSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- labelNbr++;
- labelPos += posStep;
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera, true, true,
+ Drawer::LabelMid, alignment, false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+ if (!drawSelection && m_axisCacheX.isTitleVisible()) {
+ labelTrans.setX(0.0f);
+ drawAxisTitleX(labelRotation, labelTrans, totalRotation, m_dummyRenderItem,
+ activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader);
}
}
+
// Y Labels
if (m_axisCacheY.segmentCount() > 0) {
- GLfloat posStep = m_axisCacheY.segmentStep();
- GLfloat labelPos = m_axisCacheY.min() - m_translationOffset.y();
- int labelNbr = 0;
+ labelsMaxWidth = 0.0f;
+ labelAutoAngle = m_axisCacheY.labelAutoRotation();
+ labelAngleFraction = labelAutoAngle / 90.0f;
+ fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ int labelCount = m_axisCacheY.labelCount();
#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
- GLfloat labelXTrans = (aspectRatio * m_backgroundMargin * m_areaSize.width())
- / m_scaleFactor;
- GLfloat labelZTrans = (aspectRatio * m_backgroundMargin * m_areaSize.height())
- / m_scaleFactor;
+ GLfloat labelXTrans = (m_graphAspectRatio* m_areaSize.width())
+ / m_scaleFactor + m_backgroundMargin;
+ GLfloat labelZTrans = (m_graphAspectRatio * m_areaSize.height())
+ / m_scaleFactor + m_backgroundMargin;
if (m_maxItemSize > labelXTrans)
labelXTrans = m_maxItemSize;
if (m_maxItemSize > labelZTrans)
labelZTrans = m_maxItemSize;
#else // ..and this if we want uniform scaling based on largest dimension
- GLfloat labelXTrans = aspectRatio * m_backgroundMargin;
+ GLfloat labelXTrans = m_graphAspectRatio + m_backgroundMargin;
GLfloat labelZTrans = labelXTrans;
#endif
- // Back wall init
+ // Back & side wall
GLfloat labelMarginXTrans = labelMargin;
GLfloat labelMarginZTrans = labelMargin;
- GLfloat rotLabelX = 0.0f;
- GLfloat rotLabelY = -90.0f;
- GLfloat rotLabelZ = 0.0f;
- Qt::AlignmentFlag alignmentBack = Qt::AlignLeft;
+ QVector3D backLabelRotation(0.0f, -90.0f, 0.0f);
+ QVector3D sideLabelRotation(0.0f, 0.0f, 0.0f);
+ Qt::AlignmentFlag backAlignment =
+ (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ Qt::AlignmentFlag sideAlignment =
+ (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
if (!m_xFlipped) {
labelXTrans = -labelXTrans;
labelMarginXTrans = -labelMargin;
- rotLabelY = 90.0f;
}
if (m_zFlipped) {
labelZTrans = -labelZTrans;
labelMarginZTrans = -labelMargin;
- alignmentBack = Qt::AlignRight;
}
- QVector3D labelRotateVectorBack(rotLabelX, rotLabelY, rotLabelZ);
- QVector3D labelTransBack = QVector3D(labelXTrans, 0.0f, labelZTrans + labelMarginZTrans);
+ if (labelAutoAngle == 0.0f) {
+ if (!m_xFlipped)
+ backLabelRotation.setY(90.0f);
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.f);
+ } else {
+ // Orient side labels somewhat towards the camera
+ if (m_xFlipped) {
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.0f + (2.0f * labelAutoAngle) - fractionCamX);
+ else
+ sideLabelRotation.setY(-fractionCamX);
+ backLabelRotation.setY(-90.0f + labelAutoAngle - fractionCamX);
+ } else {
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.0f - (2.0f * labelAutoAngle) - fractionCamX);
+ else
+ sideLabelRotation.setY(-fractionCamX);
+ backLabelRotation.setY(90.0f - labelAutoAngle - fractionCamX);
+ }
+ }
+ sideLabelRotation.setX(-fractionCamY);
+ backLabelRotation.setX(-fractionCamY);
- // Side wall init
- Qt::AlignmentFlag alignmentSide = Qt::AlignLeft;
- if (m_xFlipped)
- alignmentSide = Qt::AlignLeft;
- else
- alignmentSide = Qt::AlignRight;
- if (m_zFlipped)
- rotLabelY = 180.0f;
- else
- rotLabelY = 0.0f;
+ QQuaternion totalSideRotation = Utils::calculateRotation(sideLabelRotation);
+ QQuaternion totalBackRotation = Utils::calculateRotation(backLabelRotation);
- QVector3D labelRotateVectorSide(rotLabelX, rotLabelY, rotLabelZ);
+ QVector3D labelTransBack = QVector3D(labelXTrans, 0.0f, labelZTrans + labelMarginZTrans);
QVector3D labelTransSide(-labelXTrans - labelMarginXTrans, 0.0f, -labelZTrans);
- for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) {
- if (m_axisCacheY.labelItems().size() > labelNbr) {
- const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
- const GLfloat labelYTrans = labelPos / m_heightNormalizer;
-
- glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f);
-
- // Back wall
- labelTransBack.setY(labelYTrans);
- m_dummyRenderItem.setTranslation(labelTransBack);
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, labelRotateVectorBack, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera, true, true,
- Drawer::LabelMid, alignmentBack);
-
- // Side wall
- labelTransSide.setY(labelYTrans);
- m_dummyRenderItem.setTranslation(labelTransSide);
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- zeroVector, labelRotateVectorSide, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera, true, true,
- Drawer::LabelMid, alignmentSide);
- }
- labelNbr++;
- labelPos += posStep;
+ if (m_yFlipped) {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ } else {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
}
- }
- glDisable(GL_POLYGON_OFFSET_FILL);
+ for (int label = startIndex; label != endIndex; label = label + indexStep) {
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(label);
+ const GLfloat labelYTrans = m_axisCacheY.labelPosition(label);
- // Handle selection clearing and selection label drawing
- if (!dotSelectionFound) {
- // We have no ownership, don't delete. Just NULL the pointer.
- m_selectedItem = NULL;
- } else {
- glDisable(GL_DEPTH_TEST);
- // Draw the selection label
- LabelItem &labelItem = selectionLabelItem();
- if (m_selectedItem != selectedItem || m_updateLabels
- || !labelItem.textureId() || m_selectionLabelDirty) {
- QString labelText = selectionLabel();
- if (labelText.isNull() || m_selectionLabelDirty) {
- static const QString xTitleTag(QStringLiteral("@xTitle"));
- static const QString yTitleTag(QStringLiteral("@yTitle"));
- static const QString zTitleTag(QStringLiteral("@zTitle"));
- static const QString xLabelTag(QStringLiteral("@xLabel"));
- static const QString yLabelTag(QStringLiteral("@yLabel"));
- static const QString zLabelTag(QStringLiteral("@zLabel"));
- static const QString seriesNameTag(QStringLiteral("@seriesName"));
-
- labelText = m_visibleSeriesList[m_selectedItemSeriesIndex].itemLabelFormat();
-
- labelText.replace(xTitleTag, m_axisCacheX.title());
- labelText.replace(yTitleTag, m_axisCacheY.title());
- labelText.replace(zTitleTag, m_axisCacheZ.title());
-
- if (labelText.contains(xLabelTag)) {
- QString labelFormat = m_axisCacheX.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat,
- selectedItem->position().x());
- labelText.replace(xLabelTag, valueLabelText);
- }
- if (labelText.contains(yLabelTag)) {
- QString labelFormat = m_axisCacheY.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat,
- selectedItem->position().y());
- labelText.replace(yLabelTag, valueLabelText);
- }
- if (labelText.contains(zLabelTag)) {
- QString labelFormat = m_axisCacheZ.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat,
- selectedItem->position().z());
- labelText.replace(zLabelTag, valueLabelText);
- }
- labelText.replace(seriesNameTag, m_visibleSeriesList[m_selectedItemSeriesIndex].name());
+ glPolygonOffset(GLfloat(label) / -10.0f, 1.0f);
- setSelectionLabel(labelText);
- m_selectionLabelDirty = false;
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(0.0f, 0.0f, label / 255.0f,
+ alphaForValueSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- m_drawer->generateLabelItem(labelItem, labelText);
- m_selectedItem = selectedItem;
- }
- m_drawer->drawLabel(*selectedItem, labelItem, viewMatrix, projectionMatrix,
- zeroVector, zeroVector, selectedItemSize, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera, true, false,
- Drawer::LabelOver);
+ // Back wall
+ labelTransBack.setY(labelYTrans);
+ m_dummyRenderItem.setTranslation(labelTransBack);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalBackRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera, true, true,
+ Drawer::LabelMid, backAlignment, false, drawSelection);
- // Reset label update flag; they should have been updated when we get here
- m_updateLabels = false;
- glEnable(GL_DEPTH_TEST);
+ // Side wall
+ labelTransSide.setY(labelYTrans);
+ m_dummyRenderItem.setTranslation(labelTransSide);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ zeroVector, totalSideRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera, true, true,
+ Drawer::LabelMid, sideAlignment, false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+ if (!drawSelection && m_axisCacheY.isTitleVisible()) {
+ labelTransSide.setY(0.0f);
+ labelTransBack.setY(0.0f);
+ drawAxisTitleY(sideLabelRotation, backLabelRotation, labelTransSide, labelTransBack,
+ totalSideRotation, totalBackRotation, m_dummyRenderItem, activeCamera,
+ labelsMaxWidth, viewMatrix, projectionMatrix,
+ shader);
+ }
}
-
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
-
- // Release shader
- glUseProgram(0);
-
- m_selectionDirty = false;
+ glDisable(GL_POLYGON_OFFSET_FILL);
}
-void Scatter3DRenderer::updateSelectedItem(int index, const QScatter3DSeries *series)
+void Scatter3DRenderer::updateSelectedItem(int index, QScatter3DSeries *series)
{
m_selectionDirty = true;
m_selectionLabelDirty = true;
- m_selectedSeries = series;
+ m_selectedSeriesCache =
+ static_cast<ScatterSeriesRenderCache *>(m_renderCacheList.value(series, 0));
m_selectedItemIndex = Scatter3DController::invalidSelectionIndex();
- m_selectedItemTotalIndex = Scatter3DController::invalidSelectionIndex();
- m_selectedItemSeriesIndex = Scatter3DController::invalidSelectionIndex();
- if (!m_renderingArrays.isEmpty() && index != Scatter3DController::invalidSelectionIndex()) {
- int totalIndex = 0;
- for (int i = 0; i < m_visibleSeriesList.size(); i++) {
- if (m_visibleSeriesList.at(i).series() == series) {
- m_selectedItemSeriesIndex = i;
- m_selectedItemIndex = index;
- m_selectedItemTotalIndex = index + totalIndex;
- break;
+ if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic)
+ && m_oldSelectedSeriesCache
+ && m_oldSelectedSeriesCache->mesh() == QAbstract3DSeries::MeshPoint) {
+ m_oldSelectedSeriesCache->bufferPoints()->popPoint();
+ m_oldSelectedSeriesCache = 0;
+ }
+
+ if (m_selectedSeriesCache) {
+ const ScatterRenderItemArray &renderArray = m_selectedSeriesCache->renderArray();
+ if (index < renderArray.size() && index >= 0) {
+ m_selectedItemIndex = index;
+
+ if (m_cachedOptimizationHint.testFlag(QAbstract3DGraph::OptimizationStatic)
+ && m_selectedSeriesCache->mesh() == QAbstract3DSeries::MeshPoint) {
+ m_selectedSeriesCache->bufferPoints()->pushPoint(m_selectedItemIndex);
+ m_oldSelectedSeriesCache = m_selectedSeriesCache;
}
- totalIndex += m_renderingArrays.at(i).size();
}
}
}
@@ -1598,26 +1950,8 @@ void Scatter3DRenderer::updateShadowQuality(QAbstract3DGraph::ShadowQuality qual
void Scatter3DRenderer::loadBackgroundMesh()
{
- if (m_backgroundObj)
- delete m_backgroundObj;
- m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
- m_backgroundObj->load();
-}
-
-void Scatter3DRenderer::loadGridLineMesh()
-{
- if (m_gridLineObj)
- delete m_gridLineObj;
- m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_gridLineObj->load();
-}
-
-void Scatter3DRenderer::loadLabelMesh()
-{
- if (m_labelObj)
- delete m_labelObj;
- m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_labelObj->load();
+ ObjectHelper::resetObjectHelper(this, m_backgroundObj,
+ QStringLiteral(":/defaultMeshes/background"));
}
void Scatter3DRenderer::updateTextures()
@@ -1640,11 +1974,10 @@ void Scatter3DRenderer::fixMeshFileName(QString &fileName, QAbstract3DSeries::Me
void Scatter3DRenderer::calculateTranslation(ScatterRenderItem &item)
{
// We need to normalize translations
- GLfloat xTrans = (aspectRatio * (item.position().x() - m_translationOffset.x()))
- / m_scaleFactor;
- GLfloat zTrans = -(aspectRatio * (item.position().z() - m_translationOffset.z()))
- / m_scaleFactor;
- GLfloat yTrans = (item.position().y() - m_translationOffset.y()) / m_heightNormalizer;
+ const QVector3D &pos = item.position();
+ float xTrans = m_axisCacheX.positionAt(pos.x());
+ float yTrans = m_axisCacheY.positionAt(pos.y());
+ float zTrans = m_axisCacheZ.positionAt(pos.z());
item.setTranslation(QVector3D(xTrans, yTrans, zTrans));
}
@@ -1655,10 +1988,16 @@ void Scatter3DRenderer::calculateSceneScalingFactors()
m_areaSize.setWidth((m_axisCacheX.max() - m_axisCacheX.min()) / 2.0f);
m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height());
- // Calculate translation offsets
- m_translationOffset = QVector3D((m_axisCacheX.max() + m_axisCacheX.min()) / 2.0f,
- (m_axisCacheY.max() + m_axisCacheY.min()) / 2.0f,
- (m_axisCacheZ.max() + m_axisCacheZ.min()) / 2.0f);
+#ifndef USE_UNIFORM_SCALING // Use this if we want to use autoscaling for x and z
+ float factorScaler = 2.0f * m_graphAspectRatio / m_scaleFactor;
+ m_axisCacheX.setScale(factorScaler * m_areaSize.width());
+ m_axisCacheZ.setScale(-factorScaler * m_areaSize.height());
+#else // ..and this if we want uniform scaling based on largest dimension
+ m_axisCacheX.setScale(2.0f * m_graphAspectRatio);
+ m_axisCacheZ.setScale(-m_axisCacheX.scale());
+#endif
+ m_axisCacheX.setTranslate(-m_axisCacheX.scale() / 2.0f);
+ m_axisCacheZ.setTranslate(-m_axisCacheZ.scale() / 2.0f);
}
void Scatter3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader)
@@ -1689,10 +2028,7 @@ void Scatter3DRenderer::initSelectionShader()
void Scatter3DRenderer::initSelectionBuffer()
{
- if (m_selectionTexture) {
- m_textureHelper->deleteTexture(&m_selectionTexture);
- m_selectionTexture = 0;
- }
+ m_textureHelper->deleteTexture(&m_selectionTexture);
if (m_primarySubViewport.size().isEmpty())
return;
@@ -1714,10 +2050,7 @@ void Scatter3DRenderer::initDepthShader()
void Scatter3DRenderer::updateDepthBuffer()
{
- if (m_depthTexture) {
- m_textureHelper->deleteTexture(&m_depthTexture);
- m_depthTexture = 0;
- }
+ m_textureHelper->deleteTexture(&m_depthTexture);
if (m_primarySubViewport.size().isEmpty())
return;
@@ -1758,30 +2091,54 @@ void Scatter3DRenderer::initLabelShaders(const QString &vertexShader, const QStr
m_labelShader->initialize();
}
-QVector3D Scatter3DRenderer::indexToSelectionColor(GLint index)
-{
- GLubyte dotIdxRed = index & 0xff;
- GLubyte dotIdxGreen = (index & 0xff00) >> 8;
- GLubyte dotIdxBlue = (index & 0xff0000) >> 16;
-
- return QVector3D(dotIdxRed, dotIdxGreen, dotIdxBlue);
-}
-
-void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector3D &color,
+void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector4D &color,
int &index,
QAbstract3DSeries *&series)
{
+ m_clickedType = QAbstract3DGraph::ElementNone;
+ m_selectedLabelIndex = -1;
+ m_selectedCustomItemIndex = -1;
if (color != selectionSkipColor) {
- index = int(color.x())
- + (int(color.y()) << 8)
- + (int(color.z()) << 16);
- // Find the series and adjust the index accordingly
- for (int i = 0; i < m_renderingArrays.size(); i++) {
- if (index < m_renderingArrays.at(i).size()) {
- series = m_visibleSeriesList.at(i).series();
- return; // Valid found and already set to return parameters, so we can return
- } else {
- index -= m_renderingArrays.at(i).size();
+ if (color.w() == labelRowAlpha) {
+ // Row selection
+ index = Scatter3DController::invalidSelectionIndex();
+ m_selectedLabelIndex = color.x();
+ m_clickedType = QAbstract3DGraph::ElementAxisZLabel;
+ } else if (color.w() == labelColumnAlpha) {
+ // Column selection
+ index = Scatter3DController::invalidSelectionIndex();
+ m_selectedLabelIndex = color.y();
+ m_clickedType = QAbstract3DGraph::ElementAxisXLabel;
+ } else if (color.w() == labelValueAlpha) {
+ // Value selection
+ index = Scatter3DController::invalidSelectionIndex();
+ m_selectedLabelIndex = color.z();
+ m_clickedType = QAbstract3DGraph::ElementAxisYLabel;
+ } else if (color.w() == customItemAlpha) {
+ // Custom item selection
+ index = Scatter3DController::invalidSelectionIndex();
+ m_selectedCustomItemIndex = int(color.x())
+ + (int(color.y()) << 8)
+ + (int(color.z()) << 16);
+ m_clickedType = QAbstract3DGraph::ElementCustomItem;
+ } else {
+ int totalIndex = int(color.x())
+ + (int(color.y()) << 8)
+ + (int(color.z()) << 16);
+ // Find the series and adjust the index accordingly
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ if (baseCache->isVisible()) {
+ ScatterSeriesRenderCache *cache =
+ static_cast<ScatterSeriesRenderCache *>(baseCache);
+ int offset = cache->selectionIndexOffset();
+ if (totalIndex >= offset
+ && totalIndex < (offset + cache->renderArray().size())) {
+ index = totalIndex - offset;
+ series = cache->series();
+ m_clickedType = QAbstract3DGraph::ElementSeries;
+ return;
+ }
+ }
}
}
}
@@ -1791,4 +2148,41 @@ void Scatter3DRenderer::selectionColorToSeriesAndIndex(const QVector3D &color,
series = 0;
}
+void Scatter3DRenderer::updateRenderItem(const QScatterDataItem &dataItem,
+ ScatterRenderItem &renderItem)
+{
+ QVector3D dotPos = dataItem.position();
+ if ((dotPos.x() >= m_axisCacheX.min() && dotPos.x() <= m_axisCacheX.max() )
+ && (dotPos.y() >= m_axisCacheY.min() && dotPos.y() <= m_axisCacheY.max())
+ && (dotPos.z() >= m_axisCacheZ.min() && dotPos.z() <= m_axisCacheZ.max())) {
+ renderItem.setPosition(dotPos);
+ renderItem.setVisible(true);
+ if (!dataItem.rotation().isIdentity())
+ renderItem.setRotation(dataItem.rotation().normalized());
+ else
+ renderItem.setRotation(identityQuaternion);
+ calculateTranslation(renderItem);
+ } else {
+ renderItem.setVisible(false);
+ }
+}
+
+QVector3D Scatter3DRenderer::convertPositionToTranslation(const QVector3D &position,
+ bool isAbsolute)
+{
+ float xTrans = 0.0f;
+ float yTrans = 0.0f;
+ float zTrans = 0.0f;
+ if (!isAbsolute) {
+ xTrans = m_axisCacheX.positionAt(position.x());
+ yTrans = m_axisCacheY.positionAt(position.y());
+ zTrans = m_axisCacheZ.positionAt(position.z());
+ } else {
+ xTrans = position.x() * m_axisCacheX.scale() / 2.0f;
+ yTrans = position.y();
+ zTrans = position.z() * m_axisCacheZ.scale() / 2.0f;
+ }
+ return QVector3D(xTrans, yTrans, zTrans);
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/scatter3drenderer_p.h b/src/datavisualization/engine/scatter3drenderer_p.h
index 5591a362..7f213179 100644
--- a/src/datavisualization/engine/scatter3drenderer_p.h
+++ b/src/datavisualization/engine/scatter3drenderer_p.h
@@ -32,20 +32,16 @@
#include "datavisualizationglobal_p.h"
#include "scatter3dcontroller_p.h"
#include "abstract3drenderer_p.h"
-#include "qscatterdataproxy.h"
#include "scatterrenderitem_p.h"
-class QPoint;
class QSizeF;
-class QOpenGLShaderProgram;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class ShaderHelper;
-class ObjectHelper;
-class LabelItem;
class Q3DScene;
-class QAbstractAxisPrivate;
+class ScatterSeriesRenderCache;
+class QScatterDataItem;
class QT_DATAVISUALIZATION_EXPORT Scatter3DRenderer : public Abstract3DRenderer
{
@@ -54,9 +50,6 @@ class QT_DATAVISUALIZATION_EXPORT Scatter3DRenderer : public Abstract3DRenderer
private:
// Internal state
ScatterRenderItem *m_selectedItem; // points to renderitem array
- bool m_xFlipped;
- bool m_zFlipped;
- bool m_yFlipped;
bool m_updateLabels;
ShaderHelper *m_dotShader;
ShaderHelper *m_dotGradientShader;
@@ -67,9 +60,6 @@ private:
ShaderHelper *m_selectionShader;
ShaderHelper *m_backgroundShader;
ShaderHelper *m_labelShader;
- ObjectHelper *m_backgroundObj;
- ObjectHelper *m_gridLineObj;
- ObjectHelper *m_labelObj;
GLuint m_bgrTexture;
GLuint m_depthTexture;
GLuint m_selectionTexture;
@@ -81,33 +71,40 @@ private:
GLfloat m_heightNormalizer;
GLfloat m_scaleFactor;
int m_selectedItemIndex;
- int m_selectedItemTotalIndex;
- int m_selectedItemSeriesIndex;
- const QScatter3DSeries *m_selectedSeries;
+ ScatterSeriesRenderCache *m_selectedSeriesCache;
+ ScatterSeriesRenderCache *m_oldSelectedSeriesCache;
QSizeF m_areaSize;
GLfloat m_dotSizeScale;
- QVector3D m_translationOffset;
bool m_hasHeightAdjustmentChanged;
ScatterRenderItem m_dummyRenderItem;
- QVector<ScatterRenderItemArray> m_renderingArrays;
GLfloat m_backgroundMargin;
GLfloat m_maxItemSize;
- QVector<float> m_cachedItemSize;
int m_clickedIndex;
+ bool m_havePointSeries;
+ bool m_haveMeshSeries;
+ bool m_haveUniformColorMeshSeries;
+ bool m_haveGradientMeshSeries;
public:
explicit Scatter3DRenderer(Scatter3DController *controller);
~Scatter3DRenderer();
- void updateSeries(const QList<QAbstract3DSeries *> &seriesList, bool updateVisibility);
void updateData();
+ void updateSeries(const QList<QAbstract3DSeries *> &seriesList);
+ SeriesRenderCache *createNewCache(QAbstract3DSeries *series);
+ void updateItems(const QVector<Scatter3DController::ChangeItem> &items);
void updateScene(Q3DScene *scene);
+ QVector3D convertPositionToTranslation(const QVector3D &position, bool isAbsolute);
+
inline int clickedIndex() const { return m_clickedIndex; }
void resetClickedStatus();
void render(GLuint defaultFboHandle);
+public slots:
+ void updateSelectedItem(int index, QScatter3DSeries *series);
+
protected:
virtual void initializeOpenGL();
@@ -119,10 +116,10 @@ private:
virtual void fixMeshFileName(QString &fileName, QAbstract3DSeries::Mesh mesh);
void drawScene(GLuint defaultFboHandle);
+ void drawLabels(bool drawSelection, const Q3DCamera *activeCamera,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix);
void loadBackgroundMesh();
- void loadGridLineMesh();
- void loadLabelMesh();
void initSelectionShader();
void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
@@ -136,17 +133,11 @@ private:
void calculateTranslation(ScatterRenderItem &item);
void calculateSceneScalingFactors();
- Q_DISABLE_COPY(Scatter3DRenderer)
-
- friend class ScatterRenderItem;
-
-public slots:
- void updateSelectedItem(int index, const QScatter3DSeries *series);
-
-private:
- QVector3D indexToSelectionColor(GLint index);
- void selectionColorToSeriesAndIndex(const QVector3D &color, int &index,
+ void selectionColorToSeriesAndIndex(const QVector4D &color, int &index,
QAbstract3DSeries *&series);
+ inline void updateRenderItem(const QScatterDataItem &dataItem, ScatterRenderItem &renderItem);
+
+ Q_DISABLE_COPY(Scatter3DRenderer)
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/scatterseriesrendercache.cpp b/src/datavisualization/engine/scatterseriesrendercache.cpp
new file mode 100644
index 00000000..e8888d19
--- /dev/null
+++ b/src/datavisualization/engine/scatterseriesrendercache.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "scatterseriesrendercache_p.h"
+#include "scatterobjectbufferhelper_p.h"
+#include "scatterpointbufferhelper_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+ScatterSeriesRenderCache::ScatterSeriesRenderCache(QAbstract3DSeries *series,
+ Abstract3DRenderer *renderer)
+ : SeriesRenderCache(series, renderer),
+ m_itemSize(0.0f),
+ m_selectionIndexOffset(0),
+ m_oldRenderArraySize(0),
+ m_oldMeshFileName(QString()),
+ m_scatterBufferObj(0),
+ m_scatterBufferPoints(0)
+{
+}
+
+ScatterSeriesRenderCache::~ScatterSeriesRenderCache()
+{
+ delete m_scatterBufferObj;
+ delete m_scatterBufferPoints;
+}
+
+void ScatterSeriesRenderCache::cleanup(TextureHelper *texHelper)
+{
+ m_renderArray.clear();
+
+ SeriesRenderCache::cleanup(texHelper);
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/scatterseriesrendercache_p.h b/src/datavisualization/engine/scatterseriesrendercache_p.h
new file mode 100644
index 00000000..490e21fb
--- /dev/null
+++ b/src/datavisualization/engine/scatterseriesrendercache_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SCATTERSERIESRENDERCACHE_P_H
+#define SCATTERSERIESRENDERCACHE_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "seriesrendercache_p.h"
+#include "qscatter3dseries_p.h"
+#include "scatterrenderitem_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class ScatterObjectBufferHelper;
+class ScatterPointBufferHelper;
+
+class ScatterSeriesRenderCache : public SeriesRenderCache
+{
+public:
+ ScatterSeriesRenderCache(QAbstract3DSeries *series, Abstract3DRenderer *renderer);
+ virtual ~ScatterSeriesRenderCache();
+
+ void cleanup(TextureHelper *texHelper);
+
+ inline ScatterRenderItemArray &renderArray() { return m_renderArray; }
+ inline QScatter3DSeries *series() const { return static_cast<QScatter3DSeries *>(m_series); }
+ inline void setItemSize(float size) { m_itemSize = size; }
+ inline float itemSize() const { return m_itemSize; }
+ inline void setSelectionIndexOffset(int offset) { m_selectionIndexOffset = offset; }
+ inline int selectionIndexOffset() const { return m_selectionIndexOffset; }
+ inline int oldArraySize() const { return m_oldRenderArraySize; }
+ inline void setOldArraySize(int size) { m_oldRenderArraySize = size; }
+ inline const QString &oldMeshFileName() const { return m_oldMeshFileName; }
+ inline void setOldMeshFileName(const QString &meshFileName) { m_oldMeshFileName = meshFileName; }
+ inline void setBufferObject(ScatterObjectBufferHelper *object) { m_scatterBufferObj = object; }
+ inline ScatterObjectBufferHelper *bufferObject() const { return m_scatterBufferObj; }
+ inline void setBufferPoints(ScatterPointBufferHelper *object) { m_scatterBufferPoints = object; }
+ inline ScatterPointBufferHelper *bufferPoints() const { return m_scatterBufferPoints; }
+
+protected:
+ ScatterRenderItemArray m_renderArray;
+ float m_itemSize;
+ int m_selectionIndexOffset; // Temporarily cached value for selection color calculations
+ int m_oldRenderArraySize; // Used to detect if full buffer change needed
+ QString m_oldMeshFileName; // Used to detect if full buffer change needed
+ ScatterObjectBufferHelper *m_scatterBufferObj;
+ ScatterPointBufferHelper *m_scatterBufferPoints;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/engine/selectionpointer.cpp b/src/datavisualization/engine/selectionpointer.cpp
index d4e635bc..183d3f8e 100644
--- a/src/datavisualization/engine/selectionpointer.cpp
+++ b/src/datavisualization/engine/selectionpointer.cpp
@@ -17,16 +17,11 @@
****************************************************************************/
#include "selectionpointer_p.h"
-#include "surface3dcontroller_p.h"
#include "shaderhelper_p.h"
#include "objecthelper_p.h"
#include "texturehelper_p.h"
#include "q3dcamera_p.h"
-#include "drawer_p.h"
#include "utils_p.h"
-#include "q3dlight.h"
-
-#include <QtGui/QMatrix4x4>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -54,7 +49,6 @@ SelectionPointer::~SelectionPointer()
{
delete m_labelShader;
delete m_pointShader;
- delete m_labelObj;
delete m_textureHelper;
}
@@ -66,7 +60,6 @@ void SelectionPointer::initializeOpenGL()
m_drawer->initializeOpenGL();
initShaders();
- loadLabelMesh();
}
void SelectionPointer::updateScene(Q3DScene *scene)
@@ -74,7 +67,7 @@ void SelectionPointer::updateScene(Q3DScene *scene)
m_cachedScene = scene;
}
-void SelectionPointer::render(GLuint defaultFboHandle)
+void SelectionPointer::render(GLuint defaultFboHandle, bool useOrtho)
{
Q_UNUSED(defaultFboHandle)
@@ -89,17 +82,22 @@ void SelectionPointer::render(GLuint defaultFboHandle)
// Get view matrix
QMatrix4x4 viewMatrix;
QMatrix4x4 projectionMatrix;
+ GLfloat viewPortRatio = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
if (m_cachedIsSlicingActivated) {
- GLfloat aspect = (GLfloat)m_mainViewPort.width() / (GLfloat)m_mainViewPort.height();
GLfloat sliceUnitsScaled = sliceUnits / m_autoScaleAdjustment;
viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 1.0f), zeroVector, upVector);
- projectionMatrix.ortho(-sliceUnitsScaled * aspect, sliceUnitsScaled * aspect,
+ projectionMatrix.ortho(-sliceUnitsScaled * viewPortRatio, sliceUnitsScaled * viewPortRatio,
-sliceUnitsScaled, sliceUnitsScaled,
-1.0f, 4.0f);
+ } else if (useOrtho) {
+ viewMatrix = camera->d_ptr->viewMatrix();
+ GLfloat orthoRatio = 2.0f;
+ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
+ -orthoRatio, orthoRatio,
+ 0.0f, 100.0f);
} else {
viewMatrix = camera->d_ptr->viewMatrix();
- projectionMatrix.perspective(45.0f, (GLfloat)m_mainViewPort.width()
- / (GLfloat)m_mainViewPort.height(), 0.1f, 100.0f);
+ projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
}
// Calculate scale factor to get uniform font size
@@ -209,7 +207,7 @@ void SelectionPointer::updateSliceData(bool sliceActivated, GLfloat autoScaleAdj
m_autoScaleAdjustment = autoScaleAdjustment;
}
-void SelectionPointer::setHighlightColor(const QVector3D &colorVector)
+void SelectionPointer::setHighlightColor(const QVector4D &colorVector)
{
m_highlightColor = colorVector;
}
@@ -230,6 +228,11 @@ void SelectionPointer::setPointerObject(ObjectHelper *object)
m_pointObj = object;
}
+void SelectionPointer::setLabelObject(ObjectHelper *object)
+{
+ m_labelObj = object;
+}
+
void SelectionPointer::handleDrawerChange()
{
m_cachedTheme = m_drawer->theme();
@@ -264,12 +267,4 @@ void SelectionPointer::initShaders()
}
-void SelectionPointer::loadLabelMesh()
-{
- if (m_labelObj)
- delete m_labelObj;
- m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_labelObj->load();
-}
-
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/selectionpointer_p.h b/src/datavisualization/engine/selectionpointer_p.h
index 1eac22be..7dc28024 100644
--- a/src/datavisualization/engine/selectionpointer_p.h
+++ b/src/datavisualization/engine/selectionpointer_p.h
@@ -29,7 +29,6 @@
#ifndef SELECTIONPOINTER_P_H
#define SELECTIONPOINTER_P_H
-#include "q3dscene.h"
#include "datavisualizationglobal_p.h"
#include "surface3dcontroller_p.h"
@@ -37,7 +36,6 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class ShaderHelper;
class ObjectHelper;
-class SurfaceObject;
class TextureHelper;
class Drawer;
@@ -49,26 +47,26 @@ public:
explicit SelectionPointer(Drawer *drawer);
~SelectionPointer();
- void render(GLuint defaultFboHandle = 0);
+ void render(GLuint defaultFboHandle = 0, bool useOrtho = false);
void setPosition(const QVector3D &position);
void setLabel(const QString &label);
void setPointerObject(ObjectHelper *object);
+ void setLabelObject(ObjectHelper *object);
void handleDrawerChange();
void updateBoundingRect(const QRect &rect);
void updateScene(Q3DScene *scene);
void updateSliceData(bool sliceActivated, GLfloat autoScaleAdjustment);
- void setHighlightColor(const QVector3D &colorVector);
+ void setHighlightColor(const QVector4D &colorVector);
void setRotation(const QQuaternion &rotation);
private:
void initializeOpenGL();
void initShaders();
- void loadLabelMesh();
private:
ShaderHelper *m_labelShader;
ShaderHelper *m_pointShader;
- ObjectHelper *m_labelObj;
+ ObjectHelper *m_labelObj; // Not owned
ObjectHelper *m_pointObj; // Not owned
TextureHelper *m_textureHelper;
Q3DTheme *m_cachedTheme;
@@ -81,7 +79,7 @@ private:
QString m_label;
bool m_cachedIsSlicingActivated;
GLfloat m_autoScaleAdjustment;
- QVector3D m_highlightColor;
+ QVector4D m_highlightColor;
QQuaternion m_rotation;
};
diff --git a/src/datavisualization/engine/seriesrendercache.cpp b/src/datavisualization/engine/seriesrendercache.cpp
index 896b3b28..dc4b9db3 100644
--- a/src/datavisualization/engine/seriesrendercache.cpp
+++ b/src/datavisualization/engine/seriesrendercache.cpp
@@ -17,7 +17,6 @@
****************************************************************************/
#include "seriesrendercache_p.h"
-#include "objecthelper_p.h"
#include "abstract3drenderer_p.h"
#include "texturehelper_p.h"
#include "utils_p.h"
@@ -26,14 +25,19 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
const QString smoothString(QStringLiteral("Smooth"));
-SeriesRenderCache::SeriesRenderCache()
- : m_series(0),
+SeriesRenderCache::SeriesRenderCache(QAbstract3DSeries *series, Abstract3DRenderer *renderer)
+ : m_series(series),
m_object(0),
m_mesh(QAbstract3DSeries::MeshCube),
m_baseUniformTexture(0),
m_baseGradientTexture(0),
+ m_gradientImage(0),
m_singleHighlightGradientTexture(0),
- m_multiHighlightGradientTexture(0)
+ m_multiHighlightGradientTexture(0),
+ m_valid(false),
+ m_visible(false),
+ m_renderer(renderer),
+ m_objectDirty(true)
{
}
@@ -41,27 +45,13 @@ SeriesRenderCache::~SeriesRenderCache()
{
}
-void SeriesRenderCache::populate(QAbstract3DSeries *series, Abstract3DRenderer *renderer)
+void SeriesRenderCache::populate(bool newSeries)
{
- Q_ASSERT(series);
+ QAbstract3DSeriesChangeBitField &changeTracker = m_series->d_ptr->m_changeTracker;
- bool seriesChanged = false;
-
- if (m_series != series) {
- m_series = series;
- seriesChanged = true;
- }
-
- QAbstract3DSeriesChangeBitField &changeTracker = series->d_ptr->m_changeTracker;
-
- if (seriesChanged || changeTracker.itemLabelFormatChanged) {
- m_itemLabelFormat = series->itemLabelFormat();
- changeTracker.itemLabelFormatChanged = false;
- }
-
- if (seriesChanged || changeTracker.meshChanged || changeTracker.meshSmoothChanged
+ if (newSeries || changeTracker.meshChanged || changeTracker.meshSmoothChanged
|| changeTracker.userDefinedMeshChanged) {
- m_mesh = series->mesh();
+ m_mesh = m_series->mesh();
changeTracker.meshChanged = false;
changeTracker.meshSmoothChanged = false;
changeTracker.userDefinedMeshChanged = false;
@@ -71,7 +61,7 @@ void SeriesRenderCache::populate(QAbstract3DSeries *series, Abstract3DRenderer *
// Compose mesh filename
if (m_mesh == QAbstract3DSeries::MeshUserDefined) {
// Always use the supplied mesh directly
- meshFileName = series->userDefinedMesh();
+ meshFileName = m_series->userDefinedMesh();
} else {
switch (m_mesh) {
case QAbstract3DSeries::MeshBar:
@@ -111,24 +101,18 @@ void SeriesRenderCache::populate(QAbstract3DSeries *series, Abstract3DRenderer *
break;
}
- if (series->isMeshSmooth() && m_mesh != QAbstract3DSeries::MeshPoint)
+ if (m_series->isMeshSmooth() && m_mesh != QAbstract3DSeries::MeshPoint)
meshFileName += smoothString;
// Give renderer an opportunity to customize the mesh
- renderer->fixMeshFileName(meshFileName, m_mesh);
+ m_renderer->fixMeshFileName(meshFileName, m_mesh);
}
- delete m_object;
- if (meshFileName.isEmpty()) {
- m_object = 0;
- } else {
- m_object = new ObjectHelper(meshFileName);
- m_object->load();
- }
+ ObjectHelper::resetObjectHelper(m_renderer, m_object, meshFileName);
}
- if (seriesChanged || changeTracker.meshRotationChanged) {
- m_meshRotation = series->meshRotation().normalized();
+ if (newSeries || changeTracker.meshRotationChanged) {
+ m_meshRotation = m_series->meshRotation().normalized();
if (m_series->type() == QAbstract3DSeries::SeriesTypeBar
&& (m_meshRotation.x() || m_meshRotation.z())) {
m_meshRotation = identityQuaternion;
@@ -136,55 +120,73 @@ void SeriesRenderCache::populate(QAbstract3DSeries *series, Abstract3DRenderer *
changeTracker.meshRotationChanged = false;
}
- if (seriesChanged || changeTracker.colorStyleChanged) {
- m_colorStyle = series->colorStyle();
+ if (newSeries || changeTracker.colorStyleChanged) {
+ m_colorStyle = m_series->colorStyle();
changeTracker.colorStyleChanged = false;
}
- if (seriesChanged || changeTracker.baseColorChanged) {
- m_baseColor = Utils::vectorFromColor(series->baseColor());
+ if (newSeries || changeTracker.baseColorChanged) {
+ m_baseColor = Utils::vectorFromColor(m_series->baseColor());
if (m_series->type() == QAbstract3DSeries::SeriesTypeSurface)
- renderer->generateBaseColorTexture(series->baseColor(), &m_baseUniformTexture);
+ m_renderer->generateBaseColorTexture(m_series->baseColor(), &m_baseUniformTexture);
changeTracker.baseColorChanged = false;
}
- if (seriesChanged || changeTracker.baseGradientChanged) {
- QLinearGradient gradient = series->baseGradient();
- renderer->fixGradientAndGenerateTexture(&gradient, &m_baseGradientTexture);
+ if (newSeries || changeTracker.baseGradientChanged) {
+ QLinearGradient gradient = m_series->baseGradient();
+ m_gradientImage = Utils::getGradientImage(gradient);
+ m_renderer->fixGradientAndGenerateTexture(&gradient, &m_baseGradientTexture);
changeTracker.baseGradientChanged = false;
}
- if (seriesChanged || changeTracker.singleHighlightColorChanged) {
- m_singleHighlightColor = Utils::vectorFromColor(series->singleHighlightColor());
+ if (newSeries || changeTracker.singleHighlightColorChanged) {
+ m_singleHighlightColor = Utils::vectorFromColor(m_series->singleHighlightColor());
changeTracker.singleHighlightColorChanged = false;
}
- if (seriesChanged || changeTracker.singleHighlightGradientChanged) {
- QLinearGradient gradient = series->singleHighlightGradient();
- renderer->fixGradientAndGenerateTexture(&gradient, &m_singleHighlightGradientTexture);
+ if (newSeries || changeTracker.singleHighlightGradientChanged) {
+ QLinearGradient gradient = m_series->singleHighlightGradient();
+ m_renderer->fixGradientAndGenerateTexture(&gradient, &m_singleHighlightGradientTexture);
changeTracker.singleHighlightGradientChanged = false;
}
- if (seriesChanged || changeTracker.multiHighlightColorChanged) {
- m_multiHighlightColor = Utils::vectorFromColor(series->multiHighlightColor());
+ if (newSeries || changeTracker.multiHighlightColorChanged) {
+ m_multiHighlightColor = Utils::vectorFromColor(m_series->multiHighlightColor());
changeTracker.multiHighlightColorChanged = false;
}
- if (seriesChanged || changeTracker.multiHighlightGradientChanged) {
- QLinearGradient gradient = series->multiHighlightGradient();
- renderer->fixGradientAndGenerateTexture(&gradient, &m_multiHighlightGradientTexture);
+ if (newSeries || changeTracker.multiHighlightGradientChanged) {
+ QLinearGradient gradient = m_series->multiHighlightGradient();
+ m_renderer->fixGradientAndGenerateTexture(&gradient, &m_multiHighlightGradientTexture);
changeTracker.multiHighlightGradientChanged = false;
}
- if (seriesChanged || changeTracker.nameChanged) {
- m_name = series->name();
+ if (newSeries || changeTracker.nameChanged) {
+ m_name = m_series->name();
changeTracker.nameChanged = false;
}
+
+ if (newSeries || changeTracker.itemLabelChanged
+ || changeTracker.itemLabelVisibilityChanged) {
+ changeTracker.itemLabelChanged = false;
+ changeTracker.itemLabelVisibilityChanged = false;
+ // series->itemLabel() call resolves the item label and emits the changed signal
+ // if it is dirty, so we need to call it even if m_itemLabel is eventually set
+ // to an empty string.
+ m_itemLabel = m_series->itemLabel();
+ if (!m_series->isItemLabelVisible())
+ m_itemLabel = QString();
+ }
+
+ if (newSeries || changeTracker.visibilityChanged) {
+ m_visible = m_series->isVisible();
+ changeTracker.visibilityChanged = false;
+ }
}
void SeriesRenderCache::cleanup(TextureHelper *texHelper)
{
- delete m_object;
+ ObjectHelper::releaseObjectHelper(m_renderer, m_object);
if (QOpenGLContext::currentContext()) {
texHelper->deleteTexture(&m_baseUniformTexture);
texHelper->deleteTexture(&m_baseGradientTexture);
diff --git a/src/datavisualization/engine/seriesrendercache_p.h b/src/datavisualization/engine/seriesrendercache_p.h
index 77e050b0..96b61b87 100644
--- a/src/datavisualization/engine/seriesrendercache_p.h
+++ b/src/datavisualization/engine/seriesrendercache_p.h
@@ -41,48 +41,59 @@ class TextureHelper;
class SeriesRenderCache
{
public:
- SeriesRenderCache();
+ SeriesRenderCache(QAbstract3DSeries *series, Abstract3DRenderer *renderer);
virtual ~SeriesRenderCache();
- void populate(QAbstract3DSeries *series, Abstract3DRenderer *renderer);
+ virtual void populate(bool newSeries);
virtual void cleanup(TextureHelper *texHelper);
// NOTE: Series pointer can only be used to access the series when syncing with controller.
// It is not guaranteed to be valid while rendering and should only be used as an identifier.
inline QAbstract3DSeries *series() const { return m_series; }
- inline const QString &itemLabelFormat() const { return m_itemLabelFormat; }
inline const QAbstract3DSeries::Mesh &mesh() const { return m_mesh; }
inline const QQuaternion &meshRotation() const { return m_meshRotation; }
inline void setMeshRotation(const QQuaternion &rotation) { m_meshRotation = rotation; }
inline ObjectHelper *object() const { return m_object; }
inline const Q3DTheme::ColorStyle &colorStyle() const { return m_colorStyle; }
- inline const QVector3D &baseColor() const { return m_baseColor; }
+ inline const QVector4D &baseColor() const { return m_baseColor; }
inline const GLuint &baseUniformTexture() const { return m_baseUniformTexture; }
inline const GLuint &baseGradientTexture() const { return m_baseGradientTexture; }
- inline const QVector3D &singleHighlightColor() const { return m_singleHighlightColor; }
+ inline const QImage &gradientImage() const { return m_gradientImage; }
+ inline const QVector4D &singleHighlightColor() const { return m_singleHighlightColor; }
inline const GLuint &singleHighlightGradientTexture() const { return m_singleHighlightGradientTexture; }
- inline const QVector3D &multiHighlightColor() const { return m_multiHighlightColor; }
+ inline const QVector4D &multiHighlightColor() const { return m_multiHighlightColor; }
inline const GLuint &multiHighlightGradientTexture() const { return m_multiHighlightGradientTexture; }
inline const QString &name() const { return m_name; }
+ inline const QString &itemLabel() const { return m_itemLabel; }
+ inline void setValid(bool valid) { m_valid = valid; }
+ inline bool isValid() const { return m_valid; }
+ inline bool isVisible() const { return m_visible; }
+ inline void setDataDirty(bool state) { m_objectDirty = state; }
+ inline bool dataDirty() const { return m_objectDirty; }
protected:
QAbstract3DSeries *m_series;
- QString m_itemLabelFormat;
- ObjectHelper *m_object;
+ ObjectHelper *m_object; // Shared reference
QAbstract3DSeries::Mesh m_mesh;
QQuaternion m_meshRotation;
Q3DTheme::ColorStyle m_colorStyle;
- QVector3D m_baseColor;
+ QVector4D m_baseColor;
GLuint m_baseUniformTexture;
GLuint m_baseGradientTexture;
- QVector3D m_singleHighlightColor;
+ QImage m_gradientImage;
+ QVector4D m_singleHighlightColor;
GLuint m_singleHighlightGradientTexture;
- QVector3D m_multiHighlightColor;
+ QVector4D m_multiHighlightColor;
GLuint m_multiHighlightGradientTexture;
QString m_name;
+ QString m_itemLabel;
+ bool m_valid;
+ bool m_visible;
+ Abstract3DRenderer *m_renderer;
+ bool m_objectDirty;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/shaders/colorOnY.frag b/src/datavisualization/engine/shaders/colorOnY.frag
index 8c610cd7..7a5eb46b 100644
--- a/src/datavisualization/engine/shaders/colorOnY.frag
+++ b/src/datavisualization/engine/shaders/colorOnY.frag
@@ -6,7 +6,7 @@ uniform highp float ambientStrength;
uniform sampler2D textureSampler;
uniform highp float gradMin;
uniform highp float gradHeight;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
varying highp vec3 position_wrld;
varying highp vec3 normal_cmr;
@@ -17,8 +17,8 @@ varying highp vec2 coords_mdl;
void main() {
highp vec2 gradientUV = vec2(0.0, gradMin + ((coords_mdl.y + 1.0) * gradHeight));
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp float distance = length(lightPosition_wrld - position_wrld);
highp vec3 n = normalize(normal_cmr);
diff --git a/src/datavisualization/engine/shaders/colorOnY_ES2.frag b/src/datavisualization/engine/shaders/colorOnY_ES2.frag
index 5b553562..4352de05 100644
--- a/src/datavisualization/engine/shaders/colorOnY_ES2.frag
+++ b/src/datavisualization/engine/shaders/colorOnY_ES2.frag
@@ -1,11 +1,11 @@
-uniform highp vec3 lightPosition_wrld;
uniform highp float lightStrength;
uniform highp float ambientStrength;
uniform sampler2D textureSampler;
uniform highp float gradMin;
uniform highp float gradHeight;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
+varying highp vec3 lightPosition_wrld_frag;
varying highp vec3 position_wrld;
varying highp vec3 normal_cmr;
varying highp vec3 eyeDirection_cmr;
@@ -15,10 +15,10 @@ varying highp vec2 coords_mdl;
void main() {
highp vec2 gradientUV = vec2(0.0, gradMin + ((coords_mdl.y + 1.0) * gradHeight));
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
- highp float distance = length(lightPosition_wrld - position_wrld);
+ highp float distance = length(lightPosition_wrld_frag - position_wrld);
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
highp float cosTheta = dot(n, l);
diff --git a/src/datavisualization/engine/shaders/default.frag b/src/datavisualization/engine/shaders/default.frag
index ca6fefb9..d16055a3 100644
--- a/src/datavisualization/engine/shaders/default.frag
+++ b/src/datavisualization/engine/shaders/default.frag
@@ -8,15 +8,15 @@ varying highp vec3 eyeDirection_cmr;
varying highp vec3 lightDirection_cmr;
uniform highp vec3 lightPosition_wrld;
-uniform highp vec3 color_mdl;
+uniform highp vec4 color_mdl;
uniform highp float lightStrength;
uniform highp float ambientStrength;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
void main() {
highp vec3 materialDiffuseColor = color_mdl.rgb;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp float distance = length(lightPosition_wrld - position_wrld);
diff --git a/src/datavisualization/engine/shaders/default.vert b/src/datavisualization/engine/shaders/default.vert
index efb40862..b454913b 100644
--- a/src/datavisualization/engine/shaders/default.vert
+++ b/src/datavisualization/engine/shaders/default.vert
@@ -8,6 +8,7 @@ uniform highp mat4 M;
uniform highp mat4 itM;
uniform highp vec3 lightPosition_wrld;
+varying highp vec3 lightPosition_wrld_frag;
varying highp vec3 position_wrld;
varying highp vec3 normal_cmr;
varying highp vec3 eyeDirection_cmr;
@@ -17,10 +18,11 @@ varying highp vec2 coords_mdl;
void main() {
gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
coords_mdl = vertexPosition_mdl.xy;
- position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
- vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ position_wrld = vec4(M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = vec4(V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
- vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ vec3 lightPosition_cmr = vec4(V * vec4(lightPosition_wrld, 1.0)).xyz;
lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
- normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ normal_cmr = vec4(V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ lightPosition_wrld_frag = lightPosition_wrld;
}
diff --git a/src/datavisualization/engine/shaders/default_ES2.frag b/src/datavisualization/engine/shaders/default_ES2.frag
index bc5c18b6..73d66d5b 100644
--- a/src/datavisualization/engine/shaders/default_ES2.frag
+++ b/src/datavisualization/engine/shaders/default_ES2.frag
@@ -4,19 +4,19 @@ varying highp vec3 position_wrld;
varying highp vec3 normal_cmr;
varying highp vec3 eyeDirection_cmr;
varying highp vec3 lightDirection_cmr;
+varying highp vec3 lightPosition_wrld_frag;
-uniform highp vec3 lightPosition_wrld;
-uniform highp vec3 color_mdl;
+uniform highp vec4 color_mdl;
uniform highp float lightStrength;
uniform highp float ambientStrength;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
void main() {
highp vec3 materialDiffuseColor = color_mdl.rgb;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
- highp float distance = length(lightPosition_wrld - position_wrld);
+ highp float distance = length(lightPosition_wrld_frag - position_wrld);
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/plainColor.frag b/src/datavisualization/engine/shaders/plainColor.frag
index 099c87a1..da9ee060 100644
--- a/src/datavisualization/engine/shaders/plainColor.frag
+++ b/src/datavisualization/engine/shaders/plainColor.frag
@@ -1,7 +1,6 @@
-uniform highp vec3 color_mdl;
+uniform highp vec4 color_mdl;
void main() {
- gl_FragColor.rgb = color_mdl;
- gl_FragColor.a = 1.0;
+ gl_FragColor = color_mdl;
}
diff --git a/src/datavisualization/engine/shaders/shadow.frag b/src/datavisualization/engine/shaders/shadow.frag
index e2286dc5..237e9780 100644
--- a/src/datavisualization/engine/shaders/shadow.frag
+++ b/src/datavisualization/engine/shaders/shadow.frag
@@ -5,7 +5,7 @@ uniform highp float ambientStrength;
uniform highp float shadowQuality;
uniform highp sampler2D textureSampler;
uniform highp sampler2DShadow shadowMap;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
varying highp vec4 shadowCoord;
varying highp vec2 UV;
@@ -33,8 +33,8 @@ highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
void main() {
highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor * 0.2;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb * 0.2;
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/shadow.vert b/src/datavisualization/engine/shaders/shadow.vert
index e29a8a30..0adcd43c 100644
--- a/src/datavisualization/engine/shaders/shadow.vert
+++ b/src/datavisualization/engine/shaders/shadow.vert
@@ -28,10 +28,10 @@ void main() {
gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
coords_mdl = vertexPosition_mdl.xy;
shadowCoord = bias * depthMVP * vec4(vertexPosition_mdl, 1.0);
- position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
- vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ position_wrld = vec4(M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = vec4(V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
- lightDirection_cmr = (V * vec4(lightPosition_wrld, 0.0)).xyz;
- normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ lightDirection_cmr = vec4(V * vec4(lightPosition_wrld, 0.0)).xyz;
+ normal_cmr = vec4(V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
UV = vertexUV;
}
diff --git a/src/datavisualization/engine/shaders/shadowNoTex.frag b/src/datavisualization/engine/shaders/shadowNoTex.frag
index d54efea9..b2e7adfc 100644
--- a/src/datavisualization/engine/shaders/shadowNoTex.frag
+++ b/src/datavisualization/engine/shaders/shadowNoTex.frag
@@ -3,9 +3,9 @@
uniform highp float lightStrength;
uniform highp float ambientStrength;
uniform highp float shadowQuality;
-uniform highp vec3 color_mdl;
+uniform highp vec4 color_mdl;
uniform highp sampler2DShadow shadowMap;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
varying highp vec4 shadowCoord;
varying highp vec3 position_wrld;
@@ -32,8 +32,8 @@ highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
void main() {
highp vec3 materialDiffuseColor = color_mdl.rgb;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag b/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag
index e986a52a..73b84138 100644
--- a/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag
+++ b/src/datavisualization/engine/shaders/shadowNoTexColorOnY.frag
@@ -7,7 +7,7 @@ uniform highp sampler2DShadow shadowMap;
uniform sampler2D textureSampler;
uniform highp float gradMin;
uniform highp float gradHeight;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
varying highp vec4 shadowCoord;
varying highp vec3 position_wrld;
@@ -36,8 +36,8 @@ highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
void main() {
highp vec2 gradientUV = vec2(0.0, gradMin + ((coords_mdl.y + 1.0) * gradHeight));
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/surface.frag b/src/datavisualization/engine/shaders/surface.frag
index b5205d2d..f17dd73e 100644
--- a/src/datavisualization/engine/shaders/surface.frag
+++ b/src/datavisualization/engine/shaders/surface.frag
@@ -10,13 +10,13 @@ uniform sampler2D textureSampler;
uniform highp vec3 lightPosition_wrld;
uniform highp float lightStrength;
uniform highp float ambientStrength;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
void main() {
highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.0) / 2.0);
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp float distance = length(lightPosition_wrld - position_wrld);
diff --git a/src/datavisualization/engine/shaders/surfaceFlat.frag b/src/datavisualization/engine/shaders/surfaceFlat.frag
index 7eaa917f..748fb3dd 100644
--- a/src/datavisualization/engine/shaders/surfaceFlat.frag
+++ b/src/datavisualization/engine/shaders/surfaceFlat.frag
@@ -12,13 +12,13 @@ uniform sampler2D textureSampler;
uniform highp vec3 lightPosition_wrld;
uniform highp float lightStrength;
uniform highp float ambientStrength;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
void main() {
highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.0) / 2.0);
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp float distance = length(lightPosition_wrld - position_wrld);
diff --git a/src/datavisualization/engine/shaders/surfaceFlat.vert b/src/datavisualization/engine/shaders/surfaceFlat.vert
index 0d39f6bc..102bea78 100644
--- a/src/datavisualization/engine/shaders/surfaceFlat.vert
+++ b/src/datavisualization/engine/shaders/surfaceFlat.vert
@@ -20,10 +20,10 @@ varying highp vec3 coords_mdl;
void main() {
gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
coords_mdl = vertexPosition_mdl;
- position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
- vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ position_wrld = vec4(M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = vec4(V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
- vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ vec3 lightPosition_cmr = vec4(V * vec4(lightPosition_wrld, 1.0)).xyz;
lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
- normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ normal_cmr = vec4(V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
}
diff --git a/src/datavisualization/engine/shaders/surfaceShadowFlat.frag b/src/datavisualization/engine/shaders/surfaceShadowFlat.frag
index 9b9305ab..0613a40c 100644
--- a/src/datavisualization/engine/shaders/surfaceShadowFlat.frag
+++ b/src/datavisualization/engine/shaders/surfaceShadowFlat.frag
@@ -15,7 +15,7 @@ uniform highp vec3 lightPosition_wrld;
uniform highp float lightStrength;
uniform highp float ambientStrength;
uniform highp float shadowQuality;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
vec2(0.94558609, -0.76890725),
@@ -37,8 +37,8 @@ highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
void main() {
highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.0) / 2.0);
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/surfaceShadowFlat.vert b/src/datavisualization/engine/shaders/surfaceShadowFlat.vert
index 0a6e967f..8da7b196 100644
--- a/src/datavisualization/engine/shaders/surfaceShadowFlat.vert
+++ b/src/datavisualization/engine/shaders/surfaceShadowFlat.vert
@@ -28,10 +28,10 @@ void main() {
gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
coords_mdl = vertexPosition_mdl;
shadowCoord = bias * depthMVP * vec4(vertexPosition_mdl, 1.0);
- position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
- vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ position_wrld = vec4(M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = vec4(V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
- vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ vec3 lightPosition_cmr = vec4(V * vec4(lightPosition_wrld, 1.0)).xyz;
lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
- normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ normal_cmr = vec4(V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
}
diff --git a/src/datavisualization/engine/shaders/surfaceShadowNoTex.frag b/src/datavisualization/engine/shaders/surfaceShadowNoTex.frag
index 3427fbae..1acf8f69 100644
--- a/src/datavisualization/engine/shaders/surfaceShadowNoTex.frag
+++ b/src/datavisualization/engine/shaders/surfaceShadowNoTex.frag
@@ -13,7 +13,7 @@ uniform highp vec3 lightPosition_wrld;
uniform highp float lightStrength;
uniform highp float ambientStrength;
uniform highp float shadowQuality;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
vec2(0.94558609, -0.76890725),
@@ -35,8 +35,8 @@ highp vec2 poissonDisk[16] = vec2[16](vec2(-0.94201624, -0.39906216),
void main() {
highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.0) / 2.0);
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/surface_ES2.frag b/src/datavisualization/engine/shaders/surface_ES2.frag
index 0e17cacd..58d13834 100644
--- a/src/datavisualization/engine/shaders/surface_ES2.frag
+++ b/src/datavisualization/engine/shaders/surface_ES2.frag
@@ -4,20 +4,20 @@ varying highp vec3 position_wrld;
varying highp vec3 normal_cmr;
varying highp vec3 eyeDirection_cmr;
varying highp vec3 lightDirection_cmr;
+varying highp vec3 lightPosition_wrld_frag;
uniform sampler2D textureSampler;
-uniform highp vec3 lightPosition_wrld;
uniform highp float lightStrength;
uniform highp float ambientStrength;
-uniform highp vec3 lightColor;
+uniform highp vec4 lightColor;
void main() {
highp vec2 gradientUV = vec2(0.0, (coords_mdl.y + 1.0) / 2.0);
highp vec3 materialDiffuseColor = texture2D(textureSampler, gradientUV).xyz;
- highp vec3 materialAmbientColor = lightColor * ambientStrength * materialDiffuseColor;
- highp vec3 materialSpecularColor = lightColor;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
- highp float distance = length(lightPosition_wrld - position_wrld);
+ highp float distance = length(lightPosition_wrld_frag - position_wrld);
highp vec3 n = normalize(normal_cmr);
highp vec3 l = normalize(lightDirection_cmr);
diff --git a/src/datavisualization/engine/shaders/texture.frag b/src/datavisualization/engine/shaders/texture.frag
new file mode 100644
index 00000000..41c4259b
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture.frag
@@ -0,0 +1,37 @@
+#version 120
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp sampler2D textureSampler;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp vec4 lightColor;
+
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance;
+ gl_FragColor.a = texture2D(textureSampler, UV).a;
+ gl_FragColor.rgb = clamp(gl_FragColor.rgb, 0.0, 1.0);
+}
+
diff --git a/src/datavisualization/engine/shaders/texture.vert b/src/datavisualization/engine/shaders/texture.vert
new file mode 100644
index 00000000..90c0ac23
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture.vert
@@ -0,0 +1,28 @@
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+varying highp vec3 lightPosition_wrld_frag;
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ position_wrld = vec4(M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = vec4(V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = vec4(V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = vec4(V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ UV = vertexUV;
+ lightPosition_wrld_frag = lightPosition_wrld;
+}
diff --git a/src/datavisualization/engine/shaders/texture_ES2.frag b/src/datavisualization/engine/shaders/texture_ES2.frag
new file mode 100644
index 00000000..82ad6614
--- /dev/null
+++ b/src/datavisualization/engine/shaders/texture_ES2.frag
@@ -0,0 +1,40 @@
+varying highp vec2 UV;
+varying highp vec2 coords_mdl;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec3 lightPosition_wrld_frag;
+
+uniform highp sampler2D textureSampler;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp vec4 lightColor;
+
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = lightColor.rgb * ambientStrength * materialDiffuseColor;
+ highp vec3 materialSpecularColor = lightColor.rgb;
+
+ highp float distance = length(lightPosition_wrld_frag - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = dot(n, l);
+ if (cosTheta < 0.0) cosTheta = 0.0;
+ else if (cosTheta > 1.0) cosTheta = 1.0;
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = dot(E, R);
+ if (cosAlpha < 0.0) cosAlpha = 0.0;
+ else if (cosAlpha > 1.0) cosAlpha = 1.0;
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * (cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha * cosAlpha) / distance;
+ gl_FragColor.a = texture2D(textureSampler, UV).a;
+ gl_FragColor.rgb = clamp(gl_FragColor.rgb, 0.0, 1.0);
+}
+
diff --git a/src/datavisualization/engine/surface3dcontroller.cpp b/src/datavisualization/engine/surface3dcontroller.cpp
index 991a1ce8..c03bafd8 100644
--- a/src/datavisualization/engine/surface3dcontroller.cpp
+++ b/src/datavisualization/engine/surface3dcontroller.cpp
@@ -18,15 +18,9 @@
#include "surface3dcontroller_p.h"
#include "surface3drenderer_p.h"
-#include "camerahelper_p.h"
-#include "qabstract3daxis_p.h"
#include "qvalue3daxis_p.h"
-#include "qcategory3daxis.h"
#include "qsurfacedataproxy_p.h"
#include "qsurface3dseries_p.h"
-#include "shaderhelper_p.h"
-
-#include <QtGui/QMatrix4x4>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -66,11 +60,6 @@ void Surface3DController::synchDataToRenderer()
if (!isInitialized())
return;
- if (m_changedSeriesList.size()) {
- m_renderer->modifiedSeriesList(m_changedSeriesList);
- m_changedSeriesList.clear();
- }
-
Abstract3DController::synchDataToRenderer();
// Notify changes to renderer
@@ -81,7 +70,7 @@ void Surface3DController::synchDataToRenderer()
}
if (m_changeTracker.itemChanged) {
- m_renderer->updateItem(m_changedItems);
+ m_renderer->updateItems(m_changedItems);
m_changeTracker.itemChanged = false;
m_changedItems.clear();
}
@@ -98,7 +87,7 @@ void Surface3DController::handleAxisAutoAdjustRangeChangedInOrientation(
Q_UNUSED(orientation)
Q_UNUSED(autoAdjust)
- adjustValueAxisRange();
+ adjustAxisRanges();
}
void Surface3DController::handleAxisRangeChangedBySender(QObject *sender)
@@ -113,8 +102,6 @@ void Surface3DController::handleSeriesVisibilityChangedBySender(QObject *sender)
{
Abstract3DController::handleSeriesVisibilityChangedBySender(sender);
- adjustValueAxisRange();
-
// Visibility changes may require disabling slicing,
// so just reset selection to ensure everything is still valid.
setSelectedPoint(m_selectedPoint, m_selectedSeries, false);
@@ -128,6 +115,8 @@ void Surface3DController::handlePendingClick()
setSelectedPoint(position, series, true);
+ Abstract3DController::handlePendingClick();
+
m_renderer->resetClickedStatus();
}
@@ -148,9 +137,6 @@ void Surface3DController::addSeries(QAbstract3DSeries *series)
Abstract3DController::addSeries(series);
- if (series->isVisible())
- adjustValueAxisRange();
-
QSurface3DSeries *surfaceSeries = static_cast<QSurface3DSeries *>(series);
if (surfaceSeries->selectedPoint() != invalidSelectionPosition())
setSelectedPoint(surfaceSeries->selectedPoint(), surfaceSeries, false);
@@ -166,7 +152,7 @@ void Surface3DController::removeSeries(QAbstract3DSeries *series)
setSelectedPoint(invalidSelectionPosition(), 0, false);
if (wasVisible)
- adjustValueAxisRange();
+ adjustAxisRanges();
}
QList<QSurface3DSeries *> Surface3DController::surfaceSeriesList()
@@ -214,7 +200,8 @@ void Surface3DController::setSelectionMode(QAbstract3DGraph::SelectionFlags mode
}
}
-void Surface3DController::setSelectedPoint(const QPoint &position, QSurface3DSeries *series, bool enterSlice)
+void Surface3DController::setSelectedPoint(const QPoint &position, QSurface3DSeries *series,
+ bool enterSlice)
{
// If the selection targets non-existent point, clear selection instead.
QPoint pos = position;
@@ -290,13 +277,15 @@ void Surface3DController::handleArrayReset()
{
QSurface3DSeries *series = static_cast<QSurfaceDataProxy *>(sender())->series();
if (series->isVisible()) {
- adjustValueAxisRange();
- if (!m_changedSeriesList.contains(series))
- m_changedSeriesList.append(series);
+ adjustAxisRanges();
m_isDataDirty = true;
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
+
// Clear selection unless still valid
setSelectedPoint(m_selectedPoint, m_selectedSeries, false);
+ series->d_ptr->markItemLabelDirty();
emitNeedRender();
}
@@ -315,33 +304,34 @@ void Surface3DController::handleFlatShadingSupportedChange(bool supported)
void Surface3DController::handleRowsChanged(int startIndex, int count)
{
- QSurfaceDataProxy *sender = static_cast<QSurfaceDataProxy *>(QObject::sender());
- if (m_changedRows.size() == 0)
- m_changedRows.reserve(sender->rowCount());
-
- QSurface3DSeries *series = sender->series();
+ QSurface3DSeries *series = static_cast<QSurfaceDataProxy *>(QObject::sender())->series();
int oldChangeCount = m_changedRows.size();
+ if (!oldChangeCount)
+ m_changedRows.reserve(count);
+
+ int selectedRow = m_selectedPoint.x();
for (int i = 0; i < count; i++) {
bool newItem = true;
int candidate = startIndex + i;
- for (int i = 0; i < oldChangeCount; i++) {
- if (m_changedRows.at(i).row == candidate &&
- series == m_changedRows.at(i).series) {
+ for (int j = 0; j < oldChangeCount; j++) {
+ const ChangeRow &oldChangeItem = m_changedRows.at(j);
+ if (oldChangeItem.row == candidate && series == oldChangeItem.series) {
newItem = false;
break;
}
}
if (newItem) {
- ChangeRow newItem = {series, candidate};
- m_changedRows.append(newItem);
+ ChangeRow newChangeItem = {series, candidate};
+ m_changedRows.append(newChangeItem);
+ if (series == m_selectedSeries && selectedRow == candidate)
+ series->d_ptr->markItemLabelDirty();
}
}
- if (m_changedRows.size()) {
+ if (count) {
m_changeTracker.rowsChanged = true;
- adjustValueAxisRange();
- // Clear selection unless still valid
- setSelectedPoint(m_selectedPoint, m_selectedSeries, false);
+ if (series->isVisible())
+ adjustAxisRanges();
emitNeedRender();
}
}
@@ -352,7 +342,7 @@ void Surface3DController::handleItemChanged(int rowIndex, int columnIndex)
QSurface3DSeries *series = sender->series();
bool newItem = true;
- QPoint candidate(columnIndex, rowIndex);
+ QPoint candidate(rowIndex, columnIndex);
foreach (ChangeItem item, m_changedItems) {
if (item.point == candidate && item.series == series) {
newItem = false;
@@ -364,9 +354,11 @@ void Surface3DController::handleItemChanged(int rowIndex, int columnIndex)
m_changedItems.append(newItem);
m_changeTracker.itemChanged = true;
- adjustValueAxisRange();
- // Clear selection unless still valid
- setSelectedPoint(m_selectedPoint, m_selectedSeries, false);
+ if (series == m_selectedSeries && m_selectedPoint == candidate)
+ series->d_ptr->markItemLabelDirty();
+
+ if (series->isVisible())
+ adjustAxisRanges();
emitNeedRender();
}
}
@@ -377,11 +369,11 @@ void Surface3DController::handleRowsAdded(int startIndex, int count)
Q_UNUSED(count)
QSurface3DSeries *series = static_cast<QSurfaceDataProxy *>(sender())->series();
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
- if (!m_changedSeriesList.contains(series))
- m_changedSeriesList.append(series);
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
@@ -400,11 +392,11 @@ void Surface3DController::handleRowsInserted(int startIndex, int count)
}
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
- if (!m_changedSeriesList.contains(series))
- m_changedSeriesList.append(series);
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
@@ -428,16 +420,16 @@ void Surface3DController::handleRowsRemoved(int startIndex, int count)
}
if (series->isVisible()) {
- adjustValueAxisRange();
+ adjustAxisRanges();
m_isDataDirty = true;
- if (!m_changedSeriesList.contains(series))
- m_changedSeriesList.append(series);
}
+ if (!m_changedSeriesList.contains(series))
+ m_changedSeriesList.append(series);
emitNeedRender();
}
-void Surface3DController::adjustValueAxisRange()
+void Surface3DController::adjustAxisRanges()
{
QValue3DAxis *valueAxisX = static_cast<QValue3DAxis *>(m_axisX);
QValue3DAxis *valueAxisY = static_cast<QValue3DAxis *>(m_axisY);
@@ -517,7 +509,7 @@ void Surface3DController::adjustValueAxisRange()
adjustment = defaultAdjustment;
}
}
- valueAxisX->dptr()->setRange(minValueX - adjustment, maxValueX + adjustment);
+ valueAxisX->dptr()->setRange(minValueX - adjustment, maxValueX + adjustment, true);
}
if (adjustY) {
// If all points at same coordinate, need to default to some valid range
@@ -525,7 +517,7 @@ void Surface3DController::adjustValueAxisRange()
float adjustment = 0.0f;
if (minValueY == maxValueY)
adjustment = defaultAdjustment;
- valueAxisY->dptr()->setRange(minValueY - adjustment, maxValueY + adjustment);
+ valueAxisY->dptr()->setRange(minValueY - adjustment, maxValueY + adjustment, true);
}
if (adjustZ) {
// If all points at same coordinate, need to default to some valid range
@@ -544,7 +536,7 @@ void Surface3DController::adjustValueAxisRange()
adjustment = defaultAdjustment;
}
}
- valueAxisZ->dptr()->setRange(minValueZ - adjustment, maxValueZ + adjustment);
+ valueAxisZ->dptr()->setRange(minValueZ - adjustment, maxValueZ + adjustment, true);
}
}
}
diff --git a/src/datavisualization/engine/surface3dcontroller_p.h b/src/datavisualization/engine/surface3dcontroller_p.h
index 14c0dd40..2be74f35 100644
--- a/src/datavisualization/engine/surface3dcontroller_p.h
+++ b/src/datavisualization/engine/surface3dcontroller_p.h
@@ -38,15 +38,11 @@ class Surface3DRenderer;
class QSurface3DSeries;
struct Surface3DChangeBitField {
- bool smoothStatusChanged : 1;
- bool surfaceGridChanged : 1;
bool selectedPointChanged : 1;
bool rowsChanged : 1;
bool itemChanged : 1;
Surface3DChangeBitField() :
- smoothStatusChanged(true),
- surfaceGridChanged(true),
selectedPointChanged(true),
rowsChanged(false),
itemChanged(false)
@@ -77,7 +73,6 @@ private:
bool m_flatShadingSupported;
QVector<ChangeItem> m_changedItems;
QVector<ChangeRow> m_changedRows;
- QVector<QSurface3DSeries *> m_changedSeriesList;
public:
explicit Surface3DController(QRect rect, Q3DScene *scene = 0);
@@ -97,6 +92,7 @@ public:
virtual void handleAxisRangeChangedBySender(QObject *sender);
virtual void handleSeriesVisibilityChangedBySender(QObject *sender);
virtual void handlePendingClick();
+ virtual void adjustAxisRanges();
static QPoint invalidSelectionPosition();
bool isFlatShadingSupported();
@@ -119,8 +115,6 @@ signals:
void selectedSeriesChanged(QSurface3DSeries *series);
private:
- void adjustValueAxisRange();
-
Q_DISABLE_COPY(Surface3DController)
};
diff --git a/src/datavisualization/engine/surface3drenderer.cpp b/src/datavisualization/engine/surface3drenderer.cpp
index 41415393..12627966 100644
--- a/src/datavisualization/engine/surface3drenderer.cpp
+++ b/src/datavisualization/engine/surface3drenderer.cpp
@@ -16,22 +16,12 @@
**
****************************************************************************/
-#include "surface3dcontroller_p.h"
#include "surface3drenderer_p.h"
-#include "q3dcamera.h"
#include "q3dcamera_p.h"
#include "shaderhelper_p.h"
-#include "objecthelper_p.h"
-#include "surfaceobject_p.h"
#include "texturehelper_p.h"
-#include "selectionpointer_p.h"
#include "utils_p.h"
-#include "drawer_p.h"
-#include "q3dlight.h"
-#include "qsurface3dseries_p.h"
-#include <QtGui/QMatrix4x4>
-#include <QtGui/QMouseEvent>
#include <QtCore/qmath.h>
static const int ID_TO_RGBA_MASK = 0xff;
@@ -40,12 +30,15 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
//#define SHOW_DEPTH_TEXTURE_SCENE
-const GLfloat aspectRatio = 2.0f; // Forced ratio of x and z to y. Dynamic will make it look odd.
-const GLfloat backgroundMargin = 1.1f; // Margin for background (1.1f = make it 10% larger to avoid items being drawn inside background)
-const GLfloat labelMargin = 0.05f;
+// Margin for background (1.10 make it 10% larger to avoid
+// selection ball being drawn inside background)
+const GLfloat backgroundMargin = 1.1f;
const GLfloat gridLineWidth = 0.005f;
const GLfloat sliceZScale = 0.1f;
const GLfloat sliceUnits = 2.5f;
+const uint greenMultiplier = 256;
+const uint blueMultiplier = 65536;
+const uint alphaMultiplier = 16777216;
Surface3DRenderer::Surface3DRenderer(Surface3DController *controller)
: Abstract3DRenderer(controller),
@@ -65,15 +58,6 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller)
m_scaleZ(0.0f),
m_scaleXWithBackground(0.0f),
m_scaleZWithBackground(0.0f),
- m_minVisibleColumnValue(0.0f),
- m_maxVisibleColumnValue(0.0f),
- m_minVisibleRowValue(0.0f),
- m_maxVisibleRowValue(0.0f),
- m_visibleColumnRange(0.0f),
- m_visibleRowRange(0.0f),
- m_backgroundObj(0),
- m_gridLineObj(0),
- m_labelObj(0),
m_depthTexture(0),
m_depthModelTexture(0),
m_depthFrameBuffer(0),
@@ -83,9 +67,6 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller)
m_shadowQualityToShader(33.3f),
m_flatSupported(true),
m_selectionActive(false),
- m_xFlipped(false),
- m_zFlipped(false),
- m_yFlipped(false),
m_shadowQualityMultiplier(3),
m_hasHeightAdjustmentChanged(true),
m_selectedPoint(Surface3DController::invalidSelectionPosition()),
@@ -94,6 +75,9 @@ Surface3DRenderer::Surface3DRenderer(Surface3DController *controller)
m_selectionTexturesDirty(false),
m_noShadowTexture(0)
{
+ m_axisCacheY.setScale(2.0f);
+ m_axisCacheY.setTranslate(-1.0f);
+
// Check if flat feature is supported
ShaderHelper tester(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
QStringLiteral(":/shaders/fragmentSurfaceFlat"));
@@ -131,16 +115,6 @@ Surface3DRenderer::~Surface3DRenderer()
delete m_surfaceSliceFlatShader;
delete m_surfaceSliceSmoothShader;
delete m_labelShader;
-
- delete m_backgroundObj;
- delete m_gridLineObj;
- delete m_labelObj;
-
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
- cache->cleanup(m_textureHelper);
- delete cache;
- }
- m_renderCacheList.clear();
}
void Surface3DRenderer::initializeOpenGL()
@@ -160,8 +134,10 @@ void Surface3DRenderer::initializeOpenGL()
// Init selection shader
initSelectionShaders();
+#if !(defined QT_OPENGL_ES_2)
// Load grid line mesh
loadGridLineMesh();
+#endif
// Load label mesh
loadLabelMesh();
@@ -183,22 +159,25 @@ void Surface3DRenderer::updateData()
{
calculateSceneScalingFactors();
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
- const QSurface3DSeries *currentSeries = cache->series();
- QSurfaceDataProxy *dataProxy = currentSeries->dataProxy();
- const QSurfaceDataArray &array = *dataProxy->array();
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
+ if (cache->isVisible() && cache->dataDirty()) {
+ const QSurface3DSeries *currentSeries = cache->series();
+ QSurfaceDataProxy *dataProxy = currentSeries->dataProxy();
+ const QSurfaceDataArray &array = *dataProxy->array();
+ QSurfaceDataArray &dataArray = cache->dataArray();
+ QRect sampleSpace;
- // Need minimum of 2x2 array to draw a surface
- if (array.size() >= 2 && array.at(0)->size() >= 2) {
- QRect sampleSpace = calculateSampleRect(cache, array);
+ // Need minimum of 2x2 array to draw a surface
+ if (array.size() >= 2 && array.at(0)->size() >= 2)
+ sampleSpace = calculateSampleRect(array);
- QSurfaceDataArray &dataArray = cache->dataArray();
- bool dimensionChanged = false;
+ bool dimensionsChanged = false;
if (cache->sampleSpace() != sampleSpace) {
if (sampleSpace.width() >= 2)
m_selectionTexturesDirty = true;
- dimensionChanged = true;
+ dimensionsChanged = true;
cache->setSampleSpace(sampleSpace);
for (int i = 0; i < dataArray.size(); i++)
@@ -207,7 +186,7 @@ void Surface3DRenderer::updateData()
}
if (sampleSpace.width() >= 2 && sampleSpace.height() >= 2) {
- if (dimensionChanged) {
+ if (dimensionsChanged) {
dataArray.reserve(sampleSpace.height());
for (int i = 0; i < sampleSpace.height(); i++)
dataArray << new QSurfaceDataRow(sampleSpace.width());
@@ -219,13 +198,13 @@ void Surface3DRenderer::updateData()
}
}
- if (dataArray.size() > 0 && (cache->objectDirty() || dimensionChanged)) {
- checkFlatSupport(cache);
- updateObjects(cache, dimensionChanged);
- cache->setObjectDirty(false);
- cache->setFlatStatusDirty(false);
- }
+ checkFlatSupport(cache);
+ updateObjects(cache, dimensionsChanged);
+ cache->setFlatStatusDirty(false);
+ } else {
+ cache->surfaceObject()->clear();
}
+ cache->setDataDirty(false);
}
}
@@ -235,31 +214,22 @@ void Surface3DRenderer::updateData()
updateSelectedPoint(m_selectedPoint, m_selectedSeries);
}
-void Surface3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList,
- bool updateVisibility)
+void Surface3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesList)
{
- Q_UNUSED(updateVisibility);
-
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList)
- cache->setValid(false);
+ Abstract3DRenderer::updateSeries(seriesList);
+ bool noSelection = true;
foreach (QAbstract3DSeries *series, seriesList) {
- // Item selection label may need update
- if (series->d_ptr->m_changeTracker.nameChanged
- || series->d_ptr->m_changeTracker.itemLabelFormatChanged) {
- m_selectionLabelDirty = true;
- }
-
QSurface3DSeries *surfaceSeries = static_cast<QSurface3DSeries *>(series);
- SurfaceSeriesRenderCache *cache = m_renderCacheList.value(surfaceSeries);
- if (!cache) {
- cache = new SurfaceSeriesRenderCache;
- m_renderCacheList[surfaceSeries] = cache;
-
- m_selectionTexturesDirty = true;
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>( m_renderCacheList.value(series));
+ if (noSelection
+ && surfaceSeries->selectedPoint() != QSurface3DSeries::invalidSelectionPosition()) {
+ if (selectionLabel() != cache->itemLabel())
+ m_selectionLabelDirty = true;
+ noSelection = false;
}
- cache->setValid(true);
- cache->populate(surfaceSeries, this);
+
if (cache->isFlatStatusDirty() && cache->sampleSpace().width()) {
checkFlatSupport(cache);
updateObjects(cache, true);
@@ -267,24 +237,16 @@ void Surface3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesLis
}
}
- // Remove non-valid objects from the cache list
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
- if (!cache->isValid()) {
- if (cache->series() == m_selectedSeries)
- updateSelectedPoint(Surface3DController::invalidSelectionPosition(), 0);
-
- m_renderCacheList.remove(cache->series());
- cache->cleanup(m_textureHelper);
- delete cache;
-
- m_selectionTexturesDirty = true;
- }
+ if (noSelection && !selectionLabel().isEmpty()) {
+ m_selectionLabelDirty = true;
+ updateSelectedPoint(Surface3DController::invalidSelectionPosition(), 0);
}
// Selection pointer issues
if (m_selectedSeries) {
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
- QVector3D highlightColor =
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
+ QVector4D highlightColor =
Utils::vectorFromColor(cache->series()->singleHighlightColor());
SelectionPointer *slicePointer = cache->sliceSelectionPointer();
if (slicePointer) {
@@ -302,19 +264,23 @@ void Surface3DRenderer::updateSeries(const QList<QAbstract3DSeries *> &seriesLis
}
}
-void Surface3DRenderer::modifiedSeriesList(const QVector<QSurface3DSeries *> &seriesList)
+SeriesRenderCache *Surface3DRenderer::createNewCache(QAbstract3DSeries *series)
{
- foreach (QSurface3DSeries *series, seriesList) {
- SurfaceSeriesRenderCache *cache = m_renderCacheList.value(series);
- if (cache)
- cache->setObjectDirty(true);
- }
+ m_selectionTexturesDirty = true;
+ return new SurfaceSeriesRenderCache(series, this);
+}
+
+void Surface3DRenderer::cleanCache(SeriesRenderCache *cache)
+{
+ Abstract3DRenderer::cleanCache(cache);
+ m_selectionTexturesDirty = true;
}
void Surface3DRenderer::updateRows(const QVector<Surface3DController::ChangeRow> &rows)
{
foreach (Surface3DController::ChangeRow item, rows) {
- SurfaceSeriesRenderCache *cache = m_renderCacheList.value(item.series);
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(m_renderCacheList.value(item.series));
QSurfaceDataArray &dstArray = cache->dataArray();
const QRect &sampleSpace = cache->sampleSpace();
@@ -335,15 +301,10 @@ void Surface3DRenderer::updateRows(const QVector<Surface3DController::ChangeRow>
srcArray->at(row)->at(j + sampleSpace.x());
}
- if (cache->isFlatShadingEnabled()) {
- cache->surfaceObject()->updateCoarseRow(dstArray, row - sampleSpace.y(),
- m_heightNormalizer,
- m_axisCacheY.min());
- } else {
- cache->surfaceObject()->updateSmoothRow(dstArray, row - sampleSpace.y(),
- m_heightNormalizer,
- m_axisCacheY.min());
- }
+ if (cache->isFlatShadingEnabled())
+ cache->surfaceObject()->updateCoarseRow(dstArray, row - sampleSpace.y());
+ else
+ cache->surfaceObject()->updateSmoothRow(dstArray, row - sampleSpace.y());
}
if (updateBuffers)
cache->surfaceObject()->uploadBuffers();
@@ -353,10 +314,11 @@ void Surface3DRenderer::updateRows(const QVector<Surface3DController::ChangeRow>
updateSelectedPoint(m_selectedPoint, m_selectedSeries);
}
-void Surface3DRenderer::updateItem(const QVector<Surface3DController::ChangeItem> &points)
+void Surface3DRenderer::updateItems(const QVector<Surface3DController::ChangeItem> &points)
{
foreach (Surface3DController::ChangeItem item, points) {
- SurfaceSeriesRenderCache *cache = m_renderCacheList.value(item.series);
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(m_renderCacheList.value(item.series));
QSurfaceDataArray &dstArray = cache->dataArray();
const QRect &sampleSpace = cache->sampleSpace();
@@ -370,22 +332,20 @@ void Surface3DRenderer::updateItem(const QVector<Surface3DController::ChangeItem
int sampleSpaceTop = sampleSpace.y() + sampleSpace.height();
int sampleSpaceRight = sampleSpace.x() + sampleSpace.width();
bool updateBuffers = false;
+ // Note: Point is (row, column), samplespace is (columns x rows)
QPoint point = item.point;
- if (point.y() <= sampleSpaceTop && point.y() >= sampleSpace.y() &&
- point.x() <= sampleSpaceRight && point.x() >= sampleSpace.x()) {
+ if (point.x() <= sampleSpaceTop && point.x() >= sampleSpace.y() &&
+ point.y() <= sampleSpaceRight && point.y() >= sampleSpace.x()) {
updateBuffers = true;
- int x = point.x() - sampleSpace.x();
- int y = point.y() - sampleSpace.y();
- (*(dstArray.at(y)))[x] = srcArray->at(point.y())->at(point.x());
-
- if (cache->isFlatShadingEnabled()) {
- cache->surfaceObject()->updateCoarseItem(dstArray, y, x, m_heightNormalizer,
- m_axisCacheY.min());
- } else {
- cache->surfaceObject()->updateSmoothItem(dstArray, y, x, m_heightNormalizer,
- m_axisCacheY.min());
- }
+ int x = point.y() - sampleSpace.x();
+ int y = point.x() - sampleSpace.y();
+ (*(dstArray.at(y)))[x] = srcArray->at(point.x())->at(point.y());
+
+ if (cache->isFlatShadingEnabled())
+ cache->surfaceObject()->updateCoarseItem(dstArray, y, x);
+ else
+ cache->surfaceObject()->updateSmoothItem(dstArray, y, x);
}
if (updateBuffers)
cache->surfaceObject()->uploadBuffers();
@@ -396,31 +356,22 @@ void Surface3DRenderer::updateItem(const QVector<Surface3DController::ChangeItem
updateSelectedPoint(m_selectedPoint, m_selectedSeries);
}
-void Surface3DRenderer::updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min,
- float max)
-{
- Abstract3DRenderer::updateAxisRange(orientation, min, max);
-
- if (orientation == QAbstract3DAxis::AxisOrientationY) {
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList)
- cache->setObjectDirty(true);
- }
-}
-
void Surface3DRenderer::updateSliceDataModel(const QPoint &point)
{
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList)
- cache->sliceSurfaceObject()->clear();
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList)
+ static_cast<SurfaceSeriesRenderCache *>(baseCache)->sliceSurfaceObject()->clear();
if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries)) {
// Find axis coordinates for the selected point
- SurfaceSeriesRenderCache *selectedCache =
- m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries));
- QSurfaceDataArray &dataArray = selectedCache->dataArray();
+ SeriesRenderCache *selectedCache =
+ m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries));
+ QSurfaceDataArray &dataArray =
+ static_cast<SurfaceSeriesRenderCache *>(selectedCache)->dataArray();
QSurfaceDataItem item = dataArray.at(point.x())->at(point.y());
QPointF coords(item.x(), item.z());
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->series() != m_selectedSeries) {
QPoint mappedPoint = mapCoordsToSampleSpace(cache, coords);
updateSliceObject(cache, mappedPoint);
@@ -431,9 +382,10 @@ void Surface3DRenderer::updateSliceDataModel(const QPoint &point)
} else {
if (m_selectedSeries) {
SurfaceSeriesRenderCache *cache =
- m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries));
+ static_cast<SurfaceSeriesRenderCache *>(
+ m_renderCacheList.value(m_selectedSeries));
if (cache)
- updateSliceObject(cache, point);
+ updateSliceObject(static_cast<SurfaceSeriesRenderCache *>(cache), point);
}
}
}
@@ -536,7 +488,7 @@ void Surface3DRenderer::updateSliceObject(SurfaceSeriesRenderCache *cache, const
int row = point.x();
if ((m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow) && row == -1) ||
- (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionColumn) && column == -1)) {
+ (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionColumn) && column == -1)) {
cache->sliceSurfaceObject()->clear();
return;
}
@@ -550,19 +502,27 @@ void Surface3DRenderer::updateSliceObject(SurfaceSeriesRenderCache *cache, const
QSurfaceDataRow *sliceRow;
QSurfaceDataArray &dataArray = cache->dataArray();
float adjust = (0.025f * m_heightNormalizer) / 2.0f;
- float stepDown = 2.0f * adjust;
+ float doubleAdjust = 2.0f * adjust;
+ bool flipZX = false;
+ float zBack;
+ float zFront;
if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow)) {
QSurfaceDataRow *src = dataArray.at(row);
sliceRow = new QSurfaceDataRow(src->size());
+ zBack = m_axisCacheZ.min();
+ zFront = m_axisCacheZ.max();
for (int i = 0; i < sliceRow->size(); i++)
- (*sliceRow)[i].setPosition(QVector3D(src->at(i).x(), src->at(i).y() + adjust, -1.0f));
+ (*sliceRow)[i].setPosition(QVector3D(src->at(i).x(), src->at(i).y() + adjust, zFront));
} else {
+ flipZX = true;
const QRect &sampleSpace = cache->sampleSpace();
sliceRow = new QSurfaceDataRow(sampleSpace.height());
+ zBack = m_axisCacheX.min();
+ zFront = m_axisCacheX.max();
for (int i = 0; i < sampleSpace.height(); i++) {
(*sliceRow)[i].setPosition(QVector3D(dataArray.at(i)->at(column).z(),
dataArray.at(i)->at(column).y() + adjust,
- -1.0f));
+ zFront));
}
}
sliceDataArray << sliceRow;
@@ -571,114 +531,134 @@ void Surface3DRenderer::updateSliceObject(SurfaceSeriesRenderCache *cache, const
QSurfaceDataRow *duplicateRow = new QSurfaceDataRow(*sliceRow);
for (int i = 0; i < sliceRow->size(); i++) {
(*sliceRow)[i].setPosition(QVector3D(sliceRow->at(i).x(),
- sliceRow->at(i).y() - stepDown,
- 1.0f));
+ sliceRow->at(i).y() - doubleAdjust,
+ zBack));
}
sliceDataArray << duplicateRow;
QRect sliceRect(0, 0, sliceRow->size(), 2);
if (sliceRow->size() > 0) {
- if (cache->isFlatShadingEnabled()) {
- cache->sliceSurfaceObject()->setUpData(sliceDataArray, sliceRect,
- m_heightNormalizer,
- m_axisCacheY.min(), true);
+ if (cache->isFlatShadingEnabled())
+ cache->sliceSurfaceObject()->setUpData(sliceDataArray, sliceRect, true, flipZX);
+ else
+ cache->sliceSurfaceObject()->setUpSmoothData(sliceDataArray, sliceRect, true, flipZX);
+ }
+}
+
+inline static float getDataValue(const QSurfaceDataArray &array, bool searchRow, int index)
+{
+ if (searchRow)
+ return array.at(0)->at(index).x();
+ else
+ return array.at(index)->at(0).z();
+}
+
+inline static int binarySearchArray(const QSurfaceDataArray &array, int maxIdx, float limitValue,
+ bool searchRow, bool lowBound, bool ascending)
+{
+ int min = 0;
+ int max = maxIdx;
+ int mid = 0;
+ int retVal;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ float arrayValue = getDataValue(array, searchRow, mid);
+ if (arrayValue == limitValue)
+ return mid;
+ if (ascending) {
+ if (arrayValue < limitValue)
+ min = mid + 1;
+ else
+ max = mid - 1;
} else {
- cache->sliceSurfaceObject()->setUpSmoothData(sliceDataArray, sliceRect,
- m_heightNormalizer,
- m_axisCacheY.min(), true);
+ if (arrayValue > limitValue)
+ min = mid + 1;
+ else
+ max = mid - 1;
}
}
+
+ // Exact match not found, return closest depending on bound.
+ // The boundary is between last mid and min/max.
+ if (lowBound == ascending) {
+ if (mid > max)
+ retVal = mid;
+ else
+ retVal = min;
+ } else {
+ if (mid > max)
+ retVal = max;
+ else
+ retVal = mid;
+ }
+ if (retVal < 0 || retVal > maxIdx) {
+ retVal = -1;
+ } else if (lowBound) {
+ if (getDataValue(array, searchRow, retVal) < limitValue)
+ retVal = -1;
+ } else {
+ if (getDataValue(array, searchRow, retVal) > limitValue)
+ retVal = -1;
+ }
+ return retVal;
}
-QRect Surface3DRenderer::calculateSampleRect(SurfaceSeriesRenderCache *cache,
- const QSurfaceDataArray &array)
+QRect Surface3DRenderer::calculateSampleRect(const QSurfaceDataArray &array)
{
QRect sampleSpace;
- int rowCount = array.size();
- int columnCount = array.at(0)->size();
+ const int maxRow = array.size() - 1;
+ const int maxColumn = array.at(0)->size() - 1;
- int i;
- bool found;
- float axisMinX = m_axisCacheX.min();
- float axisMaxX = m_axisCacheX.max();
- float axisMinZ = m_axisCacheZ.min();
- float axisMaxZ = m_axisCacheZ.max();
+ // We assume data is ordered sequentially in rows for X-value and in columns for Z-value.
+ // Determine if data is ascending or descending in each case.
+ const bool ascendingX = array.at(0)->at(0).x() < array.at(0)->at(maxColumn).x();
+ const bool ascendingZ = array.at(0)->at(0).z() < array.at(maxRow)->at(0).z();
- // m_minVisibleColumnValue
- for (i = 0, found = false; i < columnCount; i++) {
- if (array.at(0)->at(i).x() >= axisMinX) {
- found = true;
- break;
- }
- }
- if (found) {
- m_minVisibleColumnValue = array.at(0)->at(i).x();
- sampleSpace.setLeft(i);
+ int idx = binarySearchArray(array, maxColumn, m_axisCacheX.min(), true, true, ascendingX);
+ if (idx != -1) {
+ if (ascendingX)
+ sampleSpace.setLeft(idx);
+ else
+ sampleSpace.setRight(idx);
} else {
sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
return sampleSpace;
}
- // m_maxVisibleColumnValue
- for (i = columnCount - 1, found = false; i >= 0; i--) {
- if (array.at(0)->at(i).x() <= axisMaxX) {
- found = true;
- break;
- }
- }
- if (found) {
- m_maxVisibleColumnValue = array.at(0)->at(i).x();
- sampleSpace.setRight(i);
+ idx = binarySearchArray(array, maxColumn, m_axisCacheX.max(), true, false, ascendingX);
+ if (idx != -1) {
+ if (ascendingX)
+ sampleSpace.setRight(idx);
+ else
+ sampleSpace.setLeft(idx);
} else {
sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
return sampleSpace;
}
- // m_minVisibleRowValue
- for (i = 0, found = false; i < rowCount; i++) {
- if (array.at(i)->at(0).z() >= axisMinZ) {
- found = true;
- break;
- }
- }
- if (found) {
- m_minVisibleRowValue = array.at(i)->at(0).z();
- sampleSpace.setTop(i);
+ idx = binarySearchArray(array, maxRow, m_axisCacheZ.min(), false, true, ascendingZ);
+ if (idx != -1) {
+ if (ascendingZ)
+ sampleSpace.setTop(idx);
+ else
+ sampleSpace.setBottom(idx);
} else {
sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
return sampleSpace;
}
- // m_maxVisibleRowValue
- for (i = rowCount - 1, found = false; i >= 0; i--) {
- if (array.at(i)->at(0).z() <= axisMaxZ) {
- found = true;
- break;
- }
- }
- if (found) {
- m_maxVisibleRowValue = array.at(i)->at(0).z();
- sampleSpace.setBottom(i);
+ idx = binarySearchArray(array, maxRow, m_axisCacheZ.max(), false, false, ascendingZ);
+ if (idx != -1) {
+ if (ascendingZ)
+ sampleSpace.setBottom(idx);
+ else
+ sampleSpace.setTop(idx);
} else {
sampleSpace.setWidth(-1); // to indicate nothing needs to be shown
return sampleSpace;
}
- m_visibleColumnRange = m_maxVisibleColumnValue - m_minVisibleColumnValue;
- m_visibleRowRange = m_maxVisibleRowValue - m_minVisibleRowValue;
- GLfloat surfaceScaleX = m_scaleX * m_visibleColumnRange / m_areaSize.width();
- GLfloat surfaceScaleZ = m_scaleZ * m_visibleRowRange / m_areaSize.height();
- GLfloat axis2XCenterX = axisMinX + axisMaxX;
- GLfloat axis2XCenterZ = axisMinZ + axisMaxZ;
- GLfloat data2XCenterX = GLfloat(m_minVisibleColumnValue + m_maxVisibleColumnValue);
- GLfloat data2XCenterZ = GLfloat(m_minVisibleRowValue + m_maxVisibleRowValue);
- GLfloat surfaceOffsetX = m_scaleX * (data2XCenterX - axis2XCenterX) / m_areaSize.width();
- GLfloat surfaceOffsetZ = -m_scaleZ * (data2XCenterZ - axis2XCenterZ) / m_areaSize.height();
-
- cache->setScale(QVector3D(surfaceScaleX, 1.0f, surfaceScaleZ));
- cache->setOffset(QVector3D(surfaceOffsetX, 0.0f, surfaceOffsetZ));
-
return sampleSpace;
}
@@ -708,6 +688,13 @@ void Surface3DRenderer::render(GLuint defaultFboHandle)
// Handle GL state setup for FBO buffers and clearing of the render surface
Abstract3DRenderer::render(defaultFboHandle);
+ if (m_axisCacheX.positionsDirty())
+ m_axisCacheX.updateAllPositions();
+ if (m_axisCacheY.positionsDirty())
+ m_axisCacheY.updateAllPositions();
+ if (m_axisCacheZ.positionsDirty())
+ m_axisCacheZ.updateAllPositions();
+
drawScene(defaultFboHandle);
if (m_cachedIsSlicingActivated)
drawSlicedScene();
@@ -715,13 +702,14 @@ void Surface3DRenderer::render(GLuint defaultFboHandle)
// Render selection ball
if (m_selectionActive
&& m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionItem)) {
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->slicePointerActive() && cache->renderable() &&
m_cachedIsSlicingActivated ) {
cache->sliceSelectionPointer()->render(defaultFboHandle);
}
if (cache->mainPointerActive() && cache->renderable())
- cache->mainSelectionPointer()->render(defaultFboHandle);
+ cache->mainSelectionPointer()->render(defaultFboHandle, m_useOrthoProjection);
}
}
}
@@ -730,7 +718,7 @@ void Surface3DRenderer::drawSlicedScene()
{
QVector3D lightPos;
- QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
+ QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
// Specify viewport
glViewport(m_secondarySubViewport.x(),
@@ -760,13 +748,18 @@ void Surface3DRenderer::drawSlicedScene()
const Q3DCamera *activeCamera = m_cachedScene->activeCamera();
bool rowMode = m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow);
+ AxisRenderCache &sliceCache = rowMode ? m_axisCacheX : m_axisCacheZ;
GLfloat scaleXBackground = 0.0f;
- if (m_renderCacheList.size()) {
+ // Disable culling to avoid ugly conditionals with reversed axes and data
+ glDisable(GL_CULL_FACE);
+
+ if (!m_renderCacheList.isEmpty()) {
bool drawGrid = false;
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->sliceSurfaceObject()->indexCount() && cache->renderable()) {
if (!drawGrid && cache->surfaceGridVisible()) {
glEnable(GL_POLYGON_OFFSET_FILL);
@@ -774,24 +767,16 @@ void Surface3DRenderer::drawSlicedScene()
drawGrid = true;
}
- GLfloat scaleX = 0.0f;
- GLfloat offset = 0.0f;
- if (rowMode) {
- scaleX = cache->scale().x();
+ if (rowMode)
scaleXBackground = m_scaleXWithBackground;
- offset = cache->offset().x();
- } else {
- scaleX = cache->scale().z();
+ else
scaleXBackground = m_scaleZWithBackground;
- offset = -cache->offset().z();
- }
QMatrix4x4 MVPMatrix;
QMatrix4x4 modelMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(offset, 0.0f, 0.0f);
- QVector3D scaling(scaleX, 1.0f, sliceZScale);
+ QVector3D scaling(1.0f, 1.0f, sliceZScale);
modelMatrix.scale(scaling);
itModelMatrix.scale(scaling);
@@ -832,10 +817,13 @@ void Surface3DRenderer::drawSlicedScene()
m_surfaceGridShader->bind();
m_surfaceGridShader->setUniformValue(m_surfaceGridShader->color(),
Utils::vectorFromColor(m_cachedTheme->gridLineColor()));
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
- if (cache->sliceSurfaceObject()->indexCount() && cache->isSeriesVisible() &&
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(baseCache);
+ if (cache->sliceSurfaceObject()->indexCount() && cache->isVisible() &&
cache->surfaceGridVisible()) {
- m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(), cache->MVPMatrix());
+ m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(),
+ cache->MVPMatrix());
m_drawer->drawSurfaceGrid(m_surfaceGridShader, cache->sliceSurfaceObject());
}
}
@@ -845,14 +833,22 @@ void Surface3DRenderer::drawSlicedScene()
// Disable textures
glDisable(GL_TEXTURE_2D);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+
// Grid lines
if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) {
+#if !(defined QT_OPENGL_ES_2)
ShaderHelper *lineShader = m_backgroundShader;
+#else
+ ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES
+#endif
+
// Bind line shader
lineShader->bind();
// Set unchanging shader bindings
- QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
+ QVector4D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
lineShader->setUniformValue(lineShader->lightP(), lightPos);
lineShader->setUniformValue(lineShader->view(), viewMatrix);
lineShader->setUniformValue(lineShader->color(), lineColor);
@@ -862,19 +858,16 @@ void Surface3DRenderer::drawSlicedScene()
lineShader->setUniformValue(lineShader->lightColor(), lightColor);
// Horizontal lines
+ int gridLineCount = m_axisCacheY.gridLineCount();
if (m_axisCacheY.segmentCount() > 0) {
QVector3D gridLineScaleX(scaleXBackground, gridLineWidth, gridLineWidth);
- GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer;
- GLfloat linePos = -1.0f;
- int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
-
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(0.0f, linePos, -sliceZScale);
+ modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), -1.0f);
modelMatrix.scale(gridLineScaleX);
itModelMatrix.scale(gridLineScaleX);
@@ -888,36 +881,30 @@ void Surface3DRenderer::drawSlicedScene()
lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
// Draw the object
+#if !(defined QT_OPENGL_ES_2)
m_drawer->drawObject(lineShader, m_gridLineObj);
-
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
// Vertical lines
QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth);
- int lastSegment;
- GLfloat lineStep;
- GLfloat linePos;
- if (rowMode) {
- lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor;
- lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount();
- linePos = m_scaleX;
- } else {
- lineStep = -2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor;
- lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount();
- linePos = m_scaleZ;
- }
-
- for (int segment = 0; segment <= lastSegment; segment++) {
+ gridLineCount = sliceCache.gridLineCount();
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(linePos, 0.0f, -sliceZScale);
+ modelMatrix.translate(sliceCache.gridLinePosition(line), 0.0f, -1.0f);
modelMatrix.scale(gridLineScaleY);
itModelMatrix.scale(gridLineScaleY);
+#if (defined QT_OPENGL_ES_2)
+ modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+ itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+#endif
MVPMatrix = projectionViewMatrix * modelMatrix;
@@ -928,9 +915,11 @@ void Surface3DRenderer::drawSlicedScene()
lineShader->setUniformValue(lineShader->MVP(), MVPMatrix);
// Draw the object
+#if !(defined QT_OPENGL_ES_2)
m_drawer->drawObject(lineShader, m_gridLineObj);
-
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
@@ -938,96 +927,76 @@ void Surface3DRenderer::drawSlicedScene()
m_labelShader->bind();
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
- glCullFace(GL_BACK);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Y Labels to back wall
- GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer;
- GLfloat labelPos = -1.0f;
int labelNbr = 0;
QVector3D positionComp(0.0f, 0.0f, 0.0f);
- QVector3D rotation(0.0f, 0.0f, 0.0f);
- QVector3D labelTrans = QVector3D(scaleXBackground + labelMargin, labelPos, 0.0f);
- for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) {
+ QVector3D labelTrans = QVector3D(scaleXBackground + labelMargin, 0.0f, 0.0f);
+ int labelCount = m_axisCacheY.labelCount();
+ for (int label = 0; label < labelCount; label++) {
if (m_axisCacheY.labelItems().size() > labelNbr) {
- labelTrans.setY(labelPos);
+ labelTrans.setY(m_axisCacheY.labelPosition(label));
const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
// Draw the label here
m_dummyRenderItem.setTranslation(labelTrans);
m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- positionComp, rotation, 0, m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, Qt::AlignRight, true);
+ positionComp, identityQuaternion, 0, m_cachedSelectionMode,
+ m_labelShader, m_labelObj, activeCamera, true, true,
+ Drawer::LabelMid, Qt::AlignLeft, true);
}
labelNbr++;
- labelPos += posStep;
}
// X Labels to ground
- int countLabelItems;
- int lastSegment;
- if (rowMode) {
- posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor;
- labelPos = -m_scaleX;
- lastSegment = m_axisCacheX.segmentCount();
- countLabelItems = m_axisCacheX.labelItems().size();
- } else {
- posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor;
- labelPos = -m_scaleZ;
- lastSegment = m_axisCacheZ.segmentCount();
- countLabelItems = m_axisCacheZ.labelItems().size();
- }
+ int countLabelItems = sliceCache.labelItems().size();
+
+ QVector3D rotation(0.0f, 0.0f, -45.0f);
+ QQuaternion totalRotation = Utils::calculateRotation(rotation);
labelNbr = 0;
positionComp.setY(-0.1f);
- rotation.setZ(-45.0f);
labelTrans.setY(-backgroundMargin);
- for (int segment = 0; segment <= lastSegment; segment++) {
+ labelCount = sliceCache.labelCount();
+ for (int label = 0; label < labelCount; label++) {
if (countLabelItems > labelNbr) {
// Draw the label here
- labelTrans.setX(labelPos);
+ labelTrans.setX(sliceCache.labelPosition(label));
m_dummyRenderItem.setTranslation(labelTrans);
LabelItem *axisLabelItem;
- if (rowMode)
- axisLabelItem = m_axisCacheX.labelItems().at(labelNbr);
- else
- axisLabelItem = m_axisCacheZ.labelItems().at(labelNbr);
+ axisLabelItem = sliceCache.labelItems().at(labelNbr);
m_drawer->drawLabel(m_dummyRenderItem, *axisLabelItem, viewMatrix, projectionMatrix,
- positionComp, rotation, 0, QAbstract3DGraph::SelectionRow,
+ positionComp, totalRotation, 0, QAbstract3DGraph::SelectionRow,
m_labelShader, m_labelObj, activeCamera,
- false, false, Drawer::LabelBelow, Qt::AlignBottom, true);
+ false, false, Drawer::LabelBelow,
+ Qt::AlignmentFlag(Qt::AlignLeft | Qt::AlignTop), true);
}
labelNbr++;
- labelPos += posStep;
}
// Draw labels for axes
AbstractRenderItem *dummyItem(0);
positionComp.setY(m_autoScaleAdjustment);
- if (rowMode) {
- m_drawer->drawLabel(*dummyItem, m_axisCacheX.titleItem(), viewMatrix, projectionMatrix,
- positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, false, false, Drawer::LabelBottom,
- Qt::AlignCenter, true);
- } else {
- m_drawer->drawLabel(*dummyItem, m_axisCacheZ.titleItem(), viewMatrix, projectionMatrix,
- positionComp, zeroVector, 0, m_cachedSelectionMode, m_labelShader,
- m_labelObj, activeCamera, false, false, Drawer::LabelBottom,
- Qt::AlignCenter, true);
- }
+ m_drawer->drawLabel(*dummyItem, sliceCache.titleItem(), viewMatrix, projectionMatrix,
+ positionComp, identityQuaternion, 0, m_cachedSelectionMode, m_labelShader,
+ m_labelObj, activeCamera, false, false, Drawer::LabelBottom,
+ Qt::AlignCenter, true);
+
// Y-axis label
+ rotation = QVector3D(0.0f, 0.0f, 90.0f);
+ totalRotation = Utils::calculateRotation(rotation);
labelTrans = QVector3D(-scaleXBackground - labelMargin, 0.0f, 0.0f);
m_dummyRenderItem.setTranslation(labelTrans);
m_drawer->drawLabel(m_dummyRenderItem, m_axisCacheY.titleItem(), viewMatrix,
- projectionMatrix, zeroVector, QVector3D(0.0f, 0.0f, 90.0f), 0,
+ projectionMatrix, zeroVector, totalRotation, 0,
m_cachedSelectionMode, m_labelShader, m_labelObj, activeCamera,
- false, false, Drawer::LabelMid, Qt::AlignHCenter);
+ false, false, Drawer::LabelMid, Qt::AlignBottom);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
@@ -1042,7 +1011,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
bool noShadows = true;
GLfloat backgroundRotation = 0;
- QVector3D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
+ QVector4D lightColor = Utils::vectorFromColor(m_cachedTheme->lightColor());
glViewport(m_primarySubViewport.x(),
m_primarySubViewport.y(),
@@ -1051,8 +1020,16 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
// Set up projection matrix
QMatrix4x4 projectionMatrix;
- projectionMatrix.perspective(45.0f, (GLfloat)m_primarySubViewport.width()
- / (GLfloat)m_primarySubViewport.height(), 0.1f, 100.0f);
+ GLfloat viewPortRatio = (GLfloat)m_primarySubViewport.width()
+ / (GLfloat)m_primarySubViewport.height();
+ if (m_useOrthoProjection) {
+ GLfloat orthoRatio = 2.0f;
+ projectionMatrix.ortho(-viewPortRatio * orthoRatio, viewPortRatio * orthoRatio,
+ -orthoRatio, orthoRatio,
+ 0.0f, 100.0f);
+ } else {
+ projectionMatrix.perspective(45.0f, viewPortRatio, 0.1f, 100.0f);
+ }
const Q3DCamera *activeCamera = m_cachedScene->activeCamera();
@@ -1089,8 +1066,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
// Draw depth buffer
#if !defined(QT_OPENGL_ES_2)
- GLfloat adjustedLightStrength = m_cachedTheme->lightStrength() / 10.0f;
- if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone && m_renderCacheList.size()) {
+ GLfloat adjustedLightStrength = m_cachedTheme->lightStrength() / 10.0f;
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone &&
+ (!m_renderCacheList.isEmpty() || !m_customRenderCache.isEmpty())) {
// Render scene into a depth texture for using with shadow mapping
// Enable drawing to depth framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, m_depthFrameBuffer);
@@ -1121,15 +1099,14 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glDisable(GL_CULL_FACE);
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
SurfaceObject *object = cache->surfaceObject();
- if (object->indexCount() && cache->surfaceVisible() && cache->isSeriesVisible()
+ if (object->indexCount() && cache->surfaceVisible() && cache->isVisible()
&& cache->sampleSpace().width() >= 2 && cache->sampleSpace().height() >= 2) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
- modelMatrix.translate(cache->offset());
- modelMatrix.scale(cache->scale());
MVPMatrix = depthProjectionViewMatrix * modelMatrix;
cache->setMVPMatrix(MVPMatrix);
m_depthShader->setUniformValue(m_depthShader->MVP(), MVPMatrix);
@@ -1149,16 +1126,18 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
}
}
- glEnable(GL_CULL_FACE);
- glCullFace(GL_FRONT);
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
m_depthModelTexture, 0);
glClear(GL_DEPTH_BUFFER_BIT);
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
SurfaceObject *object = cache->surfaceObject();
- if (object->indexCount() && cache->surfaceVisible() && cache->isSeriesVisible()
+ if (object->indexCount() && cache->surfaceVisible() && cache->isVisible()
&& cache->sampleSpace().width() >= 2 && cache->sampleSpace().height() >= 2) {
m_depthShader->setUniformValue(m_depthShader->MVP(), cache->MVPMatrix());
@@ -1183,6 +1162,10 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glDisableVertexAttribArray(m_depthShader->posAtt());
+ Abstract3DRenderer::drawCustomItems(RenderingDepth, m_depthShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
// Disable drawing to depth framebuffer (= enable drawing to screen)
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
@@ -1201,7 +1184,9 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glEnable(GL_TEXTURE_2D);
// Draw selection buffer
- if (!m_cachedIsSlicingActivated && m_renderCacheList.size() && m_selectionState == SelectOnScene
+ if (!m_cachedIsSlicingActivated && (!m_renderCacheList.isEmpty()
+ || !m_customRenderCache.isEmpty())
+ && m_selectionState == SelectOnScene
&& m_cachedSelectionMode > QAbstract3DGraph::SelectionNone) {
m_selectionShader->bind();
glBindFramebuffer(GL_FRAMEBUFFER, m_selectionFrameBuffer);
@@ -1217,14 +1202,12 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glDisable(GL_CULL_FACE);
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->surfaceObject()->indexCount() && cache->renderable()) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
- modelMatrix.translate(cache->offset());
- modelMatrix.scale(cache->scale());
-
MVPMatrix = projectionViewMatrix * modelMatrix;
m_selectionShader->setUniformValue(m_selectionShader->MVP(), MVPMatrix);
@@ -1232,21 +1215,23 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
cache->selectionTexture());
}
}
+ m_surfaceGridShader->bind();
+ Abstract3DRenderer::drawCustomItems(RenderingSelection, m_surfaceGridShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+ drawLabels(true, activeCamera, viewMatrix, projectionMatrix);
glEnable(GL_DITHER);
- GLubyte pixel[4] = {0, 0, 0, 0};
- glReadPixels(m_inputPosition.x(), m_viewport.height() - m_inputPosition.y(),
- 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void *)pixel);
+ QVector4D clickedColor = Utils::getSelection(m_inputPosition, m_viewport.height());
glBindFramebuffer(GL_FRAMEBUFFER, defaultFboHandle);
// Put the RGBA value back to uint
-#if !defined(QT_OPENGL_ES_2)
- uint selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536 + pixel[3] * 16777216;
-#else
- uint selectionId = pixel[0] + pixel[1] * 256 + pixel[2] * 65536;
-#endif
+ uint selectionId = uint(clickedColor.x())
+ + uint(clickedColor.y()) * greenMultiplier
+ + uint(clickedColor.z()) * blueMultiplier
+ + uint(clickedColor.w()) * alphaMultiplier;
m_clickedPosition = selectionIdToSurfacePoint(selectionId);
@@ -1260,21 +1245,18 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
}
// Draw the surface
- if (m_renderCacheList.size()) {
+ if (!m_renderCacheList.isEmpty()) {
// For surface we can see climpses from underneath
glDisable(GL_CULL_FACE);
bool drawGrid = false;
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(cache->offset());
- modelMatrix.scale(cache->scale());
- itModelMatrix.scale(cache->scale());
-
#ifdef SHOW_DEPTH_TEXTURE_SCENE
MVPMatrix = depthProjectionViewMatrix * modelMatrix;
#else
@@ -1283,7 +1265,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
cache->setMVPMatrix(MVPMatrix);
const QRect &sampleSpace = cache->sampleSpace();
- if (cache->surfaceObject()->indexCount() && cache->isSeriesVisible() &&
+ if (cache->surfaceObject()->indexCount() && cache->isVisible() &&
sampleSpace.width() >= 2 && sampleSpace.height() >= 2) {
noShadows = false;
if (!drawGrid && cache->surfaceGridVisible()) {
@@ -1346,13 +1328,18 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
glDisable(GL_POLYGON_OFFSET_FILL);
m_surfaceGridShader->bind();
m_surfaceGridShader->setUniformValue(m_surfaceGridShader->color(),
- Utils::vectorFromColor(m_cachedTheme->gridLineColor()));
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
- m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(), cache->MVPMatrix());
+ Utils::vectorFromColor(
+ m_cachedTheme->gridLineColor()));
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(baseCache);
+ m_surfaceGridShader->setUniformValue(m_surfaceGridShader->MVP(),
+ cache->MVPMatrix());
const QRect &sampleSpace = cache->sampleSpace();
- if (cache->surfaceObject()->indexCount() && cache->surfaceGridVisible() &&
- cache->isSeriesVisible() && sampleSpace.width() >= 2 && sampleSpace.height() >= 2) {
+ if (cache->surfaceObject()->indexCount() && cache->surfaceGridVisible()
+ && cache->isVisible() && sampleSpace.width() >= 2
+ && sampleSpace.height() >= 2) {
m_drawer->drawSurfaceGrid(m_surfaceGridShader, cache->surfaceObject());
}
}
@@ -1388,7 +1375,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
MVPMatrix = projectionViewMatrix * modelMatrix;
#endif
- QVector3D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor());
+ QVector4D backgroundColor = Utils::vectorFromColor(m_cachedTheme->backgroundColor());
// Set shader bindings
m_backgroundShader->setUniformValue(m_backgroundShader->lightP(), lightPos);
@@ -1412,7 +1399,7 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
m_backgroundShader->setUniformValue(m_backgroundShader->lightS(),
adjustedLightStrength);
// Draw the object
- if (noShadows)
+ if (noShadows && m_customRenderCache.isEmpty())
m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_noShadowTexture);
else
m_drawer->drawObject(m_backgroundShader, m_backgroundObj, 0, m_depthTexture);
@@ -1436,13 +1423,17 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
QVector3D gridLineScaleY(gridLineWidth, backgroundMargin, gridLineWidth);
if (m_cachedTheme->isGridEnabled() && m_heightNormalizer) {
+#if !(defined QT_OPENGL_ES_2)
ShaderHelper *lineShader = m_backgroundShader;
+#else
+ ShaderHelper *lineShader = m_selectionShader; // Plain color shader for GL_LINES
+#endif
// Bind line shader
lineShader->bind();
// Set unchanging shader bindings
- QVector3D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
+ QVector4D lineColor = Utils::vectorFromColor(m_cachedTheme->gridLineColor());
lineShader->setUniformValue(lineShader->lightP(), lightPos);
lineShader->setUniformValue(lineShader->view(), viewMatrix);
lineShader->setUniformValue(lineShader->color(), lineColor);
@@ -1482,16 +1473,15 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
// Rows (= Z)
if (m_axisCacheZ.segmentCount() > 0) {
// Floor lines
- GLfloat lineStep = 2.0f * aspectRatio * m_axisCacheZ.subSegmentStep() / m_scaleFactor;
- GLfloat linePos = m_scaleZ; // Start line
- int lastSegment = m_axisCacheZ.subSegmentCount() * m_axisCacheZ.segmentCount();
+ int gridLineCount = m_axisCacheZ.gridLineCount();
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(0.0f, yFloorLinePosition, linePos);
+ modelMatrix.translate(0.0f, yFloorLinePosition,
+ m_axisCacheZ.gridLinePosition(line));
modelMatrix.scale(gridLineScaleX);
itModelMatrix.scale(gridLineScaleX);
@@ -1514,34 +1504,38 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos -= lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Side wall lines
GLfloat lineXTrans = m_scaleXWithBackground - gridLineOffset;
- linePos = m_scaleZ; // Start line
if (!m_xFlipped)
lineXTrans = -lineXTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(lineXTrans, 0.0f, linePos);
+ modelMatrix.translate(lineXTrans, 0.0f, m_axisCacheZ.gridLinePosition(line));
modelMatrix.scale(gridLineScaleY);
itModelMatrix.scale(gridLineScaleY);
+#if !defined(QT_OPENGL_ES_2)
modelMatrix.rotate(lineYRotation);
itModelMatrix.rotate(lineYRotation);
+#else
+ modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+ itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+#endif
MVPMatrix = projectionViewMatrix * modelMatrix;
@@ -1558,29 +1552,31 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos -= lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
// Columns (= X)
if (m_axisCacheX.segmentCount() > 0) {
+#if defined(QT_OPENGL_ES_2)
+ lineXRotation = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 90.0f);
+#endif
// Floor lines
- GLfloat lineStep = -2.0f * aspectRatio * m_axisCacheX.subSegmentStep() / m_scaleFactor;
- GLfloat linePos = m_scaleX;
- int lastSegment = m_axisCacheX.subSegmentCount() * m_axisCacheX.segmentCount();
+ int gridLineCount = m_axisCacheX.gridLineCount();
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(linePos, yFloorLinePosition, 0.0f);
+ modelMatrix.translate(m_axisCacheX.gridLinePosition(line), yFloorLinePosition,
+ 0.0f);
modelMatrix.scale(gridLineScaleZ);
itModelMatrix.scale(gridLineScaleZ);
@@ -1603,36 +1599,40 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Back wall lines
GLfloat lineZTrans = m_scaleZWithBackground - gridLineOffset;
- linePos = m_scaleX;
if (!m_zFlipped)
lineZTrans = -lineZTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(linePos, 0.0f, lineZTrans);
+ modelMatrix.translate(m_axisCacheX.gridLinePosition(line), 0.0f, lineZTrans);
modelMatrix.scale(gridLineScaleY);
itModelMatrix.scale(gridLineScaleY);
+#if !defined(QT_OPENGL_ES_2)
if (m_zFlipped) {
modelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f);
itModelMatrix.rotate(180.0f, 1.0f, 0.0f, 0.0f);
}
+#else
+ modelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+ itModelMatrix.rotate(90.0f, 0.0f, 0.0f, 1.0f);
+#endif
MVPMatrix = projectionViewMatrix * modelMatrix;
@@ -1649,34 +1649,32 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
// Horizontal wall lines
if (m_axisCacheY.segmentCount() > 0) {
// Back wall
- GLfloat lineStep = 2.0f * m_axisCacheY.subSegmentStep() / m_heightNormalizer;
- GLfloat linePos = -1.0f;
- int lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
+ int gridLineCount = m_axisCacheY.gridLineCount();
GLfloat lineZTrans = m_scaleZWithBackground - gridLineOffset;
if (!m_zFlipped)
lineZTrans = -lineZTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(0.0f, linePos, lineZTrans);
+ modelMatrix.translate(0.0f, m_axisCacheY.gridLinePosition(line), lineZTrans);
modelMatrix.scale(gridLineScaleX);
itModelMatrix.scale(gridLineScaleX);
@@ -1701,29 +1699,27 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
// Side wall
- linePos = -1.0f;
- lastSegment = m_axisCacheY.subSegmentCount() * m_axisCacheY.segmentCount();
GLfloat lineXTrans = m_scaleXWithBackground - gridLineOffset;
if (!m_xFlipped)
lineXTrans = -lineXTrans;
- for (int segment = 0; segment <= lastSegment; segment++) {
+ for (int line = 0; line < gridLineCount; line++) {
QMatrix4x4 modelMatrix;
QMatrix4x4 MVPMatrix;
QMatrix4x4 itModelMatrix;
- modelMatrix.translate(lineXTrans, linePos, 0.0f);
+ modelMatrix.translate(lineXTrans, m_axisCacheY.gridLinePosition(line), 0.0f);
modelMatrix.scale(gridLineScaleZ);
itModelMatrix.scale(gridLineScaleZ);
@@ -1746,221 +1742,434 @@ void Surface3DRenderer::drawScene(GLuint defaultFboHandle)
lineShader->setUniformValue(lineShader->depth(), depthMVPMatrix);
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj, 0, m_depthTexture);
- } else
-#endif
- {
+ } else {
// Draw the object
m_drawer->drawObject(lineShader, m_gridLineObj);
}
- linePos += lineStep;
+#else
+ m_drawer->drawLine(lineShader);
+#endif
}
}
}
- // Draw axis labels
- m_labelShader->bind();
+ Abstract3DRenderer::drawCustomItems(RenderingNormal, m_customItemShader, viewMatrix,
+ projectionViewMatrix, depthProjectionViewMatrix,
+ m_depthTexture, m_shadowQualityToShader);
+
+ drawLabels(false, activeCamera, viewMatrix, projectionMatrix);
+
+ // Release shader
+ glUseProgram(0);
+
+ // Selection handling
+ if (m_selectionDirty || m_selectionLabelDirty) {
+ QPoint visiblePoint = Surface3DController::invalidSelectionPosition();
+ if (m_selectedSeries) {
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(
+ m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries)));
+ if (cache && m_selectedPoint != Surface3DController::invalidSelectionPosition()) {
+ const QRect &sampleSpace = cache->sampleSpace();
+ int x = m_selectedPoint.x() - sampleSpace.y();
+ int y = m_selectedPoint.y() - sampleSpace.x();
+ if (x >= 0 && y >= 0 && x < sampleSpace.height() && y < sampleSpace.width()
+ && cache->dataArray().size()) {
+ visiblePoint = QPoint(x, y);
+ }
+ }
+ }
+
+ if (m_cachedSelectionMode == QAbstract3DGraph::SelectionNone
+ || visiblePoint == Surface3DController::invalidSelectionPosition()) {
+ m_selectionActive = false;
+ } else {
+ if (m_cachedIsSlicingActivated)
+ updateSliceDataModel(visiblePoint);
+ if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionItem))
+ surfacePointSelected(visiblePoint);
+ m_selectionActive = true;
+ }
+
+ m_selectionDirty = false;
+ }
+}
+
+void Surface3DRenderer::drawLabels(bool drawSelection, const Q3DCamera *activeCamera,
+ const QMatrix4x4 &viewMatrix,
+ const QMatrix4x4 &projectionMatrix)
+{
+ ShaderHelper *shader = 0;
+ GLfloat alphaForValueSelection = labelValueAlpha / 255.0f;
+ GLfloat alphaForRowSelection = labelRowAlpha / 255.0f;
+ GLfloat alphaForColumnSelection = labelColumnAlpha / 255.0f;
+ if (drawSelection) {
+ shader = m_surfaceGridShader;
+ } else {
+ shader = m_labelShader;
+ shader->bind();
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POLYGON_OFFSET_FILL);
+ float labelAutoAngle = m_axisCacheZ.labelAutoRotation();
+ float labelAngleFraction = labelAutoAngle / 90.0f;
+ float fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ float fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ float labelsMaxWidth = 0.0f;
+
+ int startIndex;
+ int endIndex;
+ int indexStep;
+
// Z Labels
QVector3D positionZComp(0.0f, 0.0f, 0.0f);
if (m_axisCacheZ.segmentCount() > 0) {
- GLfloat posStep = 2.0f * aspectRatio * m_axisCacheZ.segmentStep() / m_scaleFactor;
- GLfloat labelPos = m_scaleZ;
- int lastSegment = m_axisCacheZ.segmentCount();
- int labelNbr = 0;
+ int labelCount = m_axisCacheZ.labelCount();
GLfloat labelXTrans = m_scaleXWithBackground + labelMargin;
GLfloat labelYTrans = -backgroundMargin;
- 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) {
+ Qt::AlignmentFlag alignment = (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ QVector3D labelRotation;
+ if (m_xFlipped)
labelXTrans = -labelXTrans;
- alignment = Qt::AlignLeft;
- }
- if (m_yFlipped) {
- rotLabelZ += 180.0f;
- rotLabelY += 180.0f;
+ if (m_yFlipped)
labelYTrans = -labelYTrans;
+ if (labelAutoAngle == 0.0f) {
+ labelRotation.setX(-90.0f);
+ if (m_zFlipped)
+ labelRotation.setY(180.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped)
+ labelRotation.setY(0.0f);
+ else
+ labelRotation.setY(180.0f);
+ labelRotation.setZ(180.0f);
+ }
+ } else {
+ if (m_zFlipped)
+ labelRotation.setY(180.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f - (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(90.0f + (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f + (labelAutoAngle - fractionCamX)
+ * -(labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f + (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f - (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f - (labelAutoAngle - fractionCamX)
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + (labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ }
+ }
+ }
}
+
+ QQuaternion totalRotation = Utils::calculateRotation(labelRotation);
+
QVector3D labelTrans = QVector3D(labelXTrans,
labelYTrans,
- labelPos);
- QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ);
-
- for (int segment = 0; segment <= lastSegment; segment++) {
- if (m_axisCacheZ.labelItems().size() > labelNbr) {
- glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f);
- // Draw the label here
- labelTrans.setZ(labelPos);
- m_dummyRenderItem.setTranslation(labelTrans);
- const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(labelNbr);
-
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- positionZComp, rotation, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, alignment);
+ 0.0f);
+
+ if (m_zFlipped) {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
+ } else {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ }
+ for (int label = startIndex; label != endIndex; label = label + indexStep) {
+ glPolygonOffset(GLfloat(label) / -10.0f, 1.0f);
+ // Draw the label here
+ labelTrans.setZ(m_axisCacheZ.labelPosition(label));
+ m_dummyRenderItem.setTranslation(labelTrans);
+ const LabelItem &axisLabelItem = *m_axisCacheZ.labelItems().at(label);
+
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(label / 255.0f, 0.0f, 0.0f,
+ alphaForRowSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- labelNbr++;
- labelPos -= posStep;
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, totalRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, alignment, false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+ if (!drawSelection && m_axisCacheZ.isTitleVisible()) {
+ labelTrans.setZ(0.0f);
+ drawAxisTitleZ(labelRotation, labelTrans, totalRotation, m_dummyRenderItem,
+ activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader);
}
}
// X Labels
if (m_axisCacheX.segmentCount() > 0) {
- GLfloat posStep = 2.0f * aspectRatio * m_axisCacheX.segmentStep() / m_scaleFactor;
- GLfloat labelPos = -m_scaleX;
- int lastSegment = m_axisCacheX.segmentCount();
+ labelsMaxWidth = 0.0f;
+ labelAutoAngle = m_axisCacheX.labelAutoRotation();
+ labelAngleFraction = labelAutoAngle / 90.0f;
+ fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ int labelCount = m_axisCacheX.labelCount();
- int labelNbr = 0;
GLfloat labelZTrans = m_scaleZWithBackground + labelMargin;
GLfloat labelYTrans = -backgroundMargin;
- 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) {
+ Qt::AlignmentFlag alignment = (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ QVector3D labelRotation;
+ if (m_zFlipped)
labelZTrans = -labelZTrans;
- alignment = Qt::AlignRight;
- }
- if (m_yFlipped) {
- rotLabelZ += 180.0f;
- rotLabelY += 180.0f;
+ if (m_yFlipped)
labelYTrans = -labelYTrans;
+ if (labelAutoAngle == 0.0f) {
+ labelRotation = QVector3D(-90.0f, 90.0f, 0.0f);
+ if (m_xFlipped)
+ labelRotation.setY(-90.0f);
+ if (m_yFlipped) {
+ if (m_xFlipped)
+ labelRotation.setY(90.0f);
+ else
+ labelRotation.setY(-90.0f);
+ labelRotation.setZ(180.0f);
+ }
+ } else {
+ if (m_xFlipped)
+ labelRotation.setY(-90.0f);
+ else
+ labelRotation.setY(90.0f);
+ if (m_yFlipped) {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f - (2.0f * labelAutoAngle - fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - (2.0f * labelAutoAngle + fractionCamX)
+ * (labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(90.0f + fractionCamX
+ * -(labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(90.0f - fractionCamX
+ * (-labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle - fractionCamY);
+ }
+ }
+ } else {
+ if (m_zFlipped) {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f + (2.0f * labelAutoAngle - fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + (2.0f * labelAutoAngle + fractionCamX)
+ * (labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ }
+ } else {
+ if (m_xFlipped) {
+ labelRotation.setX(-90.0f - fractionCamX
+ * (-labelAutoAngle + fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(-labelAutoAngle + fractionCamY);
+ } else {
+ labelRotation.setX(-90.0f + fractionCamX
+ * -(labelAutoAngle - fractionCamY) / labelAutoAngle);
+ labelRotation.setZ(labelAutoAngle - fractionCamY);
+ }
+ }
+ }
}
- QVector3D labelTrans = QVector3D(labelPos,
+ QQuaternion totalRotation = Utils::calculateRotation(labelRotation);
+
+ QVector3D labelTrans = QVector3D(0.0f,
labelYTrans,
labelZTrans);
- QVector3D rotation(rotLabelX, rotLabelY, rotLabelZ);
-
- for (int segment = 0; segment <= lastSegment; segment++) {
- if (m_axisCacheX.labelItems().size() > labelNbr) {
- glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f);
- // Draw the label here
- labelTrans.setX(labelPos);
- m_dummyRenderItem.setTranslation(labelTrans);
- const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(labelNbr);
-
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- positionZComp, rotation, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, alignment);
+
+ if (m_xFlipped) {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ } else {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
+ }
+ for (int label = startIndex; label != endIndex; label = label + indexStep) {
+ glPolygonOffset(GLfloat(label) / -10.0f, 1.0f);
+ // Draw the label here
+ labelTrans.setX(m_axisCacheX.labelPosition(label));
+ m_dummyRenderItem.setTranslation(labelTrans);
+ const LabelItem &axisLabelItem = *m_axisCacheX.labelItems().at(label);
+
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(0.0f, label / 255.0f, 0.0f,
+ alphaForColumnSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- labelNbr++;
- labelPos += posStep;
+
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, totalRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, alignment, false, drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+ if (!drawSelection && m_axisCacheX.isTitleVisible()) {
+ labelTrans.setX(0.0f);
+ drawAxisTitleX(labelRotation, labelTrans, totalRotation, m_dummyRenderItem,
+ activeCamera, labelsMaxWidth, viewMatrix, projectionMatrix, shader);
}
}
// Y Labels
if (m_axisCacheY.segmentCount() > 0) {
- GLfloat posStep = 2.0f * m_axisCacheY.segmentStep() / m_heightNormalizer;
- GLfloat labelPos = -1.0f;
- int labelNbr = 0;
+ labelsMaxWidth = 0.0f;
+ labelAutoAngle = m_axisCacheY.labelAutoRotation();
+ labelAngleFraction = labelAutoAngle / 90.0f;
+ fractionCamY = activeCamera->yRotation() * labelAngleFraction;
+ fractionCamX = activeCamera->xRotation() * labelAngleFraction;
+ int labelCount = m_axisCacheY.labelCount();
+
GLfloat labelXTrans = m_scaleXWithBackground;
GLfloat labelZTrans = m_scaleZWithBackground;
- // Back wall init
+ // Back & side wall
GLfloat labelMarginXTrans = labelMargin;
GLfloat labelMarginZTrans = labelMargin;
- GLfloat rotLabelX = 0.0f;
- GLfloat rotLabelY = -90.0f;
- GLfloat rotLabelZ = 0.0f;
- Qt::AlignmentFlag alignmentBack = Qt::AlignLeft;
+ QVector3D backLabelRotation(0.0f, -90.0f, 0.0f);
+ QVector3D sideLabelRotation(0.0f, 0.0f, 0.0f);
+ Qt::AlignmentFlag backAlignment =
+ (m_xFlipped != m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
+ Qt::AlignmentFlag sideAlignment =
+ (m_xFlipped == m_zFlipped) ? Qt::AlignLeft : Qt::AlignRight;
if (!m_xFlipped) {
labelXTrans = -labelXTrans;
labelMarginXTrans = -labelMargin;
- rotLabelY = 90.0f;
}
if (m_zFlipped) {
labelZTrans = -labelZTrans;
labelMarginZTrans = -labelMargin;
- alignmentBack = Qt::AlignRight;
}
- QVector3D labelRotateVectorBack(rotLabelX, rotLabelY, rotLabelZ);
- QVector3D labelTransBack = QVector3D(labelXTrans, 0.0f, labelZTrans + labelMarginZTrans);
+ if (labelAutoAngle == 0.0f) {
+ if (!m_xFlipped)
+ backLabelRotation.setY(90.0f);
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.f);
+ } else {
+ // Orient side labels somewhat towards the camera
+ if (m_xFlipped) {
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.0f + (2.0f * labelAutoAngle) - fractionCamX);
+ else
+ sideLabelRotation.setY(-fractionCamX);
+ backLabelRotation.setY(-90.0f + labelAutoAngle - fractionCamX);
+ } else {
+ if (m_zFlipped)
+ sideLabelRotation.setY(180.0f - (2.0f * labelAutoAngle) - fractionCamX);
+ else
+ sideLabelRotation.setY(-fractionCamX);
+ backLabelRotation.setY(90.0f - labelAutoAngle - fractionCamX);
+ }
+ }
+ sideLabelRotation.setX(-fractionCamY);
+ backLabelRotation.setX(-fractionCamY);
- // Side wall init
- Qt::AlignmentFlag alignmentSide = Qt::AlignLeft;
- if (m_xFlipped)
- alignmentSide = Qt::AlignLeft;
- else
- alignmentSide = Qt::AlignRight;
- if (m_zFlipped)
- rotLabelY = 180.0f;
- else
- rotLabelY = 0.0f;
+ QQuaternion totalSideRotation = Utils::calculateRotation(sideLabelRotation);
+ QQuaternion totalBackRotation = Utils::calculateRotation(backLabelRotation);
- QVector3D labelRotateVectorSide(rotLabelX, rotLabelY, rotLabelZ);
+ QVector3D labelTransBack = QVector3D(labelXTrans, 0.0f, labelZTrans + labelMarginZTrans);
QVector3D labelTransSide(-labelXTrans - labelMarginXTrans, 0.0f, -labelZTrans);
- for (int segment = 0; segment <= m_axisCacheY.segmentCount(); segment++) {
- if (m_axisCacheY.labelItems().size() > labelNbr) {
- const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(labelNbr);
-
- glPolygonOffset(GLfloat(segment) / -10.0f, 1.0f);
-
- // Back wall
- labelTransBack.setY(labelPos);
- m_dummyRenderItem.setTranslation(labelTransBack);
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- positionZComp, labelRotateVectorBack, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, alignmentBack);
-
- // Side wall
- labelTransSide.setY(labelPos);
- m_dummyRenderItem.setTranslation(labelTransSide);
- m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
- positionZComp, labelRotateVectorSide, 0, m_cachedSelectionMode,
- m_labelShader, m_labelObj, activeCamera,
- true, true, Drawer::LabelMid, alignmentSide);
- }
- labelNbr++;
- labelPos += posStep;
+ if (m_yFlipped) {
+ startIndex = labelCount - 1;
+ endIndex = -1;
+ indexStep = -1;
+ } else {
+ startIndex = 0;
+ endIndex = labelCount;
+ indexStep = 1;
}
- }
- glDisable(GL_POLYGON_OFFSET_FILL);
+ for (int label = startIndex; label != endIndex; label = label + indexStep) {
+ const LabelItem &axisLabelItem = *m_axisCacheY.labelItems().at(label);
+ const GLfloat labelYTrans = m_axisCacheY.labelPosition(label);
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
+ glPolygonOffset(GLfloat(label) / -10.0f, 1.0f);
- // Release shader
- glUseProgram(0);
-
- // Selection handling
- if (m_selectionDirty || m_selectionLabelDirty) {
- QPoint visiblePoint = Surface3DController::invalidSelectionPosition();
- if (m_selectedSeries) {
- SurfaceSeriesRenderCache *cache =
- m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries));
- if (cache && m_selectedPoint != Surface3DController::invalidSelectionPosition()) {
- const QRect &sampleSpace = cache->sampleSpace();
- int x = m_selectedPoint.x() - sampleSpace.y();
- int y = m_selectedPoint.y() - sampleSpace.x();
- if (x >= 0 && y >= 0 && x < sampleSpace.height() && y < sampleSpace.width()
- && cache->dataArray().size()) {
- visiblePoint = QPoint(x, y);
- }
+ if (drawSelection) {
+ QVector4D labelColor = QVector4D(0.0f, 0.0f, label / 255.0f,
+ alphaForValueSelection);
+ shader->setUniformValue(shader->color(), labelColor);
}
- }
- if (m_cachedSelectionMode == QAbstract3DGraph::SelectionNone
- || visiblePoint == Surface3DController::invalidSelectionPosition()) {
- m_selectionActive = false;
- } else {
- if (m_cachedIsSlicingActivated)
- updateSliceDataModel(visiblePoint);
- if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionItem))
- surfacePointSelected(visiblePoint);
- m_selectionActive = true;
+ // Back wall
+ labelTransBack.setY(labelYTrans);
+ m_dummyRenderItem.setTranslation(labelTransBack);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, totalBackRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, backAlignment, false,
+ drawSelection);
+
+ // Side wall
+ labelTransSide.setY(labelYTrans);
+ m_dummyRenderItem.setTranslation(labelTransSide);
+ m_drawer->drawLabel(m_dummyRenderItem, axisLabelItem, viewMatrix, projectionMatrix,
+ positionZComp, totalSideRotation, 0, m_cachedSelectionMode,
+ shader, m_labelObj, activeCamera,
+ true, true, Drawer::LabelMid, sideAlignment, false,
+ drawSelection);
+ labelsMaxWidth = qMax(labelsMaxWidth, float(axisLabelItem.size().width()));
+ }
+ if (!drawSelection && m_axisCacheY.isTitleVisible()) {
+ labelTransSide.setY(0.0f);
+ labelTransBack.setY(0.0f);
+ drawAxisTitleY(sideLabelRotation, backLabelRotation, labelTransSide, labelTransBack,
+ totalSideRotation, totalBackRotation, m_dummyRenderItem, activeCamera,
+ labelsMaxWidth, viewMatrix, projectionMatrix,
+ shader);
}
+ }
+ glDisable(GL_POLYGON_OFFSET_FILL);
- m_selectionDirty = false;
+ if (!drawSelection) {
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
}
}
@@ -1976,7 +2185,9 @@ void Surface3DRenderer::updateSelectionTextures()
{
uint lastSelectionId = 1;
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(baseCache);
GLuint texture = cache->selectionTexture();
m_textureHelper->deleteTexture(&texture);
createSelectionTexture(cache, lastSelectionId);
@@ -1992,6 +2203,13 @@ void Surface3DRenderer::createSelectionTexture(SurfaceSeriesRenderCache *cache,
const QRect &sampleSpace = cache->sampleSpace();
int idImageWidth = (sampleSpace.width() - 1) * 4;
int idImageHeight = (sampleSpace.height() - 1) * 4;
+
+ if (idImageHeight <= 0 || idImageWidth <= 0) {
+ cache->setSelectionIdRange(-1, -1);
+ cache->setSelectionTexture(0);
+ return;
+ }
+
int stride = idImageWidth * 4 * sizeof(uchar); // 4 = number of color components (rgba)
uint idStart = lastSelectionId;
@@ -2031,10 +2249,7 @@ void Surface3DRenderer::createSelectionTexture(SurfaceSeriesRenderCache *cache,
void Surface3DRenderer::initSelectionBuffer()
{
// Create the result selection texture and buffers
- if (m_selectionResultTexture) {
- m_textureHelper->deleteTexture(&m_selectionResultTexture);
- m_selectionResultTexture = 0;
- }
+ m_textureHelper->deleteTexture(&m_selectionResultTexture);
m_selectionResultTexture = m_textureHelper->createSelectionTexture(m_primarySubViewport.size(),
m_selectionFrameBuffer,
@@ -2076,10 +2291,16 @@ void Surface3DRenderer::calculateSceneScalingFactors()
m_areaSize.setHeight(m_axisCacheZ.max() - m_axisCacheZ.min());
m_areaSize.setWidth(m_axisCacheX.max() - m_axisCacheX.min());
m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height());
- m_scaleX = aspectRatio * m_areaSize.width() / m_scaleFactor;
- m_scaleZ = aspectRatio * m_areaSize.height() / m_scaleFactor;
- m_scaleXWithBackground = m_scaleX * backgroundMargin;
- m_scaleZWithBackground = m_scaleZ * backgroundMargin;
+ m_scaleX = m_graphAspectRatio * m_areaSize.width() / m_scaleFactor;
+ m_scaleZ = m_graphAspectRatio * m_areaSize.height() / m_scaleFactor;
+ m_scaleXWithBackground = m_scaleX + backgroundMargin - 1.0f;
+ m_scaleZWithBackground = m_scaleZ + backgroundMargin - 1.0f;
+
+ float factorScaler = 2.0f * m_graphAspectRatio / m_scaleFactor;
+ m_axisCacheX.setScale(factorScaler * m_areaSize.width());
+ m_axisCacheZ.setScale(-factorScaler * m_areaSize.height());
+ m_axisCacheX.setTranslate(-m_axisCacheX.scale() / 2.0f);
+ m_axisCacheZ.setTranslate(-m_axisCacheZ.scale() / 2.0f);
}
void Surface3DRenderer::checkFlatSupport(SurfaceSeriesRenderCache *cache)
@@ -2098,17 +2319,13 @@ void Surface3DRenderer::updateObjects(SurfaceSeriesRenderCache *cache, bool dime
QSurfaceDataArray &dataArray = cache->dataArray();
const QRect &sampleSpace = cache->sampleSpace();
-
- if (cache->isFlatShadingEnabled()) {
- cache->surfaceObject()->setUpData(dataArray, sampleSpace, m_heightNormalizer,
- m_axisCacheY.min(), dimensionChanged);
- } else {
- cache->surfaceObject()->setUpSmoothData(dataArray, sampleSpace, m_heightNormalizer,
- m_axisCacheY.min(), dimensionChanged);
- }
+ if (cache->isFlatShadingEnabled())
+ cache->surfaceObject()->setUpData(dataArray, sampleSpace, dimensionChanged);
+ else
+ cache->surfaceObject()->setUpSmoothData(dataArray, sampleSpace, dimensionChanged);
}
-void Surface3DRenderer::updateSelectedPoint(const QPoint &position, const QSurface3DSeries *series)
+void Surface3DRenderer::updateSelectedPoint(const QPoint &position, QSurface3DSeries *series)
{
m_selectedPoint = position;
m_selectedSeries = series;
@@ -2123,23 +2340,15 @@ void Surface3DRenderer::resetClickedStatus()
void Surface3DRenderer::loadBackgroundMesh()
{
- if (m_backgroundObj)
- delete m_backgroundObj;
- m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
- m_backgroundObj->load();
-}
-
-void Surface3DRenderer::loadGridLineMesh()
-{
- if (m_gridLineObj)
- delete m_gridLineObj;
- m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_gridLineObj->load();
+ ObjectHelper::resetObjectHelper(this, m_backgroundObj,
+ QStringLiteral(":/defaultMeshes/background"));
}
void Surface3DRenderer::surfacePointSelected(const QPoint &point)
{
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(baseCache);
cache->setSlicePointerActivity(false);
cache->setMainPointerActivity(false);
}
@@ -2147,12 +2356,15 @@ void Surface3DRenderer::surfacePointSelected(const QPoint &point)
if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries)) {
// Find axis coordinates for the selected point
SurfaceSeriesRenderCache *selectedCache =
- m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries));
+ static_cast<SurfaceSeriesRenderCache *>(
+ m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries)));
QSurfaceDataArray &dataArray = selectedCache->dataArray();
QSurfaceDataItem item = dataArray.at(point.x())->at(point.y());
QPointF coords(item.x(), item.z());
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache =
+ static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->series() != m_selectedSeries) {
QPoint mappedPoint = mapCoordsToSampleSpace(cache, coords);
updateSelectionPoint(cache, mappedPoint, false);
@@ -2163,7 +2375,8 @@ void Surface3DRenderer::surfacePointSelected(const QPoint &point)
} else {
if (m_selectedSeries) {
SurfaceSeriesRenderCache *cache =
- m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries));
+ static_cast<SurfaceSeriesRenderCache *>(
+ m_renderCacheList.value(const_cast<QSurface3DSeries *>(m_selectedSeries)));
if (cache)
updateSelectionPoint(cache, point, true);
}
@@ -2179,9 +2392,6 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co
if (column < 0 || row < 0)
return;
- QSurfaceDataArray &dataArray = cache->dataArray();
- float value = dataArray.at(row)->at(column).y();
-
SelectionPointer *slicePointer = cache->sliceSelectionPointer();
if (!slicePointer && m_cachedIsSlicingActivated) {
slicePointer = new SelectionPointer(m_drawer);
@@ -2193,28 +2403,28 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co
cache->setMainSelectionPointer(mainPointer);
}
- const QVector3D &scale = cache->scale();
- const QVector3D &offset = cache->offset();
QString selectionLabel;
- if (label)
- selectionLabel = createSelectionLabel(cache, value, column, row);
+ if (label) {
+ m_selectionLabelDirty = false;
+ selectionLabel = cache->itemLabel();
+ }
if (m_cachedIsSlicingActivated) {
- QVector3D subPos;
+ QVector3D subPosFront;
+ QVector3D subPosBack;
if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionRow)) {
- subPos = cache->sliceSurfaceObject()->vertexAt(column, 0);
- subPos *= QVector3D(scale.x(), 1.0f, 0.0f);
- subPos += QVector3D(offset.x(), 0.0f, 0.0f);
+ subPosFront = cache->sliceSurfaceObject()->vertexAt(column, 0);
+ subPosBack = cache->sliceSurfaceObject()->vertexAt(column, 1);
} else if (m_cachedSelectionMode.testFlag(QAbstract3DGraph::SelectionColumn)) {
- subPos = cache->sliceSurfaceObject()->vertexAt(row, 0);
- subPos *= QVector3D(scale.z(), 1.0f, 0.0f);
- subPos += QVector3D(-offset.z(), 0.0f, 0.0f);
+ subPosFront = cache->sliceSurfaceObject()->vertexAt(row, 0);
+ subPosBack = cache->sliceSurfaceObject()->vertexAt(row, 1);
}
slicePointer->updateBoundingRect(m_secondarySubViewport);
slicePointer->updateSliceData(true, m_autoScaleAdjustment);
- slicePointer->setPosition(subPos);
+ slicePointer->setPosition((subPosFront + subPosBack) / 2.0f);
slicePointer->setLabel(selectionLabel);
slicePointer->setPointerObject(cache->object());
+ slicePointer->setLabelObject(m_labelObj);
slicePointer->setHighlightColor(cache->singleHighlightColor());
slicePointer->updateScene(m_cachedScene);
slicePointer->setRotation(cache->meshRotation());
@@ -2223,13 +2433,12 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co
QVector3D mainPos;
mainPos = cache->surfaceObject()->vertexAt(column, row);
- mainPos *= scale;
- mainPos += offset;
mainPointer->updateBoundingRect(m_primarySubViewport);
mainPointer->updateSliceData(false, m_autoScaleAdjustment);
mainPointer->setPosition(mainPos);
mainPointer->setLabel(selectionLabel);
mainPointer->setPointerObject(cache->object());
+ mainPointer->setLabelObject(m_labelObj);
mainPointer->setHighlightColor(cache->singleHighlightColor());
mainPointer->updateScene(m_cachedScene);
mainPointer->setRotation(cache->meshRotation());
@@ -2239,8 +2448,33 @@ void Surface3DRenderer::updateSelectionPoint(SurfaceSeriesRenderCache *cache, co
// Maps selection Id to surface point in data array
QPoint Surface3DRenderer::selectionIdToSurfacePoint(uint id)
{
+ m_clickedType = QAbstract3DGraph::ElementNone;
+ m_selectedLabelIndex = -1;
+ m_selectedCustomItemIndex = -1;
+ // Check for label and custom item selection
+ if (id / alphaMultiplier == labelRowAlpha) {
+ m_selectedLabelIndex = id - (alphaMultiplier * uint(labelRowAlpha));
+ m_clickedType = QAbstract3DGraph::ElementAxisZLabel;
+ return Surface3DController::invalidSelectionPosition();
+ } else if (id / alphaMultiplier == labelColumnAlpha) {
+ m_selectedLabelIndex = (id - (alphaMultiplier * uint(labelColumnAlpha))) / greenMultiplier;
+ m_clickedType = QAbstract3DGraph::ElementAxisXLabel;
+ return Surface3DController::invalidSelectionPosition();
+ } else if (id / alphaMultiplier == labelValueAlpha) {
+ m_selectedLabelIndex = (id - (alphaMultiplier * uint(labelValueAlpha))) / blueMultiplier;
+ m_clickedType = QAbstract3DGraph::ElementAxisYLabel;
+ return Surface3DController::invalidSelectionPosition();
+ } else if (id / alphaMultiplier == customItemAlpha) {
+ // Custom item selection
+ m_clickedType = QAbstract3DGraph::ElementCustomItem;
+ m_selectedCustomItemIndex = id - (alphaMultiplier * uint(customItemAlpha));
+ return Surface3DController::invalidSelectionPosition();
+ }
+
+ // Not a label selection
SurfaceSeriesRenderCache *selectedCache = 0;
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->isWithinIdRange(id)) {
selectedCache = cache;
break;
@@ -2257,57 +2491,10 @@ QPoint Surface3DRenderer::selectionIdToSurfacePoint(uint id)
int row = ((idInSeries - 1) / sampleSpace.width()) + sampleSpace.y();
m_clickedSeries = selectedCache->series();
+ m_clickedType = QAbstract3DGraph::ElementSeries;
return QPoint(row, column);
}
-QString Surface3DRenderer::createSelectionLabel(SurfaceSeriesRenderCache *cache, float value,
- int column, int row)
-{
- QSurfaceDataArray &dataArray = cache->dataArray();
- QString labelText = cache->itemLabelFormat();
- static const QString xTitleTag(QStringLiteral("@xTitle"));
- static const QString yTitleTag(QStringLiteral("@yTitle"));
- static const QString zTitleTag(QStringLiteral("@zTitle"));
- static const QString xLabelTag(QStringLiteral("@xLabel"));
- static const QString yLabelTag(QStringLiteral("@yLabel"));
- static const QString zLabelTag(QStringLiteral("@zLabel"));
- static const QString seriesNameTag(QStringLiteral("@seriesName"));
-
- labelText.replace(xTitleTag, m_axisCacheX.title());
- labelText.replace(yTitleTag, m_axisCacheY.title());
- labelText.replace(zTitleTag, m_axisCacheZ.title());
-
- if (labelText.contains(xLabelTag)) {
- QString labelFormat = m_axisCacheX.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat,
- dataArray.at(row)->at(column).x());
- labelText.replace(xLabelTag, valueLabelText);
- }
- if (labelText.contains(yLabelTag)) {
- QString labelFormat = m_axisCacheY.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat, value);
- labelText.replace(yLabelTag, valueLabelText);
- }
- if (labelText.contains(zLabelTag)) {
- QString labelFormat = m_axisCacheZ.labelFormat();
- if (labelFormat.isEmpty())
- labelFormat = Utils::defaultLabelFormat();
- QString valueLabelText = generateValueLabel(labelFormat,
- dataArray.at(row)->at(column).z());
- labelText.replace(zLabelTag, valueLabelText);
- }
-
- labelText.replace(seriesNameTag, cache->name());
-
- m_selectionLabelDirty = false;
-
- return labelText;
-}
-
void Surface3DRenderer::updateShadowQuality(QAbstract3DGraph::ShadowQuality quality)
{
m_cachedShadowQuality = quality;
@@ -2371,20 +2558,13 @@ void Surface3DRenderer::updateSlicingActive(bool isSlicing)
m_selectionDirty = true;
- foreach (SurfaceSeriesRenderCache *cache, m_renderCacheList) {
+ foreach (SeriesRenderCache *baseCache, m_renderCacheList) {
+ SurfaceSeriesRenderCache *cache = static_cast<SurfaceSeriesRenderCache *>(baseCache);
if (cache->mainSelectionPointer())
cache->mainSelectionPointer()->updateBoundingRect(m_primarySubViewport);
}
}
-void Surface3DRenderer::loadLabelMesh()
-{
- if (m_labelObj)
- delete m_labelObj;
- m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/plane"));
- m_labelObj->load();
-}
-
void Surface3DRenderer::initShaders(const QString &vertexShader, const QString &fragmentShader)
{
Q_UNUSED(vertexShader);
@@ -2408,17 +2588,22 @@ void Surface3DRenderer::initShaders(const QString &vertexShader, const QString &
m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragmentSurface"));
}
- if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
- m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceShadowFlat"),
- QStringLiteral(":/shaders/fragmentSurfaceShadowFlat"));
- } else {
- m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
- QStringLiteral(":/shaders/fragmentSurfaceFlat"));
- }
m_surfaceSliceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragmentSurface"));
- m_surfaceSliceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
- QStringLiteral(":/shaders/fragmentSurfaceFlat"));
+ if (m_flatSupported) {
+ if (m_cachedShadowQuality > QAbstract3DGraph::ShadowQualityNone) {
+ m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceShadowFlat"),
+ QStringLiteral(":/shaders/fragmentSurfaceShadowFlat"));
+ } else {
+ m_surfaceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
+ QStringLiteral(":/shaders/fragmentSurfaceFlat"));
+ }
+ m_surfaceSliceFlatShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertexSurfaceFlat"),
+ QStringLiteral(":/shaders/fragmentSurfaceFlat"));
+ } else {
+ m_surfaceFlatShader = 0;
+ m_surfaceSliceFlatShader = 0;
+ }
#else
m_surfaceSmoothShader = new ShaderHelper(this, QStringLiteral(":/shaders/vertex"),
QStringLiteral(":/shaders/fragmentSurfaceES2"));
@@ -2430,9 +2615,11 @@ void Surface3DRenderer::initShaders(const QString &vertexShader, const QString &
QStringLiteral(":/shaders/fragmentSurfaceES2"));
#endif
m_surfaceSmoothShader->initialize();
- m_surfaceFlatShader->initialize();
m_surfaceSliceSmoothShader->initialize();
- m_surfaceSliceFlatShader->initialize();
+ if (m_flatSupported) {
+ m_surfaceFlatShader->initialize();
+ m_surfaceSliceFlatShader->initialize();
+ }
}
void Surface3DRenderer::initBackgroundShaders(const QString &vertexShader,
@@ -2486,14 +2673,8 @@ void Surface3DRenderer::initDepthShader()
void Surface3DRenderer::updateDepthBuffer()
{
- if (m_depthTexture) {
- m_textureHelper->deleteTexture(&m_depthTexture);
- m_depthTexture = 0;
- }
- if (m_depthModelTexture) {
- m_textureHelper->deleteTexture(&m_depthModelTexture);
- m_depthModelTexture = 0;
- }
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ m_textureHelper->deleteTexture(&m_depthModelTexture);
if (m_primarySubViewport.size().isEmpty())
return;
@@ -2512,4 +2693,22 @@ void Surface3DRenderer::updateDepthBuffer()
}
#endif
+QVector3D Surface3DRenderer::convertPositionToTranslation(const QVector3D &position,
+ bool isAbsolute)
+{
+ float xTrans = 0.0f;
+ float yTrans = 0.0f;
+ float zTrans = 0.0f;
+ if (!isAbsolute) {
+ xTrans = m_axisCacheX.positionAt(position.x());
+ yTrans = m_axisCacheY.positionAt(position.y());
+ zTrans = m_axisCacheZ.positionAt(position.z());
+ } else {
+ xTrans = position.x() * m_scaleX;
+ yTrans = position.y();
+ zTrans = position.z() * m_scaleZ;
+ }
+ return QVector3D(xTrans, yTrans, zTrans);
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/surface3drenderer_p.h b/src/datavisualization/engine/surface3drenderer_p.h
index 2c55d902..efa8ff7e 100644
--- a/src/datavisualization/engine/surface3drenderer_p.h
+++ b/src/datavisualization/engine/surface3drenderer_p.h
@@ -32,17 +32,12 @@
#include "datavisualizationglobal_p.h"
#include "surface3dcontroller_p.h"
#include "abstract3drenderer_p.h"
-#include "scatterrenderitem_p.h"
-#include "qsurfacedataproxy.h"
#include "surfaceseriesrendercache_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class ShaderHelper;
-class ObjectHelper;
-class SurfaceObject;
class Q3DScene;
-class SelectionPointer;
class QT_DATAVISUALIZATION_EXPORT Surface3DRenderer : public Abstract3DRenderer
{
@@ -67,15 +62,6 @@ private:
GLfloat m_scaleZ;
GLfloat m_scaleXWithBackground;
GLfloat m_scaleZWithBackground;
- GLfloat m_minVisibleColumnValue;
- GLfloat m_maxVisibleColumnValue;
- GLfloat m_minVisibleRowValue;
- GLfloat m_maxVisibleRowValue;
- GLfloat m_visibleColumnRange;
- GLfloat m_visibleRowRange;
- ObjectHelper *m_backgroundObj;
- ObjectHelper *m_gridLineObj;
- ObjectHelper *m_labelObj;
GLuint m_depthTexture;
GLuint m_depthModelTexture;
GLuint m_depthFrameBuffer;
@@ -85,17 +71,13 @@ private:
GLfloat m_shadowQualityToShader;
bool m_flatSupported;
bool m_selectionActive;
- bool m_xFlipped;
- bool m_zFlipped;
- bool m_yFlipped;
AbstractRenderItem m_dummyRenderItem;
GLint m_shadowQualityMultiplier;
QSizeF m_areaSize;
bool m_hasHeightAdjustmentChanged;
QPoint m_selectedPoint;
- const QSurface3DSeries *m_selectedSeries;
+ QSurface3DSeries *m_selectedSeries;
QPoint m_clickedPosition;
- QHash<QSurface3DSeries *, SurfaceSeriesRenderCache *> m_renderCacheList;
bool m_selectionTexturesDirty;
GLuint m_noShadowTexture;
@@ -104,19 +86,19 @@ public:
~Surface3DRenderer();
void updateData();
- void updateSeries(const QList<QAbstract3DSeries *> &seriesList, bool updateVisibility);
+ void updateSeries(const QList<QAbstract3DSeries *> &seriesList);
+ SeriesRenderCache *createNewCache(QAbstract3DSeries *series);
+ void cleanCache(SeriesRenderCache *cache);
void updateSelectionMode(QAbstract3DGraph::SelectionFlags mode);
- void modifiedSeriesList(const QVector<QSurface3DSeries *> &seriesList);
void updateRows(const QVector<Surface3DController::ChangeRow> &rows);
- void updateItem(const QVector<Surface3DController::ChangeItem> &points);
- void updateAxisRange(QAbstract3DAxis::AxisOrientation orientation, float min, float max);
+ void updateItems(const QVector<Surface3DController::ChangeItem> &points);
void updateScene(Q3DScene *scene);
void updateSlicingActive(bool isSlicing);
- void updateSelectedPoint(const QPoint &position, const QSurface3DSeries *series);
+ void updateSelectedPoint(const QPoint &position, QSurface3DSeries *series);
inline QPoint clickedPosition() const { return m_clickedPosition; }
void resetClickedStatus();
+ QVector3D convertPositionToTranslation(const QVector3D &position, bool isAbsolute);
- void drawSlicedScene();
void render(GLuint defaultFboHandle = 0);
protected:
@@ -136,11 +118,14 @@ private:
void updateShadowQuality(QAbstract3DGraph::ShadowQuality quality);
void updateTextures();
void initShaders(const QString &vertexShader, const QString &fragmentShader);
- QRect calculateSampleRect(SurfaceSeriesRenderCache *cache, const QSurfaceDataArray &array);
+ QRect calculateSampleRect(const QSurfaceDataArray &array);
void loadBackgroundMesh();
- void loadGridLineMesh();
- void loadLabelMesh();
+
+ void drawSlicedScene();
void drawScene(GLuint defaultFboHandle);
+ void drawLabels(bool drawSelection, const Q3DCamera *activeCamera,
+ const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix);
+
void calculateSceneScalingFactors();
void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
@@ -155,13 +140,14 @@ private:
void surfacePointSelected(const QPoint &point);
void updateSelectionPoint(SurfaceSeriesRenderCache *cache, const QPoint &point, bool label);
QPoint selectionIdToSurfacePoint(uint id);
- QString createSelectionLabel(SurfaceSeriesRenderCache *cache, float value, int column, int row);
#if !defined(QT_OPENGL_ES_2)
void updateDepthBuffer();
#endif
void emitSelectedPointChanged(QPoint position);
Q_DISABLE_COPY(Surface3DRenderer)
+
+ friend class SurfaceObject;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/engine/surfaceseriesrendercache.cpp b/src/datavisualization/engine/surfaceseriesrendercache.cpp
index ba25d71d..1cce5288 100644
--- a/src/datavisualization/engine/surfaceseriesrendercache.cpp
+++ b/src/datavisualization/engine/surfaceseriesrendercache.cpp
@@ -16,35 +16,30 @@
**
****************************************************************************/
-#include "seriesrendercache_p.h"
#include "surfaceseriesrendercache_p.h"
-#include "objecthelper_p.h"
-#include "abstract3drenderer_p.h"
+#include "surface3drenderer_p.h"
#include "texturehelper_p.h"
-#include "utils_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-SurfaceSeriesRenderCache::SurfaceSeriesRenderCache()
- : m_surfaceVisible(false),
+SurfaceSeriesRenderCache::SurfaceSeriesRenderCache(QAbstract3DSeries *series,
+ Surface3DRenderer *renderer)
+ : SeriesRenderCache(series, renderer),
+ m_surfaceVisible(false),
m_surfaceGridVisible(false),
- m_surfaceFlatShading(true),
- m_surfaceObj(new SurfaceObject),
- m_sliceSurfaceObj(new SurfaceObject),
- m_sampleSpace(QRect(0, 0, 0 , 0)),
+ m_surfaceFlatShading(false),
+ m_surfaceObj(new SurfaceObject(renderer)),
+ m_sliceSurfaceObj(new SurfaceObject(renderer)),
+ m_sampleSpace(QRect(0, 0, 0, 0)),
m_selectionTexture(0),
m_selectionIdStart(0),
m_selectionIdEnd(0),
m_flatChangeAllowed(true),
- m_flatStatusDirty(false),
- m_scale(QVector3D(1.0f, 1.0f, 1.0f)),
- m_offset(QVector3D(0.0f, 0.0f, 0.0f)),
+ m_flatStatusDirty(true),
m_sliceSelectionPointer(0),
m_mainSelectionPointer(0),
m_slicePointerActive(false),
- m_mainPointerActive(false),
- m_valid(false),
- m_objectDirty(true)
+ m_mainPointerActive(false)
{
}
@@ -52,17 +47,15 @@ SurfaceSeriesRenderCache::~SurfaceSeriesRenderCache()
{
}
-void SurfaceSeriesRenderCache::populate(QSurface3DSeries *series, Abstract3DRenderer *renderer)
+void SurfaceSeriesRenderCache::populate(bool newSeries)
{
- Q_ASSERT(series);
+ SeriesRenderCache::populate(newSeries);
- SeriesRenderCache::populate(series, renderer);
-
- QSurface3DSeries::DrawFlags drawMode = series->drawMode();
+ QSurface3DSeries::DrawFlags drawMode = series()->drawMode();
m_surfaceVisible = drawMode.testFlag(QSurface3DSeries::DrawSurface);
m_surfaceGridVisible = drawMode.testFlag(QSurface3DSeries::DrawWireframe);
- if (m_flatChangeAllowed && m_surfaceFlatShading != series->isFlatShadingEnabled()) {
- m_surfaceFlatShading = series->isFlatShadingEnabled();
+ if (m_flatChangeAllowed && m_surfaceFlatShading != series()->isFlatShadingEnabled()) {
+ m_surfaceFlatShading = series()->isFlatShadingEnabled();
m_flatStatusDirty = true;
}
}
diff --git a/src/datavisualization/engine/surfaceseriesrendercache_p.h b/src/datavisualization/engine/surfaceseriesrendercache_p.h
index 2dda0670..b6254a75 100644
--- a/src/datavisualization/engine/surfaceseriesrendercache_p.h
+++ b/src/datavisualization/engine/surfaceseriesrendercache_p.h
@@ -31,7 +31,6 @@
#include "datavisualizationglobal_p.h"
#include "seriesrendercache_p.h"
-#include "qabstract3dseries_p.h"
#include "qsurface3dseries_p.h"
#include "surfaceobject_p.h"
#include "selectionpointer_p.h"
@@ -40,17 +39,15 @@
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-class Abstract3DRenderer;
-class ObjectHelper;
-class TextureHelper;
+class Surface3DRenderer;
class SurfaceSeriesRenderCache : public SeriesRenderCache
{
public:
- SurfaceSeriesRenderCache();
+ SurfaceSeriesRenderCache(QAbstract3DSeries *series, Surface3DRenderer *renderer);
virtual ~SurfaceSeriesRenderCache();
- void populate(QSurface3DSeries *series, Abstract3DRenderer *renderer);
+ virtual void populate(bool newSeries);
virtual void cleanup(TextureHelper *texHelper);
inline bool surfaceVisible() const { return m_surfaceVisible; }
@@ -58,8 +55,6 @@ public:
inline bool isFlatShadingEnabled() const { return m_surfaceFlatShading; }
inline void setFlatShadingEnabled(bool enabled) { m_surfaceFlatShading = enabled; }
inline void setFlatChangeAllowed(bool allowed) { m_flatChangeAllowed = allowed; }
- inline void setValid(bool valid) { m_valid = valid; }
- inline bool isValid() const { return m_valid; }
inline SurfaceObject *surfaceObject() { return m_surfaceObj; }
inline SurfaceObject *sliceSurfaceObject() { return m_sliceSurfaceObj; }
inline const QRect &sampleSpace() const { return m_sampleSpace; }
@@ -67,11 +62,8 @@ public:
inline QSurface3DSeries *series() const { return static_cast<QSurface3DSeries *>(m_series); }
inline QSurfaceDataArray &dataArray() { return m_dataArray; }
inline QSurfaceDataArray &sliceDataArray() { return m_sliceDataArray; }
- inline bool isSeriesVisible() const { return m_series->isVisible(); }
- inline bool renderable() const { return m_series->isVisible() && (m_surfaceVisible ||
- m_surfaceGridVisible); }
- inline void setObjectDirty(bool state) { m_objectDirty = state; }
- inline bool objectDirty() const { return m_objectDirty; }
+ inline bool renderable() const { return m_visible && (m_surfaceVisible ||
+ m_surfaceGridVisible); }
inline void setSelectionTexture(GLuint texture) { m_selectionTexture = texture; }
inline GLuint selectionTexture() const { return m_selectionTexture; }
inline void setSelectionIdRange(uint start, uint end) { m_selectionIdStart = start;
@@ -81,11 +73,6 @@ public:
selection <= m_selectionIdEnd; }
inline bool isFlatStatusDirty() const { return m_flatStatusDirty; }
inline void setFlatStatusDirty(bool status) { m_flatStatusDirty = status; }
- inline void setScale(const QVector3D &scale) { m_scale = scale; }
- inline const QVector3D &scale() const { return m_scale; }
- inline void setOffset(const QVector3D &offset) { m_offset = offset; }
- inline const QVector3D &offset() const { return m_offset; }
- // m_MVPMatrix is volatile, used only for optimizing rendering a bit
inline void setMVPMatrix(const QMatrix4x4 &matrix) { m_MVPMatrix = matrix; }
inline const QMatrix4x4 &MVPMatrix() { return m_MVPMatrix; }
@@ -113,16 +100,11 @@ protected:
uint m_selectionIdEnd;
bool m_flatChangeAllowed;
bool m_flatStatusDirty;
- QVector3D m_scale;
- QVector3D m_offset;
QMatrix4x4 m_MVPMatrix;
SelectionPointer *m_sliceSelectionPointer;
SelectionPointer *m_mainSelectionPointer;
bool m_slicePointerActive;
bool m_mainPointerActive;
-
- bool m_valid;
- bool m_objectDirty;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/global/datavisualizationglobal_p.h b/src/datavisualization/global/datavisualizationglobal_p.h
index e448c1cb..abdac998 100644
--- a/src/datavisualization/global/datavisualizationglobal_p.h
+++ b/src/datavisualization/global/datavisualizationglobal_p.h
@@ -43,7 +43,11 @@ static const GLfloat cameraDistance = 6.0f;
// Size of font to be used in label texture rendering. Doesn't affect the actual font size.
static const int textureFontSize = 50;
static const GLfloat defaultRatio = 1.0f / 1.6f; // default aspect ratio 16:10
+#if !(defined QT_OPENGL_ES)
static const float gridLineOffset = 0.0001f; // Offset for lifting grid lines off background
+#else
+static const float gridLineOffset = 0.0035f; // Offset for lifting grid lines off background
+#endif
// Default light position. To have shadows working correctly, light should be as far as camera, or a bit further
// y position is added to the minimum height (or can be thought to be that much above or below the camera)
static const QVector3D defaultLightPos = QVector3D(0.0f, 0.5f, 0.0f);
@@ -53,12 +57,18 @@ static const QVector3D cameraDistanceVector = QVector3D(0.0f, 0.0f, cameraDistan
static const QQuaternion identityQuaternion;
// Skip color == selection texture's background color
-static const QVector3D selectionSkipColor = QVector3D(255.0f, 255.0f, 255.0f);
-static const QVector3D invalidColorVector = QVector3D(-1.0f, -1.0f, -1.0f);
+static const QVector4D selectionSkipColor = QVector4D(255.0f, 255.0f, 255.0f, 255.0f);
+static const QVector4D invalidColorVector = QVector4D(-1.0f, -1.0f, -1.0f, -1.0f);
+static const GLfloat itemAlpha = 0.0f;
+static const GLfloat customItemAlpha = 252.0f;
+static const GLfloat labelValueAlpha = 253.0f;
+static const GLfloat labelRowAlpha = 254.0f;
+static const GLfloat labelColumnAlpha = 255.0f;
static const GLfloat gradientTextureHeight = 1024.0f;
static const GLfloat gradientTextureWidth = 2.0f;
static const GLfloat uniformTextureHeight = 64.0f;
static const GLfloat uniformTextureWidth = 2.0f;
+static const GLfloat labelMargin = 0.05f;
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/global/qdatavisualizationglobal.h b/src/datavisualization/global/qdatavisualizationglobal.h
index 186db94c..e84d03c0 100644
--- a/src/datavisualization/global/qdatavisualizationglobal.h
+++ b/src/datavisualization/global/qdatavisualizationglobal.h
@@ -21,11 +21,11 @@
#include <QtCore/qglobal.h>
-#define QT_DATAVISUALIZATION_VERSION_STR "1.0.0"
+#define QT_DATAVISUALIZATION_VERSION_STR "1.1.0"
/*
QT_DATAVISUALIZATION_VERSION is (major << 16) + (minor << 8) + patch.
*/
-#define QT_DATAVISUALIZATION_VERSION 0x010000
+#define QT_DATAVISUALIZATION_VERSION 0x010100
/*
can be used like #if (QT_DATAVISUALIZATION_VERSION >= QT_DATAVISUALIZATION_VERSION_CHECK(1, 0, 0))
*/
diff --git a/src/datavisualization/input/q3dinputhandler.cpp b/src/datavisualization/input/q3dinputhandler.cpp
index 1a197418..f0044096 100644
--- a/src/datavisualization/input/q3dinputhandler.cpp
+++ b/src/datavisualization/input/q3dinputhandler.cpp
@@ -18,7 +18,6 @@
#include "datavisualizationglobal_p.h"
#include "q3dinputhandler_p.h"
-#include "q3dcamera_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -37,7 +36,7 @@ const float rotationSpeed = 100.0f;
* \class Q3DInputHandler
* \inmodule QtDataVisualization
* \brief Basic wheel mouse based input handler.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* Q3DInputHandler is the basic input handler for wheel mouse type of input devices.
*
@@ -88,19 +87,18 @@ Q3DInputHandler::~Q3DInputHandler()
*/
void Q3DInputHandler::mousePressEvent(QMouseEvent *event, const QPoint &mousePos)
{
-#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+#if defined(Q_OS_IOS)
Q_UNUSED(event);
Q_UNUSED(mousePos);
#else
if (Qt::LeftButton == event->button()) {
if (scene()->isSlicingActive()) {
- if (scene()->isPointInPrimarySubView(mousePos)) {
+ if (scene()->isPointInPrimarySubView(mousePos))
setInputView(InputViewOnPrimary);
- } else if (scene()->isPointInSecondarySubView(mousePos)) {
+ else if (scene()->isPointInSecondarySubView(mousePos))
setInputView(InputViewOnSecondary);
- } else {
+ else
setInputView(InputViewNone);
- }
} else {
// update mouse positions to prevent jumping when releasing or repressing a button
setInputPosition(mousePos);
@@ -128,7 +126,7 @@ void Q3DInputHandler::mousePressEvent(QMouseEvent *event, const QPoint &mousePos
void Q3DInputHandler::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos)
{
Q_UNUSED(event);
-#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+#if defined(Q_OS_IOS)
Q_UNUSED(mousePos);
#else
if (QAbstract3DInputHandlerPrivate::InputStateRotating == d_ptr->m_inputState) {
@@ -147,7 +145,7 @@ void Q3DInputHandler::mouseReleaseEvent(QMouseEvent *event, const QPoint &mouseP
void Q3DInputHandler::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos)
{
Q_UNUSED(event);
-#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+#if defined(Q_OS_IOS)
Q_UNUSED(mousePos);
#else
if (QAbstract3DInputHandlerPrivate::InputStateRotating == d_ptr->m_inputState) {
diff --git a/src/datavisualization/input/qabstract3dinputhandler.cpp b/src/datavisualization/input/qabstract3dinputhandler.cpp
index 9e1e314c..5109631f 100644
--- a/src/datavisualization/input/qabstract3dinputhandler.cpp
+++ b/src/datavisualization/input/qabstract3dinputhandler.cpp
@@ -17,7 +17,6 @@
****************************************************************************/
#include "qabstract3dinputhandler_p.h"
-#include "q3dscene.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -25,7 +24,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class QAbstract3DInputHandler
* \inmodule QtDataVisualization
* \brief The base class for implementations of input handlers.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QAbstract3DInputHandler is the base class that is subclassed by different input handling implementations
* that take input events and translate those to camera and light movements. Input handlers also translate
@@ -56,7 +55,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* This type is uncreatable.
*
- * For AbstractInputHandler3D enums, see \l QAbstract3DInputHandler::InputView
+ * For AbstractInputHandler3D enums, see \l{QAbstract3DInputHandler::InputView}.
*/
/*!
@@ -231,7 +230,8 @@ QAbstract3DInputHandlerPrivate::QAbstract3DInputHandlerPrivate(QAbstract3DInputH
m_previousInputPos(QPoint(0,0)),
m_inputView(QAbstract3DInputHandler::InputViewNone),
m_inputPosition(QPoint(0,0)),
- m_scene(0)
+ m_scene(0),
+ m_isDefaultHandler(false)
{
}
diff --git a/src/datavisualization/input/qabstract3dinputhandler_p.h b/src/datavisualization/input/qabstract3dinputhandler_p.h
index fa5a2315..b4b2eda2 100644
--- a/src/datavisualization/input/qabstract3dinputhandler_p.h
+++ b/src/datavisualization/input/qabstract3dinputhandler_p.h
@@ -55,9 +55,6 @@ public:
int m_prevDistance;
QPoint m_previousInputPos;
- GLfloat m_defaultXRotation;
- GLfloat m_defaultYRotation;
-
private:
QAbstract3DInputHandler::InputView m_inputView;
QPoint m_inputPosition;
diff --git a/src/datavisualization/input/qtouch3dinputhandler.cpp b/src/datavisualization/input/qtouch3dinputhandler.cpp
index d40fbf5a..30f31d4a 100644
--- a/src/datavisualization/input/qtouch3dinputhandler.cpp
+++ b/src/datavisualization/input/qtouch3dinputhandler.cpp
@@ -17,7 +17,6 @@
****************************************************************************/
#include "qtouch3dinputhandler_p.h"
-#include "q3dcamera_p.h"
#include <QtCore/QTimer>
#include <QtCore/qmath.h>
@@ -39,7 +38,7 @@ const int maxZoomLevel = 500;
* \class QTouch3DInputHandler
* \inmodule QtDataVisualization
* \brief Basic touch display based input handler.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* QTouch3DInputHandler is the basic input handler for touch screen devices.
*
diff --git a/src/datavisualization/theme/q3dtheme.cpp b/src/datavisualization/theme/q3dtheme.cpp
index 83da96f8..eaed3c41 100644
--- a/src/datavisualization/theme/q3dtheme.cpp
+++ b/src/datavisualization/theme/q3dtheme.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
* \class Q3DTheme
* \inmodule QtDataVisualization
* \brief Q3DTheme class provides a visual style for graphs.
- * \since Qt Data Visualization 1.0
+ * \since QtDataVisualization 1.0
*
* Q3DTheme is used to specify visual properties that affect the whole graph. There are several
* built-in themes that can be used directly, or be modified freely. User can also create a theme
@@ -236,7 +236,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
*
* \snippet doc_src_q3dtheme.cpp 6
*
- * For Theme3D enums, see \l Q3DTheme::ColorStyle and \l Q3DTheme::Theme
+ * For Theme3D enums, see \l Q3DTheme::ColorStyle and \l{Q3DTheme::Theme}.
*/
/*!
diff --git a/src/datavisualization/utils/abstractobjecthelper_p.h b/src/datavisualization/utils/abstractobjecthelper_p.h
index 3220b37d..c1618909 100644
--- a/src/datavisualization/utils/abstractobjecthelper_p.h
+++ b/src/datavisualization/utils/abstractobjecthelper_p.h
@@ -30,7 +30,6 @@
#define ABSTRACTOBJECTHELPER_H
#include "datavisualizationglobal_p.h"
-#include <QtGui/QOpenGLFunctions>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/camerahelper_p.h b/src/datavisualization/utils/camerahelper_p.h
index f410ceb5..89dd48f4 100644
--- a/src/datavisualization/utils/camerahelper_p.h
+++ b/src/datavisualization/utils/camerahelper_p.h
@@ -33,9 +33,7 @@
#include "q3dcamera.h"
class QMatrix4x4;
-class QVector3D;
class QPoint;
-class QPointF;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/objecthelper.cpp b/src/datavisualization/utils/objecthelper.cpp
index 97695193..a66e0f7e 100644
--- a/src/datavisualization/utils/objecthelper.cpp
+++ b/src/datavisualization/utils/objecthelper.cpp
@@ -19,7 +19,6 @@
#include "meshloader_p.h"
#include "vertexindexer_p.h"
#include "objecthelper_p.h"
-#include "abstractobjecthelper_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -27,15 +26,87 @@ ObjectHelper::ObjectHelper(const QString &objectFile)
: m_objectFile(objectFile)
{
m_indicesType = GL_UNSIGNED_SHORT;
+ load();
}
+struct ObjectHelperRef {
+ int refCount;
+ ObjectHelper *obj;
+};
+
+// The "Abstract3DRenderer *" key identifies the renderer
+static QHash<const Abstract3DRenderer *, QHash<QString, ObjectHelperRef *> *> cacheTable;
+
ObjectHelper::~ObjectHelper()
{
}
-void ObjectHelper::setObjectFile(const QString &objectFile)
+void ObjectHelper::resetObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj,
+ const QString &meshFile)
+{
+ Q_ASSERT(cacheId);
+
+ if (obj) {
+ const QString &oldFile = obj->objectFile();
+ if (meshFile == oldFile)
+ return; // same file, do nothing
+ releaseObjectHelper(cacheId, obj);
+ }
+ obj = getObjectHelper(cacheId, meshFile);
+}
+
+void ObjectHelper::releaseObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj)
+{
+ Q_ASSERT(cacheId);
+
+ if (obj) {
+ QHash<QString, ObjectHelperRef *> *objectTable = cacheTable.value(cacheId, 0);
+ if (objectTable) {
+ // Delete object if last reference is released
+ ObjectHelperRef *objRef = objectTable->value(obj->m_objectFile, 0);
+ if (objRef) {
+ objRef->refCount--;
+ if (objRef->refCount <= 0) {
+ objectTable->remove(obj->m_objectFile);
+ delete objRef->obj;
+ delete objRef;
+ }
+ }
+ if (objectTable->isEmpty()) {
+ // Remove the entire cache if last object was removed
+ cacheTable.remove(cacheId);
+ delete objectTable;
+ }
+ } else {
+ // Just delete the object if unknown cache
+ delete obj;
+ }
+ obj = 0;
+ }
+}
+
+ObjectHelper *ObjectHelper::getObjectHelper(const Abstract3DRenderer *cacheId,
+ const QString &objectFile)
{
- m_objectFile = objectFile;
+ if (objectFile.isEmpty())
+ return 0;
+
+ QHash<QString, ObjectHelperRef *> *objectTable = cacheTable.value(cacheId, 0);
+ if (!objectTable) {
+ objectTable = new QHash<QString, ObjectHelperRef *>;
+ cacheTable.insert(cacheId, objectTable);
+ }
+
+ // Check if object helper for this mesh already exists
+ ObjectHelperRef *objRef = objectTable->value(objectFile, 0);
+ if (!objRef) {
+ objRef = new ObjectHelperRef;
+ objRef->refCount = 0;
+ objRef->obj = new ObjectHelper(objectFile);
+ objectTable->insert(objectFile, objRef);
+ }
+ objRef->refCount++;
+ return objRef->obj;
}
void ObjectHelper::load()
@@ -47,6 +118,10 @@ void ObjectHelper::load()
glDeleteBuffers(1, &m_uvbuffer);
glDeleteBuffers(1, &m_normalbuffer);
glDeleteBuffers(1, &m_elementbuffer);
+ m_indices.clear();
+ m_indexedVertices.clear();
+ m_indexedUVs.clear();
+ m_indexedNormals.clear();
}
QVector<QVector3D> vertices;
QVector<QVector2D> uvs;
@@ -56,36 +131,32 @@ void ObjectHelper::load()
qFatal("loading failed");
// Index vertices
- QVector<unsigned short> indices;
- QVector<QVector3D> indexed_vertices;
- QVector<QVector2D> indexed_uvs;
- QVector<QVector3D> indexed_normals;
- VertexIndexer::indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs,
- indexed_normals);
+ VertexIndexer::indexVBO(vertices, uvs, normals, m_indices, m_indexedVertices, m_indexedUVs,
+ m_indexedNormals);
- m_indexCount = indices.size();
+ m_indexCount = m_indices.size();
glGenBuffers(1, &m_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
- glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(QVector3D),
- &indexed_vertices.at(0),
+ glBufferData(GL_ARRAY_BUFFER, m_indexedVertices.size() * sizeof(QVector3D),
+ &m_indexedVertices.at(0),
GL_STATIC_DRAW);
glGenBuffers(1, &m_normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
- glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(QVector3D),
- &indexed_normals.at(0),
+ glBufferData(GL_ARRAY_BUFFER, m_indexedNormals.size() * sizeof(QVector3D),
+ &m_indexedNormals.at(0),
GL_STATIC_DRAW);
glGenBuffers(1, &m_uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
- glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(QVector2D),
- &indexed_uvs.at(0), GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, m_indexedUVs.size() * sizeof(QVector2D),
+ &m_indexedUVs.at(0), GL_STATIC_DRAW);
glGenBuffers(1, &m_elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short),
- &indices.at(0), GL_STATIC_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(unsigned short),
+ &m_indices.at(0), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
diff --git a/src/datavisualization/utils/objecthelper_p.h b/src/datavisualization/utils/objecthelper_p.h
index 0260dd05..c84f53bd 100644
--- a/src/datavisualization/utils/objecthelper_p.h
+++ b/src/datavisualization/utils/objecthelper_p.h
@@ -31,22 +31,38 @@
#include "datavisualizationglobal_p.h"
#include "abstractobjecthelper_p.h"
-#include <QtGui/QOpenGLFunctions>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+class Abstract3DRenderer;
+
class ObjectHelper : public AbstractObjectHelper
{
+private:
+ ObjectHelper(const QString &objectFile);
public:
- ObjectHelper(const QString &objectFile = QString());
~ObjectHelper();
- void setObjectFile(const QString &objectFile);
+ static void resetObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj,
+ const QString &meshFile);
+ static void releaseObjectHelper(const Abstract3DRenderer *cacheId, ObjectHelper *&obj);
+ inline const QString &objectFile() { return m_objectFile; }
- void load();
+ inline const QVector<unsigned short> &indices() const { return m_indices; }
+ inline const QVector<QVector3D> &indexedvertices() const { return m_indexedVertices; }
+ inline const QVector<QVector2D> &indexedUVs() const { return m_indexedUVs; }
+ inline const QVector<QVector3D> &indexedNormals() const { return m_indexedNormals; }
private:
+ static ObjectHelper *getObjectHelper(const Abstract3DRenderer *cacheId,
+ const QString &objectFile);
+ void load();
+
QString m_objectFile;
+ QVector<unsigned short> m_indices;
+ QVector<QVector3D> m_indexedVertices;
+ QVector<QVector2D> m_indexedUVs;
+ QVector<QVector3D> m_indexedNormals;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/scatterobjectbufferhelper.cpp b/src/datavisualization/utils/scatterobjectbufferhelper.cpp
new file mode 100644
index 00000000..123588f1
--- /dev/null
+++ b/src/datavisualization/utils/scatterobjectbufferhelper.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "scatterobjectbufferhelper_p.h"
+#include "objecthelper_p.h"
+#include <QtGui/QVector2D>
+#include <QtGui/QMatrix4x4>
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+const GLfloat itemScaler = 3.0f;
+
+ScatterObjectBufferHelper::ScatterObjectBufferHelper()
+{
+ m_indicesType = GL_UNSIGNED_INT;
+}
+
+ScatterObjectBufferHelper::~ScatterObjectBufferHelper()
+{
+}
+
+void ScatterObjectBufferHelper::fullLoad(ScatterSeriesRenderCache *cache, qreal dotScale)
+{
+ initializeOpenGLFunctions();
+
+ ObjectHelper *dotObj = cache->object();
+ ScatterRenderItemArray &renderArray = cache->renderArray();
+ const uint renderArraySize = renderArray.size();
+ uint itemCount = renderArraySize;
+ QQuaternion seriesRotation(cache->meshRotation());
+
+ if (m_meshDataLoaded) {
+ // Delete old data
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+ }
+
+ // Index vertices
+ const QVector<unsigned short> indices = dotObj->indices();
+ const QVector<QVector3D> indexed_vertices = dotObj->indexedvertices();
+ const QVector<QVector2D> indexed_uvs = dotObj->indexedUVs();
+ const QVector<QVector3D> indexed_normals = dotObj->indexedNormals();
+ int indicesCount = indices.count();
+ int verticeCount = indexed_vertices.count();
+ int uvsCount = indexed_uvs.count();
+ int normalsCount = indexed_normals.count();
+
+ float itemSize = cache->itemSize() / itemScaler;
+ if (itemSize == 0.0f)
+ itemSize = dotScale;
+ QVector3D modelScaler(itemSize, itemSize, itemSize);
+ QMatrix4x4 modelMatrix;
+ if (!seriesRotation.isIdentity()) {
+ QMatrix4x4 matrix;
+ matrix.rotate(seriesRotation);
+ modelMatrix = matrix.transposed();
+ }
+ modelMatrix.scale(modelScaler);
+
+ QVector<QVector3D> scaled_vertices;
+ scaled_vertices.resize(verticeCount);
+ for (int i = 0; i < verticeCount; i++)
+ scaled_vertices[i] = indexed_vertices[i] * modelMatrix;
+
+ QVector<GLuint> buffered_indices;
+ QVector<QVector3D> buffered_vertices;
+ QVector<QVector2D> buffered_uvs;
+ QVector<QVector3D> buffered_normals;
+
+ buffered_indices.resize(indicesCount * renderArraySize);
+ buffered_vertices.resize(verticeCount * renderArraySize);
+ buffered_uvs.resize(uvsCount * renderArraySize);
+ buffered_normals.resize(normalsCount * renderArraySize);
+ uint pos = 0;
+ for (uint i = 0; i < renderArraySize; i++) {
+ ScatterRenderItem &item = renderArray[i];
+ if (!item.isVisible()) {
+ itemCount--;
+ continue;
+ }
+
+ int offset = pos * verticeCount;
+ if (item.rotation().isIdentity()) {
+ for (int j = 0; j < verticeCount; j++)
+ buffered_vertices[j + offset] = scaled_vertices[j] + item.translation();
+ } else {
+ QMatrix4x4 matrix;
+ matrix.rotate(seriesRotation * item.rotation());
+ modelMatrix = matrix.transposed();
+ modelMatrix.scale(modelScaler);
+
+ for (int j = 0; j < verticeCount; j++)
+ buffered_vertices[j + offset] = indexed_vertices[j] * modelMatrix
+ + item.translation();
+ }
+
+ offset = pos * normalsCount;
+ for (int j = 0; j < normalsCount; j++)
+ buffered_normals[j + offset] = indexed_normals[j];
+
+ offset = pos * uvsCount;
+ for (int j = 0; j < uvsCount; j++)
+ buffered_uvs[j + offset] = indexed_uvs[j];
+
+ int offsetVertice = i * verticeCount;
+ offset = pos * indicesCount;
+ for (int j = 0; j < indicesCount; j++) {
+ buffered_indices[j + offset] = GLuint(indices[j] + offsetVertice);
+ }
+
+ pos++;
+ }
+
+ m_indexCount = indicesCount * itemCount;
+
+ glGenBuffers(1, &m_vertexbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, verticeCount * itemCount * sizeof(QVector3D),
+ &buffered_vertices.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_normalbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
+ glBufferData(GL_ARRAY_BUFFER, normalsCount * itemCount * sizeof(QVector3D),
+ &buffered_normals.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_uvbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
+ glBufferData(GL_ARRAY_BUFFER, uvsCount * itemCount * sizeof(QVector2D),
+ &buffered_uvs.at(0), GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_elementbuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesCount * itemCount * sizeof(GLint),
+ &buffered_indices.at(0), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+void ScatterObjectBufferHelper::update(ScatterSeriesRenderCache *cache, qreal dotScale)
+{
+ initializeOpenGLFunctions();
+
+ ObjectHelper *dotObj = cache->object();
+ ScatterRenderItemArray &renderArray = cache->renderArray();
+ const int renderArraySize = renderArray.size();
+ QQuaternion seriesRotation(cache->meshRotation());
+
+ // Index vertices
+ const QVector<QVector3D> indexed_vertices = dotObj->indexedvertices();
+ int verticeCount = indexed_vertices.count();
+
+ float itemSize = cache->itemSize() / itemScaler;
+ if (itemSize == 0.0f)
+ itemSize = dotScale;
+ QVector3D modelScaler(itemSize, itemSize, itemSize);
+ QMatrix4x4 modelMatrix;
+ if (!seriesRotation.isIdentity()) {
+ QMatrix4x4 matrix;
+ matrix.rotate(seriesRotation);
+ modelMatrix = matrix.transposed();
+ }
+ modelMatrix.scale(modelScaler);
+
+ QVector<QVector3D> scaled_vertices;
+ scaled_vertices.resize(verticeCount);
+ for (int i = 0; i < verticeCount; i++)
+ scaled_vertices[i] = indexed_vertices[i] * modelMatrix;
+
+ QVector<QVector3D> buffered_vertices;
+
+ buffered_vertices.resize(verticeCount * renderArraySize);
+ for (int i = 0; i < renderArraySize; i++) {
+ ScatterRenderItem &item = renderArray[i];
+ if (!item.isVisible())
+ continue;
+
+ const int offset = i * verticeCount;
+ if (item.rotation().isIdentity()) {
+ for (int j = 0; j < verticeCount; j++)
+ buffered_vertices[j + offset] = scaled_vertices[j] + item.translation();
+ } else {
+ QMatrix4x4 matrix;
+ matrix.rotate(seriesRotation * item.rotation());
+ modelMatrix = matrix.transposed();
+ modelMatrix.scale(modelScaler);
+
+ for (int j = 0; j < verticeCount; j++)
+ buffered_vertices[j + offset] = indexed_vertices[j] * modelMatrix
+ + item.translation();
+ }
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, buffered_vertices.size() * sizeof(QVector3D),
+ &buffered_vertices.at(0),
+ GL_DYNAMIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/scatterobjectbufferhelper_p.h b/src/datavisualization/utils/scatterobjectbufferhelper_p.h
new file mode 100644
index 00000000..952c3d7d
--- /dev/null
+++ b/src/datavisualization/utils/scatterobjectbufferhelper_p.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SCATTEROBJECTBUFFERHELPER_P_H
+#define SCATTEROBJECTBUFFERHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstractobjecthelper_p.h"
+#include "scatterseriesrendercache_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class ScatterObjectBufferHelper : public AbstractObjectHelper
+{
+public:
+ ScatterObjectBufferHelper();
+ ~ScatterObjectBufferHelper();
+
+ void fullLoad(ScatterSeriesRenderCache *cache, qreal dotScale);
+ void update(ScatterSeriesRenderCache *cache, qreal dotScale);
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/utils/scatterpointbufferhelper.cpp b/src/datavisualization/utils/scatterpointbufferhelper.cpp
new file mode 100644
index 00000000..0f290aeb
--- /dev/null
+++ b/src/datavisualization/utils/scatterpointbufferhelper.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "scatterpointbufferhelper_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+const GLfloat itemScaler = 3.0f;
+const QVector3D hiddenPos(-1000.0f, -1000.0f, -1000.0f);
+
+ScatterPointBufferHelper::ScatterPointBufferHelper()
+ : m_pointbuffer(0),
+ m_oldRemoveIndex(0),
+ m_oldRemove(false)
+{
+ m_indicesType = GL_UNSIGNED_INT;
+}
+
+ScatterPointBufferHelper::~ScatterPointBufferHelper()
+{
+ if (QOpenGLContext::currentContext())
+ glDeleteBuffers(1, &m_pointbuffer);
+}
+
+GLuint ScatterPointBufferHelper::pointBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_pointbuffer;
+}
+
+void ScatterPointBufferHelper::pushPoint(uint pointIndex)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, m_pointbuffer);
+
+ if (m_oldRemove && m_oldRemoveIndex < pointIndex) {
+ glBufferSubData(GL_ARRAY_BUFFER, m_oldRemoveIndex * sizeof(QVector3D),
+ sizeof(QVector3D), &m_bufferedPoints.at(m_oldRemoveIndex));
+ }
+
+ glBufferSubData(GL_ARRAY_BUFFER, pointIndex * sizeof(QVector3D),
+ sizeof(QVector3D),
+ &hiddenPos);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ m_oldRemoveIndex = pointIndex;
+ m_oldRemove = true;
+}
+
+void ScatterPointBufferHelper::popPoint()
+{
+ if (m_oldRemove) {
+ glBindBuffer(GL_ARRAY_BUFFER, m_pointbuffer);
+ glBufferSubData(GL_ARRAY_BUFFER, m_oldRemoveIndex * sizeof(QVector3D),
+ sizeof(QVector3D), &m_bufferedPoints.at(m_oldRemoveIndex));
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ m_oldRemoveIndex = 0;
+ m_oldRemove = false;
+}
+
+void ScatterPointBufferHelper::load(ScatterSeriesRenderCache *cache)
+{
+ initializeOpenGLFunctions();
+
+ ScatterRenderItemArray &renderArray = cache->renderArray();
+ const int renderArraySize = renderArray.size();
+
+ if (m_meshDataLoaded) {
+ // Delete old data
+ glDeleteBuffers(1, &m_pointbuffer);
+ m_bufferedPoints.clear();
+ }
+
+ m_bufferedPoints.resize(renderArraySize);
+ for (int i = 0; i < renderArraySize; i++) {
+ ScatterRenderItem &item = renderArray[i];
+ if (!item.isVisible())
+ m_bufferedPoints[i] = hiddenPos;
+ else
+ m_bufferedPoints[i] = item.translation();
+ }
+
+ m_indexCount = renderArraySize;
+
+ glGenBuffers(1, &m_pointbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_pointbuffer);
+ glBufferData(GL_ARRAY_BUFFER, m_bufferedPoints.size() * sizeof(QVector3D),
+ &m_bufferedPoints.at(0),
+ GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/scatterpointbufferhelper_p.h b/src/datavisualization/utils/scatterpointbufferhelper_p.h
new file mode 100644
index 00000000..b3adcfa8
--- /dev/null
+++ b/src/datavisualization/utils/scatterpointbufferhelper_p.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtDataVisualization API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SCATTERPOINTBUFFERHELPER_P_H
+#define SCATTERPOINTBUFFERHELPER_P_H
+
+#include "datavisualizationglobal_p.h"
+#include "abstractobjecthelper_p.h"
+#include "scatterseriesrendercache_p.h"
+
+QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+
+class ScatterPointBufferHelper : public AbstractObjectHelper
+{
+public:
+ ScatterPointBufferHelper();
+ ~ScatterPointBufferHelper();
+
+ GLuint pointBuf();
+
+ void pushPoint(uint pointIndex);
+ void popPoint();
+ void load(ScatterSeriesRenderCache *cache);
+
+public:
+ GLuint m_pointbuffer;
+
+private:
+ QVector<QVector3D> m_bufferedPoints;
+ uint m_oldRemoveIndex;
+ bool m_oldRemove;
+};
+
+QT_END_NAMESPACE_DATAVISUALIZATION
+
+#endif
diff --git a/src/datavisualization/utils/shaderhelper_p.h b/src/datavisualization/utils/shaderhelper_p.h
index ced27572..fdef0dff 100644
--- a/src/datavisualization/utils/shaderhelper_p.h
+++ b/src/datavisualization/utils/shaderhelper_p.h
@@ -30,7 +30,6 @@
#define SHADERHELPER_P_H
#include "datavisualizationglobal_p.h"
-#include <QtGui/QOpenGLFunctions>
class QOpenGLShaderProgram;
diff --git a/src/datavisualization/utils/surfaceobject.cpp b/src/datavisualization/utils/surfaceobject.cpp
index 9bcdfee2..d999ba90 100644
--- a/src/datavisualization/utils/surfaceobject.cpp
+++ b/src/datavisualization/utils/surfaceobject.cpp
@@ -17,17 +17,21 @@
****************************************************************************/
#include "surfaceobject_p.h"
-#include "abstractobjecthelper_p.h"
+#include "surface3drenderer_p.h"
#include <QtGui/QVector2D>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-SurfaceObject::SurfaceObject()
+SurfaceObject::SurfaceObject(Surface3DRenderer *renderer)
: m_surfaceType(Undefined),
m_columns(0),
m_rows(0),
- m_gridIndexCount(0)
+ m_gridIndexCount(0),
+ m_axisCacheX(renderer->m_axisCacheX),
+ m_axisCacheY(renderer->m_axisCacheY),
+ m_axisCacheZ(renderer->m_axisCacheZ)
+
{
m_indicesType = GL_UNSIGNED_INT;
initializeOpenGLFunctions();
@@ -45,16 +49,11 @@ SurfaceObject::~SurfaceObject()
}
void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space,
- GLfloat yRange, GLfloat yMin, bool changeGeometry)
+ bool changeGeometry, bool flipXZ)
{
m_columns = space.width();
m_rows = space.height();
int totalSize = m_rows * m_columns;
- GLfloat xMin = dataArray.at(0)->at(0).x();
- GLfloat zMin = dataArray.at(0)->at(0).z();
- GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
- GLfloat yNormalizer = yRange / 2.0f;
- GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
GLfloat uvX = 1.0f / GLfloat(m_columns - 1);
GLfloat uvY = 1.0f / GLfloat(m_rows - 1);
@@ -68,21 +67,31 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR
if (changeGeometry)
uvs.resize(totalSize);
int totalIndex = 0;
+
+ AxisRenderCache &xCache = flipXZ ? m_axisCacheZ : m_axisCacheX;
+ AxisRenderCache &zCache = flipXZ ? m_axisCacheX : m_axisCacheZ;
+
for (int i = 0; i < m_rows; i++) {
const QSurfaceDataRow &p = *dataArray.at(i);
for (int j = 0; j < m_columns; j++) {
const QSurfaceDataItem &data = p.at(j);
- float normalizedX = ((data.x() - xMin) / xNormalizer);
- float normalizedY = ((data.y() - yMin) / yNormalizer);
- float normalizedZ = ((data.z() - zMin) / zNormalizer);
- m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f,
- normalizedZ + 1.0f);
+ float normalizedX = xCache.positionAt(data.x());
+ float normalizedY = m_axisCacheY.positionAt(data.y());
+ float normalizedZ = zCache.positionAt(data.z());
+ m_vertices[totalIndex] = QVector3D(normalizedX, normalizedY, normalizedZ);
if (changeGeometry)
uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY);
totalIndex++;
}
}
+ if (flipXZ) {
+ for (int i = 0; i < m_vertices.size(); i++) {
+ m_vertices[i].setX(-m_vertices.at(i).x());
+ m_vertices[i].setZ(-m_vertices.at(i).z());
+ }
+ }
+
// Create normals
int rowLimit = m_rows - 1;
int colLimit = m_columns - 1;
@@ -92,25 +101,30 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR
m_normals.resize(totalSize);
totalIndex = 0;
+ const bool flipNormal = checkFlipNormal(dataArray);
for (int row = 0; row < rowColLimit; row += m_columns) {
for (int j = 0; j < colLimit; j++) {
m_normals[totalIndex++] = normal(m_vertices.at(row + j),
m_vertices.at(row + j + 1),
- m_vertices.at(row + m_columns + j));
+ m_vertices.at(row + m_columns + j),
+ flipNormal);
}
int p = row + colLimit;
m_normals[totalIndex++] = normal(m_vertices.at(p),
m_vertices.at(p + m_columns),
- m_vertices.at(p - 1));
+ m_vertices.at(p - 1),
+ flipNormal);
}
for (int j = rowColLimit; j < totalLimit; j++) {
m_normals[totalIndex++] = normal(m_vertices.at(j),
m_vertices.at(j - m_columns),
- m_vertices.at(j + 1));
+ m_vertices.at(j + 1),
+ flipNormal);
}
m_normals[totalIndex++] = normal(m_vertices.at(totalLimit),
m_vertices.at(totalLimit - 1),
- m_vertices.at(totalLimit - m_columns));
+ m_vertices.at(totalLimit - m_columns),
+ flipNormal);
// Create indices table
if (changeGeometry)
@@ -123,24 +137,18 @@ void SurfaceObject::setUpSmoothData(const QSurfaceDataArray &dataArray, const QR
createBuffers(m_vertices, uvs, m_normals, 0, changeGeometry);
}
-void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowIndex,
- GLfloat yRange, GLfloat yMin)
+void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowIndex)
{
- GLfloat xMin = dataArray.at(0)->at(0).x();
- GLfloat zMin = dataArray.at(0)->at(0).z();
- GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
- GLfloat yNormalizer = yRange / 2.0f;
- GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
-
// Update vertices
int p = rowIndex * m_columns;
const QSurfaceDataRow &dataRow = *dataArray.at(rowIndex);
+
for (int j = 0; j < m_columns; j++) {
const QSurfaceDataItem &data = dataRow.at(j);
- float normalizedX = ((data.x() - xMin) / xNormalizer);
- float normalizedY = ((data.y() - yMin) / yNormalizer);
- float normalizedZ = ((data.z() - zMin) / zNormalizer);
- m_vertices[p++] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f);
+ float normalizedX = m_axisCacheX.positionAt(data.x());
+ float normalizedY = m_axisCacheY.positionAt(data.y());
+ float normalizedZ = m_axisCacheZ.positionAt(data.z());
+ m_vertices[p++] = QVector3D(normalizedX, normalizedY, normalizedZ);
}
// Create normals
@@ -153,18 +161,21 @@ void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowI
if (rowIndex == m_rows - 1)
rowLimit = rowIndex * m_columns; // The rowIndex is top most row, special handling
+ const bool flipNormal = checkFlipNormal(dataArray);
for (int row = totalIndex; row < rowLimit; row += m_columns) {
for (int j = 0; j < colLimit; j++) {
// One right and one up
m_normals[totalIndex++] = normal(m_vertices.at(row + j),
m_vertices.at(row + j + 1),
- m_vertices.at(row + m_columns + j));
+ m_vertices.at(row + m_columns + j),
+ flipNormal);
}
int p = row + colLimit;
// One up and one left
m_normals[totalIndex++] = normal(m_vertices.at(p),
m_vertices.at(p + m_columns),
- m_vertices.at(p - 1));
+ m_vertices.at(p - 1),
+ flipNormal);
}
if (rowIndex == m_rows - 1) {
// Top most line, nothing above, must have different handling.
@@ -173,32 +184,26 @@ void SurfaceObject::updateSmoothRow(const QSurfaceDataArray &dataArray, int rowI
for (int j = rowIndex * m_columns; j < rowLimit; j++) {
m_normals[totalIndex++] = normal(m_vertices.at(j),
m_vertices.at(j - m_columns),
- m_vertices.at(j + 1));
+ m_vertices.at(j + 1),
+ flipNormal);
}
// Top left corner. Take from one left and one down
m_normals[totalIndex++] = normal(m_vertices.at(rowLimit),
m_vertices.at(rowLimit - 1),
- m_vertices.at(rowLimit - m_columns));
+ m_vertices.at(rowLimit - m_columns),
+ flipNormal);
}
}
-void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row,
- int column, GLfloat yRange, GLfloat yMin)
+void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row, int column)
{
- GLfloat xMin = dataArray.at(0)->at(0).x();
- GLfloat zMin = dataArray.at(0)->at(0).z();
- GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
- GLfloat yNormalizer = yRange / 2.0f;
- GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
-
// Update a vertice
const QSurfaceDataItem &data = dataArray.at(row)->at(column);
- float normalizedX = ((data.x() - xMin) / xNormalizer);
- float normalizedY = ((data.y() - yMin) / yNormalizer);
- float normalizedZ = ((data.z() - zMin) / zNormalizer);
- m_vertices[row * m_columns + column] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f,
- normalizedZ + 1.0f);
+ float normalizedX = m_axisCacheX.positionAt(data.x());
+ float normalizedY = m_axisCacheY.positionAt(data.y());
+ float normalizedZ = m_axisCacheZ.positionAt(data.z());
+ m_vertices[row * m_columns + column] = QVector3D(normalizedX, normalizedY, normalizedZ);
// Create normals
int startRow = row;
@@ -210,6 +215,7 @@ void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row
int rightCol = m_columns - 1;
int topRow = m_rows - 1;
+ const bool flipNormal = checkFlipNormal(dataArray);
for (int i = startRow; i <= row; i++) {
for (int j = startCol; j <= column; j++) {
int p = i * m_columns + j;
@@ -218,12 +224,14 @@ void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row
// One right and one up
m_normals[p] = normal(m_vertices.at(p),
m_vertices.at(p + 1),
- m_vertices.at(p + m_columns));
+ m_vertices.at(p + m_columns),
+ flipNormal);
} else {
// Last item, nothing on the right. One up and one left
m_normals[p] = normal(m_vertices.at(p),
m_vertices.at(p + m_columns),
- m_vertices.at(p - 1));
+ m_vertices.at(p - 1),
+ flipNormal);
}
} else {
// Top most line, nothing above, must have different handling.
@@ -231,12 +239,14 @@ void SurfaceObject::updateSmoothItem(const QSurfaceDataArray &dataArray, int row
// Take from one down and one right. Read till second-to-last
m_normals[p] = normal(m_vertices.at(p),
m_vertices.at(p - m_columns),
- m_vertices.at(p + 1));
+ m_vertices.at(p + 1),
+ flipNormal);
} else {
// Top left corner. Take from one left and one down
m_normals[p] = normal(m_vertices.at(p),
m_vertices.at(p - 1),
- m_vertices.at(p - m_columns));
+ m_vertices.at(p - m_columns),
+ flipNormal);
}
}
}
@@ -321,16 +331,11 @@ void SurfaceObject::createSmoothGridlineIndices(int x, int y, int endX, int endY
}
void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &space,
- GLfloat yRange, GLfloat yMin, bool changeGeometry)
+ bool changeGeometry, bool flipXZ)
{
m_columns = space.width();
m_rows = space.height();
int totalSize = m_rows * m_columns * 2;
- GLfloat xMin = dataArray.at(0)->at(0).x();
- GLfloat zMin = dataArray.at(0)->at(0).z();
- GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
- GLfloat yNormalizer = yRange / 2.0f;
- GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
GLfloat uvX = 1.0f / GLfloat(m_columns - 1);
GLfloat uvY = 1.0f / GLfloat(m_rows - 1);
@@ -350,15 +355,17 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s
int doubleColumns = m_columns * 2 - 2;
int rowColLimit = rowLimit * doubleColumns;
+ AxisRenderCache &xCache = flipXZ ? m_axisCacheZ : m_axisCacheX;
+ AxisRenderCache &zCache = flipXZ ? m_axisCacheX : m_axisCacheZ;
+
for (int i = 0; i < m_rows; i++) {
const QSurfaceDataRow &row = *dataArray.at(i);
for (int j = 0; j < m_columns; j++) {
const QSurfaceDataItem &data = row.at(j);
- float normalizedX = ((data.x() - xMin) / xNormalizer);
- float normalizedY = ((data.y() - yMin) / yNormalizer);
- float normalizedZ = ((data.z() - zMin) / zNormalizer);
- m_vertices[totalIndex] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f,
- normalizedZ + 1.0f);
+ float normalizedX = xCache.positionAt(data.x());
+ float normalizedY = m_axisCacheY.positionAt(data.y());
+ float normalizedZ = zCache.positionAt(data.z());
+ m_vertices[totalIndex] = QVector3D(normalizedX, normalizedY, normalizedZ);
if (changeGeometry)
uvs[totalIndex] = QVector2D(GLfloat(j) * uvX, GLfloat(i) * uvY);
@@ -373,6 +380,13 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s
}
}
+ if (flipXZ) {
+ for (int i = 0; i < m_vertices.size(); i++) {
+ m_vertices[i].setX(-m_vertices.at(i).x());
+ m_vertices[i].setZ(-m_vertices.at(i).z());
+ }
+ }
+
// Create normals & indices table
GLint *indices = 0;
int p = 0;
@@ -384,6 +398,7 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s
}
totalIndex = 0;
+ const bool flipNormal = checkFlipNormal(dataArray);
for (int row = 0, upperRow = doubleColumns;
row < rowColLimit;
row += doubleColumns, upperRow += doubleColumns) {
@@ -391,12 +406,14 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s
// Normal for the left triangle
m_normals[totalIndex++] = normal(m_vertices.at(row + j),
m_vertices.at(row + j + 1),
- m_vertices.at(upperRow + j));
+ m_vertices.at(upperRow + j),
+ flipNormal);
// Normal for the right triangle
m_normals[totalIndex++] = normal(m_vertices.at(row + j + 1),
m_vertices.at(upperRow + j + 1),
- m_vertices.at(upperRow + j));
+ m_vertices.at(upperRow + j),
+ flipNormal);
if (changeGeometry) {
// Left triangle
@@ -421,26 +438,20 @@ void SurfaceObject::setUpData(const QSurfaceDataArray &dataArray, const QRect &s
delete[] indices;
}
-void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex,
- GLfloat yRange, GLfloat yMin)
+void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex)
{
- GLfloat xMin = dataArray.at(0)->at(0).x();
- GLfloat zMin = dataArray.at(0)->at(0).z();
- GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
- GLfloat yNormalizer = yRange / 2.0f;
- GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
-
int colLimit = m_columns - 1;
int doubleColumns = m_columns * 2 - 2;
int p = rowIndex * doubleColumns;
const QSurfaceDataRow &dataRow = *dataArray.at(rowIndex);
+
for (int j = 0; j < m_columns; j++) {
const QSurfaceDataItem &data = dataRow.at(j);
- float normalizedX = ((data.x() - xMin) / xNormalizer);
- float normalizedY = ((data.y() - yMin) / yNormalizer);
- float normalizedZ = ((data.z() - zMin) / zNormalizer);
- m_vertices[p++] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f);
+ float normalizedX = m_axisCacheX.positionAt(data.x());
+ float normalizedY = m_axisCacheY.positionAt(data.y());
+ float normalizedZ = m_axisCacheZ.positionAt(data.z());
+ m_vertices[p++] = QVector3D(normalizedX, normalizedY, normalizedZ);
if (j > 0 && j < colLimit) {
m_vertices[p] = m_vertices[p - 1];
@@ -455,6 +466,7 @@ void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowI
int rowLimit = (rowIndex + 1) * doubleColumns;
if (rowIndex == m_rows - 1)
rowLimit = rowIndex * doubleColumns; //Topmost row, no normals
+ const bool flipNormal = checkFlipNormal(dataArray);
for (int row = p, upperRow = p + doubleColumns;
row < rowLimit;
row += doubleColumns, upperRow += doubleColumns) {
@@ -462,35 +474,30 @@ void SurfaceObject::updateCoarseRow(const QSurfaceDataArray &dataArray, int rowI
// Normal for the left triangle
m_normals[p++] = normal(m_vertices.at(row + j),
m_vertices.at(row + j + 1),
- m_vertices.at(upperRow + j));
+ m_vertices.at(upperRow + j),
+ flipNormal);
// Normal for the right triangle
m_normals[p++] = normal(m_vertices.at(row + j + 1),
m_vertices.at(upperRow + j + 1),
- m_vertices.at(upperRow + j));
+ m_vertices.at(upperRow + j),
+ flipNormal);
}
}
}
-void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row,
- int column, GLfloat yRange, GLfloat yMin)
+void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row, int column)
{
- GLfloat xMin = dataArray.at(0)->at(0).x();
- GLfloat zMin = dataArray.at(0)->at(0).z();
- GLfloat xNormalizer = (dataArray.at(0)->last().x() - xMin) / 2.0f;
- GLfloat yNormalizer = yRange / 2.0f;
- GLfloat zNormalizer = (dataArray.last()->at(0).z() - zMin) / -2.0f;
-
int colLimit = m_columns - 1;
int doubleColumns = m_columns * 2 - 2;
// Update a vertice
int p = row * doubleColumns + column * 2 - (column > 0);
const QSurfaceDataItem &data = dataArray.at(row)->at(column);
- float normalizedX = ((data.x() - xMin) / xNormalizer);
- float normalizedY = ((data.y() - yMin) / yNormalizer);
- float normalizedZ = ((data.z() - zMin) / zNormalizer);
- m_vertices[p] = QVector3D(normalizedX - 1.0f, normalizedY - 1.0f, normalizedZ + 1.0f);
+ float normalizedX = m_axisCacheX.positionAt(data.x());
+ float normalizedY = m_axisCacheY.positionAt(data.y());
+ float normalizedZ = m_axisCacheZ.positionAt(data.z());
+ m_vertices[p] = QVector3D(normalizedX, normalizedY, normalizedZ);
p++;
if (column > 0 && column < colLimit)
@@ -508,19 +515,22 @@ void SurfaceObject::updateCoarseItem(const QSurfaceDataArray &dataArray, int row
if (column == m_columns - 1)
column--;
+ const bool flipNormal = checkFlipNormal(dataArray);
for (int i = startRow; i <= row; i++) {
for (int j = startCol; j <= column; j++) {
p = i * doubleColumns + j * 2;
// Normal for the left triangle
m_normals[p] = normal(m_vertices.at(p),
m_vertices.at(p + 1),
- m_vertices.at(p + doubleColumns));
+ m_vertices.at(p + doubleColumns),
+ flipNormal);
p++;
// Normal for the right triangle
m_normals[p] = normal(m_vertices.at(p),
m_vertices.at(p + doubleColumns),
- m_vertices.at(p + doubleColumns - 1));
+ m_vertices.at(p + doubleColumns - 1),
+ flipNormal);
}
}
}
@@ -656,6 +666,13 @@ void SurfaceObject::createBuffers(const QVector<QVector3D> &vertices, const QVec
m_meshDataLoaded = true;
}
+bool SurfaceObject::checkFlipNormal(const QSurfaceDataArray &array)
+{
+ const bool ascendingX = array.at(0)->at(0).x() < array.at(0)->at(array.at(0)->size() - 1).x();
+ const bool ascendingZ = array.at(0)->at(0).z() < array.at(array.size() - 1)->at(0).z();
+ return ascendingX != ascendingZ;
+}
+
GLuint SurfaceObject::gridElementBuf()
{
if (!m_meshDataLoaded)
@@ -686,13 +703,19 @@ void SurfaceObject::clear()
m_gridIndexCount = 0;
m_indexCount = 0;
m_surfaceType = Undefined;
+ m_vertices.clear();
+ m_normals.clear();
}
-QVector3D SurfaceObject::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c)
+QVector3D SurfaceObject::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c,
+ bool flipNormal)
{
QVector3D v1 = b - a;
QVector3D v2 = c - a;
- return QVector3D::crossProduct(v1, v2);
+ QVector3D normal = QVector3D::crossProduct(v1, v2);
+ if (flipNormal)
+ normal *= -1;
+ return normal;
}
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/surfaceobject_p.h b/src/datavisualization/utils/surfaceobject_p.h
index 69cb7e5d..9c18dcb2 100644
--- a/src/datavisualization/utils/surfaceobject_p.h
+++ b/src/datavisualization/utils/surfaceobject_p.h
@@ -37,6 +37,9 @@
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
+class Surface3DRenderer;
+class AxisRenderCache;
+
class SurfaceObject : public AbstractObjectHelper
{
public:
@@ -47,21 +50,17 @@ public:
};
public:
- SurfaceObject();
+ SurfaceObject(Surface3DRenderer *renderer);
~SurfaceObject();
- void setUpData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange,
- GLfloat yMin, bool changeGeometry);
- void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space, GLfloat yRange,
- GLfloat yMin, bool changeGeometry);
- void updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex,
- GLfloat yRange, GLfloat yMin);
- void updateSmoothRow(const QSurfaceDataArray &dataArray, int startRow,
- GLfloat yRange, GLfloat yMin);
- void updateSmoothItem(const QSurfaceDataArray &dataArray, int row,
- int column, GLfloat yRange, GLfloat yMin);
- void updateCoarseItem(const QSurfaceDataArray &dataArray, int row,
- int column, GLfloat yRange, GLfloat yMin);
+ void setUpData(const QSurfaceDataArray &dataArray, const QRect &space,
+ bool changeGeometry, bool flipXZ = false);
+ void setUpSmoothData(const QSurfaceDataArray &dataArray, const QRect &space,
+ bool changeGeometry, bool flipXZ = false);
+ void updateCoarseRow(const QSurfaceDataArray &dataArray, int rowIndex);
+ void updateSmoothRow(const QSurfaceDataArray &dataArray, int startRow);
+ void updateSmoothItem(const QSurfaceDataArray &dataArray, int row, int column);
+ void updateCoarseItem(const QSurfaceDataArray &dataArray, int row, int column);
void createSmoothIndices(int x, int y, int endX, int endY);
void createCoarseIndices(int x, int y, int columns, int rows);
void createSmoothGridlineIndices(int x, int y, int endX, int endY);
@@ -73,10 +72,11 @@ public:
void clear();
private:
- QVector3D normal(const QVector3D &a, const QVector3D &b, const QVector3D &c);
+ QVector3D normal(const QVector3D &a, const QVector3D &b, const QVector3D &c, bool flipNormal);
void createBuffers(const QVector<QVector3D> &vertices, const QVector<QVector2D> &uvs,
const QVector<QVector3D> &normals, const GLint *indices,
bool changeGeometry);
+ bool checkFlipNormal(const QSurfaceDataArray &array);
private:
SurfaceType m_surfaceType;
@@ -86,6 +86,10 @@ private:
GLuint m_gridIndexCount;
QVector<QVector3D> m_vertices;
QVector<QVector3D> m_normals;
+ // Caches are not owned
+ AxisRenderCache &m_axisCacheX;
+ AxisRenderCache &m_axisCacheY;
+ AxisRenderCache &m_axisCacheZ;
};
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/texturehelper.cpp b/src/datavisualization/utils/texturehelper.cpp
index 52c673dc..185d99e4 100644
--- a/src/datavisualization/utils/texturehelper.cpp
+++ b/src/datavisualization/utils/texturehelper.cpp
@@ -108,13 +108,8 @@ GLuint TextureHelper::createSelectionTexture(const QSize &size, GLuint &frameBuf
glBindTexture(GL_TEXTURE_2D, textureid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-#if !defined(QT_OPENGL_ES_2)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
-#else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
- GL_UNSIGNED_BYTE, NULL);
-#endif
glBindTexture(GL_TEXTURE_2D, 0);
// Create render buffer
@@ -198,7 +193,8 @@ GLuint TextureHelper::createDepthTexture(const QSize &size, GLuint textureSize)
#endif
#if !defined(QT_OPENGL_ES_2)
-GLuint TextureHelper::createDepthTextureFrameBuffer(const QSize &size, GLuint &frameBuffer, GLuint textureSize)
+GLuint TextureHelper::createDepthTextureFrameBuffer(const QSize &size, GLuint &frameBuffer,
+ GLuint textureSize)
{
GLuint depthtextureid = createDepthTexture(size, textureSize);
@@ -228,7 +224,8 @@ GLuint TextureHelper::createDepthTextureFrameBuffer(const QSize &size, GLuint &f
#endif
#if !defined(QT_OPENGL_ES_2)
-void TextureHelper::fillDepthTexture(GLuint texture,const QSize &size, GLuint textureSize, GLfloat value)
+void TextureHelper::fillDepthTexture(GLuint texture,const QSize &size, GLuint textureSize,
+ GLfloat value)
{
int nItems = size.width() * textureSize * size.height() * textureSize;
GLfloat *bits = new GLfloat[nItems];
@@ -244,9 +241,12 @@ void TextureHelper::fillDepthTexture(GLuint texture,const QSize &size, GLuint te
}
#endif
-void TextureHelper::deleteTexture(const GLuint *texture)
+void TextureHelper::deleteTexture(GLuint *texture)
{
- glDeleteTextures(1, texture);
+ if (texture && *texture) {
+ glDeleteTextures(1, texture);
+ *texture = 0;
+ }
}
QImage TextureHelper::convertToGLFormat(const QImage &srcImage)
diff --git a/src/datavisualization/utils/texturehelper_p.h b/src/datavisualization/utils/texturehelper_p.h
index ebfaa042..aec137a4 100644
--- a/src/datavisualization/utils/texturehelper_p.h
+++ b/src/datavisualization/utils/texturehelper_p.h
@@ -30,7 +30,6 @@
#define TEXTUREHELPER_P_H
#include "datavisualizationglobal_p.h"
-#include <QtGui/QOpenGLFunctions>
#include <QtGui/QRgb>
#include <QtGui/QLinearGradient>
@@ -56,7 +55,7 @@ class TextureHelper : protected QOpenGLFunctions
GLuint createDepthTextureFrameBuffer(const QSize &size, GLuint &frameBuffer, GLuint textureSize);
void fillDepthTexture(GLuint texture, const QSize &size, GLuint textureSize, GLfloat value);
#endif
- void deleteTexture(const GLuint *texture);
+ void deleteTexture(GLuint *texture);
private:
QImage convertToGLFormat(const QImage &srcImage);
diff --git a/src/datavisualization/utils/utils.cpp b/src/datavisualization/utils/utils.cpp
index e0b1370e..5852bf11 100644
--- a/src/datavisualization/utils/utils.cpp
+++ b/src/datavisualization/utils/utils.cpp
@@ -18,12 +18,7 @@
#include "utils_p.h"
-#include <QtGui/QColor>
#include <QtGui/QPainter>
-#include <QtCore/QPoint>
-#include <QtGui/QImage>
-#include <QtCore/QRegExp>
-#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -38,14 +33,21 @@ GLuint Utils::getNearestPowerOfTwo(GLuint value, GLuint &padding)
return powOfTwoValue;
}
-QVector3D Utils::vectorFromColor(const QColor &color)
+QVector4D Utils::vectorFromColor(const QColor &color)
{
- return QVector3D(color.redF(), color.greenF(), color.blueF());
+ return QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF());
}
QColor Utils::colorFromVector(const QVector3D &colorVector)
{
- return QColor(colorVector.x() * 255.0f, colorVector.y() * 255.0f, colorVector.z() * 255.0f);
+ return QColor(colorVector.x() * 255.0f, colorVector.y() * 255.0f,
+ colorVector.z() * 255.0f, 255.0f);
+}
+
+QColor Utils::colorFromVector(const QVector4D &colorVector)
+{
+ return QColor(colorVector.x() * 255.0f, colorVector.y() * 255.0f,
+ colorVector.z() * 255.0f, colorVector.w() * 255.0f);
}
QImage Utils::printTextToImage(const QFont &font, const QString &text, const QColor &bgrColor,
@@ -126,18 +128,27 @@ QImage Utils::printTextToImage(const QFont &font, const QString &text, const QCo
return image;
}
-QVector3D Utils::getSelection(QPoint mousepos, int height)
+QVector4D Utils::getSelection(QPoint mousepos, int height)
{
// This is the only one that works with OpenGL ES 2.0, so we're forced to use it
// Item count will be limited to 256*256*256
- GLubyte pixel[4] = {255, 255, 255, 0};
+ GLubyte pixel[4] = {255, 255, 255, 255};
glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
(void *)pixel);
- QVector3D selectedColor(pixel[0], pixel[1], pixel[2]);
-
+ QVector4D selectedColor(pixel[0], pixel[1], pixel[2], pixel[3]);
return selectedColor;
}
+QImage Utils::getGradientImage(const QLinearGradient &gradient)
+{
+ QImage image(QSize(1, 101), QImage::Format_RGB32);
+ QPainter pmp(&image);
+ pmp.setBrush(QBrush(gradient));
+ pmp.setPen(Qt::NoPen);
+ pmp.drawRect(0, 0, 1, 101);
+ return image;
+}
+
Utils::ParamType Utils::mapFormatCharToParamType(const QChar &formatChar)
{
ParamType retVal = ParamTypeUnknown;
@@ -177,7 +188,7 @@ Utils::ParamType Utils::findFormatParamType(const QString &format)
return ParamTypeUnknown;
}
-QString Utils::formatLabel(const QByteArray &format, ParamType paramType, float value)
+QString Utils::formatLabel(const QByteArray &format, ParamType paramType, qreal value)
{
switch (paramType) {
case ParamTypeInt:
@@ -218,4 +229,13 @@ float Utils::wrapValue(float value, float min, float max)
return value;
}
+QQuaternion Utils::calculateRotation(const QVector3D &xyzRotations)
+{
+ QQuaternion rotQuatX = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, xyzRotations.x());
+ QQuaternion rotQuatY = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, xyzRotations.y());
+ QQuaternion rotQuatZ = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, xyzRotations.z());
+ QQuaternion totalRotation = rotQuatY * rotQuatZ * rotQuatX;
+ return totalRotation;
+}
+
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualization/utils/utils.pri b/src/datavisualization/utils/utils.pri
index 8ce8794e..30bfb156 100644
--- a/src/datavisualization/utils/utils.pri
+++ b/src/datavisualization/utils/utils.pri
@@ -7,7 +7,9 @@ HEADERS += $$PWD/meshloader_p.h \
$$PWD/utils_p.h \
$$PWD/abstractobjecthelper_p.h \
$$PWD/surfaceobject_p.h \
- $$PWD/qutils.h
+ $$PWD/qutils.h \
+ $$PWD/scatterobjectbufferhelper_p.h \
+ $$PWD/scatterpointbufferhelper_p.h
SOURCES += $$PWD/meshloader.cpp \
$$PWD/vertexindexer.cpp \
@@ -17,4 +19,6 @@ SOURCES += $$PWD/meshloader.cpp \
$$PWD/texturehelper.cpp \
$$PWD/utils.cpp \
$$PWD/abstractobjecthelper.cpp \
- $$PWD/surfaceobject.cpp
+ $$PWD/surfaceobject.cpp \
+ $$PWD/scatterobjectbufferhelper.cpp \
+ $$PWD/scatterpointbufferhelper.cpp
diff --git a/src/datavisualization/utils/utils_p.h b/src/datavisualization/utils/utils_p.h
index 7288419b..d7187c16 100644
--- a/src/datavisualization/utils/utils_p.h
+++ b/src/datavisualization/utils/utils_p.h
@@ -31,12 +31,7 @@
#include "datavisualizationglobal_p.h"
-class QVector3D;
-class QColor;
-class QPainter;
-class QString;
-class QPoint;
-class QImage;
+class QLinearGradient;
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -51,10 +46,9 @@ public:
};
static GLuint getNearestPowerOfTwo(GLuint value, GLuint &padding);
- static QVector3D vectorFromColor(const QColor &color);
+ static QVector4D vectorFromColor(const QColor &color);
static QColor colorFromVector(const QVector3D &colorVector);
- static void printText(QPainter *painter, const QString &text, const QSize &position,
- bool absoluteCoords = true, float rotation = 0.0f, float scale = 1.0f);
+ static QColor colorFromVector(const QVector4D &colorVector);
static QImage printTextToImage(const QFont &font,
const QString &text,
const QColor &bgrColor,
@@ -62,13 +56,15 @@ public:
bool labelBackground,
bool borders = false,
int maxLabelWidth = 0);
- static QVector3D getSelection(QPoint mousepos, int height);
+ static QVector4D getSelection(QPoint mousepos, int height);
+ static QImage getGradientImage(const QLinearGradient &gradient);
static ParamType findFormatParamType(const QString &format);
- static QString formatLabel(const QByteArray &format, ParamType paramType, float value);
+ static QString formatLabel(const QByteArray &format, ParamType paramType, qreal value);
static QString defaultLabelFormat();
static float wrapValue(float value, float min, float max);
+ static QQuaternion calculateRotation(const QVector3D &xyzRotations);
private:
static ParamType mapFormatCharToParamType(const QChar &formatChar);
diff --git a/src/datavisualizationqml2/abstractdeclarative.cpp b/src/datavisualizationqml2/abstractdeclarative.cpp
index 65e7c6c3..a6dee6eb 100644
--- a/src/datavisualizationqml2/abstractdeclarative.cpp
+++ b/src/datavisualizationqml2/abstractdeclarative.cpp
@@ -17,7 +17,6 @@
****************************************************************************/
#include "abstractdeclarative_p.h"
-#include "qvalue3daxis.h"
#include "declarativetheme_p.h"
#include "declarativerendernode_p.h"
@@ -37,18 +36,18 @@ AbstractDeclarative::AbstractDeclarative(QQuickItem *parent) :
m_controller(0),
m_contextWindow(0),
m_renderMode(RenderIndirect),
-#if defined(QT_OPENGL_ES_2)
+ #if defined(QT_OPENGL_ES_2)
m_samples(0),
-#else
+ #else
m_samples(4),
-#endif
+ #endif
m_windowSamples(0),
m_initialisedSize(0, 0),
-#ifdef USE_SHARED_CONTEXT
+ #ifdef USE_SHARED_CONTEXT
m_context(0),
-#else
+ #else
m_stateStore(0),
-#endif
+ #endif
m_qtContext(0),
m_mainThread(QThread::currentThread()),
m_contextThread(0)
@@ -171,7 +170,7 @@ Declarative3DScene* AbstractDeclarative::scene() const
void AbstractDeclarative::setTheme(Q3DTheme *theme)
{
- m_controller->setActiveTheme(theme);
+ m_controller->setActiveTheme(theme, isComponentComplete());
}
Q3DTheme *AbstractDeclarative::theme() const
@@ -211,6 +210,84 @@ bool AbstractDeclarative::shadowsSupported() const
return m_controller->shadowsSupported();
}
+int AbstractDeclarative::addCustomItem(QCustom3DItem *item)
+{
+ return m_controller->addCustomItem(item);
+}
+
+void AbstractDeclarative::removeCustomItems()
+{
+ m_controller->deleteCustomItems();
+}
+
+void AbstractDeclarative::removeCustomItem(QCustom3DItem *item)
+{
+ m_controller->deleteCustomItem(item);
+}
+
+void AbstractDeclarative::removeCustomItemAt(const QVector3D &position)
+{
+ m_controller->deleteCustomItem(position);
+}
+
+void AbstractDeclarative::releaseCustomItem(QCustom3DItem *item)
+{
+ return m_controller->releaseCustomItem(item);
+}
+
+int AbstractDeclarative::selectedLabelIndex() const
+{
+ return m_controller->selectedLabelIndex();
+}
+
+QAbstract3DAxis *AbstractDeclarative::selectedAxis() const
+{
+ return m_controller->selectedAxis();
+}
+
+int AbstractDeclarative::selectedCustomItemIndex() const
+{
+ return m_controller->selectedCustomItemIndex();
+}
+
+QCustom3DItem *AbstractDeclarative::selectedCustomItem() const
+{
+ return m_controller->selectedCustomItem();
+}
+
+QQmlListProperty<QCustom3DItem> AbstractDeclarative::customItemList()
+{
+ return QQmlListProperty<QCustom3DItem>(this, this,
+ &AbstractDeclarative::appendCustomItemFunc,
+ &AbstractDeclarative::countCustomItemFunc,
+ &AbstractDeclarative::atCustomItemFunc,
+ &AbstractDeclarative::clearCustomItemFunc);
+}
+
+void AbstractDeclarative::appendCustomItemFunc(QQmlListProperty<QCustom3DItem> *list,
+ QCustom3DItem *item)
+{
+ AbstractDeclarative *decl = reinterpret_cast<AbstractDeclarative *>(list->data);
+ decl->addCustomItem(item);
+}
+
+int AbstractDeclarative::countCustomItemFunc(QQmlListProperty<QCustom3DItem> *list)
+{
+ return reinterpret_cast<AbstractDeclarative *>(list->data)->m_controller->m_customItems.size();
+}
+
+QCustom3DItem *AbstractDeclarative::atCustomItemFunc(QQmlListProperty<QCustom3DItem> *list,
+ int index)
+{
+ return reinterpret_cast<AbstractDeclarative *>(list->data)->m_controller->m_customItems.at(index);
+}
+
+void AbstractDeclarative::clearCustomItemFunc(QQmlListProperty<QCustom3DItem> *list)
+{
+ AbstractDeclarative *decl = reinterpret_cast<AbstractDeclarative *>(list->data);
+ decl->removeCustomItems();
+}
+
void AbstractDeclarative::setSharedController(Abstract3DController *controller)
{
Q_ASSERT(controller);
@@ -230,6 +307,8 @@ void AbstractDeclarative::setSharedController(Abstract3DController *controller)
&AbstractDeclarative::themeChanged);
QObject::connect(m_controller.data(), &Abstract3DController::selectionModeChanged, this,
&AbstractDeclarative::handleSelectionModeChange);
+ QObject::connect(m_controller.data(), &Abstract3DController::elementSelected, this,
+ &AbstractDeclarative::selectedElementChanged);
QObject::connect(m_controller.data(), &Abstract3DController::axisXChanged, this,
&AbstractDeclarative::handleAxisXChanged);
@@ -237,6 +316,17 @@ void AbstractDeclarative::setSharedController(Abstract3DController *controller)
&AbstractDeclarative::handleAxisYChanged);
QObject::connect(m_controller.data(), &Abstract3DController::axisZChanged, this,
&AbstractDeclarative::handleAxisZChanged);
+
+ QObject::connect(m_controller.data(), &Abstract3DController::measureFpsChanged, this,
+ &AbstractDeclarative::measureFpsChanged);
+ QObject::connect(m_controller.data(), &Abstract3DController::currentFpsChanged, this,
+ &AbstractDeclarative::currentFpsChanged);
+
+ QObject::connect(m_controller.data(), &Abstract3DController::orthoProjectionChanged, this,
+ &AbstractDeclarative::orthoProjectionChanged);
+
+ QObject::connect(m_controller.data(), &Abstract3DController::aspectRatioChanged, this,
+ &AbstractDeclarative::aspectRatioChanged);
}
void AbstractDeclarative::activateOpenGLContext(QQuickWindow *window)
@@ -569,6 +659,58 @@ void AbstractDeclarative::checkWindowList(QQuickWindow *window)
}
}
+void AbstractDeclarative::setMeasureFps(bool enable)
+{
+ m_controller->setMeasureFps(enable);
+}
+
+bool AbstractDeclarative::measureFps() const
+{
+ return m_controller->measureFps();
+}
+
+qreal AbstractDeclarative::currentFps() const
+{
+ return m_controller->currentFps();
+}
+
+void AbstractDeclarative::setOrthoProjection(bool enable)
+{
+ m_controller->setOrthoProjection(enable);
+}
+
+bool AbstractDeclarative::isOrthoProjection() const
+{
+ return m_controller->isOrthoProjection();
+}
+
+AbstractDeclarative::ElementType AbstractDeclarative::selectedElement() const
+{
+ return ElementType(m_controller->selectedElement());
+}
+
+void AbstractDeclarative::setAspectRatio(qreal ratio)
+{
+ m_controller->setAspectRatio(float(ratio));
+}
+
+qreal AbstractDeclarative::aspectRatio() const
+{
+ return m_controller->aspectRatio();
+}
+
+void AbstractDeclarative::setOptimizationHints(OptimizationHints hints)
+{
+ int intmode = int(hints);
+ m_controller->setOptimizationHints(QAbstract3DGraph::OptimizationHints(intmode));
+}
+
+AbstractDeclarative::OptimizationHints AbstractDeclarative::optimizationHints() const
+{
+ int intmode = int(m_controller->optimizationHints());
+ return OptimizationHints(intmode);
+}
+
void AbstractDeclarative::windowDestroyed(QObject *obj)
{
// Remove destroyed window from window lists
diff --git a/src/datavisualizationqml2/abstractdeclarative_p.h b/src/datavisualizationqml2/abstractdeclarative_p.h
index 87b108db..ebe8b49c 100644
--- a/src/datavisualizationqml2/abstractdeclarative_p.h
+++ b/src/datavisualizationqml2/abstractdeclarative_p.h
@@ -31,12 +31,9 @@
#include "datavisualizationglobal_p.h"
#include "abstract3dcontroller_p.h"
-#include "qabstract3dinputhandler.h"
#include "declarativescene_p.h"
-#include <QtCore/QAbstractItemModel>
#include <QtQuick/QQuickItem>
-#include <QtQuick/QQuickWindow>
#include <QtCore/QPointer>
#include <QtCore/QThread>
@@ -57,7 +54,9 @@ class AbstractDeclarative : public QQuickItem
Q_OBJECT
Q_ENUMS(ShadowQuality)
Q_ENUMS(RenderingMode)
+ Q_ENUMS(ElementType)
Q_FLAGS(SelectionFlag SelectionFlags)
+ Q_FLAGS(OptimizationHint OptimizationHints)
Q_PROPERTY(SelectionFlags selectionMode READ selectionMode WRITE setSelectionMode NOTIFY selectionModeChanged)
Q_PROPERTY(ShadowQuality shadowQuality READ shadowQuality WRITE setShadowQuality NOTIFY shadowQualityChanged)
Q_PROPERTY(bool shadowsSupported READ shadowsSupported NOTIFY shadowsSupportedChanged)
@@ -66,6 +65,13 @@ class AbstractDeclarative : public QQuickItem
Q_PROPERTY(QAbstract3DInputHandler* inputHandler READ inputHandler WRITE setInputHandler NOTIFY inputHandlerChanged)
Q_PROPERTY(Q3DTheme* theme READ theme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(RenderingMode renderingMode READ renderingMode WRITE setRenderingMode NOTIFY renderingModeChanged)
+ Q_PROPERTY(bool measureFps READ measureFps WRITE setMeasureFps NOTIFY measureFpsChanged REVISION 1)
+ Q_PROPERTY(qreal currentFps READ currentFps NOTIFY currentFpsChanged REVISION 1)
+ Q_PROPERTY(QQmlListProperty<QCustom3DItem> customItemList READ customItemList REVISION 1)
+ Q_PROPERTY(bool orthoProjection READ isOrthoProjection WRITE setOrthoProjection NOTIFY orthoProjectionChanged REVISION 1)
+ Q_PROPERTY(ElementType selectedElement READ selectedElement NOTIFY selectedElementChanged REVISION 1)
+ Q_PROPERTY(qreal aspectRatio READ aspectRatio WRITE setAspectRatio NOTIFY aspectRatioChanged REVISION 1)
+ Q_PROPERTY(OptimizationHints optimizationHints READ optimizationHints WRITE setOptimizationHints NOTIFY optimizationHintsChanged REVISION 1)
public:
enum SelectionFlag {
@@ -92,12 +98,27 @@ public:
ShadowQualitySoftHigh
};
+ enum ElementType {
+ ElementNone = 0,
+ ElementSeries,
+ ElementAxisXLabel,
+ ElementAxisYLabel,
+ ElementAxisZLabel,
+ ElementCustomItem
+ };
+
enum RenderingMode {
RenderDirectToBackground = 0,
RenderDirectToBackground_NoClear,
RenderIndirect
};
+ enum OptimizationHint {
+ OptimizationDefault = 0,
+ OptimizationStatic = 1
+ };
+ Q_DECLARE_FLAGS(OptimizationHints, OptimizationHint)
+
public:
explicit AbstractDeclarative(QQuickItem *parent = 0);
virtual ~AbstractDeclarative();
@@ -126,7 +147,26 @@ public:
Q_INVOKABLE virtual void clearSelection();
- virtual void geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry);
+ Q_REVISION(1) Q_INVOKABLE virtual int addCustomItem(QCustom3DItem *item);
+ Q_REVISION(1) Q_INVOKABLE virtual void removeCustomItems();
+ Q_REVISION(1) Q_INVOKABLE virtual void removeCustomItem(QCustom3DItem *item);
+ Q_REVISION(1) Q_INVOKABLE virtual void removeCustomItemAt(const QVector3D &position);
+ Q_REVISION(1) Q_INVOKABLE virtual void releaseCustomItem(QCustom3DItem *item);
+
+ Q_REVISION(1) Q_INVOKABLE virtual int selectedLabelIndex() const;
+ Q_REVISION(1) Q_INVOKABLE virtual QAbstract3DAxis *selectedAxis() const;
+
+ Q_REVISION(1) Q_INVOKABLE virtual int selectedCustomItemIndex() const;
+ Q_REVISION(1) Q_INVOKABLE virtual QCustom3DItem *selectedCustomItem() const;
+
+ QQmlListProperty<QCustom3DItem> customItemList();
+ static void appendCustomItemFunc(QQmlListProperty<QCustom3DItem> *list,
+ QCustom3DItem *item);
+ static int countCustomItemFunc(QQmlListProperty<QCustom3DItem> *list);
+ static QCustom3DItem *atCustomItemFunc(QQmlListProperty<QCustom3DItem> *list, int index);
+ static void clearCustomItemFunc(QQmlListProperty<QCustom3DItem> *list);
+
+ virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
void setSharedController(Abstract3DController *controller);
// Used to synch up data model from controller to renderer while main thread is locked
@@ -138,6 +178,21 @@ public:
void checkWindowList(QQuickWindow *window);
+ void setMeasureFps(bool enable);
+ bool measureFps() const;
+ qreal currentFps() const;
+
+ void setOrthoProjection(bool enable);
+ bool isOrthoProjection() const;
+
+ AbstractDeclarative::ElementType selectedElement() const;
+
+ void setAspectRatio(qreal ratio);
+ qreal aspectRatio() const;
+
+ void setOptimizationHints(OptimizationHints hints);
+ OptimizationHints optimizationHints() const;
+
public slots:
virtual void handleAxisXChanged(QAbstract3DAxis *axis) = 0;
virtual void handleAxisYChanged(QAbstract3DAxis *axis) = 0;
@@ -167,6 +222,12 @@ signals:
void inputHandlerChanged(QAbstract3DInputHandler *inputHandler);
void themeChanged(Q3DTheme *theme);
void renderingModeChanged(AbstractDeclarative::RenderingMode mode);
+ Q_REVISION(1) void measureFpsChanged(bool enabled);
+ Q_REVISION(1) void currentFpsChanged(qreal fps);
+ Q_REVISION(1) void selectedElementChanged(QAbstract3DGraph::ElementType type);
+ Q_REVISION(1) void orthoProjectionChanged(bool enabled);
+ Q_REVISION(1) void aspectRatioChanged(qreal ratio);
+ Q_REVISION(1) void optimizationHintsChanged(QAbstract3DGraph::OptimizationHints hints);
private:
QPointer<Abstract3DController> m_controller;
@@ -187,6 +248,7 @@ private:
bool m_runningInDesigner;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractDeclarative::SelectionFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractDeclarative::OptimizationHints)
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp b/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp
index 04e70ecb..09780dc5 100644
--- a/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp
+++ b/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp
@@ -25,8 +25,11 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION
void QtDataVisualizationQml2Plugin::registerTypes(const char *uri)
{
// @uri QtDataVisualization
- qmlRegisterUncreatableType<const QAbstractItemModel>(uri, 1, 0, "AbstractItemModel",
- QLatin1String("Trying to create uncreatable: AbstractItemModel."));
+
+ // QtDataVisualization 1.0
+
+ qmlRegisterUncreatableType<QAbstractItemModel>(uri, 1, 0, "AbstractItemModel",
+ QLatin1String("Trying to create uncreatable: AbstractItemModel."));
qmlRegisterUncreatableType<QAbstract3DAxis>(uri, 1, 0, "AbstractAxis3D",
QLatin1String("Trying to create uncreatable: AbstractAxis."));
qmlRegisterUncreatableType<QAbstractDataProxy>(uri, 1, 0, "AbstractDataProxy",
@@ -40,7 +43,7 @@ void QtDataVisualizationQml2Plugin::registerTypes(const char *uri)
qmlRegisterUncreatableType<AbstractDeclarative>(uri, 1, 0, "AbstractGraph3D",
QLatin1String("Trying to create uncreatable: AbstractGraph3D."));
qmlRegisterUncreatableType<Declarative3DScene>(uri, 1, 0, "Scene3D",
- QLatin1String("Trying to create uncreatable: Scene3D."));
+ QLatin1String("Trying to create uncreatable: Scene3D."));
qmlRegisterUncreatableType<QAbstract3DSeries>(uri, 1, 0, "Abstract3DSeries",
QLatin1String("Trying to create uncreatable: Abstract3DSeries."));
qmlRegisterUncreatableType<QBar3DSeries>(uri, 1, 0, "QBar3DSeries",
@@ -80,6 +83,29 @@ void QtDataVisualizationQml2Plugin::registerTypes(const char *uri)
qmlRegisterType<DeclarativeSurface3DSeries>(uri, 1, 0, "Surface3DSeries");
qRegisterMetaType<QAbstract3DGraph::ShadowQuality>("QAbstract3DGraph::ShadowQuality");
+
+ // QtDataVisualization 1.1
+
+ // New revisions
+ qmlRegisterUncreatableType<QAbstract3DAxis, 1>(uri, 1, 1, "AbstractAxis3D",
+ QLatin1String("Trying to create uncreatable: AbstractAxis."));
+ qmlRegisterUncreatableType<QAbstract3DSeries, 1>(uri, 1, 1, "Abstract3DSeries",
+ QLatin1String("Trying to create uncreatable: Abstract3DSeries."));
+ qmlRegisterUncreatableType<AbstractDeclarative, 1>(uri, 1, 1, "AbstractGraph3D",
+ QLatin1String("Trying to create uncreatable: AbstractGraph3D."));
+ qmlRegisterType<QValue3DAxis, 1>(uri, 1, 1, "ValueAxis3D");
+ qmlRegisterType<QItemModelBarDataProxy, 1>(uri, 1, 1, "ItemModelBarDataProxy");
+ qmlRegisterType<QItemModelSurfaceDataProxy, 1>(uri, 1, 1, "ItemModelSurfaceDataProxy");
+ qmlRegisterType<QItemModelScatterDataProxy, 1>(uri, 1, 1, "ItemModelScatterDataProxy");
+
+ // New types
+ qmlRegisterType<QValue3DAxisFormatter>(uri, 1, 1, "ValueAxis3DFormatter");
+ qmlRegisterType<QLogValue3DAxisFormatter>(uri, 1, 1, "LogValueAxis3DFormatter");
+ qmlRegisterType<QCustom3DItem>(uri, 1, 1, "Custom3DItem");
+ qmlRegisterType<QCustom3DLabel>(uri, 1, 1, "Custom3DLabel");
+
+ // New metatypes
+ qRegisterMetaType<QAbstract3DGraph::ElementType>("QAbstract3DGraph::ElementType");
}
QT_END_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualizationqml2/datavisualizationqml2_plugin.h b/src/datavisualizationqml2/datavisualizationqml2_plugin.h
index e39d6b35..21ef85b8 100644
--- a/src/datavisualizationqml2/datavisualizationqml2_plugin.h
+++ b/src/datavisualizationqml2/datavisualizationqml2_plugin.h
@@ -28,6 +28,8 @@
#include "qitemmodelsurfacedataproxy.h"
#include "qheightmapsurfacedataproxy.h"
#include "qvalue3daxis.h"
+#include "qvalue3daxisformatter.h"
+#include "qlogvalue3daxisformatter.h"
#include "qcategory3daxis.h"
#include "q3dobject.h"
#include "q3dcamera.h"
@@ -43,6 +45,8 @@
#include "qabstract3dinputhandler.h"
#include "declarativecolor_p.h"
#include "declarativescene_p.h"
+#include "qcustom3ditem.h"
+#include "qcustom3dlabel.h"
#include <QtQml/QQmlExtensionPlugin>
@@ -53,11 +57,13 @@ QML_DECLARE_TYPE(DeclarativeBars)
QML_DECLARE_TYPE(DeclarativeScatter)
QML_DECLARE_TYPE(DeclarativeSurface)
-QML_DECLARE_TYPE(const QAbstractItemModel)
+QML_DECLARE_TYPE(QAbstractItemModel)
QML_DECLARE_TYPE(QAbstract3DAxis)
QML_DECLARE_TYPE(QCategory3DAxis)
QML_DECLARE_TYPE(QValue3DAxis)
+QML_DECLARE_TYPE(QValue3DAxisFormatter)
+QML_DECLARE_TYPE(QLogValue3DAxisFormatter)
QML_DECLARE_TYPE(Q3DScene)
QML_DECLARE_TYPE(Declarative3DScene)
@@ -92,6 +98,9 @@ QML_DECLARE_TYPE(DeclarativeTheme3D)
QML_DECLARE_TYPE(QAbstract3DInputHandler)
+QML_DECLARE_TYPE(QCustom3DItem)
+QML_DECLARE_TYPE(QCustom3DLabel)
+
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class QtDataVisualizationQml2Plugin : public QQmlExtensionPlugin
diff --git a/src/datavisualizationqml2/declarativebars.cpp b/src/datavisualizationqml2/declarativebars.cpp
index 4f984c32..9670a7db 100644
--- a/src/datavisualizationqml2/declarativebars.cpp
+++ b/src/datavisualizationqml2/declarativebars.cpp
@@ -17,9 +17,6 @@
****************************************************************************/
#include "declarativebars_p.h"
-#include "qvalue3daxis.h"
-#include "qitemmodelbardataproxy.h"
-#include "declarativescene_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -90,7 +87,8 @@ bool DeclarativeBars::isMultiSeriesUniform() const
void DeclarativeBars::setBarThickness(float thicknessRatio)
{
if (thicknessRatio != barThickness()) {
- m_barsController->setBarSpecs(GLfloat(thicknessRatio), barSpacing(), isBarSpacingRelative());
+ m_barsController->setBarSpecs(GLfloat(thicknessRatio), barSpacing(),
+ isBarSpacingRelative());
emit barThicknessChanged(thicknessRatio);
}
}
diff --git a/src/datavisualizationqml2/declarativebars_p.h b/src/datavisualizationqml2/declarativebars_p.h
index 97f5882a..52690813 100644
--- a/src/datavisualizationqml2/declarativebars_p.h
+++ b/src/datavisualizationqml2/declarativebars_p.h
@@ -32,11 +32,6 @@
#include "datavisualizationglobal_p.h"
#include "abstractdeclarative_p.h"
#include "bars3dcontroller_p.h"
-#include "declarativebars_p.h"
-#include "qvalue3daxis.h"
-#include "qcategory3daxis.h"
-#include "qbardataproxy.h"
-#include "qbar3dseries.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -88,7 +83,6 @@ public:
Q_INVOKABLE void insertSeries(int index, QBar3DSeries *series);
void setPrimarySeries(QBar3DSeries *series);
QBar3DSeries *primarySeries() const;
-
QBar3DSeries *selectedSeries() const;
public slots:
diff --git a/src/datavisualizationqml2/declarativerendernode.cpp b/src/datavisualizationqml2/declarativerendernode.cpp
index 1f6d4b56..e9bb65fd 100644
--- a/src/datavisualizationqml2/declarativerendernode.cpp
+++ b/src/datavisualizationqml2/declarativerendernode.cpp
@@ -17,24 +17,22 @@
****************************************************************************/
#include "declarativerendernode_p.h"
-#include "abstract3dcontroller_p.h"
#include "abstractdeclarative_p.h"
-#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFramebufferObject>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
DeclarativeRenderNode::DeclarativeRenderNode(AbstractDeclarative *declarative)
: QSGGeometryNode(),
- m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
- m_texture(0),
- m_declarative(declarative),
- m_controller(0),
- m_fbo(0),
- m_multisampledFBO(0),
- m_window(0),
- m_samples(0),
- m_dirtyFBO(false)
+ m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4),
+ m_texture(0),
+ m_declarative(declarative),
+ m_controller(0),
+ m_fbo(0),
+ m_multisampledFBO(0),
+ m_window(0),
+ m_samples(0),
+ m_dirtyFBO(false)
{
setMaterial(&m_material);
setOpaqueMaterial(&m_materialO);
@@ -92,8 +90,10 @@ void DeclarativeRenderNode::updateFBO()
QSGGeometry::updateTexturedRectGeometry(&m_geometry,
QRectF(0, 0,
- m_size.width() / m_controller->scene()->devicePixelRatio(),
- m_size.height() / m_controller->scene()->devicePixelRatio()),
+ m_size.width()
+ / m_controller->scene()->devicePixelRatio(),
+ m_size.height()
+ / m_controller->scene()->devicePixelRatio()),
QRectF(0, 1, 1, -1));
delete m_texture;
diff --git a/src/datavisualizationqml2/declarativerendernode_p.h b/src/datavisualizationqml2/declarativerendernode_p.h
index e35791d4..a7ede03a 100644
--- a/src/datavisualizationqml2/declarativerendernode_p.h
+++ b/src/datavisualizationqml2/declarativerendernode_p.h
@@ -33,12 +33,8 @@
#include <QtQuick/QSGGeometryNode>
#include <QtQuick/QSGTextureMaterial>
-#include <QtQuick/QSGOpaqueTextureMaterial>
#include <QtQuick/QQuickWindow>
-class QOpenGLContext;
-class QOpenGLFramebufferObject;
-
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
class Abstract3DController;
diff --git a/src/datavisualizationqml2/declarativescatter.cpp b/src/datavisualizationqml2/declarativescatter.cpp
index dcc52a3d..96af6df6 100644
--- a/src/datavisualizationqml2/declarativescatter.cpp
+++ b/src/datavisualizationqml2/declarativescatter.cpp
@@ -17,8 +17,6 @@
****************************************************************************/
#include "declarativescatter_p.h"
-#include "qitemmodelscatterdataproxy.h"
-#include "declarativescene_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
@@ -79,13 +77,14 @@ QScatter3DSeries *DeclarativeScatter::selectedSeries() const
QQmlListProperty<QScatter3DSeries> DeclarativeScatter::seriesList()
{
return QQmlListProperty<QScatter3DSeries>(this, this,
- &DeclarativeScatter::appendSeriesFunc,
- &DeclarativeScatter::countSeriesFunc,
- &DeclarativeScatter::atSeriesFunc,
- &DeclarativeScatter::clearSeriesFunc);
+ &DeclarativeScatter::appendSeriesFunc,
+ &DeclarativeScatter::countSeriesFunc,
+ &DeclarativeScatter::atSeriesFunc,
+ &DeclarativeScatter::clearSeriesFunc);
}
-void DeclarativeScatter::appendSeriesFunc(QQmlListProperty<QScatter3DSeries> *list, QScatter3DSeries *series)
+void DeclarativeScatter::appendSeriesFunc(QQmlListProperty<QScatter3DSeries> *list,
+ QScatter3DSeries *series)
{
reinterpret_cast<DeclarativeScatter *>(list->data)->addSeries(series);
}
diff --git a/src/datavisualizationqml2/declarativescatter_p.h b/src/datavisualizationqml2/declarativescatter_p.h
index 79b56e02..370750ea 100644
--- a/src/datavisualizationqml2/declarativescatter_p.h
+++ b/src/datavisualizationqml2/declarativescatter_p.h
@@ -32,9 +32,6 @@
#include "datavisualizationglobal_p.h"
#include "abstractdeclarative_p.h"
#include "scatter3dcontroller_p.h"
-#include "declarativescatter_p.h"
-#include "qvalue3daxis.h"
-#include "qscatterdataproxy.h"
#include "qscatter3dseries.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualizationqml2/declarativeseries.cpp b/src/datavisualizationqml2/declarativeseries.cpp
index 21555f45..661f87ba 100644
--- a/src/datavisualizationqml2/declarativeseries.cpp
+++ b/src/datavisualizationqml2/declarativeseries.cpp
@@ -17,14 +17,12 @@
****************************************************************************/
#include "declarativeseries_p.h"
-#include "qbardataproxy.h"
-#include "qscatterdataproxy.h"
-#include "qsurfacedataproxy.h"
#include <QtCore/QMetaMethod>
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
-static void setSeriesGradient(QAbstract3DSeries *series, const ColorGradient &gradient, GradientType type)
+static void setSeriesGradient(QAbstract3DSeries *series, const ColorGradient &gradient,
+ GradientType type)
{
QLinearGradient newGradient;
QGradientStops stops;
@@ -198,7 +196,8 @@ QQmlListProperty<QObject> DeclarativeScatter3DSeries::seriesChildren()
, 0, 0, 0);
}
-void DeclarativeScatter3DSeries::appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element)
+void DeclarativeScatter3DSeries::appendSeriesChildren(QQmlListProperty<QObject> *list,
+ QObject *element)
{
QScatterDataProxy *proxy = qobject_cast<QScatterDataProxy *>(element);
if (proxy)
@@ -293,7 +292,8 @@ QQmlListProperty<QObject> DeclarativeSurface3DSeries::seriesChildren()
, 0, 0, 0);
}
-void DeclarativeSurface3DSeries::appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element)
+void DeclarativeSurface3DSeries::appendSeriesChildren(QQmlListProperty<QObject> *list,
+ QObject *element)
{
QSurfaceDataProxy *proxy = qobject_cast<QSurfaceDataProxy *>(element);
if (proxy)
diff --git a/src/datavisualizationqml2/declarativesurface.cpp b/src/datavisualizationqml2/declarativesurface.cpp
index 78519586..3075d207 100644
--- a/src/datavisualizationqml2/declarativesurface.cpp
+++ b/src/datavisualizationqml2/declarativesurface.cpp
@@ -17,9 +17,6 @@
****************************************************************************/
#include "declarativesurface_p.h"
-#include "qvalue3daxis.h"
-#include "qitemmodelsurfacedataproxy.h"
-#include "declarativescene_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualizationqml2/declarativesurface_p.h b/src/datavisualizationqml2/declarativesurface_p.h
index a4747167..6fe800ba 100644
--- a/src/datavisualizationqml2/declarativesurface_p.h
+++ b/src/datavisualizationqml2/declarativesurface_p.h
@@ -32,9 +32,6 @@
#include "datavisualizationglobal_p.h"
#include "abstractdeclarative_p.h"
#include "surface3dcontroller_p.h"
-#include "declarativesurface_p.h"
-#include "qvalue3daxis.h"
-#include "qsurfacedataproxy.h"
#include "qsurface3dseries.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
diff --git a/src/datavisualizationqml2/declarativetheme.cpp b/src/datavisualizationqml2/declarativetheme.cpp
index 5aec2408..ab10155e 100644
--- a/src/datavisualizationqml2/declarativetheme.cpp
+++ b/src/datavisualizationqml2/declarativetheme.cpp
@@ -36,17 +36,17 @@ DeclarativeTheme3D::~DeclarativeTheme3D()
{
}
-QQmlListProperty<QObject> DeclarativeTheme3D::seriesChildren()
+QQmlListProperty<QObject> DeclarativeTheme3D::themeChildren()
{
- return QQmlListProperty<QObject>(this, this, &DeclarativeTheme3D::appendSeriesChildren,
+ return QQmlListProperty<QObject>(this, this, &DeclarativeTheme3D::appendThemeChildren,
0, 0, 0);
}
-void DeclarativeTheme3D::appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element)
+void DeclarativeTheme3D::appendThemeChildren(QQmlListProperty<QObject> *list, QObject *element)
{
Q_UNUSED(list)
Q_UNUSED(element)
- // Nothing to do, seriesChildren is there only to enable scoping gradient items in Theme3D item.
+ // Nothing to do, themeChildren is there only to enable scoping gradient items in Theme3D item.
}
void DeclarativeTheme3D::handleTypeChange(Theme themeType)
@@ -236,6 +236,10 @@ ColorGradient *DeclarativeTheme3D::convertGradient(const QLinearGradient &gradie
void DeclarativeTheme3D::addColor(DeclarativeColor *color)
{
+ if (!color) {
+ qWarning("Color is invalid, use ThemeColor");
+ return;
+ }
clearDummyColors();
m_colors.append(color);
connect(color, &DeclarativeColor::colorChanged,
@@ -283,6 +287,10 @@ void DeclarativeTheme3D::clearDummyColors()
void DeclarativeTheme3D::addGradient(ColorGradient *gradient)
{
+ if (!gradient) {
+ qWarning("Gradient is invalid, use ColorGradient");
+ return;
+ }
clearDummyGradients();
m_gradients.append(gradient);
connect(gradient, &ColorGradient::updated,
diff --git a/src/datavisualizationqml2/declarativetheme_p.h b/src/datavisualizationqml2/declarativetheme_p.h
index a7f40b1e..89b66f8c 100644
--- a/src/datavisualizationqml2/declarativetheme_p.h
+++ b/src/datavisualizationqml2/declarativetheme_p.h
@@ -42,19 +42,19 @@ class DeclarativeTheme3D : public Q3DTheme, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
- Q_PROPERTY(QQmlListProperty<QObject> seriesChildren READ seriesChildren)
+ Q_PROPERTY(QQmlListProperty<QObject> themeChildren READ themeChildren)
Q_PROPERTY(QQmlListProperty<DeclarativeColor> baseColors READ baseColors)
Q_PROPERTY(QQmlListProperty<ColorGradient> baseGradients READ baseGradients)
Q_PROPERTY(ColorGradient *singleHighlightGradient READ singleHighlightGradient WRITE setSingleHighlightGradient NOTIFY singleHighlightGradientChanged)
Q_PROPERTY(ColorGradient *multiHighlightGradient READ multiHighlightGradient WRITE setMultiHighlightGradient NOTIFY multiHighlightGradientChanged)
- Q_CLASSINFO("DefaultProperty", "seriesChildren")
+ Q_CLASSINFO("DefaultProperty", "themeChildren")
public:
DeclarativeTheme3D(QObject *parent = 0);
virtual ~DeclarativeTheme3D();
- QQmlListProperty<QObject> seriesChildren();
- static void appendSeriesChildren(QQmlListProperty<QObject> *list, QObject *element);
+ QQmlListProperty<QObject> themeChildren();
+ static void appendThemeChildren(QQmlListProperty<QObject> *list, QObject *element);
QQmlListProperty<DeclarativeColor> baseColors();
static void appendBaseColorsFunc(QQmlListProperty<DeclarativeColor> *list,
diff --git a/src/datavisualizationqml2/designer/Bars3DSpecifics.qml b/src/datavisualizationqml2/designer/Bars3DSpecifics.qml
index e52320ac..cb5fb4a0 100644
--- a/src/datavisualizationqml2/designer/Bars3DSpecifics.qml
+++ b/src/datavisualizationqml2/designer/Bars3DSpecifics.qml
@@ -266,6 +266,29 @@ Column {
}
}
}
+ Label {
+ text: qsTr("measureFps")
+ toolTip: qsTr("Measure Frames Per Second")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.measureFps
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("orthoProjection")
+ toolTip: qsTr("Use Orthographic Projection")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.orthoProjection
+ Layout.fillWidth: true
+ }
+ }
+
// Kept for debugging
Label { }
SecondColumnLayout {
diff --git a/src/datavisualizationqml2/designer/Scatter3DSpecifics.qml b/src/datavisualizationqml2/designer/Scatter3DSpecifics.qml
index b9a9ef97..1e2556ec 100644
--- a/src/datavisualizationqml2/designer/Scatter3DSpecifics.qml
+++ b/src/datavisualizationqml2/designer/Scatter3DSpecifics.qml
@@ -84,6 +84,43 @@ Column {
scope: "AbstractGraph3D"
}
}
+ Label {
+ text: qsTr("measureFps")
+ toolTip: qsTr("Measure Frames Per Second")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.measureFps
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("orthoProjection")
+ toolTip: qsTr("Use Orthographic Projection")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.orthoProjection
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("aspectRatio")
+ toolTip: qsTr("Horizontal to Vertical Aspect Ratio")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ SpinBox {
+ backendValue: backendValues.aspectRatio
+ minimumValue: 0.1
+ maximumValue: 10.0
+ stepSize: 0.1
+ decimals: 1
+ Layout.fillWidth: true
+ }
+ }
}
}
}
diff --git a/src/datavisualizationqml2/designer/Surface3DSpecifics.qml b/src/datavisualizationqml2/designer/Surface3DSpecifics.qml
index 74470e4b..65a65d37 100644
--- a/src/datavisualizationqml2/designer/Surface3DSpecifics.qml
+++ b/src/datavisualizationqml2/designer/Surface3DSpecifics.qml
@@ -204,6 +204,44 @@ Column {
}
}
}
+ Label {
+ text: qsTr("measureFps")
+ toolTip: qsTr("Measure Frames Per Second")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.measureFps
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("orthoProjection")
+ toolTip: qsTr("Use Orthographic Projection")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ CheckBox {
+ backendValue: backendValues.orthoProjection
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("aspectRatio")
+ toolTip: qsTr("Horizontal to Vertical Aspect Ratio")
+ Layout.fillWidth: true
+ }
+ SecondColumnLayout {
+ SpinBox {
+ backendValue: backendValues.aspectRatio
+ minimumValue: 0.1
+ maximumValue: 10.0
+ stepSize: 0.1
+ decimals: 1
+ Layout.fillWidth: true
+ }
+ }
+
// Kept for debugging
Label { }
SecondColumnLayout {
diff --git a/src/datavisualizationqml2/enumtostringmap.cpp b/src/datavisualizationqml2/enumtostringmap.cpp
index 249fbae3..b4b04fc2 100644
--- a/src/datavisualizationqml2/enumtostringmap.cpp
+++ b/src/datavisualizationqml2/enumtostringmap.cpp
@@ -15,12 +15,13 @@
** contact form at http://qt.digia.com
**
****************************************************************************/
+
#include "enumtostringmap_p.h"
-#include <QString>
-#include <QDebug>
#ifdef VERBOSE_STATE_STORE
+#include <QDebug>
+
static EnumToStringMap *theInstance = 0;
static unsigned int theInstanceCount = 0;
@@ -367,7 +368,8 @@ EnumToStringMap::EnumToStringMap() :
m_map[GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE] = "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE";
m_map[GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME] = "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME";
m_map[GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL] = "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL";
- m_map[GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE] = "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE";
+ m_map[GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE] =
+ "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE";
m_map[GL_COLOR_ATTACHMENT0] = "COLOR_ATTACHMENT0";
m_map[GL_DEPTH_ATTACHMENT] = "DEPTH_ATTACHMENT";
@@ -375,11 +377,16 @@ EnumToStringMap::EnumToStringMap() :
m_map[GL_FRAMEBUFFER_COMPLETE] = "FRAMEBUFFER_COMPLETE";
m_map[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
- m_map[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+ m_map[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] =
+ "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
m_map[GL_FRAMEBUFFER_UNSUPPORTED] = "FRAMEBUFFER_UNSUPPORTED";
m_map[GL_FRAMEBUFFER_BINDING] = "FRAMEBUFFER_BINDING";
+#if !defined(QT_OPENGL_ES_2)
m_map[GL_RENDERBUFFER_BINDING] = "RENDERBUFFER_BINDING";
+#else
+ m_map[GL_RENDERBUFFER] = "RENDERBUFFER_BINDING";
+#endif
m_map[GL_MAX_RENDERBUFFER_SIZE] = "MAX_RENDERBUFFER_SIZE";
m_map[GL_INVALID_FRAMEBUFFER_OPERATION] = "INVALID_FRAMEBUFFER_OPERATION";
diff --git a/src/datavisualizationqml2/glstatestore.cpp b/src/datavisualizationqml2/glstatestore.cpp
index f053078b..973d5054 100644
--- a/src/datavisualizationqml2/glstatestore.cpp
+++ b/src/datavisualizationqml2/glstatestore.cpp
@@ -15,6 +15,7 @@
** contact form at http://qt.digia.com
**
****************************************************************************/
+
#include "glstatestore_p.h"
#include <QDebug>
#include <QColor>
@@ -50,13 +51,13 @@ GLStateStore::GLStateStore(QOpenGLContext *context, QObject *parent) :
#endif
m_maxVertexAttribs = qMin(maxVertexAttribs, 2); // Datavis only uses 2 attribs max
- m_vertexAttribArrayEnabledStates = new GLint[maxVertexAttribs];
- m_vertexAttribArrayBoundBuffers = new GLint[maxVertexAttribs];
- m_vertexAttribArraySizes = new GLint[maxVertexAttribs];
- m_vertexAttribArrayTypes = new GLint[maxVertexAttribs];
- m_vertexAttribArrayNormalized = new GLint[maxVertexAttribs];
- m_vertexAttribArrayStrides = new GLint[maxVertexAttribs];
- m_vertexAttribArrayOffsets = new GLint[maxVertexAttribs];
+ m_vertexAttribArrayEnabledStates.reset(new GLint[maxVertexAttribs]);
+ m_vertexAttribArrayBoundBuffers.reset(new GLint[maxVertexAttribs]);
+ m_vertexAttribArraySizes.reset(new GLint[maxVertexAttribs]);
+ m_vertexAttribArrayTypes.reset(new GLint[maxVertexAttribs]);
+ m_vertexAttribArrayNormalized.reset(new GLint[maxVertexAttribs]);
+ m_vertexAttribArrayStrides.reset(new GLint[maxVertexAttribs]);
+ m_vertexAttribArrayOffsets.reset(new GLint[maxVertexAttribs]);
initGLDefaultState();
}
@@ -67,8 +68,6 @@ GLStateStore::~GLStateStore()
EnumToStringMap::deleteInstance();
m_map = 0;
#endif
- delete m_vertexAttribArrayEnabledStates;
- delete m_vertexAttribArrayBoundBuffers;
}
void GLStateStore::storeGLState()
@@ -80,8 +79,10 @@ void GLStateStore::storeGLState()
#if !defined(QT_OPENGL_ES_2)
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &m_drawFramebuffer);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &m_readFramebuffer);
-#endif
glGetIntegerv(GL_RENDERBUFFER_BINDING, &m_renderbuffer);
+#else
+ glGetIntegerv(GL_RENDERBUFFER, &m_renderbuffer);
+#endif
glGetFloatv(GL_COLOR_CLEAR_VALUE, m_clearColor);
m_isBlendingEnabled = glIsEnabled(GL_BLEND);
m_isDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST);
@@ -111,11 +112,14 @@ void GLStateStore::storeGLState()
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &m_boundElementArrayBuffer);
for (int i = 0; i < m_maxVertexAttribs;i++) {
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &m_vertexAttribArrayEnabledStates[i]);
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &m_vertexAttribArrayBoundBuffers[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
+ &m_vertexAttribArrayEnabledStates[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ &m_vertexAttribArrayBoundBuffers[i]);
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &m_vertexAttribArraySizes[i]);
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &m_vertexAttribArrayTypes[i]);
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &m_vertexAttribArrayNormalized[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ &m_vertexAttribArrayNormalized[i]);
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &m_vertexAttribArrayStrides[i]);
}
}
@@ -173,8 +177,10 @@ void GLStateStore::printCurrentState(bool in)
#if !defined(QT_OPENGL_ES_2)
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer);
-#endif
glGetIntegerv(GL_RENDERBUFFER_BINDING, &renderbuffer);
+#else
+ glGetIntegerv(GL_RENDERBUFFER, &renderbuffer);
+#endif
glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth);
glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);
@@ -198,11 +204,14 @@ void GLStateStore::printCurrentState(bool in)
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBufferBinding);
for (int i = 0; i < m_maxVertexAttribs;i++) {
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertexAttribArrayEnabledStates[i]);
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &vertexAttribArrayBoundBuffers[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
+ &vertexAttribArrayEnabledStates[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ &vertexAttribArrayBoundBuffers[i]);
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertexAttribArraySizes[i]);
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertexAttribArrayTypes[i]);
- glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vertexAttribArrayNormalized[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ &vertexAttribArrayNormalized[i]);
glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertexAttribArrayStrides[i]);
}
@@ -265,8 +274,10 @@ void GLStateStore::restoreGLState()
#if !defined(QT_OPENGL_ES_2)
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_readFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFramebuffer);
-#endif
glBindRenderbuffer(GL_RENDERBUFFER_BINDING, m_renderbuffer);
+#else
+ glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffer);
+#endif
if (m_isScissorTestEnabled)
glEnable(GL_SCISSOR_TEST);
diff --git a/src/datavisualizationqml2/glstatestore_p.h b/src/datavisualizationqml2/glstatestore_p.h
index 14c46c43..4add606b 100644
--- a/src/datavisualizationqml2/glstatestore_p.h
+++ b/src/datavisualizationqml2/glstatestore_p.h
@@ -29,9 +29,8 @@
#ifndef GLSTATESTORE_P_H
#define GLSTATESTORE_P_H
-#include <QObject>
#include <QtGui/QOpenGLFunctions>
-#include <QtGui/QOpenGLContext>
+#include <QtCore/QScopedArrayPointer>
#include "enumtostringmap_p.h"
class GLStateStore : public QObject, protected QOpenGLFunctions
@@ -66,13 +65,13 @@ public:
GLboolean m_isDepthWriteEnabled;
GLint m_currentProgram;
GLint m_maxVertexAttribs;
- GLint *m_vertexAttribArrayEnabledStates;
- GLint *m_vertexAttribArrayBoundBuffers;
- GLint *m_vertexAttribArraySizes;
- GLint *m_vertexAttribArrayTypes;
- GLint *m_vertexAttribArrayNormalized;
- GLint *m_vertexAttribArrayStrides;
- GLint *m_vertexAttribArrayOffsets;
+ QScopedArrayPointer<GLint> m_vertexAttribArrayEnabledStates;
+ QScopedArrayPointer<GLint> m_vertexAttribArrayBoundBuffers;
+ QScopedArrayPointer<GLint> m_vertexAttribArraySizes;
+ QScopedArrayPointer<GLint> m_vertexAttribArrayTypes;
+ QScopedArrayPointer<GLint> m_vertexAttribArrayNormalized;
+ QScopedArrayPointer<GLint> m_vertexAttribArrayStrides;
+ QScopedArrayPointer<GLint> m_vertexAttribArrayOffsets;
GLint m_activeTexture;
GLint m_texBinding2D;
diff --git a/src/datavisualizationqml2/plugins.qmltypes b/src/datavisualizationqml2/plugins.qmltypes
index 48a30665..99fa53de 100644
--- a/src/datavisualizationqml2/plugins.qmltypes
+++ b/src/datavisualizationqml2/plugins.qmltypes
@@ -4,16 +4,19 @@ import QtQuick.tooling 1.1
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtDataVisualization 1.0'
+// 'qmlplugindump -nonrelocatable QtDataVisualization 1.1'
Module {
Component {
name: "QtDataVisualization::AbstractDeclarative"
defaultProperty: "data"
prototype: "QQuickItem"
- exports: ["QtDataVisualization/AbstractGraph3D 1.0"]
+ exports: [
+ "QtDataVisualization/AbstractGraph3D 1.0",
+ "QtDataVisualization/AbstractGraph3D 1.1"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1]
Enum {
name: "SelectionFlag"
values: {
@@ -57,6 +60,17 @@ Module {
}
}
Enum {
+ name: "ElementType"
+ values: {
+ "ElementNone": 0,
+ "ElementSeries": 1,
+ "ElementAxisXLabel": 2,
+ "ElementAxisYLabel": 3,
+ "ElementAxisZLabel": 4,
+ "ElementCustomItem": 5
+ }
+ }
+ Enum {
name: "RenderingMode"
values: {
"RenderDirectToBackground": 0,
@@ -66,18 +80,35 @@ Module {
}
Property { name: "selectionMode"; type: "SelectionFlags" }
Property { name: "shadowQuality"; type: "ShadowQuality" }
+ Property { name: "shadowsSupported"; type: "bool"; isReadonly: true }
Property { name: "msaaSamples"; type: "int" }
Property { name: "scene"; type: "Declarative3DScene"; isReadonly: true; isPointer: true }
Property { name: "inputHandler"; type: "QAbstract3DInputHandler"; isPointer: true }
Property { name: "theme"; type: "Q3DTheme"; isPointer: true }
Property { name: "renderingMode"; type: "RenderingMode" }
+ Property { name: "measureFps"; revision: 1; type: "bool" }
+ Property { name: "currentFps"; revision: 1; type: "double"; isReadonly: true }
+ Property {
+ name: "customItemList"
+ revision: 1
+ type: "QCustom3DItem"
+ isList: true
+ isReadonly: true
+ }
+ Property { name: "orthoProjection"; revision: 1; type: "bool" }
+ Property { name: "selectedElement"; revision: 1; type: "ElementType"; isReadonly: true }
+ Property { name: "aspectRatio"; revision: 1; type: "double" }
Signal {
name: "selectionModeChanged"
- Parameter { name: "mode"; type: "SelectionFlags" }
+ Parameter { name: "mode"; type: "AbstractDeclarative::SelectionFlags" }
}
Signal {
name: "shadowQualityChanged"
- Parameter { name: "quality"; type: "ShadowQuality" }
+ Parameter { name: "quality"; type: "AbstractDeclarative::ShadowQuality" }
+ }
+ Signal {
+ name: "shadowsSupportedChanged"
+ Parameter { name: "supported"; type: "bool" }
}
Signal {
name: "msaaSamplesChanged"
@@ -97,7 +128,32 @@ Module {
}
Signal {
name: "renderingModeChanged"
- Parameter { name: "mode"; type: "RenderingMode" }
+ Parameter { name: "mode"; type: "AbstractDeclarative::RenderingMode" }
+ }
+ Signal {
+ name: "measureFpsChanged"
+ revision: 1
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ Signal {
+ name: "currentFpsChanged"
+ revision: 1
+ Parameter { name: "fps"; type: "double" }
+ }
+ Signal {
+ name: "selectedElementChanged"
+ revision: 1
+ Parameter { name: "type"; type: "QAbstract3DGraph::ElementType" }
+ }
+ Signal {
+ name: "orthoProjectionChanged"
+ revision: 1
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ Signal {
+ name: "aspectRatioChanged"
+ revision: 1
+ Parameter { name: "ratio"; type: "double" }
}
Method {
name: "handleAxisXChanged"
@@ -116,6 +172,32 @@ Module {
Parameter { name: "obj"; type: "QObject"; isPointer: true }
}
Method { name: "clearSelection" }
+ Method {
+ name: "addCustomItem"
+ revision: 1
+ type: "int"
+ Parameter { name: "item"; type: "QCustom3DItem"; isPointer: true }
+ }
+ Method { name: "removeCustomItems"; revision: 1 }
+ Method {
+ name: "removeCustomItem"
+ revision: 1
+ Parameter { name: "item"; type: "QCustom3DItem"; isPointer: true }
+ }
+ Method {
+ name: "removeCustomItemAt"
+ revision: 1
+ Parameter { name: "position"; type: "QVector3D" }
+ }
+ Method {
+ name: "releaseCustomItem"
+ revision: 1
+ Parameter { name: "item"; type: "QCustom3DItem"; isPointer: true }
+ }
+ Method { name: "selectedLabelIndex"; revision: 1; type: "int" }
+ Method { name: "selectedAxis"; revision: 1; type: "QAbstract3DAxis*" }
+ Method { name: "selectedCustomItemIndex"; revision: 1; type: "int" }
+ Method { name: "selectedCustomItem"; revision: 1; type: "QCustom3DItem*" }
}
Component {
name: "QtDataVisualization::ColorGradient"
@@ -437,11 +519,11 @@ Module {
}
Component {
name: "QtDataVisualization::DeclarativeTheme3D"
- defaultProperty: "seriesChildren"
+ defaultProperty: "themeChildren"
prototype: "QtDataVisualization::Q3DTheme"
exports: ["QtDataVisualization/Theme3D 1.0"]
exportMetaObjectRevisions: [0]
- Property { name: "seriesChildren"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "themeChildren"; type: "QObject"; isList: true; isReadonly: true }
Property { name: "baseColors"; type: "DeclarativeColor"; isList: true; isReadonly: true }
Property { name: "baseGradients"; type: "ColorGradient"; isList: true; isReadonly: true }
Property { name: "singleHighlightGradient"; type: "ColorGradient"; isPointer: true }
@@ -492,7 +574,7 @@ Module {
}
Property { name: "xRotation"; type: "double" }
Property { name: "yRotation"; type: "double" }
- Property { name: "zoomLevel"; type: "int" }
+ Property { name: "zoomLevel"; type: "double" }
Property { name: "cameraPreset"; type: "CameraPreset" }
Property { name: "wrapXRotation"; type: "bool" }
Property { name: "wrapYRotation"; type: "bool" }
@@ -506,11 +588,11 @@ Module {
}
Signal {
name: "zoomLevelChanged"
- Parameter { name: "zoomLevel"; type: "int" }
+ Parameter { name: "zoomLevel"; type: "double" }
}
Signal {
name: "cameraPresetChanged"
- Parameter { name: "preset"; type: "CameraPreset" }
+ Parameter { name: "preset"; type: "Q3DCamera::CameraPreset" }
}
Signal {
name: "wrapXRotationChanged"
@@ -642,7 +724,7 @@ Module {
Property { name: "colorStyle"; type: "ColorStyle" }
Signal {
name: "typeChanged"
- Parameter { name: "themeType"; type: "Theme" }
+ Parameter { name: "themeType"; type: "Q3DTheme::Theme" }
}
Signal {
name: "baseColorsChanged"
@@ -726,15 +808,18 @@ Module {
}
Signal {
name: "colorStyleChanged"
- Parameter { name: "style"; type: "ColorStyle" }
+ Parameter { name: "style"; type: "Q3DTheme::ColorStyle" }
}
}
Component {
name: "QtDataVisualization::QAbstract3DAxis"
prototype: "QObject"
- exports: ["QtDataVisualization/AbstractAxis3D 1.0"]
+ exports: [
+ "QtDataVisualization/AbstractAxis3D 1.0",
+ "QtDataVisualization/AbstractAxis3D 1.1"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1]
Enum {
name: "AxisOrientation"
values: {
@@ -759,13 +844,14 @@ Module {
Property { name: "min"; type: "double" }
Property { name: "max"; type: "double" }
Property { name: "autoAdjustRange"; type: "bool" }
+ Property { name: "labelAutoRotation"; revision: 1; type: "double" }
Signal {
name: "titleChanged"
Parameter { name: "newTitle"; type: "string" }
}
Signal {
name: "orientationChanged"
- Parameter { name: "orientation"; type: "AxisOrientation" }
+ Parameter { name: "orientation"; type: "QAbstract3DAxis::AxisOrientation" }
}
Signal {
name: "minChanged"
@@ -784,6 +870,11 @@ Module {
name: "autoAdjustRangeChanged"
Parameter { name: "autoAdjust"; type: "bool" }
}
+ Signal {
+ name: "labelAutoRotationChanged"
+ revision: 1
+ Parameter { name: "angle"; type: "double" }
+ }
}
Component {
name: "QtDataVisualization::QAbstract3DInputHandler"
@@ -808,7 +899,7 @@ Module {
}
Signal {
name: "inputViewChanged"
- Parameter { name: "view"; type: "InputView" }
+ Parameter { name: "view"; type: "QAbstract3DInputHandler::InputView" }
}
Signal {
name: "sceneChanged"
@@ -818,9 +909,12 @@ Module {
Component {
name: "QtDataVisualization::QAbstract3DSeries"
prototype: "QObject"
- exports: ["QtDataVisualization/Abstract3DSeries 1.0"]
+ exports: [
+ "QtDataVisualization/Abstract3DSeries 1.0",
+ "QtDataVisualization/Abstract3DSeries 1.1"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1]
Enum {
name: "SeriesType"
values: {
@@ -862,6 +956,8 @@ Module {
Property { name: "multiHighlightColor"; type: "QColor" }
Property { name: "multiHighlightGradient"; type: "QLinearGradient" }
Property { name: "name"; type: "string" }
+ Property { name: "itemLabel"; revision: 1; type: "string"; isReadonly: true }
+ Property { name: "itemLabelVisible"; revision: 1; type: "bool" }
Signal {
name: "itemLabelFormatChanged"
Parameter { name: "format"; type: "string" }
@@ -872,7 +968,7 @@ Module {
}
Signal {
name: "meshChanged"
- Parameter { name: "mesh"; type: "Mesh" }
+ Parameter { name: "mesh"; type: "QAbstract3DSeries::Mesh" }
}
Signal {
name: "meshSmoothChanged"
@@ -918,6 +1014,16 @@ Module {
name: "nameChanged"
Parameter { name: "name"; type: "string" }
}
+ Signal {
+ name: "itemLabelChanged"
+ revision: 1
+ Parameter { name: "label"; type: "string" }
+ }
+ Signal {
+ name: "itemLabelVisibilityChanged"
+ revision: 1
+ Parameter { name: "visible"; type: "bool" }
+ }
Method {
name: "setMeshAxisAndAngle"
Parameter { name: "axis"; type: "QVector3D" }
@@ -1016,6 +1122,57 @@ Module {
Property { name: "labels"; type: "QStringList" }
}
Component {
+ name: "QtDataVisualization::QCustom3DItem"
+ prototype: "QObject"
+ exports: ["QtDataVisualization/Custom3DItem 1.1"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "meshFile"; type: "string" }
+ Property { name: "textureFile"; type: "string" }
+ Property { name: "position"; type: "QVector3D" }
+ Property { name: "positionAbsolute"; type: "bool" }
+ Property { name: "scaling"; type: "QVector3D" }
+ Property { name: "rotation"; type: "QQuaternion" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "shadowCasting"; type: "bool" }
+ Signal {
+ name: "meshFileChanged"
+ Parameter { name: "meshFile"; type: "string" }
+ }
+ Signal {
+ name: "textureFileChanged"
+ Parameter { name: "textureFile"; type: "string" }
+ }
+ Signal {
+ name: "positionChanged"
+ Parameter { name: "position"; type: "QVector3D" }
+ }
+ Signal {
+ name: "positionAbsoluteChanged"
+ Parameter { name: "positionAbsolute"; type: "bool" }
+ }
+ Signal {
+ name: "scalingChanged"
+ Parameter { name: "scaling"; type: "QVector3D" }
+ }
+ Signal {
+ name: "rotationChanged"
+ Parameter { name: "rotation"; type: "QQuaternion" }
+ }
+ Signal {
+ name: "visibleChanged"
+ Parameter { name: "visible"; type: "bool" }
+ }
+ Signal {
+ name: "shadowCastingChanged"
+ Parameter { name: "shadowCasting"; type: "bool" }
+ }
+ Method {
+ name: "setRotationAxisAndAngle"
+ Parameter { name: "axis"; type: "QVector3D" }
+ Parameter { name: "angle"; type: "double" }
+ }
+ }
+ Component {
name: "QtDataVisualization::QHeightMapSurfaceDataProxy"
prototype: "QtDataVisualization::QSurfaceDataProxy"
exports: ["QtDataVisualization/HeightMapSurfaceDataProxy 1.0"]
@@ -1054,8 +1211,20 @@ Module {
Component {
name: "QtDataVisualization::QItemModelBarDataProxy"
prototype: "QtDataVisualization::QBarDataProxy"
- exports: ["QtDataVisualization/ItemModelBarDataProxy 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtDataVisualization/ItemModelBarDataProxy 1.0",
+ "QtDataVisualization/ItemModelBarDataProxy 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
+ Enum {
+ name: "MultiMatchBehavior"
+ values: {
+ "MMBFirst": 0,
+ "MMBLast": 1,
+ "MMBAverage": 2,
+ "MMBCumulative": 3
+ }
+ }
Property { name: "itemModel"; type: "const QAbstractItemModel"; isPointer: true }
Property { name: "rowRole"; type: "string" }
Property { name: "columnRole"; type: "string" }
@@ -1066,6 +1235,15 @@ Module {
Property { name: "useModelCategories"; type: "bool" }
Property { name: "autoRowCategories"; type: "bool" }
Property { name: "autoColumnCategories"; type: "bool" }
+ Property { name: "rowRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "columnRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "valueRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "rotationRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "rowRoleReplace"; revision: 1; type: "string" }
+ Property { name: "columnRoleReplace"; revision: 1; type: "string" }
+ Property { name: "valueRoleReplace"; revision: 1; type: "string" }
+ Property { name: "rotationRoleReplace"; revision: 1; type: "string" }
+ Property { name: "multiMatchBehavior"; revision: 1; type: "MultiMatchBehavior" }
Signal {
name: "itemModelChanged"
Parameter { name: "itemModel"; type: "const QAbstractItemModel"; isPointer: true }
@@ -1098,6 +1276,51 @@ Module {
name: "autoColumnCategoriesChanged"
Parameter { name: "enable"; type: "bool" }
}
+ Signal {
+ name: "rowRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "columnRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "valueRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "rotationRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "rowRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "columnRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "valueRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "rotationRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "multiMatchBehaviorChanged"
+ revision: 1
+ Parameter { name: "behavior"; type: "MultiMatchBehavior" }
+ }
Method {
name: "rowCategoryIndex"
type: "int"
@@ -1112,13 +1335,24 @@ Module {
Component {
name: "QtDataVisualization::QItemModelScatterDataProxy"
prototype: "QtDataVisualization::QScatterDataProxy"
- exports: ["QtDataVisualization/ItemModelScatterDataProxy 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtDataVisualization/ItemModelScatterDataProxy 1.0",
+ "QtDataVisualization/ItemModelScatterDataProxy 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "itemModel"; type: "const QAbstractItemModel"; isPointer: true }
Property { name: "xPosRole"; type: "string" }
Property { name: "yPosRole"; type: "string" }
Property { name: "zPosRole"; type: "string" }
Property { name: "rotationRole"; type: "string" }
+ Property { name: "xPosRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "yPosRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "zPosRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "rotationRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "xPosRoleReplace"; revision: 1; type: "string" }
+ Property { name: "yPosRoleReplace"; revision: 1; type: "string" }
+ Property { name: "zPosRoleReplace"; revision: 1; type: "string" }
+ Property { name: "rotationRoleReplace"; revision: 1; type: "string" }
Signal {
name: "itemModelChanged"
Parameter { name: "itemModel"; type: "const QAbstractItemModel"; isPointer: true }
@@ -1139,12 +1373,64 @@ Module {
name: "rotationRoleChanged"
Parameter { name: "role"; type: "string" }
}
+ Signal {
+ name: "xPosRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "yPosRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "zPosRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "rotationRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "rotationRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "xPosRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "yPosRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "zPosRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
}
Component {
name: "QtDataVisualization::QItemModelSurfaceDataProxy"
prototype: "QtDataVisualization::QSurfaceDataProxy"
- exports: ["QtDataVisualization/ItemModelSurfaceDataProxy 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtDataVisualization/ItemModelSurfaceDataProxy 1.0",
+ "QtDataVisualization/ItemModelSurfaceDataProxy 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
+ Enum {
+ name: "MultiMatchBehavior"
+ values: {
+ "MMBFirst": 0,
+ "MMBLast": 1,
+ "MMBAverage": 2,
+ "MMBCumulativeY": 3
+ }
+ }
Property { name: "itemModel"; type: "const QAbstractItemModel"; isPointer: true }
Property { name: "rowRole"; type: "string" }
Property { name: "columnRole"; type: "string" }
@@ -1156,6 +1442,17 @@ Module {
Property { name: "useModelCategories"; type: "bool" }
Property { name: "autoRowCategories"; type: "bool" }
Property { name: "autoColumnCategories"; type: "bool" }
+ Property { name: "rowRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "columnRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "xPosRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "yPosRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "zPosRolePattern"; revision: 1; type: "QRegExp" }
+ Property { name: "rowRoleReplace"; revision: 1; type: "string" }
+ Property { name: "columnRoleReplace"; revision: 1; type: "string" }
+ Property { name: "xPosRoleReplace"; revision: 1; type: "string" }
+ Property { name: "yPosRoleReplace"; revision: 1; type: "string" }
+ Property { name: "zPosRoleReplace"; revision: 1; type: "string" }
+ Property { name: "multiMatchBehavior"; revision: 1; type: "MultiMatchBehavior" }
Signal {
name: "itemModelChanged"
Parameter { name: "itemModel"; type: "const QAbstractItemModel"; isPointer: true }
@@ -1192,6 +1489,61 @@ Module {
name: "autoColumnCategoriesChanged"
Parameter { name: "enable"; type: "bool" }
}
+ Signal {
+ name: "rowRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "columnRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "xPosRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "yPosRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "zPosRolePatternChanged"
+ revision: 1
+ Parameter { name: "pattern"; type: "QRegExp" }
+ }
+ Signal {
+ name: "rowRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "columnRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "xPosRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "yPosRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "zPosRoleReplaceChanged"
+ revision: 1
+ Parameter { name: "replace"; type: "string" }
+ }
+ Signal {
+ name: "multiMatchBehaviorChanged"
+ revision: 1
+ Parameter { name: "behavior"; type: "MultiMatchBehavior" }
+ }
Method {
name: "rowCategoryIndex"
type: "int"
@@ -1204,6 +1556,27 @@ Module {
}
}
Component {
+ name: "QtDataVisualization::QLogValue3DAxisFormatter"
+ prototype: "QtDataVisualization::QValue3DAxisFormatter"
+ exports: ["QtDataVisualization/LogValueAxis3DFormatter 1.1"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "base"; type: "double" }
+ Property { name: "autoSubGrid"; type: "bool" }
+ Property { name: "showEdgeLabels"; type: "bool" }
+ Signal {
+ name: "baseChanged"
+ Parameter { name: "base"; type: "double" }
+ }
+ Signal {
+ name: "autoSubGridChanged"
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ Signal {
+ name: "showEdgeLabelsChanged"
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ }
+ Component {
name: "QtDataVisualization::QScatter3DSeries"
prototype: "QtDataVisualization::QAbstract3DSeries"
exports: ["QtDataVisualization/QScatter3DSeries 1.0"]
@@ -1366,11 +1739,16 @@ Module {
Component {
name: "QtDataVisualization::QValue3DAxis"
prototype: "QtDataVisualization::QAbstract3DAxis"
- exports: ["QtDataVisualization/ValueAxis3D 1.0"]
- exportMetaObjectRevisions: [0]
+ exports: [
+ "QtDataVisualization/ValueAxis3D 1.0",
+ "QtDataVisualization/ValueAxis3D 1.1"
+ ]
+ exportMetaObjectRevisions: [0, 1]
Property { name: "segmentCount"; type: "int" }
Property { name: "subSegmentCount"; type: "int" }
Property { name: "labelFormat"; type: "string" }
+ Property { name: "formatter"; revision: 1; type: "QValue3DAxisFormatter"; isPointer: true }
+ Property { name: "reversed"; revision: 1; type: "bool" }
Signal {
name: "segmentCountChanged"
Parameter { name: "count"; type: "int" }
@@ -1383,5 +1761,21 @@ Module {
name: "labelFormatChanged"
Parameter { name: "format"; type: "string" }
}
+ Signal {
+ name: "formatterChanged"
+ revision: 1
+ Parameter { name: "formatter"; type: "QValue3DAxisFormatter"; isPointer: true }
+ }
+ Signal {
+ name: "reversedChanged"
+ revision: 1
+ Parameter { name: "enable"; type: "bool" }
+ }
+ }
+ Component {
+ name: "QtDataVisualization::QValue3DAxisFormatter"
+ prototype: "QObject"
+ exports: ["QtDataVisualization/ValueAxis3DFormatter 1.1"]
+ exportMetaObjectRevisions: [0]
}
}