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 | #define NOMINMAX |
31 | |
32 | #include "data.h" |
33 | #include <QtDataVisualization/QValue3DAxis> |
34 | #include <QtDataVisualization/Q3DCamera> |
35 | #include <QtDataVisualization/QBar3DSeries> |
36 | #include <QtDataVisualization/QScatter3DSeries> |
37 | #include <QtDataVisualization/QSurface3DSeries> |
38 | #include <QtDataVisualization/Q3DTheme> |
39 | #include <QScrollBar> |
40 | #include <QSize> |
41 | #include <QImage> |
42 | |
43 | using namespace QtDataVisualization; |
44 | |
45 | Data::Data(Q3DSurface *surface, Q3DScatter *scatter, Q3DBars *bars, |
46 | QTextEdit *statusArea, QWidget *widget) : |
47 | m_surface(surface), |
48 | m_scatter(scatter), |
49 | m_bars(bars), |
50 | m_statusArea(statusArea), |
51 | m_widget(widget), |
52 | m_resize(true), |
53 | m_resolution(QSize(300, 300)), |
54 | m_resolutionLevel(0), |
55 | m_mode(Surface), |
56 | m_scatterDataArray(0), |
57 | m_barDataArray(0), |
58 | m_started(false) |
59 | { |
60 | // Initialize surface |
61 | m_surface->activeTheme()->setType(Q3DTheme::ThemeIsabelle); |
62 | QLinearGradient gradient; |
63 | gradient.setColorAt(pos: 0.0, color: Qt::black); |
64 | gradient.setColorAt(pos: 0.33, color: Qt::blue); |
65 | gradient.setColorAt(pos: 0.67, color: Qt::red); |
66 | gradient.setColorAt(pos: 1.0, color: Qt::yellow); |
67 | m_surface->setSelectionMode(QAbstract3DGraph::SelectionNone); |
68 | m_surface->activeTheme()->setGridEnabled(false); |
69 | m_surface->activeTheme()->setBackgroundEnabled(false); |
70 | m_surface->scene()->activeCamera()->setCameraPosition(horizontal: 0.0, vertical: 90.0, zoom: 150.0); |
71 | QSurface3DSeries *series1 = new QSurface3DSeries(new QHeightMapSurfaceDataProxy()); |
72 | series1->setFlatShadingEnabled(true); |
73 | series1->setDrawMode(QSurface3DSeries::DrawSurface); |
74 | series1->setColorStyle(Q3DTheme::ColorStyleRangeGradient); |
75 | series1->setBaseGradient(gradient); |
76 | m_surface->addSeries(series: series1); |
77 | |
78 | // Initialize scatter |
79 | m_scatter->activeTheme()->setType(Q3DTheme::ThemeStoneMoss); |
80 | m_scatter->setSelectionMode(QAbstract3DGraph::SelectionNone); |
81 | m_scatter->activeTheme()->setGridEnabled(false); |
82 | m_scatter->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow); |
83 | m_scatter->scene()->activeCamera()->setCameraPosition(horizontal: 0.0, vertical: 85.0, zoom: 150.0); |
84 | QScatter3DSeries *series2 = new QScatter3DSeries; |
85 | series2->setMesh(QAbstract3DSeries::MeshPoint); |
86 | m_scatter->addSeries(series: series2); |
87 | |
88 | // Initialize bars |
89 | m_bars->activeTheme()->setType(Q3DTheme::ThemeQt); |
90 | m_bars->setSelectionMode(QAbstract3DGraph::SelectionItemAndRow | QAbstract3DGraph::SelectionSlice); |
91 | m_bars->activeTheme()->setGridEnabled(false); |
92 | m_bars->setShadowQuality(QAbstract3DGraph::ShadowQualityLow); |
93 | m_bars->setBarSpacing(QSizeF(0.0, 0.0)); |
94 | m_bars->scene()->activeCamera()->setCameraPosition(horizontal: 0.0, vertical: 75.0, zoom: 150.0); |
95 | QBar3DSeries *series3 = new QBar3DSeries; |
96 | series3->setMesh(QAbstract3DSeries::MeshBar); |
97 | m_bars->addSeries(series: series3); |
98 | |
99 | // Hide scroll bar |
100 | m_statusArea->verticalScrollBar()->setVisible(false); |
101 | } |
102 | |
103 | Data::~Data() |
104 | { |
105 | delete m_bars; |
106 | delete m_surface; |
107 | delete m_scatter; |
108 | delete m_widget; |
109 | delete m_scatterDataArray; // only portion of this array is set to graph |
110 | } |
111 | |
112 | void Data::updateData() |
113 | { |
114 | if (!m_started) { |
115 | m_statusArea->append(QStringLiteral("<i>We are stopped. The changes will take effect once started.</i>" )); |
116 | return; |
117 | } |
118 | QImage depthMap = QImage(":/australia.png" ); |
119 | if (m_resize) // Resize for better performance |
120 | depthMap = depthMap.scaled(s: m_resolution); |
121 | if (m_mode != Surface) |
122 | setData(depthMap); |
123 | else |
124 | static_cast<QHeightMapSurfaceDataProxy *>(m_surface->seriesList().at(i: 0)->dataProxy())->setHeightMap( |
125 | depthMap); |
126 | } |
127 | |
128 | void Data::clearData() |
129 | { |
130 | m_bars->seriesList().at(i: 0)->dataProxy()->resetArray(newArray: 0); |
131 | m_scatter->seriesList().at(i: 0)->dataProxy()->resetArray(newArray: 0); |
132 | m_surface->seriesList().at(i: 0)->dataProxy()->resetArray(newArray: 0); |
133 | } |
134 | |
135 | void Data::setResolution(int selection) |
136 | { |
137 | m_resolutionLevel = selection; |
138 | switch (selection) { |
139 | case 0: { |
140 | m_resize = true; |
141 | m_resolution = QSize(300, 300); |
142 | break; |
143 | } |
144 | case 1: { |
145 | m_resize = true; |
146 | m_resolution = QSize(600, 600); |
147 | break; |
148 | } |
149 | case 2: { |
150 | m_resize = true; |
151 | m_resolution = QSize(800, 800); |
152 | break; |
153 | } |
154 | case 3: { |
155 | m_resize = false; |
156 | m_resolution = QSize(1020, 1020); // image size |
157 | break; |
158 | } |
159 | }; |
160 | if (m_mode == Scatter) { |
161 | m_resize = true; |
162 | m_resolution /= 3; |
163 | delete m_scatterDataArray; |
164 | m_scatterDataArray = new QScatterDataArray; |
165 | m_scatterDataArray->resize(asize: m_resolution.width() * m_resolution.height()); |
166 | } else if (m_mode == Bars) { |
167 | m_resize = true; |
168 | m_resolution /= 6; |
169 | m_barDataArray = new QBarDataArray; |
170 | m_barDataArray->reserve(alloc: m_resolution.height()); |
171 | for (int i = 0; i < m_resolution.height(); i++) { |
172 | QBarDataRow *newProxyRow = new QBarDataRow(m_resolution.width()); |
173 | m_barDataArray->append(t: newProxyRow); |
174 | } |
175 | } |
176 | |
177 | m_statusArea->append(text: QString(QStringLiteral("<b>Resolution:</b> %1 x %2" )).arg( |
178 | a: m_resolution.width()).arg(a: m_resolution.height())); |
179 | |
180 | updateData(); |
181 | } |
182 | |
183 | void Data::scrollDown() |
184 | { |
185 | QScrollBar *scrollbar = m_statusArea->verticalScrollBar(); |
186 | scrollbar->setValue(scrollbar->maximum()); |
187 | } |
188 | |
189 | void Data::useGradientOne() |
190 | { |
191 | m_surface->activeTheme()->setType(Q3DTheme::ThemeIsabelle); |
192 | QLinearGradient gradient; |
193 | gradient.setColorAt(pos: 0.0, color: Qt::black); |
194 | gradient.setColorAt(pos: 0.33, color: Qt::blue); |
195 | gradient.setColorAt(pos: 0.67, color: Qt::red); |
196 | gradient.setColorAt(pos: 1.0, color: Qt::yellow); |
197 | m_surface->seriesList().at(i: 0)->setBaseGradient(gradient); |
198 | m_surface->seriesList().at(i: 0)->setColorStyle(Q3DTheme::ColorStyleRangeGradient); |
199 | m_statusArea->append(QStringLiteral("<b>Colors:</b> Thermal image imitation" )); |
200 | } |
201 | |
202 | void Data::useGradientTwo() |
203 | { |
204 | m_surface->activeTheme()->setType(Q3DTheme::ThemeQt); |
205 | QLinearGradient gradient; |
206 | gradient.setColorAt(pos: 0.0, color: Qt::white); |
207 | gradient.setColorAt(pos: 0.8, color: Qt::red); |
208 | gradient.setColorAt(pos: 1.0, color: Qt::green); |
209 | m_surface->seriesList().at(i: 0)->setBaseGradient(gradient); |
210 | m_surface->seriesList().at(i: 0)->setColorStyle(Q3DTheme::ColorStyleRangeGradient); |
211 | m_statusArea->append(QStringLiteral("<b>Colors:</b> Highlight foreground" )); |
212 | } |
213 | |
214 | void Data::setData(const QImage &image) |
215 | { |
216 | QImage heightImage = image; |
217 | |
218 | uchar *bits = heightImage.bits(); |
219 | |
220 | int imageHeight = heightImage.height(); |
221 | int imageWidth = heightImage.width(); |
222 | int bitCount = imageWidth * 4 * (imageHeight - 1); |
223 | int widthBits = imageWidth * 4; |
224 | |
225 | if (m_mode == Scatter) { |
226 | QScatterDataItem *ptrToDataArray = &m_scatterDataArray->first(); |
227 | |
228 | int limitsX = imageWidth / 2; |
229 | int limitsZ = imageHeight / 2; |
230 | float height = 0; |
231 | int count = 0; |
232 | |
233 | for (int i = -limitsZ; i < limitsZ; i++, bitCount -= widthBits) { |
234 | for (int j = -limitsX; j < limitsX; j++) { |
235 | height = float(bits[bitCount + ((j + limitsX) * 4)]) - 128.0; |
236 | if (height > -128) { |
237 | ptrToDataArray->setPosition(QVector3D(float(j), height, float(i))); |
238 | ptrToDataArray++; |
239 | count++; |
240 | } |
241 | } |
242 | } |
243 | |
244 | QScatterDataArray *dataArray = new QScatterDataArray(m_scatterDataArray->mid(pos: 0, len: count)); |
245 | m_scatter->seriesList().at(i: 0)->dataProxy()->resetArray(newArray: dataArray); |
246 | } else { |
247 | QBarDataArray *dataArray = m_barDataArray; |
248 | for (int i = 0; i < imageHeight; i++, bitCount -= widthBits) { |
249 | QBarDataRow &newRow = *dataArray->at(i); |
250 | for (int j = 0; j < imageWidth; j++) |
251 | newRow[j] = float(bits[bitCount + (j * 4)]); |
252 | } |
253 | |
254 | m_bars->seriesList().at(i: 0)->dataProxy()->resetArray(newArray: dataArray); |
255 | } |
256 | } |
257 | |
258 | void Data::changeMode(int mode) |
259 | { |
260 | m_mode = VisualizationMode(mode); |
261 | switch (m_mode) { |
262 | case Surface: { |
263 | m_statusArea->append(QStringLiteral("<b>Visualization Type:</b> Surface" )); |
264 | break; |
265 | } |
266 | case Scatter: { |
267 | m_statusArea->append(QStringLiteral("<b>Visualization Type:</b> Scatter" )); |
268 | break; |
269 | } |
270 | default: { |
271 | m_statusArea->append(QStringLiteral("<b>Visualization Type:</b> Bars" )); |
272 | break; |
273 | } |
274 | } |
275 | // Reset resolution after mode change |
276 | setResolution(m_resolutionLevel); |
277 | } |
278 | |
279 | void Data::start() |
280 | { |
281 | m_started = true; |
282 | // Reset resolution before starting (otherwise restart will crash due to empty data) |
283 | setResolution(m_resolutionLevel); |
284 | updateData(); |
285 | m_statusArea->append(QStringLiteral("<b>Started<\b>" )); |
286 | } |
287 | |
288 | void Data::stop() |
289 | { |
290 | m_started = false; |
291 | clearData(); |
292 | m_statusArea->append(QStringLiteral("<b>Stopped<\b>" )); |
293 | } |
294 | |
295 | ContainerChanger::ContainerChanger(QWidget *surface, QWidget *scatter, QWidget *bars, |
296 | QWidget *buttonOne, QWidget *buttonTwo) |
297 | : m_surface(surface), |
298 | m_scatter(scatter), |
299 | m_bars(bars), |
300 | m_button1(buttonOne), |
301 | m_button2(buttonTwo) |
302 | { |
303 | } |
304 | |
305 | ContainerChanger::~ContainerChanger() |
306 | { |
307 | } |
308 | |
309 | void ContainerChanger::changeContainer(int container) |
310 | { |
311 | switch (container) { |
312 | case 0: { |
313 | m_scatter->setVisible(false); |
314 | m_bars->setVisible(false); |
315 | m_surface->setVisible(true); |
316 | m_button1->setEnabled(true); |
317 | m_button2->setEnabled(true); |
318 | break; |
319 | } |
320 | case 1: { |
321 | m_surface->setVisible(false); |
322 | m_bars->setVisible(false); |
323 | m_scatter->setVisible(true); |
324 | m_button1->setEnabled(false); |
325 | m_button2->setEnabled(false); |
326 | break; |
327 | } |
328 | case 2: { |
329 | m_surface->setVisible(false); |
330 | m_scatter->setVisible(false); |
331 | m_bars->setVisible(true); |
332 | m_button1->setEnabled(false); |
333 | m_button2->setEnabled(false); |
334 | break; |
335 | } |
336 | } |
337 | } |
338 | |