| 1 | // Copyright (C) 2023 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 3 | // |
| 4 | // W A R N I N G |
| 5 | // ------------- |
| 6 | // |
| 7 | // This file is not part of the QtGraphs API. It exists purely as an |
| 8 | // implementation detail. This header file may change from version to |
| 9 | // version without notice, or even be removed. |
| 10 | // |
| 11 | // We mean it. |
| 12 | #ifndef QQUICKGRAPHSSCATTER_P_H |
| 13 | #define QQUICKGRAPHSSCATTER_P_H |
| 14 | |
| 15 | #include "qquickgraphsitem_p.h" |
| 16 | #include "qscatter3dseries.h" |
| 17 | #include "qvalue3daxis.h" |
| 18 | #include <private/scatterinstancing_p.h> |
| 19 | |
| 20 | #include <private/qgraphsglobal_p.h> |
| 21 | #include <private/qqmldelegatemodel_p.h> |
| 22 | |
| 23 | QT_BEGIN_NAMESPACE |
| 24 | |
| 25 | struct Scatter3DChangeBitField |
| 26 | { |
| 27 | bool selectedItemChanged : 1; |
| 28 | bool itemChanged : 1; |
| 29 | |
| 30 | Scatter3DChangeBitField() |
| 31 | : selectedItemChanged(true) |
| 32 | , itemChanged(false) |
| 33 | {} |
| 34 | }; |
| 35 | |
| 36 | class Q_GRAPHS_EXPORT QQuickGraphsScatter : public QQuickGraphsItem |
| 37 | { |
| 38 | Q_OBJECT |
| 39 | Q_PROPERTY(QValue3DAxis *axisX READ axisX WRITE setAxisX NOTIFY axisXChanged) |
| 40 | Q_PROPERTY(QValue3DAxis *axisY READ axisY WRITE setAxisY NOTIFY axisYChanged) |
| 41 | Q_PROPERTY(QValue3DAxis *axisZ READ axisZ WRITE setAxisZ NOTIFY axisZChanged) |
| 42 | Q_PROPERTY(QScatter3DSeries *selectedSeries READ selectedSeries NOTIFY selectedSeriesChanged) |
| 43 | Q_PROPERTY(QQmlListProperty<QScatter3DSeries> seriesList READ seriesList CONSTANT) |
| 44 | Q_CLASSINFO("DefaultProperty" , "seriesList" ) |
| 45 | |
| 46 | QML_NAMED_ELEMENT(Scatter3D) |
| 47 | |
| 48 | public: |
| 49 | explicit QQuickGraphsScatter(QQuickItem *parent = 0); |
| 50 | ~QQuickGraphsScatter() override; |
| 51 | |
| 52 | struct ChangeItem |
| 53 | { |
| 54 | QScatter3DSeries *series; |
| 55 | qsizetype index; |
| 56 | }; |
| 57 | |
| 58 | void setAxisX(QValue3DAxis *axis); |
| 59 | QValue3DAxis *axisX() const; |
| 60 | void setAxisY(QValue3DAxis *axis); |
| 61 | QValue3DAxis *axisY() const; |
| 62 | void setAxisZ(QValue3DAxis *axis); |
| 63 | QValue3DAxis *axisZ() const; |
| 64 | |
| 65 | QQmlListProperty<QScatter3DSeries> seriesList(); |
| 66 | static void appendSeriesFunc(QQmlListProperty<QScatter3DSeries> *list, QScatter3DSeries *series); |
| 67 | static qsizetype countSeriesFunc(QQmlListProperty<QScatter3DSeries> *list); |
| 68 | static QScatter3DSeries *atSeriesFunc(QQmlListProperty<QScatter3DSeries> *list, qsizetype index); |
| 69 | static void clearSeriesFunc(QQmlListProperty<QScatter3DSeries> *list); |
| 70 | Q_INVOKABLE void clearSelection() override; |
| 71 | Q_INVOKABLE void addSeries(QScatter3DSeries *series); |
| 72 | Q_INVOKABLE void removeSeries(QScatter3DSeries *series); |
| 73 | QList<QScatter3DSeries *> scatterSeriesList(); |
| 74 | |
| 75 | QScatter3DSeries *selectedSeries() const; |
| 76 | void setSelectedItem(qsizetype index, QScatter3DSeries *series); |
| 77 | |
| 78 | static constexpr qsizetype invalidSelectionIndex() { return -1; } |
| 79 | void setSelectionMode(QtGraphs3D::SelectionFlags mode) override; |
| 80 | |
| 81 | bool hasSelectedItemChanged() const { return m_changeTracker.selectedItemChanged; } |
| 82 | void setSelectedItemChanged(bool changed) { m_changeTracker.selectedItemChanged = changed; } |
| 83 | bool hasItemChanged() const { return m_changeTracker.itemChanged; } |
| 84 | void setItemChanged(bool changed) { m_changeTracker.itemChanged = changed; } |
| 85 | |
| 86 | void handleAxisAutoAdjustRangeChangedInOrientation(QAbstract3DAxis::AxisOrientation orientation, |
| 87 | bool autoAdjust) override; |
| 88 | void handleAxisRangeChangedBySender(QObject *sender) override; |
| 89 | void adjustAxisRanges() override; |
| 90 | bool hasChangedSeriesList() const { return !m_changedSeriesList.empty(); } |
| 91 | bool isSeriesVisualsDirty() const { return m_isSeriesVisualsDirty; } |
| 92 | void setSeriesVisualsDirty() { m_isSeriesVisualsDirty = true; } |
| 93 | bool isDataDirty() const { return m_isDataDirty; } |
| 94 | |
| 95 | public Q_SLOTS: |
| 96 | void handleAxisXChanged(QAbstract3DAxis *axis) override; |
| 97 | void handleAxisYChanged(QAbstract3DAxis *axis) override; |
| 98 | void handleAxisZChanged(QAbstract3DAxis *axis) override; |
| 99 | void handleSeriesMeshChanged(); |
| 100 | void handleMeshSmoothChanged(bool enable); |
| 101 | |
| 102 | void handleArrayReset(); |
| 103 | void handleItemsAdded(qsizetype startIndex, qsizetype count); |
| 104 | void handleItemsChanged(qsizetype startIndex, qsizetype count); |
| 105 | void handleItemsRemoved(qsizetype startIndex, qsizetype count); |
| 106 | void handleItemsInserted(qsizetype startIndex, qsizetype count); |
| 107 | |
| 108 | Q_SIGNALS: |
| 109 | void axisXChanged(QValue3DAxis *axis); |
| 110 | void axisYChanged(QValue3DAxis *axis); |
| 111 | void axisZChanged(QValue3DAxis *axis); |
| 112 | void selectedSeriesChanged(QScatter3DSeries *series); |
| 113 | |
| 114 | protected: |
| 115 | void calculateSceneScalingFactors() override; |
| 116 | void componentComplete() override; |
| 117 | bool doPicking(QPointF position) override; |
| 118 | void updateShadowQuality(QtGraphs3D::ShadowQuality quality) override; |
| 119 | void updateLightStrength() override; |
| 120 | void startRecordingRemovesAndInserts() override; |
| 121 | |
| 122 | private: |
| 123 | Scatter3DChangeBitField m_changeTracker; |
| 124 | QList<ChangeItem> m_changedItems; |
| 125 | |
| 126 | struct InsertRemoveRecord |
| 127 | { |
| 128 | bool m_isInsert; |
| 129 | qsizetype m_startIndex; |
| 130 | qsizetype m_count; |
| 131 | QAbstract3DSeries *m_series; |
| 132 | |
| 133 | InsertRemoveRecord() |
| 134 | : m_isInsert(false) |
| 135 | , m_startIndex(0) |
| 136 | , m_count(0) |
| 137 | , m_series(0) |
| 138 | {} |
| 139 | |
| 140 | InsertRemoveRecord(bool isInsert, qsizetype startIndex, qsizetype count, QAbstract3DSeries *series) |
| 141 | : m_isInsert(isInsert) |
| 142 | , m_startIndex(startIndex) |
| 143 | , m_count(count) |
| 144 | , m_series(series) |
| 145 | {} |
| 146 | }; |
| 147 | |
| 148 | QList<InsertRemoveRecord> m_insertRemoveRecords; |
| 149 | bool m_recordInsertsAndRemoves; |
| 150 | |
| 151 | struct ScatterModel |
| 152 | { |
| 153 | QList<QQuick3DModel *> dataItems; |
| 154 | QQuick3DTexture *seriesTexture; |
| 155 | QQuick3DTexture *highlightTexture; |
| 156 | QScatter3DSeries *series; |
| 157 | |
| 158 | //Legacy optimiaztion material reference models |
| 159 | QQuick3DModel *baseRef = nullptr; |
| 160 | QQuick3DModel *selectionRef = nullptr; |
| 161 | // For instanced, i.e. Default optimization |
| 162 | ScatterInstancing *instancing = nullptr; |
| 163 | QQuick3DModel *instancingRootItem = nullptr; |
| 164 | QQuick3DModel *selectionIndicator = nullptr; |
| 165 | }; |
| 166 | |
| 167 | float m_maxItemSize = 0.0f; |
| 168 | |
| 169 | const float m_defaultMinSize = 0.01f; |
| 170 | const float m_defaultMaxSize = 0.1f; |
| 171 | const float m_itemScaler = 3.0f; |
| 172 | float m_pointScale = 0; |
| 173 | |
| 174 | const float m_indicatorScaleAdjustment = 1.1f; |
| 175 | const float m_rangeGradientYHelper = 0.5f; |
| 176 | |
| 177 | bool m_polarGraph = false; |
| 178 | |
| 179 | float m_selectedGradientPos = 0.0f; |
| 180 | qsizetype m_selectedItem = invalidSelectionIndex(); |
| 181 | QScatter3DSeries *m_selectedItemSeries = nullptr; // Points to the series for which the bar is |
| 182 | // selected in single series selection cases. |
| 183 | QQuick3DModel *m_selected = nullptr; |
| 184 | QQuick3DModel *m_previousSelected = nullptr; |
| 185 | |
| 186 | QList<ScatterModel *> m_scatterGraphs; |
| 187 | |
| 188 | bool m_optimizationChanged = false; |
| 189 | |
| 190 | void connectSeries(QScatter3DSeries *series); |
| 191 | void disconnectSeries(QScatter3DSeries *series); |
| 192 | qsizetype getItemIndex(QQuick3DModel *item); |
| 193 | QVector3D selectedItemPosition(); |
| 194 | |
| 195 | float m_dotSizedScale = 1.0f; |
| 196 | |
| 197 | void updateMaterialReference(ScatterModel *model); |
| 198 | void updateInstancedMaterialProperties(ScatterModel *graphModel, |
| 199 | const bool isHighlight = false, |
| 200 | QQuick3DTexture *seriesTexture = nullptr, |
| 201 | QQuick3DTexture *highlightTexture = nullptr, |
| 202 | const bool transparency = false); |
| 203 | void updateItemMaterial(QQuick3DModel *item, |
| 204 | bool useGradient, |
| 205 | bool rangeGradient, |
| 206 | bool usePoint, |
| 207 | const QString &materialName); |
| 208 | void updateMaterialProperties(QQuick3DModel *item, |
| 209 | QQuick3DTexture *texture, |
| 210 | QColor color = Qt::white, |
| 211 | const bool transparency = false); |
| 212 | QQuick3DTexture *createTexture(); |
| 213 | QQuick3DModel *createDataItemModel(QAbstract3DSeries::Mesh meshType); |
| 214 | QQuick3DNode *createSeriesRoot(); |
| 215 | QQuick3DModel *createDataItem(QAbstract3DSeries *series); |
| 216 | void removeDataItems(ScatterModel *graphModel, QtGraphs3D::OptimizationHint optimizationHint); |
| 217 | void fixMeshFileName(QString &fileName, QAbstract3DSeries *series); |
| 218 | QString getMeshFileName(QAbstract3DSeries *series); |
| 219 | |
| 220 | void deleteDataItem(QQuick3DModel *item); |
| 221 | void removeDataItems(QList<QQuick3DModel *> &items, qsizetype count); |
| 222 | void recreateDataItems(); |
| 223 | void recreateDataItems(const QList<ScatterModel *> &); |
| 224 | void addPointsToScatterModel(ScatterModel *graphModel, qsizetype count); |
| 225 | qsizetype sizeDifference(qsizetype size1, qsizetype size2); |
| 226 | void handleSeriesChanged(QList<QAbstract3DSeries *> changedSeries); |
| 227 | |
| 228 | QColor m_selectedSeriesColor; |
| 229 | bool selectedItemInSeries(const QScatter3DSeries *series); |
| 230 | |
| 231 | bool isDotPositionInAxisRange(QVector3D dotPos); |
| 232 | |
| 233 | QQmlComponent *createRepeaterDelegate(QAbstract3DSeries::Mesh MeshType); |
| 234 | float calculatePointScaleSize(); |
| 235 | void updatePointScaleSize(); |
| 236 | void calculatePolarXZ(const float posX, const float posZ, float &x, float &z) const; |
| 237 | |
| 238 | void generatePointsForScatterModel(ScatterModel *series); |
| 239 | void updateScatterGraphItemPositions(ScatterModel *graphModel); |
| 240 | void updateScatterGraphItemVisuals(ScatterModel *graphModel); |
| 241 | |
| 242 | QQuick3DModel *selected() const; |
| 243 | void setSelected(QQuick3DModel *newSelected); |
| 244 | void setSelected(QQuick3DModel *root, qsizetype index); |
| 245 | void clearSelectionModel(); |
| 246 | void clearAllSelectionInstanced(); |
| 247 | |
| 248 | void optimizationChanged(QtGraphs3D::OptimizationHint toOptimization); |
| 249 | |
| 250 | void updateGraph() override; |
| 251 | void synchData() override; |
| 252 | void handleOptimizationHintChange(QtGraphs3D::OptimizationHint hint) override; |
| 253 | void handleSeriesVisibilityChangedBySender(QObject *sender) override; |
| 254 | |
| 255 | bool selectedItemInRange(const ScatterModel *graphModel); |
| 256 | ScatterModel *findGraphModel(QScatter3DSeries *series); |
| 257 | |
| 258 | private slots: |
| 259 | void cameraRotationChanged(); |
| 260 | |
| 261 | friend class Q3DScatterWidgetItem; |
| 262 | }; |
| 263 | |
| 264 | QT_END_NAMESPACE |
| 265 | #endif // QQUICKGRAPHSSCATTER_P_H |
| 266 | |