1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qcustom3ditem.h"
5#include "qquickgraphsnode_p.h"
6#include <qtconfigmacros.h>
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 * \qmltype GraphsNode
12 * \inherits Node
13 * \qmlabstract
14 * \inqmlmodule QtGraphs
15 * \ingroup graphs_qml_3D
16 * \brief Base type for 3D graphs.
17 *
18 * The uncreatable base type for all 3D graph nodes in Qt Graphs.
19 *
20 * \sa Bars3DNode, Scatter3DNode, Surface3DNode, {Qt Graphs C++ Classes for 3D}
21 */
22
23/*!
24 * \qmlproperty Graphs3D.SelectionMode GraphsNode::selectionMode
25 * The active selection mode in the graph.
26 * One of the \l graphs3d.selectionflag enum values.
27 */
28
29/*!
30 * \qmlproperty GraphsTheme GraphsNode::theme
31 * The active theme of the graph.
32 *
33 * \sa GraphsTheme
34 */
35
36/*!
37 * \qmlproperty list<Custom3DItem> GraphsNode::customItemList
38 *
39 * The list of \l{Custom3DItem} items added to the graph. The graph takes
40 * ownership of the added items.
41 */
42
43/*!
44 * \qmlproperty bool GraphsNode::polar
45 *
46 * If \c {true}, the horizontal axes are changed into polar axes. The x-axis
47 * becomes the angular axis and the z-axis becomes the radial axis.
48 * Polar mode is not available for bar graphs.
49 *
50 * Defaults to \c{false}.
51 *
52 * \sa radialLabelOffset
53 */
54
55/*!
56 * \qmlproperty real GraphsNode::labelMargin
57 *
58 * This property specifies the margin for the placement of the axis labels.
59 *
60 * Negative values place the labels inside the plot-area while positive values
61 * place them outside the plot-area. Label automatic rotation is disabled when
62 * the value is negative. Defaults to \c 0.1
63 *
64 * \sa QAbstract3DAxis::labelAutoAngle
65 *
66 */
67
68/*!
69 * \qmlproperty real GraphsNode::radialLabelOffset
70 *
71 * This property specifies the normalized horizontal offset for the axis labels
72 * of the radial polar axis. The value \c 0.0 indicates that the labels should
73 * be drawn next to the 0-angle angular axis grid line. The value \c 1.0
74 * indicates that the labels are drawn in their usual place at the edge of the
75 * graph background. This property is ignored if the polar property value is
76 * \c{false}. Defaults to \c 1.0.
77 *
78 * \sa polar
79 */
80
81/*!
82 * \qmlmethod void GraphsNode::clearSelection()
83 * Clears selection from all attached series.
84 */
85
86/*!
87 * \qmlmethod bool GraphsNode::hasSeries(Abstract3DSeries series)
88 * Returns whether the \a series has already been added to the graph.
89 */
90
91/*!
92 * \qmlmethod qsizetype GraphsNode::addCustomItem(Custom3DItem item)
93 *
94 * Adds a Custom3DItem \a item to the graph. Graph takes ownership of the added
95 * item.
96 *
97 * \return index to the added item if add was successful, -1 if trying to add a
98 * null item, and index of the item if trying to add an already added item.
99 *
100 * \sa removeCustomItems(), removeCustomItem(), removeCustomItemAt()
101 */
102
103/*!
104 * \qmlmethod void GraphsNode::removeCustomItems()
105 *
106 * Removes all custom items. Deletes the resources allocated to them.
107 */
108
109/*!
110 * \qmlmethod void GraphsNode::removeCustomItem(Custom3DItem item)
111 *
112 * Removes the custom \a {item}. Deletes the resources allocated to it.
113 */
114
115/*!
116 * \qmlmethod void GraphsNode::removeCustomItemAt(vector3d position)
117 *
118 * Removes all custom items at \a {position}. Deletes the resources allocated to them.
119 */
120
121/*!
122 * \qmlmethod void GraphsNode::releaseCustomItem(Custom3DItem item)
123 *
124 * Gets ownership of \a item back and removes the \a item from the graph.
125 *
126 * \note If the same item is added back to the graph, the texture file needs to
127 * be re-set.
128 *
129 * \sa Custom3DItem::textureFile
130 */
131
132/*!
133 * \qmlmethod void GraphsNode::doPicking(QPoint point)
134 *
135 * Performs picking using view coordinates from \a point
136 * on the elements of the graph, selecting the first item hit.
137 * Default input handling performs this upon receiving the onTapped event.
138 *
139 * \sa selectedElement
140 */
141
142/*!
143 * \qmlmethod void GraphsNode::doRayPicking(QVector3D origin, QVector3D direction)
144 *
145 * Performs picking starting from \a origin and in \a direction
146 * on the elements of the graph, selecting the first item hit.
147 *
148 * \sa selectedElement
149 */
150
151/*!
152 * \qmlmethod int GraphsNode::selectedLabelIndex()
153 *
154 * Can be used to query the index of the selected label after receiving
155 * \c selectedElementChanged signal with any label type. Selection is valid
156 * until the next \c selectedElementChanged signal.
157 *
158 * \return index of the selected label, or -1.
159 *
160 * \sa selectedElement
161 */
162
163/*!
164 * \qmlmethod Abstract3DAxis GraphsNode::selectedAxis()
165 *
166 * Can be used to get the selected axis after receiving \c selectedElementChanged
167 * signal with any label type. Selection is valid until the next
168 * \c selectedElementChanged signal.
169 *
170 * \return the selected axis, or null.
171 *
172 * \sa selectedElement
173 */
174
175/*!
176 * \qmlmethod qsizetype GraphsNode::selectedCustomItemIndex()
177 *
178 * Can be used to query the index of the selected custom item after receiving
179 * \c selectedElementChanged signal with
180 * \l{QtGraphs3D::ElementType::CustomItem}{ElementType.CustomItem} type.
181 * Selection is valid until the next \c selectedElementChanged signal.
182 *
183 * \return index of the selected custom item, or -1.
184 *
185 * \sa selectedElement
186 */
187
188/*!
189 * \qmlmethod Custom3DItem GraphsNode::selectedCustomItem()
190 *
191 * Can be used to get the selected custom item after receiving
192 * \c selectedElementChanged signal with
193 * \l{QtGraphs3D::ElementType::CustomItem}{ElementType.CustomItem} type.
194 * Ownership of the item remains with the graph.
195 * Selection is valid until the next \c selectedElementChanged signal.
196 *
197 * \return the selected custom item, or null.
198 *
199 * \sa selectedElement
200 */
201
202/*!
203 * \qmlproperty Graphs3D.ElementType GraphsNode::selectedElement
204 * \readonly
205 *
206 * The element selected in the graph.
207 *
208 * This property can be used to query the selected element type.
209 * The type is valid until a new selection is made in the graph and the
210 * \c selectedElementChanged signal is emitted.
211 *
212 * The signal can be used for example for implementing customized input
213 * handling, as demonstrated by the \l {Axis Handling} example.
214 *
215 * \sa selectedLabelIndex(), selectedAxis(), selectedCustomItemIndex(),
216 * selectedCustomItem(), Bars3DNode::selectedSeries, Scatter3DNode::selectedSeries,
217 * Scene3D::selectionQueryPosition, Graphs3D.ElementType
218 */
219
220/*!
221 * \qmlproperty real GraphsNode::aspectRatio
222 *
223 * The ratio of the graph scaling between the longest axis on the horizontal
224 * plane and the y-axis. Defaults to \c{2.0}.
225 *
226 * \note Has no effect on Bars3D.
227 *
228 * \sa horizontalAspectRatio
229 */
230
231/*!
232 * \qmlproperty real GraphsNode::horizontalAspectRatio
233 *
234 * The ratio of the graph scaling between the x-axis and z-axis.
235 * The value of \c 0.0 indicates automatic scaling according to axis ranges.
236 * Defaults to \c{0.0}.
237 *
238 * \note Has no effect on Bars3DNode, which handles scaling on the horizontal plane
239 * via the \l{Bars3DNode::barThickness}{barThickness} and
240 * \l{Bars3DNode::barSpacing}{barSpacing} properties. Polar graphs also ignore this
241 * property.
242 *
243 * \sa aspectRatio, polar, Bars3DNode::barThickness, Bars3DNode::barSpacing
244 */
245
246/*!
247 * \qmlproperty Graphs3D.OptimizationHint GraphsNode::optimizationHint
248 *
249 * \brief Specifies whether the default or legacy mode is used for rendering optimization.
250 *
251 * The default mode uses instanced rendering, and provides the full feature set
252 * at the best level of performance on most systems. The static mode optimizes
253 * graph rendering and is ideal for large non-changing data sets. It is slower
254 * with dynamic data changes and item rotations. Selection is not optimized, so
255 * using the static mode with massive data sets is not advisable. Legacy mode
256 * renders all items in th graph individually, without instancing. It should be
257 * used only if default mode does not work, that is the same as if the target
258 * system does not support instancing. Defaults to
259 * \l{QtGraphs3D::OptimizationHint::Default}{Default}.
260 *
261 * \note On some environments, large graphs using static optimization may not
262 * render, because all of the items are rendered using a single draw call, and
263 * different graphics drivers support different maximum vertice counts per call.
264 * This is mostly an issue on 32bit and OpenGL ES2 platforms. To work around
265 * this issue, choose an item mesh with a low vertex count or use the point mesh.
266 *
267 * \sa Abstract3DSeries::mesh, Graphs3D.OptimizationHint
268 */
269
270/*!
271 * \qmlproperty locale GraphsNode::locale
272 *
273 * Sets the locale used for formatting various numeric labels.
274 * Defaults to the \c{"C"} locale.
275 *
276 * \sa Value3DAxis::labelFormat
277 */
278
279/*!
280 * \qmlproperty vector3d GraphsNode::queriedGraphPosition
281 * \readonly
282 *
283 * This read-only property contains the latest graph position values along each
284 * axis queried using Scene3D::graphPositionQuery. The values are normalized to
285 * range \c{[-1, 1]}. If the queried position was outside the graph bounds, the
286 * values will not reflect the real position, but will instead be some undefined
287 * position outside the range \c{[-1, 1]}. The value will be undefined until a
288 * query is made.
289 *
290 * There is no single correct 3D coordinate to match a particular screen
291 * position, so to be consistent, the queries are always done against the inner
292 * sides of an invisible box surrounding the graph.
293 *
294 * \note Bar graphs only allow querying graph position at the graph floor level,
295 * so the y-value is always zero for bar graphs and valid queries can be only
296 * made at screen positions that contain the floor of the graph.
297 *
298 * \sa Scene3D::graphPositionQuery
299 */
300
301/*!
302 * \qmlproperty real GraphsNode::margin
303 *
304 * The absolute value used for the space left between the edge of the
305 * plottable graph area and the edge of the graph background.
306 *
307 * If the margin value is negative, the margins are determined automatically and
308 * can vary according to the size of the items in the series and the type of the
309 * graph. The value is interpreted as a fraction of the y-axis range if the
310 * graph aspect ratios have not been changed from the default values.
311 * Defaults to \c{-1.0}.
312 *
313 * \note Setting a smaller margin for a scatter graph than the automatically
314 * determined margin can cause the scatter items at the edges of the graph to
315 * overlap with the graph background.
316 *
317 * \note On scatter and surface graphs, if the margin is small in comparison to
318 * the axis label size, the positions of the edge labels of the axes are
319 * adjusted to avoid overlap with the edge labels of the neighboring axes.
320 */
321
322/*!
323 * \qmlproperty Graphs3D.GridLineType GraphsNode::gridLineType
324 *
325 * Defines whether the grid lines type is \c Graphs3D.GridLineType.Shader or
326 * \c Graphs3D.GridLineType.Geometry.
327 *
328 * This value affects all grid lines.
329 *
330 * \sa Graphs3D.GridLineType
331 */
332
333QQuickGraphsNode::QQuickGraphsNode(QQuick3DNode *parent)
334 : QQuick3DNode(parent)
335 , m_selectionMode(QtGraphs3D::SelectionFlag::Item)
336 , m_aspectRatio(2.0)
337 , m_optimizationHint(QtGraphs3D::OptimizationHint::Default)
338 , m_polar(false)
339 , m_labelMargin(.1f)
340 , m_radialLabelOffset(1.0f)
341 , m_horizontalAspectRatio(0.0)
342 , m_locale(QLocale::c())
343 , m_margin(-1.0)
344 , m_gridLineType(QtGraphs3D::GridLineType::Geometry)
345{
346 QGraphsTheme *theme = new QGraphsTheme(this);
347 setTheme(theme);
348}
349
350QQuickGraphsNode::~QQuickGraphsNode() {}
351
352void QQuickGraphsNode::componentComplete()
353{
354 QQuick3DNode::componentComplete();
355
356 //initialize properties
357 m_graph->setTheme(m_theme);
358 m_graph->setAspectRatio(m_aspectRatio);
359 m_graph->setOptimizationHint(m_optimizationHint);
360 m_graph->setPolar(m_polar);
361 m_graph->setLabelMargin(m_labelMargin);
362 m_graph->setRadialLabelOffset(m_radialLabelOffset);
363 m_graph->setHorizontalAspectRatio(m_horizontalAspectRatio);
364 m_graph->setLocale(m_locale);
365 m_graph->setMargin(m_margin);
366 m_graph->setGridLineType(m_gridLineType);
367
368 for (auto item : std::as_const(t&: m_customItemList))
369 m_graph->addCustomItem(item);
370
371 //connect signals
372 connect(sender: m_graph.get(),
373 signal: &QQuickGraphsItem::selectionModeChanged,
374 context: this,
375 slot: &QQuickGraphsNode::selectionModeChanged);
376 connect(sender: m_graph.get(), signal: &QQuickGraphsItem::themeChanged, context: this, slot: &QQuickGraphsNode::themeChanged);
377 connect(sender: m_graph.get(),
378 signal: &QQuickGraphsItem::aspectRatioChanged,
379 context: this,
380 slot: &QQuickGraphsNode::aspectRatioChanged);
381 connect(sender: m_graph.get(),
382 signal: &QQuickGraphsItem::optimizationHintChanged,
383 context: this,
384 slot: &QQuickGraphsNode::optimizationHintChanged);
385 connect(sender: m_graph.get(), signal: &QQuickGraphsItem::polarChanged, context: this, slot: &QQuickGraphsNode::polarChanged);
386 connect(sender: m_graph.get(),
387 signal: &QQuickGraphsItem::labelMarginChanged,
388 context: this,
389 slot: &QQuickGraphsNode::labelMarginChanged);
390 connect(sender: m_graph.get(),
391 signal: &QQuickGraphsItem::radialLabelOffsetChanged,
392 context: this,
393 slot: &QQuickGraphsNode::radialLabelOffsetChanged);
394 connect(sender: m_graph.get(),
395 signal: &QQuickGraphsItem::horizontalAspectRatioChanged,
396 context: this,
397 slot: &QQuickGraphsNode::horizontalAspectRatioChanged);
398 connect(sender: m_graph.get(), signal: &QQuickGraphsItem::localeChanged, context: this, slot: &QQuickGraphsNode::localeChanged);
399 connect(sender: m_graph.get(),
400 signal: &QQuickGraphsItem::queriedGraphPositionChanged,
401 context: this,
402 slot: &QQuickGraphsNode::queriedGraphPositionChanged);
403 connect(sender: m_graph.get(), signal: &QQuickGraphsItem::marginChanged, context: this, slot: &QQuickGraphsNode::marginChanged);
404 connect(sender: m_graph.get(),
405 signal: &QQuickGraphsItem::gridLineTypeChanged,
406 context: this,
407 slot: &QQuickGraphsNode::gridLineTypeChanged);
408}
409
410void QQuickGraphsNode::setGraphParent()
411{
412 if (m_graph)
413 m_graph->setParentNode(this);
414}
415
416void QQuickGraphsNode::setSelectionMode(QtGraphs3D::SelectionFlags selectionMode)
417{
418 if (m_selectionMode == selectionMode)
419 return;
420
421 m_selectionMode = selectionMode;
422 if (m_graph)
423 m_graph->setSelectionMode(m_selectionMode);
424}
425
426QtGraphs3D::SelectionFlags QQuickGraphsNode::selectionMode() const
427{
428 if (m_graph)
429 return m_graph->selectionMode();
430 else
431 return m_selectionMode;
432}
433
434void QQuickGraphsNode::setTheme(QGraphsTheme *theme)
435{
436 if (m_theme == theme)
437 return;
438
439 m_theme = theme;
440 if (m_graph)
441 m_graph->setTheme(m_theme);
442}
443
444QGraphsTheme *QQuickGraphsNode::theme() const
445{
446 if (m_graph)
447 return m_graph->theme();
448 else
449 return m_theme;
450}
451
452QQmlListProperty<QCustom3DItem> QQuickGraphsNode::customItemList() const
453{
454 if (m_graph)
455 return m_graph->customItemList();
456 else
457 return QQmlListProperty<QCustom3DItem>();
458}
459
460
461QtGraphs3D::ElementType QQuickGraphsNode::selectedElement() const
462{
463 if (m_graph)
464 return m_graph->selectedElement();
465 else
466 return QtGraphs3D::ElementType::None;
467}
468
469void QQuickGraphsNode::setAspectRatio(qreal aspectRatio)
470{
471 if (m_aspectRatio == aspectRatio)
472 return;
473
474 m_aspectRatio = aspectRatio;
475 if (m_graph)
476 m_graph->setAspectRatio(aspectRatio);
477}
478
479qreal QQuickGraphsNode::aspectRatio() const
480{
481 if (m_graph)
482 return m_graph->aspectRatio();
483 else
484 return m_aspectRatio;
485}
486
487void QQuickGraphsNode::setOptimizationHint(QtGraphs3D::OptimizationHint optimizationHint)
488{
489 if (m_optimizationHint == optimizationHint)
490 return;
491
492 m_optimizationHint = optimizationHint;
493 if (m_graph)
494 m_graph->setOptimizationHint(optimizationHint);
495}
496QtGraphs3D::OptimizationHint QQuickGraphsNode::optimizationHint() const
497{
498 if (m_graph)
499 return m_graph->optimizationHint();
500 else
501 return m_optimizationHint;
502}
503void QQuickGraphsNode::setPolar(bool enabled)
504{
505 if (m_polar == enabled)
506 return;
507
508 m_polar = enabled;
509 if (m_graph)
510 m_graph->setPolar(enabled);
511}
512
513bool QQuickGraphsNode::isPolar() const
514{
515 if (m_graph)
516 return m_graph->isPolar();
517 else
518 return m_polar;
519}
520
521void QQuickGraphsNode::setLabelMargin(float labelMargin)
522{
523 if (m_labelMargin == labelMargin)
524 return;
525
526 m_labelMargin = labelMargin;
527 if (m_graph)
528 m_graph->setLabelMargin(labelMargin);
529}
530
531float QQuickGraphsNode::labelMargin() const
532{
533 if (m_graph)
534 return m_graph->labelMargin();
535 else
536 return m_labelMargin;
537}
538
539void QQuickGraphsNode::setRadialLabelOffset(float radialLabelOffset)
540{
541 if (m_radialLabelOffset == radialLabelOffset)
542 return;
543
544 m_radialLabelOffset = radialLabelOffset;
545 if (m_graph)
546 m_graph->setRadialLabelOffset(radialLabelOffset);
547}
548
549float QQuickGraphsNode::radialLabelOffset() const
550{
551 if (m_graph)
552 return m_graph->radialLabelOffset();
553 else
554 return m_radialLabelOffset;
555}
556
557void QQuickGraphsNode::setHorizontalAspectRatio(qreal horizontalAspectRatio)
558{
559 if (m_horizontalAspectRatio == horizontalAspectRatio)
560 return;
561
562 m_horizontalAspectRatio = horizontalAspectRatio;
563 if (m_graph)
564 m_graph->setHorizontalAspectRatio(horizontalAspectRatio);
565}
566
567qreal QQuickGraphsNode::horizontalAspectRatio() const
568{
569 if (m_graph)
570 return m_graph->horizontalAspectRatio();
571 else
572 return m_horizontalAspectRatio;
573}
574
575void QQuickGraphsNode::setLocale(QLocale locale)
576{
577 if (m_locale == locale)
578 return;
579
580 m_locale = locale;
581 if (m_graph)
582 m_graph->setLocale(locale);
583}
584
585QLocale QQuickGraphsNode::locale() const
586{
587 if (m_graph)
588 return m_graph->locale();
589 else
590 return m_locale;
591}
592
593QVector3D QQuickGraphsNode::queriedGraphPosition() const
594{
595 if (m_graph)
596 return m_graph->queriedGraphPosition();
597 else
598 return QVector3D();
599}
600
601qreal QQuickGraphsNode::margin() const
602{
603 if (m_graph)
604 return m_graph->margin();
605 else
606 return m_margin;
607}
608
609void QQuickGraphsNode::setMargin(qreal margin)
610{
611 if (m_margin == margin)
612 return;
613
614 m_margin = margin;
615 if (m_graph)
616 m_graph->setMargin(margin);
617}
618
619QtGraphs3D::GridLineType QQuickGraphsNode::gridLineType() const
620{
621 if (m_graph)
622 return m_graph->gridLineType();
623 else
624 return m_gridLineType;
625}
626void QQuickGraphsNode::setGridLineType(const QtGraphs3D::GridLineType &gridLineType)
627{
628 if (m_gridLineType == gridLineType)
629 return;
630
631 m_gridLineType = gridLineType;
632 if (m_graph)
633 m_graph->setGridLineType(gridLineType);
634}
635
636bool QQuickGraphsNode::hasSeries(QAbstract3DSeries *series)
637{
638 if (m_graph)
639 return m_graph->hasSeries(series);
640 else
641 return m_seriesList.contains(t: series);
642}
643void QQuickGraphsNode::addSeriesInternal(QAbstract3DSeries *series)
644{
645 insertSeries(index: m_seriesList.size(), series);
646}
647
648void QQuickGraphsNode::insertSeries(qsizetype index, QAbstract3DSeries *series)
649{
650 if (series) {
651 if (m_seriesList.contains(t: series)) {
652 qsizetype oldIndex = m_seriesList.indexOf(t: series);
653 if (index != oldIndex) {
654 m_seriesList.removeOne(t: series);
655 if (oldIndex < index)
656 index--;
657 m_seriesList.insert(i: index, t: series);
658 }
659 } else {
660 m_seriesList.insert(i: index, t: series);
661 }
662 }
663}
664
665void QQuickGraphsNode::removeSeriesInternal(QAbstract3DSeries *series)
666{
667 if (series)
668 m_seriesList.removeAll(t: series);
669}
670
671QList<QAbstract3DSeries *> QQuickGraphsNode::seriesList()
672{
673 return m_seriesList;
674}
675
676qsizetype QQuickGraphsNode::addCustomItem(QCustom3DItem *item)
677{
678 if (m_graph)
679 m_graph->addCustomItem(item);
680
681 m_customItemList.append(t: item);
682 return m_customItemList.size() - 1;
683}
684
685void QQuickGraphsNode::removeCustomItems()
686{
687 if (m_graph)
688 m_graph->removeCustomItems();
689
690 m_customItemList.clear();
691}
692
693void QQuickGraphsNode::removeCustomItem(QCustom3DItem *item)
694{
695 if (m_graph)
696 m_graph->deleteCustomItem(item);
697
698 m_customItemList.removeOne(t: item);
699}
700
701void QQuickGraphsNode::removeCustomItemAt(QVector3D position)
702{
703 if (m_graph)
704 m_graph->removeCustomItemAt(position);
705
706 for (QCustom3DItem *item : std::as_const(t&: m_customItemList)) {
707 if (item->position() == position)
708 m_customItemList.removeOne(t: item);
709 }
710}
711
712void QQuickGraphsNode::releaseCustomItem(QCustom3DItem *item)
713{
714 if (m_graph)
715 m_graph->releaseCustomItem(item);
716
717 m_customItemList.removeOne(t: item);
718}
719
720int QQuickGraphsNode::selectedLabelIndex() const
721{
722 if (m_graph)
723 return selectedLabelIndex();
724 else
725 return -1;
726}
727
728QAbstract3DAxis *QQuickGraphsNode::selectedAxis() const
729{
730 if (m_graph)
731 return m_graph->selectedAxis();
732 return nullptr;
733}
734
735qsizetype QQuickGraphsNode::selectedCustomItemIndex() const
736{
737 if (m_graph)
738 return m_graph->selectedCustomItemIndex();
739 else
740 return -1;
741}
742
743QCustom3DItem *QQuickGraphsNode::selectedCustomItem() const
744{
745 if (m_graph)
746 return m_graph->selectedCustomItem();
747 else
748 return nullptr;
749}
750
751QT_END_NAMESPACE
752

source code of qtgraphs/src/graphs3d/qml/qquickgraphsnode.cpp