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> |
40 | using namespace QtDataVisualization; |
41 | |
42 | //#define RANDOM_SCATTER |
43 | |
44 | const int numberOfItems = 10000; |
45 | |
46 | ScatterDataModifier::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 | |
84 | ScatterDataModifier::~ScatterDataModifier() |
85 | { |
86 | delete m_chart; |
87 | } |
88 | |
89 | void ScatterDataModifier::start() |
90 | { |
91 | addData(); |
92 | } |
93 | |
94 | static const int itemsPerUnit = 100; // "unit" is one unit range along Z-axis |
95 | |
96 | void 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 | |
208 | void 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 | |
221 | void 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 | |
248 | void ScatterDataModifier::setFpsMeasurement(bool enable) |
249 | { |
250 | m_chart->setMeasureFps(enable); |
251 | } |
252 | |
253 | void 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 | |
429 | void 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 | |
497 | void 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 | |
545 | void 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 | |
585 | void 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 | |
595 | void 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 | |
605 | void ScatterDataModifier::changeLabelStyle() |
606 | { |
607 | m_chart->activeTheme()->setLabelBackgroundEnabled(!m_chart->activeTheme()->isLabelBackgroundEnabled()); |
608 | } |
609 | |
610 | void ScatterDataModifier::changeFont(const QFont &font) |
611 | { |
612 | QFont newFont = font; |
613 | newFont.setPointSizeF(m_fontSize); |
614 | m_chart->activeTheme()->setFont(newFont); |
615 | } |
616 | |
617 | void 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 | |
625 | void ScatterDataModifier::changePointSize(int pointSize) |
626 | { |
627 | m_targetSeries->setItemSize(0.01f * float(pointSize)); |
628 | } |
629 | |
630 | void 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 | |
637 | void 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 | |
649 | void ScatterDataModifier::deleteAxis(QValue3DAxis *axis) |
650 | { |
651 | m_chart->releaseAxis(axis); |
652 | delete axis; |
653 | } |
654 | |
655 | void 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 | |
675 | void 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 | |
685 | void 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 | |
697 | void 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 | |
707 | void 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 | |
719 | void 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 | |
731 | void 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 | |
762 | void 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 | |
773 | void 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 | |
782 | void 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 | |
830 | void 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 | |
841 | void 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 | |
854 | void 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 | |
868 | void 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 | |
904 | void ScatterDataModifier::clearSeriesData() |
905 | { |
906 | if (m_targetSeries) |
907 | m_targetSeries->dataProxy()->resetArray(newArray: 0); |
908 | } |
909 | |
910 | void 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 | |
920 | void 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 | |
932 | void ScatterDataModifier::toggleSeriesVisibility() |
933 | { |
934 | if (m_targetSeries) |
935 | m_targetSeries->setVisible(!m_targetSeries->isVisible()); |
936 | } |
937 | |
938 | void 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 | |
944 | void ScatterDataModifier::handleAxisXChanged(QValue3DAxis *axis) |
945 | { |
946 | qDebug() << __FUNCTION__ << axis << axis->orientation() << (axis == m_chart->axisX()); |
947 | } |
948 | |
949 | void ScatterDataModifier::handleAxisYChanged(QValue3DAxis *axis) |
950 | { |
951 | qDebug() << __FUNCTION__ << axis << axis->orientation() << (axis == m_chart->axisY()); |
952 | } |
953 | |
954 | void ScatterDataModifier::handleAxisZChanged(QValue3DAxis *axis) |
955 | { |
956 | qDebug() << __FUNCTION__ << axis << axis->orientation() << (axis == m_chart->axisZ()); |
957 | } |
958 | |
959 | void ScatterDataModifier::handleFpsChange(qreal fps) |
960 | { |
961 | static const QString fpsPrefix(QStringLiteral("FPS: " )); |
962 | m_fpsLabel->setText(fpsPrefix + QString::number(qRound(d: fps))); |
963 | } |
964 | |
965 | void 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 | |
972 | void ScatterDataModifier::changeRadialLabelOffset(int offset) |
973 | { |
974 | m_chart->setRadialLabelOffset(float(offset) / 100.0f); |
975 | } |
976 | |
977 | void 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 | |
984 | void 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 | |
991 | void 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 | |
1013 | void ScatterDataModifier::togglePolar(bool enable) |
1014 | { |
1015 | m_chart->setPolar(enable); |
1016 | } |
1017 | |
1018 | void ScatterDataModifier::toggleStatic(bool enable) |
1019 | { |
1020 | if (enable) |
1021 | m_chart->setOptimizationHints(QAbstract3DGraph::OptimizationStatic); |
1022 | else |
1023 | m_chart->setOptimizationHints(QAbstract3DGraph::OptimizationDefault); |
1024 | } |
1025 | |
1026 | void ScatterDataModifier::toggleOrtho(bool enable) |
1027 | { |
1028 | m_chart->setOrthoProjection(enable); |
1029 | } |
1030 | |
1031 | void 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 | |
1039 | void 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 | |
1047 | void 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 | |
1055 | void ScatterDataModifier::setGraphMargin(int value) |
1056 | { |
1057 | m_chart->setMargin(qreal(value) / 100.0); |
1058 | qDebug() << "Setting margin:" << m_chart->margin() << value; |
1059 | } |
1060 | |
1061 | void ScatterDataModifier::changeShadowQuality(int quality) |
1062 | { |
1063 | QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality); |
1064 | m_chart->setShadowQuality(sq); |
1065 | emit shadowQualityChanged(quality); |
1066 | } |
1067 | |
1068 | void ScatterDataModifier::setBackgroundEnabled(int enabled) |
1069 | { |
1070 | m_chart->activeTheme()->setBackgroundEnabled((bool)enabled); |
1071 | } |
1072 | |
1073 | void ScatterDataModifier::setGridEnabled(int enabled) |
1074 | { |
1075 | m_chart->activeTheme()->setGridEnabled((bool)enabled); |
1076 | } |
1077 | |
1078 | void ScatterDataModifier::setMinX(int min) |
1079 | { |
1080 | m_chart->axisX()->setMin(min); |
1081 | } |
1082 | |
1083 | void ScatterDataModifier::setMinY(int min) |
1084 | { |
1085 | m_chart->axisY()->setMin(float(min) / 100.0f); |
1086 | } |
1087 | |
1088 | void ScatterDataModifier::setMinZ(int min) |
1089 | { |
1090 | m_chart->axisZ()->setMin(min); |
1091 | } |
1092 | |
1093 | void ScatterDataModifier::setMaxX(int max) |
1094 | { |
1095 | m_chart->axisX()->setMax(max); |
1096 | } |
1097 | |
1098 | void ScatterDataModifier::setMaxY(int max) |
1099 | { |
1100 | m_chart->axisY()->setMax(float(max) / 100.0f); |
1101 | } |
1102 | |
1103 | void ScatterDataModifier::setMaxZ(int max) |
1104 | { |
1105 | m_chart->axisZ()->setMax(max); |
1106 | } |
1107 | |
1108 | void ScatterDataModifier::setAspectRatio(int ratio) |
1109 | { |
1110 | qreal aspectRatio = qreal(ratio) / 10.0; |
1111 | m_chart->setAspectRatio(aspectRatio); |
1112 | } |
1113 | |
1114 | void ScatterDataModifier::setHorizontalAspectRatio(int ratio) |
1115 | { |
1116 | qreal aspectRatio = qreal(ratio) / 100.0; |
1117 | m_chart->setHorizontalAspectRatio(aspectRatio); |
1118 | } |
1119 | |
1120 | QVector3D 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 | |
1132 | QScatter3DSeries *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 | |
1155 | void 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 | |
1167 | void 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 | |