1/****************************************************************************
2**
3** Copyright (C) 2017 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 "qabstract3daxis_p.h"
31
32QT_BEGIN_NAMESPACE_DATAVISUALIZATION
33
34/*!
35 * \class QAbstract3DAxis
36 * \inmodule QtDataVisualization
37 * \brief The QAbstract3DAxis class is a base class for the axes of a graph.
38 * \since QtDataVisualization 1.0
39 *
40 * This class specifies the enumerations, properties, and functions shared by
41 * graph axes. It should not be used directly, but one of its subclasses should
42 * be used instead.
43 *
44 * \sa QCategory3DAxis, QValue3DAxis
45 */
46
47/*!
48 * \qmltype AbstractAxis3D
49 * \inqmlmodule QtDataVisualization
50 * \since QtDataVisualization 1.0
51 * \ingroup datavisualization_qml
52 * \instantiates QAbstract3DAxis
53 * \brief A base type for the axes of a graph.
54 *
55 * This type is uncreatable, but contains properties that are exposed via subtypes.
56 *
57 * For AbstractAxis3D enums, see \l QAbstract3DAxis::AxisOrientation and
58 * \l{QAbstract3DAxis::AxisType}.
59 */
60
61/*!
62 * \qmlproperty string AbstractAxis3D::title
63 * The title for the axis.
64 *
65 * \sa titleVisible, titleFixed
66 */
67
68/*!
69 * \qmlproperty list AbstractAxis3D::labels
70 * The labels for the axis.
71 * \note Setting this property for ValueAxis3D does nothing, as it generates labels automatically.
72 */
73
74/*!
75 * \qmlproperty AbstractAxis3D.AxisOrientation AbstractAxis3D::orientation
76 * The orientation of the axis.
77 */
78
79/*!
80 * \qmlproperty AbstractAxis3D.AxisType AbstractAxis3D::type
81 * The type of the axis.
82 */
83
84/*!
85 * \qmlproperty real AbstractAxis3D::min
86 *
87 * The minimum value on the axis.
88 * When setting this property, the maximum value is adjusted if necessary, to
89 * ensure that the range remains valid.
90 */
91
92/*!
93 * \qmlproperty real AbstractAxis3D::max
94 *
95 * The maximum value on the axis.
96 * When setting this property, the minimum value is adjusted if necessary, to
97 * ensure that the range remains valid.
98 */
99
100/*!
101 * \qmlproperty bool AbstractAxis3D::autoAdjustRange
102 *
103 * Defines whether the axis will automatically adjust the range so that all data fits in it.
104 */
105
106/*!
107 * \qmlproperty real AbstractAxis3D::labelAutoRotation
108 *
109 * The maximum angle the labels can autorotate when the camera angle changes.
110 * The angle can be between 0 and 90, inclusive. The default value is 0.
111 * If the value is 0, axis labels do not automatically rotate.
112 * If the value is greater than zero, labels attempt to orient themselves toward the camera, up to
113 * the specified angle.
114 */
115
116/*!
117 * \qmlproperty bool AbstractAxis3D::titleVisible
118 *
119 * Defines whether the axis title is visible in the primary graph view.
120 *
121 * The default value is \c{false}.
122 *
123 * \sa title, titleFixed
124 */
125
126/*!
127 * \qmlproperty bool AbstractAxis3D::titleFixed
128 *
129 * The rotation of axis titles.
130 *
131 * If \c{true}, axis titles in the primary graph view will be rotated towards the camera similarly
132 * to the axis labels.
133 * If \c{false}, axis titles are only rotated around their axis but are not otherwise oriented
134 * towards the camera.
135 * This property does not have any effect if the labelAutoRotation property
136 * value is zero.
137 * Default value is \c{true}.
138 *
139 * \sa labelAutoRotation, title, titleVisible
140 */
141
142/*!
143 * \enum QAbstract3DAxis::AxisOrientation
144 *
145 * The orientation of the axis object.
146 *
147 * \value AxisOrientationNone
148 * \value AxisOrientationX
149 * \value AxisOrientationY
150 * \value AxisOrientationZ
151 */
152
153/*!
154 * \enum QAbstract3DAxis::AxisType
155 *
156 * The type of the axis object.
157 *
158 * \value AxisTypeNone
159 * \value AxisTypeCategory
160 * \value AxisTypeValue
161 */
162
163/*!
164 * \internal
165 */
166QAbstract3DAxis::QAbstract3DAxis(QAbstract3DAxisPrivate *d, QObject *parent) :
167 QObject(parent),
168 d_ptr(d)
169{
170}
171
172/*!
173 * Destroys QAbstract3DAxis.
174 */
175QAbstract3DAxis::~QAbstract3DAxis()
176{
177}
178
179/*!
180 * \property QAbstract3DAxis::orientation
181 *
182 * \brief The orientation of the axis.
183 *
184 * The value is one of AxisOrientation values.
185 */
186QAbstract3DAxis::AxisOrientation QAbstract3DAxis::orientation() const
187{
188 return d_ptr->m_orientation;
189}
190
191/*!
192 * \property QAbstract3DAxis::type
193 *
194 * \brief The type of the axis.
195 *
196 * The value is one of AxisType values.
197 */
198QAbstract3DAxis::AxisType QAbstract3DAxis::type() const
199{
200 return d_ptr->m_type;
201}
202
203/*!
204 * \property QAbstract3DAxis::title
205 *
206 * \brief The title for the axis.
207 *
208 * \sa titleVisible, titleFixed
209 */
210void QAbstract3DAxis::setTitle(const QString &title)
211{
212 if (d_ptr->m_title != title) {
213 d_ptr->m_title = title;
214 emit titleChanged(newTitle: title);
215 }
216}
217
218QString QAbstract3DAxis::title() const
219{
220 return d_ptr->m_title;
221}
222
223/*!
224 * \property QAbstract3DAxis::labels
225 *
226 * \brief The labels for the axis.
227 * \note Setting this property for QValue3DAxis does nothing, as it generates labels automatically.
228 */
229void QAbstract3DAxis::setLabels(const QStringList &labels)
230{
231 Q_UNUSED(labels)
232}
233
234QStringList QAbstract3DAxis::labels() const
235{
236 d_ptr->updateLabels();
237 return d_ptr->m_labels;
238}
239
240/*!
241 * Sets the value range of the axis from \a min to \a max.
242 * When setting the range, the maximum value is adjusted if necessary, to ensure
243 * that the range remains valid.
244 * \note For QCategory3DAxis, specifies the index range of rows or columns to
245 * show.
246 */
247void QAbstract3DAxis::setRange(float min, float max)
248{
249 d_ptr->setRange(min, max);
250 setAutoAdjustRange(false);
251}
252
253/*!
254 * \property QAbstract3DAxis::labelAutoRotation
255 *
256 * \brief The maximum angle the labels can autorotate when the camera angle changes.
257 *
258 * The angle can be between 0 and 90, inclusive. The default value is 0.
259 * If the value is 0, axis labels do not automatically rotate.
260 * If the value is greater than zero, labels attempt to orient themselves toward the camera, up to
261 * the specified angle.
262 */
263void QAbstract3DAxis::setLabelAutoRotation(float angle)
264{
265 if (angle < 0.0f)
266 angle = 0.0f;
267 if (angle > 90.0f)
268 angle = 90.0f;
269 if (d_ptr->m_labelAutoRotation != angle) {
270 d_ptr->m_labelAutoRotation = angle;
271 emit labelAutoRotationChanged(angle);
272 }
273}
274
275float QAbstract3DAxis::labelAutoRotation() const
276{
277 return d_ptr->m_labelAutoRotation;
278}
279
280/*!
281 * \property QAbstract3DAxis::titleVisible
282 *
283 * \brief Whether the axis title is visible in the primary graph view.
284 *
285 * The default value is \c{false}.
286 *
287 * \sa title, titleFixed
288 */
289void QAbstract3DAxis::setTitleVisible(bool visible)
290{
291 if (d_ptr->m_titleVisible != visible) {
292 d_ptr->m_titleVisible = visible;
293 emit titleVisibilityChanged(visible);
294 }
295}
296
297bool QAbstract3DAxis::isTitleVisible() const
298{
299 return d_ptr->m_titleVisible;
300}
301
302/*!
303 * \property QAbstract3DAxis::titleFixed
304 *
305 * \brief The rotation of the axis titles.
306 *
307 * If \c{true}, axis titles in the primary graph view will be rotated towards the camera similarly
308 * to the axis labels.
309 * If \c{false}, axis titles are only rotated around their axis but are not otherwise oriented
310 * towards the camera.
311 * This property does not have any effect if the labelAutoRotation property
312 * value is zero.
313 * Default value is \c{true}.
314 *
315 * \sa labelAutoRotation, title, titleVisible
316 */
317void QAbstract3DAxis::setTitleFixed(bool fixed)
318{
319 if (d_ptr->m_titleFixed != fixed) {
320 d_ptr->m_titleFixed = fixed;
321 emit titleFixedChanged(fixed);
322 }
323}
324
325bool QAbstract3DAxis::isTitleFixed() const
326{
327 return d_ptr->m_titleFixed;
328}
329
330/*!
331 * \property QAbstract3DAxis::min
332 *
333 * \brief The minimum value on the axis.
334 *
335 * When setting this property, the maximum value is adjusted if necessary, to
336 * ensure that the range remains valid.
337 * \note For QCategory3DAxis, specifies the index of the first row or column to
338 * show.
339 */
340void QAbstract3DAxis::setMin(float min)
341{
342 d_ptr->setMin(min);
343 setAutoAdjustRange(false);
344}
345
346/*!
347 * \property QAbstract3DAxis::max
348 *
349 * \brief The maximum value on the axis.
350 *
351 * When setting this property, the minimum value is adjusted if necessary, to
352 * ensure that the range remains valid.
353 * \note For QCategory3DAxis, specifies the index of the last row or column to
354 * show.
355 */
356void QAbstract3DAxis::setMax(float max)
357{
358 d_ptr->setMax(max);
359 setAutoAdjustRange(false);
360}
361
362float QAbstract3DAxis::min() const
363{
364 return d_ptr->m_min;
365}
366
367float QAbstract3DAxis::max() const
368{
369 return d_ptr->m_max;
370}
371
372/*!
373 * \property QAbstract3DAxis::autoAdjustRange
374 *
375 * \brief Whether the axis will automatically adjust the range so that all data fits in it.
376 *
377 * \sa setRange(), setMin(), setMax()
378 */
379void QAbstract3DAxis::setAutoAdjustRange(bool autoAdjust)
380{
381 if (d_ptr->m_autoAdjust != autoAdjust) {
382 d_ptr->m_autoAdjust = autoAdjust;
383 emit autoAdjustRangeChanged(autoAdjust);
384 }
385}
386
387bool QAbstract3DAxis::isAutoAdjustRange() const
388{
389 return d_ptr->m_autoAdjust;
390}
391
392/*!
393 * \fn QAbstract3DAxis::rangeChanged(float min, float max)
394 *
395 * Emits the minimum and maximum values of the range, \a min and \a max, when
396 * the range changes.
397 */
398
399// QAbstract3DAxisPrivate
400QAbstract3DAxisPrivate::QAbstract3DAxisPrivate(QAbstract3DAxis *q, QAbstract3DAxis::AxisType type)
401 : QObject(0),
402 q_ptr(q),
403 m_orientation(QAbstract3DAxis::AxisOrientationNone),
404 m_type(type),
405 m_isDefaultAxis(false),
406 m_min(0.0f),
407 m_max(10.0f),
408 m_autoAdjust(true),
409 m_labelAutoRotation(0.0f),
410 m_titleVisible(false),
411 m_titleFixed(true)
412{
413}
414
415QAbstract3DAxisPrivate::~QAbstract3DAxisPrivate()
416{
417}
418
419void QAbstract3DAxisPrivate::setOrientation(QAbstract3DAxis::AxisOrientation orientation)
420{
421 if (m_orientation == QAbstract3DAxis::AxisOrientationNone) {
422 m_orientation = orientation;
423 emit q_ptr->orientationChanged(orientation);
424 } else {
425 Q_ASSERT("Attempted to reset axis orientation.");
426 }
427}
428
429void QAbstract3DAxisPrivate::updateLabels()
430{
431 // Default implementation does nothing
432}
433
434void QAbstract3DAxisPrivate::setRange(float min, float max, bool suppressWarnings)
435{
436 bool adjusted = false;
437 if (!allowNegatives()) {
438 if (allowZero()) {
439 if (min < 0.0f) {
440 min = 0.0f;
441 adjusted = true;
442 }
443 if (max < 0.0f) {
444 max = 0.0f;
445 adjusted = true;
446 }
447 } else {
448 if (min <= 0.0f) {
449 min = 1.0f;
450 adjusted = true;
451 }
452 if (max <= 0.0f) {
453 max = 1.0f;
454 adjusted = true;
455 }
456 }
457 }
458 // If min >= max, we adjust ranges so that
459 // m_max becomes (min + 1.0f)
460 // as axes need some kind of valid range.
461 bool minDirty = false;
462 bool maxDirty = false;
463 if (m_min != min) {
464 m_min = min;
465 minDirty = true;
466 }
467 if (m_max != max || min > max || (!allowMinMaxSame() && min == max)) {
468 if (min > max || (!allowMinMaxSame() && min == max)) {
469 m_max = min + 1.0f;
470 adjusted = true;
471 } else {
472 m_max = max;
473 }
474 maxDirty = true;
475 }
476
477 if (minDirty || maxDirty) {
478 if (adjusted && !suppressWarnings) {
479 qWarning() << "Warning: Tried to set invalid range for axis."
480 " Range automatically adjusted to a valid one:"
481 << min << "-" << max << "-->" << m_min << "-" << m_max;
482 }
483 emit q_ptr->rangeChanged(min: m_min, max: m_max);
484 }
485
486 if (minDirty)
487 emit q_ptr->minChanged(value: m_min);
488 if (maxDirty)
489 emit q_ptr->maxChanged(value: m_max);
490}
491
492void QAbstract3DAxisPrivate::setMin(float min)
493{
494 if (!allowNegatives()) {
495 if (allowZero()) {
496 if (min < 0.0f) {
497 min = 0.0f;
498 qWarning() << "Warning: Tried to set negative minimum for an axis that only"
499 "supports positive values and zero:" << min;
500 }
501 } else {
502 if (min <= 0.0f) {
503 min = 1.0f;
504 qWarning() << "Warning: Tried to set negative or zero minimum for an axis that only"
505 "supports positive values:" << min;
506 }
507 }
508 }
509
510 if (m_min != min) {
511 bool maxChanged = false;
512 if (min > m_max || (!allowMinMaxSame() && min == m_max)) {
513 float oldMax = m_max;
514 m_max = min + 1.0f;
515 qWarning() << "Warning: Tried to set minimum to equal or larger than maximum for"
516 " value axis. Maximum automatically adjusted to a valid one:"
517 << oldMax << "-->" << m_max;
518 maxChanged = true;
519 }
520 m_min = min;
521
522 emit q_ptr->rangeChanged(min: m_min, max: m_max);
523 emit q_ptr->minChanged(value: m_min);
524 if (maxChanged)
525 emit q_ptr->maxChanged(value: m_max);
526 }
527}
528
529void QAbstract3DAxisPrivate::setMax(float max)
530{
531 if (!allowNegatives()) {
532 if (allowZero()) {
533 if (max < 0.0f) {
534 max = 0.0f;
535 qWarning() << "Warning: Tried to set negative maximum for an axis that only"
536 "supports positive values and zero:" << max;
537 }
538 } else {
539 if (max <= 0.0f) {
540 max = 1.0f;
541 qWarning() << "Warning: Tried to set negative or zero maximum for an axis that only"
542 "supports positive values:" << max;
543 }
544 }
545 }
546
547 if (m_max != max) {
548 bool minChanged = false;
549 if (m_min > max || (!allowMinMaxSame() && m_min == max)) {
550 float oldMin = m_min;
551 m_min = max - 1.0f;
552 if (!allowNegatives() && m_min < 0.0f) {
553 if (allowZero())
554 m_min = 0.0f;
555 else
556 m_min = max / 2.0f; // Need some positive value smaller than max
557
558 if (!allowMinMaxSame() && max == 0.0f) {
559 m_min = oldMin;
560 qWarning() << "Unable to set maximum value to zero.";
561 return;
562 }
563 }
564 qWarning() << "Warning: Tried to set maximum to equal or smaller than minimum for"
565 " value axis. Minimum automatically adjusted to a valid one:"
566 << oldMin << "-->" << m_min;
567 minChanged = true;
568 }
569 m_max = max;
570 emit q_ptr->rangeChanged(min: m_min, max: m_max);
571 emit q_ptr->maxChanged(value: m_max);
572 if (minChanged)
573 emit q_ptr->minChanged(value: m_min);
574 }
575}
576
577QT_END_NAMESPACE_DATAVISUALIZATION
578

source code of qtdatavis3d/src/datavisualization/axis/qabstract3daxis.cpp