1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qscatterdataproxy_p.h"
5#include "qscatter3dseries_p.h"
6#include "qabstract3daxis_p.h"
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 * \class QScatterDataProxy
12 * \inmodule QtDataVisualization
13 * \brief The QScatterDataProxy class is the data proxy for 3D scatter graphs.
14 * \since QtDataVisualization 1.0
15 *
16 * A scatter data proxy handles adding, inserting, changing, and removing data
17 * items.
18 *
19 * QScatterDataProxy takes ownership of all
20 * QtDataVisualization::QScatterDataArray and QScatterDataItem objects passed to
21 * it.
22 *
23 * \sa {Qt Data Visualization Data Handling}
24 */
25
26/*!
27 * \typedef QScatterDataArray
28 * \relates QScatterDataProxy
29 *
30 * A list of \l {QScatterDataItem} objects.
31 */
32
33/*!
34 * \qmltype ScatterDataProxy
35 * \inqmlmodule QtDataVisualization
36 * \since QtDataVisualization 1.0
37 * \ingroup datavisualization_qml
38 * \instantiates QScatterDataProxy
39 * \inherits AbstractDataProxy
40 * \brief The data proxy for 3D scatter graphs.
41 *
42 * This type handles adding, inserting, changing, and removing data items.
43 *
44 * This type is uncreatable, but contains properties that are exposed via subtypes.
45 *
46 * \sa ItemModelScatterDataProxy, {Qt Data Visualization Data Handling}
47 */
48
49/*!
50 * \qmlproperty int ScatterDataProxy::itemCount
51 * The number of items in the array.
52 */
53
54/*!
55 * \qmlproperty Scatter3DSeries ScatterDataProxy::series
56 *
57 * The series this proxy is attached to.
58 */
59
60/*!
61 * Constructs QScatterDataProxy with the given \a parent.
62 */
63QScatterDataProxy::QScatterDataProxy(QObject *parent) :
64 QAbstractDataProxy(new QScatterDataProxyPrivate(this), parent)
65{
66}
67
68/*!
69 * \internal
70 */
71QScatterDataProxy::QScatterDataProxy(QScatterDataProxyPrivate *d, QObject *parent) :
72 QAbstractDataProxy(d, parent)
73{
74}
75
76/*!
77 * Deletes the scatter data proxy.
78 */
79QScatterDataProxy::~QScatterDataProxy()
80{
81}
82
83/*!
84 * \property QScatterDataProxy::series
85 *
86 * \brief The series this proxy is attached to.
87 */
88QScatter3DSeries *QScatterDataProxy::series() const
89{
90 return static_cast<QScatter3DSeries *>(d_ptr->series());
91}
92
93/*!
94 * Takes ownership of the array \a newArray. Clears the existing array if the
95 * new array differs from it. If the arrays are the same, this function
96 * just triggers the arrayReset() signal.
97 *
98 * Passing a null array deletes the old array and creates a new empty array.
99 */
100void QScatterDataProxy::resetArray(QScatterDataArray *newArray)
101{
102 if (dptr()->m_dataArray != newArray)
103 dptr()->resetArray(newArray);
104
105 emit arrayReset();
106 emit itemCountChanged(count: itemCount());
107}
108
109/*!
110 * Replaces the item at the position \a index with the item \a item.
111 */
112void QScatterDataProxy::setItem(int index, const QScatterDataItem &item)
113{
114 dptr()->setItem(index, item);
115 emit itemsChanged(startIndex: index, count: 1);
116}
117
118/*!
119 * Replaces the items starting from the position \a index with the items
120 * specified by \a items.
121 */
122void QScatterDataProxy::setItems(int index, const QScatterDataArray &items)
123{
124 dptr()->setItems(index, items);
125 emit itemsChanged(startIndex: index, count: items.size());
126}
127
128/*!
129 * Adds the item \a item to the end of the array.
130 *
131 * Returns the index of the added item.
132 */
133int QScatterDataProxy::addItem(const QScatterDataItem &item)
134{
135 int addIndex = dptr()->addItem(item);
136 emit itemsAdded(startIndex: addIndex, count: 1);
137 emit itemCountChanged(count: itemCount());
138 return addIndex;
139}
140
141/*!
142 * Adds the items specified by \a items to the end of the array.
143 *
144 * Returns the index of the first added item.
145 */
146int QScatterDataProxy::addItems(const QScatterDataArray &items)
147{
148 int addIndex = dptr()->addItems(items);
149 emit itemsAdded(startIndex: addIndex, count: items.size());
150 emit itemCountChanged(count: itemCount());
151 return addIndex;
152}
153
154/*!
155 * Inserts the item \a item to the position \a index. If the index is equal to
156 * the data array size, the item is added to the array.
157 */
158void QScatterDataProxy::insertItem(int index, const QScatterDataItem &item)
159{
160 dptr()->insertItem(index, item);
161 emit itemsInserted(startIndex: index, count: 1);
162 emit itemCountChanged(count: itemCount());
163}
164
165/*!
166 * Inserts the items specified by \a items to the position \a index. If the
167 * index is equal to data array size, the items are added to the array.
168 */
169void QScatterDataProxy::insertItems(int index, const QScatterDataArray &items)
170{
171 dptr()->insertItems(index, items);
172 emit itemsInserted(startIndex: index, count: items.size());
173 emit itemCountChanged(count: itemCount());
174}
175
176/*!
177 * Removes the number of items specified by \a removeCount starting at the
178 * position \a index. Attempting to remove items past the end of
179 * the array does nothing.
180 */
181void QScatterDataProxy::removeItems(int index, int removeCount)
182{
183 if (index >= dptr()->m_dataArray->size())
184 return;
185
186 dptr()->removeItems(index, removeCount);
187 emit itemsRemoved(startIndex: index, count: removeCount);
188 emit itemCountChanged(count: itemCount());
189}
190
191/*!
192 * \property QScatterDataProxy::itemCount
193 *
194 * \brief The number of items in the array.
195 */
196int QScatterDataProxy::itemCount() const
197{
198 return dptrc()->m_dataArray->size();
199}
200
201/*!
202 * Returns the pointer to the data array.
203 */
204const QScatterDataArray *QScatterDataProxy::array() const
205{
206 return dptrc()->m_dataArray;
207}
208
209/*!
210 * Returns the pointer to the item at the index \a index. It is guaranteed to be
211 * valid only until the next call that modifies data.
212 */
213const QScatterDataItem *QScatterDataProxy::itemAt(int index) const
214{
215 return &dptrc()->m_dataArray->at(i: index);
216}
217
218/*!
219 * \internal
220 */
221QScatterDataProxyPrivate *QScatterDataProxy::dptr()
222{
223 return static_cast<QScatterDataProxyPrivate *>(d_ptr.data());
224}
225
226/*!
227 * \internal
228 */
229const QScatterDataProxyPrivate *QScatterDataProxy::dptrc() const
230{
231 return static_cast<const QScatterDataProxyPrivate *>(d_ptr.data());
232}
233
234/*!
235 * \fn void QScatterDataProxy::arrayReset()
236 *
237 * This signal is emitted when the data array is reset.
238 * If the contents of the whole array are changed without calling resetArray(),
239 * this signal needs to be emitted to update the graph.
240 */
241
242/*!
243 * \fn void QScatterDataProxy::itemsAdded(int startIndex, int count)
244 *
245 * This signal is emitted when the number of items specified by \a count is
246 * added starting at the position \a startIndex.
247 * If items are added to the array without calling addItem() or addItems(),
248 * this signal needs to be emitted to update the graph.
249 */
250
251/*!
252 * \fn void QScatterDataProxy::itemsChanged(int startIndex, int count)
253 *
254 * This signal is emitted when the number of items specified by \a count is
255 * changed starting at the position \a startIndex.
256 * If items are changed in the array without calling setItem() or setItems(),
257 * this signal needs to be emitted to update the graph.
258 */
259
260/*!
261 * \fn void QScatterDataProxy::itemsRemoved(int startIndex, int count)
262 *
263 * This signal is emitted when the number of rows specified by \a count is
264 * removed starting at the position \a startIndex.
265 * The index may be larger than the current array size if items are removed from
266 * the end. If items are removed from the array without calling removeItems(),
267 * this signal needs to be emitted to update the graph.
268 */
269
270/*!
271 * \fn void QScatterDataProxy::itemsInserted(int startIndex, int count)
272 *
273 * This signal is emitted when the number of items specified by \a count is
274 * inserted starting at the position \a startIndex.
275 * If items are inserted into the array without calling insertItem() or
276 * insertItems(), this signal needs to be emitted to update the graph.
277 */
278
279// QScatterDataProxyPrivate
280
281QScatterDataProxyPrivate::QScatterDataProxyPrivate(QScatterDataProxy *q)
282 : QAbstractDataProxyPrivate(q, QAbstractDataProxy::DataTypeScatter),
283 m_dataArray(new QScatterDataArray)
284{
285}
286
287QScatterDataProxyPrivate::~QScatterDataProxyPrivate()
288{
289 m_dataArray->clear();
290 delete m_dataArray;
291}
292
293void QScatterDataProxyPrivate::resetArray(QScatterDataArray *newArray)
294{
295 if (!newArray)
296 newArray = new QScatterDataArray;
297
298 if (newArray != m_dataArray) {
299 m_dataArray->clear();
300 delete m_dataArray;
301 m_dataArray = newArray;
302 }
303}
304
305void QScatterDataProxyPrivate::setItem(int index, const QScatterDataItem &item)
306{
307 Q_ASSERT(index >= 0 && index < m_dataArray->size());
308 (*m_dataArray)[index] = item;
309}
310
311void QScatterDataProxyPrivate::setItems(int index, const QScatterDataArray &items)
312{
313 Q_ASSERT(index >= 0 && (index + items.size()) <= m_dataArray->size());
314 for (int i = 0; i < items.size(); i++)
315 (*m_dataArray)[index++] = items[i];
316}
317
318int QScatterDataProxyPrivate::addItem(const QScatterDataItem &item)
319{
320 int currentSize = m_dataArray->size();
321 m_dataArray->append(t: item);
322 return currentSize;
323}
324
325int QScatterDataProxyPrivate::addItems(const QScatterDataArray &items)
326{
327 int currentSize = m_dataArray->size();
328 (*m_dataArray) += items;
329 return currentSize;
330}
331
332void QScatterDataProxyPrivate::insertItem(int index, const QScatterDataItem &item)
333{
334 Q_ASSERT(index >= 0 && index <= m_dataArray->size());
335 m_dataArray->insert(i: index, t: item);
336}
337
338void QScatterDataProxyPrivate::insertItems(int index, const QScatterDataArray &items)
339{
340 Q_ASSERT(index >= 0 && index <= m_dataArray->size());
341 for (int i = 0; i < items.size(); i++)
342 m_dataArray->insert(i: index++, t: items.at(i));
343}
344
345void QScatterDataProxyPrivate::removeItems(int index, int removeCount)
346{
347 Q_ASSERT(index >= 0);
348 int maxRemoveCount = m_dataArray->size() - index;
349 removeCount = qMin(a: removeCount, b: maxRemoveCount);
350 m_dataArray->remove(i: index, n: removeCount);
351}
352
353void QScatterDataProxyPrivate::limitValues(QVector3D &minValues, QVector3D &maxValues,
354 QAbstract3DAxis *axisX, QAbstract3DAxis *axisY,
355 QAbstract3DAxis *axisZ) const
356{
357 if (m_dataArray->isEmpty())
358 return;
359
360 const QVector3D &firstPos = m_dataArray->at(i: 0).position();
361
362 float minX = firstPos.x();
363 float maxX = minX;
364 float minY = firstPos.y();
365 float maxY = minY;
366 float minZ = firstPos.z();
367 float maxZ = minZ;
368
369 if (m_dataArray->size() > 1) {
370 for (int i = 1; i < m_dataArray->size(); i++) {
371 const QVector3D &pos = m_dataArray->at(i).position();
372
373 float value = pos.x();
374 if (qIsNaN(f: value) || qIsInf(f: value))
375 continue;
376 if (isValidValue(axisValue: minX, value, axis: axisX))
377 minX = value;
378 if (maxX < value)
379 maxX = value;
380
381 value = pos.y();
382 if (qIsNaN(f: value) || qIsInf(f: value))
383 continue;
384 if (isValidValue(axisValue: minY, value, axis: axisY))
385 minY = value;
386 if (maxY < value)
387 maxY = value;
388
389 value = pos.z();
390 if (qIsNaN(f: value) || qIsInf(f: value))
391 continue;
392 if (isValidValue(axisValue: minZ, value, axis: axisZ))
393 minZ = value;
394 if (maxZ < value)
395 maxZ = value;
396 }
397 }
398
399 minValues.setX(minX);
400 minValues.setY(minY);
401 minValues.setZ(minZ);
402
403 maxValues.setX(maxX);
404 maxValues.setY(maxY);
405 maxValues.setZ(maxZ);
406}
407
408bool QScatterDataProxyPrivate::isValidValue(float axisValue, float value,
409 QAbstract3DAxis *axis) const
410{
411 return (axisValue > value && (value > 0.0f
412 || (value == 0.0f && axis->d_ptr->allowZero())
413 || (value < 0.0f && axis->d_ptr->allowNegatives())));
414}
415
416void QScatterDataProxyPrivate::setSeries(QAbstract3DSeries *series)
417{
418 QAbstractDataProxyPrivate::setSeries(series);
419 QScatter3DSeries *scatterSeries = static_cast<QScatter3DSeries *>(series);
420 emit qptr()->seriesChanged(series: scatterSeries);
421}
422
423QScatterDataProxy *QScatterDataProxyPrivate::qptr()
424{
425 return static_cast<QScatterDataProxy *>(q_ptr);
426}
427
428QT_END_NAMESPACE
429

source code of qtdatavis3d/src/datavisualization/data/qscatterdataproxy.cpp