1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qabstract3daxis_p.h"
5#include "qsurface3dseries_p.h"
6#include "qsurfacedataproxy_p.h"
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 * \class QSurfaceDataProxy
12 * \inmodule QtGraphs
13 * \ingroup graphs_3D
14 * \brief The QSurfaceDataProxy class is the data proxy for a 3D surface graph.
15 *
16 * A surface data proxy handles surface related data in rows. For this it
17 * provides two auxiliary type aliases: QtGraphs::QSurfaceDataArray and
18 * QtGraphs::QSurfaceDataRow. \c QSurfaceDataArray is a QList that
19 * controls the rows. \c QSurfaceDataRow is a QList that contains
20 * QSurfaceDataItem objects. For more information about how to feed the data to
21 * the proxy, see the sample code in the Q3DSurfaceWidgetItem documentation. Since data is
22 * stored in series, it is necessary to create a series associated with the
23 * proxy before using these functions for the dataset.
24 *
25 * All rows must have the same number of items.
26 *
27 * QSurfaceDataProxy takes ownership of all \c QSurfaceDataRow objects passed to
28 * it, whether directly or in a \c QSurfaceDataArray container.
29 * To use surface data row pointers to directly modify data after adding the
30 * array to the proxy, the appropriate signal must be emitted to update the
31 * graph.
32 *
33 * To make a sensible surface, the x-value of each successive item in all rows
34 * must be either ascending or descending throughout the row. Similarly, the
35 * z-value of each successive item in all columns must be either ascending or
36 * descending throughout the column.
37 *
38 * \note Currently only surfaces with straight rows and columns are fully
39 * supported. Any row with items that do not have the exact same z-value or any
40 * column with items that do not have the exact same x-value may get clipped
41 * incorrectly if the whole surface does not completely fit within the visible
42 * x-axis or z-axis ranges.
43 *
44 * \note Surfaces with less than two rows or columns are not considered valid
45 * surfaces and will not be rendered.
46 *
47 * \note On some environments, surfaces with a lot of visible vertices may not
48 * render, because they exceed the per-draw vertex count supported by the
49 * graphics driver. This is mostly an issue on 32-bit and OpenGL ES2 platforms.
50 *
51 * \sa {Qt Graphs Data Handling with 3D}
52 */
53
54/*!
55 * \typealias QSurfaceDataRow
56 * \relates QSurfaceDataProxy
57 *
58 * A list of \l {QSurfaceDataItem} objects.
59 */
60
61/*!
62 * \typealias QSurfaceDataArray
63 * \relates QSurfaceDataProxy
64 *
65 * A list of pointers to \l {QSurfaceDataRow} objects.
66 */
67
68/*!
69 * \qmltype SurfaceDataProxy
70 * \inqmlmodule QtGraphs
71 * \ingroup graphs_qml_3D
72 * \nativetype QSurfaceDataProxy
73 * \inherits AbstractDataProxy
74 * \brief The data proxy for a 3D surface graph.
75 *
76 * This type handles surface data items. The data is arranged into rows and
77 * columns, and all rows must have the same number of columns.
78 *
79 * This type is uncreatable, but contains properties that are exposed via
80 * subtypes.
81 *
82 * For a more complete description, see QSurfaceDataProxy.
83 *
84 * \sa ItemModelSurfaceDataProxy, {Qt Graphs Data Handling with 3D}
85 */
86
87/*!
88 * \qmlproperty int SurfaceDataProxy::rowCount
89 * The number of rows in the data array.
90 */
91
92/*!
93 * \qmlproperty int SurfaceDataProxy::columnCount
94 * The number of columns in the data array.
95 */
96
97/*!
98 * \qmlproperty Surface3DSeries SurfaceDataProxy::series
99 *
100 * The series this proxy is attached to.
101 */
102
103/*!
104 \qmlsignal SurfaceDataProxy::rowCountChanged(int count)
105
106 This signal is emitted when rowCount changes to \a count.
107*/
108/*!
109 \qmlsignal SurfaceDataProxy::columnCountChanged(int count)
110
111 This signal is emitted when columnCount changes to \a count.
112*/
113/*!
114 \qmlsignal SurfaceDataProxy::seriesChanged(Surface3DSeries series)
115
116 This signal is emitted when \l series changes to \a series.
117*/
118
119/*!
120 * Constructs QSurfaceDataProxy with the given \a parent.
121 */
122QSurfaceDataProxy::QSurfaceDataProxy(QObject *parent)
123 : QAbstractDataProxy(*(new QSurfaceDataProxyPrivate()), parent)
124{}
125
126/*!
127 * \internal
128 */
129QSurfaceDataProxy::QSurfaceDataProxy(QSurfaceDataProxyPrivate &d, QObject *parent)
130 : QAbstractDataProxy(d, parent)
131{}
132
133/*!
134 * Deletes the surface data proxy.
135 */
136QSurfaceDataProxy::~QSurfaceDataProxy() {}
137
138/*!
139 * \property QSurfaceDataProxy::series
140 *
141 * \brief The series this proxy is attached to.
142 */
143QSurface3DSeries *QSurfaceDataProxy::series() const
144{
145 Q_D(const QSurfaceDataProxy);
146 if (!d->series())
147 qWarning(msg: "Series needs to be created to access data members");
148 return static_cast<QSurface3DSeries *>(d->series());
149}
150
151/*!
152 * Clears the existing array and triggers the arrayReset() signal.
153 */
154void QSurfaceDataProxy::resetArray()
155{
156 Q_D(QSurfaceDataProxy);
157 d->resetArray(newArray: QSurfaceDataArray());
158
159 emit arrayReset();
160 emit rowCountChanged(count: rowCount());
161 emit columnCountChanged(count: columnCount());
162}
163
164/*!
165 * Sets the array from \a newArray. If the new array is equal to the
166 * existing one, this function simply triggers the arrayReset() signal.
167*/
168void QSurfaceDataProxy::resetArray(QSurfaceDataArray newArray)
169{
170 Q_D(QSurfaceDataProxy);
171 if (!series())
172 return;
173
174 if (series()->dataArray().data() != newArray.data())
175 d->resetArray(newArray: std::move(newArray));
176
177 emit arrayReset();
178 emit rowCountChanged(count: rowCount());
179 emit columnCountChanged(count: columnCount());
180}
181
182/*!
183 * Changes an existing row by replacing the row at the position \a rowIndex
184 * with the new row specified by \a row. The new row can be the same as the
185 * existing row already stored at the \a rowIndex. The new row must have
186 * the same number of columns as the row it is replacing.
187 */
188void QSurfaceDataProxy::setRow(qsizetype rowIndex, QSurfaceDataRow row)
189{
190 Q_D(QSurfaceDataProxy);
191 d->setRow(rowIndex, row: std::move(row));
192 emit rowsChanged(startIndex: rowIndex, count: 1);
193}
194
195/*!
196 * Changes existing rows by replacing the rows starting at the position
197 * \a rowIndex with the new rows specifies by \a rows.
198 * The rows in the \a rows array can be the same as the existing rows already
199 * stored at the \a rowIndex. The new rows must have the same number of columns
200 * as the rows they are replacing.
201 */
202void QSurfaceDataProxy::setRows(qsizetype rowIndex, QSurfaceDataArray rows)
203{
204 Q_D(QSurfaceDataProxy);
205 d->setRows(rowIndex, rows: std::move(rows));
206 emit rowsChanged(startIndex: rowIndex, count: rows.size());
207}
208
209/*!
210 * Changes a single item at the position specified by \a rowIndex and
211 * \a columnIndex to the item \a item.
212 */
213void QSurfaceDataProxy::setItem(qsizetype rowIndex, qsizetype columnIndex, QSurfaceDataItem item)
214{
215 Q_D(QSurfaceDataProxy);
216 d->setItem(rowIndex, columnIndex, item: std::move(item));
217 emit itemChanged(rowIndex, columnIndex);
218}
219
220/*!
221 * Changes a single item at the position \a position to the item \a item.
222 * The x-value of \a position indicates the row and the y-value indicates the
223 * column.
224 */
225void QSurfaceDataProxy::setItem(QPoint position, QSurfaceDataItem item)
226{
227 setItem(rowIndex: position.x(), columnIndex: position.y(), item);
228}
229
230/*!
231 * Adds the new row \a row to the end of an array. The new row must have
232 * the same number of columns as the rows in the initial array.
233 *
234 * Returns the index of the added row.
235 */
236qsizetype QSurfaceDataProxy::addRow(QSurfaceDataRow row)
237{
238 Q_D(QSurfaceDataProxy);
239 qsizetype addIndex = d->addRow(row: std::move(row));
240 emit rowsAdded(startIndex: addIndex, count: 1);
241 emit rowCountChanged(count: rowCount());
242 return addIndex;
243}
244
245/*!
246 * Adds new \a rows to the end of an array. The new rows must have the same
247 * number of columns as the rows in the initial array.
248 *
249 * Returns the index of the first added row.
250 */
251qsizetype QSurfaceDataProxy::addRows(QSurfaceDataArray rows)
252{
253 Q_D(QSurfaceDataProxy);
254 qsizetype addIndex = d->addRows(rows: std::move(rows));
255 emit rowsAdded(startIndex: addIndex, count: rows.size());
256 emit rowCountChanged(count: rowCount());
257 return addIndex;
258}
259
260/*!
261 * Inserts the new row \a row into \a rowIndex.
262 * If \a rowIndex is equal to the array size, the rows are added to the end of
263 * the array. The new row must have the same number of columns as the rows in
264 * the initial array.
265 */
266void QSurfaceDataProxy::insertRow(qsizetype rowIndex, QSurfaceDataRow row)
267{
268 Q_D(QSurfaceDataProxy);
269 d->insertRow(rowIndex, row: std::move(row));
270 emit rowsInserted(startIndex: rowIndex, count: 1);
271 emit rowCountChanged(count: rowCount());
272}
273
274/*!
275 * Inserts new \a rows into \a rowIndex.
276 * If \a rowIndex is equal to the array size, the rows are added to the end of
277 * the array. The new \a rows must have the same number of columns as the rows
278 * in the initial array.
279 */
280void QSurfaceDataProxy::insertRows(qsizetype rowIndex, QSurfaceDataArray rows)
281{
282 Q_D(QSurfaceDataProxy);
283 d->insertRows(rowIndex, rows: std::move(rows));
284 emit rowsInserted(startIndex: rowIndex, count: rows.size());
285 emit rowCountChanged(count: rowCount());
286}
287
288/*!
289 * Removes the number of rows specified by \a removeCount starting at the
290 * position \a rowIndex. Attempting to remove rows past the end of the
291 * array does nothing.
292 */
293void QSurfaceDataProxy::removeRows(qsizetype rowIndex, qsizetype removeCount)
294{
295 Q_D(QSurfaceDataProxy);
296 if (rowIndex < rowCount() && removeCount >= 1) {
297 d->removeRows(rowIndex, removeCount);
298 emit rowsRemoved(startIndex: rowIndex, count: removeCount);
299 emit rowCountChanged(count: rowCount());
300 }
301}
302
303/*!
304 * Returns the pointer to the item at the position specified by \a rowIndex and
305 * \a columnIndex. It is guaranteed to be valid only
306 * until the next call that modifies data.
307 */
308const QSurfaceDataItem &QSurfaceDataProxy::itemAt(qsizetype rowIndex, qsizetype columnIndex) const
309{
310 const QSurfaceDataArray &dataArray = series()->dataArray();
311 Q_ASSERT(rowIndex >= 0 && rowIndex < dataArray.size());
312 const QSurfaceDataRow &dataRow = dataArray[rowIndex];
313 Q_ASSERT(columnIndex >= 0 && columnIndex < dataRow.size());
314 return dataRow.at(i: columnIndex);
315}
316
317/*!
318 * Returns the pointer to the item at the position \a position. The x-value of
319 * \a position indicates the row and the y-value indicates the column. The item
320 * is guaranteed to be valid only until the next call that modifies data.
321 */
322const QSurfaceDataItem &QSurfaceDataProxy::itemAt(QPoint position) const
323{
324 return itemAt(rowIndex: position.x(), columnIndex: position.y());
325}
326
327/*!
328 * \property QSurfaceDataProxy::rowCount
329 *
330 * \brief The number of rows in the data array.
331 */
332qsizetype QSurfaceDataProxy::rowCount() const
333{
334 if (series())
335 return series()->dataArray().size();
336 else
337 return 0;
338}
339
340/*!
341 * \property QSurfaceDataProxy::columnCount
342 *
343 * \brief The number of columns in the data array.
344 */
345qsizetype QSurfaceDataProxy::columnCount() const
346{
347 if (series() && series()->dataArray().size() > 0)
348 return series()->dataArray().at(i: 0).size();
349 else
350 return 0;
351}
352
353/*!
354 * \fn void QSurfaceDataProxy::arrayReset()
355 *
356 * This signal is emitted when the data array is reset.
357 * If the contents of the whole array are changed without calling resetArray(),
358 * this signal needs to be emitted to update the graph.
359 */
360
361/*!
362 * \fn void QSurfaceDataProxy::rowsAdded(qsizetype startIndex, qsizetype count)
363 *
364 * This signal is emitted when the number of rows specified by \a count is
365 * added, starting at the position \a startIndex.
366 * If rows are added to the array without calling addRow() or addRows(),
367 * this signal needs to be emitted to update the graph.
368 */
369
370/*!
371 * \fn void QSurfaceDataProxy::rowsChanged(qsizetype startIndex, qsizetype count)
372 *
373 * This signal is emitted when the number of rows specified by \a count is
374 * changed, starting at the position \a startIndex.
375 * If rows are changed in the array without calling setRow() or setRows(),
376 * this signal needs to be emitted to update the graph.
377 */
378
379/*!
380 * \fn void QSurfaceDataProxy::rowsRemoved(qsizetype startIndex, qsizetype count)
381 *
382 * This signal is emitted when the number of rows specified by \a count is
383 * removed, starting at the position \a startIndex.
384 *
385 * The index is the current array size if the rows were removed from the end of
386 * the array. If rows are removed from the array without calling removeRows(),
387 * this signal needs to be emitted to update the graph.
388 */
389
390/*!
391 * \fn void QSurfaceDataProxy::rowsInserted(qsizetype startIndex, qsizetype count)
392 *
393 * This signal is emitted when the number of rows specified by \a count is
394 * inserted at the position \a startIndex.
395 *
396 * If rows are inserted into the array without calling insertRow() or
397 * insertRows(), this signal needs to be emitted to update the graph.
398 */
399
400/*!
401 * \fn void QSurfaceDataProxy::itemChanged(qsizetype rowIndex, qsizetype columnIndex)
402 *
403 * This signal is emitted when the item at the position specified by \a rowIndex
404 * and \a columnIndex changes.
405 * If the item is changed in the array without calling setItem(),
406 * this signal needs to be emitted to update the graph.
407 */
408
409// QSurfaceDataProxyPrivate
410
411QSurfaceDataProxyPrivate::QSurfaceDataProxyPrivate()
412 : QAbstractDataProxyPrivate(QAbstractDataProxy::DataType::Surface)
413{}
414
415QSurfaceDataProxyPrivate::~QSurfaceDataProxyPrivate() {}
416
417void QSurfaceDataProxyPrivate::resetArray(QSurfaceDataArray &&newArray)
418{
419 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
420 if (newArray.data() != surfaceSeries->dataArray().data()) {
421 surfaceSeries->clearArray();
422 surfaceSeries->setDataArray(newArray);
423 }
424}
425
426void QSurfaceDataProxyPrivate::setRow(qsizetype rowIndex, QSurfaceDataRow &&row)
427{
428 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
429 Q_ASSERT(rowIndex >= 0 && rowIndex < surfaceSeries->dataArray().size());
430 Q_ASSERT(surfaceSeries->dataArray().at(rowIndex).size() == row.size());
431
432 if (row.data() != surfaceSeries->dataArray().at(i: rowIndex).data()) {
433 surfaceSeries->clearRow(rowIndex);
434 QSurfaceDataArray array = surfaceSeries->dataArray();
435 array[rowIndex] = row;
436 surfaceSeries->setDataArray(array);
437 }
438}
439
440void QSurfaceDataProxyPrivate::setRows(qsizetype rowIndex, QSurfaceDataArray &&rows)
441{
442 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
443 QSurfaceDataArray array = surfaceSeries->dataArray();
444 Q_ASSERT(rowIndex >= 0 && (rowIndex + rows.size()) <= array.size());
445
446 for (int i = 0; i < rows.size(); i++) {
447 Q_ASSERT(surfaceSeries->dataArray().at(rowIndex).size() == rows.at(i).size());
448 if (rows.at(i).data() != array.at(i: rowIndex).data()) {
449 surfaceSeries->clearRow(rowIndex);
450 array[rowIndex] = rows.at(i);
451 }
452 rowIndex++;
453 }
454 surfaceSeries->setDataArray(array);
455}
456
457void QSurfaceDataProxyPrivate::setItem(qsizetype rowIndex, qsizetype columnIndex, QSurfaceDataItem &&item)
458{
459 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
460 Q_ASSERT(rowIndex >= 0 && rowIndex < surfaceSeries->dataArray().size());
461 QSurfaceDataArray array = surfaceSeries->dataArray();
462 QSurfaceDataRow &row = array[rowIndex];
463 Q_ASSERT(columnIndex < row.size());
464 row[columnIndex] = item;
465 surfaceSeries->setDataArray(array);
466}
467
468qsizetype QSurfaceDataProxyPrivate::addRow(QSurfaceDataRow &&row)
469{
470 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
471 Q_ASSERT(surfaceSeries->dataArray().isEmpty()
472 || surfaceSeries->dataArray().at(0).size() == row.size());
473 qsizetype currentSize = surfaceSeries->dataArray().size();
474 QSurfaceDataArray array = surfaceSeries->dataArray();
475 array.append(t: row);
476 surfaceSeries->setDataArray(array);
477 return currentSize;
478}
479
480qsizetype QSurfaceDataProxyPrivate::addRows(QSurfaceDataArray &&rows)
481{
482 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
483 qsizetype currentSize = surfaceSeries->dataArray().size();
484 QSurfaceDataArray array = surfaceSeries->dataArray();
485 for (int i = 0; i < rows.size(); i++) {
486 Q_ASSERT(surfaceSeries->dataArray().isEmpty()
487 || surfaceSeries->dataArray().at(0).size() == rows.at(i).size());
488 array.append(t: rows.at(i));
489 }
490 surfaceSeries->setDataArray(array);
491 return currentSize;
492}
493
494void QSurfaceDataProxyPrivate::insertRow(qsizetype rowIndex, QSurfaceDataRow &&row)
495{
496 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
497 Q_ASSERT(rowIndex >= 0 && rowIndex <= surfaceSeries->dataArray().size());
498 Q_ASSERT(surfaceSeries->dataArray().isEmpty()
499 || surfaceSeries->dataArray().at(0).size() == row.size());
500 QSurfaceDataArray array = surfaceSeries->dataArray();
501 array.insert(i: rowIndex, t: row);
502 surfaceSeries->setDataArray(array);
503}
504
505void QSurfaceDataProxyPrivate::insertRows(qsizetype rowIndex, QSurfaceDataArray &&rows)
506{
507 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
508 Q_ASSERT(rowIndex >= 0 && rowIndex <= surfaceSeries->dataArray().size());
509 QSurfaceDataArray array = surfaceSeries->dataArray();
510
511 for (int i = 0; i < rows.size(); i++) {
512 Q_ASSERT(surfaceSeries->dataArray().isEmpty()
513 || surfaceSeries->dataArray().at(0).size() == rows.at(i).size());
514 array.insert(i: rowIndex++, t: rows.at(i));
515 }
516 surfaceSeries->setDataArray(array);
517}
518
519void QSurfaceDataProxyPrivate::removeRows(qsizetype rowIndex, qsizetype removeCount)
520{
521 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
522 Q_ASSERT(rowIndex >= 0);
523 qsizetype maxRemoveCount = surfaceSeries->dataArray().size() - rowIndex;
524 removeCount = qMin(a: removeCount, b: maxRemoveCount);
525 QSurfaceDataArray array = surfaceSeries->dataArray();
526 for (int i = 0; i < removeCount; i++) {
527 surfaceSeries->clearRow(rowIndex);
528 array.removeAt(i: rowIndex);
529 }
530 surfaceSeries->setDataArray(array);
531}
532
533void QSurfaceDataProxyPrivate::limitValues(QVector3D &minValues,
534 QVector3D &maxValues,
535 QAbstract3DAxis *axisX,
536 QAbstract3DAxis *axisY,
537 QAbstract3DAxis *axisZ) const
538{
539 float min = 0.0f;
540 float max = 0.0f;
541
542 auto *surfaceSeries = static_cast<QSurface3DSeries *>(series());
543 qsizetype rows = surfaceSeries->dataArray().size();
544 qsizetype columns = 0;
545 if (rows)
546 columns = surfaceSeries->dataArray().at(i: 0).size();
547
548 if (rows && columns) {
549 min = surfaceSeries->dataArray().at(i: 0).at(i: 0).y();
550 max = surfaceSeries->dataArray().at(i: 0).at(i: 0).y();
551 }
552
553 for (int i = 0; i < rows; i++) {
554 const QSurfaceDataRow &row = surfaceSeries->dataArray().at(i);
555 if (!row.isEmpty()) {
556 for (int j = 0; j < columns; j++) {
557 float itemValue = surfaceSeries->dataArray().at(i).at(i: j).y();
558 if (qIsNaN(f: itemValue) || qIsInf(f: itemValue))
559 continue;
560 if ((min > itemValue || (qIsNaN(f: min) || qIsInf(f: min)))
561 && isValidValue(value: itemValue, axis: axisY)) {
562 min = itemValue;
563 }
564 if (max < itemValue || (qIsNaN(f: max) || qIsInf(f: max)))
565 max = itemValue;
566 }
567 }
568 }
569
570 minValues.setY(min);
571 maxValues.setY(max);
572
573 if (columns) {
574 // Have some defaults
575 float xLow = surfaceSeries->dataArray().at(i: 0).at(i: 0).x();
576 float xHigh = surfaceSeries->dataArray().at(i: 0).last().x();
577 float zLow = surfaceSeries->dataArray().at(i: 0).at(i: 0).z();
578 float zHigh = surfaceSeries->dataArray().last().at(i: 0).z();
579 for (int i = 0; i < rows; i++) {
580 for (int j = 0; j < columns; j++) {
581 float zItemValue = surfaceSeries->dataArray().at(i).at(i: j).z();
582 if (qIsNaN(f: zItemValue) || qIsInf(f: zItemValue))
583 continue;
584 else if (isValidValue(value: zItemValue, axis: axisZ))
585 zLow = qMin(a: zLow, b: zItemValue);
586 }
587 if (!qIsNaN(f: zLow) && !qIsInf(f: zLow))
588 break;
589 }
590 for (qsizetype i = rows - 1; i >= 0; i--) {
591 for (qsizetype j = 0; j < columns; j++) {
592 float zItemValue = surfaceSeries->dataArray().at(i).at(i: j).z();
593 if (qIsNaN(f: zItemValue) || qIsInf(f: zItemValue))
594 continue;
595 else if (isValidValue(value: zItemValue, axis: axisZ)) {
596 if (!qIsNaN(f: zHigh) && !qIsInf(f: zHigh))
597 zHigh = qMax(a: zHigh, b: zItemValue);
598 else
599 zHigh = zItemValue;
600 }
601 }
602 if (!qIsNaN(f: zHigh) && !qIsInf(f: zHigh))
603 break;
604 }
605 for (qsizetype j = 0; j < columns; j++) {
606 for (qsizetype i = 0; i < rows; i++) {
607 float xItemValue = surfaceSeries->dataArray().at(i).at(i: j).x();
608 if (qIsNaN(f: xItemValue) || qIsInf(f: xItemValue))
609 continue;
610 else if (isValidValue(value: xItemValue, axis: axisX))
611 xLow = qMin(a: xLow, b: xItemValue);
612 }
613 if (!qIsNaN(f: xLow) && !qIsInf(f: xLow))
614 break;
615 }
616 for (qsizetype j = columns - 1; j >= 0; j--) {
617 for (qsizetype i = 0; i < rows; i++) {
618 float xItemValue = surfaceSeries->dataArray().at(i).at(i: j).x();
619 if (qIsNaN(f: xItemValue) || qIsInf(f: xItemValue)) {
620 continue;
621 } else if (isValidValue(value: xItemValue, axis: axisX)) {
622 if (!qIsNaN(f: xHigh) && !qIsInf(f: xHigh))
623 xHigh = qMax(a: xHigh, b: xItemValue);
624 else
625 xHigh = xItemValue;
626 }
627 }
628 if (!qIsNaN(f: xHigh) && !qIsInf(f: xHigh))
629 break;
630 }
631 minValues.setX(xLow);
632 minValues.setZ(zLow);
633 maxValues.setX(xHigh);
634 maxValues.setZ(zHigh);
635 } else {
636 minValues.setX(axisX->d_func()->allowZero() ? 0.0f : 1.0f);
637 minValues.setZ(axisZ->d_func()->allowZero() ? 0.0f : 1.0f);
638 maxValues.setX(axisX->d_func()->allowZero() ? 0.0f : 1.0f);
639 maxValues.setZ(axisZ->d_func()->allowZero() ? 0.0f : 1.0f);
640 }
641}
642
643bool QSurfaceDataProxyPrivate::isValidValue(float value, QAbstract3DAxis *axis) const
644{
645 return (value > 0.0f || (value == 0.0f && axis->d_func()->allowZero())
646 || (value < 0.0f && axis->d_func()->allowNegatives()));
647}
648
649void QSurfaceDataProxyPrivate::setSeries(QAbstract3DSeries *series)
650{
651 Q_Q(QSurfaceDataProxy);
652 QAbstractDataProxyPrivate::setSeries(series);
653 QSurface3DSeries *surfaceSeries = static_cast<QSurface3DSeries *>(series);
654 emit q->seriesChanged(series: surfaceSeries);
655}
656
657QT_END_NAMESPACE
658

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtgraphs/src/graphs3d/data/qsurfacedataproxy.cpp