diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-09-04 15:00:28 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-09-08 09:21:04 +0300 |
commit | bb30ea555c71604de9a2bc5096fa35c9532b26bd (patch) | |
tree | 42825d3574e07136e4028f90abb1f719e2c8b6f6 | |
parent | 18413de96ea907ea5c7defdcb40248fdfbaa4de7 (diff) |
Add possibility to scale custom items according to data ranges
Proper behavior of volume objects that are shown only partially
will be added in a separate patch later.
Change-Id: I1fcd98faa6c4a7d09e3fef1645ed9816ff54654f
Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
-rw-r--r-- | examples/datavisualization/volumetric/volumetric.cpp | 30 | ||||
-rw-r--r-- | src/datavisualization/data/customrenderitem.cpp | 4 | ||||
-rw-r--r-- | src/datavisualization/data/customrenderitem_p.h | 15 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3ditem.cpp | 85 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3ditem.h | 5 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3ditem_p.h | 4 | ||||
-rw-r--r-- | src/datavisualization/data/qcustom3dvolume.cpp | 4 | ||||
-rw-r--r-- | src/datavisualization/engine/abstract3drenderer.cpp | 60 | ||||
-rw-r--r-- | src/datavisualization/engine/abstract3drenderer_p.h | 2 | ||||
-rw-r--r-- | src/datavisualizationqml2/datavisualizationqml2_plugin.cpp | 1 | ||||
-rw-r--r-- | tests/volumetrictest/main.cpp | 34 | ||||
-rw-r--r-- | tests/volumetrictest/volumetrictest.cpp | 89 | ||||
-rw-r--r-- | tests/volumetrictest/volumetrictest.h | 4 |
13 files changed, 281 insertions, 56 deletions
diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp index 156e0bf4..eb8f2188 100644 --- a/examples/datavisualization/volumetric/volumetric.cpp +++ b/examples/datavisualization/volumetric/volumetric.cpp @@ -22,6 +22,7 @@ #include <QtDataVisualization/q3dcamera.h> #include <QtDataVisualization/q3dtheme.h> #include <QtDataVisualization/qcustom3dlabel.h> +#include <QtDataVisualization/q3dscatter.h> #include <QtCore/qmath.h> #include <QtWidgets/QLabel> #include <QtWidgets/QRadioButton> @@ -40,6 +41,7 @@ const int mineShaftDiameter(1); const int airColorIndex(254); const int mineShaftColorIndex(255); const int layerColorThickness(60); +const int heightToColorDiv(128); const int magmaColorsMin(0); const int magmaColorsMax(layerColorThickness); const int aboveWaterGroundColorsMin(magmaColorsMax + 1); @@ -93,7 +95,10 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) excavateMineShaft(lowDetailSize, 0, m_mineShaftArray.size(), m_lowDetailData); m_volumeItem = new QCustom3DVolume; - m_volumeItem->setScaling(QVector3D(2.0f, 1.0f, 2.0f)); + m_volumeItem->setScaling(QVector3D(m_graph->axisX()->max() - m_graph->axisX()->min(), + m_graph->axisY()->max() - m_graph->axisY()->min(), + m_graph->axisZ()->max() - m_graph->axisZ()->min())); + m_volumeItem->setScalingAbsolute(false); m_volumeItem->setTextureWidth(lowDetailSize); m_volumeItem->setTextureHeight(lowDetailSize / 2); m_volumeItem->setTextureDepth(lowDetailSize); @@ -108,11 +113,14 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) if (i < magmaColorsMax) { m_colorTable1[i] = qRgba(130 - (i * 2), 0, 0, 255); } else if (i < aboveWaterGroundColorsMax) { - m_colorTable1[i] = qRgba(0, ((i - magmaColorsMax) * 2) + 120, 0, terrainTransparency); + m_colorTable1[i] = qRgba((i - magmaColorsMax) * 4, + ((i - magmaColorsMax) * 2) + 120, + (i - magmaColorsMax) * 5, terrainTransparency); } else if (i < underWaterGroundColorsMax) { - m_colorTable1[i] = qRgba(((i - aboveWaterGroundColorsMax) * 2) + 30, - ((i - aboveWaterGroundColorsMax) * 2) + 100, - ((i - aboveWaterGroundColorsMax) * 2) + 30, terrainTransparency); + m_colorTable1[i] = qRgba(((layerColorThickness - i - aboveWaterGroundColorsMax)) + 70, + ((layerColorThickness - i - aboveWaterGroundColorsMax) * 2) + 20, + ((layerColorThickness - i - aboveWaterGroundColorsMax)) + 50, + terrainTransparency); } else if (i < waterColorsMax) { m_colorTable1[i] = qRgba(0, 0, ((i - underWaterGroundColorsMax) * 2) + 120, terrainTransparency); @@ -471,19 +479,19 @@ int VolumetricModifier::createVolume(int textureSize, int startIndex, int count, int height((layerDataSize - (j * 2 * multiplier)) / 2); if (height < magmaHeights.at(k)) { // Magma layer - colorIndex = int((float(height) / colorTableSize) + colorIndex = int((float(height) / heightToColorDiv) * float(layerColorThickness)) + magmaColorsMin; - } else if (height <= groundHeights.at(k) && height <= waterHeights.at(k)) { + } else if (height < groundHeights.at(k) && height < waterHeights.at(k)) { // Ground layer below water - colorIndex = int((float(waterHeights.at(k) - height) / colorTableSize) + colorIndex = int((float(waterHeights.at(k) - height) / heightToColorDiv) * float(layerColorThickness)) + underWaterGroundColorsMin; } else if (height <= waterHeights.at(k)) { // Water layer where water goes over ground - colorIndex = int((float(height - magmaHeights.at(k)) / colorTableSize) + colorIndex = int((float(height - magmaHeights.at(k)) / heightToColorDiv) * float(layerColorThickness)) + waterColorsMin; } else if (height <= groundHeights.at(k)) { // Ground above water - colorIndex = int((float(height - waterHeights.at(k)) / colorTableSize) + colorIndex = int((float(height - waterHeights.at(k)) / heightToColorDiv) * float(layerColorThickness)) + aboveWaterGroundColorsMin; } else { // Rest is air @@ -499,7 +507,7 @@ int VolumetricModifier::createVolume(int textureSize, int startIndex, int count, } int VolumetricModifier::excavateMineShaft(int textureSize, int startIndex, int count, - QVector<uchar> *textureData) + QVector<uchar> *textureData) { int endIndex = startIndex + count; if (endIndex > m_mineShaftArray.size()) diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp index 555f48b7..64194bac 100644 --- a/src/datavisualization/data/customrenderitem.cpp +++ b/src/datavisualization/data/customrenderitem.cpp @@ -23,7 +23,8 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION CustomRenderItem::CustomRenderItem() : AbstractRenderItem(), m_texture(0), - m_absolute(false), + m_positionAbsolute(false), + m_scalingAbsolute(true), m_object(0), m_needBlend(true), m_visible(true), @@ -33,6 +34,7 @@ CustomRenderItem::CustomRenderItem() m_isFacingCamera(false), m_item(0), m_renderer(0), + m_labelItem(false), m_textureWidth(0), m_textureHeight(0), m_textureDepth(0), diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h index 5024270a..8ea8e894 100644 --- a/src/datavisualization/data/customrenderitem_p.h +++ b/src/datavisualization/data/customrenderitem_p.h @@ -51,10 +51,14 @@ public: 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 setOrigScaling(const QVector3D &scaling) { m_origScaling = scaling; } + inline QVector3D origScaling() const { return m_origScaling; } 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 setPositionAbsolute(bool absolute) { m_positionAbsolute = absolute; } + inline bool isPositionAbsolute() const { return m_positionAbsolute; } + inline void setScalingAbsolute(bool absolute) { m_scalingAbsolute = absolute; } + inline bool isScalingAbsolute() const { return m_scalingAbsolute; } inline void setBlendNeeded(bool blend) { m_needBlend = blend; } inline bool isBlendNeeded() const { return m_needBlend; } inline void setVisible(bool visible) { m_visible = visible; } @@ -70,6 +74,8 @@ public: inline void setFacingCamera(bool facing) { m_isFacingCamera = facing; } inline bool isFacingCamera() const { return m_isFacingCamera; } inline void setRenderer(Abstract3DRenderer *renderer) { m_renderer = renderer; } + inline void setLabelItem(bool isLabel) { m_labelItem = isLabel; } + inline bool isLabel() const { return m_labelItem; } // Volume specific inline void setTextureWidth(int width) { m_textureWidth = width; } @@ -104,8 +110,10 @@ private: GLuint m_texture; QVector3D m_scaling; + QVector3D m_origScaling; QVector3D m_position; - bool m_absolute; + bool m_positionAbsolute; + bool m_scalingAbsolute; ObjectHelper *m_object; // shared reference bool m_needBlend; bool m_visible; @@ -115,6 +123,7 @@ private: bool m_isFacingCamera; QCustom3DItem *m_item; Abstract3DRenderer *m_renderer; + bool m_labelItem; // Volume specific int m_textureWidth; diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp index cb843b62..64cb4531 100644 --- a/src/datavisualization/data/qcustom3ditem.cpp +++ b/src/datavisualization/data/qcustom3ditem.cpp @@ -62,11 +62,13 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION * * 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 + * Item position is either in data coordinates or in absolute coordinates, depending on the * 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}. + * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}, + * unless the item is a Custom3DVolume that would be partially visible. In that case, the visible + * portion of the volume will be rendered. * * \sa positionAbsolute */ @@ -83,8 +85,31 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION /*! \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. + * + * Item scaling is either in data values or in absolute values, depending on the + * scalingAbsolute property. The default vector interpreted as absolute values sets the item to + * 10% of the height of the graph, provided the item mesh is normalized and the graph aspect ratios + * haven't been changed from the defaults. + * + * \sa scalingAbsolute + */ + +/*! \qmlproperty bool Custom3DItem::scalingAbsolute + * \since QtDataVisualization 1.2 + * + * This property dictates if item scaling is to be handled in data values or in absolute + * values. Defaults to \c{true}. Items with absolute scaling will be rendered at the same + * size, regardless of axis ranges. Items with data scaling will change their apparent size + * according to the axis ranges. If positionAbsolute value is \c{true}, this property is ignored + * and scaling is interpreted as an absolute value. + * + * \note: Only absolute scaling is supported for Custom3DLabel items or for custom items used in + * \l{AbstractGraph3D::polar}{polar} graphs. + * + * \note: The custom item's mesh must be normalized to range \c{[-1 ,1]}, or the data + * scaling will not be accurate. + * + * \sa scaling, positionAbsolute */ /*! \qmlproperty quaternion Custom3DItem::rotation @@ -180,7 +205,9 @@ QString QCustom3DItem::meshFile() const * 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}. + * \note Items positioned outside any axis range are not rendered if positionAbsolute is \c{false}, + * unless the item is a QCustom3DVolume that would be partially visible. In that case, the visible + * portion of the volume will be rendered. * * \sa positionAbsolute */ @@ -211,7 +238,7 @@ void QCustom3DItem::setPositionAbsolute(bool positionAbsolute) { if (d_ptr->m_positionAbsolute != positionAbsolute) { d_ptr->m_positionAbsolute = positionAbsolute; - d_ptr->m_dirtyBits.positionAbsoluteDirty = true; + d_ptr->m_dirtyBits.positionDirty = true; emit positionAbsoluteChanged(positionAbsolute); emit d_ptr->needUpdate(); } @@ -225,8 +252,13 @@ bool QCustom3DItem::isPositionAbsolute() const /*! \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. + * + * Item scaling is either in data values or in absolute values, depending on the + * scalingAbsolute property. The default vector interpreted as absolute values sets the item to + * 10% of the height of the graph, provided the item mesh is normalized and the graph aspect ratios + * haven't been changed from the defaults. + * + * \sa scalingAbsolute */ void QCustom3DItem::setScaling(const QVector3D &scaling) { @@ -243,6 +275,40 @@ QVector3D QCustom3DItem::scaling() const return d_ptr->m_scaling; } +/*! \property QCustom3DItem::scalingAbsolute + * \since QtDataVisualization 1.2 + * + * This property dictates if item scaling is to be handled in data values or in absolute + * values. Defaults to \c{true}. Items with absolute scaling will be rendered at the same + * size, regardless of axis ranges. Items with data scaling will change their apparent size + * according to the axis ranges. If positionAbsolute value is \c{true}, this property is ignored + * and scaling is interpreted as an absolute value. + * + * \note: Only absolute scaling is supported for QCustom3DLabel items or for custom items used in + * \l{QAbstract3DGraph::polar}{polar} graphs. + * + * \note: The custom item's mesh must be normalized to range \c{[-1 ,1]}, or the data + * scaling will not be accurate. + * + * \sa scaling, positionAbsolute + */ +void QCustom3DItem::setScalingAbsolute(bool scalingAbsolute) +{ + if (d_ptr->m_isLabelItem && !scalingAbsolute) { + qWarning() << __FUNCTION__ << "Data bounds are not supported for label items."; + } else if (d_ptr->m_scalingAbsolute != scalingAbsolute) { + d_ptr->m_scalingAbsolute = scalingAbsolute; + d_ptr->m_dirtyBits.scalingDirty = true; + emit scalingAbsoluteChanged(scalingAbsolute); + emit d_ptr->needUpdate(); + } +} + +bool QCustom3DItem::isScalingAbsolute() const +{ + return d_ptr->m_scalingAbsolute; +} + /*! \property QCustom3DItem::rotation * * Holds the item \a rotation as a QQuaternion. Defaults to \c {QQuaternion(0.0, 0.0, 0.0, 0.0)}. @@ -371,6 +437,7 @@ QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q) : m_position(QVector3D(0.0f, 0.0f, 0.0f)), m_positionAbsolute(false), m_scaling(QVector3D(0.1f, 0.1f, 0.1f)), + m_scalingAbsolute(true), m_rotation(QQuaternion(0.0f, 0.0f, 0.0f, 0.0f)), m_visible(true), m_shadowCasting(true), @@ -388,6 +455,7 @@ QCustom3DItemPrivate::QCustom3DItemPrivate(QCustom3DItem *q, const QString &mesh m_position(position), m_positionAbsolute(false), m_scaling(scaling), + m_scalingAbsolute(true), m_rotation(rotation), m_visible(true), m_shadowCasting(true), @@ -416,7 +484,6 @@ 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; diff --git a/src/datavisualization/data/qcustom3ditem.h b/src/datavisualization/data/qcustom3ditem.h index 2f7f37cf..5c880213 100644 --- a/src/datavisualization/data/qcustom3ditem.h +++ b/src/datavisualization/data/qcustom3ditem.h @@ -39,6 +39,7 @@ class QT_DATAVISUALIZATION_EXPORT QCustom3DItem : public QObject 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) + Q_PROPERTY(bool scalingAbsolute READ isScalingAbsolute WRITE setScalingAbsolute NOTIFY scalingAbsoluteChanged REVISION 1) public: explicit QCustom3DItem(QObject *parent = 0); @@ -62,6 +63,9 @@ public: void setScaling(const QVector3D &scaling); QVector3D scaling() const; + void setScalingAbsolute(bool scalingAbsolute); + bool isScalingAbsolute() const; + void setRotation(const QQuaternion &rotation); QQuaternion rotation(); @@ -84,6 +88,7 @@ signals: void rotationChanged(const QQuaternion &rotation); void visibleChanged(bool visible); void shadowCastingChanged(bool shadowCasting); + Q_REVISION(1) void scalingAbsoluteChanged(bool scalingAbsolute); protected: QCustom3DItem(QCustom3DItemPrivate *d, QObject *parent = 0); diff --git a/src/datavisualization/data/qcustom3ditem_p.h b/src/datavisualization/data/qcustom3ditem_p.h index d766bcf3..627bf53f 100644 --- a/src/datavisualization/data/qcustom3ditem_p.h +++ b/src/datavisualization/data/qcustom3ditem_p.h @@ -29,6 +29,7 @@ #ifndef QCUSTOM3DITEM_P_H #define QCUSTOM3DITEM_P_H +#include "datavisualizationglobal_p.h" #include "qcustom3ditem.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION @@ -37,7 +38,6 @@ struct QCustomItemDirtyBitField { bool textureDirty : 1; bool meshDirty : 1; bool positionDirty : 1; - bool positionAbsoluteDirty : 1; bool scalingDirty : 1; bool rotationDirty : 1; bool visibleDirty : 1; @@ -47,7 +47,6 @@ struct QCustomItemDirtyBitField { : textureDirty(false), meshDirty(false), positionDirty(false), - positionAbsoluteDirty(false), scalingDirty(false), rotationDirty(false), visibleDirty(false), @@ -77,6 +76,7 @@ public: QVector3D m_position; bool m_positionAbsolute; QVector3D m_scaling; + bool m_scalingAbsolute; QQuaternion m_rotation; bool m_visible; bool m_shadowCasting; diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp index 393533c0..d0e0c139 100644 --- a/src/datavisualization/data/qcustom3dvolume.cpp +++ b/src/datavisualization/data/qcustom3dvolume.cpp @@ -623,7 +623,7 @@ void QCustom3DVolume::setSubTextureData(Qt::Axis axis, int index, const uchar *d * * \note Each X-line of the data needs to be 32bit aligned when targeting Y-axis or Z-axis. * If the textureFormat is QImage::Format_Indexed8 and textureWidth is not divisible by four, - * padding bytes need to be added to each X-line of the \a data in cases it is not already + * padding bytes need to be added to each X-line of the \a image in cases it is not already * properly aligned. The padding bytes should indicate an fully transparent color to avoid * rendering artifacts. It is not guaranteed QImage will do this automatically. * @@ -893,6 +893,8 @@ void QCustom3DVolumePrivate::resetDirtyBits() m_dirtyBitsVolume.colorTableDirty = false; m_dirtyBitsVolume.textureDataDirty = false; m_dirtyBitsVolume.textureFormatDirty = false; + m_dirtyBitsVolume.alphaDirty = false; + m_dirtyBitsVolume.shaderDirty = false; } QImage QCustom3DVolumePrivate::renderSlice(Qt::Axis axis, int index) diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 3d5ccba1..18384872 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -960,12 +960,16 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) newItem->setRenderer(this); newItem->setItemPointer(item); // Store pointer for render item updates newItem->setMesh(item->meshFile()); - QVector3D scaling = item->scaling(); + newItem->setPosition(item->position()); + newItem->setOrigScaling(item->scaling()); + newItem->setScalingAbsolute(item->isScalingAbsolute()); + newItem->setPositionAbsolute(item->isPositionAbsolute()); QImage textureImage = item->d_ptr->textureImage(); bool facingCamera = false; GLuint texture = 0; if (item->d_ptr->m_isLabelItem) { QCustom3DLabel *labelItem = static_cast<QCustom3DLabel *>(item); + newItem->setLabelItem(true); float pointSize = labelItem->font().pointSizeF(); // Check do we have custom visuals or need to use theme if (!labelItem->dptr()->m_customVisuals) { @@ -979,8 +983,10 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) } // Calculate scaling based on text (texture size), font size and asked scaling float scaledFontSize = (0.05f + pointSize / 500.0f) / float(textureImage.height()); + QVector3D scaling = newItem->origScaling(); scaling.setX(scaling.x() * textureImage.width() * scaledFontSize); scaling.setY(scaling.y() * textureImage.height() * scaledFontSize); + newItem->setOrigScaling(scaling); // Check if facing camera facingCamera = labelItem->isFacingCamera(); #if !defined(QT_OPENGL_ES_2) @@ -1007,10 +1013,8 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) newItem->setUseHighDefShader(volumeItem->useHighDefShader()); #endif } - newItem->setScaling(scaling); + recalculateCustomItemScaling(newItem); newItem->setRotation(item->rotation()); - newItem->setPosition(item->position()); - newItem->setPositionAbsolute(item->isPositionAbsolute()); #if !defined(QT_OPENGL_ES_2) // In OpenGL ES we simply draw volumes as regular custom item placeholders. if (!item->d_ptr->m_isVolumeItem) @@ -1021,8 +1025,8 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) } newItem->setTexture(texture); item->d_ptr->clearTextureImage(); - QVector3D translation = convertPositionToTranslation(item->position(), - item->isPositionAbsolute()); + QVector3D translation = convertPositionToTranslation(newItem->position(), + newItem->isPositionAbsolute()); newItem->setTranslation(translation); newItem->setVisible(item->isVisible()); newItem->setShadowCasting(item->isShadowCasting()); @@ -1031,6 +1035,27 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) return newItem; } +void Abstract3DRenderer::recalculateCustomItemScaling(CustomRenderItem *item) +{ + if (!m_polarGraph && !item->isLabel() && !item->isScalingAbsolute() + && !item->isPositionAbsolute()) { + QVector3D scale = item->origScaling() / 2.0f; + QVector3D pos = item->position(); + QVector3D minBounds(pos.x() - scale.x(), + pos.y() - scale.y(), + pos.z() - scale.z()); + QVector3D maxBounds(pos.x() + scale.x(), + pos.y() + scale.y(), + pos.z() + scale.z()); + QVector3D min = convertPositionToTranslation(minBounds, false); + QVector3D max = convertPositionToTranslation(maxBounds, false); + item->setScaling(QVector3D(qAbs(max.x() - min.x()), qAbs(max.y() - min.y()), + qAbs(max.z() - min.z())) / 2.0f); + } else { + item->setScaling(item->origScaling()); + } +} + void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) { QCustom3DItem *item = renderItem->itemPointer(); @@ -1038,8 +1063,18 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) renderItem->setMesh(item->meshFile()); item->d_ptr->m_dirtyBits.meshDirty = false; } + if (item->d_ptr->m_dirtyBits.positionDirty) { + renderItem->setPosition(item->position()); + renderItem->setPositionAbsolute(item->isPositionAbsolute()); + QVector3D translation = convertPositionToTranslation(renderItem->position(), + renderItem->isPositionAbsolute()); + renderItem->setTranslation(translation); + item->d_ptr->m_dirtyBits.positionDirty = false; + } if (item->d_ptr->m_dirtyBits.scalingDirty) { QVector3D scaling = item->scaling(); + renderItem->setOrigScaling(scaling); + renderItem->setScalingAbsolute(item->isScalingAbsolute()); // 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); @@ -1062,8 +1097,9 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) scaling.setX(scaling.x() * textureImage.width() * scaledFontSize); scaling.setY(scaling.y() * textureImage.height() * scaledFontSize); item->d_ptr->clearTextureImage(); + renderItem->setOrigScaling(scaling); } - renderItem->setScaling(scaling); + recalculateCustomItemScaling(renderItem); item->d_ptr->m_dirtyBits.scalingDirty = false; } if (item->d_ptr->m_dirtyBits.rotationDirty) { @@ -1097,15 +1133,6 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) 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; @@ -1168,6 +1195,7 @@ void Abstract3DRenderer::updateCustomItem(CustomRenderItem *renderItem) void Abstract3DRenderer::updateCustomItemPositions() { foreach (CustomRenderItem *renderItem, m_customRenderCache) { + recalculateCustomItemScaling(renderItem); QVector3D translation = convertPositionToTranslation(renderItem->position(), renderItem->isPositionAbsolute()); renderItem->setTranslation(translation); diff --git a/src/datavisualization/engine/abstract3drenderer_p.h b/src/datavisualization/engine/abstract3drenderer_p.h index 83b4e1c7..8152e0c9 100644 --- a/src/datavisualization/engine/abstract3drenderer_p.h +++ b/src/datavisualization/engine/abstract3drenderer_p.h @@ -205,6 +205,8 @@ protected: virtual void fixCameraTarget(QVector3D &target) = 0; void updateCameraViewport(); + void recalculateCustomItemScaling(CustomRenderItem *item); + bool m_hasNegativeValues; Q3DTheme *m_cachedTheme; Drawer *m_drawer; diff --git a/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp b/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp index c0bd4183..ecdd7454 100644 --- a/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp +++ b/src/datavisualizationqml2/datavisualizationqml2_plugin.cpp @@ -115,6 +115,7 @@ void QtDataVisualizationQml2Plugin::registerTypes(const char *uri) QLatin1String("Trying to create uncreatable: AbstractGraph3D.")); qmlRegisterType<DeclarativeSurface, 1>(uri, 1, 2, "Surface3D"); qmlRegisterType<Q3DCamera, 1>(uri, 1, 2, "Camera3D"); + qmlRegisterType<QCustom3DItem, 1>(uri, 1, 2, "Custom3DItem"); // New types qmlRegisterType<Q3DInputHandler>(uri, 1, 2, "InputHandler3D"); diff --git a/tests/volumetrictest/main.cpp b/tests/volumetrictest/main.cpp index ba5ba6d3..02f67d6c 100644 --- a/tests/volumetrictest/main.cpp +++ b/tests/volumetrictest/main.cpp @@ -97,6 +97,27 @@ int main(int argc, char **argv) QPushButton *testSubTextureSetting = new QPushButton(widget); testSubTextureSetting->setText(QStringLiteral("Test subtexture settings")); + QLabel *rangeSliderLabel = new QLabel(QStringLiteral("Adjust ranges:"), widget); + + QSlider *rangeXSlider = new QSlider(Qt::Horizontal, widget); + rangeXSlider->setMinimum(0); + rangeXSlider->setMaximum(1024); + rangeXSlider->setValue(512); + rangeXSlider->setEnabled(true); + QSlider *rangeYSlider = new QSlider(Qt::Horizontal, widget); + rangeYSlider->setMinimum(0); + rangeYSlider->setMaximum(1024); + rangeYSlider->setValue(512); + rangeYSlider->setEnabled(true); + QSlider *rangeZSlider = new QSlider(Qt::Horizontal, widget); + rangeZSlider->setMinimum(0); + rangeZSlider->setMaximum(1024); + rangeZSlider->setValue(512); + rangeZSlider->setEnabled(true); + + QPushButton *testBoundsSetting = new QPushButton(widget); + testBoundsSetting->setText(QStringLiteral("Test data bounds")); + vLayout->addWidget(fpsLabel); vLayout->addWidget(sliceXCheckBox); vLayout->addWidget(sliceXSlider); @@ -107,6 +128,11 @@ int main(int argc, char **argv) vLayout->addWidget(sliceZCheckBox); vLayout->addWidget(sliceZSlider); vLayout->addWidget(sliceImageZLabel); + vLayout->addWidget(rangeSliderLabel); + vLayout->addWidget(rangeXSlider); + vLayout->addWidget(rangeYSlider); + vLayout->addWidget(rangeZSlider); + vLayout->addWidget(testBoundsSetting); vLayout->addWidget(testSubTextureSetting, 1, Qt::AlignTop); VolumetricModifier *modifier = new VolumetricModifier(graph); @@ -127,6 +153,14 @@ int main(int argc, char **argv) &VolumetricModifier::adjustSliceZ); QObject::connect(testSubTextureSetting, &QPushButton::clicked, modifier, &VolumetricModifier::testSubtextureSetting); + QObject::connect(rangeXSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustRangeX); + QObject::connect(rangeYSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustRangeY); + QObject::connect(rangeZSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustRangeZ); + QObject::connect(testBoundsSetting, &QPushButton::clicked, modifier, + &VolumetricModifier::testBoundsSetting); widget->show(); return app.exec(); diff --git a/tests/volumetrictest/volumetrictest.cpp b/tests/volumetrictest/volumetrictest.cpp index 555cc286..6d7da021 100644 --- a/tests/volumetrictest/volumetrictest.cpp +++ b/tests/volumetrictest/volumetrictest.cpp @@ -31,6 +31,12 @@ using namespace QtDataVisualization; const int imageCount = 512; +const float xMiddle = 10.0f; +const float yMiddle = 12.5f; +const float zMiddle = -40.0f; +const float xRange = 40.0f; +const float yRange = 7.5f; +const float zRange = 20.0f; VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) : m_graph(scatter), @@ -47,6 +53,12 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront); m_graph->setOrthoProjection(true); //m_graph->scene()->activeCamera()->setTarget(QVector3D(0.5f, 0.5f, 0.5f)); + m_graph->axisX()->setRange(xMiddle - xRange, xMiddle + xRange); + m_graph->axisX()->setSegmentCount(8); + m_graph->axisY()->setRange(yMiddle - yRange, yMiddle + yRange); + m_graph->axisY()->setSegmentCount(3); + m_graph->axisZ()->setRange(zMiddle - zRange, zMiddle + zRange); + m_graph->axisZ()->setSegmentCount(8); createVolume(); createAnotherVolume(); @@ -55,6 +67,13 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) // m_volumeItem->setUseHighDefShader(false); // m_volumeItem2->setUseHighDefShader(false); // m_volumeItem3->setUseHighDefShader(false); + m_volumeItem->setScalingAbsolute(false); + m_volumeItem2->setScalingAbsolute(false); + m_volumeItem3->setScalingAbsolute(false); + m_volumeItem->setPositionAbsolute(false); + m_volumeItem2->setPositionAbsolute(false); + m_volumeItem3->setPositionAbsolute(false); + m_plainItem = new QCustom3DItem; QImage texture(2, 2, QImage::Format_ARGB32); @@ -62,8 +81,9 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) m_plainItem->setMeshFile(QStringLiteral(":/mesh")); m_plainItem->setTextureImage(texture); m_plainItem->setRotation(m_volumeItem->rotation()); - m_plainItem->setPosition(m_volumeItem->position() + QVector3D(0.8f, 0.0f, 0.0f)); - m_plainItem->setScaling(m_volumeItem->scaling()); + m_plainItem->setPosition(QVector3D(30.0f, 17.5f, -30.0f)); + m_plainItem->setScaling(QVector3D(20.0f, 5.0f, 10.0f)); + m_plainItem->setScalingAbsolute(false); m_graph->addCustomItem(m_volumeItem); m_graph->addCustomItem(m_volumeItem2); @@ -80,7 +100,9 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) label->setScaling(QVector3D(2.0f, 2.0f, 0.0f)); label->setRotationAxisAndAngle(QVector3D(0.0f, 1.0f, 0.0f), 45.0f); label->setPosition(m_volumeItem3->position()); - label->setPositionAbsolute(true); + label->setPositionAbsolute(false); + label->setScalingAbsolute(true); + m_graph->addCustomItem(label); QObject::connect(m_graph, &QAbstract3DGraph::currentFpsChanged, this, @@ -218,6 +240,50 @@ void VolumetricModifier::testSubtextureSetting() m_volumeItem3->setSubTextureData(Qt::ZAxis, 190, slice); } +void VolumetricModifier::adjustRangeX(int value) +{ + float adjustment = float(value - 512) / 10.0f; + m_graph->axisX()->setRange(xMiddle + adjustment - xRange, xMiddle + adjustment + xRange); +} + +void VolumetricModifier::adjustRangeY(int value) +{ + float adjustment = float(value - 512) / 10.0f; + m_graph->axisY()->setRange(yMiddle + adjustment - yRange, yMiddle + adjustment + yRange); +} + +void VolumetricModifier::adjustRangeZ(int value) +{ + float adjustment = float(value - 512) / 10.0f; + m_graph->axisZ()->setRange(zMiddle + adjustment - zRange, zMiddle + adjustment + zRange); +} + +void VolumetricModifier::testBoundsSetting() +{ + static QVector3D scaling1 = m_volumeItem->scaling(); + static QVector3D scaling2 = m_volumeItem2->scaling(); + static QVector3D scaling3 = m_volumeItem3->scaling(); + static QVector3D scaleVector = QVector3D(0.5f, 0.3f, 0.2f); + + if (m_volumeItem->isScalingAbsolute()) { + m_volumeItem->setScalingAbsolute(false); + m_volumeItem2->setScalingAbsolute(false); + m_volumeItem3->setScalingAbsolute(false); + + m_volumeItem->setScaling(scaling1); + m_volumeItem2->setScaling(scaling2); + m_volumeItem3->setScaling(scaling3); + } else { + m_volumeItem->setScalingAbsolute(true); + m_volumeItem2->setScalingAbsolute(true); + m_volumeItem3->setScalingAbsolute(true); + + m_volumeItem->setScaling(scaleVector); + m_volumeItem2->setScaling(scaleVector); + m_volumeItem3->setScaling(scaleVector); + } +} + void VolumetricModifier::checkRenderCase(int id, Qt::Axis axis, int index, const QVector<uchar> &dataBefore, QCustom3DVolume *volumeItem) @@ -236,7 +302,7 @@ void VolumetricModifier::createVolume() m_volumeItem = new QCustom3DVolume; m_volumeItem->setTextureFormat(QImage::Format_ARGB32); // m_volumeItem->setRotation(QQuaternion::fromAxisAndAngle(1.0f, 1.0f, 0.0f, 10.0f)); - m_volumeItem->setPosition(QVector3D(-0.5f, 0.6f, 0.0f)); + m_volumeItem->setPosition(QVector3D(xMiddle - (xRange / 2.0f), yMiddle + (yRange / 2.0f), zMiddle)); QImage logo; logo.load(QStringLiteral(":/logo_no_padding.png")); @@ -284,10 +350,7 @@ void VolumetricModifier::createVolume() int depth = m_volumeItem->textureDepth(); int frameSize = width * height; qDebug() << width << height << depth << m_volumeItem->textureData()->size(); -// m_volumeItem->setScaling(QVector3D(float(width) / float(depth) * 2.0f, -// float(height) / float(depth) * 2.0f, -// 2.0f)); - m_volumeItem->setScaling(QVector3D(0.4f, 0.4f, 0.4f)); + m_volumeItem->setScaling(QVector3D(xRange, yRange, zRange) / 2.0f); uchar *data = m_volumeItem->textureData()->data(); uchar *p = data; @@ -389,7 +452,7 @@ void VolumetricModifier::createAnotherVolume() { m_volumeItem2 = new QCustom3DVolume; m_volumeItem2->setTextureFormat(QImage::Format_ARGB32); - m_volumeItem2->setPosition(QVector3D(0.5f, -0.5f, 0.0f)); + m_volumeItem2->setPosition(QVector3D(xMiddle + (xRange / 2.0f), yMiddle - (yRange / 2.0f), zMiddle)); QImage logo; logo.load(QStringLiteral(":/logo_no_padding.png")); @@ -417,9 +480,9 @@ void VolumetricModifier::createAnotherVolume() int height = m_volumeItem2->textureHeight(); int depth = m_volumeItem2->textureDepth(); qDebug() << width << height << depth << m_volumeItem2->textureData()->size(); - m_volumeItem2->setScaling(QVector3D(float(width) / float(depth) * 2.0f, - float(height) / float(depth) * 2.0f, - 2.0f)); + m_volumeItem2->setScaling(QVector3D(float(width) / float(depth) * xRange * 2.0f, + float(height) / float(depth) * yRange * 2.0f, + zRange * 2.0f)); // Change one picture using subtexture replacement QImage flipped = logo.mirrored(); @@ -433,7 +496,7 @@ void VolumetricModifier::createYetAnotherVolume() m_volumeItem3 = new QCustom3DVolume; m_volumeItem3->setTextureFormat(QImage::Format_Indexed8); // m_volumeItem2->setRotation(QQuaternion::fromAxisAndAngle(1.0f, 1.0f, 0.0f, 10.0f)); - m_volumeItem3->setPosition(QVector3D(-0.5f, -0.6f, 0.0f)); + m_volumeItem3->setPosition(QVector3D(xMiddle - (xRange / 2.0f), yMiddle - (yRange / 2.0f), zMiddle)); // m_volumeItem3->setTextureDimensions(m_volumeItem->textureDataWidth(), // m_volumeItem->textureHeight(), diff --git a/tests/volumetrictest/volumetrictest.h b/tests/volumetrictest/volumetrictest.h index b1b98455..48c805d4 100644 --- a/tests/volumetrictest/volumetrictest.h +++ b/tests/volumetrictest/volumetrictest.h @@ -46,6 +46,10 @@ public slots: void adjustSliceZ(int value); void handleFpsChange(); void testSubtextureSetting(); + void adjustRangeX(int value); + void adjustRangeY(int value); + void adjustRangeZ(int value); + void testBoundsSetting(); private: void createVolume(); |