1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Data Visualization module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "scatterchart.h"
31#include <QtDataVisualization/qscatterdataproxy.h>
32#include <QtDataVisualization/qscatter3dseries.h>
33#include <QtDataVisualization/qvalue3daxis.h>
34#include <QtDataVisualization/q3dscene.h>
35#include <QtDataVisualization/q3dcamera.h>
36#include <QtDataVisualization/q3dtheme.h>
37#include <QtDataVisualization/Q3DInputHandler>
38#include <qmath.h>
39#include <qrandom.h>
40using namespace QtDataVisualization;
41
42//#define RANDOM_SCATTER
43
44const int numberOfItems = 10000;
45
46ScatterDataModifier::ScatterDataModifier(Q3DScatter *scatter)
47 : m_chart(scatter),
48 m_fontSize(30.0f),
49 m_loopCounter(0),
50 m_selectedItem(-1),
51 m_targetSeries(0)
52{
53 m_chart->activeTheme()->setType(Q3DTheme::ThemeStoneMoss);
54 QFont font = m_chart->activeTheme()->font();
55 font.setPointSize(m_fontSize);
56 m_chart->activeTheme()->setFont(font);
57 m_chart->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
58 m_chart->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
59 m_chart->setAxisX(new QValue3DAxis);
60 m_chart->setAxisY(new QValue3DAxis);
61 m_chart->setAxisZ(new QValue3DAxis);
62 m_chart->axisY()->setLabelFormat(QStringLiteral("%.7f"));
63 static_cast<Q3DInputHandler *>(m_chart->activeInputHandler())->setZoomAtTargetEnabled(true);
64
65 createAndAddSeries();
66 createAndAddSeries();
67
68 m_chart->setSelectionMode(QAbstract3DGraph::SelectionItem);
69
70 QObject::connect(sender: &m_timer, signal: &QTimer::timeout, receiver: this, slot: &ScatterDataModifier::timeout);
71 QObject::connect(sender: m_chart, signal: &Q3DScatter::shadowQualityChanged, receiver: this,
72 slot: &ScatterDataModifier::shadowQualityUpdatedByVisual);
73
74 QObject::connect(sender: m_chart, signal: &Q3DScatter::axisXChanged, receiver: this,
75 slot: &ScatterDataModifier::handleAxisXChanged);
76 QObject::connect(sender: m_chart, signal: &Q3DScatter::axisYChanged, receiver: this,
77 slot: &ScatterDataModifier::handleAxisYChanged);
78 QObject::connect(sender: m_chart, signal: &Q3DScatter::axisZChanged, receiver: this,
79 slot: &ScatterDataModifier::handleAxisZChanged);
80 QObject::connect(sender: m_chart, signal: &QAbstract3DGraph::currentFpsChanged, receiver: this,
81 slot: &ScatterDataModifier::handleFpsChange);
82}
83
84ScatterDataModifier::~ScatterDataModifier()
85{
86 delete m_chart;
87}
88
89void ScatterDataModifier::start()
90{
91 addData();
92}
93
94static const int itemsPerUnit = 100; // "unit" is one unit range along Z-axis
95
96void ScatterDataModifier::massiveDataTest()
97{
98 static int testPhase = 0;
99 static QTimer *massiveTestTimer = 0;
100
101 if (!massiveTestTimer)
102 massiveTestTimer = new QTimer;
103
104 int items = 1000000;
105 int visibleRange = 200;
106 int unitCount = items / itemsPerUnit;
107 int cacheSize = visibleRange * itemsPerUnit * 5;
108
109 switch (testPhase) {
110 case 0: {
111 float yRangeMin = 0.0f;
112 float yRangeMax = 1.0f;
113 float yRangeMargin = 0.05f;
114 float minY = yRangeMin + yRangeMargin;
115 float maxY = yRangeMax - yRangeMargin;
116 float unitBase = minY;
117 float direction = 1.0f;
118
119 if (!m_massiveTestCacheArray.size()) {
120 m_massiveTestCacheArray.resize(asize: cacheSize);
121 int totalIndex = 0;
122 for (int i = 0; i < unitCount && totalIndex < cacheSize; i++) {
123 unitBase += direction * (QRandomGenerator::global()->bounded(highest: 3) / 100.0f);
124 if (unitBase > maxY) {
125 unitBase = maxY;
126 direction = -1.0f;
127 } else if (unitBase < minY) {
128 unitBase = minY;
129 direction = 1.0f;
130 }
131 for (int j = 0; j < itemsPerUnit && totalIndex < cacheSize; j++) {
132 float randFactor = float(QRandomGenerator::global()->bounded(highest: 100)) / (100 / yRangeMargin);
133 m_massiveTestCacheArray[totalIndex].setPosition(
134 QVector3D(float(QRandomGenerator::global()->bounded(highest: itemsPerUnit)),
135 unitBase + randFactor, 0.0f));
136 // Z value is irrelevant, we replace it anyway when we take item to use
137 totalIndex++;
138 }
139 }
140 }
141
142 qDebug() << __FUNCTION__ << testPhase << ": Setting the graph up...";
143 QValue3DAxis *xAxis = new QValue3DAxis();
144 QValue3DAxis *yAxis = new QValue3DAxis();
145 QValue3DAxis *zAxis = new QValue3DAxis();
146 xAxis->setRange(min: 0.0f, max: float(itemsPerUnit - 1));
147 yAxis->setRange(min: yRangeMin, max: yRangeMax);
148 zAxis->setRange(min: 0.0f, max: float(visibleRange - 1));
149 xAxis->setSegmentCount(1);
150 yAxis->setSegmentCount(1);
151 zAxis->setSegmentCount(1);
152 m_chart->setAxisX(xAxis);
153 m_chart->setAxisY(yAxis);
154 m_chart->setAxisZ(zAxis);
155 m_chart->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetRight);
156 m_chart->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
157 foreach (QAbstract3DSeries *series, m_chart->seriesList())
158 m_chart->removeSeries(series: static_cast<QScatter3DSeries *>(series));
159
160 qDebug() << __FUNCTION__ << testPhase << ": Creating massive array..." << items;
161 QScatterDataArray *massiveArray = new QScatterDataArray;
162 massiveArray->resize(asize: items);
163
164 int cacheIndex = 0;
165 for (int i = 0; i < items; i++) {
166 // Use qreals for precicion as the numbers can overflow int
167 float currentZ = float(qreal(i) * qreal(unitCount) / qreal(items));
168 (*massiveArray)[i] = m_massiveTestCacheArray.at(i: cacheIndex++);
169 (*massiveArray)[i].setZ(currentZ);
170 if (cacheIndex >= cacheSize)
171 cacheIndex = 0;
172 }
173 qDebug() << __FUNCTION__ << testPhase << ": Massive array creation finished!";
174
175 QScatter3DSeries *series = new QScatter3DSeries;
176 series->dataProxy()->resetArray(newArray: massiveArray);
177 series->setMesh(QAbstract3DSeries::MeshPoint);
178 m_chart->addSeries(series);
179 break;
180 }
181 case 1: {
182 qDebug() << __FUNCTION__ << testPhase << ": Scroll";
183 QObject::disconnect(sender: massiveTestTimer, signal: 0, receiver: this, member: 0);
184 QObject::connect(sender: massiveTestTimer, signal: &QTimer::timeout, receiver: this,
185 slot: &ScatterDataModifier::massiveTestScroll);
186 massiveTestTimer->start(msec: 16);
187 break;
188 }
189 case 2: {
190 qDebug() << __FUNCTION__ << testPhase << ": Append and scroll";
191 massiveTestTimer->stop();
192 QObject::disconnect(sender: massiveTestTimer, signal: 0, receiver: this, member: 0);
193 QObject::connect(sender: massiveTestTimer, signal: &QTimer::timeout, receiver: this,
194 slot: &ScatterDataModifier::massiveTestAppendAndScroll);
195 m_chart->axisZ()->setRange(min: unitCount - visibleRange, max: unitCount);
196 massiveTestTimer->start(msec: 16);
197 break;
198 }
199 default:
200 QObject::disconnect(sender: massiveTestTimer, signal: 0, receiver: this, member: 0);
201 massiveTestTimer->stop();
202 qDebug() << __FUNCTION__ << testPhase << ": Resetting the test";
203 testPhase = -1;
204 }
205 testPhase++;
206}
207
208void ScatterDataModifier::massiveTestScroll()
209{
210 const int scrollAmount = 20;
211 int itemCount = m_chart->seriesList().at(i: 0)->dataProxy()->itemCount();
212 int min = m_chart->axisZ()->min() + scrollAmount;
213 int max = m_chart->axisZ()->max() + scrollAmount;
214 if (max >= itemCount / itemsPerUnit) {
215 max = max - min - 1;
216 min = 0;
217 }
218 m_chart->axisZ()->setRange(min, max);
219}
220
221void ScatterDataModifier::massiveTestAppendAndScroll()
222{
223 const int addedUnits = 50;
224 const int addedItems = itemsPerUnit * addedUnits;
225 int cacheSize = m_massiveTestCacheArray.size();
226 int itemCount = m_chart->seriesList().at(i: 0)->dataProxy()->itemCount();
227 static int cacheIndex = 0;
228
229 // Copy items from cache
230 QScatterDataArray appendArray;
231 appendArray.resize(asize: addedItems);
232
233 float zOffset = m_chart->seriesList().at(i: 0)->dataProxy()->itemAt(index: itemCount - 1)->z();
234 for (int i = 0; i < addedItems; i++) {
235 float currentZ = zOffset + float(qreal(i) * qreal(addedUnits) / qreal(addedItems));
236 appendArray[i] = m_massiveTestCacheArray.at(i: cacheIndex++);
237 appendArray[i].setZ(currentZ);
238 if (cacheIndex >= cacheSize)
239 cacheIndex = 0;
240 }
241
242 m_chart->seriesList().at(i: 0)->dataProxy()->addItems(items: appendArray);
243 int min = m_chart->axisZ()->min() + addedUnits;
244 int max = m_chart->axisZ()->max() + addedUnits;
245 m_chart->axisZ()->setRange(min, max);
246}
247
248void ScatterDataModifier::setFpsMeasurement(bool enable)
249{
250 m_chart->setMeasureFps(enable);
251}
252
253void ScatterDataModifier::testItemChanges()
254{
255 static int counter = 0;
256 const int rowCount = 12;
257 const int colCount = 10;
258 static QScatter3DSeries *series0 = 0;
259 static QScatter3DSeries *series1 = 0;
260 static QScatter3DSeries *series2 = 0;
261
262 switch (counter) {
263 case 0: {
264 qDebug() << __FUNCTION__ << counter << "Setup test";
265 foreach (QScatter3DSeries *series, m_chart->seriesList())
266 m_chart->removeSeries(series);
267 foreach (QValue3DAxis *axis, m_chart->axes())
268 deleteAxis(axis);
269 delete series0;
270 delete series1;
271 delete series2;
272 series0 = new QScatter3DSeries;
273 series1 = new QScatter3DSeries;
274 series2 = new QScatter3DSeries;
275 populateFlatSeries(series: series0, rows: rowCount, columns: colCount, value: 10.0f);
276 populateFlatSeries(series: series1, rows: rowCount, columns: colCount, value: 30.0f);
277 populateFlatSeries(series: series2, rows: rowCount, columns: colCount, value: 50.0f);
278 m_chart->axisX()->setRange(min: 3.0f, max: 6.0f);
279 m_chart->axisY()->setRange(min: 0.0f, max: 100.0f);
280 m_chart->axisZ()->setRange(min: 4.0f, max: 8.0f);
281 m_chart->addSeries(series: series0);
282 m_chart->addSeries(series: series1);
283 m_chart->addSeries(series: series2);
284 }
285 break;
286 case 1: {
287 qDebug() << __FUNCTION__ << counter << "Change single item, unselected";
288 int itemIndex = 3 * colCount + 5;
289 QScatterDataItem item = *series0->dataProxy()->itemAt(index: itemIndex);
290 item.setY(75.0f);
291 series0->dataProxy()->setItem(index: itemIndex, item);
292 }
293 break;
294 case 2: {
295 qDebug() << __FUNCTION__ << counter << "Change single item, selected";
296 int itemIndex = 4 * colCount + 4;
297 series1->setSelectedItem(itemIndex);
298 QScatterDataItem item = *series1->dataProxy()->itemAt(index: itemIndex);
299 item.setY(75.0f);
300 series1->dataProxy()->setItem(index: itemIndex, item);
301 }
302 break;
303 case 3: {
304 qDebug() << __FUNCTION__ << counter << "Change item outside visible area";
305 int itemIndex = 2;
306 QScatterDataItem item = *series1->dataProxy()->itemAt(index: itemIndex);
307 item.setY(75.0f);
308 series1->dataProxy()->setItem(index: itemIndex, item);
309 }
310 break;
311 case 4: {
312 qDebug() << __FUNCTION__ << counter << "Change single item from two series, unselected";
313 int itemIndex = 4 * colCount + 6;
314 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex);
315 QScatterDataItem item1 = *series1->dataProxy()->itemAt(index: itemIndex);
316 item0.setY(65.0f);
317 item1.setY(85.0f);
318 series0->dataProxy()->setItem(index: itemIndex, item: item0);
319 series1->dataProxy()->setItem(index: itemIndex, item: item1);
320 }
321 break;
322 case 5: {
323 qDebug() << __FUNCTION__ << counter << "Change single item from two series, one selected";
324 int itemIndex0 = 5 * colCount + 5;
325 int itemIndex1 = 4 * colCount + 4;
326 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex0);
327 QScatterDataItem item1 = *series1->dataProxy()->itemAt(index: itemIndex1);
328 item0.setY(65.0f);
329 item1.setY(85.0f);
330 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
331 series1->dataProxy()->setItem(index: itemIndex1, item: item1);
332 }
333 break;
334 case 6: {
335 qDebug() << __FUNCTION__ << counter << "Change single item from two series, one outside range";
336 int itemIndex0 = 6 * colCount + 6;
337 int itemIndex1 = 9 * colCount + 2;
338 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex0);
339 QScatterDataItem item1 = *series1->dataProxy()->itemAt(index: itemIndex1);
340 item0.setY(65.0f);
341 item1.setY(85.0f);
342 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
343 series1->dataProxy()->setItem(index: itemIndex1, item: item1);
344 }
345 break;
346 case 7: {
347 qDebug() << __FUNCTION__ << counter << "Change single item from two series, both outside range";
348 int itemIndex0 = 1 * colCount + 3;
349 int itemIndex1 = 9 * colCount + 2;
350 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex0);
351 QScatterDataItem item1 = *series1->dataProxy()->itemAt(index: itemIndex1);
352 item0.setY(65.0f);
353 item1.setY(85.0f);
354 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
355 series1->dataProxy()->setItem(index: itemIndex1, item: item1);
356 }
357 break;
358 case 8: {
359 qDebug() << __FUNCTION__ << counter << "Change item to same value as previously";
360 int itemIndex0 = 5 * colCount + 7;
361 int itemIndex1 = 4 * colCount + 7;
362 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex0);
363 QScatterDataItem item1 = *series1->dataProxy()->itemAt(index: itemIndex1);
364 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
365 series1->dataProxy()->setItem(index: itemIndex1, item: item1);
366 }
367 break;
368 case 9: {
369 qDebug() << __FUNCTION__ << counter << "Change 3 items on each series";
370 int itemIndex0 = 5 * colCount + 6;
371 int itemIndex1 = 4 * colCount + 6;
372 QScatterDataItem item00 = *series0->dataProxy()->itemAt(index: itemIndex0);
373 QScatterDataItem item01 = *series0->dataProxy()->itemAt(index: itemIndex0 + 1);
374 QScatterDataItem item02 = *series0->dataProxy()->itemAt(index: itemIndex0 + 2);
375 QScatterDataItem item10 = *series1->dataProxy()->itemAt(index: itemIndex1);
376 QScatterDataItem item11 = *series1->dataProxy()->itemAt(index: itemIndex1 + 1);
377 QScatterDataItem item12 = *series1->dataProxy()->itemAt(index: itemIndex1 + 2);
378 item00.setY(65.0f);
379 item01.setY(70.0f);
380 item02.setY(75.0f);
381 item10.setY(80.0f);
382 item11.setY(85.0f);
383 item12.setY(90.0f);
384 series0->dataProxy()->setItem(index: itemIndex0, item: item00);
385 series0->dataProxy()->setItem(index: itemIndex0 + 1, item: item01);
386 series0->dataProxy()->setItem(index: itemIndex0 + 2, item: item02);
387 series1->dataProxy()->setItem(index: itemIndex1, item: item10);
388 series1->dataProxy()->setItem(index: itemIndex1 + 1, item: item11);
389 series1->dataProxy()->setItem(index: itemIndex1 + 2, item: item12);
390 }
391 break;
392 case 10: {
393 qDebug() << __FUNCTION__ << counter << "Level the field single item at a time";
394 QScatterDataItem item;
395 for (int i = 0; i < rowCount; i++) {
396 for (int j = 0; j < colCount; j++) {
397 int itemIndex = i * colCount + j;
398 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex);
399 QScatterDataItem item1 = *series1->dataProxy()->itemAt(index: itemIndex);
400 QScatterDataItem item2 = *series2->dataProxy()->itemAt(index: itemIndex);
401 item0.setY(10.0f);
402 item1.setY(15.0f);
403 item2.setY(20.0f);
404 series0->dataProxy()->setItem(index: itemIndex, item: item0);
405 series1->dataProxy()->setItem(index: itemIndex, item: item1);
406 series2->dataProxy()->setItem(index: itemIndex, item: item2);
407 }
408 }
409 }
410 break;
411 case 11: {
412 qDebug() << __FUNCTION__ << counter << "Change same items multiple times";
413 int itemIndex0 = 6 * colCount + 6;
414 QScatterDataItem item0 = *series0->dataProxy()->itemAt(index: itemIndex0);
415 item0.setY(90.0f);
416 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
417 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
418 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
419 series0->dataProxy()->setItem(index: itemIndex0, item: item0);
420 }
421 break;
422 default:
423 qDebug() << __FUNCTION__ << "Resetting test";
424 counter = -1;
425 }
426 counter++;
427}
428
429void ScatterDataModifier::testAxisReverse()
430{
431 static int counter = 0;
432 const int rowCount = 16;
433 const int colCount = 16;
434 static QScatter3DSeries *series0 = 0;
435 static QScatter3DSeries *series1 = 0;
436
437 switch (counter) {
438 case 0: {
439 qDebug() << __FUNCTION__ << counter << "Setup test";
440 foreach (QScatter3DSeries *series, m_chart->seriesList())
441 m_chart->removeSeries(series);
442 foreach (QValue3DAxis *axis, m_chart->axes())
443 deleteAxis(axis);
444 delete series0;
445 delete series1;
446 series0 = new QScatter3DSeries;
447 series1 = new QScatter3DSeries;
448 populateRisingSeries(series: series0, rows: rowCount, columns: colCount, minValue: 0.0f, maxValue: 50.0f);
449 populateRisingSeries(series: series1, rows: rowCount, columns: colCount, minValue: -20.0f, maxValue: 30.0f);
450 m_chart->axisX()->setRange(min: 0.0f, max: 10.0f);
451 m_chart->axisY()->setRange(min: -20.0f, max: 50.0f);
452 m_chart->axisZ()->setRange(min: 5.0f, max: 15.0f);
453 m_chart->axisX()->setTitle("Axis X");
454 m_chart->axisZ()->setTitle("Axis Z");
455 m_chart->axisX()->setTitleVisible(true);
456 m_chart->axisZ()->setTitleVisible(true);
457 m_chart->addSeries(series: series0);
458 m_chart->addSeries(series: series1);
459 }
460 break;
461 case 1: {
462 qDebug() << __FUNCTION__ << counter << "Reverse X axis";
463 m_chart->axisX()->setReversed(true);
464 }
465 break;
466 case 2: {
467 qDebug() << __FUNCTION__ << counter << "Reverse Y axis";
468 m_chart->axisY()->setReversed(true);
469 }
470 break;
471 case 3: {
472 qDebug() << __FUNCTION__ << counter << "Reverse Z axis";
473 m_chart->axisZ()->setReversed(true);
474 }
475 break;
476 case 4: {
477 qDebug() << __FUNCTION__ << counter << "Return all axes to normal";
478 m_chart->axisX()->setReversed(false);
479 m_chart->axisY()->setReversed(false);
480 m_chart->axisZ()->setReversed(false);
481 }
482 break;
483 case 5: {
484 qDebug() << __FUNCTION__ << counter << "Reverse all axes";
485 m_chart->axisX()->setReversed(true);
486 m_chart->axisY()->setReversed(true);
487 m_chart->axisZ()->setReversed(true);
488 }
489 break;
490 default:
491 qDebug() << __FUNCTION__ << "Resetting test";
492 counter = -1;
493 }
494 counter++;
495}
496
497void ScatterDataModifier::addData()
498{
499 // Add labels
500 m_chart->axisX()->setTitle("X - Axis");
501 m_chart->axisY()->setTitle("Y - Axis");
502 m_chart->axisZ()->setTitle("Z - Axis");
503 m_chart->axisX()->setRange(min: -50.0f, max: 50.0f);
504 m_chart->axisY()->setRange(min: -1.0f, max: 1.2f);
505 m_chart->axisZ()->setRange(min: -50.0f, max: 50.0f);
506 m_chart->axisX()->setSegmentCount(5);
507 m_chart->axisY()->setSegmentCount(4);
508 m_chart->axisZ()->setSegmentCount(10);
509 m_chart->axisX()->setSubSegmentCount(2);
510 m_chart->axisY()->setSubSegmentCount(3);
511 m_chart->axisZ()->setSubSegmentCount(1);
512
513 QScatterDataArray *dataArray = new QScatterDataArray;
514 dataArray->resize(asize: numberOfItems);
515 QScatterDataItem *ptrToDataArray = &dataArray->first();
516 QScatterDataArray *dataArray2 = new QScatterDataArray;
517 dataArray2->resize(asize: numberOfItems);
518 QScatterDataItem *ptrToDataArray2 = &dataArray2->first();
519
520#ifdef RANDOM_SCATTER
521 for (int i = 0; i < numberOfItems; i++) {
522 ptrToDataArray->setPosition(randVector());
523 ptrToDataArray++;
524 ptrToDataArray2->setPosition(randVector());
525 ptrToDataArray2++;
526 }
527#else
528 float limit = qSqrt(v: numberOfItems) / 2.0f;
529 for (float i = -limit; i < limit; i++) {
530 for (float j = -limit; j < limit; j++) {
531 ptrToDataArray->setPosition(QVector3D(i, qCos(v: qDegreesToRadians(degrees: (i * j) / 7.5)), j));
532 ptrToDataArray++;
533 ptrToDataArray2->setPosition(QVector3D(i, qCos(v: qDegreesToRadians(degrees: (i * j) / 7.5)) + 0.2, j));
534 ptrToDataArray2++;
535 }
536 }
537#endif
538
539 m_chart->seriesList().at(i: 0)->dataProxy()->resetArray(newArray: dataArray);
540 m_chart->seriesList().at(i: 1)->dataProxy()->resetArray(newArray: dataArray2);
541 m_chart->seriesList().at(i: 0)->setItemSize(0.0f);
542 m_chart->seriesList().at(i: 1)->setItemSize(0.0f);
543}
544
545void ScatterDataModifier::changeStyle()
546{
547 if (!m_targetSeries)
548 createAndAddSeries();
549
550 if (m_targetSeries->isMeshSmooth()) {
551 m_targetSeries->setMeshSmooth(false);
552 switch (m_targetSeries->mesh()) {
553 case QAbstract3DSeries::MeshCube:
554 m_targetSeries->setMesh(QAbstract3DSeries::MeshPyramid);
555 break;
556 case QAbstract3DSeries::MeshPyramid:
557 m_targetSeries->setMesh(QAbstract3DSeries::MeshCone);
558 break;
559 case QAbstract3DSeries::MeshCone:
560 m_targetSeries->setMesh(QAbstract3DSeries::MeshCylinder);
561 break;
562 case QAbstract3DSeries::MeshCylinder:
563 m_targetSeries->setMesh(QAbstract3DSeries::MeshBevelCube);
564 break;
565 case QAbstract3DSeries::MeshBevelCube:
566 m_targetSeries->setMesh(QAbstract3DSeries::MeshSphere);
567 break;
568 case QAbstract3DSeries::MeshSphere:
569 m_targetSeries->setMesh(QAbstract3DSeries::MeshMinimal);
570 break;
571 case QAbstract3DSeries::MeshMinimal:
572 m_targetSeries->setMesh(QAbstract3DSeries::MeshPoint);
573 break;
574 default:
575 m_targetSeries->setMesh(QAbstract3DSeries::MeshCube);
576 break;
577 }
578 } else {
579 m_targetSeries->setMeshSmooth(true);
580 }
581
582 qDebug() << __FUNCTION__ << m_targetSeries->mesh() << m_targetSeries->isMeshSmooth();
583}
584
585void ScatterDataModifier::changePresetCamera()
586{
587 static int preset = Q3DCamera::CameraPresetFrontLow;
588
589 m_chart->scene()->activeCamera()->setCameraPreset((Q3DCamera::CameraPreset)preset);
590
591 if (++preset > Q3DCamera::CameraPresetDirectlyAboveCCW45)
592 preset = Q3DCamera::CameraPresetFrontLow;
593}
594
595void ScatterDataModifier::changeTheme()
596{
597 static int theme = Q3DTheme::ThemeQt;
598
599 m_chart->activeTheme()->setType(Q3DTheme::Theme(theme));
600
601 if (++theme > Q3DTheme::ThemeIsabelle)
602 theme = Q3DTheme::ThemeQt;
603}
604
605void ScatterDataModifier::changeLabelStyle()
606{
607 m_chart->activeTheme()->setLabelBackgroundEnabled(!m_chart->activeTheme()->isLabelBackgroundEnabled());
608}
609
610void ScatterDataModifier::changeFont(const QFont &font)
611{
612 QFont newFont = font;
613 newFont.setPointSizeF(m_fontSize);
614 m_chart->activeTheme()->setFont(newFont);
615}
616
617void ScatterDataModifier::changeFontSize(int fontSize)
618{
619 m_fontSize = fontSize;
620 QFont font = m_chart->activeTheme()->font();
621 font.setPointSize(m_fontSize);
622 m_chart->activeTheme()->setFont(font);
623}
624
625void ScatterDataModifier::changePointSize(int pointSize)
626{
627 m_targetSeries->setItemSize(0.01f * float(pointSize));
628}
629
630void ScatterDataModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality sq)
631{
632 int quality = int(sq);
633 // Updates the UI component to show correct shadow quality
634 emit shadowQualityChanged(quality);
635}
636
637void ScatterDataModifier::clear()
638{
639 foreach (QScatter3DSeries *series, m_chart->seriesList()) {
640 m_chart->removeSeries(series);
641 delete series;
642 }
643
644 m_targetSeries = 0;
645
646 qDebug() << m_loopCounter << "Cleared array";
647}
648
649void ScatterDataModifier::deleteAxis(QValue3DAxis *axis)
650{
651 m_chart->releaseAxis(axis);
652 delete axis;
653}
654
655void ScatterDataModifier::resetAxes()
656{
657 deleteAxis(axis: m_chart->axisX());
658 deleteAxis(axis: m_chart->axisY());
659 deleteAxis(axis: m_chart->axisZ());
660
661 m_chart->setAxisX(new QValue3DAxis);
662 m_chart->setAxisY(new QValue3DAxis);
663 m_chart->setAxisZ(new QValue3DAxis);
664 m_chart->axisX()->setSegmentCount(6);
665 m_chart->axisY()->setSegmentCount(4);
666 m_chart->axisZ()->setSegmentCount(9);
667 m_chart->axisX()->setSubSegmentCount(2);
668 m_chart->axisY()->setSubSegmentCount(3);
669 m_chart->axisZ()->setSubSegmentCount(1);
670 m_chart->axisX()->setTitle("X");
671 m_chart->axisY()->setTitle("Y");
672 m_chart->axisZ()->setTitle("Z");
673}
674
675void ScatterDataModifier::addOne()
676{
677 if (!m_targetSeries)
678 createAndAddSeries();
679
680 QScatterDataItem item(randVector());
681 int addIndex = m_targetSeries->dataProxy()->addItem(item);
682 qDebug() << m_loopCounter << "added one to index:" << addIndex << "array size:" << m_targetSeries->dataProxy()->array()->size();
683}
684
685void ScatterDataModifier::addBunch()
686{
687 if (!m_targetSeries)
688 createAndAddSeries();
689
690 QScatterDataArray items(100);
691 for (int i = 0; i < items.size(); i++)
692 items[i].setPosition(randVector());
693 int addIndex = m_targetSeries->dataProxy()->addItems(items);
694 qDebug() << m_loopCounter << "added bunch to index:" << addIndex << "array size:" << m_targetSeries->dataProxy()->array()->size();
695}
696
697void ScatterDataModifier::insertOne()
698{
699 if (!m_targetSeries)
700 createAndAddSeries();
701
702 QScatterDataItem item(randVector());
703 m_targetSeries->dataProxy()->insertItem(index: 0, item);
704 qDebug() << m_loopCounter << "Inserted one, array size:" << m_targetSeries->dataProxy()->array()->size();
705}
706
707void ScatterDataModifier::insertBunch()
708{
709 if (!m_targetSeries)
710 createAndAddSeries();
711
712 QScatterDataArray items(100);
713 for (int i = 0; i < items.size(); i++)
714 items[i].setPosition(randVector());
715 m_targetSeries->dataProxy()->insertItems(index: 0, items);
716 qDebug() << m_loopCounter << "Inserted bunch, array size:" << m_targetSeries->dataProxy()->array()->size();
717}
718
719void ScatterDataModifier::changeOne()
720{
721 if (!m_targetSeries)
722 createAndAddSeries();
723
724 if (m_selectedItem >= 0 && m_selectedItem < m_targetSeries->dataProxy()->itemCount()) {
725 QScatterDataItem item(randVector());
726 m_targetSeries->dataProxy()->setItem(index: m_selectedItem, item);
727 qDebug() << m_loopCounter << "Changed one, array size:" << m_targetSeries->dataProxy()->array()->size();
728 }
729}
730
731void ScatterDataModifier::changeBunch()
732{
733 if (!m_targetSeries)
734 createAndAddSeries();
735
736 if (m_targetSeries->dataProxy()->array()->size()) {
737 int amount = qMin(a: m_targetSeries->dataProxy()->array()->size(), b: 100);
738 QScatterDataArray items(amount);
739 for (int i = 0; i < items.size(); i++) {
740 items[i].setPosition(randVector());
741 // Change the Y-values of first few items to exact gradient boundaries
742 if (i == 0)
743 items[i].setY(0.65f);
744 else if (i == 1)
745 items[i].setY(0.1f);
746 else if (i == 2)
747 items[i].setY(-0.45f);
748 else if (i == 3)
749 items[i].setY(-1.0f);
750 else if (i == 4)
751 items[i].setY(1.2f);
752// else
753// items[i].setY(0.1001f - (0.00001f * float(i)));
754
755 }
756
757 m_targetSeries->dataProxy()->setItems(index: 0, items);
758 qDebug() << m_loopCounter << "Changed bunch, array size:" << m_targetSeries->dataProxy()->array()->size();
759 }
760}
761
762void ScatterDataModifier::removeOne()
763{
764 if (!m_targetSeries)
765 createAndAddSeries();
766
767 if (m_selectedItem >= 0) {
768 m_targetSeries->dataProxy()->removeItems(index: m_selectedItem, removeCount: 1);
769 qDebug() << m_loopCounter << "Removed one, array size:" << m_targetSeries->dataProxy()->array()->size();
770 }
771}
772
773void ScatterDataModifier::removeBunch()
774{
775 if (!m_targetSeries)
776 createAndAddSeries();
777
778 m_targetSeries->dataProxy()->removeItems(index: 0, removeCount: 100);
779 qDebug() << m_loopCounter << "Removed bunch, array size:" << m_targetSeries->dataProxy()->array()->size();
780}
781
782void ScatterDataModifier::timeout()
783{
784 int doWhat = QRandomGenerator::global()->bounded(highest: 10);
785 if (!(QRandomGenerator::global()->bounded(highest: 100)))
786 doWhat = -1;
787
788 switch (doWhat) {
789 case 0:
790 addOne();
791 break;
792 case 1:
793 addBunch();
794 break;
795 case 2:
796 insertOne();
797 break;
798 case 3:
799 insertBunch();
800 break;
801 case 4:
802 changeOne();
803 break;
804 case 5:
805 changeBunch();
806 break;
807 case 6:
808 removeOne();
809 break;
810 case 7:
811 removeBunch();
812 break;
813 case 8:
814 addSeries();
815 break;
816 case 9:
817 if (m_chart->seriesList().size())
818 m_targetSeries = m_chart->seriesList().at(i: QRandomGenerator::global()->bounded(highest: m_chart->seriesList().size()));
819 else
820 addSeries();
821 break;
822 default:
823 clear();
824 break;
825 }
826
827 m_loopCounter++;
828}
829
830void ScatterDataModifier::startStopTimer()
831{
832 if (m_timer.isActive()) {
833 m_timer.stop();
834 } else {
835 clear();
836 m_loopCounter = 0;
837 m_timer.start(msec: 0);
838 }
839}
840
841void ScatterDataModifier::selectItem()
842{
843 if (!m_targetSeries)
844 createAndAddSeries();
845
846 int targetItem(3);
847 int noSelection(-1);
848 if (m_selectedItem != targetItem || m_targetSeries != m_chart->seriesList().at(i: 0))
849 m_chart->seriesList().at(i: 0)->setSelectedItem(targetItem);
850 else
851 m_chart->seriesList().at(i: 0)->setSelectedItem(noSelection);
852}
853
854void ScatterDataModifier::handleSelectionChange(int index)
855{
856 m_selectedItem = index;
857 m_targetSeries = static_cast<QScatter3DSeries *>(sender());
858 int seriesIndex = 0;
859 foreach (QScatter3DSeries *series, m_chart->seriesList()) {
860 if (series == sender())
861 break;
862 seriesIndex++;
863 }
864
865 qDebug() << "Selected item index:" << index << "series:" << seriesIndex;
866}
867
868void ScatterDataModifier::setGradient()
869{
870 QLinearGradient baseGradient(0, 0, 1, 100);
871 baseGradient.setColorAt(pos: 1.0, color: Qt::lightGray);
872 baseGradient.setColorAt(pos: 0.75001, color: Qt::lightGray);
873 baseGradient.setColorAt(pos: 0.75, color: Qt::blue);
874 baseGradient.setColorAt(pos: 0.50001, color: Qt::blue);
875 baseGradient.setColorAt(pos: 0.50, color: Qt::red);
876 baseGradient.setColorAt(pos: 0.25001, color: Qt::red);
877 baseGradient.setColorAt(pos: 0.25, color: Qt::yellow);
878 baseGradient.setColorAt(pos: 0.0, color: Qt::yellow);
879
880 QLinearGradient singleHighlightGradient(0, 0, 1, 100);
881 singleHighlightGradient.setColorAt(pos: 1.0, color: Qt::lightGray);
882 singleHighlightGradient.setColorAt(pos: 0.75, color: Qt::blue);
883 singleHighlightGradient.setColorAt(pos: 0.50, color: Qt::red);
884 singleHighlightGradient.setColorAt(pos: 0.25, color: Qt::yellow);
885 singleHighlightGradient.setColorAt(pos: 0.0, color: Qt::white);
886
887 if (m_targetSeries) {
888 m_targetSeries->setBaseColor(Qt::green);
889 m_targetSeries->setSingleHighlightColor(Qt::white);
890
891 m_targetSeries->setBaseGradient(baseGradient);
892 m_targetSeries->setSingleHighlightGradient(singleHighlightGradient);
893
894 Q3DTheme::ColorStyle oldStyle = m_targetSeries->colorStyle();
895 if (oldStyle == Q3DTheme::ColorStyleUniform)
896 m_targetSeries->setColorStyle(Q3DTheme::ColorStyleObjectGradient);
897 else if (oldStyle == Q3DTheme::ColorStyleObjectGradient)
898 m_targetSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
899 if (oldStyle == Q3DTheme::ColorStyleRangeGradient)
900 m_targetSeries->setColorStyle(Q3DTheme::ColorStyleUniform);
901 }
902}
903
904void ScatterDataModifier::clearSeriesData()
905{
906 if (m_targetSeries)
907 m_targetSeries->dataProxy()->resetArray(newArray: 0);
908}
909
910void ScatterDataModifier::addSeries()
911{
912 QScatter3DSeries *series = createAndAddSeries();
913
914 QScatter3DSeries *oldTargetSeries = m_targetSeries;
915 m_targetSeries = series; // adding always adds to target series, so fake it for a bit
916 addOne(); // add one random item to start the new series off
917 m_targetSeries = oldTargetSeries;
918}
919
920void ScatterDataModifier::removeSeries()
921{
922 if (m_targetSeries) {
923 m_chart->removeSeries(series: m_targetSeries);
924 delete m_targetSeries;
925 if (m_chart->seriesList().size())
926 m_targetSeries = m_chart->seriesList().at(i: 0);
927 else
928 m_targetSeries = 0;
929 }
930}
931
932void ScatterDataModifier::toggleSeriesVisibility()
933{
934 if (m_targetSeries)
935 m_targetSeries->setVisible(!m_targetSeries->isVisible());
936}
937
938void ScatterDataModifier::changeSeriesName()
939{
940 if (m_targetSeries)
941 m_targetSeries->setName(m_targetSeries->name().append(s: "-").append(s: QString::number(QRandomGenerator::global()->bounded(highest: 10))));
942}
943
944void ScatterDataModifier::handleAxisXChanged(QValue3DAxis *axis)
945{
946 qDebug() << __FUNCTION__ << axis << axis->orientation() << (axis == m_chart->axisX());
947}
948
949void ScatterDataModifier::handleAxisYChanged(QValue3DAxis *axis)
950{
951 qDebug() << __FUNCTION__ << axis << axis->orientation() << (axis == m_chart->axisY());
952}
953
954void ScatterDataModifier::handleAxisZChanged(QValue3DAxis *axis)
955{
956 qDebug() << __FUNCTION__ << axis << axis->orientation() << (axis == m_chart->axisZ());
957}
958
959void ScatterDataModifier::handleFpsChange(qreal fps)
960{
961 static const QString fpsPrefix(QStringLiteral("FPS: "));
962 m_fpsLabel->setText(fpsPrefix + QString::number(qRound(d: fps)));
963}
964
965void ScatterDataModifier::changeLabelRotation(int rotation)
966{
967 m_chart->axisX()->setLabelAutoRotation(float(rotation));
968 m_chart->axisY()->setLabelAutoRotation(float(rotation));
969 m_chart->axisZ()->setLabelAutoRotation(float(rotation));
970}
971
972void ScatterDataModifier::changeRadialLabelOffset(int offset)
973{
974 m_chart->setRadialLabelOffset(float(offset) / 100.0f);
975}
976
977void ScatterDataModifier::toggleAxisTitleVisibility(bool enabled)
978{
979 m_chart->axisX()->setTitleVisible(enabled);
980 m_chart->axisY()->setTitleVisible(enabled);
981 m_chart->axisZ()->setTitleVisible(enabled);
982}
983
984void ScatterDataModifier::toggleAxisTitleFixed(bool enabled)
985{
986 m_chart->axisX()->setTitleFixed(enabled);
987 m_chart->axisY()->setTitleFixed(enabled);
988 m_chart->axisZ()->setTitleFixed(enabled);
989}
990
991void ScatterDataModifier::renderToImage()
992{
993 QImage renderedImage8AA = m_chart->renderToImage(msaaSamples: 8);
994 QImage renderedImageNoAA = m_chart->renderToImage(msaaSamples: 0);
995 QImage renderedImage8AASmall = m_chart->renderToImage(msaaSamples: 8, imageSize: QSize(100, 100));
996 QImage renderedImageNoAASmall = m_chart->renderToImage(msaaSamples: 0, imageSize: QSize(100, 100));
997
998 if (m_chart->isVisible()) {
999 renderedImage8AA.save(QStringLiteral("./renderedImage8AA_visible.png"));
1000 renderedImageNoAA.save(QStringLiteral("./renderedImageNoAA_visible.png"));
1001 renderedImage8AASmall.save(QStringLiteral("./renderedImage8AASmall_visible.png"));
1002 renderedImageNoAASmall.save(QStringLiteral("./renderedImageNoAASmall_visible.png"));
1003 qDebug() << "Visible images rendered!";
1004 } else {
1005 renderedImage8AA.save(QStringLiteral("./renderedImage8AA_hidden.png"));
1006 renderedImageNoAA.save(QStringLiteral("./renderedImageNoAA_hidden.png"));
1007 renderedImage8AASmall.save(QStringLiteral("./renderedImage8AASmall_hidden.png"));
1008 renderedImageNoAASmall.save(QStringLiteral("./renderedImageNoAASmall_hidden.png"));
1009 qDebug() << "Hidden images rendered!";
1010 }
1011}
1012
1013void ScatterDataModifier::togglePolar(bool enable)
1014{
1015 m_chart->setPolar(enable);
1016}
1017
1018void ScatterDataModifier::toggleStatic(bool enable)
1019{
1020 if (enable)
1021 m_chart->setOptimizationHints(QAbstract3DGraph::OptimizationStatic);
1022 else
1023 m_chart->setOptimizationHints(QAbstract3DGraph::OptimizationDefault);
1024}
1025
1026void ScatterDataModifier::toggleOrtho(bool enable)
1027{
1028 m_chart->setOrthoProjection(enable);
1029}
1030
1031void ScatterDataModifier::setCameraTargetX(int value)
1032{
1033 // Value is (-100, 100), normalize
1034 m_cameraTarget.setX(float(value) / 100.0f);
1035 m_chart->scene()->activeCamera()->setTarget(m_cameraTarget);
1036 qDebug() << "m_cameraTarget:" << m_cameraTarget;
1037}
1038
1039void ScatterDataModifier::setCameraTargetY(int value)
1040{
1041 // Value is (-100, 100), normalize
1042 m_cameraTarget.setY(float(value) / 100.0f);
1043 m_chart->scene()->activeCamera()->setTarget(m_cameraTarget);
1044 qDebug() << "m_cameraTarget:" << m_cameraTarget;
1045}
1046
1047void ScatterDataModifier::setCameraTargetZ(int value)
1048{
1049 // Value is (-100, 100), normalize
1050 m_cameraTarget.setZ(float(value) / 100.0f);
1051 m_chart->scene()->activeCamera()->setTarget(m_cameraTarget);
1052 qDebug() << "m_cameraTarget:" << m_cameraTarget;
1053}
1054
1055void ScatterDataModifier::setGraphMargin(int value)
1056{
1057 m_chart->setMargin(qreal(value) / 100.0);
1058 qDebug() << "Setting margin:" << m_chart->margin() << value;
1059}
1060
1061void ScatterDataModifier::changeShadowQuality(int quality)
1062{
1063 QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality);
1064 m_chart->setShadowQuality(sq);
1065 emit shadowQualityChanged(quality);
1066}
1067
1068void ScatterDataModifier::setBackgroundEnabled(int enabled)
1069{
1070 m_chart->activeTheme()->setBackgroundEnabled((bool)enabled);
1071}
1072
1073void ScatterDataModifier::setGridEnabled(int enabled)
1074{
1075 m_chart->activeTheme()->setGridEnabled((bool)enabled);
1076}
1077
1078void ScatterDataModifier::setMinX(int min)
1079{
1080 m_chart->axisX()->setMin(min);
1081}
1082
1083void ScatterDataModifier::setMinY(int min)
1084{
1085 m_chart->axisY()->setMin(float(min) / 100.0f);
1086}
1087
1088void ScatterDataModifier::setMinZ(int min)
1089{
1090 m_chart->axisZ()->setMin(min);
1091}
1092
1093void ScatterDataModifier::setMaxX(int max)
1094{
1095 m_chart->axisX()->setMax(max);
1096}
1097
1098void ScatterDataModifier::setMaxY(int max)
1099{
1100 m_chart->axisY()->setMax(float(max) / 100.0f);
1101}
1102
1103void ScatterDataModifier::setMaxZ(int max)
1104{
1105 m_chart->axisZ()->setMax(max);
1106}
1107
1108void ScatterDataModifier::setAspectRatio(int ratio)
1109{
1110 qreal aspectRatio = qreal(ratio) / 10.0;
1111 m_chart->setAspectRatio(aspectRatio);
1112}
1113
1114void ScatterDataModifier::setHorizontalAspectRatio(int ratio)
1115{
1116 qreal aspectRatio = qreal(ratio) / 100.0;
1117 m_chart->setHorizontalAspectRatio(aspectRatio);
1118}
1119
1120QVector3D ScatterDataModifier::randVector()
1121{
1122 QVector3D retvec = QVector3D(
1123 (float)(QRandomGenerator::global()->bounded(highest: 100)) / 2.0f - (float)(QRandomGenerator::global()->bounded(highest: 100)) / 2.0f,
1124 (float)(QRandomGenerator::global()->bounded(highest: 100)) / 100.0f - (float)(QRandomGenerator::global()->bounded(highest: 100)) / 100.0f,
1125 (float)(QRandomGenerator::global()->bounded(highest: 100)) / 2.0f - (float)(QRandomGenerator::global()->bounded(highest: 100)) / 2.0f);
1126
1127 qDebug() << __FUNCTION__ << retvec;
1128
1129 return retvec;
1130}
1131
1132QScatter3DSeries *ScatterDataModifier::createAndAddSeries()
1133{
1134 static int counter = 0;
1135
1136 QScatter3DSeries *series = new QScatter3DSeries;
1137
1138 if (!m_targetSeries)
1139 m_targetSeries = series;
1140
1141 m_chart->addSeries(series);
1142 series->setName(QString("Series %1").arg(a: counter++));
1143 series->setItemLabelFormat(QStringLiteral("@seriesName: (X:@xLabel / Z:@zLabel) Y:@yLabel"));
1144 series->setMesh(QAbstract3DSeries::MeshSphere);
1145 series->setMeshSmooth(true);
1146 series->setBaseColor(QColor(QRandomGenerator::global()->bounded(highest: 256), QRandomGenerator::global()->bounded(highest: 256), QRandomGenerator::global()->bounded(highest: 256)));
1147 series->setItemSize(float(QRandomGenerator::global()->bounded(highest: 90) + 10) / 100.0f);
1148
1149 QObject::connect(sender: series, signal: &QScatter3DSeries::selectedItemChanged, receiver: this,
1150 slot: &ScatterDataModifier::handleSelectionChange);
1151
1152 return series;
1153}
1154
1155void ScatterDataModifier::populateFlatSeries(QScatter3DSeries *series, int rows, int columns,
1156 float value)
1157{
1158 QScatterDataArray *dataArray = new QScatterDataArray;
1159 dataArray->resize(asize: rows * columns);
1160 for (int i = 0; i < rows; i++) {
1161 for (int j = 0; j < columns; j++)
1162 (*dataArray)[i * columns + j].setPosition(QVector3D(float(i), value, float(j)));
1163 }
1164 series->dataProxy()->resetArray(newArray: dataArray);
1165}
1166
1167void ScatterDataModifier::populateRisingSeries(QScatter3DSeries *series, int rows, int columns,
1168 float minValue, float maxValue)
1169{
1170 QScatterDataArray *dataArray = new QScatterDataArray;
1171 int arraySize = rows * columns;
1172 dataArray->resize(asize: arraySize);
1173 float range = maxValue - minValue;
1174 for (int i = 0; i < rows; i++) {
1175 for (int j = 0; j < columns; j++) {
1176 float yValue = minValue + (range * i * j / arraySize);
1177 (*dataArray)[i * columns + j].setPosition(QVector3D(float(i), yValue, float(j)));
1178 }
1179 }
1180 series->dataProxy()->resetArray(newArray: dataArray);
1181}
1182

source code of qtdatavis3d/tests/manual/scattertest/scatterchart.cpp