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 "q3dsurface.h"
31#include "q3dsurface_p.h"
32
33QT_BEGIN_NAMESPACE_DATAVISUALIZATION
34
35/*!
36 * \class Q3DSurface
37 * \inmodule QtDataVisualization
38 * \brief The Q3DSurface class provides methods for rendering 3D surface plots.
39 * \since QtDataVisualization 1.0
40 *
41 * This class enables developers to render 3D surface plots and to view them by rotating the scene
42 * freely. The visual properties of the surface such as draw mode and shading can be controlled
43 * via QSurface3DSeries.
44 *
45 * The Q3DSurface supports selection by showing a highlighted ball on the data point where the user has clicked
46 * with left mouse button (when default input handler is in use) or selected via QSurface3DSeries.
47 * The selection pointer is accompanied with a label which in default case shows the value of the
48 * data point and the coordinates of the point.
49 *
50 * The value range and the label format shown on the axis can be controlled through QValue3DAxis.
51 *
52 * To rotate the graph, hold down the right mouse button and move the mouse. Zooming is done using mouse
53 * wheel. Both assume the default input handler is in use.
54 *
55 * If no axes are set explicitly to Q3DSurface, temporary default axes with no labels are created.
56 * These default axes can be modified via axis accessors, but as soon any axis is set explicitly
57 * for the orientation, the default axis for that orientation is destroyed.
58 *
59 * \section1 How to construct a minimal Q3DSurface graph
60 *
61 * First, construct Q3DSurface. Since we are running the graph as top level window
62 * in this example, we need to clear the \c Qt::FramelessWindowHint flag, which gets set by
63 * default:
64 *
65 * \snippet doc_src_q3dsurface_construction.cpp 0
66 *
67 * Now Q3DSurface is ready to receive data to be rendered. Create data elements to receive values:
68 *
69 * \snippet doc_src_q3dsurface_construction.cpp 1
70 *
71 * First feed the data to the row elements and then add their pointers to the data element:
72 *
73 * \snippet doc_src_q3dsurface_construction.cpp 2
74 *
75 * Create a new series and set data to it:
76 *
77 * \snippet doc_src_q3dsurface_construction.cpp 3
78 *
79 * Finally you will need to set it visible:
80 *
81 * \snippet doc_src_q3dsurface_construction.cpp 4
82 *
83 * The complete code needed to create and display this graph is:
84 *
85 * \snippet doc_src_q3dsurface_construction.cpp 5
86 *
87 * And this is what those few lines of code produce:
88 *
89 * \image q3dsurface-minimal.png
90 *
91 * The scene can be rotated, zoomed into, and a surface point can be selected to view its position,
92 * but no other interaction is included in this minimal code example.
93 * You can learn more by familiarizing yourself with the examples provided,
94 * like the \l{Surface Example}.
95 *
96 *
97 * \sa Q3DBars, Q3DScatter, {Qt Data Visualization C++ Classes}
98 */
99
100/*!
101 * Constructs a new 3D surface graph with optional \a parent window
102 * and surface \a format.
103 */
104Q3DSurface::Q3DSurface(const QSurfaceFormat *format, QWindow *parent)
105 : QAbstract3DGraph(new Q3DSurfacePrivate(this), format, parent)
106{
107 if (!dptr()->m_initialized)
108 return;
109
110 dptr()->m_shared = new Surface3DController(geometry());
111 d_ptr->setVisualController(dptr()->m_shared);
112 dptr()->m_shared->initializeOpenGL();
113 QObject::connect(sender: dptr()->m_shared, signal: &Surface3DController::selectedSeriesChanged,
114 receiver: this, slot: &Q3DSurface::selectedSeriesChanged);
115 QObject::connect(sender: dptr()->m_shared, signal: &Surface3DController::flipHorizontalGridChanged,
116 receiver: this, slot: &Q3DSurface::flipHorizontalGridChanged);
117}
118
119/*!
120 * Destroys the 3D surface graph.
121 */
122Q3DSurface::~Q3DSurface()
123{
124}
125
126/*!
127 * Adds the \a series to the graph. A graph can contain multiple series, but has only one set of
128 * axes. If the newly added series has specified a selected item, it will be highlighted and
129 * any existing selection will be cleared. Only one added series can have an active selection.
130 */
131void Q3DSurface::addSeries(QSurface3DSeries *series)
132{
133 dptr()->m_shared->addSeries(series);
134}
135
136/*!
137 * Removes the \a series from the graph.
138 */
139void Q3DSurface::removeSeries(QSurface3DSeries *series)
140{
141 dptr()->m_shared->removeSeries(series);
142}
143
144/*!
145 * Returns the list of series added to this graph.
146 */
147QList<QSurface3DSeries *> Q3DSurface::seriesList() const
148{
149 return dptrc()->m_shared->surfaceSeriesList();
150}
151
152Q3DSurfacePrivate *Q3DSurface::dptr()
153{
154 return static_cast<Q3DSurfacePrivate *>(d_ptr.data());
155}
156
157const Q3DSurfacePrivate *Q3DSurface::dptrc() const
158{
159 return static_cast<const Q3DSurfacePrivate *>(d_ptr.data());
160}
161
162/*!
163 * \property Q3DSurface::axisX
164 *
165 * \brief The active x-axis.
166 */
167
168/*!
169 * Sets \a axis as the active x-axis. Implicitly calls addAxis() to transfer the
170 * ownership of the axis to this graph.
171 *
172 * If \a axis is null, a temporary default axis with no labels and an
173 * automatically adjusting range is created.
174 *
175 * This temporary axis is destroyed if another axis is set explicitly to the
176 * same orientation.
177 *
178 * \sa addAxis(), releaseAxis()
179 */
180void Q3DSurface::setAxisX(QValue3DAxis *axis)
181{
182 dptr()->m_shared->setAxisX(axis);
183}
184
185QValue3DAxis *Q3DSurface::axisX() const
186{
187 return static_cast<QValue3DAxis *>(dptrc()->m_shared->axisX());
188}
189
190/*!
191 * \property Q3DSurface::axisY
192 *
193 * \brief The active y-axis.
194 */
195
196/*!
197 * Sets \a axis as the active y-axis. Implicitly calls addAxis() to transfer the
198 * ownership of the axis to this graph.
199 *
200 * If \a axis is null, a temporary default axis with no labels and an
201 * automatically adjusting range is created.
202 *
203 * This temporary axis is destroyed if another axis is set explicitly to the
204 * same orientation.
205 *
206 * \sa addAxis(), releaseAxis()
207 */
208void Q3DSurface::setAxisY(QValue3DAxis *axis)
209{
210 dptr()->m_shared->setAxisY(axis);
211}
212
213QValue3DAxis *Q3DSurface::axisY() const
214{
215 return static_cast<QValue3DAxis *>(dptrc()->m_shared->axisY());
216}
217
218/*!
219 * \property Q3DSurface::axisZ
220 *
221 * \brief The active z-axis.
222 */
223
224/*!
225 * Sets \a axis as the active z-axis. Implicitly calls addAxis() to transfer the
226 * ownership of the axis to this graph.
227 *
228 * If \a axis is null, a temporary default axis with no labels and an
229 * automatically adjusting range is created.
230 *
231 * This temporary axis is destroyed if another axis is set explicitly to the
232 * same orientation.
233 *
234 * \sa addAxis(), releaseAxis()
235 */
236void Q3DSurface::setAxisZ(QValue3DAxis *axis)
237{
238 dptr()->m_shared->setAxisZ(axis);
239}
240
241QValue3DAxis *Q3DSurface::axisZ() const
242{
243 return static_cast<QValue3DAxis *>(dptrc()->m_shared->axisZ());
244}
245
246/*!
247 * \property Q3DSurface::selectedSeries
248 *
249 * \brief The selected series or null.
250 *
251 * If selectionMode has \c SelectionMultiSeries set, this
252 * property holds the series which owns the selected point.
253 */
254QSurface3DSeries *Q3DSurface::selectedSeries() const
255{
256 return dptrc()->m_shared->selectedSeries();
257}
258
259/*!
260 * \property Q3DSurface::flipHorizontalGrid
261 * \since QtDataVisualization 1.2
262 *
263 * \brief Whether the horizontal axis grid is displayed on top of the graph
264 * rather than on the bottom.
265 *
266 * In some use cases the horizontal axis grid is mostly covered by the surface, so it can be more
267 * useful to display the horizontal axis grid on top of the graph rather than on the bottom.
268 * A typical use case for this is showing 2D spectrograms using orthoGraphic projection with
269 * a top-down viewpoint.
270 *
271 * If \c{false}, the horizontal axis grid and labels are drawn on the horizontal background
272 * of the graph.
273 * If \c{true}, the horizontal axis grid and labels are drawn on the opposite side of the graph
274 * from the horizontal background.
275 * Defaults to \c{false}.
276 */
277void Q3DSurface::setFlipHorizontalGrid(bool flip)
278{
279 dptr()->m_shared->setFlipHorizontalGrid(flip);
280}
281
282bool Q3DSurface::flipHorizontalGrid() const
283{
284 return dptrc()->m_shared->flipHorizontalGrid();
285}
286
287/*!
288 * Adds \a axis to the graph. The axes added via addAxis are not yet taken to use,
289 * addAxis is simply used to give the ownership of the \a axis to the graph.
290 * The \a axis must not be null or added to another graph.
291 *
292 * \sa releaseAxis(), setAxisX(), setAxisY(), setAxisZ()
293 */
294void Q3DSurface::addAxis(QValue3DAxis *axis)
295{
296 dptr()->m_shared->addAxis(axis);
297}
298
299/*!
300 * Releases the ownership of the \a axis back to the caller, if it is added to this graph.
301 * If the released \a axis is in use, a new default axis will be created and set active.
302 *
303 * If the default axis is released and added back later, it behaves as any other axis would.
304 *
305 * \sa addAxis(), setAxisX(), setAxisY(), setAxisZ()
306 */
307void Q3DSurface::releaseAxis(QValue3DAxis *axis)
308{
309 dptr()->m_shared->releaseAxis(axis);
310}
311
312/*!
313 * Returns the list of all added axes.
314 *
315 * \sa addAxis()
316 */
317QList<QValue3DAxis *> Q3DSurface::axes() const
318{
319 QList<QAbstract3DAxis *> abstractAxes = dptrc()->m_shared->axes();
320 QList<QValue3DAxis *> retList;
321 foreach (QAbstract3DAxis *axis, abstractAxes)
322 retList.append(t: static_cast<QValue3DAxis *>(axis));
323
324 return retList;
325}
326
327// Q3DSurfacePrivate
328
329Q3DSurfacePrivate::Q3DSurfacePrivate(Q3DSurface *q)
330 : QAbstract3DGraphPrivate(q),
331 m_shared(0)
332{
333}
334
335Q3DSurfacePrivate::~Q3DSurfacePrivate()
336{
337}
338
339void Q3DSurfacePrivate::handleAxisXChanged(QAbstract3DAxis *axis)
340{
341 emit qptr()->axisXChanged(axis: static_cast<QValue3DAxis *>(axis));
342}
343
344void Q3DSurfacePrivate::handleAxisYChanged(QAbstract3DAxis *axis)
345{
346 emit qptr()->axisYChanged(axis: static_cast<QValue3DAxis *>(axis));
347}
348
349void Q3DSurfacePrivate::handleAxisZChanged(QAbstract3DAxis *axis)
350{
351 emit qptr()->axisZChanged(axis: static_cast<QValue3DAxis *>(axis));
352}
353
354Q3DSurface *Q3DSurfacePrivate::qptr()
355{
356 return static_cast<Q3DSurface *>(q_ptr);
357}
358
359QT_END_NAMESPACE_DATAVISUALIZATION
360

source code of qtdatavis3d/src/datavisualization/engine/q3dsurface.cpp