summaryrefslogtreecommitdiffstats
path: root/examples/datavisualization/graphgallery
diff options
context:
space:
mode:
Diffstat (limited to 'examples/datavisualization/graphgallery')
-rw-r--r--examples/datavisualization/graphgallery/CMakeLists.txt75
-rw-r--r--examples/datavisualization/graphgallery/axesinputhandler.cpp116
-rw-r--r--examples/datavisualization/graphgallery/axesinputhandler.h54
-rw-r--r--examples/datavisualization/graphgallery/bargraph.cpp329
-rw-r--r--examples/datavisualization/graphgallery/bargraph.h26
-rw-r--r--examples/datavisualization/graphgallery/custominputhandler.cpp161
-rw-r--r--examples/datavisualization/graphgallery/custominputhandler.h76
-rw-r--r--examples/datavisualization/graphgallery/data/layer_1.pngbin0 -> 34540 bytes
-rw-r--r--examples/datavisualization/graphgallery/data/layer_2.pngbin0 -> 10553 bytes
-rw-r--r--examples/datavisualization/graphgallery/data/layer_3.pngbin0 -> 7119 bytes
-rw-r--r--examples/datavisualization/graphgallery/data/license.txt77
-rw-r--r--examples/datavisualization/graphgallery/data/maptexture.jpgbin0 -> 352922 bytes
-rw-r--r--examples/datavisualization/graphgallery/data/oilrig.obj2322
-rw-r--r--examples/datavisualization/graphgallery/data/pipe.obj330
-rw-r--r--examples/datavisualization/graphgallery/data/raindata.txt158
-rw-r--r--examples/datavisualization/graphgallery/data/refinery.obj2330
-rw-r--r--examples/datavisualization/graphgallery/data/topography.pngbin0 -> 395504 bytes
-rw-r--r--examples/datavisualization/graphgallery/doc/images/graphgallery-example.pngbin0 -> 375425 bytes
-rw-r--r--examples/datavisualization/graphgallery/doc/src/graphgallery.qdoc705
-rw-r--r--examples/datavisualization/graphgallery/graphgallery.pro49
-rw-r--r--examples/datavisualization/graphgallery/graphgallery.qrc13
-rw-r--r--examples/datavisualization/graphgallery/graphmodifier.cpp441
-rw-r--r--examples/datavisualization/graphgallery/graphmodifier.h87
-rw-r--r--examples/datavisualization/graphgallery/highlightseries.cpp101
-rw-r--r--examples/datavisualization/graphgallery/highlightseries.h35
-rw-r--r--examples/datavisualization/graphgallery/main.cpp52
-rw-r--r--examples/datavisualization/graphgallery/rainfalldata.cpp117
-rw-r--r--examples/datavisualization/graphgallery/rainfalldata.h43
-rw-r--r--examples/datavisualization/graphgallery/scatterdatamodifier.cpp191
-rw-r--r--examples/datavisualization/graphgallery/scatterdatamodifier.h49
-rw-r--r--examples/datavisualization/graphgallery/scattergraph.cpp142
-rw-r--r--examples/datavisualization/graphgallery/scattergraph.h26
-rw-r--r--examples/datavisualization/graphgallery/surfacegraph.cpp346
-rw-r--r--examples/datavisualization/graphgallery/surfacegraph.h26
-rw-r--r--examples/datavisualization/graphgallery/surfacegraphmodifier.cpp647
-rw-r--r--examples/datavisualization/graphgallery/surfacegraphmodifier.h109
-rw-r--r--examples/datavisualization/graphgallery/topographicseries.cpp55
-rw-r--r--examples/datavisualization/graphgallery/topographicseries.h26
-rw-r--r--examples/datavisualization/graphgallery/variantbardatamapping.cpp85
-rw-r--r--examples/datavisualization/graphgallery/variantbardatamapping.h66
-rw-r--r--examples/datavisualization/graphgallery/variantbardataproxy.cpp114
-rw-r--r--examples/datavisualization/graphgallery/variantbardataproxy.h48
-rw-r--r--examples/datavisualization/graphgallery/variantdataset.cpp45
-rw-r--r--examples/datavisualization/graphgallery/variantdataset.h41
44 files changed, 9713 insertions, 0 deletions
diff --git a/examples/datavisualization/graphgallery/CMakeLists.txt b/examples/datavisualization/graphgallery/CMakeLists.txt
new file mode 100644
index 00000000..c66fee25
--- /dev/null
+++ b/examples/datavisualization/graphgallery/CMakeLists.txt
@@ -0,0 +1,75 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(graphgallery LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS DataVisualization)
+
+qt_add_executable(graphgallery
+ main.cpp
+ bargraph.cpp bargraph.h
+ graphmodifier.cpp graphmodifier.h
+ rainfalldata.cpp rainfalldata.h
+ variantbardatamapping.cpp variantbardatamapping.h
+ variantbardataproxy.cpp variantbardataproxy.h
+ variantdataset.cpp variantdataset.h
+ scattergraph.cpp scattergraph.h
+ scatterdatamodifier.cpp scatterdatamodifier.h
+ axesinputhandler.cpp axesinputhandler.h
+ surfacegraph.cpp surfacegraph.h
+ surfacegraphmodifier.cpp surfacegraphmodifier.h
+ custominputhandler.cpp custominputhandler.h
+ highlightseries.cpp highlightseries.h
+ topographicseries.cpp topographicseries.h
+)
+set_target_properties(graphgallery PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(graphgallery PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
+ Qt::DataVisualization
+)
+
+set(graphgallery_resource_files
+ "data/raindata.txt"
+ "data/layer_1.png"
+ "data/layer_2.png"
+ "data/layer_3.png"
+ "data/oilrig.obj"
+ "data/pipe.obj"
+ "data/refinery.obj"
+ "data/maptexture.jpg"
+ "data/topography.png"
+)
+
+qt6_add_resources(graphgallery "graphgallery"
+ PREFIX
+ "/"
+ FILES
+ ${graphgallery_resource_files}
+)
+
+install(TARGETS graphgallery
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/datavisualization/graphgallery/axesinputhandler.cpp b/examples/datavisualization/graphgallery/axesinputhandler.cpp
new file mode 100644
index 00000000..3292650e
--- /dev/null
+++ b/examples/datavisualization/graphgallery/axesinputhandler.cpp
@@ -0,0 +1,116 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "axesinputhandler.h"
+#include <QtCore/qmath.h>
+
+AxesInputHandler::AxesInputHandler(QAbstract3DGraph *graph, QObject *parent) :
+ Q3DInputHandler(parent)
+{
+ //! [3]
+ // Connect to the item selection signal from graph
+ connect(graph, &QAbstract3DGraph::selectedElementChanged, this,
+ &AxesInputHandler::handleElementSelected);
+ //! [3]
+}
+
+//! [0]
+void AxesInputHandler::mousePressEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q3DInputHandler::mousePressEvent(event, mousePos);
+ if (Qt::LeftButton == event->button())
+ m_mousePressed = true;
+}
+//! [0]
+
+//! [2]
+void AxesInputHandler::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ //! [5]
+ // Check if we're trying to drag axis label
+ if (m_mousePressed && m_state != StateNormal) {
+ //! [5]
+ setPreviousInputPos(inputPosition());
+ setInputPosition(mousePos);
+ handleAxisDragging();
+ } else {
+ Q3DInputHandler::mouseMoveEvent(event, mousePos);
+ }
+}
+//! [2]
+
+//! [1]
+void AxesInputHandler::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q3DInputHandler::mouseReleaseEvent(event, mousePos);
+ m_mousePressed = false;
+ m_state = StateNormal;
+}
+//! [1]
+
+void AxesInputHandler::handleElementSelected(QAbstract3DGraph::ElementType type)
+{
+ //! [4]
+ switch (type) {
+ case QAbstract3DGraph::ElementAxisXLabel:
+ m_state = StateDraggingX;
+ break;
+ case QAbstract3DGraph::ElementAxisYLabel:
+ m_state = StateDraggingY;
+ break;
+ case QAbstract3DGraph::ElementAxisZLabel:
+ m_state = StateDraggingZ;
+ break;
+ default:
+ m_state = StateNormal;
+ break;
+ }
+ //! [4]
+}
+
+void AxesInputHandler::handleAxisDragging()
+{
+ float distance = 0.0f;
+
+ //! [6]
+ // Get scene orientation from active camera
+ float xRotation = scene()->activeCamera()->xRotation();
+ float yRotation = scene()->activeCamera()->yRotation();
+ //! [6]
+
+ //! [7]
+ // Calculate directional drag multipliers based on rotation
+ float xMulX = qCos(qDegreesToRadians(xRotation));
+ float xMulY = qSin(qDegreesToRadians(xRotation));
+ float zMulX = qSin(qDegreesToRadians(xRotation));
+ float zMulY = qCos(qDegreesToRadians(xRotation));
+ //! [7]
+
+ //! [8]
+ // Get the drag amount
+ QPoint move = inputPosition() - previousInputPos();
+
+ // Flip the effect of y movement if we're viewing from below
+ float yMove = (yRotation < 0) ? -move.y() : move.y();
+ //! [8]
+
+ //! [9]
+ // Adjust axes
+ switch (m_state) {
+ case StateDraggingX:
+ distance = (move.x() * xMulX - yMove * xMulY) / m_speedModifier;
+ m_axisX->setRange(m_axisX->min() - distance, m_axisX->max() - distance);
+ break;
+ case StateDraggingZ:
+ distance = (move.x() * zMulX + yMove * zMulY) / m_speedModifier;
+ m_axisZ->setRange(m_axisZ->min() + distance, m_axisZ->max() + distance);
+ break;
+ case StateDraggingY:
+ distance = move.y() / m_speedModifier; // No need to use adjusted y move here
+ m_axisY->setRange(m_axisY->min() + distance, m_axisY->max() + distance);
+ break;
+ default:
+ break;
+ }
+ //! [9]
+}
diff --git a/examples/datavisualization/graphgallery/axesinputhandler.h b/examples/datavisualization/graphgallery/axesinputhandler.h
new file mode 100644
index 00000000..bb8432ac
--- /dev/null
+++ b/examples/datavisualization/graphgallery/axesinputhandler.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef AXESINPUTHANDLER_H
+#define AXESINPUTHANDLER_H
+
+#include <QtDataVisualization/q3dinputhandler.h>
+#include <QtDataVisualization/qabstract3dgraph.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+
+//! [0]
+class AxesInputHandler : public Q3DInputHandler
+//! [0]
+{
+ Q_OBJECT
+
+ enum InputState {
+ StateNormal = 0,
+ StateDraggingX,
+ StateDraggingZ,
+ StateDraggingY
+ };
+
+public:
+ explicit AxesInputHandler(QAbstract3DGraph *graph, QObject *parent = 0);
+
+ inline void setAxes(QValue3DAxis *axisX, QValue3DAxis *axisZ, QValue3DAxis *axisY) {
+ m_axisX = axisX;
+ m_axisZ = axisZ;
+ m_axisY = axisY;
+ }
+
+ //! [1]
+ inline void setDragSpeedModifier(float modifier) { m_speedModifier = modifier; }
+ //! [1]
+
+ virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos);
+
+private:
+ void handleElementSelected(QAbstract3DGraph::ElementType type);
+ void handleAxisDragging();
+
+private:
+ bool m_mousePressed = false;
+ InputState m_state = StateNormal;
+ QValue3DAxis *m_axisX = nullptr;
+ QValue3DAxis *m_axisZ = nullptr;
+ QValue3DAxis *m_axisY = nullptr;
+ float m_speedModifier = 15.f;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/bargraph.cpp b/examples/datavisualization/graphgallery/bargraph.cpp
new file mode 100644
index 00000000..5873c757
--- /dev/null
+++ b/examples/datavisualization/graphgallery/bargraph.cpp
@@ -0,0 +1,329 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "bargraph.h"
+#include "graphmodifier.h"
+
+#include <QtWidgets/qboxlayout.h>
+#include <QtWidgets/qpushbutton.h>
+#include <QtWidgets/qcheckbox.h>
+#include <QtWidgets/qslider.h>
+#include <QtWidgets/qfontcombobox.h>
+#include <QtWidgets/qlabel.h>
+#include <QtWidgets/qradiobutton.h>
+#include <QtWidgets/qbuttongroup.h>
+#include <QtGui/qfontdatabase.h>
+
+using namespace Qt::StringLiterals;
+
+BarGraph::BarGraph()
+{
+ //! [0]
+ m_barsGraph = new Q3DBars();
+ //! [0]
+}
+
+BarGraph::~BarGraph() = default;
+
+bool BarGraph::initialize(const QSize &minimumGraphSize, const QSize &maximumGraphSize)
+{
+ if (!m_barsGraph->hasContext())
+ return false;
+
+ //! [1]
+ m_barsWidget = new QWidget;
+ auto *hLayout = new QHBoxLayout(m_barsWidget);
+ m_container = QWidget::createWindowContainer(m_barsGraph, m_barsWidget);
+ m_barsGraph->resize(minimumGraphSize);
+ m_container->setMinimumSize(minimumGraphSize);
+ m_container->setMaximumSize(maximumGraphSize);
+ m_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_container->setFocusPolicy(Qt::StrongFocus);
+ hLayout->addWidget(m_container, 1);
+
+ auto *vLayout = new QVBoxLayout();
+ hLayout->addLayout(vLayout);
+ //! [1]
+
+ auto *themeList = new QComboBox(m_barsWidget);
+ themeList->addItem(u"Qt"_s);
+ themeList->addItem(u"Primary Colors"_s);
+ themeList->addItem(u"Digia"_s);
+ themeList->addItem(u"Stone Moss"_s);
+ themeList->addItem(u"Army Blue"_s);
+ themeList->addItem(u"Retro"_s);
+ themeList->addItem(u"Ebony"_s);
+ themeList->addItem(u"Isabelle"_s);
+ themeList->setCurrentIndex(0);
+
+ auto *labelButton = new QPushButton(m_barsWidget);
+ labelButton->setText(u"Change label style"_s);
+
+ auto *smoothCheckBox = new QCheckBox(m_barsWidget);
+ smoothCheckBox->setText(u"Smooth bars"_s);
+ smoothCheckBox->setChecked(false);
+
+ auto *barStyleList = new QComboBox(m_barsWidget);
+ barStyleList->addItem(u"Bar"_s, QAbstract3DSeries::MeshBar);
+ barStyleList->addItem(u"Pyramid"_s, QAbstract3DSeries::MeshPyramid);
+ barStyleList->addItem(u"Cone"_s, QAbstract3DSeries::MeshCone);
+ barStyleList->addItem(u"Cylinder"_s, QAbstract3DSeries::MeshCylinder);
+ barStyleList->addItem(u"Bevel bar"_s, QAbstract3DSeries::MeshBevelBar);
+ barStyleList->addItem(u"Sphere"_s, QAbstract3DSeries::MeshSphere);
+ barStyleList->setCurrentIndex(4);
+
+ auto *cameraButton = new QPushButton(m_barsWidget);
+ cameraButton->setText(u"Change camera preset"_s);
+
+ auto *zoomToSelectedButton = new QPushButton(m_barsWidget);
+ zoomToSelectedButton->setText(u"Zoom to selected bar"_s);
+
+ auto *selectionModeList = new QComboBox(m_barsWidget);
+ selectionModeList->addItem(u"None"_s,
+ int(QAbstract3DGraph::SelectionNone));
+ selectionModeList->addItem(u"Bar"_s,
+ int(QAbstract3DGraph::SelectionItem));
+ selectionModeList->addItem(u"Row"_s,
+ int(QAbstract3DGraph::SelectionRow));
+ selectionModeList->addItem(u"Bar and Row"_s,
+ int(QAbstract3DGraph::SelectionItemAndRow));
+ selectionModeList->addItem(u"Column"_s,
+ int(QAbstract3DGraph::SelectionColumn));
+ selectionModeList->addItem(u"Bar and Column"_s,
+ int(QAbstract3DGraph::SelectionItemAndColumn));
+ selectionModeList->addItem(u"Row and Column"_s,
+ int(QAbstract3DGraph::SelectionRowAndColumn));
+ selectionModeList->addItem(u"Bar, Row and Column"_s,
+ int(QAbstract3DGraph::SelectionItemRowAndColumn));
+ selectionModeList->addItem(u"Slice into Row"_s,
+ int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionRow));
+ selectionModeList->addItem(u"Slice into Row and Item"_s,
+ int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndRow));
+ selectionModeList->addItem(u"Slice into Column"_s,
+ int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionColumn));
+ selectionModeList->addItem(u"Slice into Column and Item"_s,
+ int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndColumn));
+ selectionModeList->addItem(u"Multi: Bar, Row, Col"_s,
+ int(QAbstract3DGraph::SelectionItemRowAndColumn
+ | QAbstract3DGraph::SelectionMultiSeries));
+ selectionModeList->addItem(u"Multi, Slice: Row, Item"_s,
+ int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndRow
+ | QAbstract3DGraph::SelectionMultiSeries));
+ selectionModeList->addItem(u"Multi, Slice: Col, Item"_s,
+ int(QAbstract3DGraph::SelectionSlice | QAbstract3DGraph::SelectionItemAndColumn
+ | QAbstract3DGraph::SelectionMultiSeries));
+ selectionModeList->setCurrentIndex(1);
+
+ auto *backgroundCheckBox = new QCheckBox(m_barsWidget);
+ backgroundCheckBox->setText(u"Show background"_s);
+ backgroundCheckBox->setChecked(false);
+
+ auto *gridCheckBox = new QCheckBox(m_barsWidget);
+ gridCheckBox->setText(u"Show grid"_s);
+ gridCheckBox->setChecked(true);
+
+ auto *seriesCheckBox = new QCheckBox(m_barsWidget);
+ seriesCheckBox->setText(u"Show second series"_s);
+ seriesCheckBox->setChecked(false);
+
+ auto *reverseValueAxisCheckBox = new QCheckBox(m_barsWidget);
+ reverseValueAxisCheckBox->setText(u"Reverse value axis"_s);
+ reverseValueAxisCheckBox->setChecked(false);
+
+ auto *reflectionCheckBox = new QCheckBox(m_barsWidget);
+ reflectionCheckBox->setText(u"Show reflections"_s);
+ reflectionCheckBox->setChecked(false);
+
+ //! [3]
+ auto *rotationSliderX = new QSlider(Qt::Horizontal, m_barsWidget);
+ rotationSliderX->setTickInterval(30);
+ rotationSliderX->setTickPosition(QSlider::TicksBelow);
+ rotationSliderX->setMinimum(-180);
+ rotationSliderX->setValue(0);
+ rotationSliderX->setMaximum(180);
+ //! [3]
+ auto *rotationSliderY = new QSlider(Qt::Horizontal, m_barsWidget);
+ rotationSliderY->setTickInterval(15);
+ rotationSliderY->setTickPosition(QSlider::TicksAbove);
+ rotationSliderY->setMinimum(-90);
+ rotationSliderY->setValue(0);
+ rotationSliderY->setMaximum(90);
+
+ auto *fontSizeSlider = new QSlider(Qt::Horizontal, m_barsWidget);
+ fontSizeSlider->setTickInterval(10);
+ fontSizeSlider->setTickPosition(QSlider::TicksBelow);
+ fontSizeSlider->setMinimum(1);
+ fontSizeSlider->setValue(30);
+ fontSizeSlider->setMaximum(100);
+
+ auto *fontList = new QFontComboBox(m_barsWidget);
+ fontList->setCurrentFont(QFont("Times New Roman"));
+
+ auto *shadowQuality = new QComboBox(m_barsWidget);
+ shadowQuality->addItem(u"None"_s);
+ shadowQuality->addItem(u"Low"_s);
+ shadowQuality->addItem(u"Medium"_s);
+ shadowQuality->addItem(u"High"_s);
+ shadowQuality->addItem(u"Low Soft"_s);
+ shadowQuality->addItem(u"Medium Soft"_s);
+ shadowQuality->addItem(u"High Soft"_s);
+ shadowQuality->setCurrentIndex(5);
+
+ auto *rangeList = new QComboBox(m_barsWidget);
+ rangeList->addItem(u"2015"_s);
+ rangeList->addItem(u"2016"_s);
+ rangeList->addItem(u"2017"_s);
+ rangeList->addItem(u"2018"_s);
+ rangeList->addItem(u"2019"_s);
+ rangeList->addItem(u"2020"_s);
+ rangeList->addItem(u"2021"_s);
+ rangeList->addItem(u"2022"_s);
+ rangeList->addItem(u"All"_s);
+ rangeList->setCurrentIndex(8);
+
+ auto *axisTitlesVisibleCB = new QCheckBox(m_barsWidget);
+ axisTitlesVisibleCB->setText(u"Axis titles visible"_s);
+ axisTitlesVisibleCB->setChecked(true);
+
+ auto *axisTitlesFixedCB = new QCheckBox(m_barsWidget);
+ axisTitlesFixedCB->setText(u"Axis titles fixed"_s);
+ axisTitlesFixedCB->setChecked(true);
+
+ auto *axisLabelRotationSlider = new QSlider(Qt::Horizontal, m_barsWidget);
+ axisLabelRotationSlider->setTickInterval(10);
+ axisLabelRotationSlider->setTickPosition(QSlider::TicksBelow);
+ axisLabelRotationSlider->setMinimum(0);
+ axisLabelRotationSlider->setValue(30);
+ axisLabelRotationSlider->setMaximum(90);
+
+ auto *modeGroup = new QButtonGroup(m_barsWidget);
+ auto *modeWeather = new QRadioButton(u"Temperature Data"_s, m_barsWidget);
+ modeWeather->setChecked(true);
+ auto *modeCustomProxy = new QRadioButton(u"Custom Proxy Data"_s, m_barsWidget);
+ modeGroup->addButton(modeWeather);
+ modeGroup->addButton(modeCustomProxy);
+
+ //! [4]
+ vLayout->addWidget(new QLabel(u"Rotate horizontally"_s));
+ vLayout->addWidget(rotationSliderX, 0, Qt::AlignTop);
+ //! [4]
+ vLayout->addWidget(new QLabel(u"Rotate vertically"_s));
+ vLayout->addWidget(rotationSliderY, 0, Qt::AlignTop);
+ vLayout->addWidget(labelButton, 0, Qt::AlignTop);
+ vLayout->addWidget(cameraButton, 0, Qt::AlignTop);
+ vLayout->addWidget(zoomToSelectedButton, 0, Qt::AlignTop);
+ vLayout->addWidget(backgroundCheckBox);
+ vLayout->addWidget(gridCheckBox);
+ vLayout->addWidget(smoothCheckBox);
+ vLayout->addWidget(reflectionCheckBox);
+ vLayout->addWidget(seriesCheckBox);
+ vLayout->addWidget(reverseValueAxisCheckBox);
+ vLayout->addWidget(axisTitlesVisibleCB);
+ vLayout->addWidget(axisTitlesFixedCB);
+ vLayout->addWidget(new QLabel(u"Show year"_s));
+ vLayout->addWidget(rangeList);
+ vLayout->addWidget(new QLabel(u"Change bar style"_s));
+ vLayout->addWidget(barStyleList);
+ vLayout->addWidget(new QLabel(u"Change selection mode"_s));
+ vLayout->addWidget(selectionModeList);
+ vLayout->addWidget(new QLabel(u"Change theme"_s));
+ vLayout->addWidget(themeList);
+ vLayout->addWidget(new QLabel(u"Adjust shadow quality"_s));
+ vLayout->addWidget(shadowQuality);
+ vLayout->addWidget(new QLabel(u"Change font"_s));
+ vLayout->addWidget(fontList);
+ vLayout->addWidget(new QLabel(u"Adjust font size"_s));
+ vLayout->addWidget(fontSizeSlider);
+ vLayout->addWidget(new QLabel(u"Axis label rotation"_s));
+ vLayout->addWidget(axisLabelRotationSlider, 0, Qt::AlignTop);
+ vLayout->addWidget(modeWeather, 0, Qt::AlignTop);
+ vLayout->addWidget(modeCustomProxy, 1, Qt::AlignTop);
+
+ //! [2]
+ auto *modifier = new GraphModifier(m_barsGraph, this);
+ //! [2]
+
+ //! [5]
+ QObject::connect(rotationSliderX, &QSlider::valueChanged, modifier, &GraphModifier::rotateX);
+ //! [5]
+ QObject::connect(rotationSliderY, &QSlider::valueChanged, modifier, &GraphModifier::rotateY);
+
+ QObject::connect(labelButton, &QPushButton::clicked, modifier,
+ &GraphModifier::changeLabelBackground);
+ QObject::connect(cameraButton, &QPushButton::clicked, modifier,
+ &GraphModifier::changePresetCamera);
+ QObject::connect(zoomToSelectedButton, &QPushButton::clicked, modifier,
+ &GraphModifier::zoomToSelectedBar);
+
+ QObject::connect(backgroundCheckBox, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setBackgroundEnabled);
+ QObject::connect(gridCheckBox, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setGridEnabled);
+ QObject::connect(smoothCheckBox, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setSmoothBars);
+ QObject::connect(seriesCheckBox, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setSeriesVisibility);
+ QObject::connect(reverseValueAxisCheckBox, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setReverseValueAxis);
+ QObject::connect(reflectionCheckBox, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setReflection);
+
+ QObject::connect(modifier, &GraphModifier::backgroundEnabledChanged,
+ backgroundCheckBox, &QCheckBox::setChecked);
+ QObject::connect(modifier, &GraphModifier::gridEnabledChanged,
+ gridCheckBox, &QCheckBox::setChecked);
+
+ QObject::connect(rangeList, &QComboBox::currentIndexChanged, modifier,
+ &GraphModifier::changeRange);
+
+ QObject::connect(barStyleList, &QComboBox::currentIndexChanged, modifier,
+ &GraphModifier::changeStyle);
+
+ QObject::connect(selectionModeList, &QComboBox::currentIndexChanged, modifier,
+ &GraphModifier::changeSelectionMode);
+
+ QObject::connect(themeList, &QComboBox::currentIndexChanged, modifier,
+ &GraphModifier::changeTheme);
+
+ QObject::connect(shadowQuality, &QComboBox::currentIndexChanged, modifier,
+ &GraphModifier::changeShadowQuality);
+
+ QObject::connect(modifier, &GraphModifier::shadowQualityChanged, shadowQuality,
+ &QComboBox::setCurrentIndex);
+ QObject::connect(m_barsGraph, &Q3DBars::shadowQualityChanged, modifier,
+ &GraphModifier::shadowQualityUpdatedByVisual);
+
+ QObject::connect(fontSizeSlider, &QSlider::valueChanged, modifier,
+ &GraphModifier::changeFontSize);
+ QObject::connect(fontList, &QFontComboBox::currentFontChanged, modifier,
+ &GraphModifier::changeFont);
+
+ QObject::connect(modifier, &GraphModifier::fontSizeChanged, fontSizeSlider,
+ &QSlider::setValue);
+ QObject::connect(modifier, &GraphModifier::fontChanged, fontList,
+ &QFontComboBox::setCurrentFont);
+
+ QObject::connect(axisTitlesVisibleCB, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setAxisTitleVisibility);
+ QObject::connect(axisTitlesFixedCB, &QCheckBox::stateChanged, modifier,
+ &GraphModifier::setAxisTitleFixed);
+ QObject::connect(axisLabelRotationSlider, &QSlider::valueChanged, modifier,
+ &GraphModifier::changeLabelRotation);
+
+ QObject::connect(modeWeather, &QRadioButton::toggled, modifier,
+ &GraphModifier::setDataModeToWeather);
+ QObject::connect(modeCustomProxy, &QRadioButton::toggled, modifier,
+ &GraphModifier::setDataModeToCustom);
+ QObject::connect(modeWeather, &QRadioButton::toggled, seriesCheckBox,
+ &QCheckBox::setEnabled);
+ QObject::connect(modeWeather, &QRadioButton::toggled, rangeList,
+ &QComboBox::setEnabled);
+ QObject::connect(modeWeather, &QRadioButton::toggled, axisTitlesVisibleCB,
+ &QCheckBox::setEnabled);
+ QObject::connect(modeWeather, &QRadioButton::toggled, axisTitlesFixedCB,
+ &QCheckBox::setEnabled);
+ QObject::connect(modeWeather, &QRadioButton::toggled, axisLabelRotationSlider,
+ &QSlider::setEnabled);
+
+ return true;
+}
diff --git a/examples/datavisualization/graphgallery/bargraph.h b/examples/datavisualization/graphgallery/bargraph.h
new file mode 100644
index 00000000..004c14eb
--- /dev/null
+++ b/examples/datavisualization/graphgallery/bargraph.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef BARGRAPH_H
+#define BARGRAPH_H
+
+#include <QtDataVisualization/q3dbars.h>
+#include <QtCore/qobject.h>
+
+class BarGraph : public QObject
+{
+ Q_OBJECT
+public:
+ BarGraph();
+ ~BarGraph();
+
+ bool initialize(const QSize &minimumGraphSize, const QSize &maximumGraphSize);
+ QWidget *barsWidget() { return m_barsWidget; }
+
+private:
+ Q3DBars *m_barsGraph = nullptr;
+ QWidget *m_container = nullptr;
+ QWidget *m_barsWidget = nullptr;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/custominputhandler.cpp b/examples/datavisualization/graphgallery/custominputhandler.cpp
new file mode 100644
index 00000000..f9f06871
--- /dev/null
+++ b/examples/datavisualization/graphgallery/custominputhandler.cpp
@@ -0,0 +1,161 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "custominputhandler.h"
+
+#include <QtDataVisualization/q3dcamera.h>
+#include <QtCore/qmath.h>
+
+CustomInputHandler::CustomInputHandler(QAbstract3DGraph *graph, QObject *parent) :
+ Q3DInputHandler(parent)
+{
+ // Connect to the item selection signal from graph
+ connect(graph, &QAbstract3DGraph::selectedElementChanged, this,
+ &CustomInputHandler::handleElementSelected);
+}
+
+void CustomInputHandler::mousePressEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ if (Qt::LeftButton == event->button()) {
+ m_highlight->setVisible(false);
+ m_mousePressed = true;
+ }
+ Q3DInputHandler::mousePressEvent(event, mousePos);
+}
+
+//! [1]
+void CustomInputHandler::wheelEvent(QWheelEvent *event)
+{
+ float delta = float(event->angleDelta().y());
+
+ m_axisXMinValue += delta;
+ m_axisXMaxValue -= delta;
+ m_axisZMinValue += delta;
+ m_axisZMaxValue -= delta;
+ checkConstraints();
+
+ float y = (m_axisXMaxValue - m_axisXMinValue) * m_aspectRatio;
+
+ m_axisX->setRange(m_axisXMinValue, m_axisXMaxValue);
+ m_axisY->setRange(100.f, y);
+ m_axisZ->setRange(m_axisZMinValue, m_axisZMaxValue);
+}
+//! [1]
+
+void CustomInputHandler::mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ // Check if we're trying to drag axis label
+ if (m_mousePressed && m_state != StateNormal) {
+ setPreviousInputPos(inputPosition());
+ setInputPosition(mousePos);
+ handleAxisDragging();
+ } else {
+ Q3DInputHandler::mouseMoveEvent(event, mousePos);
+ }
+}
+
+void CustomInputHandler::mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos)
+{
+ Q3DInputHandler::mouseReleaseEvent(event, mousePos);
+ m_mousePressed = false;
+ m_state = StateNormal;
+}
+
+void CustomInputHandler::handleElementSelected(QAbstract3DGraph::ElementType type)
+{
+ switch (type) {
+ case QAbstract3DGraph::ElementAxisXLabel:
+ m_state = StateDraggingX;
+ break;
+ case QAbstract3DGraph::ElementAxisZLabel:
+ m_state = StateDraggingZ;
+ break;
+ default:
+ m_state = StateNormal;
+ break;
+ }
+}
+
+void CustomInputHandler::handleAxisDragging()
+{
+ float distance = 0.f;
+
+ // Get scene orientation from active camera
+ float xRotation = scene()->activeCamera()->xRotation();
+
+ // Calculate directional drag multipliers based on rotation
+ float xMulX = qCos(qDegreesToRadians(xRotation));
+ float xMulY = qSin(qDegreesToRadians(xRotation));
+ float zMulX = qSin(qDegreesToRadians(xRotation));
+ float zMulY = qCos(qDegreesToRadians(xRotation));
+
+ // Get the drag amount
+ QPoint move = inputPosition() - previousInputPos();
+
+ // Adjust axes
+ switch (m_state) {
+ //! [0]
+ case StateDraggingX:
+ distance = (move.x() * xMulX - move.y() * xMulY) * m_speedModifier;
+ m_axisXMinValue -= distance;
+ m_axisXMaxValue -= distance;
+ if (m_axisXMinValue < m_areaMinValue) {
+ float dist = m_axisXMaxValue - m_axisXMinValue;
+ m_axisXMinValue = m_areaMinValue;
+ m_axisXMaxValue = m_axisXMinValue + dist;
+ }
+ if (m_axisXMaxValue > m_areaMaxValue) {
+ float dist = m_axisXMaxValue - m_axisXMinValue;
+ m_axisXMaxValue = m_areaMaxValue;
+ m_axisXMinValue = m_axisXMaxValue - dist;
+ }
+ m_axisX->setRange(m_axisXMinValue, m_axisXMaxValue);
+ break;
+ //! [0]
+ case StateDraggingZ:
+ distance = (move.x() * zMulX + move.y() * zMulY) * m_speedModifier;
+ m_axisZMinValue += distance;
+ m_axisZMaxValue += distance;
+ if (m_axisZMinValue < m_areaMinValue) {
+ float dist = m_axisZMaxValue - m_axisZMinValue;
+ m_axisZMinValue = m_areaMinValue;
+ m_axisZMaxValue = m_axisZMinValue + dist;
+ }
+ if (m_axisZMaxValue > m_areaMaxValue) {
+ float dist = m_axisZMaxValue - m_axisZMinValue;
+ m_axisZMaxValue = m_areaMaxValue;
+ m_axisZMinValue = m_axisZMaxValue - dist;
+ }
+ m_axisZ->setRange(m_axisZMinValue, m_axisZMaxValue);
+ break;
+ default:
+ break;
+ }
+}
+
+void CustomInputHandler::checkConstraints()
+{
+ //! [2]
+ if (m_axisXMinValue < m_areaMinValue)
+ m_axisXMinValue = m_areaMinValue;
+ if (m_axisXMaxValue > m_areaMaxValue)
+ m_axisXMaxValue = m_areaMaxValue;
+ // Don't allow too much zoom in
+ if ((m_axisXMaxValue - m_axisXMinValue) < m_axisXMinRange) {
+ float adjust = (m_axisXMinRange - (m_axisXMaxValue - m_axisXMinValue)) / 2.f;
+ m_axisXMinValue -= adjust;
+ m_axisXMaxValue += adjust;
+ }
+ //! [2]
+
+ if (m_axisZMinValue < m_areaMinValue)
+ m_axisZMinValue = m_areaMinValue;
+ if (m_axisZMaxValue > m_areaMaxValue)
+ m_axisZMaxValue = m_areaMaxValue;
+ // Don't allow too much zoom in
+ if ((m_axisZMaxValue - m_axisZMinValue) < m_axisZMinRange) {
+ float adjust = (m_axisZMinRange - (m_axisZMaxValue - m_axisZMinValue)) / 2.f;
+ m_axisZMinValue -= adjust;
+ m_axisZMaxValue += adjust;
+ }
+}
diff --git a/examples/datavisualization/graphgallery/custominputhandler.h b/examples/datavisualization/graphgallery/custominputhandler.h
new file mode 100644
index 00000000..a28b5851
--- /dev/null
+++ b/examples/datavisualization/graphgallery/custominputhandler.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef CUSTOMINPUTHANDLER_H
+#define CUSTOMINPUTHANDLER_H
+
+#include "highlightseries.h"
+
+#include <QtDataVisualization/q3dinputhandler.h>
+#include <QtDataVisualization/qabstract3dgraph.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+
+class CustomInputHandler : public Q3DInputHandler
+{
+ Q_OBJECT
+
+ enum InputState {
+ StateNormal = 0,
+ StateDraggingX,
+ StateDraggingZ,
+ StateDraggingY
+ };
+
+public:
+ explicit CustomInputHandler(QAbstract3DGraph *graph, QObject *parent = 0);
+
+ inline void setLimits(float min, float max, float minRange) {
+ m_areaMinValue = min;
+ m_areaMaxValue = max;
+ m_axisXMinValue = m_areaMinValue;
+ m_axisXMaxValue = m_areaMaxValue;
+ m_axisZMinValue = m_areaMinValue;
+ m_axisZMaxValue = m_areaMaxValue;
+ m_axisXMinRange = minRange;
+ m_axisZMinRange = minRange;
+ }
+ inline void setAxes(QValue3DAxis *axisX, QValue3DAxis *axisY, QValue3DAxis *axisZ) {
+ m_axisX = axisX;
+ m_axisY = axisY;
+ m_axisZ = axisZ;
+ }
+ inline void setAspectRatio(float ratio) { m_aspectRatio = ratio; }
+ inline void setHighlightSeries(HighlightSeries *series) { m_highlight = series; }
+ inline void setDragSpeedModifier(float modifier) { m_speedModifier = modifier; }
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseMoveEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void mouseReleaseEvent(QMouseEvent *event, const QPoint &mousePos);
+ virtual void wheelEvent(QWheelEvent *event);
+
+private:
+ void handleElementSelected(QAbstract3DGraph::ElementType type);
+ void handleAxisDragging();
+ void checkConstraints();
+
+private:
+ HighlightSeries *m_highlight = nullptr;
+ bool m_mousePressed = false;
+ InputState m_state = StateNormal;
+ QValue3DAxis *m_axisX = nullptr;
+ QValue3DAxis *m_axisY = nullptr;
+ QValue3DAxis *m_axisZ = nullptr;
+ float m_speedModifier = 20.f;
+ float m_aspectRatio = 0.f;
+ float m_axisXMinValue = 0.f;
+ float m_axisXMaxValue = 0.f;
+ float m_axisXMinRange = 0.f;
+ float m_axisZMinValue = 0.f;
+ float m_axisZMaxValue = 0.f;
+ float m_axisZMinRange = 0.f;
+ float m_areaMinValue = 0.f;
+ float m_areaMaxValue = 0.f;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/data/layer_1.png b/examples/datavisualization/graphgallery/data/layer_1.png
new file mode 100644
index 00000000..9138c710
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/layer_1.png
Binary files differ
diff --git a/examples/datavisualization/graphgallery/data/layer_2.png b/examples/datavisualization/graphgallery/data/layer_2.png
new file mode 100644
index 00000000..61631ae8
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/layer_2.png
Binary files differ
diff --git a/examples/datavisualization/graphgallery/data/layer_3.png b/examples/datavisualization/graphgallery/data/layer_3.png
new file mode 100644
index 00000000..066ffbe7
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/layer_3.png
Binary files differ
diff --git a/examples/datavisualization/graphgallery/data/license.txt b/examples/datavisualization/graphgallery/data/license.txt
new file mode 100644
index 00000000..749daf31
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/license.txt
@@ -0,0 +1,77 @@
+License information regarding the data obtained from National Land Survey of
+Finland http://www.maanmittauslaitos.fi/en
+- topographic model from Elevation model 2 m (U4421B, U4421D, U4422A and
+ U4422C) 08/2014
+- map image extracted from Topographic map raster 1:50 000 (U442) 08/2014
+
+National Land Survey open data licence - version 1.0 - 1 May 2012
+
+1. General information
+
+The National Land Survey of Finland (hereinafter the Licensor), as the holder
+of the immaterial rights to the data, has granted on the terms mentioned below
+the right to use a copy (hereinafter data or dataset(s)) of the data (or a part
+of it).
+
+The Licensee is a natural or legal person who makes use of the data covered by
+this licence. The Licensee accepts the terms of this licence by receiving the
+dataset(s) covered by the licence.
+
+This Licence agreement does not create a co-operation or business relationship
+between the Licensee and the Licensor.
+
+2. Terms of the licence
+
+2.1. Right of use
+
+This licence grants a worldwide, free of charge and irrevocable parallel right
+of use to open data. According to the terms of the licence, data received by
+the Licensee can be freely:
+ - copied, distributed and published,
+ - modified and utilised commercially and non-commercially,
+ - inserted into other products and
+ - used as a part of a software application or service.
+
+2.2. Duties and responsibilities of the Licensee
+
+Through reasonable means suitable to the distribution medium or method which is
+used in conjunction with a product containing data or a service utilising data
+covered by this licence or while distributing data, the Licensee shall:
+ - mention the name of the Licensor, the name of the dataset(s) and the time
+ when the National Land Survey has delivered the dataset(s) (e.g.: contains
+ data from the National Land Survey of Finland Topographic Database 06/2012)
+ - provide a copy of this licence or a link to it, as well as
+ - require third parties to provide the same information when granting rights
+ to copies of dataset(s) or products and services containing such data and
+ - remove the name of the Licensor from the product or service, if required to
+ do so by the Licensor.
+
+The terms of this licence do not allow the Licensee to state in conjunction
+with the use of dataset(s) that the Licensor supports or recommends such use.
+
+2.3. Duties and responsibilities of the Licensor
+
+The Licensor shall ensure that
+ - the Licensor has the right to grant rights to the dataset(s) in accordance
+ with this licence.
+
+The data has been licensed "as is" and the Licensor
+ - shall not be held responsible for any errors or omissions in the data,
+ disclaims any warranty for the validity or up to date status of the data and
+ shall be free from liability for direct or consequential damages arising
+ from the use of data provided by the Licensor,
+ - and is not obligated to ensure the continuous availability of the data, nor
+ to announce in advance the interruption or cessation of availability, and
+ the Licensor shall be free from liability for direct or consequential
+ damages arising from any such interruption or cessation.
+
+3. Jurisdiction
+
+Finnish law shall apply to this licence.
+
+4. Changes to this licence
+
+The Licensor may at any time change the terms of the licence or apply a
+different licence to the data. The terms of this licence shall, however, still
+apply to such data that has been received prior to the change of the terms of
+the licence or the licence itself.
diff --git a/examples/datavisualization/graphgallery/data/maptexture.jpg b/examples/datavisualization/graphgallery/data/maptexture.jpg
new file mode 100644
index 00000000..ae5d66eb
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/maptexture.jpg
Binary files differ
diff --git a/examples/datavisualization/graphgallery/data/oilrig.obj b/examples/datavisualization/graphgallery/data/oilrig.obj
new file mode 100644
index 00000000..c3b6ea57
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/oilrig.obj
@@ -0,0 +1,2322 @@
+# Blender v2.66 (sub 0) OBJ File: 'oilrig.blend'
+# www.blender.org
+v 0.057462 2.272318 -1.170324
+v 0.057461 8.181165 -0.128434
+v 0.055540 2.268930 -1.151111
+v 0.055539 8.177776 -0.109221
+v 0.049849 2.265673 -1.132637
+v 0.049849 8.174520 -0.090747
+v 0.040608 2.262671 -1.115611
+v 0.040608 8.171517 -0.073721
+v 0.028172 2.260039 -1.100687
+v 0.028172 8.168886 -0.058798
+v 0.013019 2.257880 -1.088440
+v 0.013018 8.166726 -0.046550
+v -0.004270 2.256275 -1.079339
+v -0.004271 8.165121 -0.037450
+v -0.023029 2.255287 -1.073735
+v -0.023030 8.164133 -0.031846
+v -0.042539 2.254953 -1.071843
+v -0.042539 8.163799 -0.029953
+v -0.062048 2.255287 -1.073735
+v -0.062048 8.164133 -0.031846
+v -0.080807 2.256275 -1.079339
+v -0.080808 8.165121 -0.037450
+v -0.098096 2.257880 -1.088440
+v -0.098096 8.166726 -0.046550
+v -0.113249 2.260039 -1.100687
+v -0.113250 8.168886 -0.058798
+v -0.125685 2.262671 -1.115611
+v -0.125686 8.171517 -0.073721
+v -0.134926 2.265673 -1.132637
+v -0.134927 8.174520 -0.090747
+v -0.140617 2.268930 -1.151111
+v -0.140618 8.177776 -0.109222
+v -0.142538 2.272318 -1.170324
+v -0.142539 8.181165 -0.128434
+v -0.140617 2.275706 -1.189536
+v -0.140618 8.184552 -0.147647
+v -0.134926 2.278963 -1.208011
+v -0.134927 8.187810 -0.166121
+v -0.125685 2.281965 -1.225037
+v -0.125686 8.190812 -0.183147
+v -0.113249 2.284597 -1.239960
+v -0.113250 8.193443 -0.198071
+v -0.098095 2.286757 -1.252208
+v -0.098096 8.195602 -0.210318
+v -0.080807 2.288361 -1.261308
+v -0.080807 8.197207 -0.219419
+v -0.062047 2.289349 -1.266912
+v -0.062048 8.198195 -0.225023
+v -0.042538 2.289683 -1.268804
+v -0.042539 8.198529 -0.226915
+v -0.023029 2.289349 -1.266912
+v -0.023030 8.198195 -0.225023
+v -0.004270 2.288361 -1.261308
+v -0.004271 8.197207 -0.219418
+v 0.013019 2.286757 -1.252207
+v 0.013018 8.195602 -0.210318
+v 0.028172 2.284597 -1.239960
+v 0.028172 8.193443 -0.198070
+v 0.040609 2.281965 -1.225036
+v 0.040608 8.190812 -0.183147
+v 0.049850 2.278963 -1.208010
+v 0.049849 8.187810 -0.166121
+v 0.055540 2.275706 -1.189536
+v 0.055539 8.184552 -0.147646
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.961940 0.308658
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.990393 0.597545
+vt 0.915735 0.222215
+vt 0.961940 0.691342
+vt 0.853553 0.146447
+vt 0.915735 0.777785
+vt 0.777785 0.084265
+vt 0.853553 0.853553
+vt 0.691342 0.038060
+vt 0.777785 0.915735
+vt 0.597545 0.009607
+vt 0.691342 0.961940
+vt 0.000000 0.500000
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.038060 0.691342
+vt 0.009607 0.597546
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.308659 0.961940
+vt 0.222215 0.915735
+vt 0.084265 0.222215
+vt 0.146447 0.853554
+vt 0.084266 0.777786
+vn 0.995185 -0.017020 0.096528
+vn 0.956940 -0.050408 0.285877
+vn 0.881921 -0.081857 0.464235
+vn 0.773009 -0.110162 0.624758
+vn 0.634397 -0.134231 0.761264
+vn 0.471397 -0.153144 0.868523
+vn 0.290285 -0.166171 0.942402
+vn 0.098018 -0.172812 0.980066
+vn -0.098022 -0.172812 0.980065
+vn -0.290285 -0.166171 0.942402
+vn -0.471392 -0.153145 0.868526
+vn -0.634399 -0.134231 0.761262
+vn -0.773009 -0.110162 0.624757
+vn -0.881923 -0.081857 0.464231
+vn -0.956941 -0.050407 0.285873
+vn -0.995185 -0.017021 0.096528
+vn -0.995185 0.017021 -0.096529
+vn -0.956940 0.050407 -0.285875
+vn -0.881920 0.081858 -0.464238
+vn -0.773015 0.110160 -0.624751
+vn -0.634391 0.134232 -0.761268
+vn -0.471394 0.153144 -0.868524
+vn -0.290288 0.166171 -0.942401
+vn -0.098006 0.172812 -0.980067
+vn 0.098019 0.172812 -0.980065
+vn 0.290285 0.166171 -0.942402
+vn 0.471401 0.153144 -0.868521
+vn 0.634393 0.134232 -0.761267
+vn 0.773011 0.110161 -0.624755
+vn 0.881922 0.081857 -0.464233
+vn -0.000000 0.984796 0.173713
+vn 0.995185 0.017020 -0.096527
+vn 0.956941 0.050407 -0.285872
+vn -0.000011 -0.984808 -0.173648
+vn 0.995185 -0.017020 0.096529
+vn 0.956940 -0.050407 0.285875
+vn 0.881920 -0.081858 0.464237
+vn 0.773011 -0.110161 0.624755
+vn 0.634396 -0.134231 0.761265
+vn 0.471389 -0.153145 0.868527
+vn 0.290287 -0.166171 0.942402
+vn 0.098019 -0.172812 0.980065
+vn -0.098021 -0.172812 0.980065
+vn -0.290282 -0.166171 0.942403
+vn -0.471402 -0.153144 0.868520
+vn -0.634395 -0.134232 0.761265
+vn -0.773010 -0.110161 0.624756
+vn -0.881922 -0.081857 0.464234
+vn -0.956940 -0.050408 0.285875
+vn -0.995185 -0.017020 0.096527
+vn -0.956940 0.050408 -0.285876
+vn -0.881921 0.081857 -0.464236
+vn -0.773009 0.110162 -0.624757
+vn -0.634391 0.134232 -0.761269
+vn -0.471398 0.153144 -0.868522
+vn -0.290282 0.166171 -0.942403
+vn -0.098016 0.172812 -0.980066
+vn 0.098018 0.172812 -0.980065
+vn 0.290287 0.166171 -0.942402
+vn 0.471399 0.153144 -0.868522
+vn 0.773014 0.110161 -0.624751
+vn 0.881921 0.081857 -0.464236
+vn -0.000000 0.984812 0.173622
+vn -0.000000 0.984812 0.173623
+vn -0.000000 0.984801 0.173685
+vn -0.000000 0.984814 0.173615
+vn -0.000000 0.984810 0.173634
+vn -0.000000 0.984808 0.173649
+vn -0.000000 0.984806 0.173660
+vn -0.000043 0.984788 0.173763
+vn -0.000000 0.984797 0.173710
+vn -0.000000 0.984805 0.173661
+vn -0.000000 0.984810 0.173635
+vn -0.000000 0.984810 0.173637
+vn -0.000000 0.984802 0.173683
+vn -0.000000 0.984814 0.173611
+vn -0.000000 0.984800 0.173689
+vn -0.000000 0.984800 0.173690
+vn -0.000000 0.984801 0.173686
+vn 0.000005 0.984810 0.173637
+vn 0.956941 0.050407 -0.285873
+vn -0.000000 -0.984818 -0.173587
+vn -0.000007 -0.984807 -0.173654
+vn -0.000000 -0.984808 -0.173648
+vn -0.000027 -0.984801 -0.173685
+vn -0.000004 -0.984807 -0.173652
+vn -0.000010 -0.984800 -0.173693
+vn -0.000020 -0.984817 -0.173596
+vn -0.000013 -0.984810 -0.173638
+vn -0.000001 -0.984807 -0.173650
+vn -0.000005 -0.984808 -0.173646
+vn -0.000002 -0.984808 -0.173648
+vn 0.000002 -0.984808 -0.173649
+vn 0.000001 -0.984808 -0.173649
+vn -0.000011 -0.984809 -0.173642
+vn -0.000004 -0.984808 -0.173646
+vn -0.000001 -0.984808 -0.173648
+vn -0.000002 -0.984808 -0.173649
+vn -0.000006 -0.984808 -0.173649
+vn 0.000004 -0.984808 -0.173648
+vn 0.000000 -0.984808 -0.173649
+vn -0.000004 -0.984807 -0.173650
+vn 0.000005 -0.984808 -0.173646
+vn 0.000003 -0.984808 -0.173647
+vn 0.000008 -0.984805 -0.173663
+s off
+f 1/1/1 2/2/1 4/3/1
+f 3/1/2 4/2/2 6/3/2
+f 5/1/3 6/2/3 8/3/3
+f 7/1/4 8/2/4 10/3/4
+f 9/1/5 10/2/5 12/3/5
+f 11/1/6 12/2/6 14/3/6
+f 13/1/7 14/2/7 16/3/7
+f 15/1/8 16/2/8 18/3/8
+f 17/1/9 18/2/9 19/4/9
+f 19/1/10 20/2/10 21/4/10
+f 21/1/11 22/2/11 23/4/11
+f 23/1/12 24/2/12 25/4/12
+f 25/1/13 26/2/13 27/4/13
+f 27/1/14 28/2/14 29/4/14
+f 29/1/15 30/2/15 31/4/15
+f 31/1/16 32/2/16 33/4/16
+f 33/1/17 34/2/17 35/4/17
+f 35/1/18 36/2/18 37/4/18
+f 37/1/19 38/2/19 39/4/19
+f 39/1/20 40/2/20 41/4/20
+f 41/1/21 42/2/21 43/4/21
+f 43/1/22 44/2/22 45/4/22
+f 45/1/23 46/2/23 47/4/23
+f 47/1/24 48/2/24 49/4/24
+f 49/1/25 50/2/25 52/3/25
+f 51/1/26 52/2/26 54/3/26
+f 53/1/27 54/2/27 56/3/27
+f 55/1/28 56/2/28 58/3/28
+f 57/1/29 58/2/29 60/3/29
+f 59/1/30 60/2/30 62/3/30
+f 48/5/31 52/6/31 50/7/31
+f 63/1/32 64/2/32 2/3/32
+f 61/1/33 62/2/33 64/3/33
+f 1/8/34 3/9/34 63/10/34
+f 3/4/35 1/1/35 4/3/35
+f 5/4/36 3/1/36 6/3/36
+f 7/4/37 5/1/37 8/3/37
+f 9/4/38 7/1/38 10/3/38
+f 11/4/39 9/1/39 12/3/39
+f 13/4/40 11/1/40 14/3/40
+f 15/4/41 13/1/41 16/3/41
+f 17/4/42 15/1/42 18/3/42
+f 18/2/43 20/3/43 19/4/43
+f 20/2/44 22/3/44 21/4/44
+f 22/2/45 24/3/45 23/4/45
+f 24/2/46 26/3/46 25/4/46
+f 26/2/47 28/3/47 27/4/47
+f 28/2/48 30/3/48 29/4/48
+f 30/2/49 32/3/49 31/4/49
+f 32/2/50 34/3/50 33/4/50
+f 34/2/17 36/3/17 35/4/17
+f 36/2/51 38/3/51 37/4/51
+f 38/2/52 40/3/52 39/4/52
+f 40/2/53 42/3/53 41/4/53
+f 42/2/54 44/3/54 43/4/54
+f 44/2/55 46/3/55 45/4/55
+f 46/2/56 48/3/56 47/4/56
+f 48/2/57 50/3/57 49/4/57
+f 51/4/58 49/1/58 52/3/58
+f 53/4/59 51/1/59 54/3/59
+f 55/4/60 53/1/60 56/3/60
+f 57/4/28 55/1/28 58/3/28
+f 59/4/61 57/1/61 60/3/61
+f 61/4/62 59/1/62 62/3/62
+f 48/5/63 54/11/63 52/6/63
+f 46/12/64 54/11/64 48/5/64
+f 46/12/65 56/13/65 54/11/65
+f 44/14/65 56/13/65 46/12/65
+f 44/14/66 58/15/66 56/13/66
+f 42/16/66 58/15/66 44/14/66
+f 42/16/67 60/17/67 58/15/67
+f 40/18/67 60/17/67 42/16/67
+f 40/18/68 62/19/68 60/17/68
+f 38/20/68 62/19/68 40/18/68
+f 38/20/69 64/21/69 62/19/69
+f 20/22/70 24/23/70 22/24/70
+f 16/25/71 20/22/71 18/26/71
+f 16/25/72 24/23/72 20/22/72
+f 36/27/69 64/21/69 38/20/69
+f 34/28/73 64/21/73 36/27/73
+f 2/9/74 64/21/74 34/28/74
+f 4/8/75 2/9/75 34/28/75
+f 4/8/75 34/28/75 32/29/75
+f 6/10/76 4/8/76 32/29/76
+f 6/10/76 32/29/76 30/30/76
+f 6/10/68 30/30/68 28/31/68
+f 8/32/68 6/10/68 28/31/68
+f 10/33/73 8/32/73 28/31/73
+f 10/33/67 28/31/67 26/34/67
+f 12/35/77 10/33/77 26/34/77
+f 12/35/78 26/34/78 24/23/78
+f 14/36/79 12/35/79 24/23/79
+f 16/25/80 14/36/80 24/23/80
+f 1/4/32 63/1/32 2/3/32
+f 63/4/81 61/1/81 64/3/81
+f 19/7/82 15/11/82 17/6/82
+f 41/31/83 37/29/83 39/30/83
+f 3/9/84 5/21/84 63/10/84
+f 45/23/85 41/31/85 43/34/85
+f 45/23/86 37/29/86 41/31/86
+f 49/22/87 45/23/87 47/24/87
+f 49/22/84 37/29/84 45/23/84
+f 49/22/84 35/28/84 37/29/84
+f 49/22/84 33/27/84 35/28/84
+f 49/22/84 31/20/84 33/27/84
+f 55/36/88 51/26/88 53/25/88
+f 59/33/89 55/36/89 57/35/89
+f 61/32/90 55/36/90 59/33/90
+f 63/10/91 55/36/91 61/32/91
+f 63/10/92 5/21/92 55/36/92
+f 5/21/93 7/19/93 55/36/93
+f 7/19/94 9/17/94 55/36/94
+f 29/18/95 25/14/95 27/16/95
+f 31/20/96 25/14/96 29/18/96
+f 49/22/97 25/14/97 31/20/97
+f 49/22/98 23/12/98 25/14/98
+f 9/17/93 11/15/93 55/36/93
+f 11/15/99 13/13/99 55/36/99
+f 13/13/100 15/11/100 55/36/100
+f 15/11/101 19/7/101 55/36/101
+f 19/7/102 21/5/102 55/36/102
+f 21/5/103 23/12/103 55/36/103
+f 23/12/104 49/22/104 55/36/104
+f 49/22/105 51/26/105 55/36/105
+v 0.053672 2.252534 1.125439
+v 0.053673 8.161380 0.083549
+v 0.051751 2.255921 1.144652
+v 0.051751 8.164768 0.102762
+v 0.046060 2.259179 1.163126
+v 0.046061 8.168025 0.121236
+v 0.036819 2.262181 1.180152
+v 0.036820 8.171027 0.138262
+v 0.024383 2.264812 1.195075
+v 0.024384 8.173658 0.153186
+v 0.009229 2.266972 1.207323
+v 0.009230 8.175818 0.165433
+v -0.008059 2.268577 1.216423
+v -0.008059 8.177423 0.174534
+v -0.026819 2.269565 1.222028
+v -0.026818 8.178411 0.180138
+v -0.046328 2.269898 1.223920
+v -0.046327 8.178745 0.182030
+v -0.065837 2.269565 1.222027
+v -0.065836 8.178411 0.180138
+v -0.084596 2.268577 1.216423
+v -0.084595 8.177423 0.174534
+v -0.101885 2.266972 1.207323
+v -0.101884 8.175818 0.165433
+v -0.117038 2.264812 1.195075
+v -0.117038 8.173658 0.153186
+v -0.129475 2.262181 1.180152
+v -0.129474 8.171027 0.138262
+v -0.138716 2.259179 1.163126
+v -0.138715 8.168025 0.121236
+v -0.144406 2.255921 1.144651
+v -0.144406 8.164768 0.102762
+v -0.146328 2.252534 1.125439
+v -0.146327 8.161380 0.083549
+v -0.144406 2.249146 1.106226
+v -0.144406 8.157992 0.064337
+v -0.138716 2.245888 1.087752
+v -0.138715 8.154735 0.045862
+v -0.129475 2.242886 1.070726
+v -0.129474 8.151732 0.028836
+v -0.117038 2.240255 1.055802
+v -0.117038 8.149101 0.013913
+v -0.101885 2.238095 1.043555
+v -0.101884 8.146942 0.001666
+v -0.084596 2.236491 1.034454
+v -0.084595 8.145337 -0.007435
+v -0.065837 2.235502 1.028850
+v -0.065836 8.144349 -0.013039
+v -0.046328 2.235169 1.026958
+v -0.046327 8.144015 -0.014931
+v -0.026819 2.235502 1.028850
+v -0.026818 8.144349 -0.013039
+v -0.008059 2.236491 1.034455
+v -0.008059 8.145337 -0.007435
+v 0.009229 2.238095 1.043555
+v 0.009230 8.146942 0.001666
+v 0.024383 2.240255 1.055803
+v 0.024384 8.149101 0.013913
+v 0.036819 2.242886 1.070726
+v 0.036820 8.151732 0.028837
+v 0.046060 2.245888 1.087752
+v 0.046061 8.154735 0.045863
+v 0.051751 2.249146 1.106226
+v 0.051752 8.157992 0.064337
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.308659 0.961940
+vt 0.222215 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 0.990393 0.402455
+vt 1.000000 0.500000
+vt 0.853553 0.146447
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.691342 0.038060
+vt 0.777785 0.084265
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.146447 0.853554
+vt 0.084266 0.777786
+vt 0.038060 0.691342
+vt 0.308658 0.038060
+vt 0.402455 0.009607
+vt 0.146446 0.146447
+vt 0.222215 0.084265
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.009607 0.597546
+vt 0.000000 0.500000
+vn 0.995185 0.017020 0.096528
+vn 0.956940 0.050408 0.285877
+vn 0.881921 0.081857 0.464236
+vn 0.773010 0.110161 0.624756
+vn 0.634396 0.134232 0.761265
+vn 0.471397 0.153144 0.868523
+vn 0.290283 0.166171 0.942403
+vn 0.098018 0.172812 0.980066
+vn -0.098018 0.172812 0.980066
+vn -0.290285 0.166171 0.942402
+vn -0.471398 0.153144 0.868522
+vn -0.634392 0.134232 0.761268
+vn -0.773007 0.110162 0.624759
+vn -0.881923 0.081857 0.464231
+vn -0.956941 0.050407 0.285874
+vn -0.995185 0.017021 0.096528
+vn -0.995185 -0.017021 -0.096529
+vn -0.956940 -0.050408 -0.285877
+vn -0.881921 -0.081857 -0.464236
+vn -0.773008 -0.110162 -0.624758
+vn -0.634391 -0.134232 -0.761269
+vn -0.471388 -0.153145 -0.868528
+vn -0.290288 -0.166171 -0.942401
+vn -0.098006 -0.172812 -0.980067
+vn 0.098021 -0.172812 -0.980065
+vn 0.290285 -0.166171 -0.942402
+vn 0.471402 -0.153144 -0.868520
+vn 0.634392 -0.134232 -0.761267
+vn 0.773010 -0.110161 -0.624755
+vn 0.881922 -0.081857 -0.464233
+vn -0.000356 0.984796 -0.173717
+vn 0.995185 -0.017020 -0.096527
+vn 0.956941 -0.050407 -0.285872
+vn -0.000005 -0.984808 0.173646
+vn 0.995185 0.017020 0.096529
+vn 0.956940 0.050407 0.285875
+vn 0.881920 0.081858 0.464237
+vn 0.773011 0.110161 0.624755
+vn 0.634396 0.134231 0.761264
+vn 0.471389 0.153145 0.868527
+vn 0.290292 0.166171 0.942400
+vn 0.098013 0.172812 0.980066
+vn -0.098019 0.172812 0.980065
+vn -0.290283 0.166171 0.942403
+vn -0.471400 0.153144 0.868521
+vn -0.634396 0.134232 0.761264
+vn -0.773010 0.110161 0.624756
+vn -0.881922 0.081857 0.464234
+vn -0.956940 0.050408 0.285876
+vn -0.995185 0.017020 0.096526
+vn -0.995185 -0.017021 -0.096530
+vn -0.956940 -0.050407 -0.285875
+vn -0.773009 -0.110161 -0.624757
+vn -0.634390 -0.134232 -0.761269
+vn -0.471399 -0.153144 -0.868522
+vn -0.290282 -0.166171 -0.942403
+vn -0.098018 -0.172812 -0.980066
+vn 0.098018 -0.172812 -0.980065
+vn 0.290287 -0.166171 -0.942402
+vn 0.471399 -0.153144 -0.868522
+vn 0.634393 -0.134232 -0.761267
+vn 0.773014 -0.110161 -0.624751
+vn 0.881921 -0.081857 -0.464236
+vn -0.000114 0.984812 -0.173626
+vn -0.000002 0.984808 -0.173648
+vn -0.000054 0.984802 -0.173678
+vn -0.000008 0.984808 -0.173648
+vn -0.000004 0.984808 -0.173647
+vn -0.000107 0.984836 -0.173487
+vn -0.000015 0.984812 -0.173622
+vn -0.000013 0.984820 -0.173580
+vn -0.000001 0.984809 -0.173639
+vn -0.000044 0.984787 -0.173766
+vn -0.000047 0.984804 -0.173672
+vn -0.000051 0.984803 -0.173676
+vn -0.000050 0.984803 -0.173675
+vn -0.000006 0.984799 -0.173697
+vn -0.000037 0.984791 -0.173743
+vn -0.000244 0.984806 -0.173659
+vn -0.000025 0.984806 -0.173659
+vn -0.000168 0.984823 -0.173560
+vn -0.000013 0.984812 -0.173624
+vn -0.000088 0.984819 -0.173584
+vn -0.000036 0.984813 -0.173618
+vn 0.000016 0.984808 -0.173645
+vn 0.000005 0.984808 -0.173650
+vn 0.000006 0.984807 -0.173650
+vn 0.000005 0.984808 -0.173649
+vn 0.000002 0.984808 -0.173648
+vn 0.000003 0.984807 -0.173650
+vn 0.000005 0.984804 -0.173667
+vn 0.956941 -0.050407 -0.285873
+vn -0.000005 -0.984808 0.173649
+vn -0.000001 -0.984818 0.173592
+vn -0.000000 -0.984808 0.173648
+vn -0.000006 -0.984808 0.173646
+vn -0.000001 -0.984808 0.173648
+vn -0.000002 -0.984808 0.173648
+vn -0.000001 -0.984806 0.173661
+vn -0.000000 -0.984805 0.173663
+vn -0.000000 -0.984810 0.173635
+vn -0.000000 -0.984810 0.173634
+vn -0.000000 -0.984807 0.173653
+vn -0.000000 -0.984807 0.173650
+vn -0.000000 -0.984808 0.173647
+vn 0.000000 -0.984807 0.173651
+vn -0.000000 -0.984807 0.173649
+vn -0.000000 -0.984810 0.173637
+vn 0.000000 -0.984806 0.173659
+vn -0.000001 -0.984805 0.173664
+s off
+f 65/37/106 66/38/106 68/39/106
+f 67/37/107 68/38/107 70/39/107
+f 69/37/108 70/38/108 72/39/108
+f 71/37/109 72/38/109 74/39/109
+f 73/37/110 74/38/110 76/39/110
+f 75/37/111 76/38/111 78/39/111
+f 77/37/112 78/38/112 80/39/112
+f 79/37/113 80/38/113 82/39/113
+f 81/37/114 82/38/114 83/40/114
+f 83/37/115 84/38/115 85/40/115
+f 85/37/116 86/38/116 87/40/116
+f 87/37/117 88/38/117 89/40/117
+f 89/37/118 90/38/118 91/40/118
+f 91/37/119 92/38/119 93/40/119
+f 93/37/120 94/38/120 95/40/120
+f 95/37/121 96/38/121 97/40/121
+f 97/37/122 98/38/122 99/40/122
+f 99/37/123 100/38/123 101/40/123
+f 101/37/124 102/38/124 103/40/124
+f 103/37/125 104/38/125 105/40/125
+f 105/37/126 106/38/126 107/40/126
+f 107/37/127 108/38/127 109/40/127
+f 109/37/128 110/38/128 111/40/128
+f 111/37/129 112/38/129 113/40/129
+f 113/37/130 114/38/130 116/39/130
+f 115/37/131 116/38/131 118/39/131
+f 117/37/132 118/38/132 120/39/132
+f 119/37/133 120/38/133 122/39/133
+f 121/37/134 122/38/134 124/39/134
+f 123/37/135 124/38/135 126/39/135
+f 68/41/136 66/42/136 70/43/136
+f 127/37/137 128/38/137 66/39/137
+f 125/37/138 126/38/138 128/39/138
+f 65/41/139 67/42/139 69/44/139
+f 67/40/140 65/37/140 68/39/140
+f 69/40/141 67/37/141 70/39/141
+f 71/40/142 69/37/142 72/39/142
+f 73/40/143 71/37/143 74/39/143
+f 75/40/144 73/37/144 76/39/144
+f 77/40/145 75/37/145 78/39/145
+f 79/40/146 77/37/146 80/39/146
+f 81/40/147 79/37/147 82/39/147
+f 82/38/148 84/39/148 83/40/148
+f 84/38/149 86/39/149 85/40/149
+f 86/38/150 88/39/150 87/40/150
+f 88/38/151 90/39/151 89/40/151
+f 90/38/152 92/39/152 91/40/152
+f 92/38/153 94/39/153 93/40/153
+f 94/38/154 96/39/154 95/40/154
+f 96/38/155 98/39/155 97/40/155
+f 98/38/156 100/39/156 99/40/156
+f 100/38/157 102/39/157 101/40/157
+f 102/38/124 104/39/124 103/40/124
+f 104/38/158 106/39/158 105/40/158
+f 106/38/159 108/39/159 107/40/159
+f 108/38/160 110/39/160 109/40/160
+f 110/38/161 112/39/161 111/40/161
+f 112/38/162 114/39/162 113/40/162
+f 115/40/163 113/37/163 116/39/163
+f 117/40/164 115/37/164 118/39/164
+f 119/40/165 117/37/165 120/39/165
+f 121/40/166 119/37/166 122/39/166
+f 123/40/167 121/37/167 124/39/167
+f 125/40/168 123/37/168 126/39/168
+f 66/42/169 128/44/169 126/45/169
+f 70/43/170 66/42/170 126/45/170
+f 72/46/171 70/43/171 74/47/171
+f 70/43/172 126/45/172 74/47/172
+f 126/45/173 124/48/173 74/47/173
+f 122/49/174 120/50/174 118/51/174
+f 124/48/175 122/49/175 118/51/175
+f 114/52/176 118/51/176 116/53/176
+f 124/48/177 118/51/177 114/52/177
+f 108/54/178 112/55/178 110/56/178
+f 104/57/179 108/54/179 106/58/179
+f 102/59/180 108/54/180 104/57/180
+f 100/60/181 108/54/181 102/59/181
+f 76/61/182 74/47/182 78/62/182
+f 78/62/183 74/47/183 80/63/183
+f 96/64/184 100/60/184 98/65/184
+f 96/64/185 108/54/185 100/60/185
+f 92/66/186 96/64/186 94/67/186
+f 90/68/187 96/64/187 92/66/187
+f 88/69/188 96/64/188 90/68/188
+f 86/70/189 96/64/189 88/69/189
+f 82/71/176 86/70/176 84/72/176
+f 74/47/190 124/48/190 80/63/190
+f 124/48/191 114/52/191 80/63/191
+f 114/52/192 112/55/192 80/63/192
+f 112/55/193 108/54/193 80/63/193
+f 108/54/194 96/64/194 80/63/194
+f 96/64/195 86/70/195 80/63/195
+f 86/70/196 82/71/196 80/63/196
+f 65/40/137 127/37/137 66/39/137
+f 127/40/197 125/37/197 128/39/197
+f 127/43/198 65/41/198 125/46/198
+f 83/52/199 79/51/199 81/53/199
+f 97/60/200 93/57/200 95/59/200
+f 99/65/200 93/57/200 97/60/200
+f 103/67/201 99/65/201 101/64/201
+f 103/67/202 93/57/202 99/65/202
+f 105/66/203 93/57/203 103/67/203
+f 115/71/199 111/70/199 113/72/199
+f 115/71/204 109/69/204 111/70/204
+f 117/63/205 109/69/205 115/71/205
+f 117/63/206 107/68/206 109/69/206
+f 119/62/207 107/68/207 117/63/207
+f 119/62/208 105/66/208 107/68/208
+f 121/61/208 105/66/208 119/62/208
+f 123/47/200 105/66/200 121/61/200
+f 125/46/209 105/66/209 123/47/209
+f 125/46/200 65/41/200 105/66/200
+f 105/66/200 65/41/200 93/57/200
+f 65/41/210 69/44/210 93/57/210
+f 69/44/209 71/45/209 93/57/209
+f 93/57/200 71/45/200 91/58/200
+f 91/58/211 71/45/211 89/54/211
+f 71/45/212 73/48/212 89/54/212
+f 73/48/211 75/49/211 89/54/211
+f 89/54/208 75/49/208 87/56/208
+f 75/49/213 77/50/213 87/56/213
+f 87/56/207 77/50/207 85/55/207
+f 77/50/214 79/51/214 85/55/214
+f 79/51/215 83/52/215 85/55/215
+v 1.116865 2.257815 -0.125221
+v 0.074976 8.166661 -0.125221
+v 1.136078 2.261203 -0.123300
+v 0.094188 8.170050 -0.123300
+v 1.154552 2.264460 -0.117609
+v 0.112663 8.173306 -0.117609
+v 1.171578 2.267462 -0.108368
+v 0.129689 8.176309 -0.108368
+v 1.186502 2.270094 -0.095932
+v 0.144612 8.178940 -0.095932
+v 1.198749 2.272254 -0.080778
+v 0.156859 8.181100 -0.080778
+v 1.207850 2.273858 -0.063490
+v 0.165960 8.182705 -0.063490
+v 1.213454 2.274846 -0.044730
+v 0.171564 8.183693 -0.044730
+v 1.215346 2.275180 -0.025221
+v 0.173456 8.184027 -0.025221
+v 1.213454 2.274846 -0.005712
+v 0.171564 8.183693 -0.005712
+v 1.207850 2.273858 0.013047
+v 0.165960 8.182705 0.013047
+v 1.198749 2.272254 0.030336
+v 0.156859 8.181100 0.030336
+v 1.186502 2.270094 0.045489
+v 0.144612 8.178940 0.045489
+v 1.171578 2.267462 0.057926
+v 0.129689 8.176309 0.057926
+v 1.154552 2.264460 0.067167
+v 0.112663 8.173306 0.067167
+v 1.136078 2.261203 0.072857
+v 0.094188 8.170050 0.072857
+v 1.116865 2.257815 0.074779
+v 0.074976 8.166661 0.074779
+v 1.097653 2.254427 0.072857
+v 0.055763 8.163274 0.072857
+v 1.079178 2.251170 0.067167
+v 0.037289 8.160016 0.067167
+v 1.062152 2.248168 0.057926
+v 0.020263 8.157014 0.057926
+v 1.047229 2.245536 0.045489
+v 0.005339 8.154383 0.045489
+v 1.034981 2.243377 0.030336
+v -0.006908 8.152224 0.030336
+v 1.025881 2.241772 0.013047
+v -0.016009 8.150619 0.013047
+v 1.020277 2.240784 -0.005712
+v -0.021613 8.149631 -0.005712
+v 1.018384 2.240450 -0.025221
+v -0.023505 8.149297 -0.025221
+v 1.020277 2.240784 -0.044730
+v -0.021613 8.149631 -0.044730
+v 1.025881 2.241772 -0.063490
+v -0.016009 8.150619 -0.063490
+v 1.034981 2.243377 -0.080778
+v -0.006908 8.152224 -0.080778
+v 1.047229 2.245536 -0.095932
+v 0.005339 8.154383 -0.095932
+v 1.062152 2.248168 -0.108368
+v 0.020263 8.157014 -0.108368
+v 1.079178 2.251170 -0.117609
+v 0.037289 8.160016 -0.117609
+v 1.097653 2.254427 -0.123300
+v 0.055763 8.163274 -0.123300
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.000000 0.500000
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.146447 0.853554
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.308659 0.961940
+vt 0.222215 0.915735
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.009607 0.597546
+vt 0.084265 0.222215
+vn 0.096528 0.017020 -0.995185
+vn 0.285876 0.050408 -0.956940
+vn 0.464235 0.081857 -0.881921
+vn 0.624757 0.110162 -0.773009
+vn 0.761264 0.134232 -0.634396
+vn 0.868521 0.153144 -0.471400
+vn 0.942403 0.166171 -0.290283
+vn 0.980066 0.172812 -0.098018
+vn 0.980066 0.172812 0.098018
+vn 0.942403 0.166171 0.290283
+vn 0.868521 0.153144 0.471399
+vn 0.761264 0.134232 0.634396
+vn 0.624757 0.110162 0.773009
+vn 0.464235 0.081857 0.881921
+vn 0.285876 0.050408 0.956940
+vn 0.096527 0.017020 0.995185
+vn -0.096528 -0.017021 0.995185
+vn -0.285875 -0.050407 0.956940
+vn -0.464235 -0.081857 0.881921
+vn -0.624754 -0.110161 0.773012
+vn -0.761268 -0.134232 0.634391
+vn -0.868524 -0.153144 0.471394
+vn -0.942401 -0.166171 0.290288
+vn -0.980066 -0.172812 0.098010
+vn -0.980065 -0.172812 -0.098018
+vn -0.942402 -0.166171 -0.290285
+vn -0.868521 -0.153144 -0.471401
+vn -0.761266 -0.134232 -0.634394
+vn -0.624751 -0.110161 -0.773014
+vn -0.464236 -0.081857 -0.881921
+vn -0.173717 0.984796 0.000356
+vn -0.096527 -0.017020 -0.995185
+vn -0.285873 -0.050407 -0.956941
+vn 0.173648 -0.984808 -0.000011
+vn 0.285874 0.050407 -0.956940
+vn 0.464237 0.081858 -0.881920
+vn 0.624752 0.110161 -0.773013
+vn 0.761267 0.134232 -0.634393
+vn 0.868524 0.153144 -0.471394
+vn 0.942402 0.166171 -0.290287
+vn 0.980065 0.172812 -0.098019
+vn 0.980065 0.172812 0.098019
+vn 0.942402 0.166171 0.290287
+vn 0.868524 0.153144 0.471394
+vn 0.761267 0.134232 0.634393
+vn 0.624752 0.110161 0.773013
+vn 0.464237 0.081858 0.881920
+vn 0.285874 0.050407 0.956940
+vn -0.096529 -0.017021 0.995185
+vn -0.285874 -0.050407 0.956940
+vn -0.624758 -0.110162 0.773008
+vn -0.761268 -0.134232 0.634392
+vn -0.868523 -0.153144 0.471397
+vn -0.942402 -0.166171 0.290284
+vn -0.980066 -0.172812 0.098018
+vn -0.980065 -0.172812 -0.098021
+vn -0.868521 -0.153144 -0.471400
+vn -0.761267 -0.134232 -0.634392
+vn -0.624756 -0.110161 -0.773010
+vn -0.464234 -0.081857 -0.881922
+vn -0.173640 0.984809 -0.000036
+vn -0.173648 0.984808 0.000040
+vn -0.173648 0.984808 0.000002
+vn -0.173650 0.984807 -0.000020
+vn -0.173652 0.984807 -0.000031
+vn -0.173635 0.984810 0.000027
+vn -0.173649 0.984808 -0.000009
+vn -0.173641 0.984809 0.000007
+vn -0.173650 0.984807 -0.000006
+vn -0.173640 0.984809 0.000006
+vn -0.173660 0.984806 -0.000014
+vn -0.173675 0.984803 0.000050
+vn -0.173675 0.984803 0.000049
+vn -0.173767 0.984787 -0.000044
+vn -0.173767 0.984787 0.000044
+vn -0.173642 0.984809 0.000000
+vn -0.173677 0.984803 0.000052
+vn -0.173717 0.984796 -0.000357
+vn -0.173646 0.984808 0.000005
+vn -0.173645 0.984808 0.000007
+vn -0.173703 0.984798 -0.000011
+vn -0.173684 0.984802 -0.000003
+vn -0.173667 0.984805 0.000002
+vn -0.173671 0.984804 -0.000015
+vn -0.173656 0.984806 -0.000026
+vn -0.173637 0.984810 0.000008
+vn -0.173643 0.984809 0.000005
+vn -0.096528 -0.017020 -0.995185
+vn -0.285872 -0.050407 -0.956941
+vn 0.173648 -0.984808 -0.000000
+vn 0.173647 -0.984808 0.000006
+vn 0.173647 -0.984808 0.000005
+vn 0.173652 -0.984807 -0.000009
+vn 0.173645 -0.984808 0.000005
+vn 0.173653 -0.984807 -0.000007
+vn 0.173643 -0.984809 0.000006
+vn 0.173652 -0.984807 -0.000003
+vn 0.173643 -0.984809 0.000004
+vn 0.173651 -0.984807 -0.000002
+vn 0.173650 -0.984807 -0.000001
+vn 0.173647 -0.984808 0.000000
+vn 0.173649 -0.984808 0.000000
+vn 0.173652 -0.984807 0.000001
+vn 0.173642 -0.984809 -0.000003
+vn 0.173653 -0.984807 0.000003
+vn 0.173642 -0.984809 -0.000004
+vn 0.173655 -0.984806 0.000007
+vn 0.173641 -0.984809 -0.000008
+vn 0.173658 -0.984806 0.000013
+vn 0.173645 -0.984808 -0.000007
+vn 0.173654 -0.984807 0.000007
+vn 0.173646 -0.984808 -0.000004
+s off
+f 129/73/216 130/74/216 132/75/216
+f 131/73/217 132/74/217 134/75/217
+f 133/73/218 134/74/218 136/75/218
+f 135/73/219 136/74/219 138/75/219
+f 137/73/220 138/74/220 140/75/220
+f 139/73/221 140/74/221 142/75/221
+f 141/73/222 142/74/222 144/75/222
+f 143/73/223 144/74/223 146/75/223
+f 145/73/224 146/74/224 148/75/224
+f 147/73/225 148/74/225 150/75/225
+f 149/73/226 150/74/226 152/75/226
+f 151/73/227 152/74/227 154/75/227
+f 153/73/228 154/74/228 156/75/228
+f 155/73/229 156/74/229 158/75/229
+f 157/73/230 158/74/230 160/75/230
+f 159/73/231 160/74/231 162/75/231
+f 161/73/232 162/74/232 163/76/232
+f 163/73/233 164/74/233 165/76/233
+f 165/73/234 166/74/234 167/76/234
+f 167/73/235 168/74/235 169/76/235
+f 169/73/236 170/74/236 171/76/236
+f 171/73/237 172/74/237 173/76/237
+f 173/73/238 174/74/238 175/76/238
+f 175/73/239 176/74/239 177/76/239
+f 177/73/240 178/74/240 179/76/240
+f 179/73/241 180/74/241 181/76/241
+f 181/73/242 182/74/242 183/76/242
+f 183/73/243 184/74/243 185/76/243
+f 185/73/244 186/74/244 187/76/244
+f 187/73/245 188/74/245 189/76/245
+f 132/77/246 130/78/246 134/79/246
+f 191/73/247 192/74/247 129/76/247
+f 189/73/248 190/74/248 191/76/248
+f 129/77/249 131/78/249 191/79/249
+f 131/76/216 129/73/216 132/75/216
+f 133/76/250 131/73/250 134/75/250
+f 135/76/251 133/73/251 136/75/251
+f 137/76/252 135/73/252 138/75/252
+f 139/76/253 137/73/253 140/75/253
+f 141/76/254 139/73/254 142/75/254
+f 143/76/255 141/73/255 144/75/255
+f 145/76/256 143/73/256 146/75/256
+f 147/76/257 145/73/257 148/75/257
+f 149/76/258 147/73/258 150/75/258
+f 151/76/259 149/73/259 152/75/259
+f 153/76/260 151/73/260 154/75/260
+f 155/76/261 153/73/261 156/75/261
+f 157/76/262 155/73/262 158/75/262
+f 159/76/263 157/73/263 160/75/263
+f 161/76/231 159/73/231 162/75/231
+f 162/74/264 164/75/264 163/76/264
+f 164/74/265 166/75/265 165/76/265
+f 166/74/234 168/75/234 167/76/234
+f 168/74/266 170/75/266 169/76/266
+f 170/74/267 172/75/267 171/76/267
+f 172/74/268 174/75/268 173/76/268
+f 174/74/269 176/75/269 175/76/269
+f 176/74/270 178/75/270 177/76/270
+f 178/74/271 180/75/271 179/76/271
+f 180/74/241 182/75/241 181/76/241
+f 182/74/272 184/75/272 183/76/272
+f 184/74/273 186/75/273 185/76/273
+f 186/74/274 188/75/274 187/76/274
+f 188/74/275 190/75/275 189/76/275
+f 130/78/276 192/80/276 134/79/276
+f 192/80/277 190/81/277 134/79/277
+f 190/81/278 188/82/278 134/79/278
+f 188/82/279 186/83/279 134/79/279
+f 186/83/280 184/84/280 134/79/280
+f 184/84/281 182/85/281 134/79/281
+f 182/85/282 180/86/282 134/79/282
+f 180/86/283 178/87/283 134/79/283
+f 178/87/284 176/88/284 134/79/284
+f 176/88/285 174/89/285 134/79/285
+f 174/89/286 172/90/286 134/79/286
+f 170/91/287 168/92/287 166/93/287
+f 170/91/288 166/93/288 164/94/288
+f 148/95/289 152/96/289 150/97/289
+f 140/98/290 144/99/290 142/100/290
+f 172/90/287 170/91/287 164/94/287
+f 134/79/291 172/90/291 164/94/291
+f 136/101/292 134/79/292 138/102/292
+f 134/79/291 164/94/291 138/102/291
+f 162/103/293 160/104/293 158/105/293
+f 162/103/294 158/105/294 156/106/294
+f 146/107/295 152/96/295 148/95/295
+f 146/107/296 154/108/296 152/96/296
+f 144/99/297 154/108/297 146/107/297
+f 140/98/298 154/108/298 144/99/298
+f 138/102/299 164/94/299 140/98/299
+f 162/103/300 156/106/300 154/108/300
+f 164/94/301 162/103/301 140/98/301
+f 162/103/302 154/108/302 140/98/302
+f 192/74/303 130/75/303 129/76/303
+f 190/74/304 192/75/304 191/76/304
+f 131/78/305 133/80/305 191/79/305
+f 133/80/306 135/81/306 191/79/306
+f 135/81/305 137/82/305 191/79/305
+f 137/82/307 139/83/307 191/79/307
+f 139/83/308 141/84/308 191/79/308
+f 141/84/309 143/85/309 191/79/309
+f 143/85/310 145/86/310 191/79/310
+f 145/86/311 147/87/311 191/79/311
+f 147/87/312 149/88/312 191/79/312
+f 149/88/313 151/89/313 191/79/313
+f 151/89/314 153/90/314 191/79/314
+f 153/90/305 155/91/305 191/79/305
+f 155/91/315 157/92/315 191/79/315
+f 157/92/305 159/93/305 191/79/305
+f 159/93/316 161/94/316 191/79/316
+f 161/94/305 163/103/305 191/79/305
+f 163/103/305 165/104/305 191/79/305
+f 165/104/317 167/105/317 191/79/317
+f 167/105/317 169/106/317 191/79/317
+f 169/106/318 171/108/318 191/79/318
+f 171/108/319 173/96/319 191/79/319
+f 173/96/320 175/97/320 191/79/320
+f 175/97/321 177/95/321 191/79/321
+f 177/95/322 179/107/322 191/79/322
+f 179/107/323 181/99/323 191/79/323
+f 181/99/324 183/100/324 191/79/324
+f 183/100/325 185/98/325 191/79/325
+f 185/98/326 187/102/326 189/101/326
+f 191/79/327 185/98/327 189/101/327
+v -1.178897 2.277600 -0.129009
+v -0.137008 8.186446 -0.129009
+v -1.159685 2.274212 -0.127088
+v -0.117795 8.183058 -0.127088
+v -1.141210 2.270954 -0.121397
+v -0.099321 8.179801 -0.121397
+v -1.124184 2.267952 -0.112156
+v -0.082295 8.176799 -0.112156
+v -1.109261 2.265321 -0.099720
+v -0.067371 8.174168 -0.099720
+v -1.097013 2.263161 -0.084566
+v -0.055124 8.172008 -0.084566
+v -1.087913 2.261557 -0.067277
+v -0.046023 8.170403 -0.067277
+v -1.082309 2.260568 -0.048518
+v -0.040419 8.169415 -0.048518
+v -1.080417 2.260235 -0.029009
+v -0.038527 8.169081 -0.029009
+v -1.082309 2.260568 -0.009500
+v -0.040419 8.169415 -0.009500
+v -1.087913 2.261557 0.009259
+v -0.046023 8.170403 0.009259
+v -1.097013 2.263161 0.026548
+v -0.055124 8.172008 0.026548
+v -1.109261 2.265321 0.041702
+v -0.067371 8.174168 0.041702
+v -1.124184 2.267952 0.054138
+v -0.082295 8.176799 0.054138
+v -1.141210 2.270954 0.063379
+v -0.099321 8.179801 0.063379
+v -1.159685 2.274212 0.069069
+v -0.117795 8.183058 0.069069
+v -1.178897 2.277600 0.070991
+v -0.137008 8.186446 0.070991
+v -1.198110 2.280987 0.069069
+v -0.156220 8.189834 0.069069
+v -1.216584 2.284245 0.063379
+v -0.174695 8.193091 0.063379
+v -1.233610 2.287247 0.054138
+v -0.191721 8.196094 0.054138
+v -1.248534 2.289878 0.041702
+v -0.206644 8.198725 0.041702
+v -1.260781 2.292038 0.026548
+v -0.218892 8.200884 0.026548
+v -1.269882 2.293643 0.009259
+v -0.227992 8.202489 0.009259
+v -1.275486 2.294631 -0.009500
+v -0.233596 8.203477 -0.009500
+v -1.277378 2.294964 -0.029009
+v -0.235489 8.203811 -0.029009
+v -1.275486 2.294631 -0.048518
+v -0.233596 8.203477 -0.048518
+v -1.269882 2.293643 -0.067278
+v -0.227992 8.202489 -0.067278
+v -1.260781 2.292038 -0.084566
+v -0.218892 8.200884 -0.084566
+v -1.248534 2.289878 -0.099720
+v -0.206644 8.198725 -0.099720
+v -1.233610 2.287247 -0.112156
+v -0.191721 8.196094 -0.112156
+v -1.216584 2.284245 -0.121397
+v -0.174695 8.193091 -0.121397
+v -1.198110 2.280987 -0.127088
+v -0.156220 8.189834 -0.127088
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn 0.096528 -0.017020 -0.995185
+vn 0.285876 -0.050408 -0.956940
+vn 0.464236 -0.081857 -0.881921
+vn 0.624756 -0.110161 -0.773010
+vn 0.761265 -0.134232 -0.634395
+vn 0.868521 -0.153144 -0.471400
+vn 0.942403 -0.166171 -0.290282
+vn 0.980065 -0.172812 -0.098021
+vn 0.980066 -0.172812 0.098018
+vn 0.942402 -0.166171 0.290285
+vn 0.868522 -0.153144 0.471399
+vn 0.761265 -0.134232 0.634395
+vn 0.624756 -0.110161 0.773010
+vn 0.464235 -0.081857 0.881922
+vn 0.285876 -0.050408 0.956940
+vn 0.096527 -0.017020 0.995185
+vn -0.096528 0.017020 0.995185
+vn -0.285876 0.050408 0.956940
+vn -0.464234 0.081857 0.881922
+vn -0.624758 0.110162 0.773008
+vn -0.761264 0.134231 0.634396
+vn -0.868524 0.153144 0.471394
+vn -0.942401 0.166171 0.290288
+vn -0.980066 0.172812 0.098014
+vn -0.980066 0.172812 -0.098014
+vn -0.942403 0.166171 -0.290281
+vn -0.868522 0.153144 -0.471398
+vn -0.761268 0.134232 -0.634392
+vn -0.624751 0.110161 -0.773014
+vn -0.464236 0.081857 -0.881921
+vn 0.173717 0.984795 -0.000357
+vn -0.096527 0.017020 -0.995185
+vn -0.285874 0.050407 -0.956940
+vn -0.173648 -0.984808 0.000011
+vn 0.285874 -0.050407 -0.956940
+vn 0.464237 -0.081858 -0.881920
+vn 0.624755 -0.110161 -0.773011
+vn 0.761264 -0.134231 -0.634396
+vn 0.868524 -0.153144 -0.471394
+vn 0.942402 -0.166171 -0.290287
+vn 0.980066 -0.172812 -0.098013
+vn 0.980066 -0.172812 0.098013
+vn 0.942402 -0.166171 0.290287
+vn 0.868524 -0.153144 0.471394
+vn 0.761264 -0.134231 0.634396
+vn 0.624755 -0.110161 0.773011
+vn 0.464237 -0.081858 0.881920
+vn 0.285874 -0.050407 0.956940
+vn -0.096529 0.017021 0.995185
+vn -0.285874 0.050407 0.956940
+vn -0.464235 0.081857 0.881921
+vn -0.624756 0.110161 0.773010
+vn -0.761269 0.134232 0.634391
+vn -0.868522 0.153144 0.471398
+vn -0.942403 0.166171 0.290282
+vn -0.980066 0.172812 0.098018
+vn -0.980065 0.172812 -0.098019
+vn -0.942402 0.166171 -0.290285
+vn -0.868521 0.153144 -0.471400
+vn -0.761267 0.134232 -0.634392
+vn -0.624756 0.110161 -0.773010
+vn -0.464234 0.081857 -0.881922
+vn 0.173640 0.984809 0.000036
+vn 0.173648 0.984808 -0.000041
+vn 0.173648 0.984808 -0.000002
+vn 0.173650 0.984807 0.000019
+vn 0.173652 0.984807 0.000031
+vn 0.173635 0.984810 -0.000027
+vn 0.173649 0.984808 0.000009
+vn 0.173641 0.984809 -0.000007
+vn 0.173650 0.984807 0.000006
+vn 0.173641 0.984809 -0.000005
+vn 0.173660 0.984806 0.000014
+vn 0.173629 0.984811 -0.000011
+vn 0.173638 0.984810 -0.000005
+vn 0.173649 0.984808 0.000001
+vn 0.173659 0.984806 0.000005
+vn 0.173636 0.984810 -0.000002
+vn 0.173683 0.984802 0.000007
+vn 0.173611 0.984814 0.000000
+vn 0.173649 0.984808 0.000000
+vn 0.173635 0.984810 0.000001
+vn 0.173681 0.984802 -0.000008
+vn 0.173674 0.984803 -0.000006
+vn 0.173644 0.984808 0.000007
+vn 0.173666 0.984805 -0.000005
+vn 0.173677 0.984803 -0.000016
+vn 0.173633 0.984810 0.000028
+vn 0.173518 0.984831 0.000143
+vn 0.173638 0.984810 0.000022
+vn -0.096528 0.017020 -0.995185
+vn -0.285872 0.050407 -0.956941
+vn -0.173648 -0.984808 0.000000
+vn -0.173647 -0.984808 -0.000006
+vn -0.173648 -0.984808 -0.000002
+vn -0.173647 -0.984808 -0.000003
+vn -0.173652 -0.984807 0.000009
+vn -0.173645 -0.984808 -0.000005
+vn -0.173652 -0.984807 0.000005
+vn -0.173644 -0.984809 -0.000005
+vn -0.173652 -0.984807 0.000003
+vn -0.173643 -0.984809 -0.000004
+vn -0.173650 -0.984807 0.000001
+vn -0.173680 -0.984802 0.000024
+vn -0.173592 -0.984818 0.000023
+vn -0.173693 -0.984800 0.000010
+vn -0.173644 -0.984808 -0.000000
+vn -0.173638 -0.984810 0.000013
+vn -0.173653 -0.984807 -0.000003
+vn -0.173644 -0.984808 0.000011
+vn -0.173646 -0.984808 0.000007
+vn -0.173645 -0.984808 -0.000007
+vn -0.173651 -0.984807 0.000003
+vn -0.173649 -0.984808 0.000000
+vn -0.173648 -0.984808 0.000001
+vn -0.173647 -0.984808 0.000002
+vn -0.173640 -0.984809 -0.000005
+vn -0.173647 -0.984808 -0.000001
+s off
+f 193/109/328 194/110/328 196/111/328
+f 195/109/329 196/110/329 198/111/329
+f 197/109/330 198/110/330 200/111/330
+f 199/109/331 200/110/331 202/111/331
+f 201/109/332 202/110/332 204/111/332
+f 203/109/333 204/110/333 206/111/333
+f 205/109/334 206/110/334 208/111/334
+f 207/109/335 208/110/335 210/111/335
+f 209/109/336 210/110/336 212/111/336
+f 211/109/337 212/110/337 214/111/337
+f 213/109/338 214/110/338 216/111/338
+f 215/109/339 216/110/339 218/111/339
+f 217/109/340 218/110/340 220/111/340
+f 219/109/341 220/110/341 222/111/341
+f 221/109/342 222/110/342 224/111/342
+f 223/109/343 224/110/343 226/111/343
+f 225/109/344 226/110/344 227/112/344
+f 227/109/345 228/110/345 229/112/345
+f 229/109/346 230/110/346 231/112/346
+f 231/109/347 232/110/347 233/112/347
+f 233/109/348 234/110/348 235/112/348
+f 235/109/349 236/110/349 237/112/349
+f 237/109/350 238/110/350 239/112/350
+f 239/109/351 240/110/351 241/112/351
+f 241/109/352 242/110/352 243/112/352
+f 243/109/353 244/110/353 245/112/353
+f 245/109/354 246/110/354 247/112/354
+f 247/109/355 248/110/355 249/112/355
+f 249/109/356 250/110/356 251/112/356
+f 251/109/357 252/110/357 253/112/357
+f 196/113/358 194/114/358 198/115/358
+f 255/109/359 256/110/359 193/112/359
+f 253/109/360 254/110/360 255/112/360
+f 193/113/361 195/114/361 255/115/361
+f 195/112/328 193/109/328 196/111/328
+f 197/112/362 195/109/362 198/111/362
+f 199/112/363 197/109/363 200/111/363
+f 201/112/364 199/109/364 202/111/364
+f 203/112/365 201/109/365 204/111/365
+f 205/112/366 203/109/366 206/111/366
+f 207/112/367 205/109/367 208/111/367
+f 209/112/368 207/109/368 210/111/368
+f 211/112/369 209/109/369 212/111/369
+f 213/112/370 211/109/370 214/111/370
+f 215/112/371 213/109/371 216/111/371
+f 217/112/372 215/109/372 218/111/372
+f 219/112/373 217/109/373 220/111/373
+f 221/112/374 219/109/374 222/111/374
+f 223/112/375 221/109/375 224/111/375
+f 225/112/343 223/109/343 226/111/343
+f 226/110/376 228/111/376 227/112/376
+f 228/110/377 230/111/377 229/112/377
+f 230/110/378 232/111/378 231/112/378
+f 232/110/379 234/111/379 233/112/379
+f 234/110/380 236/111/380 235/112/380
+f 236/110/381 238/111/381 237/112/381
+f 238/110/382 240/111/382 239/112/382
+f 240/110/383 242/111/383 241/112/383
+f 242/110/384 244/111/384 243/112/384
+f 244/110/385 246/111/385 245/112/385
+f 246/110/386 248/111/386 247/112/386
+f 248/110/387 250/111/387 249/112/387
+f 250/110/388 252/111/388 251/112/388
+f 252/110/389 254/111/389 253/112/389
+f 194/114/390 256/116/390 198/115/390
+f 256/116/391 254/117/391 198/115/391
+f 254/117/392 252/118/392 198/115/392
+f 252/118/393 250/119/393 198/115/393
+f 250/119/394 248/120/394 198/115/394
+f 248/120/395 246/121/395 198/115/395
+f 246/121/396 244/122/396 198/115/396
+f 244/122/397 242/123/397 198/115/397
+f 242/123/398 240/124/398 198/115/398
+f 240/124/399 238/125/399 198/115/399
+f 238/125/400 236/126/400 198/115/400
+f 236/126/401 234/127/401 198/115/401
+f 234/127/402 232/128/402 198/115/402
+f 232/128/403 230/129/403 198/115/403
+f 230/129/404 228/130/404 198/115/404
+f 228/130/405 226/131/405 198/115/405
+f 226/131/406 224/132/406 198/115/406
+f 224/132/407 222/133/407 198/115/407
+f 222/133/408 220/134/408 198/115/408
+f 220/134/409 218/135/409 198/115/409
+f 218/135/410 216/136/410 198/115/410
+f 216/136/411 214/137/411 198/115/411
+f 214/137/412 212/138/412 198/115/412
+f 212/138/413 210/139/413 198/115/413
+f 210/139/398 208/140/398 198/115/398
+f 208/140/414 206/141/414 198/115/414
+f 206/141/415 204/142/415 198/115/415
+f 204/142/416 202/143/416 200/144/416
+f 198/115/417 204/142/417 200/144/417
+f 256/110/418 194/111/418 193/112/418
+f 254/110/419 256/111/419 255/112/419
+f 195/114/420 197/116/420 255/115/420
+f 197/116/421 199/117/421 255/115/421
+f 199/117/422 201/118/422 255/115/422
+f 201/118/423 203/119/423 255/115/423
+f 203/119/424 205/120/424 255/115/424
+f 205/120/425 207/121/425 255/115/425
+f 207/121/426 209/122/426 255/115/426
+f 209/122/427 211/123/427 255/115/427
+f 211/123/428 213/124/428 255/115/428
+f 213/124/429 215/125/429 255/115/429
+f 215/125/430 217/126/430 255/115/430
+f 237/136/431 233/134/431 235/135/431
+f 247/141/432 243/139/432 245/140/432
+f 241/138/433 237/136/433 239/137/433
+f 241/138/434 233/134/434 237/136/434
+f 251/143/435 247/141/435 249/142/435
+f 251/143/436 243/139/436 247/141/436
+f 219/127/437 221/128/437 223/129/437
+f 219/127/438 223/129/438 225/130/438
+f 233/134/439 229/132/439 231/133/439
+f 241/138/440 229/132/440 233/134/440
+f 255/115/437 251/143/437 253/144/437
+f 255/115/441 217/126/441 251/143/441
+f 251/143/441 217/126/441 243/139/441
+f 219/127/442 225/130/442 227/131/442
+f 217/126/443 219/127/443 227/131/443
+f 243/139/420 217/126/420 227/131/420
+f 241/138/444 243/139/444 229/132/444
+f 243/139/445 227/131/445 229/132/445
+v -3.858562 2.027707 3.871576
+v -3.858562 2.027707 -3.907549
+v 3.920563 2.027707 -3.907549
+v 3.920563 2.027707 3.871576
+v -3.858562 2.306528 3.871576
+v -3.858562 2.306528 -3.907549
+v 3.920563 2.306528 -3.907549
+v 3.920563 2.306528 3.871576
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 0.000000 1.000000
+vt 1.000000 1.000000
+vn -1.000000 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 0.000000 1.000000
+vn 0.000000 -1.000000 0.000000
+vn 0.000000 1.000000 0.000000
+s off
+f 261/145/446 262/146/446 257/147/446
+f 262/145/447 263/146/447 258/147/447
+f 263/145/448 264/146/448 260/148/448
+f 264/145/449 261/146/449 257/148/449
+f 257/145/450 258/146/450 259/148/450
+f 264/145/451 263/146/451 262/148/451
+f 262/146/446 258/148/446 257/147/446
+f 263/146/447 259/148/447 258/147/447
+f 259/147/448 263/145/448 260/148/448
+f 260/147/449 264/145/449 257/148/449
+f 260/147/450 257/145/450 259/148/450
+f 261/147/451 264/145/451 262/148/451
+v 2.043798 0.024218 -3.001008
+v 2.043798 2.024218 -3.001008
+v 2.238889 0.024218 -2.981793
+v 2.238889 2.024218 -2.981793
+v 2.426482 0.024218 -2.924888
+v 2.426482 2.024218 -2.924888
+v 2.599369 0.024218 -2.832478
+v 2.599369 2.024218 -2.832478
+v 2.750905 0.024218 -2.708115
+v 2.750905 2.024218 -2.708115
+v 2.875268 0.024218 -2.556578
+v 2.875268 2.024218 -2.556578
+v 2.967678 0.024218 -2.383692
+v 2.967678 2.024218 -2.383692
+v 3.024584 0.024218 -2.196099
+v 3.024584 2.024218 -2.196099
+v 3.043798 0.024218 -2.001008
+v 3.043798 2.024218 -2.001008
+v 3.024584 0.024218 -1.805918
+v 3.024584 2.024218 -1.805918
+v 2.967678 0.024218 -1.618325
+v 2.967678 2.024218 -1.618325
+v 2.875268 0.024218 -1.445438
+v 2.875268 2.024218 -1.445438
+v 2.750905 0.024218 -1.293901
+v 2.750905 2.024218 -1.293901
+v 2.599369 0.024218 -1.169539
+v 2.599369 2.024218 -1.169539
+v 2.426482 0.024218 -1.077129
+v 2.426482 2.024218 -1.077129
+v 2.238889 0.024218 -1.020223
+v 2.238889 2.024218 -1.020223
+v 2.043798 0.024218 -1.001008
+v 2.043798 2.024218 -1.001008
+v 1.848708 0.024218 -1.020223
+v 1.848708 2.024218 -1.020223
+v 1.661115 0.024218 -1.077129
+v 1.661115 2.024218 -1.077129
+v 1.488228 0.024218 -1.169539
+v 1.488228 2.024218 -1.169539
+v 1.336691 0.024218 -1.293902
+v 1.336691 2.024218 -1.293902
+v 1.212328 0.024218 -1.445439
+v 1.212328 2.024218 -1.445439
+v 1.119919 0.024218 -1.618326
+v 1.119919 2.024218 -1.618326
+v 1.063013 0.024218 -1.805919
+v 1.063013 2.024218 -1.805919
+v 1.043798 0.024218 -2.001009
+v 1.043798 2.024218 -2.001009
+v 1.063013 0.024218 -2.196100
+v 1.063013 2.024218 -2.196100
+v 1.119919 0.024218 -2.383693
+v 1.119919 2.024218 -2.383693
+v 1.212330 0.024218 -2.556580
+v 1.212330 2.024218 -2.556580
+v 1.336693 0.024218 -2.708116
+v 1.336693 2.024218 -2.708116
+v 1.488229 0.024218 -2.832479
+v 1.488229 2.024218 -2.832479
+v 1.661116 0.024218 -2.924888
+v 1.661116 2.024218 -2.924888
+v 1.848710 0.024218 -2.981794
+v 1.848710 2.024218 -2.981794
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn 0.098018 0.000000 -0.995185
+vn 0.290285 0.000000 -0.956940
+vn 0.471397 0.000000 -0.881921
+vn 0.634393 0.000000 -0.773011
+vn 0.773011 0.000000 -0.634393
+vn 0.881921 0.000000 -0.471398
+vn 0.956940 0.000000 -0.290285
+vn 0.995185 0.000000 -0.098017
+vn 0.995185 0.000000 0.098017
+vn 0.956940 0.000000 0.290285
+vn 0.881921 0.000000 0.471397
+vn 0.773011 0.000000 0.634393
+vn 0.634393 0.000000 0.773011
+vn 0.471397 0.000000 0.881921
+vn 0.290285 0.000000 0.956940
+vn 0.098017 0.000000 0.995185
+vn -0.098018 0.000000 0.995185
+vn -0.290285 0.000000 0.956940
+vn -0.471397 0.000000 0.881921
+vn -0.634394 0.000000 0.773010
+vn -0.773011 0.000000 0.634393
+vn -0.881922 0.000000 0.471396
+vn -0.956941 0.000000 0.290283
+vn -0.995185 0.000000 0.098017
+vn -0.995185 -0.000000 -0.098018
+vn -0.956940 -0.000000 -0.290286
+vn -0.881921 -0.000000 -0.471398
+vn -0.773010 -0.000000 -0.634394
+vn -0.634392 -0.000000 -0.773012
+vn -0.471396 -0.000000 -0.881922
+vn -0.098016 -0.000000 -0.995185
+vn -0.290283 -0.000000 -0.956941
+s off
+f 265/149/452 266/150/452 268/151/452
+f 267/149/453 268/150/453 270/151/453
+f 269/149/454 270/150/454 272/151/454
+f 271/149/455 272/150/455 274/151/455
+f 273/149/456 274/150/456 276/151/456
+f 275/149/457 276/150/457 278/151/457
+f 277/149/458 278/150/458 280/151/458
+f 279/149/459 280/150/459 282/151/459
+f 281/149/460 282/150/460 284/151/460
+f 283/149/461 284/150/461 286/151/461
+f 285/149/462 286/150/462 288/151/462
+f 287/149/463 288/150/463 290/151/463
+f 289/149/464 290/150/464 292/151/464
+f 291/149/465 292/150/465 294/151/465
+f 293/149/466 294/150/466 296/151/466
+f 295/149/467 296/150/467 298/151/467
+f 297/149/468 298/150/468 299/152/468
+f 299/149/469 300/150/469 301/152/469
+f 301/149/470 302/150/470 303/152/470
+f 303/149/471 304/150/471 305/152/471
+f 305/149/472 306/150/472 307/152/472
+f 307/149/473 308/150/473 309/152/473
+f 309/149/474 310/150/474 311/152/474
+f 311/149/475 312/150/475 313/152/475
+f 313/149/476 314/150/476 315/152/476
+f 315/149/477 316/150/477 317/152/477
+f 317/149/478 318/150/478 319/152/478
+f 319/149/479 320/150/479 321/152/479
+f 321/149/480 322/150/480 323/152/480
+f 323/149/481 324/150/481 325/152/481
+f 268/153/451 266/154/451 270/155/451
+f 327/149/482 328/150/482 265/152/482
+f 325/149/483 326/150/483 327/152/483
+f 265/153/450 267/154/450 327/155/450
+f 267/152/452 265/149/452 268/151/452
+f 269/152/453 267/149/453 270/151/453
+f 271/152/454 269/149/454 272/151/454
+f 273/152/455 271/149/455 274/151/455
+f 275/152/456 273/149/456 276/151/456
+f 277/152/457 275/149/457 278/151/457
+f 279/152/458 277/149/458 280/151/458
+f 281/152/459 279/149/459 282/151/459
+f 283/152/460 281/149/460 284/151/460
+f 285/152/461 283/149/461 286/151/461
+f 287/152/462 285/149/462 288/151/462
+f 289/152/463 287/149/463 290/151/463
+f 291/152/464 289/149/464 292/151/464
+f 293/152/465 291/149/465 294/151/465
+f 295/152/466 293/149/466 296/151/466
+f 297/152/467 295/149/467 298/151/467
+f 298/150/468 300/151/468 299/152/468
+f 300/150/469 302/151/469 301/152/469
+f 302/150/470 304/151/470 303/152/470
+f 304/150/471 306/151/471 305/152/471
+f 306/150/472 308/151/472 307/152/472
+f 308/150/473 310/151/473 309/152/473
+f 310/150/474 312/151/474 311/152/474
+f 312/150/475 314/151/475 313/152/475
+f 314/150/476 316/151/476 315/152/476
+f 316/150/477 318/151/477 317/152/477
+f 318/150/478 320/151/478 319/152/478
+f 320/150/479 322/151/479 321/152/479
+f 322/150/480 324/151/480 323/152/480
+f 324/150/481 326/151/481 325/152/481
+f 266/154/451 328/156/451 270/155/451
+f 328/156/451 326/157/451 270/155/451
+f 326/157/451 324/158/451 270/155/451
+f 324/158/451 322/159/451 270/155/451
+f 322/159/451 320/160/451 270/155/451
+f 320/160/451 318/161/451 270/155/451
+f 318/161/451 316/162/451 270/155/451
+f 316/162/451 314/163/451 270/155/451
+f 314/163/451 312/164/451 270/155/451
+f 312/164/451 310/165/451 270/155/451
+f 310/165/451 308/166/451 270/155/451
+f 308/166/451 306/167/451 270/155/451
+f 306/167/451 304/168/451 270/155/451
+f 304/168/451 302/169/451 270/155/451
+f 302/169/451 300/170/451 270/155/451
+f 300/170/451 298/171/451 270/155/451
+f 298/171/451 296/172/451 270/155/451
+f 296/172/451 294/173/451 270/155/451
+f 294/173/451 292/174/451 270/155/451
+f 292/174/451 290/175/451 270/155/451
+f 290/175/451 288/176/451 270/155/451
+f 288/176/451 286/177/451 270/155/451
+f 286/177/451 284/178/451 270/155/451
+f 284/178/451 282/179/451 270/155/451
+f 282/179/451 280/180/451 270/155/451
+f 280/180/451 278/181/451 270/155/451
+f 278/181/451 276/182/451 270/155/451
+f 276/182/451 274/183/451 270/155/451
+f 274/183/451 272/184/451 270/155/451
+f 328/150/482 266/151/482 265/152/482
+f 326/150/483 328/151/483 327/152/483
+f 267/154/450 269/156/450 327/155/450
+f 269/156/450 271/157/450 327/155/450
+f 271/157/450 273/158/450 327/155/450
+f 273/158/450 275/159/450 327/155/450
+f 275/159/450 277/160/450 327/155/450
+f 277/160/450 279/161/450 327/155/450
+f 279/161/450 281/162/450 327/155/450
+f 281/162/450 283/163/450 327/155/450
+f 283/163/450 285/164/450 327/155/450
+f 285/164/450 287/165/450 327/155/450
+f 287/165/450 289/166/450 327/155/450
+f 289/166/450 291/167/450 327/155/450
+f 291/167/450 293/168/450 327/155/450
+f 293/168/450 295/169/450 327/155/450
+f 295/169/450 297/170/450 327/155/450
+f 297/170/450 299/171/450 327/155/450
+f 299/171/450 301/172/450 327/155/450
+f 301/172/450 303/173/450 327/155/450
+f 303/173/450 305/174/450 327/155/450
+f 305/174/450 307/175/450 327/155/450
+f 307/175/450 309/176/450 327/155/450
+f 309/176/450 311/177/450 327/155/450
+f 311/177/450 313/178/450 327/155/450
+f 313/178/450 315/179/450 327/155/450
+f 315/179/450 317/180/450 327/155/450
+f 317/180/450 319/181/450 327/155/450
+f 319/181/450 321/182/450 327/155/450
+f 321/182/450 323/183/450 325/184/450
+f 327/155/450 321/182/450 325/184/450
+v -2.014818 0.007922 0.998641
+v -2.014818 2.007922 0.998641
+v -1.819728 0.007922 1.017856
+v -1.819728 2.007922 1.017856
+v -1.632135 0.007922 1.074762
+v -1.632135 2.007922 1.074762
+v -1.459248 0.007922 1.167172
+v -1.459248 2.007922 1.167172
+v -1.307712 0.007922 1.291534
+v -1.307712 2.007922 1.291534
+v -1.183349 0.007922 1.443071
+v -1.183349 2.007922 1.443071
+v -1.090939 0.007922 1.615958
+v -1.090939 2.007922 1.615958
+v -1.034033 0.007922 1.803551
+v -1.034033 2.007922 1.803551
+v -1.014818 0.007922 1.998641
+v -1.014818 2.007922 1.998641
+v -1.034033 0.007922 2.193732
+v -1.034033 2.007922 2.193732
+v -1.090939 0.007922 2.381325
+v -1.090939 2.007922 2.381325
+v -1.183349 0.007922 2.554211
+v -1.183349 2.007922 2.554211
+v -1.307712 0.007922 2.705748
+v -1.307712 2.007922 2.705748
+v -1.459248 0.007922 2.830111
+v -1.459248 2.007922 2.830111
+v -1.632135 0.007922 2.922521
+v -1.632135 2.007922 2.922521
+v -1.819728 0.007922 2.979427
+v -1.819728 2.007922 2.979427
+v -2.014819 0.007922 2.998641
+v -2.014819 2.007922 2.998641
+v -2.209909 0.007922 2.979426
+v -2.209909 2.007922 2.979426
+v -2.397502 0.007922 2.922521
+v -2.397502 2.007922 2.922521
+v -2.570389 0.007922 2.830111
+v -2.570389 2.007922 2.830111
+v -2.721926 0.007922 2.705748
+v -2.721926 2.007922 2.705748
+v -2.846288 0.007922 2.554211
+v -2.846288 2.007922 2.554211
+v -2.938698 0.007922 2.381324
+v -2.938698 2.007922 2.381324
+v -2.995604 0.007922 2.193731
+v -2.995604 2.007922 2.193731
+v -3.014818 0.007922 1.998640
+v -3.014818 2.007922 1.998640
+v -2.995604 0.007922 1.803550
+v -2.995604 2.007922 1.803550
+v -2.938698 0.007922 1.615957
+v -2.938698 2.007922 1.615957
+v -2.846287 0.007922 1.443070
+v -2.846287 2.007922 1.443070
+v -2.721924 0.007922 1.291534
+v -2.721924 2.007922 1.291534
+v -2.570388 0.007922 1.167171
+v -2.570388 2.007922 1.167171
+v -2.397501 0.007922 1.074761
+v -2.397501 2.007922 1.074761
+v -2.209907 0.007922 1.017856
+v -2.209907 2.007922 1.017856
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn 0.098017 0.000000 -0.995185
+vn 0.881921 0.000000 -0.471397
+vn 0.634393 0.000000 0.773010
+vn 0.471396 0.000000 0.881922
+vn -0.881920 -0.000000 -0.471398
+vn -0.634393 -0.000000 -0.773011
+vn -0.471395 -0.000000 -0.881922
+s off
+f 329/185/484 330/186/484 332/187/484
+f 331/185/453 332/186/453 334/187/453
+f 333/185/454 334/186/454 336/187/454
+f 335/185/455 336/186/455 338/187/455
+f 337/185/456 338/186/456 340/187/456
+f 339/185/485 340/186/485 342/187/485
+f 341/185/458 342/186/458 344/187/458
+f 343/185/459 344/186/459 346/187/459
+f 345/185/460 346/186/460 348/187/460
+f 347/185/461 348/186/461 350/187/461
+f 349/185/462 350/186/462 352/187/462
+f 351/185/463 352/186/463 354/187/463
+f 353/185/486 354/186/486 356/187/486
+f 355/185/487 356/186/487 358/187/487
+f 357/185/466 358/186/466 360/187/466
+f 359/185/467 360/186/467 362/187/467
+f 361/185/468 362/186/468 363/188/468
+f 363/185/469 364/186/469 365/188/469
+f 365/185/470 366/186/470 367/188/470
+f 367/185/471 368/186/471 369/188/471
+f 369/185/472 370/186/472 371/188/472
+f 371/185/473 372/186/473 373/188/473
+f 373/185/474 374/186/474 375/188/474
+f 375/185/475 376/186/475 377/188/475
+f 377/185/476 378/186/476 379/188/476
+f 379/185/477 380/186/477 381/188/477
+f 381/185/488 382/186/488 383/188/488
+f 383/185/479 384/186/479 385/188/479
+f 385/185/489 386/186/489 387/188/489
+f 387/185/490 388/186/490 389/188/490
+f 332/189/451 330/190/451 334/191/451
+f 391/185/482 392/186/482 329/188/482
+f 389/185/483 390/186/483 391/188/483
+f 329/189/450 331/190/450 391/191/450
+f 331/188/484 329/185/484 332/187/484
+f 333/188/453 331/185/453 334/187/453
+f 335/188/454 333/185/454 336/187/454
+f 337/188/455 335/185/455 338/187/455
+f 339/188/456 337/185/456 340/187/456
+f 341/188/485 339/185/485 342/187/485
+f 343/188/458 341/185/458 344/187/458
+f 345/188/459 343/185/459 346/187/459
+f 347/188/460 345/185/460 348/187/460
+f 349/188/461 347/185/461 350/187/461
+f 351/188/462 349/185/462 352/187/462
+f 353/188/463 351/185/463 354/187/463
+f 355/188/486 353/185/486 356/187/486
+f 357/188/487 355/185/487 358/187/487
+f 359/188/466 357/185/466 360/187/466
+f 361/188/467 359/185/467 362/187/467
+f 362/186/468 364/187/468 363/188/468
+f 364/186/469 366/187/469 365/188/469
+f 366/186/470 368/187/470 367/188/470
+f 368/186/471 370/187/471 369/188/471
+f 370/186/472 372/187/472 371/188/472
+f 372/186/473 374/187/473 373/188/473
+f 374/186/474 376/187/474 375/188/474
+f 376/186/475 378/187/475 377/188/475
+f 378/186/476 380/187/476 379/188/476
+f 380/186/477 382/187/477 381/188/477
+f 382/186/488 384/187/488 383/188/488
+f 384/186/479 386/187/479 385/188/479
+f 386/186/489 388/187/489 387/188/489
+f 388/186/490 390/187/490 389/188/490
+f 330/190/451 392/192/451 334/191/451
+f 392/192/451 390/193/451 334/191/451
+f 390/193/451 388/194/451 334/191/451
+f 388/194/451 386/195/451 334/191/451
+f 386/195/451 384/196/451 334/191/451
+f 384/196/451 382/197/451 334/191/451
+f 382/197/451 380/198/451 334/191/451
+f 380/198/451 378/199/451 334/191/451
+f 378/199/451 376/200/451 334/191/451
+f 376/200/451 374/201/451 334/191/451
+f 374/201/451 372/202/451 334/191/451
+f 372/202/451 370/203/451 334/191/451
+f 370/203/451 368/204/451 334/191/451
+f 368/204/451 366/205/451 334/191/451
+f 366/205/451 364/206/451 334/191/451
+f 364/206/451 362/207/451 334/191/451
+f 362/207/451 360/208/451 334/191/451
+f 360/208/451 358/209/451 334/191/451
+f 358/209/451 356/210/451 334/191/451
+f 356/210/451 354/211/451 334/191/451
+f 354/211/451 352/212/451 334/191/451
+f 352/212/451 350/213/451 334/191/451
+f 350/213/451 348/214/451 334/191/451
+f 348/214/451 346/215/451 334/191/451
+f 346/215/451 344/216/451 334/191/451
+f 344/216/451 342/217/451 334/191/451
+f 342/217/451 340/218/451 334/191/451
+f 340/218/451 338/219/451 334/191/451
+f 338/219/451 336/220/451 334/191/451
+f 392/186/482 330/187/482 329/188/482
+f 390/186/483 392/187/483 391/188/483
+f 331/190/450 333/192/450 391/191/450
+f 333/192/450 335/193/450 391/191/450
+f 335/193/450 337/194/450 391/191/450
+f 337/194/450 339/195/450 391/191/450
+f 339/195/450 341/196/450 391/191/450
+f 341/196/450 343/197/450 391/191/450
+f 343/197/450 345/198/450 391/191/450
+f 345/198/450 347/199/450 391/191/450
+f 347/199/450 349/200/450 391/191/450
+f 349/200/450 351/201/450 391/191/450
+f 351/201/450 353/202/450 391/191/450
+f 353/202/450 355/203/450 391/191/450
+f 355/203/450 357/204/450 391/191/450
+f 357/204/450 359/205/450 391/191/450
+f 359/205/450 361/206/450 391/191/450
+f 361/206/450 363/207/450 391/191/450
+f 363/207/450 365/208/450 391/191/450
+f 365/208/450 367/209/450 391/191/450
+f 367/209/450 369/210/450 391/191/450
+f 369/210/450 371/211/450 391/191/450
+f 371/211/450 373/212/450 391/191/450
+f 373/212/450 375/213/450 391/191/450
+f 375/213/450 377/214/450 391/191/450
+f 377/214/450 379/215/450 391/191/450
+f 379/215/450 381/216/450 391/191/450
+f 381/216/450 383/217/450 391/191/450
+f 383/217/450 385/218/450 391/191/450
+f 385/218/450 387/219/450 391/191/450
+f 387/219/450 389/220/450 391/191/450
+v -2.001621 -0.021814 -3.021079
+v -2.001621 1.978186 -3.021079
+v -1.806530 -0.021814 -3.001864
+v -1.806530 1.978186 -3.001864
+v -1.618937 -0.021814 -2.944958
+v -1.618937 1.978186 -2.944958
+v -1.446051 -0.021814 -2.852548
+v -1.446051 1.978186 -2.852548
+v -1.294514 -0.021814 -2.728185
+v -1.294514 1.978186 -2.728185
+v -1.170151 -0.021814 -2.576649
+v -1.170151 1.978186 -2.576649
+v -1.077741 -0.021814 -2.403762
+v -1.077741 1.978186 -2.403762
+v -1.020836 -0.021814 -2.216169
+v -1.020836 1.978186 -2.216169
+v -1.001621 -0.021814 -2.021079
+v -1.001621 1.978186 -2.021079
+v -1.020835 -0.021814 -1.825988
+v -1.020835 1.978186 -1.825988
+v -1.077741 -0.021814 -1.638395
+v -1.077741 1.978186 -1.638395
+v -1.170151 -0.021814 -1.465508
+v -1.170151 1.978186 -1.465508
+v -1.294514 -0.021814 -1.313972
+v -1.294514 1.978186 -1.313972
+v -1.446051 -0.021814 -1.189609
+v -1.446051 1.978186 -1.189609
+v -1.618937 -0.021814 -1.097199
+v -1.618937 1.978186 -1.097199
+v -1.806531 -0.021814 -1.040293
+v -1.806531 1.978186 -1.040293
+v -2.001621 -0.021814 -1.021079
+v -2.001621 1.978186 -1.021079
+v -2.196712 -0.021814 -1.040293
+v -2.196712 1.978186 -1.040293
+v -2.384305 -0.021814 -1.097199
+v -2.384305 1.978186 -1.097199
+v -2.557191 -0.021814 -1.189609
+v -2.557191 1.978186 -1.189609
+v -2.708728 -0.021814 -1.313972
+v -2.708728 1.978186 -1.313972
+v -2.833091 -0.021814 -1.465509
+v -2.833091 1.978186 -1.465509
+v -2.925501 -0.021814 -1.638396
+v -2.925501 1.978186 -1.638396
+v -2.982406 -0.021814 -1.825989
+v -2.982406 1.978186 -1.825989
+v -3.001621 -0.021814 -2.021080
+v -3.001621 1.978186 -2.021080
+v -2.982406 -0.021814 -2.216170
+v -2.982406 1.978186 -2.216170
+v -2.925500 -0.021814 -2.403763
+v -2.925500 1.978186 -2.403763
+v -2.833090 -0.021814 -2.576650
+v -2.833090 1.978186 -2.576650
+v -2.708727 -0.021814 -2.728186
+v -2.708727 1.978186 -2.728186
+v -2.557190 -0.021814 -2.852549
+v -2.557190 1.978186 -2.852549
+v -2.384303 -0.021814 -2.944959
+v -2.384303 1.978186 -2.944959
+v -2.196710 -0.021814 -3.001864
+v -2.196710 1.978186 -3.001864
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn 0.471398 0.000000 -0.881921
+vn -0.634393 0.000000 0.773010
+vn -0.881921 -0.000000 -0.471397
+vn -0.773009 -0.000000 -0.634395
+vn -0.634393 -0.000000 -0.773010
+s off
+f 393/221/484 394/222/484 396/223/484
+f 395/221/453 396/222/453 398/223/453
+f 397/221/491 398/222/491 400/223/491
+f 399/221/455 400/222/455 402/223/455
+f 401/221/456 402/222/456 404/223/456
+f 403/221/485 404/222/485 406/223/485
+f 405/221/458 406/222/458 408/223/458
+f 407/221/459 408/222/459 410/223/459
+f 409/221/460 410/222/460 412/223/460
+f 411/221/461 412/222/461 414/223/461
+f 413/221/462 414/222/462 416/223/462
+f 415/221/463 416/222/463 418/223/463
+f 417/221/464 418/222/464 420/223/464
+f 419/221/465 420/222/465 422/223/465
+f 421/221/466 422/222/466 424/223/466
+f 423/221/467 424/222/467 426/223/467
+f 425/221/468 426/222/468 427/224/468
+f 427/221/469 428/222/469 429/224/469
+f 429/221/470 430/222/470 431/224/470
+f 431/221/492 432/222/492 433/224/492
+f 433/221/472 434/222/472 435/224/472
+f 435/221/473 436/222/473 437/224/473
+f 437/221/474 438/222/474 439/224/474
+f 439/221/475 440/222/475 441/224/475
+f 441/221/476 442/222/476 443/224/476
+f 443/221/477 444/222/477 445/224/477
+f 445/221/493 446/222/493 447/224/493
+f 447/221/494 448/222/494 449/224/494
+f 449/221/495 450/222/495 451/224/495
+f 451/221/490 452/222/490 453/224/490
+f 396/225/451 394/226/451 398/227/451
+f 455/221/482 456/222/482 393/224/482
+f 453/221/483 454/222/483 455/224/483
+f 393/225/450 395/226/450 455/227/450
+f 395/224/484 393/221/484 396/223/484
+f 397/224/453 395/221/453 398/223/453
+f 399/224/491 397/221/491 400/223/491
+f 401/224/455 399/221/455 402/223/455
+f 403/224/456 401/221/456 404/223/456
+f 405/224/485 403/221/485 406/223/485
+f 407/224/458 405/221/458 408/223/458
+f 409/224/459 407/221/459 410/223/459
+f 411/224/460 409/221/460 412/223/460
+f 413/224/461 411/221/461 414/223/461
+f 415/224/462 413/221/462 416/223/462
+f 417/224/463 415/221/463 418/223/463
+f 419/224/464 417/221/464 420/223/464
+f 421/224/465 419/221/465 422/223/465
+f 423/224/466 421/221/466 424/223/466
+f 425/224/467 423/221/467 426/223/467
+f 426/222/468 428/223/468 427/224/468
+f 428/222/469 430/223/469 429/224/469
+f 430/222/470 432/223/470 431/224/470
+f 432/222/492 434/223/492 433/224/492
+f 434/222/472 436/223/472 435/224/472
+f 436/222/473 438/223/473 437/224/473
+f 438/222/474 440/223/474 439/224/474
+f 440/222/475 442/223/475 441/224/475
+f 442/222/476 444/223/476 443/224/476
+f 444/222/477 446/223/477 445/224/477
+f 446/222/493 448/223/493 447/224/493
+f 448/222/494 450/223/494 449/224/494
+f 450/222/495 452/223/495 451/224/495
+f 452/222/490 454/223/490 453/224/490
+f 394/226/451 456/228/451 398/227/451
+f 456/228/451 454/229/451 398/227/451
+f 454/229/451 452/230/451 398/227/451
+f 452/230/451 450/231/451 398/227/451
+f 450/231/451 448/232/451 398/227/451
+f 448/232/451 446/233/451 398/227/451
+f 446/233/451 444/234/451 398/227/451
+f 444/234/451 442/235/451 398/227/451
+f 442/235/451 440/236/451 398/227/451
+f 440/236/451 438/237/451 398/227/451
+f 438/237/451 436/238/451 398/227/451
+f 436/238/451 434/239/451 398/227/451
+f 434/239/451 432/240/451 398/227/451
+f 432/240/451 430/241/451 398/227/451
+f 430/241/451 428/242/451 398/227/451
+f 428/242/451 426/243/451 398/227/451
+f 426/243/451 424/244/451 398/227/451
+f 424/244/451 422/245/451 398/227/451
+f 422/245/451 420/246/451 398/227/451
+f 420/246/451 418/247/451 398/227/451
+f 418/247/451 416/248/451 398/227/451
+f 416/248/451 414/249/451 398/227/451
+f 414/249/451 412/250/451 398/227/451
+f 412/250/451 410/251/451 398/227/451
+f 410/251/451 408/252/451 398/227/451
+f 408/252/451 406/253/451 398/227/451
+f 406/253/451 404/254/451 398/227/451
+f 404/254/451 402/255/451 398/227/451
+f 402/255/451 400/256/451 398/227/451
+f 456/222/482 394/223/482 393/224/482
+f 454/222/483 456/223/483 455/224/483
+f 395/226/450 397/228/450 455/227/450
+f 397/228/450 399/229/450 455/227/450
+f 399/229/450 401/230/450 455/227/450
+f 401/230/450 403/231/450 455/227/450
+f 403/231/450 405/232/450 455/227/450
+f 405/232/450 407/233/450 455/227/450
+f 407/233/450 409/234/450 455/227/450
+f 409/234/450 411/235/450 455/227/450
+f 411/235/450 413/236/450 455/227/450
+f 413/236/450 415/237/450 455/227/450
+f 415/237/450 417/238/450 455/227/450
+f 417/238/450 419/239/450 455/227/450
+f 419/239/450 421/240/450 455/227/450
+f 421/240/450 423/241/450 455/227/450
+f 423/241/450 425/242/450 455/227/450
+f 425/242/450 427/243/450 455/227/450
+f 427/243/450 429/244/450 455/227/450
+f 429/244/450 431/245/450 455/227/450
+f 431/245/450 433/246/450 455/227/450
+f 433/246/450 435/247/450 455/227/450
+f 435/247/450 437/248/450 455/227/450
+f 437/248/450 439/249/450 455/227/450
+f 439/249/450 441/250/450 455/227/450
+f 441/250/450 443/251/450 455/227/450
+f 443/251/450 445/252/450 455/227/450
+f 445/252/450 447/253/450 455/227/450
+f 447/253/450 449/254/450 455/227/450
+f 449/254/450 451/255/450 455/227/450
+f 451/255/450 453/256/450 455/227/450
+v 2.021592 0.003623 1.016610
+v 2.021592 2.003623 1.016610
+v 2.216682 0.003623 1.035825
+v 2.216682 2.003623 1.035825
+v 2.404276 0.003623 1.092731
+v 2.404276 2.003623 1.092731
+v 2.577162 0.003623 1.185141
+v 2.577162 2.003623 1.185141
+v 2.728699 0.003623 1.309503
+v 2.728699 2.003623 1.309503
+v 2.853062 0.003623 1.461040
+v 2.853062 2.003623 1.461040
+v 2.945472 0.003623 1.633927
+v 2.945472 2.003623 1.633927
+v 3.002378 0.003623 1.821520
+v 3.002378 2.003623 1.821520
+v 3.021592 0.003623 2.016610
+v 3.021592 2.003623 2.016610
+v 3.002378 0.003623 2.211700
+v 3.002378 2.003623 2.211700
+v 2.945472 0.003623 2.399293
+v 2.945472 2.003623 2.399293
+v 2.853062 0.003623 2.572180
+v 2.853062 2.003623 2.572180
+v 2.728699 0.003623 2.723717
+v 2.728699 2.003623 2.723717
+v 2.577162 0.003623 2.848080
+v 2.577162 2.003623 2.848080
+v 2.404275 0.003623 2.940490
+v 2.404275 2.003623 2.940490
+v 2.216682 0.003623 2.997396
+v 2.216682 2.003623 2.997396
+v 2.021592 0.003623 3.016610
+v 2.021592 2.003623 3.016610
+v 1.826501 0.003623 2.997395
+v 1.826501 2.003623 2.997395
+v 1.638908 0.003623 2.940490
+v 1.638908 2.003623 2.940490
+v 1.466021 0.003623 2.848079
+v 1.466021 2.003623 2.848079
+v 1.314485 0.003623 2.723716
+v 1.314485 2.003623 2.723716
+v 1.190122 0.003623 2.572180
+v 1.190122 2.003623 2.572180
+v 1.097712 0.003623 2.399293
+v 1.097712 2.003623 2.399293
+v 1.040807 0.003623 2.211699
+v 1.040807 2.003623 2.211699
+v 1.021592 0.003623 2.016609
+v 1.021592 2.003623 2.016609
+v 1.040807 0.003623 1.821519
+v 1.040807 2.003623 1.821519
+v 1.097713 0.003623 1.633926
+v 1.097713 2.003623 1.633926
+v 1.190123 0.003623 1.461039
+v 1.190123 2.003623 1.461039
+v 1.314486 0.003623 1.309502
+v 1.314486 2.003623 1.309502
+v 1.466023 0.003623 1.185140
+v 1.466023 2.003623 1.185140
+v 1.638910 0.003623 1.092730
+v 1.638910 2.003623 1.092730
+v 1.826503 0.003623 1.035825
+v 1.826503 2.003623 1.035825
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+s off
+f 457/257/484 458/258/484 460/259/484
+f 459/257/453 460/258/453 462/259/453
+f 461/257/454 462/258/454 464/259/454
+f 463/257/455 464/258/455 466/259/455
+f 465/257/456 466/258/456 468/259/456
+f 467/257/457 468/258/457 470/259/457
+f 469/257/458 470/258/458 472/259/458
+f 471/257/459 472/258/459 474/259/459
+f 473/257/460 474/258/460 476/259/460
+f 475/257/461 476/258/461 478/259/461
+f 477/257/462 478/258/462 480/259/462
+f 479/257/463 480/258/463 482/259/463
+f 481/257/464 482/258/464 484/259/464
+f 483/257/465 484/258/465 486/259/465
+f 485/257/466 486/258/466 488/259/466
+f 487/257/467 488/258/467 490/259/467
+f 489/257/468 490/258/468 491/260/468
+f 491/257/469 492/258/469 493/260/469
+f 493/257/470 494/258/470 495/260/470
+f 495/257/471 496/258/471 497/260/471
+f 497/257/472 498/258/472 499/260/472
+f 499/257/473 500/258/473 501/260/473
+f 501/257/474 502/258/474 503/260/474
+f 503/257/475 504/258/475 505/260/475
+f 505/257/476 506/258/476 507/260/476
+f 507/257/477 508/258/477 509/260/477
+f 509/257/478 510/258/478 511/260/478
+f 511/257/494 512/258/494 513/260/494
+f 513/257/489 514/258/489 515/260/489
+f 515/257/490 516/258/490 517/260/490
+f 460/261/451 458/262/451 462/263/451
+f 519/257/482 520/258/482 457/260/482
+f 517/257/483 518/258/483 519/260/483
+f 457/261/450 459/262/450 519/263/450
+f 459/260/484 457/257/484 460/259/484
+f 461/260/453 459/257/453 462/259/453
+f 463/260/454 461/257/454 464/259/454
+f 465/260/455 463/257/455 466/259/455
+f 467/260/456 465/257/456 468/259/456
+f 469/260/457 467/257/457 470/259/457
+f 471/260/458 469/257/458 472/259/458
+f 473/260/459 471/257/459 474/259/459
+f 475/260/460 473/257/460 476/259/460
+f 477/260/461 475/257/461 478/259/461
+f 479/260/462 477/257/462 480/259/462
+f 481/260/463 479/257/463 482/259/463
+f 483/260/464 481/257/464 484/259/464
+f 485/260/465 483/257/465 486/259/465
+f 487/260/466 485/257/466 488/259/466
+f 489/260/467 487/257/467 490/259/467
+f 490/258/468 492/259/468 491/260/468
+f 492/258/469 494/259/469 493/260/469
+f 494/258/470 496/259/470 495/260/470
+f 496/258/471 498/259/471 497/260/471
+f 498/258/472 500/259/472 499/260/472
+f 500/258/473 502/259/473 501/260/473
+f 502/258/474 504/259/474 503/260/474
+f 504/258/475 506/259/475 505/260/475
+f 506/258/476 508/259/476 507/260/476
+f 508/258/477 510/259/477 509/260/477
+f 510/258/478 512/259/478 511/260/478
+f 512/258/494 514/259/494 513/260/494
+f 514/258/489 516/259/489 515/260/489
+f 516/258/490 518/259/490 517/260/490
+f 458/262/451 520/264/451 462/263/451
+f 520/264/451 518/265/451 462/263/451
+f 518/265/451 516/266/451 462/263/451
+f 516/266/451 514/267/451 462/263/451
+f 514/267/451 512/268/451 462/263/451
+f 512/268/451 510/269/451 462/263/451
+f 510/269/451 508/270/451 462/263/451
+f 508/270/451 506/271/451 462/263/451
+f 506/271/451 504/272/451 462/263/451
+f 504/272/451 502/273/451 462/263/451
+f 502/273/451 500/274/451 462/263/451
+f 500/274/451 498/275/451 462/263/451
+f 498/275/451 496/276/451 462/263/451
+f 496/276/451 494/277/451 462/263/451
+f 494/277/451 492/278/451 462/263/451
+f 492/278/451 490/279/451 462/263/451
+f 490/279/451 488/280/451 462/263/451
+f 488/280/451 486/281/451 462/263/451
+f 486/281/451 484/282/451 462/263/451
+f 484/282/451 482/283/451 462/263/451
+f 482/283/451 480/284/451 462/263/451
+f 480/284/451 478/285/451 462/263/451
+f 478/285/451 476/286/451 462/263/451
+f 476/286/451 474/287/451 462/263/451
+f 474/287/451 472/288/451 462/263/451
+f 472/288/451 470/289/451 462/263/451
+f 470/289/451 468/290/451 462/263/451
+f 468/290/451 466/291/451 462/263/451
+f 466/291/451 464/292/451 462/263/451
+f 520/258/482 458/259/482 457/260/482
+f 518/258/483 520/259/483 519/260/483
+f 459/262/450 461/264/450 519/263/450
+f 461/264/450 463/265/450 519/263/450
+f 463/265/450 465/266/450 519/263/450
+f 465/266/450 467/267/450 519/263/450
+f 467/267/450 469/268/450 519/263/450
+f 469/268/450 471/269/450 519/263/450
+f 471/269/450 473/270/450 519/263/450
+f 473/270/450 475/271/450 519/263/450
+f 475/271/450 477/272/450 519/263/450
+f 477/272/450 479/273/450 519/263/450
+f 479/273/450 481/274/450 519/263/450
+f 481/274/450 483/275/450 519/263/450
+f 483/275/450 485/276/450 519/263/450
+f 485/276/450 487/277/450 519/263/450
+f 487/277/450 489/278/450 519/263/450
+f 489/278/450 491/279/450 519/263/450
+f 491/279/450 493/280/450 519/263/450
+f 493/280/450 495/281/450 519/263/450
+f 495/281/450 497/282/450 519/263/450
+f 497/282/450 499/283/450 519/263/450
+f 499/283/450 501/284/450 519/263/450
+f 501/284/450 503/285/450 519/263/450
+f 503/285/450 505/286/450 519/263/450
+f 505/286/450 507/287/450 519/263/450
+f 507/287/450 509/288/450 519/263/450
+f 509/288/450 511/289/450 519/263/450
+f 511/289/450 513/290/450 519/263/450
+f 513/290/450 515/291/450 519/263/450
+f 515/291/450 517/292/450 519/263/450
diff --git a/examples/datavisualization/graphgallery/data/pipe.obj b/examples/datavisualization/graphgallery/data/pipe.obj
new file mode 100644
index 00000000..6ccbb286
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/pipe.obj
@@ -0,0 +1,330 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.289718 0.879351
+vt 0.288367 0.438844
+vt 0.330714 0.438714
+vt 0.332066 0.879221
+vt 0.370605 0.438592
+vt 0.371956 0.879099
+vt 0.406505 0.438482
+vt 0.407857 0.878988
+vt 0.437036 0.438388
+vt 0.778904 0.000000
+vt 0.780256 0.440507
+vt 0.749725 0.440601
+vt 0.748373 0.000094
+vt 0.713824 0.440711
+vt 0.712473 0.000204
+vt 0.673934 0.440833
+vt 0.672582 0.000326
+vt 0.631586 0.440963
+vt 0.630235 0.000456
+vt 0.588409 0.441095
+vt 0.587057 0.000588
+vt 0.546061 0.441225
+vt 0.544710 0.000718
+vt 0.506171 0.441348
+vt 0.504819 0.000841
+vt 0.470270 0.441458
+vt 0.468919 0.000951
+vt 0.439739 0.441552
+vt 0.720545 0.882916
+vt 0.719194 0.442409
+vt 0.755094 0.442299
+vt 0.756446 0.882806
+vt 0.794985 0.442176
+vt 0.796336 0.882683
+vt 0.837333 0.442046
+vt 0.838684 0.882553
+vt 0.881861 0.882421
+vt 0.880510 0.441914
+vt 0.924209 0.882291
+vt 0.922857 0.441784
+vt 0.964099 0.882168
+vt 0.962748 0.441662
+vt 1.000000 0.882058
+vt 0.717842 0.441552
+vt 0.719194 0.882058
+vt 0.681942 0.441662
+vt 0.683293 0.882169
+vt 0.642051 0.441784
+vt 0.643403 0.882291
+vt 0.599704 0.441914
+vt 0.601055 0.882421
+vt 0.556526 0.442046
+vt 0.557878 0.882553
+vt 0.514179 0.442176
+vt 0.515530 0.882683
+vt 0.474288 0.442299
+vt 0.475640 0.882806
+vt 0.438388 0.442409
+vt 0.097872 0.879939
+vt 0.096520 0.439433
+vt 0.128403 0.879846
+vt 0.127051 0.439339
+vt 0.164303 0.879735
+vt 0.162952 0.439229
+vt 0.204194 0.879613
+vt 0.000000 0.197605
+vt 0.008423 0.155257
+vt 0.000000 0.240783
+vt 0.246541 0.879483
+vt 0.245190 0.438976
+vt 0.202842 0.439106
+vt 0.438388 0.878895
+vt 0.438388 0.001045
+vt 0.998649 0.441552
+vt 0.439739 0.882916
+vt 0.024947 0.115367
+vt 0.048935 0.079466
+vt 0.079466 0.048935
+vt 0.115366 0.024947
+vt 0.155257 0.008424
+vt 0.197605 0.000000
+vt 0.240782 0.000000
+vt 0.283130 0.008423
+vt 0.323021 0.024947
+vt 0.358922 0.048935
+vt 0.389453 0.079466
+vt 0.413441 0.115367
+vt 0.429964 0.155257
+vt 0.438388 0.197605
+vt 0.438388 0.240783
+vt 0.429964 0.283130
+vt 0.413441 0.323021
+vt 0.389453 0.358922
+vt 0.358922 0.389453
+vt 0.323021 0.413441
+vt 0.283130 0.429964
+vt 0.240783 0.438388
+vt 0.197605 0.438388
+vt 0.155257 0.429964
+vt 0.115367 0.413441
+vt 0.079466 0.389453
+vt 0.048935 0.358922
+vt 0.024947 0.323021
+vt 0.008423 0.283130
+vn 0.000000 0.000000 -1.000000
+vn 0.000000 0.685690 -0.727866
+vn 0.142003 0.685690 -0.713889
+vn 0.195074 0.000000 -0.980773
+vn 0.278542 0.685690 -0.672475
+vn 0.382672 0.000000 -0.923856
+vn 0.404370 0.685690 -0.605213
+vn 0.555559 0.000000 -0.831446
+vn 0.514664 0.685690 -0.514664
+vn 0.707083 0.000000 -0.707083
+vn 0.605213 0.685690 -0.404370
+vn 0.831446 0.000000 -0.555559
+vn 0.672475 0.685690 -0.278542
+vn 0.923856 0.000000 -0.382672
+vn 0.713889 0.685690 -0.142003
+vn 0.980773 0.000000 -0.195074
+vn 0.727866 0.685690 0.000000
+vn 1.000000 0.000000 0.000000
+vn 0.713889 0.685690 0.142003
+vn 0.980773 0.000000 0.195074
+vn 0.672475 0.685690 0.278542
+vn 0.923856 0.000000 0.382672
+vn 0.605213 0.685690 0.404370
+vn 0.831446 0.000000 0.555559
+vn 0.514664 0.685690 0.514664
+vn 0.707083 0.000000 0.707083
+vn 0.404370 0.685690 0.605213
+vn 0.555559 0.000000 0.831446
+vn 0.278542 0.685690 0.672475
+vn 0.382672 0.000000 0.923856
+vn 0.142003 0.685690 0.713889
+vn 0.195074 0.000000 0.980773
+vn 0.000000 0.685690 0.727866
+vn 0.000000 0.000000 0.999969
+vn -0.195074 0.000000 0.980773
+vn -0.142003 0.685690 0.713889
+vn -0.382672 0.000000 0.923856
+vn -0.278542 0.685690 0.672475
+vn -0.555559 0.000000 0.831446
+vn -0.404370 0.685690 0.605213
+vn -0.707083 0.000000 0.707083
+vn -0.514664 0.685690 0.514664
+vn -0.831446 0.000000 0.555559
+vn -0.605213 0.685690 0.404370
+vn -0.923856 0.000000 0.382672
+vn -0.672475 0.685690 0.278542
+vn -0.980773 0.000000 0.195074
+vn -0.713889 0.685690 0.142003
+vn -1.000000 0.000000 0.000000
+vn -0.727866 0.685690 0.000000
+vn -0.980773 0.000000 -0.195074
+vn -0.713889 0.685690 -0.142003
+vn -0.923856 0.000000 -0.382672
+vn -0.672475 0.685690 -0.278542
+vn -0.831446 0.000000 -0.555559
+vn -0.605213 0.685690 -0.404370
+vn -0.707083 0.000000 -0.707083
+vn -0.514664 0.685690 -0.514695
+vn -0.555559 0.000000 -0.831446
+vn -0.404370 0.685690 -0.605213
+vn -0.382672 0.000000 -0.923856
+vn -0.195074 0.000000 -0.980773
+vn -0.142003 0.685690 -0.713889
+vn -0.278542 0.685690 -0.672475
+s 1
+f 1/1/1 2/2/2 4/3/3
+f 3/4/4 4/3/3 6/5/5
+f 5/6/6 6/5/5 8/7/7
+f 7/8/8 8/7/7 10/9/9
+f 9/10/10 10/11/9 12/12/11
+f 11/13/12 12/12/11 14/14/13
+f 13/15/14 14/14/13 16/16/15
+f 15/17/16 16/16/15 18/18/17
+f 17/19/18 18/18/17 20/20/19
+f 19/21/20 20/20/19 22/22/21
+f 21/23/22 22/22/21 24/24/23
+f 23/25/24 24/24/23 26/26/25
+f 25/27/26 26/26/25 28/28/27
+f 27/29/28 28/30/27 30/31/29
+f 29/32/30 30/31/29 32/33/31
+f 31/34/32 32/33/31 34/35/33
+f 33/36/34 34/35/33 35/37/35
+f 35/37/35 36/38/36 37/39/37
+f 37/39/37 38/40/38 39/41/39
+f 39/41/39 40/42/40 41/43/41
+f 41/44/41 42/45/42 43/46/43
+f 43/46/43 44/47/44 45/48/45
+f 45/48/45 46/49/46 47/50/47
+f 47/50/47 48/51/48 49/52/49
+f 49/52/49 50/53/50 51/54/51
+f 51/54/51 52/55/52 53/56/53
+f 53/56/53 54/57/54 55/58/55
+f 55/59/55 56/60/56 57/61/57
+f 57/61/57 58/62/58 59/63/59
+f 59/63/59 60/64/60 61/65/61
+f 4/66/3 2/67/2 6/68/5
+f 63/69/62 64/70/63 1/1/1
+f 61/65/61 62/71/64 63/69/62
+f 3/4/4 1/1/1 4/3/3
+f 5/6/6 3/4/4 6/5/5
+f 7/8/8 5/6/6 8/7/7
+f 9/72/10 7/8/8 10/9/9
+f 11/13/12 9/10/10 12/12/11
+f 13/15/14 11/13/12 14/14/13
+f 15/17/16 13/15/14 16/16/15
+f 17/19/18 15/17/16 18/18/17
+f 19/21/20 17/19/18 20/20/19
+f 21/23/22 19/21/20 22/22/21
+f 23/25/24 21/23/22 24/24/23
+f 25/27/26 23/25/24 26/26/25
+f 27/73/28 25/27/26 28/28/27
+f 29/32/30 27/29/28 30/31/29
+f 31/34/32 29/32/30 32/33/31
+f 33/36/34 31/34/32 34/35/33
+f 34/35/33 36/38/36 35/37/35
+f 36/38/36 38/40/38 37/39/37
+f 38/40/38 40/42/40 39/41/39
+f 40/42/40 42/74/42 41/43/41
+f 42/45/42 44/47/44 43/46/43
+f 44/47/44 46/49/46 45/48/45
+f 46/49/46 48/51/48 47/50/47
+f 48/51/48 50/53/50 49/52/49
+f 50/53/50 52/55/52 51/54/51
+f 52/55/52 54/57/54 53/56/53
+f 54/57/54 56/75/56 55/58/55
+f 56/60/56 58/62/58 57/61/57
+f 58/62/58 60/64/60 59/63/59
+f 60/64/60 62/71/64 61/65/61
+f 2/67/2 64/76/63 6/68/5
+f 64/76/63 62/77/64 6/68/5
+f 62/77/64 60/78/60 6/68/5
+f 60/78/60 58/79/58 6/68/5
+f 58/79/58 56/80/56 6/68/5
+f 56/80/56 54/81/54 6/68/5
+f 54/81/54 52/82/52 6/68/5
+f 52/82/52 50/83/50 6/68/5
+f 50/83/50 48/84/48 6/68/5
+f 48/84/48 46/85/46 6/68/5
+f 46/85/46 44/86/44 6/68/5
+f 44/86/44 42/87/42 6/68/5
+f 42/87/42 40/88/40 6/68/5
+f 40/88/40 38/89/38 6/68/5
+f 38/89/38 36/90/36 6/68/5
+f 36/90/36 34/91/33 6/68/5
+f 34/91/33 32/92/31 6/68/5
+f 32/92/31 30/93/29 6/68/5
+f 30/93/29 28/94/27 6/68/5
+f 28/94/27 26/95/25 6/68/5
+f 26/95/25 24/96/23 6/68/5
+f 24/96/23 22/97/21 6/68/5
+f 22/97/21 20/98/19 6/68/5
+f 20/98/19 18/99/17 6/68/5
+f 18/99/17 16/100/15 6/68/5
+f 16/100/15 14/101/13 6/68/5
+f 14/101/13 12/102/11 6/68/5
+f 12/102/11 10/103/9 8/104/7
+f 6/68/5 12/102/11 8/104/7
+f 64/70/63 2/2/2 1/1/1
+f 62/71/64 64/70/63 63/69/62
diff --git a/examples/datavisualization/graphgallery/data/raindata.txt b/examples/datavisualization/graphgallery/data/raindata.txt
new file mode 100644
index 00000000..d9558921
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/raindata.txt
@@ -0,0 +1,158 @@
+# Rainfall per month from 2010 to 2022 in Northern Finland (Oulu)
+# Format: year, month, rainfall
+2010,1, 0,
+2010,2, 3.4,
+2010,3, 52,
+2010,4, 33.8,
+2010,5, 45.6,
+2010,6, 43.8,
+2010,7, 104.6,
+2010,8, 105.4,
+2010,9, 107.2,
+2010,10,38.6,
+2010,11,17.8,
+2010,12,0,
+2011,1, 8.2,
+2011,2, 1.6,
+2011,3, 27.4,
+2011,4, 15.8,
+2011,5, 57.6,
+2011,6, 85.2,
+2011,7, 127,
+2011,8, 72.2,
+2011,9, 82.2,
+2011,10,62.4,
+2011,11,31.6,
+2011,12,53.8,
+2012,1, 0,
+2012,2, 5,
+2012,3, 32.4,
+2012,4, 57.6,
+2012,5, 71.4,
+2012,6, 60.8,
+2012,7, 109,
+2012,8, 43.6,
+2012,9, 79.4,
+2012,10,117.2,
+2012,11,59,
+2012,12,0.2,
+2013,1, 28,
+2013,2, 19,
+2013,3, 0,
+2013,4, 37.6,
+2013,5, 44.2,
+2013,6, 104.8,
+2013,7, 84.2,
+2013,8, 57.2,
+2013,9, 37.2,
+2013,10,64.6,
+2013,11,77.8,
+2013,12,92.8,
+2014,1, 23.8,
+2014,2, 23.6,
+2014,3, 15.4,
+2014,4, 13.2,
+2014,5, 36.4,
+2014,6, 26.4,
+2014,7, 95.8,
+2014,8, 81.8,
+2014,9, 13.8,
+2014,10,94.6,
+2014,11,44.6,
+2014,12,31,
+2015,1, 37.4,
+2015,2, 21,
+2015,3, 42,
+2015,4, 8.8,
+2015,5, 82.4,
+2015,6, 150,
+2015,7, 56.8,
+2015,8, 67.2,
+2015,9, 131.2,
+2015,10,38.4,
+2015,11,83.4,
+2015,12,47.8,
+2016,1, 12.4,
+2016,2, 34.8,
+2016,3, 29,
+2016,4, 40.4,
+2016,5, 32.4,
+2016,6, 80.2,
+2016,7, 102.6,
+2016,8, 95.6,
+2016,9, 40.2,
+2016,10,7.8,
+2016,11,39.6,
+2016,12,8.8,
+2017,1, 9.4,
+2017,2, 6.6,
+2017,3, 29,
+2017,4, 46.2,
+2017,5, 43.2,
+2017,6, 25.2,
+2017,7, 72.4,
+2017,8, 58.8,
+2017,9, 68.8,
+2017,10,45.8,
+2017,11,36.8,
+2017,12,29.6,
+2018,1, 19.8,
+2018,2, 0.8,
+2018,3, 4,
+2018,4, 23.2,
+2018,5, 13.2,
+2018,6, 62.8,
+2018,7, 33,
+2018,8, 96.6,
+2018,9, 72.6,
+2018,10,48.8,
+2018,11,31.8,
+2018,12,12.8,
+2019,1, 0.2,
+2019,2, 24.8,
+2019,3, 32,
+2019,4, 8.8,
+2019,5, 71.4,
+2019,6, 65.8,
+2019,7, 17.6,
+2019,8, 90,
+2019,9, 50,
+2019,10,77,
+2019,11,27,
+2019,12,43.2,
+2020,1, 28.8,
+2020,2, 45,
+2020,3, 18.6,
+2020,4, 13,
+2020,5, 30.8,
+2020,6, 21.4,
+2020,7, 163.6,
+2020,8, 12,
+2020,9, 102.4,
+2020,10,133.2,
+2020,11,69.8,
+2020,12,40.6,
+2021,1, 0.4,
+2021,2, 21.6,
+2021,3, 24,
+2021,4, 51.4,
+2021,5, 76.4,
+2021,6, 29.2,
+2021,7, 36.4,
+2021,8, 116,
+2021,9, 72.4,
+2021,10,93.4,
+2021,11,21,
+2021,12,10.2,
+2022,1, 8.6,
+2022,2, 6.6,
+2022,3, 5.2,
+2022,4, 15.2,
+2022,5, 37.6,
+2022,6, 45,
+2022,7, 67.4,
+2022,8, 161.6,
+2022,9, 22.8,
+2022,10,75.2,
+2022,11,21.8,
+2022,12,0.2
diff --git a/examples/datavisualization/graphgallery/data/refinery.obj b/examples/datavisualization/graphgallery/data/refinery.obj
new file mode 100644
index 00000000..ed90c361
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/refinery.obj
@@ -0,0 +1,2330 @@
+# Blender v2.66 (sub 0) OBJ File: 'oilrefinery.blend'
+# www.blender.org
+v -2.719012 -0.196783 4.805554
+v -2.719012 -0.196783 -4.824533
+v 2.730989 -0.196783 -4.824533
+v 2.730989 -0.196783 4.805554
+v -2.719012 0.012961 4.805554
+v -2.719012 0.012961 -4.824533
+v 2.730989 0.012961 -4.824533
+v 2.730989 0.012961 4.805554
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 0.000000 1.000000
+vt 1.000000 1.000000
+vn -0.577349 0.577349 0.577349
+vn -0.577349 0.577349 -0.577349
+vn -0.577349 -0.577349 0.577349
+vn 0.577349 0.577349 -0.577349
+vn 0.577349 -0.577349 -0.577349
+vn 0.577349 0.577349 0.577349
+vn 0.577349 -0.577349 0.577349
+vn -0.577349 -0.577349 -0.577349
+s 1
+f 5/1/1 6/2/2 1/3/3
+f 6/1/2 7/2/4 3/4/5
+f 7/1/4 8/2/6 4/4/7
+f 8/1/6 5/2/1 1/4/3
+f 1/1/3 2/2/8 3/4/5
+f 8/1/6 7/2/4 6/4/2
+f 6/2/2 2/4/8 1/3/3
+f 2/3/8 6/1/2 3/4/5
+f 3/3/5 7/1/4 4/4/7
+f 4/3/7 8/1/6 1/4/3
+f 4/3/7 1/1/3 3/4/5
+f 5/3/1 8/1/6 6/4/2
+v -1.384247 1.252743 0.422195
+v -1.384247 2.069450 0.422195
+v -1.303725 1.252743 0.430041
+v -1.303725 2.069450 0.430041
+v -1.226298 1.252743 0.453279
+v -1.226298 2.069450 0.453279
+v -1.154941 1.252743 0.491015
+v -1.154941 2.069450 0.491015
+v -1.092396 1.252743 0.541799
+v -1.092396 2.069450 0.541799
+v -1.041066 1.252743 0.603679
+v -1.041066 2.069450 0.603679
+v -1.002925 1.252743 0.674278
+v -1.002925 2.069450 0.674278
+v -0.979437 1.252743 0.750883
+v -0.979437 2.069450 0.750883
+v -0.971507 1.252743 0.830548
+v -0.971507 2.069450 0.830548
+v -0.979437 1.252743 0.910214
+v -0.979437 2.069450 0.910214
+v -1.002925 1.252743 0.986818
+v -1.002925 2.069450 0.986818
+v -1.041066 1.252743 1.057417
+v -1.041066 2.069450 1.057417
+v -1.092396 1.252743 1.119298
+v -1.092396 2.069450 1.119298
+v -1.154941 1.252743 1.170082
+v -1.154941 2.069450 1.170082
+v -1.226298 1.252743 1.207818
+v -1.226298 2.069450 1.207818
+v -1.303726 1.252743 1.231055
+v -1.303726 2.069450 1.231055
+v -1.384247 1.252743 1.238902
+v -1.384247 2.069450 1.238902
+v -1.464769 1.252743 1.231055
+v -1.464769 2.069450 1.231055
+v -1.542196 1.252743 1.207818
+v -1.542196 2.069450 1.207818
+v -1.613554 1.252743 1.170082
+v -1.613554 2.069450 1.170082
+v -1.676099 1.252743 1.119298
+v -1.676099 2.069450 1.119298
+v -1.727429 1.252743 1.057417
+v -1.727429 2.069450 1.057417
+v -1.765570 1.252743 0.986818
+v -1.765570 2.069450 0.986818
+v -1.789057 1.252743 0.910214
+v -1.789057 2.069450 0.910214
+v -1.796988 1.252743 0.830548
+v -1.796988 2.069450 0.830548
+v -1.789057 1.252743 0.750882
+v -1.789057 2.069450 0.750882
+v -1.765570 1.252743 0.674278
+v -1.765570 2.069450 0.674278
+v -1.727428 1.252743 0.603679
+v -1.727428 2.069450 0.603679
+v -1.676098 1.252743 0.541798
+v -1.676098 2.069450 0.541798
+v -1.613553 1.252743 0.491015
+v -1.613553 2.069450 0.491015
+v -1.542196 1.252743 0.453279
+v -1.542196 2.069450 0.453279
+v -1.464768 1.252743 0.430041
+v -1.464768 2.069450 0.430041
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn 0.096985 0.000000 -0.995286
+vn 0.287455 0.000000 -0.957794
+vn 0.467486 0.000000 -0.884001
+vn 0.630338 0.000000 -0.776321
+vn 0.769672 0.000000 -0.638440
+vn 0.879812 0.000000 -0.475321
+vn 0.956070 0.000000 -0.293137
+vn 0.995081 0.000000 -0.099061
+vn 0.995081 0.000000 0.099061
+vn 0.956070 0.000000 0.293137
+vn 0.879813 0.000000 0.475321
+vn 0.769672 0.000000 0.638440
+vn 0.630338 0.000000 0.776321
+vn 0.467486 0.000000 0.884001
+vn 0.287455 0.000000 0.957794
+vn 0.096986 0.000000 0.995286
+vn -0.096986 0.000000 0.995286
+vn -0.287456 0.000000 0.957794
+vn -0.467486 0.000000 0.884001
+vn -0.630338 0.000000 0.776321
+vn -0.769673 0.000000 0.638438
+vn -0.879812 0.000000 0.475322
+vn -0.956071 0.000000 0.293135
+vn -0.995081 0.000000 0.099059
+vn -0.995081 -0.000000 -0.099061
+vn -0.956070 -0.000000 -0.293138
+vn -0.879812 -0.000000 -0.475322
+vn -0.769671 -0.000000 -0.638441
+vn -0.630337 -0.000000 -0.776322
+vn -0.467484 -0.000000 -0.884001
+vn -0.000000 1.000000 0.000000
+vn -0.096985 -0.000000 -0.995286
+vn -0.287454 -0.000000 -0.957794
+vn 0.000000 -1.000000 -0.000000
+s off
+f 9/5/9 10/6/9 12/7/9
+f 11/5/10 12/6/10 14/7/10
+f 13/5/11 14/6/11 16/7/11
+f 15/5/12 16/6/12 18/7/12
+f 17/5/13 18/6/13 20/7/13
+f 19/5/14 20/6/14 22/7/14
+f 21/5/15 22/6/15 24/7/15
+f 23/5/16 24/6/16 26/7/16
+f 25/5/17 26/6/17 28/7/17
+f 27/5/18 28/6/18 30/7/18
+f 29/5/19 30/6/19 32/7/19
+f 31/5/20 32/6/20 34/7/20
+f 33/5/21 34/6/21 36/7/21
+f 35/5/22 36/6/22 38/7/22
+f 37/5/23 38/6/23 40/7/23
+f 39/5/24 40/6/24 42/7/24
+f 41/5/25 42/6/25 43/8/25
+f 43/5/26 44/6/26 45/8/26
+f 45/5/27 46/6/27 47/8/27
+f 47/5/28 48/6/28 49/8/28
+f 49/5/29 50/6/29 51/8/29
+f 51/5/30 52/6/30 53/8/30
+f 53/5/31 54/6/31 55/8/31
+f 55/5/32 56/6/32 57/8/32
+f 57/5/33 58/6/33 59/8/33
+f 59/5/34 60/6/34 61/8/34
+f 61/5/35 62/6/35 63/8/35
+f 63/5/36 64/6/36 65/8/36
+f 65/5/37 66/6/37 67/8/37
+f 67/5/38 68/6/38 69/8/38
+f 12/9/39 10/10/39 14/11/39
+f 71/5/40 72/6/40 9/8/40
+f 69/5/41 70/6/41 71/8/41
+f 9/9/42 11/10/42 71/11/42
+f 11/8/9 9/5/9 12/7/9
+f 13/8/10 11/5/10 14/7/10
+f 15/8/11 13/5/11 16/7/11
+f 17/8/12 15/5/12 18/7/12
+f 19/8/13 17/5/13 20/7/13
+f 21/8/14 19/5/14 22/7/14
+f 23/8/15 21/5/15 24/7/15
+f 25/8/16 23/5/16 26/7/16
+f 27/8/17 25/5/17 28/7/17
+f 29/8/18 27/5/18 30/7/18
+f 31/8/19 29/5/19 32/7/19
+f 33/8/20 31/5/20 34/7/20
+f 35/8/21 33/5/21 36/7/21
+f 37/8/22 35/5/22 38/7/22
+f 39/8/23 37/5/23 40/7/23
+f 41/8/24 39/5/24 42/7/24
+f 42/6/25 44/7/25 43/8/25
+f 44/6/26 46/7/26 45/8/26
+f 46/6/27 48/7/27 47/8/27
+f 48/6/28 50/7/28 49/8/28
+f 50/6/29 52/7/29 51/8/29
+f 52/6/30 54/7/30 53/8/30
+f 54/6/31 56/7/31 55/8/31
+f 56/6/32 58/7/32 57/8/32
+f 58/6/33 60/7/33 59/8/33
+f 60/6/34 62/7/34 61/8/34
+f 62/6/35 64/7/35 63/8/35
+f 64/6/36 66/7/36 65/8/36
+f 66/6/37 68/7/37 67/8/37
+f 68/6/38 70/7/38 69/8/38
+f 10/10/39 72/12/39 14/11/39
+f 72/12/39 70/13/39 14/11/39
+f 70/13/39 68/14/39 14/11/39
+f 68/14/39 66/15/39 14/11/39
+f 66/15/39 64/16/39 14/11/39
+f 64/16/39 62/17/39 14/11/39
+f 62/17/39 60/18/39 14/11/39
+f 60/18/39 58/19/39 14/11/39
+f 58/19/39 56/20/39 14/11/39
+f 56/20/39 54/21/39 14/11/39
+f 54/21/39 52/22/39 14/11/39
+f 52/22/39 50/23/39 14/11/39
+f 50/23/39 48/24/39 14/11/39
+f 48/24/39 46/25/39 14/11/39
+f 46/25/39 44/26/39 14/11/39
+f 44/26/39 42/27/39 14/11/39
+f 42/27/39 40/28/39 14/11/39
+f 40/28/39 38/29/39 14/11/39
+f 38/29/39 36/30/39 14/11/39
+f 36/30/39 34/31/39 14/11/39
+f 34/31/39 32/32/39 14/11/39
+f 32/32/39 30/33/39 14/11/39
+f 30/33/39 28/34/39 14/11/39
+f 28/34/39 26/35/39 14/11/39
+f 26/35/39 24/36/39 14/11/39
+f 24/36/39 22/37/39 14/11/39
+f 22/37/39 20/38/39 14/11/39
+f 20/38/39 18/39/39 16/40/39
+f 14/11/39 20/38/39 16/40/39
+f 72/6/40 10/7/40 9/8/40
+f 70/6/41 72/7/41 71/8/41
+f 11/10/42 13/12/42 71/11/42
+f 13/12/42 15/13/42 71/11/42
+f 15/13/42 17/14/42 71/11/42
+f 17/14/42 19/15/42 71/11/42
+f 19/15/42 21/16/42 71/11/42
+f 21/16/42 23/17/42 71/11/42
+f 23/17/42 25/18/42 71/11/42
+f 25/18/42 27/19/42 71/11/42
+f 27/19/42 29/20/42 71/11/42
+f 29/20/42 31/21/42 71/11/42
+f 31/21/42 33/22/42 71/11/42
+f 33/22/42 35/23/42 71/11/42
+f 35/23/42 37/24/42 71/11/42
+f 37/24/42 39/25/42 71/11/42
+f 39/25/42 41/26/42 71/11/42
+f 41/26/42 43/27/42 71/11/42
+f 43/27/42 45/28/42 71/11/42
+f 45/28/42 47/29/42 71/11/42
+f 47/29/42 49/30/42 71/11/42
+f 49/30/42 51/31/42 71/11/42
+f 51/31/42 53/32/42 71/11/42
+f 53/32/42 55/33/42 71/11/42
+f 55/33/42 57/34/42 71/11/42
+f 57/34/42 59/35/42 71/11/42
+f 59/35/42 61/36/42 71/11/42
+f 61/36/42 63/37/42 71/11/42
+f 63/37/42 65/38/42 71/11/42
+f 65/38/42 67/39/42 71/11/42
+f 67/39/42 69/40/42 71/11/42
+v 1.365790 1.252743 0.402799
+v 1.365790 2.069450 0.402799
+v 1.446312 1.252743 0.410646
+v 1.446312 2.069450 0.410646
+v 1.523739 1.252743 0.433883
+v 1.523739 2.069450 0.433883
+v 1.595097 1.252743 0.471619
+v 1.595097 2.069450 0.471619
+v 1.657642 1.252743 0.522403
+v 1.657642 2.069450 0.522403
+v 1.708972 1.252743 0.584284
+v 1.708972 2.069450 0.584284
+v 1.747113 1.252743 0.654883
+v 1.747113 2.069450 0.654883
+v 1.770600 1.252743 0.731487
+v 1.770600 2.069450 0.731487
+v 1.778531 1.252743 0.811153
+v 1.778531 2.069450 0.811153
+v 1.770600 1.252743 0.890818
+v 1.770600 2.069450 0.890818
+v 1.747113 1.252743 0.967423
+v 1.747113 2.069450 0.967423
+v 1.708972 1.252743 1.038022
+v 1.708972 2.069450 1.038022
+v 1.657642 1.252743 1.099902
+v 1.657642 2.069450 1.099902
+v 1.595097 1.252743 1.150686
+v 1.595097 2.069450 1.150686
+v 1.523739 1.252743 1.188422
+v 1.523739 2.069450 1.188422
+v 1.446312 1.252743 1.211660
+v 1.446312 2.069450 1.211660
+v 1.365790 1.252743 1.219506
+v 1.365790 2.069450 1.219506
+v 1.285269 1.252743 1.211660
+v 1.285269 2.069450 1.211660
+v 1.207841 1.252743 1.188422
+v 1.207841 2.069450 1.188422
+v 1.136484 1.252743 1.150686
+v 1.136484 2.069450 1.150686
+v 1.073939 1.252743 1.099902
+v 1.073939 2.069450 1.099902
+v 1.022609 1.252743 1.038021
+v 1.022609 2.069450 1.038021
+v 0.984468 1.252743 0.967422
+v 0.984468 2.069450 0.967422
+v 0.960981 1.252743 0.890818
+v 0.960981 2.069450 0.890818
+v 0.953050 1.252743 0.811152
+v 0.953050 2.069450 0.811152
+v 0.960981 1.252743 0.731486
+v 0.960981 2.069450 0.731486
+v 0.984468 1.252743 0.654882
+v 0.984468 2.069450 0.654882
+v 1.022609 1.252743 0.584283
+v 1.022609 2.069450 0.584283
+v 1.073939 1.252743 0.522403
+v 1.073939 2.069450 0.522403
+v 1.136485 1.252743 0.471619
+v 1.136485 2.069450 0.471619
+v 1.207842 1.252743 0.433883
+v 1.207842 2.069450 0.433883
+v 1.285269 1.252743 0.410646
+v 1.285269 2.069450 0.410646
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn -0.879812 0.000000 0.475321
+vn -0.956071 0.000000 0.293136
+vn -0.956070 -0.000000 -0.293137
+s off
+f 73/41/9 74/42/9 76/43/9
+f 75/41/10 76/42/10 78/43/10
+f 77/41/11 78/42/11 80/43/11
+f 79/41/12 80/42/12 82/43/12
+f 81/41/13 82/42/13 84/43/13
+f 83/41/14 84/42/14 86/43/14
+f 85/41/15 86/42/15 88/43/15
+f 87/41/16 88/42/16 90/43/16
+f 89/41/17 90/42/17 92/43/17
+f 91/41/18 92/42/18 94/43/18
+f 93/41/19 94/42/19 96/43/19
+f 95/41/20 96/42/20 98/43/20
+f 97/41/21 98/42/21 100/43/21
+f 99/41/22 100/42/22 102/43/22
+f 101/41/23 102/42/23 104/43/23
+f 103/41/24 104/42/24 106/43/24
+f 105/41/25 106/42/25 107/44/25
+f 107/41/26 108/42/26 109/44/26
+f 109/41/27 110/42/27 111/44/27
+f 111/41/28 112/42/28 113/44/28
+f 113/41/29 114/42/29 115/44/29
+f 115/41/43 116/42/43 117/44/43
+f 117/41/44 118/42/44 119/44/44
+f 119/41/32 120/42/32 121/44/32
+f 121/41/33 122/42/33 123/44/33
+f 123/41/45 124/42/45 125/44/45
+f 125/41/35 126/42/35 127/44/35
+f 127/41/36 128/42/36 129/44/36
+f 129/41/37 130/42/37 131/44/37
+f 131/41/38 132/42/38 133/44/38
+f 76/45/39 74/46/39 78/47/39
+f 135/41/40 136/42/40 73/44/40
+f 133/41/41 134/42/41 135/44/41
+f 73/45/42 75/46/42 135/47/42
+f 75/44/9 73/41/9 76/43/9
+f 77/44/10 75/41/10 78/43/10
+f 79/44/11 77/41/11 80/43/11
+f 81/44/12 79/41/12 82/43/12
+f 83/44/13 81/41/13 84/43/13
+f 85/44/14 83/41/14 86/43/14
+f 87/44/15 85/41/15 88/43/15
+f 89/44/16 87/41/16 90/43/16
+f 91/44/17 89/41/17 92/43/17
+f 93/44/18 91/41/18 94/43/18
+f 95/44/19 93/41/19 96/43/19
+f 97/44/20 95/41/20 98/43/20
+f 99/44/21 97/41/21 100/43/21
+f 101/44/22 99/41/22 102/43/22
+f 103/44/23 101/41/23 104/43/23
+f 105/44/24 103/41/24 106/43/24
+f 106/42/25 108/43/25 107/44/25
+f 108/42/26 110/43/26 109/44/26
+f 110/42/27 112/43/27 111/44/27
+f 112/42/28 114/43/28 113/44/28
+f 114/42/29 116/43/29 115/44/29
+f 116/42/43 118/43/43 117/44/43
+f 118/42/44 120/43/44 119/44/44
+f 120/42/32 122/43/32 121/44/32
+f 122/42/33 124/43/33 123/44/33
+f 124/42/45 126/43/45 125/44/45
+f 126/42/35 128/43/35 127/44/35
+f 128/42/36 130/43/36 129/44/36
+f 130/42/37 132/43/37 131/44/37
+f 132/42/38 134/43/38 133/44/38
+f 74/46/39 136/48/39 78/47/39
+f 136/48/39 134/49/39 78/47/39
+f 134/49/39 132/50/39 78/47/39
+f 132/50/39 130/51/39 78/47/39
+f 130/51/39 128/52/39 78/47/39
+f 128/52/39 126/53/39 78/47/39
+f 126/53/39 124/54/39 78/47/39
+f 124/54/39 122/55/39 78/47/39
+f 122/55/39 120/56/39 78/47/39
+f 120/56/39 118/57/39 78/47/39
+f 118/57/39 116/58/39 78/47/39
+f 116/58/39 114/59/39 78/47/39
+f 114/59/39 112/60/39 78/47/39
+f 112/60/39 110/61/39 78/47/39
+f 110/61/39 108/62/39 78/47/39
+f 108/62/39 106/63/39 78/47/39
+f 106/63/39 104/64/39 78/47/39
+f 104/64/39 102/65/39 78/47/39
+f 102/65/39 100/66/39 78/47/39
+f 100/66/39 98/67/39 78/47/39
+f 98/67/39 96/68/39 78/47/39
+f 96/68/39 94/69/39 78/47/39
+f 94/69/39 92/70/39 78/47/39
+f 92/70/39 90/71/39 78/47/39
+f 90/71/39 88/72/39 78/47/39
+f 88/72/39 86/73/39 78/47/39
+f 86/73/39 84/74/39 78/47/39
+f 84/74/39 82/75/39 80/76/39
+f 78/47/39 84/74/39 80/76/39
+f 136/42/40 74/43/40 73/44/40
+f 134/42/41 136/43/41 135/44/41
+f 75/46/42 77/48/42 135/47/42
+f 77/48/42 79/49/42 135/47/42
+f 79/49/42 81/50/42 135/47/42
+f 81/50/42 83/51/42 135/47/42
+f 83/51/42 85/52/42 135/47/42
+f 85/52/42 87/53/42 135/47/42
+f 87/53/42 89/54/42 135/47/42
+f 89/54/42 91/55/42 135/47/42
+f 91/55/42 93/56/42 135/47/42
+f 93/56/42 95/57/42 135/47/42
+f 95/57/42 97/58/42 135/47/42
+f 97/58/42 99/59/42 135/47/42
+f 99/59/42 101/60/42 135/47/42
+f 101/60/42 103/61/42 135/47/42
+f 103/61/42 105/62/42 135/47/42
+f 105/62/42 107/63/42 135/47/42
+f 107/63/42 109/64/42 135/47/42
+f 109/64/42 111/65/42 135/47/42
+f 111/65/42 113/66/42 135/47/42
+f 113/66/42 115/67/42 135/47/42
+f 115/67/42 117/68/42 135/47/42
+f 117/68/42 119/69/42 135/47/42
+f 119/69/42 121/70/42 135/47/42
+f 121/70/42 123/71/42 135/47/42
+f 123/71/42 125/72/42 135/47/42
+f 125/72/42 127/73/42 135/47/42
+f 127/73/42 129/74/42 135/47/42
+f 129/74/42 131/75/42 135/47/42
+f 131/75/42 133/76/42 135/47/42
+v -2.345663 0.025178 -0.194338
+v -2.345663 0.025178 -0.594338
+v -1.345663 0.025178 -0.594338
+v -1.345663 0.025178 -0.194338
+v -2.345663 1.525178 -0.194338
+v -2.345663 1.525178 -0.594338
+v -1.345663 1.525178 -0.594338
+v -1.345663 1.525178 -0.194338
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 0.000000 1.000000
+vt 1.000000 1.000000
+vn -1.000000 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 0.000000 1.000000
+s off
+f 141/77/46 142/78/46 137/79/46
+f 142/77/47 143/78/47 138/79/47
+f 143/77/48 144/78/48 140/80/48
+f 144/77/49 141/78/49 137/80/49
+f 137/77/42 138/78/42 139/80/42
+f 144/77/39 143/78/39 142/80/39
+f 142/78/46 138/80/46 137/79/46
+f 143/78/47 139/80/47 138/79/47
+f 139/79/48 143/77/48 140/80/48
+f 140/79/49 144/77/49 137/80/49
+f 140/79/42 137/77/42 139/80/42
+f 141/79/39 144/77/39 142/80/39
+v 1.364119 0.019809 -0.205019
+v 1.364119 0.019809 -0.605019
+v 2.364120 0.019809 -0.605019
+v 2.364120 0.019809 -0.205019
+v 1.364119 1.419809 -0.205019
+v 1.364119 1.419809 -0.605019
+v 2.364120 1.419809 -0.605019
+v 2.364120 1.419809 -0.205019
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 0.000000 1.000000
+vt 1.000000 1.000000
+s off
+f 149/81/46 150/82/46 145/83/46
+f 150/81/47 151/82/47 146/83/47
+f 151/81/48 152/82/48 148/84/48
+f 152/81/49 149/82/49 145/84/49
+f 145/81/42 146/82/42 147/84/42
+f 152/81/39 151/82/39 150/84/39
+f 150/82/46 146/84/46 145/83/46
+f 151/82/47 147/84/47 146/83/47
+f 147/83/48 151/81/48 148/84/48
+f 148/83/49 152/81/49 145/84/49
+f 148/83/42 145/81/42 147/84/42
+f 149/83/39 152/81/39 150/84/39
+v -1.384247 0.015116 3.993316
+v -1.384247 0.015113 -0.006684
+v -1.189157 0.034331 3.993316
+v -1.189157 0.034328 -0.006684
+v -1.001564 0.091236 3.993316
+v -1.001564 0.091234 -0.006684
+v -0.828677 0.183646 3.993316
+v -0.828677 0.183644 -0.006684
+v -0.677140 0.308009 3.993316
+v -0.677140 0.308007 -0.006684
+v -0.552777 0.459546 3.993316
+v -0.552777 0.459543 -0.006684
+v -0.460368 0.632432 3.993316
+v -0.460368 0.632430 -0.006684
+v -0.403462 0.820025 3.993316
+v -0.403462 0.820023 -0.006684
+v -0.384247 1.015116 3.993316
+v -0.384247 1.015113 -0.006684
+v -0.403462 1.210206 3.993316
+v -0.403462 1.210203 -0.006685
+v -0.460368 1.397799 3.993315
+v -0.460368 1.397797 -0.006685
+v -0.552777 1.570686 3.993315
+v -0.552777 1.570683 -0.006685
+v -0.677140 1.722223 3.993315
+v -0.677140 1.722220 -0.006685
+v -0.828677 1.846586 3.993315
+v -0.828677 1.846583 -0.006685
+v -1.001564 1.938995 3.993315
+v -1.001564 1.938993 -0.006685
+v -1.189157 1.995901 3.993315
+v -1.189157 1.995899 -0.006685
+v -1.384247 2.015116 3.993315
+v -1.384247 2.015113 -0.006685
+v -1.579338 1.995901 3.993315
+v -1.579338 1.995898 -0.006685
+v -1.766931 1.938995 3.993315
+v -1.766931 1.938993 -0.006685
+v -1.939818 1.846585 3.993315
+v -1.939818 1.846583 -0.006685
+v -2.091354 1.722222 3.993315
+v -2.091354 1.722220 -0.006685
+v -2.215717 1.570685 3.993315
+v -2.215717 1.570683 -0.006685
+v -2.308127 1.397799 3.993315
+v -2.308127 1.397796 -0.006685
+v -2.365032 1.210205 3.993316
+v -2.365032 1.210203 -0.006685
+v -2.384247 1.015115 3.993316
+v -2.384247 1.015112 -0.006684
+v -2.365032 0.820024 3.993316
+v -2.365032 0.820022 -0.006684
+v -2.308126 0.632431 3.993316
+v -2.308126 0.632429 -0.006684
+v -2.215716 0.459545 3.993316
+v -2.215716 0.459542 -0.006684
+v -2.091353 0.308008 3.993316
+v -2.091353 0.308006 -0.006684
+v -1.939816 0.183645 3.993316
+v -1.939816 0.183643 -0.006684
+v -1.766929 0.091236 3.993316
+v -1.766929 0.091233 -0.006684
+v -1.579336 0.034330 3.993316
+v -1.579336 0.034328 -0.006684
+v -1.384247 0.619839 -0.156215
+v -1.307133 0.627434 -0.156215
+v -1.232982 0.649928 -0.156215
+v -1.164645 0.686455 -0.156215
+v -1.104746 0.735612 -0.156215
+v -1.055589 0.795511 -0.156215
+v -1.019062 0.863848 -0.156216
+v -0.996568 0.937999 -0.156216
+v -0.988973 1.015113 -0.156216
+v -0.996568 1.092227 -0.156216
+v -1.019062 1.166378 -0.156216
+v -1.055589 1.234715 -0.156216
+v -1.104746 1.294614 -0.156216
+v -1.164645 1.343771 -0.156216
+v -1.232982 1.380298 -0.156216
+v -1.307133 1.402792 -0.156216
+v -1.384247 1.410387 -0.156216
+v -1.461361 1.402792 -0.156216
+v -1.535512 1.380298 -0.156216
+v -1.603849 1.343771 -0.156216
+v -1.663748 1.294613 -0.156216
+v -1.712905 1.234715 -0.156216
+v -1.749432 1.166377 -0.156216
+v -1.771926 1.092227 -0.156216
+v -1.779521 1.015113 -0.156216
+v -1.771925 0.937999 -0.156216
+v -1.749432 0.863848 -0.156216
+v -1.712905 0.795510 -0.156215
+v -1.663747 0.735612 -0.156215
+v -1.603849 0.686455 -0.156215
+v -1.535511 0.649928 -0.156215
+v -1.461360 0.627434 -0.156215
+v -1.384247 0.605419 4.159918
+v -1.304319 0.613291 4.159918
+v -1.227463 0.636605 4.159918
+v -1.156632 0.674465 4.159918
+v -1.094548 0.725416 4.159918
+v -1.043596 0.787500 4.159918
+v -1.005736 0.858332 4.159918
+v -0.982422 0.935188 4.159918
+v -0.974550 1.015116 4.159918
+v -0.982422 1.095044 4.159918
+v -1.005736 1.171900 4.159918
+v -1.043596 1.242731 4.159918
+v -1.094548 1.304815 4.159918
+v -1.156632 1.355766 4.159918
+v -1.227463 1.393626 4.159918
+v -1.304319 1.416940 4.159918
+v -1.384247 1.424813 4.159918
+v -1.464175 1.416940 4.159918
+v -1.541031 1.393626 4.159918
+v -1.611863 1.355766 4.159918
+v -1.673947 1.304815 4.159918
+v -1.724898 1.242731 4.159918
+v -1.762758 1.171900 4.159918
+v -1.786072 1.095043 4.159918
+v -1.793944 1.015115 4.159918
+v -1.786072 0.935187 4.159918
+v -1.762757 0.858331 4.159918
+v -1.724897 0.787500 4.159918
+v -1.673946 0.725416 4.159918
+v -1.611862 0.674465 4.159918
+v -1.541031 0.636605 4.159918
+v -1.464174 0.613291 4.159918
+v 0.006492 3.927105 -3.525056
+v 0.006492 4.374522 -3.525055
+v 0.050135 3.927105 -3.520757
+v 0.050135 4.374522 -3.520757
+v 0.092102 3.927104 -3.508027
+v 0.092102 4.374522 -3.508027
+v 0.130778 3.927104 -3.487354
+v 0.130778 4.374522 -3.487354
+v 0.164678 3.927104 -3.459533
+v 0.164678 4.374522 -3.459533
+v 0.192499 3.927104 -3.425632
+v 0.192499 4.374522 -3.425633
+v 0.213172 3.927105 -3.386956
+v 0.213172 4.374522 -3.386957
+v 0.225902 3.927105 -3.344990
+v 0.225902 4.374522 -3.344990
+v 0.230201 3.927105 -3.301347
+v 0.230201 4.374522 -3.301347
+v 0.225902 3.927105 -3.257704
+v 0.225902 4.374522 -3.257703
+v 0.213172 3.927105 -3.215737
+v 0.213172 4.374522 -3.215738
+v 0.192499 3.927105 -3.177061
+v 0.192499 4.374522 -3.177062
+v 0.164678 3.927105 -3.143161
+v 0.164678 4.374522 -3.143161
+v 0.130778 3.927105 -3.115340
+v 0.130778 4.374522 -3.115340
+v 0.092102 3.927105 -3.094666
+v 0.092102 4.374522 -3.094667
+v 0.050135 3.927105 -3.081937
+v 0.050135 4.374522 -3.081936
+v 0.006492 3.927105 -3.077638
+v 0.006492 4.374522 -3.077638
+v -0.037151 3.927105 -3.081937
+v -0.037151 4.374522 -3.081936
+v -0.079118 3.927105 -3.094666
+v -0.079118 4.374522 -3.094667
+v -0.117794 3.927105 -3.115340
+v -0.117794 4.374522 -3.115340
+v -0.151694 3.927105 -3.143161
+v -0.151694 4.374522 -3.143161
+v -0.179515 3.927105 -3.177061
+v -0.179515 4.374522 -3.177062
+v -0.200188 3.927105 -3.215737
+v -0.200188 4.374522 -3.215738
+v -0.212918 3.927105 -3.257704
+v -0.212918 4.374522 -3.257704
+v -0.217217 3.927105 -3.301347
+v -0.217217 4.374522 -3.301347
+v -0.212918 3.927105 -3.344991
+v -0.212918 4.374522 -3.344990
+v -0.200188 3.927105 -3.386957
+v -0.200188 4.374522 -3.386957
+v -0.179515 3.927104 -3.425633
+v -0.179515 4.374522 -3.425633
+v -0.151694 3.927104 -3.459533
+v -0.151694 4.374522 -3.459533
+v -0.117794 3.927104 -3.487354
+v -0.117794 4.374522 -3.487354
+v -0.079117 3.927104 -3.508027
+v -0.079117 4.374522 -3.508027
+v -0.037151 3.927105 -3.520757
+v -0.037151 4.374522 -3.520757
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.853553 0.853553
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.500000 0.000000
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.777785 0.084265
+vt 0.853553 0.146447
+vt 0.084265 0.222215
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.038060 0.308659
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vt 0.146447 0.853554
+vt 0.990393 0.597545
+vt 0.084266 0.777786
+vt 0.038060 0.691342
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.009607 0.597546
+vt 0.000000 0.500000
+vt 0.915735 0.222215
+vt 0.009607 0.402455
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vn 0.098018 -0.995185 0.000001
+vn 0.290285 -0.956940 0.000001
+vn 0.471397 -0.881921 0.000001
+vn 0.634393 -0.773010 0.000000
+vn 0.773010 -0.634393 0.000000
+vn 0.881921 -0.471397 0.000000
+vn 0.956940 -0.290285 0.000000
+vn 0.995185 -0.098017 0.000000
+vn 0.995185 0.098017 -0.000000
+vn 0.956940 0.290285 -0.000000
+vn 0.881922 0.471396 -0.000000
+vn 0.773010 0.634393 -0.000000
+vn 0.634393 0.773011 -0.000000
+vn 0.471397 0.881921 -0.000001
+vn 0.290284 0.956941 -0.000001
+vn 0.098017 0.995185 -0.000001
+vn -0.098017 0.995185 -0.000001
+vn -0.290285 0.956940 -0.000001
+vn -0.471397 0.881921 -0.000001
+vn -0.634394 0.773010 -0.000000
+vn -0.773011 0.634393 -0.000000
+vn -0.881922 0.471396 -0.000000
+vn -0.956941 0.290283 -0.000000
+vn -0.995185 0.098017 -0.000000
+vn -0.995185 -0.098018 0.000000
+vn -0.956940 -0.290286 0.000000
+vn -0.881920 -0.471398 0.000000
+vn -0.773010 -0.634394 0.000000
+vn -0.634393 -0.773011 0.000000
+vn -0.471395 -0.881922 0.000001
+vn -0.239975 -0.023636 -0.970491
+vn -0.098017 -0.995185 0.000001
+vn -0.290283 -0.956941 0.000001
+vn -0.210907 0.173086 0.962060
+vn 0.152975 0.186400 -0.970492
+vn -0.023635 -0.239975 -0.970491
+vn -0.152975 0.186400 -0.970492
+vn 0.239975 -0.023636 -0.970491
+vn -0.212662 -0.113672 -0.970491
+vn 0.069999 0.230752 -0.970492
+vn 0.113670 -0.212663 -0.970491
+vn -0.212662 0.113670 -0.970492
+vn 0.230752 0.069998 -0.970492
+vn -0.152975 -0.186401 -0.970491
+vn -0.023636 0.239974 -0.970492
+vn 0.186400 -0.152976 -0.970491
+vn -0.239974 0.023634 -0.970491
+vn 0.186401 0.152974 -0.970491
+vn -0.069998 -0.230753 -0.970491
+vn -0.113670 0.212662 -0.970492
+vn 0.230753 -0.069999 -0.970491
+vn -0.230752 -0.069999 -0.970491
+vn 0.113670 0.212662 -0.970491
+vn 0.069998 -0.230753 -0.970491
+vn -0.186401 0.152974 -0.970491
+vn 0.239975 0.023634 -0.970492
+vn -0.186400 -0.152976 -0.970491
+vn 0.023635 0.239974 -0.970492
+vn 0.152975 -0.186401 -0.970491
+vn -0.230752 0.069998 -0.970492
+vn 0.023636 -0.239975 -0.970491
+vn 0.212662 0.113670 -0.970492
+vn -0.113670 -0.212664 -0.970491
+vn -0.069999 0.230751 -0.970492
+vn 0.212663 -0.113671 -0.970491
+vn 0.271524 0.026743 0.962060
+vn -0.210906 -0.173085 0.962060
+vn 0.026743 0.271524 0.962060
+vn 0.173086 -0.210906 0.962060
+vn -0.261089 0.079201 0.962060
+vn 0.026743 -0.271523 0.962060
+vn 0.240621 0.128616 0.962060
+vn -0.128614 -0.240621 0.962060
+vn -0.079201 0.261090 0.962060
+vn 0.240621 -0.128614 0.962060
+vn -0.271524 -0.026742 0.962060
+vn 0.173087 0.210907 0.962060
+vn -0.026742 -0.271523 0.962060
+vn -0.173087 0.210907 0.962060
+vn 0.271524 -0.026742 0.962060
+vn -0.240621 -0.128615 0.962060
+vn 0.079201 0.261090 0.962060
+vn 0.128614 -0.240621 0.962060
+vn -0.240621 0.128616 0.962060
+vn 0.261089 0.079202 0.962060
+vn -0.173086 -0.210906 0.962060
+vn -0.026743 0.271524 0.962060
+vn 0.210907 -0.173085 0.962060
+vn -0.271524 0.026743 0.962060
+vn 0.210907 0.173087 0.962060
+vn -0.079201 -0.261088 0.962060
+vn -0.128615 0.240622 0.962060
+vn 0.261089 -0.079200 0.962060
+vn -0.261089 -0.079201 0.962060
+vn 0.128615 0.240622 0.962060
+vn 0.079201 -0.261088 0.962060
+vn 0.098012 0.000001 -0.995185
+vn 0.290289 -0.000001 -0.956939
+vn 0.471395 0.000001 -0.881922
+vn 0.634385 0.000001 -0.773018
+vn 0.773012 -0.000001 -0.634391
+vn 0.881922 -0.000001 -0.471395
+vn 0.956942 -0.000000 -0.290279
+vn 0.995184 -0.000000 -0.098022
+vn 0.995184 0.000000 0.098020
+vn 0.956940 -0.000000 0.290285
+vn 0.881922 0.000001 0.471395
+vn 0.773012 0.000001 0.634391
+vn 0.634398 0.000001 0.773007
+vn 0.471395 -0.000001 0.881922
+vn 0.290289 0.000001 0.956939
+vn 0.098010 -0.000001 0.995185
+vn -0.098033 0.000001 0.995183
+vn -0.290269 -0.000001 0.956945
+vn -0.471412 0.000001 0.881913
+vn -0.634385 -0.000001 0.773018
+vn -0.773012 0.000001 0.634391
+vn -0.881922 0.000001 0.471395
+vn -0.956942 0.000000 0.290279
+vn -0.995184 0.000000 0.098022
+vn -0.995184 -0.000000 -0.098020
+vn -0.956939 0.000000 -0.290289
+vn -0.881922 0.000001 -0.471395
+vn -0.773003 0.000001 -0.634402
+vn -0.634398 -0.000001 -0.773007
+vn -0.471395 0.000001 -0.881922
+vn -0.098032 -0.000001 -0.995183
+vn -0.290292 0.000001 -0.956938
+vn 0.098017 -0.995185 0.000001
+vn 0.881921 -0.471396 0.000000
+vn 0.881921 0.471397 -0.000000
+vn 0.634394 0.773010 -0.000001
+vn 0.471396 0.881922 -0.000001
+vn 0.290285 0.956940 -0.000001
+vn -0.098018 0.995185 -0.000001
+vn -0.881920 -0.471399 0.000000
+vn -0.239974 -0.023636 -0.970491
+vn -0.210907 0.173087 0.962060
+vn 0.000000 -0.000003 -1.000000
+vn 0.152975 0.186400 -0.970491
+vn 0.239975 -0.023635 -0.970491
+vn -0.212662 -0.113674 -0.970491
+vn 0.069998 0.230752 -0.970492
+vn 0.113671 -0.212663 -0.970491
+vn -0.212664 0.113668 -0.970491
+vn 0.230752 0.069998 -0.970491
+vn -0.023635 0.239974 -0.970492
+vn 0.186401 -0.152975 -0.970491
+vn -0.239974 0.023635 -0.970492
+vn 0.186400 0.152975 -0.970491
+vn 0.230753 -0.069998 -0.970491
+vn -0.230753 -0.069998 -0.970491
+vn -0.186400 0.152974 -0.970492
+vn 0.239974 0.023635 -0.970492
+vn -0.186400 -0.152975 -0.970491
+vn 0.023635 -0.239975 -0.970491
+vn 0.212664 0.113668 -0.970491
+vn -0.113670 -0.212663 -0.970491
+vn -0.069998 0.230752 -0.970492
+vn 0.212662 -0.113674 -0.970491
+vn -0.210905 -0.173086 0.962060
+vn -0.261089 0.079200 0.962060
+vn 0.026743 -0.271523 0.962061
+vn 0.240622 0.128615 0.962060
+vn 0.240621 -0.128615 0.962060
+vn -0.271523 -0.026743 0.962060
+vn 0.271523 -0.026743 0.962060
+vn 0.079200 0.261090 0.962060
+vn 0.128615 -0.240620 0.962060
+vn -0.240622 0.128615 0.962060
+vn 0.261089 0.079200 0.962060
+vn -0.173085 -0.210906 0.962060
+vn 0.210906 -0.173086 0.962060
+vn -0.271524 0.026742 0.962060
+vn -0.079200 -0.261088 0.962061
+vn -0.261089 -0.079200 0.962060
+vn 0.079200 -0.261088 0.962060
+vn 0.098033 -0.000001 -0.995183
+vn 0.290269 0.000001 -0.956945
+vn 0.634398 -0.000001 -0.773007
+vn 0.995184 -0.000000 0.098022
+vn 0.956942 0.000000 0.290279
+vn 0.634385 -0.000001 0.773018
+vn 0.471412 0.000001 0.881913
+vn 0.290269 -0.000001 0.956945
+vn 0.098032 0.000001 0.995183
+vn -0.098012 -0.000001 0.995185
+vn -0.290289 0.000001 0.956939
+vn -0.471395 -0.000001 0.881922
+vn -0.634398 0.000001 0.773007
+vn -0.995184 0.000000 -0.098022
+vn -0.773012 -0.000001 -0.634391
+vn -0.634385 0.000001 -0.773018
+vn -0.098010 0.000001 -0.995185
+vn -0.290272 -0.000001 -0.956944
+vn 0.000000 -1.000000 -0.000019
+vn -0.000002 -1.000000 0.000007
+vn 0.000001 -1.000000 -0.000000
+vn -0.000027 -1.000000 -0.000008
+vn -0.000009 -1.000000 -0.000001
+vn -0.000005 -1.000000 0.000000
+vn -0.000003 -1.000000 0.000001
+vn -0.000002 -1.000000 0.000001
+vn -0.000001 -1.000000 0.000001
+vn 0.000000 -1.000000 0.000001
+s off
+f 153/85/50 154/86/50 156/87/50
+f 155/85/51 156/86/51 158/87/51
+f 157/85/52 158/86/52 160/87/52
+f 159/85/53 160/86/53 162/87/53
+f 161/85/54 162/86/54 164/87/54
+f 163/85/55 164/86/55 166/87/55
+f 165/85/56 166/86/56 168/87/56
+f 167/85/57 168/86/57 170/87/57
+f 169/85/58 170/86/58 172/87/58
+f 171/85/59 172/86/59 174/87/59
+f 173/85/60 174/86/60 176/87/60
+f 175/85/61 176/86/61 178/87/61
+f 177/85/62 178/86/62 180/87/62
+f 179/85/63 180/86/63 182/87/63
+f 181/85/64 182/86/64 184/87/64
+f 183/85/65 184/86/65 186/87/65
+f 185/85/66 186/86/66 187/88/66
+f 187/85/67 188/86/67 189/88/67
+f 189/85/68 190/86/68 191/88/68
+f 191/85/69 192/86/69 193/88/69
+f 193/85/70 194/86/70 195/88/70
+f 195/85/71 196/86/71 197/88/71
+f 197/85/72 198/86/72 199/88/72
+f 199/85/73 200/86/73 201/88/73
+f 201/85/74 202/86/74 203/88/74
+f 203/85/75 204/86/75 205/88/75
+f 205/85/76 206/86/76 207/88/76
+f 207/85/77 208/86/77 209/88/77
+f 209/85/78 210/86/78 211/88/78
+f 211/85/79 212/86/79 213/88/79
+f 204/85/80 202/86/80 242/88/80
+f 215/85/81 216/86/81 153/88/81
+f 213/85/82 214/86/82 215/88/82
+f 193/85/83 195/86/83 269/88/83
+f 246/89/47 248/90/47 247/91/47
+f 180/85/84 178/86/84 229/87/84
+f 154/85/85 216/86/85 217/88/85
+f 194/85/86 192/86/86 237/88/86
+f 170/85/87 168/86/87 224/87/87
+f 208/85/88 206/86/88 244/88/88
+f 184/85/89 182/86/89 231/87/89
+f 160/85/90 158/86/90 219/87/90
+f 198/85/91 196/86/91 239/88/91
+f 174/85/92 172/86/92 226/87/92
+f 212/85/93 210/86/93 246/88/93
+f 188/85/94 186/86/94 234/88/94
+f 164/85/95 162/86/95 221/87/95
+f 202/85/96 200/86/96 241/88/96
+f 178/85/97 176/86/97 228/87/97
+f 216/85/98 214/86/98 248/88/98
+f 192/85/99 190/86/99 236/88/99
+f 168/85/100 166/86/100 223/87/100
+f 206/85/101 204/86/101 243/88/101
+f 182/85/102 180/86/102 230/87/102
+f 158/85/103 156/86/103 218/87/103
+f 196/85/104 194/86/104 238/88/104
+f 172/85/105 170/86/105 225/87/105
+f 210/85/106 208/86/106 245/88/106
+f 186/85/107 184/86/107 232/87/107
+f 162/85/108 160/86/108 220/87/108
+f 200/85/109 198/86/109 240/88/109
+f 156/85/110 154/86/110 217/87/110
+f 176/85/111 174/86/111 227/87/111
+f 214/85/112 212/86/112 247/88/112
+f 190/85/113 188/86/113 235/88/113
+f 166/85/114 164/86/114 222/87/114
+f 249/92/49 250/93/49 280/94/49
+f 169/85/115 171/86/115 258/87/115
+f 207/85/116 209/86/116 276/88/116
+f 183/85/117 185/86/117 265/87/117
+f 159/85/118 161/86/118 253/87/118
+f 197/85/119 199/86/119 271/88/119
+f 153/85/120 155/86/120 250/87/120
+f 173/85/121 175/86/121 260/87/121
+f 211/85/122 213/86/122 278/88/122
+f 187/85/123 189/86/123 266/88/123
+f 163/85/124 165/86/124 255/87/124
+f 201/85/125 203/86/125 273/88/125
+f 177/85/126 179/86/126 262/87/126
+f 215/85/127 153/86/127 280/88/127
+f 191/85/128 193/86/128 268/88/128
+f 167/85/129 169/86/129 257/87/129
+f 205/85/130 207/86/130 275/88/130
+f 181/85/131 183/86/131 264/87/131
+f 157/85/132 159/86/132 252/87/132
+f 195/85/133 197/86/133 270/88/133
+f 171/85/134 173/86/134 259/87/134
+f 209/85/135 211/86/135 277/88/135
+f 185/85/136 187/86/136 265/88/136
+f 161/85/137 163/86/137 254/87/137
+f 199/85/138 201/86/138 272/88/138
+f 175/85/139 177/86/139 261/87/139
+f 213/85/140 215/86/140 279/88/140
+f 189/85/141 191/86/141 267/88/141
+f 165/85/142 167/86/142 256/87/142
+f 203/85/143 205/86/143 274/88/143
+f 179/85/144 181/86/144 263/87/144
+f 155/85/145 157/86/145 251/87/145
+f 281/85/146 282/86/146 284/87/146
+f 283/85/147 284/86/147 286/87/147
+f 285/85/148 286/86/148 288/87/148
+f 287/85/149 288/86/149 290/87/149
+f 289/85/150 290/86/150 292/87/150
+f 291/85/151 292/86/151 294/87/151
+f 293/85/152 294/86/152 296/87/152
+f 295/85/153 296/86/153 298/87/153
+f 297/85/154 298/86/154 300/87/154
+f 299/85/155 300/86/155 302/87/155
+f 301/85/156 302/86/156 304/87/156
+f 303/85/157 304/86/157 306/87/157
+f 305/85/158 306/86/158 308/87/158
+f 307/85/159 308/86/159 310/87/159
+f 309/85/160 310/86/160 312/87/160
+f 311/85/161 312/86/161 314/87/161
+f 313/85/162 314/86/162 315/88/162
+f 315/85/163 316/86/163 317/88/163
+f 317/85/164 318/86/164 319/88/164
+f 319/85/165 320/86/165 321/88/165
+f 321/85/166 322/86/166 323/88/166
+f 323/85/167 324/86/167 325/88/167
+f 325/85/168 326/86/168 327/88/168
+f 327/85/169 328/86/169 329/88/169
+f 329/85/170 330/86/170 331/88/170
+f 331/85/171 332/86/171 333/88/171
+f 333/85/172 334/86/172 335/88/172
+f 335/85/173 336/86/173 337/88/173
+f 337/85/174 338/86/174 339/88/174
+f 339/85/175 340/86/175 341/88/175
+f 284/92/39 282/93/39 286/94/39
+f 343/85/176 344/86/176 281/88/176
+f 341/85/177 342/86/177 344/87/177
+f 281/92/42 283/93/42 343/94/42
+f 155/88/178 153/85/178 156/87/178
+f 157/88/51 155/85/51 158/87/51
+f 159/88/52 157/85/52 160/87/52
+f 161/88/53 159/85/53 162/87/53
+f 163/88/54 161/85/54 164/87/54
+f 165/88/179 163/85/179 166/87/179
+f 167/88/56 165/85/56 168/87/56
+f 169/88/57 167/85/57 170/87/57
+f 171/88/58 169/85/58 172/87/58
+f 173/88/59 171/85/59 174/87/59
+f 175/88/180 173/85/180 176/87/180
+f 177/88/61 175/85/61 178/87/61
+f 179/88/181 177/85/181 180/87/181
+f 181/88/182 179/85/182 182/87/182
+f 183/88/183 181/85/183 184/87/183
+f 185/88/65 183/85/65 186/87/65
+f 186/86/184 188/87/184 187/88/184
+f 188/86/67 190/87/67 189/88/67
+f 190/86/68 192/87/68 191/88/68
+f 192/86/69 194/87/69 193/88/69
+f 194/86/70 196/87/70 195/88/70
+f 196/86/71 198/87/71 197/88/71
+f 198/86/72 200/87/72 199/88/72
+f 200/86/73 202/87/73 201/88/73
+f 202/86/74 204/87/74 203/88/74
+f 204/86/75 206/87/75 205/88/75
+f 206/86/185 208/87/185 207/88/185
+f 208/86/77 210/87/77 209/88/77
+f 210/86/78 212/87/78 211/88/78
+f 212/86/79 214/87/79 213/88/79
+f 202/86/186 241/87/186 242/88/186
+f 216/86/81 154/87/81 153/88/81
+f 214/86/82 216/87/82 215/88/82
+f 195/86/187 270/87/187 269/88/187
+f 245/95/47 248/90/47 246/89/47
+f 244/96/47 248/90/47 245/95/47
+f 234/97/47 236/98/47 235/99/47
+f 234/97/47 237/100/47 236/98/47
+f 234/97/47 238/101/47 237/100/47
+f 229/102/47 231/103/47 230/104/47
+f 228/105/47 231/103/47 229/102/47
+f 219/94/47 221/106/47 220/107/47
+f 219/94/47 222/108/47 221/106/47
+f 218/92/47 217/93/47 219/94/47
+f 217/93/47 248/90/47 219/94/47
+f 248/90/47 244/96/47 219/94/47
+f 219/94/47 244/96/47 222/108/47
+f 244/96/188 243/109/188 222/108/188
+f 222/108/188 243/109/188 223/110/188
+f 223/110/47 243/109/47 224/111/47
+f 243/109/47 242/112/47 224/111/47
+f 242/112/47 241/113/47 224/111/47
+f 241/113/47 240/114/47 224/111/47
+f 224/111/47 240/114/47 225/115/47
+f 225/115/47 240/114/47 226/116/47
+f 240/114/47 239/117/47 226/116/47
+f 226/116/47 239/117/47 227/118/47
+f 239/117/188 238/101/188 227/118/188
+f 227/118/188 238/101/188 228/105/188
+f 228/105/47 238/101/47 231/103/47
+f 238/101/47 234/97/47 231/103/47
+f 234/97/47 233/119/47 232/120/47
+f 231/103/47 234/97/47 232/120/47
+f 230/88/189 180/85/189 229/87/189
+f 216/86/85 248/87/85 217/88/85
+f 192/86/86 236/87/86 237/88/86
+f 225/88/190 170/85/190 224/87/190
+f 206/86/191 243/87/191 244/88/191
+f 232/88/192 184/85/192 231/87/192
+f 220/88/193 160/85/193 219/87/193
+f 196/86/194 238/87/194 239/88/194
+f 227/88/195 174/85/195 226/87/195
+f 210/86/93 245/87/93 246/88/93
+f 186/86/196 233/87/196 234/88/196
+f 222/88/197 164/85/197 221/87/197
+f 200/86/198 240/87/198 241/88/198
+f 229/88/199 178/85/199 228/87/199
+f 214/86/98 247/87/98 248/88/98
+f 190/86/99 235/87/99 236/88/99
+f 224/88/200 168/85/200 223/87/200
+f 204/86/201 242/87/201 243/88/201
+f 231/88/102 182/85/102 230/87/102
+f 219/88/103 158/85/103 218/87/103
+f 194/86/202 237/87/202 238/88/202
+f 226/88/203 172/85/203 225/87/203
+f 208/86/204 244/87/204 245/88/204
+f 233/88/107 186/85/107 232/87/107
+f 221/88/108 162/85/108 220/87/108
+f 198/86/109 239/87/109 240/88/109
+f 218/88/205 156/85/205 217/87/205
+f 228/88/206 176/85/206 227/87/206
+f 212/86/207 246/87/207 247/88/207
+f 188/86/208 234/87/208 235/88/208
+f 223/88/209 166/85/209 222/87/209
+f 250/93/49 251/90/49 280/94/49
+f 251/90/49 252/91/49 280/94/49
+f 252/91/49 253/89/49 280/94/49
+f 253/89/49 254/95/49 280/94/49
+f 254/95/49 255/96/49 280/94/49
+f 255/96/49 256/109/49 280/94/49
+f 256/109/49 257/112/49 280/94/49
+f 257/112/49 258/113/49 280/94/49
+f 258/113/49 259/114/49 280/94/49
+f 259/114/49 260/117/49 280/94/49
+f 260/117/49 261/101/49 280/94/49
+f 261/101/49 262/100/49 280/94/49
+f 262/100/49 263/98/49 280/94/49
+f 263/98/49 264/99/49 280/94/49
+f 264/99/49 265/97/49 280/94/49
+f 265/97/49 266/119/49 280/94/49
+f 266/119/49 267/120/49 280/94/49
+f 267/120/49 268/103/49 280/94/49
+f 268/103/49 269/104/49 280/94/49
+f 269/104/49 270/102/49 280/94/49
+f 270/102/49 271/105/49 280/94/49
+f 271/105/49 272/118/49 280/94/49
+f 272/118/49 273/116/49 280/94/49
+f 273/116/49 274/115/49 280/94/49
+f 274/115/49 275/111/49 280/94/49
+f 275/111/49 276/110/49 280/94/49
+f 276/110/49 277/108/49 280/94/49
+f 277/108/49 278/106/49 279/107/49
+f 280/94/49 277/108/49 279/107/49
+f 257/88/115 169/85/115 258/87/115
+f 209/86/210 277/87/210 276/88/210
+f 264/88/117 183/85/117 265/87/117
+f 252/88/118 159/85/118 253/87/118
+f 199/86/211 272/87/211 271/88/211
+f 249/88/212 153/85/212 250/87/212
+f 259/88/213 173/85/213 260/87/213
+f 213/86/122 279/87/122 278/88/122
+f 189/86/123 267/87/123 266/88/123
+f 254/88/214 163/85/214 255/87/214
+f 203/86/215 274/87/215 273/88/215
+f 261/88/126 177/85/126 262/87/126
+f 153/86/127 249/87/127 280/88/127
+f 193/86/128 269/87/128 268/88/128
+f 256/88/216 167/85/216 257/87/216
+f 207/86/130 276/87/130 275/88/130
+f 263/88/217 181/85/217 264/87/217
+f 251/88/218 157/85/218 252/87/218
+f 197/86/219 271/87/219 270/88/219
+f 258/88/220 171/85/220 259/87/220
+f 211/86/221 278/87/221 277/88/221
+f 187/86/136 266/87/136 265/88/136
+f 253/88/222 161/85/222 254/87/222
+f 201/86/223 273/87/223 272/88/223
+f 260/88/139 175/85/139 261/87/139
+f 215/86/224 280/87/224 279/88/224
+f 191/86/141 268/87/141 267/88/141
+f 255/88/142 165/85/142 256/87/142
+f 205/86/225 275/87/225 274/88/225
+f 262/88/144 179/85/144 263/87/144
+f 250/88/226 155/85/226 251/87/226
+f 283/88/227 281/85/227 284/87/227
+f 285/88/228 283/85/228 286/87/228
+f 287/88/148 285/85/148 288/87/148
+f 289/88/229 287/85/229 290/87/229
+f 291/88/150 289/85/150 292/87/150
+f 293/88/151 291/85/151 294/87/151
+f 295/88/152 293/85/152 296/87/152
+f 297/88/153 295/85/153 298/87/153
+f 299/88/230 297/85/230 300/87/230
+f 301/88/231 299/85/231 302/87/231
+f 303/88/156 301/85/156 304/87/156
+f 305/88/157 303/85/157 306/87/157
+f 307/88/232 305/85/232 308/87/232
+f 309/88/233 307/85/233 310/87/233
+f 311/88/234 309/85/234 312/87/234
+f 313/88/235 311/85/235 314/87/235
+f 314/86/236 316/87/236 315/88/236
+f 316/86/237 318/87/237 317/88/237
+f 318/86/238 320/87/238 319/88/238
+f 320/86/239 322/87/239 321/88/239
+f 322/86/166 324/87/166 323/88/166
+f 324/86/167 326/87/167 325/88/167
+f 326/86/168 328/87/168 327/88/168
+f 328/86/169 330/87/169 329/88/169
+f 330/86/240 332/87/240 331/88/240
+f 332/86/171 334/87/171 333/88/171
+f 334/86/172 336/87/172 335/88/172
+f 336/86/241 338/87/241 337/88/241
+f 338/86/242 340/87/242 339/88/242
+f 340/86/175 342/87/175 341/88/175
+f 282/93/39 344/90/39 286/94/39
+f 344/90/39 342/91/39 286/94/39
+f 342/91/39 340/89/39 286/94/39
+f 340/89/39 338/95/39 286/94/39
+f 338/95/39 336/96/39 286/94/39
+f 336/96/39 334/109/39 286/94/39
+f 334/109/39 332/112/39 286/94/39
+f 332/112/39 330/113/39 286/94/39
+f 330/113/39 328/114/39 286/94/39
+f 328/114/39 326/117/39 286/94/39
+f 326/117/39 324/101/39 286/94/39
+f 324/101/39 322/100/39 286/94/39
+f 322/100/39 320/98/39 286/94/39
+f 320/98/39 318/99/39 286/94/39
+f 318/99/39 316/97/39 286/94/39
+f 316/97/39 314/119/39 286/94/39
+f 314/119/39 312/120/39 286/94/39
+f 312/120/39 310/103/39 286/94/39
+f 310/103/39 308/104/39 286/94/39
+f 308/104/39 306/102/39 286/94/39
+f 306/102/39 304/105/39 286/94/39
+f 304/105/39 302/118/39 286/94/39
+f 302/118/39 300/116/39 286/94/39
+f 300/116/39 298/115/39 286/94/39
+f 298/115/39 296/111/39 286/94/39
+f 296/111/39 294/110/39 286/94/39
+f 294/110/39 292/108/39 286/94/39
+f 292/108/39 290/106/39 286/94/39
+f 290/106/39 288/107/39 286/94/39
+f 344/86/243 282/87/243 281/88/243
+f 343/88/244 341/85/244 344/87/244
+f 283/93/245 285/90/245 343/94/245
+f 343/94/245 285/90/245 341/107/245
+f 285/90/42 287/91/42 341/107/42
+f 287/91/42 289/89/42 341/107/42
+f 289/89/42 291/95/42 341/107/42
+f 291/95/246 293/96/246 341/107/246
+f 293/96/247 295/109/247 341/107/247
+f 335/110/248 331/115/248 333/111/248
+f 295/109/247 297/112/247 341/107/247
+f 297/112/247 299/113/247 341/107/247
+f 335/110/249 329/116/249 331/115/249
+f 299/113/247 301/114/247 341/107/247
+f 335/110/250 327/118/250 329/116/250
+f 301/114/247 303/117/247 341/107/247
+f 335/110/251 325/105/251 327/118/251
+f 303/117/42 305/101/42 341/107/42
+f 335/110/252 323/102/252 325/105/252
+f 305/101/42 307/100/42 341/107/42
+f 335/110/253 321/104/253 323/102/253
+f 307/100/42 309/98/42 341/107/42
+f 335/110/253 319/103/253 321/104/253
+f 309/98/254 311/99/254 341/107/254
+f 335/110/254 317/120/254 319/103/254
+f 311/99/254 313/97/254 341/107/254
+f 315/119/254 317/120/254 335/110/254
+f 313/97/254 315/119/254 341/107/254
+f 315/119/254 335/110/254 341/107/254
+f 335/110/42 337/108/42 339/106/42
+f 341/107/42 335/110/42 339/106/42
+v 1.365790 0.015116 4.001092
+v 1.365790 0.015113 0.001092
+v 1.560881 0.034331 4.001092
+v 1.560881 0.034328 0.001092
+v 1.748474 0.091236 4.001092
+v 1.748474 0.091234 0.001092
+v 1.921361 0.183646 4.001092
+v 1.921361 0.183644 0.001092
+v 2.072897 0.308009 4.001092
+v 2.072897 0.308007 0.001092
+v 2.197260 0.459546 4.001092
+v 2.197260 0.459543 0.001092
+v 2.289670 0.632432 4.001092
+v 2.289670 0.632430 0.001092
+v 2.346576 0.820025 4.001092
+v 2.346576 0.820023 0.001092
+v 2.365790 1.015116 4.001092
+v 2.365790 1.015113 0.001092
+v 2.346576 1.210206 4.001091
+v 2.346576 1.210203 0.001091
+v 2.289670 1.397799 4.001091
+v 2.289670 1.397797 0.001091
+v 2.197260 1.570686 4.001091
+v 2.197260 1.570683 0.001091
+v 2.072897 1.722223 4.001091
+v 2.072897 1.722220 0.001091
+v 1.921361 1.846586 4.001091
+v 1.921361 1.846583 0.001091
+v 1.748474 1.938995 4.001091
+v 1.748474 1.938993 0.001091
+v 1.560881 1.995901 4.001091
+v 1.560881 1.995899 0.001091
+v 1.365790 2.015116 4.001091
+v 1.365790 2.015113 0.001091
+v 1.170700 1.995901 4.001091
+v 1.170700 1.995898 0.001091
+v 0.983107 1.938995 4.001091
+v 0.983107 1.938993 0.001091
+v 0.810220 1.846585 4.001091
+v 0.810220 1.846583 0.001091
+v 0.658683 1.722222 4.001091
+v 0.658683 1.722220 0.001091
+v 0.534320 1.570685 4.001091
+v 0.534320 1.570683 0.001091
+v 0.441911 1.397799 4.001091
+v 0.441911 1.397796 0.001091
+v 0.385005 1.210205 4.001091
+v 0.385005 1.210203 0.001091
+v 0.365790 1.015115 4.001092
+v 0.365790 1.015112 0.001092
+v 0.385005 0.820024 4.001092
+v 0.385005 0.820022 0.001092
+v 0.441911 0.632431 4.001092
+v 0.441911 0.632429 0.001092
+v 0.534322 0.459545 4.001092
+v 0.534322 0.459542 0.001092
+v 0.658685 0.308008 4.001092
+v 0.658685 0.308006 0.001092
+v 0.810221 0.183645 4.001092
+v 0.810221 0.183643 0.001092
+v 0.983108 0.091236 4.001092
+v 0.983108 0.091233 0.001092
+v 1.170702 0.034330 4.001092
+v 1.170702 0.034328 0.001092
+v 1.365791 0.649119 -0.167860
+v 1.437192 0.656151 -0.167860
+v 1.505850 0.676978 -0.167860
+v 1.569126 0.710800 -0.167860
+v 1.624587 0.756316 -0.167860
+v 1.670104 0.811778 -0.167860
+v 1.703925 0.875053 -0.167860
+v 1.724752 0.943711 -0.167860
+v 1.731785 1.015113 -0.167860
+v 1.724752 1.086515 -0.167860
+v 1.703925 1.155173 -0.167860
+v 1.670104 1.218448 -0.167861
+v 1.624587 1.273910 -0.167861
+v 1.569126 1.319426 -0.167861
+v 1.505850 1.353247 -0.167861
+v 1.437192 1.374075 -0.167861
+v 1.365790 1.381107 -0.167861
+v 1.294389 1.374075 -0.167861
+v 1.225731 1.353247 -0.167861
+v 1.162455 1.319426 -0.167861
+v 1.106993 1.273910 -0.167861
+v 1.061477 1.218448 -0.167861
+v 1.027656 1.155173 -0.167860
+v 1.006829 1.086515 -0.167860
+v 0.999797 1.015113 -0.167860
+v 1.006829 0.943711 -0.167860
+v 1.027656 0.875053 -0.167860
+v 1.061478 0.811777 -0.167860
+v 1.106994 0.756316 -0.167860
+v 1.162456 0.710800 -0.167860
+v 1.225731 0.676978 -0.167860
+v 1.294389 0.656151 -0.167860
+v 1.365791 0.605024 4.157856
+v 1.445795 0.612904 4.157856
+v 1.522726 0.636241 4.157856
+v 1.593625 0.674137 4.157856
+v 1.655769 0.725137 4.157856
+v 1.706769 0.787281 4.157856
+v 1.744666 0.858181 4.157855
+v 1.768002 0.935111 4.157855
+v 1.775882 1.015116 4.157855
+v 1.768002 1.095121 4.157855
+v 1.744666 1.172051 4.157855
+v 1.706769 1.242950 4.157855
+v 1.655769 1.305094 4.157855
+v 1.593625 1.356094 4.157855
+v 1.522726 1.393991 4.157855
+v 1.445795 1.417328 4.157855
+v 1.365790 1.425207 4.157855
+v 1.285786 1.417327 4.157855
+v 1.208855 1.393991 4.157855
+v 1.137956 1.356094 4.157855
+v 1.075812 1.305094 4.157855
+v 1.024812 1.242950 4.157855
+v 0.986915 1.172051 4.157855
+v 0.963579 1.095120 4.157855
+v 0.955699 1.015115 4.157855
+v 0.963579 0.935110 4.157855
+v 0.986916 0.858180 4.157855
+v 1.024812 0.787281 4.157856
+v 1.075812 0.725137 4.157856
+v 1.137956 0.674137 4.157856
+v 1.208856 0.636240 4.157856
+v 1.285786 0.612904 4.157856
+vt 0.000000 0.000000
+vt 0.450363 0.000088
+vt 0.519265 0.025135
+vt 0.412277 0.001462
+vt 0.592585 0.072108
+vt 0.660664 0.134431
+vt 0.714751 0.214466
+vt 0.755741 0.304410
+vt 0.778531 0.401983
+vt 0.781786 0.502742
+vt 0.147188 0.142771
+vt 0.050179 0.306373
+vt 0.093406 0.218681
+vt 0.765337 0.602148
+vt 0.019781 0.402090
+vt 0.729413 0.696327
+vt 0.000089 0.500905
+vt 0.680707 0.782826
+vt 0.000088 0.601389
+vt 0.627360 0.858268
+vt 0.022810 0.698277
+vt 0.566443 0.918999
+vt 0.063602 0.787572
+vt 0.501474 0.962949
+vt 0.119962 0.865210
+vt 0.436606 0.989270
+vt 0.188187 0.927714
+vt 0.377255 0.998855
+vt 0.263175 0.972402
+vt 0.336538 0.999912
+vt 0.208578 0.081678
+vt 0.280064 0.037078
+vt 0.344761 0.010798
+vn 0.634394 -0.773010 0.000000
+vn 0.773010 -0.634394 0.000000
+vn 0.773010 0.634394 -0.000000
+vn 0.634394 0.773010 -0.000000
+vn -0.956941 0.290284 -0.000000
+vn -0.995185 0.098016 -0.000000
+vn -0.881921 -0.471398 0.000000
+vn -0.634392 -0.773011 0.000000
+vn -0.075085 -0.247523 -0.965968
+vn -0.199427 0.163668 0.966148
+vn -0.121931 0.228117 -0.965969
+vn 0.247522 -0.075086 -0.965968
+vn -0.247522 -0.075086 -0.965968
+vn 0.121931 0.228117 -0.965969
+vn 0.075085 -0.247523 -0.965968
+vn -0.199948 0.164091 -0.965968
+vn 0.257414 0.025352 -0.965968
+vn -0.199947 -0.164093 -0.965968
+vn 0.025353 0.257414 -0.965969
+vn 0.164092 -0.199947 -0.965968
+vn -0.247522 0.075085 -0.965969
+vn 0.025353 -0.257415 -0.965968
+vn 0.228118 0.121931 -0.965969
+vn -0.121931 -0.228119 -0.965968
+vn -0.075086 0.247521 -0.965969
+vn 0.228118 -0.121932 -0.965968
+vn -0.257414 -0.025354 -0.965968
+vn 0.164092 0.199946 -0.965969
+vn -0.025353 -0.257415 -0.965968
+vn -0.164092 0.199946 -0.965969
+vn 0.257415 -0.025354 -0.965968
+vn -0.228117 -0.121932 -0.965968
+vn 0.075086 0.247521 -0.965969
+vn 0.121931 -0.228119 -0.965968
+vn -0.228117 0.121931 -0.965968
+vn 0.247522 0.075085 -0.965969
+vn -0.164092 -0.199947 -0.965968
+vn -0.025353 0.257414 -0.965969
+vn 0.199947 -0.164093 -0.965968
+vn -0.257414 0.025352 -0.965968
+vn 0.199947 0.164091 -0.965968
+vn 0.256746 0.025290 0.966148
+vn -0.199428 -0.163666 0.966148
+vn 0.025287 0.256747 0.966148
+vn 0.163666 -0.199428 0.966148
+vn -0.246880 0.074890 0.966148
+vn 0.025287 -0.256746 0.966148
+vn 0.227526 0.121615 0.966148
+vn -0.121615 -0.227526 0.966148
+vn -0.074890 0.246880 0.966148
+vn 0.227525 -0.121615 0.966148
+vn -0.256745 -0.025287 0.966148
+vn 0.163667 0.199428 0.966148
+vn -0.025287 -0.256746 0.966148
+vn -0.163667 0.199428 0.966148
+vn 0.256746 -0.025287 0.966148
+vn -0.227525 -0.121615 0.966148
+vn 0.074890 0.246880 0.966148
+vn 0.121615 -0.227526 0.966148
+vn -0.227526 0.121615 0.966148
+vn 0.246880 0.074890 0.966148
+vn -0.163666 -0.199428 0.966148
+vn -0.025287 0.256747 0.966148
+vn 0.199428 -0.163666 0.966148
+vn -0.256746 0.025289 0.966148
+vn 0.199427 0.163668 0.966148
+vn -0.074892 -0.246879 0.966148
+vn -0.121615 0.227526 0.966148
+vn 0.246879 -0.074890 0.966148
+vn -0.246879 -0.074890 0.966148
+vn 0.121615 0.227526 0.966148
+vn 0.074892 -0.246879 0.966148
+vn -0.199428 0.163666 0.966148
+vn 0.000000 -0.000004 -1.000000
+vn 0.247522 -0.075085 -0.965968
+vn -0.199947 0.164092 -0.965969
+vn 0.257414 0.025353 -0.965969
+vn -0.199947 -0.164092 -0.965968
+vn 0.228120 0.121929 -0.965968
+vn -0.121931 -0.228118 -0.965968
+vn -0.075085 0.247521 -0.965969
+vn 0.228117 -0.121935 -0.965968
+vn -0.257414 -0.025353 -0.965968
+vn 0.164092 0.199947 -0.965969
+vn 0.257415 -0.025353 -0.965968
+vn -0.228117 -0.121935 -0.965968
+vn 0.075085 0.247521 -0.965969
+vn 0.121932 -0.228118 -0.965968
+vn -0.228120 0.121928 -0.965968
+vn 0.199947 -0.164092 -0.965968
+vn -0.257414 0.025353 -0.965969
+vn 0.199946 0.164092 -0.965969
+vn -0.000004 0.000009 1.000000
+vn 0.000001 -0.000000 1.000000
+vn -0.000029 -0.000009 1.000000
+vn -0.000010 -0.000001 1.000000
+vn -0.000005 0.000001 1.000000
+vn -0.000003 0.000001 1.000000
+vn -0.000002 0.000001 1.000000
+vn -0.000001 0.000001 1.000000
+vn 0.000000 0.000001 1.000000
+vn 0.256746 0.025287 0.966148
+vn -0.074891 0.246880 0.966148
+vn 0.227529 -0.121610 0.966148
+vn -0.256746 -0.025287 0.966148
+vn -0.227529 -0.121610 0.966148
+vn -0.256746 0.025287 0.966148
+vn 0.199428 0.163666 0.966148
+vn -0.074889 -0.246879 0.966148
+vn 0.074890 -0.246879 0.966148
+s off
+f 345/121/50 346/121/50 348/121/50
+f 347/121/51 348/121/51 350/121/51
+f 349/121/52 350/121/52 352/121/52
+f 351/121/255 352/121/255 354/121/255
+f 353/121/256 354/121/256 356/121/256
+f 355/121/55 356/121/55 358/121/55
+f 357/121/56 358/121/56 360/121/56
+f 359/121/57 360/121/57 362/121/57
+f 361/121/58 362/121/58 364/121/58
+f 363/121/59 364/121/59 366/121/59
+f 365/121/60 366/121/60 368/121/60
+f 367/121/257 368/121/257 370/121/257
+f 369/121/258 370/121/258 372/121/258
+f 371/121/63 372/121/63 374/121/63
+f 373/121/64 374/121/64 376/121/64
+f 375/121/65 376/121/65 378/121/65
+f 377/121/66 378/121/66 379/121/66
+f 379/121/67 380/121/67 381/121/67
+f 381/121/68 382/121/68 383/121/68
+f 383/121/69 384/121/69 385/121/69
+f 385/121/70 386/121/70 387/121/70
+f 387/121/71 388/121/71 389/121/71
+f 389/121/259 390/121/259 391/121/259
+f 391/121/260 392/121/260 393/121/260
+f 393/121/74 394/121/74 395/121/74
+f 395/121/75 396/121/75 397/121/75
+f 397/121/261 398/121/261 399/121/261
+f 399/121/77 400/121/77 401/121/77
+f 401/121/262 402/121/262 403/121/262
+f 403/121/79 404/121/79 405/121/79
+f 408/121/263 406/121/263 440/121/263
+f 407/121/81 408/121/81 345/121/81
+f 405/121/82 406/121/82 407/121/82
+f 385/121/264 387/121/264 461/121/264
+f 437/121/47 439/121/47 438/121/47
+f 384/121/265 382/121/265 428/121/265
+f 360/121/266 358/121/266 415/121/266
+f 398/121/267 396/121/267 435/121/267
+f 374/121/268 372/121/268 422/121/268
+f 350/121/269 348/121/269 410/121/269
+f 388/121/270 386/121/270 430/121/270
+f 364/121/271 362/121/271 417/121/271
+f 402/121/272 400/121/272 437/121/272
+f 378/121/273 376/121/273 424/121/273
+f 354/121/274 352/121/274 412/121/274
+f 392/121/275 390/121/275 432/121/275
+f 348/121/276 346/121/276 409/121/276
+f 368/121/277 366/121/277 419/121/277
+f 406/121/278 404/121/278 439/121/278
+f 382/121/279 380/121/279 427/121/279
+f 358/121/280 356/121/280 414/121/280
+f 396/121/281 394/121/281 434/121/281
+f 372/121/282 370/121/282 421/121/282
+f 346/121/283 408/121/283 409/121/283
+f 386/121/284 384/121/284 429/121/284
+f 362/121/285 360/121/285 416/121/285
+f 400/121/286 398/121/286 436/121/286
+f 376/121/287 374/121/287 423/121/287
+f 352/121/288 350/121/288 411/121/288
+f 390/121/289 388/121/289 431/121/289
+f 366/121/290 364/121/290 418/121/290
+f 404/121/291 402/121/291 438/121/291
+f 380/121/292 378/121/292 426/121/292
+f 356/121/293 354/121/293 413/121/293
+f 394/121/294 392/121/294 433/121/294
+f 370/121/295 368/121/295 420/121/295
+f 441/122/49 442/123/49 472/124/49
+f 361/121/296 363/121/296 450/121/296
+f 399/121/297 401/121/297 468/121/297
+f 375/121/298 377/121/298 457/121/298
+f 351/121/299 353/121/299 445/121/299
+f 389/121/300 391/121/300 463/121/300
+f 345/121/301 347/121/301 442/121/301
+f 365/121/302 367/121/302 452/121/302
+f 403/121/303 405/121/303 470/121/303
+f 379/121/304 381/121/304 458/121/304
+f 355/121/305 357/121/305 447/121/305
+f 393/121/306 395/121/306 465/121/306
+f 369/121/307 371/121/307 454/121/307
+f 407/121/308 345/121/308 472/121/308
+f 383/121/309 385/121/309 460/121/309
+f 359/121/310 361/121/310 449/121/310
+f 397/121/311 399/121/311 467/121/311
+f 373/121/312 375/121/312 456/121/312
+f 349/121/313 351/121/313 444/121/313
+f 387/121/314 389/121/314 462/121/314
+f 363/121/315 365/121/315 451/121/315
+f 401/121/316 403/121/316 469/121/316
+f 377/121/317 379/121/317 457/121/317
+f 353/121/318 355/121/318 446/121/318
+f 391/121/319 393/121/319 464/121/319
+f 367/121/320 369/121/320 453/121/320
+f 405/121/321 407/121/321 471/121/321
+f 381/121/322 383/121/322 459/121/322
+f 357/121/323 359/121/323 448/121/323
+f 395/121/324 397/121/324 466/121/324
+f 371/121/325 373/121/325 455/121/325
+f 347/121/326 349/121/326 443/121/326
+f 347/121/178 345/121/178 348/121/178
+f 349/121/51 347/121/51 350/121/51
+f 351/121/52 349/121/52 352/121/52
+f 353/121/255 351/121/255 354/121/255
+f 355/121/256 353/121/256 356/121/256
+f 357/121/179 355/121/179 358/121/179
+f 359/121/56 357/121/56 360/121/56
+f 361/121/57 359/121/57 362/121/57
+f 363/121/58 361/121/58 364/121/58
+f 365/121/59 363/121/59 366/121/59
+f 367/121/60 365/121/60 368/121/60
+f 369/121/257 367/121/257 370/121/257
+f 371/121/181 369/121/181 372/121/181
+f 373/121/182 371/121/182 374/121/182
+f 375/121/183 373/121/183 376/121/183
+f 377/121/65 375/121/65 378/121/65
+f 378/121/184 380/121/184 379/121/184
+f 380/121/67 382/121/67 381/121/67
+f 382/121/68 384/121/68 383/121/68
+f 384/121/69 386/121/69 385/121/69
+f 386/121/70 388/121/70 387/121/70
+f 388/121/71 390/121/71 389/121/71
+f 390/121/259 392/121/259 391/121/259
+f 392/121/260 394/121/260 393/121/260
+f 394/121/74 396/121/74 395/121/74
+f 396/121/75 398/121/75 397/121/75
+f 398/121/261 400/121/261 399/121/261
+f 400/121/77 402/121/77 401/121/77
+f 402/121/262 404/121/262 403/121/262
+f 404/121/79 406/121/79 405/121/79
+f 406/121/263 439/121/263 440/121/263
+f 408/121/81 346/121/81 345/121/81
+f 406/121/82 408/121/82 407/121/82
+f 387/121/327 462/121/327 461/121/327
+f 436/121/47 439/121/47 437/121/47
+f 427/121/47 429/121/47 428/121/47
+f 427/121/47 430/121/47 429/121/47
+f 421/121/47 423/121/47 422/121/47
+f 420/121/47 423/121/47 421/121/47
+f 411/121/47 413/121/47 412/121/47
+f 411/121/47 414/121/47 413/121/47
+f 410/121/47 409/121/47 411/121/47
+f 409/121/47 440/121/47 411/121/47
+f 440/121/47 439/121/47 411/121/47
+f 439/121/47 436/121/47 411/121/47
+f 411/121/47 436/121/47 414/121/47
+f 436/121/328 435/121/328 414/121/328
+f 414/121/328 435/121/328 415/121/328
+f 435/121/47 434/121/47 415/121/47
+f 434/121/47 433/121/47 415/121/47
+f 433/121/47 432/121/47 415/121/47
+f 432/121/47 431/121/47 415/121/47
+f 415/121/47 431/121/47 416/121/47
+f 416/121/47 431/121/47 417/121/47
+f 417/121/47 431/121/47 418/121/47
+f 418/121/47 431/121/47 419/121/47
+f 431/121/328 430/121/328 419/121/328
+f 419/121/328 430/121/328 420/121/328
+f 430/121/47 427/121/47 420/121/47
+f 420/121/47 427/121/47 423/121/47
+f 427/121/47 426/121/47 423/121/47
+f 426/121/47 425/121/47 424/121/47
+f 423/121/47 426/121/47 424/121/47
+f 382/121/265 427/121/265 428/121/265
+f 416/121/329 360/121/329 415/121/329
+f 396/121/267 434/121/267 435/121/267
+f 423/121/268 374/121/268 422/121/268
+f 411/121/269 350/121/269 410/121/269
+f 386/121/330 429/121/330 430/121/330
+f 418/121/331 364/121/331 417/121/331
+f 400/121/332 436/121/332 437/121/332
+f 425/121/273 378/121/273 424/121/273
+f 413/121/274 354/121/274 412/121/274
+f 390/121/275 431/121/275 432/121/275
+f 410/121/276 348/121/276 409/121/276
+f 420/121/333 368/121/333 419/121/333
+f 404/121/334 438/121/334 439/121/334
+f 380/121/335 426/121/335 427/121/335
+f 415/121/336 358/121/336 414/121/336
+f 394/121/337 433/121/337 434/121/337
+f 422/121/338 372/121/338 421/121/338
+f 408/121/283 440/121/283 409/121/283
+f 384/121/284 428/121/284 429/121/284
+f 417/121/339 362/121/339 416/121/339
+f 398/121/340 435/121/340 436/121/340
+f 424/121/341 376/121/341 423/121/341
+f 412/121/342 352/121/342 411/121/342
+f 388/121/343 430/121/343 431/121/343
+f 419/121/290 366/121/290 418/121/290
+f 402/121/291 437/121/291 438/121/291
+f 378/121/292 425/121/292 426/121/292
+f 414/121/344 356/121/344 413/121/344
+f 392/121/345 432/121/345 433/121/345
+f 421/121/346 370/121/346 420/121/346
+f 442/123/49 443/125/49 472/124/49
+f 443/125/49 444/126/49 472/124/49
+f 444/126/49 445/127/49 472/124/49
+f 445/127/49 446/128/49 472/124/49
+f 446/128/347 447/129/347 472/124/347
+f 447/129/348 448/130/348 472/124/348
+f 468/131/349 466/132/349 467/133/349
+f 448/130/348 449/134/348 472/124/348
+f 468/131/350 465/135/350 466/132/350
+f 449/134/348 450/136/348 472/124/348
+f 468/131/351 464/137/351 465/135/351
+f 450/136/348 451/138/348 472/124/348
+f 468/131/352 463/139/352 464/137/352
+f 451/138/348 452/140/348 472/124/348
+f 468/131/353 462/141/353 463/139/353
+f 452/140/348 453/142/348 472/124/348
+f 468/131/354 461/143/354 462/141/354
+f 453/142/49 454/144/49 472/124/49
+f 468/131/354 460/145/354 461/143/354
+f 454/144/355 455/146/355 472/124/355
+f 468/131/354 459/147/354 460/145/354
+f 455/146/355 456/148/355 472/124/355
+f 468/131/355 458/149/355 459/147/355
+f 456/148/355 457/150/355 472/124/355
+f 457/150/355 458/149/355 472/124/355
+f 458/149/355 468/131/355 472/124/355
+f 468/131/49 469/151/49 472/124/49
+f 469/151/49 470/152/49 471/153/49
+f 472/124/49 469/151/49 471/153/49
+f 449/121/356 361/121/356 450/121/356
+f 401/121/297 469/121/297 468/121/297
+f 456/121/298 375/121/298 457/121/298
+f 444/121/299 351/121/299 445/121/299
+f 391/121/300 464/121/300 463/121/300
+f 441/121/301 345/121/301 442/121/301
+f 451/121/302 365/121/302 452/121/302
+f 405/121/303 471/121/303 470/121/303
+f 381/121/357 459/121/357 458/121/357
+f 446/121/358 355/121/358 447/121/358
+f 395/121/359 466/121/359 465/121/359
+f 453/121/307 369/121/307 454/121/307
+f 345/121/308 441/121/308 472/121/308
+f 385/121/309 461/121/309 460/121/309
+f 448/121/310 359/121/310 449/121/310
+f 399/121/360 468/121/360 467/121/360
+f 455/121/312 373/121/312 456/121/312
+f 443/121/313 349/121/313 444/121/313
+f 389/121/314 463/121/314 462/121/314
+f 450/121/315 363/121/315 451/121/315
+f 403/121/316 470/121/316 469/121/316
+f 379/121/317 458/121/317 457/121/317
+f 445/121/318 353/121/318 446/121/318
+f 393/121/361 465/121/361 464/121/361
+f 452/121/362 367/121/362 453/121/362
+f 407/121/363 472/121/363 471/121/363
+f 383/121/322 460/121/322 459/121/322
+f 447/121/323 357/121/323 448/121/323
+f 397/121/324 467/121/324 466/121/324
+f 454/121/325 371/121/325 455/121/325
+f 442/121/364 347/121/364 443/121/364
+v 0.000000 0.010026 -4.301087
+v 0.000000 4.010026 -4.301087
+v 0.195090 0.010026 -4.281873
+v 0.195090 4.010026 -4.281873
+v 0.382683 0.010026 -4.224967
+v 0.382683 4.010026 -4.224967
+v 0.555570 0.010026 -4.132557
+v 0.555570 4.010026 -4.132557
+v 0.707107 0.010026 -4.008194
+v 0.707107 4.010026 -4.008194
+v 0.831470 0.010026 -3.856658
+v 0.831470 4.010026 -3.856658
+v 0.923880 0.010026 -3.683771
+v 0.923880 4.010026 -3.683771
+v 0.980785 0.010026 -3.496178
+v 0.980785 4.010026 -3.496178
+v 1.000000 0.010026 -3.301088
+v 1.000000 4.010026 -3.301088
+v 0.980785 0.010026 -3.105997
+v 0.980785 4.010026 -3.105997
+v 0.923880 0.010026 -2.918404
+v 0.923880 4.010026 -2.918404
+v 0.831470 0.010026 -2.745517
+v 0.831470 4.010026 -2.745517
+v 0.707107 0.010026 -2.593981
+v 0.707107 4.010026 -2.593981
+v 0.555570 0.010026 -2.469618
+v 0.555570 4.010026 -2.469618
+v 0.382683 0.010026 -2.377208
+v 0.382683 4.010026 -2.377208
+v 0.195090 0.010026 -2.320302
+v 0.195090 4.010026 -2.320302
+v -0.000000 0.010026 -2.301088
+v -0.000000 4.010026 -2.301088
+v -0.195091 0.010026 -2.320302
+v -0.195091 4.010026 -2.320302
+v -0.382684 0.010026 -2.377208
+v -0.382684 4.010026 -2.377208
+v -0.555571 0.010026 -2.469618
+v -0.555571 4.010026 -2.469618
+v -0.707107 0.010026 -2.593981
+v -0.707107 4.010026 -2.593981
+v -0.831470 0.010026 -2.745518
+v -0.831470 4.010026 -2.745518
+v -0.923880 0.010026 -2.918405
+v -0.923880 4.010026 -2.918405
+v -0.980785 0.010026 -3.105998
+v -0.980785 4.010026 -3.105998
+v -1.000000 0.010026 -3.301089
+v -1.000000 4.010026 -3.301089
+v -0.980785 0.010026 -3.496179
+v -0.980785 4.010026 -3.496179
+v -0.923879 0.010026 -3.683772
+v -0.923879 4.010026 -3.683772
+v -0.831469 0.010026 -3.856659
+v -0.831469 4.010026 -3.856659
+v -0.707106 0.010026 -4.008195
+v -0.707106 4.010026 -4.008195
+v -0.555569 0.010026 -4.132558
+v -0.555569 4.010026 -4.132558
+v -0.382682 0.010026 -4.224968
+v -0.382682 4.010026 -4.224968
+v -0.195089 0.010026 -4.281873
+v -0.195089 4.010026 -4.281873
+v 0.000000 4.270857 -3.619825
+v 0.062183 4.270857 -3.613700
+v 0.121975 4.270857 -3.595562
+v 0.177081 4.270857 -3.566108
+v 0.225381 4.270857 -3.526469
+v 0.265020 4.270857 -3.478168
+v 0.294475 4.270857 -3.423063
+v 0.312612 4.270857 -3.363270
+v 0.318737 4.270857 -3.301088
+v 0.312613 4.270857 -3.238905
+v 0.294475 4.270857 -3.179112
+v 0.265020 4.270857 -3.124007
+v 0.225381 4.270857 -3.075707
+v 0.177081 4.270857 -3.036068
+v 0.121975 4.270857 -3.006613
+v 0.062182 4.270857 -2.988475
+v -0.000000 4.270857 -2.982351
+v -0.062183 4.270857 -2.988475
+v -0.121975 4.270857 -3.006613
+v -0.177081 4.270857 -3.036068
+v -0.225381 4.270857 -3.075707
+v -0.265020 4.270857 -3.124007
+v -0.294475 4.270857 -3.179113
+v -0.312613 4.270857 -3.238906
+v -0.318737 4.270857 -3.301088
+v -0.312612 4.270857 -3.363271
+v -0.294474 4.270857 -3.423064
+v -0.265020 4.270857 -3.478169
+v -0.225381 4.270857 -3.526469
+v -0.177080 4.270857 -3.566108
+v -0.121975 4.270857 -3.595562
+v -0.062182 4.270857 -3.613700
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.500000 1.000000
+vt 0.597545 0.990393
+vt 0.402456 0.990393
+vt 0.691342 0.961940
+vt 0.777785 0.915735
+vt 0.853553 0.853553
+vt 0.915735 0.777785
+vt 0.961940 0.691342
+vt 0.990393 0.597545
+vt 1.000000 0.500000
+vt 0.990393 0.402455
+vt 0.961940 0.308658
+vt 0.915735 0.222215
+vt 0.853553 0.146447
+vt 0.777785 0.084265
+vt 0.691342 0.038060
+vt 0.597545 0.009607
+vt 0.500000 0.000000
+vt 0.402455 0.009607
+vt 0.308658 0.038060
+vt 0.222215 0.084265
+vt 0.146446 0.146447
+vt 0.084265 0.222215
+vt 0.038060 0.308659
+vt 0.009607 0.402455
+vt 0.000000 0.500000
+vt 0.009607 0.597546
+vt 0.038060 0.691342
+vt 0.084266 0.777786
+vt 0.146447 0.853554
+vt 0.222215 0.915735
+vt 0.308659 0.961940
+vn 0.098017 0.000000 -0.995185
+vn 0.290285 0.000000 -0.956940
+vn 0.471396 0.000000 -0.881922
+vn 0.634394 0.000000 -0.773010
+vn 0.773011 0.000000 -0.634393
+vn 0.881921 0.000000 -0.471397
+vn 0.956940 0.000000 -0.290285
+vn 0.995185 0.000000 -0.098017
+vn 0.995185 0.000000 0.098017
+vn 0.881921 0.000000 0.471397
+vn 0.773011 0.000000 0.634393
+vn 0.634394 0.000000 0.773010
+vn 0.471396 0.000000 0.881921
+vn 0.290285 0.000000 0.956940
+vn 0.098017 0.000000 0.995185
+vn -0.098018 0.000000 0.995185
+vn -0.290285 0.000000 0.956940
+vn -0.471397 0.000000 0.881921
+vn -0.634394 0.000000 0.773010
+vn -0.773011 0.000000 0.634393
+vn -0.881922 0.000000 0.471396
+vn -0.956941 0.000000 0.290284
+vn -0.995185 0.000000 0.098016
+vn -0.995185 -0.000000 -0.098018
+vn -0.956940 -0.000000 -0.290286
+vn -0.881921 -0.000000 -0.471398
+vn -0.773010 -0.000000 -0.634394
+vn -0.634392 -0.000000 -0.773012
+vn -0.471397 -0.000000 -0.881921
+vn -0.357332 0.933314 -0.035195
+vn -0.098015 -0.000000 -0.995185
+vn -0.290282 -0.000000 -0.956941
+vn 0.227786 0.933314 0.277558
+vn -0.035193 0.933314 -0.357332
+vn -0.227786 0.933314 0.277558
+vn 0.357332 0.933314 -0.035194
+vn -0.316663 0.933314 -0.169261
+vn 0.104230 0.933314 0.343600
+vn 0.169260 0.933314 -0.316664
+vn -0.316664 0.933314 0.169260
+vn 0.343600 0.933314 0.104230
+vn -0.227785 0.933314 -0.277559
+vn -0.035194 0.933314 0.357332
+vn 0.277558 0.933314 -0.227786
+vn -0.357332 0.933314 0.035194
+vn 0.277558 0.933314 0.227786
+vn -0.104229 0.933314 -0.343600
+vn -0.169260 0.933314 0.316663
+vn 0.343600 0.933314 -0.104230
+vn -0.343600 0.933314 -0.104230
+vn 0.169260 0.933314 0.316664
+vn 0.104230 0.933314 -0.343600
+vn -0.277558 0.933314 0.227786
+vn 0.357332 0.933314 0.035194
+vn -0.277558 0.933314 -0.227786
+vn 0.035194 0.933314 0.357332
+vn 0.227786 0.933314 -0.277558
+vn -0.343600 0.933314 0.104230
+vn 0.035194 0.933314 -0.357332
+vn 0.316664 0.933314 0.169260
+vn -0.169260 0.933314 -0.316664
+vn -0.104230 0.933314 0.343600
+vn 0.316664 0.933314 -0.169260
+vn -0.357332 0.933314 -0.035194
+vn -0.035195 0.933314 -0.357332
+vn -0.316664 0.933314 -0.169260
+vn 0.169261 0.933314 -0.316663
+vn -0.227786 0.933314 -0.277558
+vn -0.357332 0.933314 0.035193
+vn -0.104230 0.933314 -0.343600
+vn -0.169261 0.933314 0.316663
+vn 0.035195 0.933314 -0.357332
+vn -0.169259 0.933314 -0.316664
+s off
+f 473/154/365 474/155/365 476/156/365
+f 475/154/366 476/155/366 478/156/366
+f 477/154/367 478/155/367 480/156/367
+f 479/154/368 480/155/368 482/156/368
+f 481/154/369 482/155/369 484/156/369
+f 483/154/370 484/155/370 486/156/370
+f 485/154/371 486/155/371 488/156/371
+f 487/154/372 488/155/372 490/156/372
+f 489/154/373 490/155/373 492/156/373
+f 491/154/155 492/155/155 494/156/155
+f 493/154/374 494/155/374 496/156/374
+f 495/154/375 496/155/375 498/156/375
+f 497/154/376 498/155/376 500/156/376
+f 499/154/377 500/155/377 502/156/377
+f 501/154/378 502/155/378 504/156/378
+f 503/154/379 504/155/379 506/156/379
+f 505/154/380 506/155/380 507/157/380
+f 507/154/381 508/155/381 509/157/381
+f 509/154/382 510/155/382 511/157/382
+f 511/154/383 512/155/383 513/157/383
+f 513/154/384 514/155/384 515/157/384
+f 515/154/385 516/155/385 517/157/385
+f 517/154/386 518/155/386 519/157/386
+f 519/154/387 520/155/387 521/157/387
+f 521/154/388 522/155/388 523/157/388
+f 523/154/389 524/155/389 525/157/389
+f 525/154/390 526/155/390 527/157/390
+f 527/154/391 528/155/391 529/157/391
+f 529/154/392 530/155/392 531/157/392
+f 531/154/393 532/155/393 533/157/393
+f 524/154/394 522/155/394 562/157/394
+f 535/154/395 536/155/395 473/157/395
+f 533/154/396 534/155/396 535/157/396
+f 473/158/42 475/159/42 535/160/42
+f 538/158/39 537/159/39 539/160/39
+f 500/154/397 498/155/397 549/156/397
+f 474/154/398 536/155/398 537/157/398
+f 514/154/399 512/155/399 557/157/399
+f 490/154/400 488/155/400 544/156/400
+f 528/154/401 526/155/401 564/157/401
+f 504/154/402 502/155/402 551/156/402
+f 480/154/403 478/155/403 539/156/403
+f 518/154/404 516/155/404 559/157/404
+f 494/154/405 492/155/405 546/156/405
+f 532/154/406 530/155/406 566/157/406
+f 508/154/407 506/155/407 554/157/407
+f 484/154/408 482/155/408 541/156/408
+f 522/154/409 520/155/409 561/157/409
+f 498/154/410 496/155/410 548/156/410
+f 536/154/411 534/155/411 568/157/411
+f 512/154/412 510/155/412 556/157/412
+f 488/154/413 486/155/413 543/156/413
+f 526/154/414 524/155/414 563/157/414
+f 502/154/415 500/155/415 550/156/415
+f 478/154/416 476/155/416 538/156/416
+f 516/154/417 514/155/417 558/157/417
+f 492/154/418 490/155/418 545/156/418
+f 530/154/419 528/155/419 565/157/419
+f 506/154/420 504/155/420 552/156/420
+f 482/154/421 480/155/421 540/156/421
+f 520/154/422 518/155/422 560/157/422
+f 476/154/423 474/155/423 537/156/423
+f 496/154/424 494/155/424 547/156/424
+f 534/154/425 532/155/425 567/157/425
+f 510/154/426 508/155/426 555/157/426
+f 486/154/427 484/155/427 542/156/427
+f 475/157/365 473/154/365 476/156/365
+f 477/157/366 475/154/366 478/156/366
+f 479/157/367 477/154/367 480/156/367
+f 481/157/368 479/154/368 482/156/368
+f 483/157/369 481/154/369 484/156/369
+f 485/157/370 483/154/370 486/156/370
+f 487/157/371 485/154/371 488/156/371
+f 489/157/372 487/154/372 490/156/372
+f 491/157/373 489/154/373 492/156/373
+f 493/157/155 491/154/155 494/156/155
+f 495/157/374 493/154/374 496/156/374
+f 497/157/375 495/154/375 498/156/375
+f 499/157/376 497/154/376 500/156/376
+f 501/157/377 499/154/377 502/156/377
+f 503/157/378 501/154/378 504/156/378
+f 505/157/379 503/154/379 506/156/379
+f 506/155/380 508/156/380 507/157/380
+f 508/155/381 510/156/381 509/157/381
+f 510/155/382 512/156/382 511/157/382
+f 512/155/383 514/156/383 513/157/383
+f 514/155/384 516/156/384 515/157/384
+f 516/155/385 518/156/385 517/157/385
+f 518/155/386 520/156/386 519/157/386
+f 520/155/387 522/156/387 521/157/387
+f 522/155/388 524/156/388 523/157/388
+f 524/155/389 526/156/389 525/157/389
+f 526/155/390 528/156/390 527/157/390
+f 528/155/391 530/156/391 529/157/391
+f 530/155/392 532/156/392 531/157/392
+f 532/155/393 534/156/393 533/157/393
+f 522/155/428 561/156/428 562/157/428
+f 536/155/395 474/156/395 473/157/395
+f 534/155/396 536/156/396 535/157/396
+f 475/159/42 477/161/42 535/160/42
+f 477/161/42 479/162/42 535/160/42
+f 479/162/42 481/163/42 535/160/42
+f 481/163/42 483/164/42 535/160/42
+f 483/164/42 485/165/42 535/160/42
+f 485/165/42 487/166/42 535/160/42
+f 487/166/42 489/167/42 535/160/42
+f 489/167/42 491/168/42 535/160/42
+f 491/168/42 493/169/42 535/160/42
+f 493/169/42 495/170/42 535/160/42
+f 495/170/42 497/171/42 535/160/42
+f 497/171/42 499/172/42 535/160/42
+f 499/172/42 501/173/42 535/160/42
+f 501/173/42 503/174/42 535/160/42
+f 503/174/42 505/175/42 535/160/42
+f 505/175/42 507/176/42 535/160/42
+f 507/176/42 509/177/42 535/160/42
+f 509/177/42 511/178/42 535/160/42
+f 511/178/42 513/179/42 535/160/42
+f 513/179/42 515/180/42 535/160/42
+f 515/180/42 517/181/42 535/160/42
+f 517/181/42 519/182/42 535/160/42
+f 519/182/42 521/183/42 535/160/42
+f 521/183/42 523/184/42 535/160/42
+f 523/184/42 525/185/42 535/160/42
+f 525/185/42 527/186/42 535/160/42
+f 527/186/42 529/187/42 535/160/42
+f 529/187/42 531/188/42 533/189/42
+f 535/160/42 529/187/42 533/189/42
+f 537/159/39 568/161/39 539/160/39
+f 568/161/39 567/162/39 539/160/39
+f 567/162/39 566/163/39 539/160/39
+f 566/163/39 565/164/39 539/160/39
+f 565/164/39 564/165/39 539/160/39
+f 564/165/39 563/166/39 539/160/39
+f 563/166/39 562/167/39 539/160/39
+f 562/167/39 561/168/39 539/160/39
+f 561/168/39 560/169/39 539/160/39
+f 560/169/39 559/170/39 539/160/39
+f 559/170/39 558/171/39 539/160/39
+f 558/171/39 557/172/39 539/160/39
+f 557/172/39 556/173/39 539/160/39
+f 556/173/39 555/174/39 539/160/39
+f 555/174/39 554/175/39 539/160/39
+f 554/175/39 553/176/39 539/160/39
+f 553/176/39 552/177/39 539/160/39
+f 552/177/39 551/178/39 539/160/39
+f 551/178/39 550/179/39 539/160/39
+f 550/179/39 549/180/39 539/160/39
+f 549/180/39 548/181/39 539/160/39
+f 548/181/39 547/182/39 539/160/39
+f 547/182/39 546/183/39 539/160/39
+f 546/183/39 545/184/39 539/160/39
+f 545/184/39 544/185/39 539/160/39
+f 544/185/39 543/186/39 539/160/39
+f 543/186/39 542/187/39 539/160/39
+f 542/187/39 541/188/39 539/160/39
+f 541/188/39 540/189/39 539/160/39
+f 550/157/397 500/154/397 549/156/397
+f 536/155/429 568/156/429 537/157/429
+f 512/155/399 556/156/399 557/157/399
+f 545/157/400 490/154/400 544/156/400
+f 526/155/430 563/156/430 564/157/430
+f 552/157/402 504/154/402 551/156/402
+f 540/157/431 480/154/431 539/156/431
+f 516/155/404 558/156/404 559/157/404
+f 547/157/405 494/154/405 546/156/405
+f 530/155/432 565/156/432 566/157/432
+f 506/155/407 553/156/407 554/157/407
+f 542/157/408 484/154/408 541/156/408
+f 520/155/433 560/156/433 561/157/433
+f 549/157/410 498/154/410 548/156/410
+f 534/155/434 567/156/434 568/157/434
+f 510/155/435 555/156/435 556/157/435
+f 544/157/413 488/154/413 543/156/413
+f 524/155/414 562/156/414 563/157/414
+f 551/157/415 502/154/415 550/156/415
+f 539/157/416 478/154/416 538/156/416
+f 514/155/417 557/156/417 558/157/417
+f 546/157/418 492/154/418 545/156/418
+f 528/155/419 564/156/419 565/157/419
+f 553/157/420 506/154/420 552/156/420
+f 541/157/421 482/154/421 540/156/421
+f 518/155/422 559/156/422 560/157/422
+f 538/157/436 476/154/436 537/156/436
+f 548/157/424 496/154/424 547/156/424
+f 532/155/437 566/156/437 567/157/437
+f 508/155/426 554/156/426 555/157/426
+f 543/157/427 486/154/427 542/156/427
+v 0.609274 0.018251 -1.901238
+v 0.609274 0.018251 -0.682690
+v -0.609274 0.018251 -0.682690
+v -0.609274 0.018251 -1.901238
+v 0.609274 1.236799 -1.901237
+v 0.609273 1.236799 -0.682690
+v -0.609274 1.236799 -0.682690
+v -0.609274 1.236799 -1.901238
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vn 1.000000 -0.000000 0.000001
+s off
+f 569/190/42 570/191/42 571/192/42
+f 573/190/39 576/191/39 575/192/39
+f 569/190/438 573/191/438 574/192/438
+f 570/190/49 574/191/49 571/193/49
+f 571/190/46 575/191/46 572/193/46
+f 573/190/47 569/191/47 572/192/47
+f 572/193/42 569/190/42 571/192/42
+f 574/193/39 573/190/39 575/192/39
+f 570/193/48 569/190/48 574/192/48
+f 574/191/49 575/192/49 571/193/49
+f 575/191/46 576/192/46 572/193/46
+f 576/193/47 573/190/47 572/192/47
diff --git a/examples/datavisualization/graphgallery/data/topography.png b/examples/datavisualization/graphgallery/data/topography.png
new file mode 100644
index 00000000..9349cdb3
--- /dev/null
+++ b/examples/datavisualization/graphgallery/data/topography.png
Binary files differ
diff --git a/examples/datavisualization/graphgallery/doc/images/graphgallery-example.png b/examples/datavisualization/graphgallery/doc/images/graphgallery-example.png
new file mode 100644
index 00000000..f3320c8e
--- /dev/null
+++ b/examples/datavisualization/graphgallery/doc/images/graphgallery-example.png
Binary files differ
diff --git a/examples/datavisualization/graphgallery/doc/src/graphgallery.qdoc b/examples/datavisualization/graphgallery/doc/src/graphgallery.qdoc
new file mode 100644
index 00000000..ff7761d2
--- /dev/null
+++ b/examples/datavisualization/graphgallery/doc/src/graphgallery.qdoc
@@ -0,0 +1,705 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example graphgallery
+ \meta tags {DataVisualization, Q3DBars, Bar Graph, Custom Proxy, Q3DScatter, Scatter Graph, Custom Input Handler, Q3DSurface, Surface Graph, QCustom3DItem, Textured Surface}
+ \title Graph Gallery
+ \ingroup qtdatavisualization_examples
+ \brief Gallery of Bar, Scatter, and Surface graphs.
+
+ \e {Graph Gallery} demonstrates all three graph types and some of their special features.
+ The graphs have their own tabs in the application.
+
+ \image graphgallery-example.png
+
+ \include examples-run.qdocinc
+
+ \section1 Bar Graph
+
+ In the \uicontrol {Bar Graph} tab, create a 3D bar graph using Q3DBars and combine the use of
+ widgets to adjust various bar graph qualities. The example shows how to:
+
+ \list
+ \li Create an application with Q3DBars and some widgets
+ \li Use QBar3DSeries and QBarDataProxy to set data to the graph
+ \li Adjust some graph and series properties using widget controls
+ \li Select a row or a column by clicking an axis label
+ \li Create a custom proxy to use with Q3DBars
+ \endlist
+
+ For information about interacting with the graph, see
+ \l{Qt Data Visualization Interacting with Data}{this page}.
+
+ \section2 Creating the Application
+
+ First, in \c{bargraph.cpp}, instantiate Q3DBars:
+
+ \snippet graphgallery/bargraph.cpp 0
+
+ Then, create the widget, and horizontal and vertical layouts.
+
+ The graph is embedded in a window container using
+ QWidget::createWindowContainer(). This is required because all data
+ visualization graph classes (Q3DBars, Q3DScatter, Q3DSurface) inherit
+ QWindow. This is the only way to use a class inheriting QWindow as a widget.
+
+ Add the graph and the vertical layout to the
+ horizontal one:
+
+ \snippet graphgallery/bargraph.cpp 1
+
+ Next, create another class to handle the data addition and other interaction with the
+ graph:
+
+ \snippet graphgallery/bargraph.cpp 2
+
+ \section2 Setting up the Bar Graph
+
+ Set up the graph in the constructor of the \c GraphModifier class:
+
+ \snippet graphgallery/graphmodifier.cpp 0
+
+ First, create the axes and the series into member variables to support changing them easily:
+
+ \snippet graphgallery/graphmodifier.cpp 1
+
+ Then, set some visual qualities for the graph:
+
+ \snippet graphgallery/graphmodifier.cpp 2
+
+ Set up the axes and make them the active axes of the graph:
+
+ \snippet graphgallery/graphmodifier.cpp 3
+
+ Give axis labels a small autorotation angle with setLabelAutoRotation() to make them orient
+ slightly toward the camera. This improves axis label readability at extreme camera angles.
+
+ Next, initialize the visual properties of the series. Note that the second series is initially
+ not visible:
+
+ \snippet graphgallery/graphmodifier.cpp 4
+
+ Add the series to the graph:
+
+ \snippet graphgallery/graphmodifier.cpp 5
+
+ Finally, set the camera angle by calling the same method the camera angle change button
+ in the UI uses to cycle through various camera angles:
+
+ \snippet graphgallery/graphmodifier.cpp 6
+
+ The camera is controlled via the scene object of the graph:
+
+ \snippet graphgallery/graphmodifier.cpp 7
+
+ For more information about using scene and cameras, see Q3DScene and Q3DCamera.
+
+ \section2 Adding Data to the Graph
+
+ At the end of the constructor, call a method that sets up the data:
+
+ \snippet graphgallery/graphmodifier.cpp 8
+
+ This method adds data to the proxies of the two series:
+
+ \snippet graphgallery/graphmodifier.cpp 9a
+ \dots 0
+ \snippet graphgallery/graphmodifier.cpp 9b
+
+ \section2 Using Widgets to Control the Graph
+
+ Continue by adding some widgets in \c{bargraph.cpp}. Add a slider:
+
+ \snippet graphgallery/bargraph.cpp 3
+
+ Use the slider to rotate the graph instead of just using a mouse or touch. Add it to the
+ vertical layout:
+
+ \snippet graphgallery/bargraph.cpp 4
+
+ Then, connect it to a method in \c GraphModifier:
+
+ \snippet graphgallery/bargraph.cpp 5
+
+ Create a slot in \c GraphModifier for the signal connection. The camera is controlled via the
+ scene object. This time, specify the actual camera position along the orbit around the center
+ point, instead of specifying a preset camera angle:
+
+ \snippet graphgallery/graphmodifier.cpp 10
+
+ You can now use the slider to rotate the graph.
+
+ Add more widgets to the vertical layout to control:
+
+ \list
+ \li Graph rotation
+ \li Label style
+ \li Camera preset
+ \li Background visibility
+ \li Grid visibility
+ \li Bar shading smoothness
+ \li Visibility of the second bar series
+ \li Value axis direction
+ \li Axis title visibility and rotation
+ \li Data range to be shown
+ \li Bar style
+ \li Selection mode
+ \li Theme
+ \li Shadow quality
+ \li Font
+ \li Font size
+ \li Axis label rotation
+ \li Data mode
+ \endlist
+
+ Some widget controls are intentionally disabled when in the \uicontrol {Custom Proxy Data}
+ data mode.
+
+ \section2 Selecting a Row or Column by Clicking an Axis Label
+
+ Selection by axis label is default functionality for bar graphs. As an example, you can select
+ rows by clicking an axis label in the following way:
+
+ \list 1
+ \li Change selection mode to \c SelectionRow
+ \li Click a year label
+ \li The row with the clicked year is selected
+ \endlist
+
+ The same method works with \c SelectionSlice and \c SelectionItem flags, as long as
+ either \c SelectionRow or \c SelectionColumn is set as well.
+
+ \section2 Zooming to Selection
+
+ As an example of adjusting the camera target, implement an animation of zooming to
+ selection via a button press. Animation initializations are done in the constructor:
+
+ \snippet graphgallery/graphmodifier.cpp 11
+
+ Function \c{GraphModifier::zoomToSelectedBar()} contains the zooming functionality.
+ QPropertyAnimation \c m_animationCameraTarget targets Q3DCamera::target property,
+ which takes a value normalized to the range (-1, 1).
+
+ Figure out where the selected bar is relative to axes, and use that as the end value for
+ \c{m_animationCameraTarget}:
+
+ \snippet graphgallery/graphmodifier.cpp 12
+ \dots 0
+ \snippet graphgallery/graphmodifier.cpp 13
+
+ Then, rotate the camera so that it always points approximately to the center of
+ the graph at the end of the animation:
+
+ \snippet graphgallery/graphmodifier.cpp 14
+
+ \section2 Custom Proxy for Data
+
+ By toggling \uicontrol {Custom Proxy Data} data mode on, a custom dataset and the corresponding
+ proxy are taken into use.
+
+ Define a simple flexible data set, \c{VariantDataSet}, where each data item is
+ a variant list. Each item can have multiple values, identified by their index in
+ the list. In this case, the data set is storing monthly rainfall data, where the value in
+ index zero is the year, the value in index one is the month, and the value in index two is
+ the amount of rainfall in that month.
+
+ The custom proxy is similar to itemmodel-based proxies provided by Qt Data Visualization, and
+ it requires mapping to interpret the data.
+
+ \section3 VariantDataSet
+
+ Define the data items as QVariantList objects. Add functionality for clearing the data set and
+ querying for a reference to the data contained in the set. Also, add signals to be emitted when
+ data is added or the set is cleared:
+
+ \snippet graphgallery/variantdataset.h 0
+ \dots 0
+ \codeline
+ \snippet graphgallery/variantdataset.h 1
+
+ \section3 VariantBarDataProxy
+
+ Subclass \c VariantBarDataProxy from QBarDataProxy and provide a simple API of getters and
+ setters for the data set and the mapping:
+
+ \snippet graphgallery/variantbardataproxy.h 0
+ \dots 0
+ \codeline
+ \snippet graphgallery/variantbardataproxy.h 1
+
+ The proxy listens for the changes in the data set and the mapping, and resolves the data set
+ if any changes are detected. This is not a particularly efficient implementation, as any change
+ will cause re-resolving of the entire data set, but that is not an issue for this example.
+
+ In \c resolveDataSet() method, sort the variant data values into rows and columns based on the
+ mapping. This is very similar to how QItemModelBarDataProxy handles mapping, except you use
+ list indexes instead of item model roles here. Once the values are sorted, generate
+ \c QBarDataArray out of them, and call the \c resetArray() method in the parent class:
+
+ \snippet graphgallery/variantbardataproxy.cpp 0
+
+ \section3 VariantBarDataMapping
+
+ Store the mapping information between \c VariantDataSet data item indexes and rows, columns,
+ and values of \c QBarDataArray in \c VariantBarDataMapping. It contains the lists of rows and
+ columns to be included in the resolved data:
+
+ \snippet graphgallery/variantbardatamapping.h 0
+ \dots 0
+ \codeline
+ \snippet graphgallery/variantbardatamapping.h 1
+ \dots 0
+ \codeline
+ \snippet graphgallery/variantbardatamapping.h 2
+ \dots 0
+ \codeline
+ \snippet graphgallery/variantbardatamapping.h 3
+
+ The primary way to use a \c VariantBarDataMapping object is to give the mappings in the
+ constructor, though you can use the \c remap() method to set them later, either individually or
+ all together. Emit a signal if mapping changes. The outcome is a simplified version of the
+ mapping functionality of QItemModelBarDataProxy, adapted to work with variant lists instead of
+ item models.
+
+ \section3 RainfallData
+
+ Handle the setup of QBar3DSeries with the custom proxy in the \c RainfallData class:
+
+ \snippet graphgallery/rainfalldata.cpp 0
+
+ Populate the variant data set in the \c addDataSet() method:
+
+ \snippet graphgallery/rainfalldata.cpp 1
+ \dots
+
+ Add the data set to the custom proxy and set the mapping:
+
+ \snippet graphgallery/rainfalldata.cpp 2
+
+ Finally, add a function for getting the created series for displaying:
+
+ \snippet graphgallery/rainfalldata.h 0
+
+ \section1 Scatter Graph
+
+ In the \uicontrol {Scatter Graph} tab, create a 3D scatter graph using Q3DScatter.
+ The example shows how to:
+
+ \list
+ \li Set up Q3DScatter graph
+ \li Use QScatterDataProxy to set data to the graph
+ \li Create a custom input handler by extending Q3DInputHandler
+ \endlist
+
+ For basic application creation, see \l {Bar Graph}.
+
+ \section2 Setting up the Scatter Graph
+
+ First, set up some visual qualities for the graph in the constructor of the
+ \c ScatterDataModifier:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 0
+
+ None of these are mandatory, but are used to override graph defaults. You can try how it looks
+ with the preset defaults by commenting out the block above.
+
+ Next, create a QScatterDataProxy and the associated QScatter3DSeries. Set a custom label format
+ and mesh smoothing for the series and add it to the graph:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 1
+
+ \section2 Adding Scatter Data
+
+ The last thing to do in the \c ScatterDataModifier constructor is to add data to the graph:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 2
+
+ The actual data addition is done in \c addData() method. First, configure the axes:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 3
+
+ You could do this also in the constructor of \c {ScatterDataModifier}. Doing it here
+ keeps the constructor simpler and the axes' configuration near the data.
+
+ Next, create a data array and populate it:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 4
+ \dots
+ \snippet graphgallery/scatterdatamodifier.cpp 5
+
+ Finally, tell the proxy to start using the data we gave it:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 6
+
+ Now, the graph has the data and is ready for use. For information about adding widgets
+ to control the graph, see \l {Using Widgets to Control the Graph}.
+
+ \section2 Replacing Default Input Handling
+
+ Initialize \c m_inputHandler in the constructor with a pointer to the scatter graph instance:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 7
+
+ Replace the default input handling mechanism by setting the active input handler of
+ Q3DScatter to \c {AxesInputHandler}, which implements the custom behavior:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 8
+
+ The input handler needs access to the axes of the graph, so pass them to it:
+
+ \snippet graphgallery/scatterdatamodifier.cpp 9
+
+ \section2 Extending Mouse Event Handling
+
+ First, inherit the custom input handler from Q3DInputHandler instead of QAbstract3DInputHandler
+ to keep all the functionality of the default input handling, and to add the custom
+ functionality on top of it:
+
+ \snippet graphgallery/axesinputhandler.h 0
+
+ Start extending the default functionality by re-implementing some of the mouse events.
+ First, extend \c {mousePressEvent}. Add a \c{m_mousePressed} flag for the left mouse button
+ to it, and keep the rest of the default functionality:
+
+ \snippet graphgallery/axesinputhandler.cpp 0
+
+ Next, modify \c mouseReleaseEvent to clear the flag, and reset the internal state:
+
+ \snippet graphgallery/axesinputhandler.cpp 1
+
+ Then, modify \c {mouseMoveEvent}. Check if \c m_mousePressed flag is \c {true} and
+ the internal state is something other than \c StateNormal. If so, set the input positions
+ for mouse movement distance calculations, and call the axis dragging function (see
+ \l {Implementing Axis Dragging} for details):
+
+ \snippet graphgallery/axesinputhandler.cpp 2
+
+ \section2 Implementing Axis Dragging
+
+ First, start listening to the selection signal from the graph. Do that in the
+ constructor, and connect it to the \c handleElementSelected method:
+
+ \snippet graphgallery/axesinputhandler.cpp 3
+
+ In \c {handleElementSelected}, check the type of the selection, and set the internal state
+ based on it:
+
+ \snippet graphgallery/axesinputhandler.cpp 4
+
+ The actual dragging logic is implemented in the \c handleAxisDragging method, which is called
+ from \c {mouseMoveEvent}, if the required conditions are met:
+
+ \snippet graphgallery/axesinputhandler.cpp 5
+
+ In \c {handleAxisDragging}, first get the scene orientation from the active camera:
+
+ \snippet graphgallery/axesinputhandler.cpp 6
+
+ Then, calculate the modifiers for mouse movement direction based on the orientation:
+
+ \snippet graphgallery/axesinputhandler.cpp 7
+
+ After that, calculate the mouse movement, and modify it based on the y rotation of the
+ camera:
+
+ \snippet graphgallery/axesinputhandler.cpp 8
+
+ Then, apply the moved distance to the correct axis:
+
+ \snippet graphgallery/axesinputhandler.cpp 9
+
+ Finally, add a function for setting the dragging speed:
+
+ \snippet graphgallery/axesinputhandler.h 1
+
+ This is needed, as the mouse movement distance is absolute in screen coordinates, and you
+ need to adjust it to the axis range. The larger the value, the slower the dragging will be.
+ Note that in this example, the scene zoom level is not taken into account when determining the
+ drag speed, so you'll notice changes in the range adjustment as you change the zoom level.
+
+ You could also adjust the modifier automatically based on the axis range and camera zoom level.
+
+ \section1 Surface Graph
+
+ In the \uicontrol {Surface Graph} tab, create a 3D surface graph using Q3DSurface.
+ The example shows how to:
+
+ \list
+ \li Set up a basic QSurfaceDataProxy and set data for it.
+ \li Use QHeightMapSurfaceDataProxy for showing 3D height maps.
+ \li Use topographic data to create 3D height maps.
+ \li Use three different selection modes for studying the graph.
+ \li Use axis ranges to display selected portions of the graph.
+ \li Set a custom surface gradient.
+ \li Add custom items and labels with QCustom3DItem and QCustom3DLabel.
+ \li Use custom input handler to enable zooming and panning.
+ \li Highlight an area of the surface.
+ \endlist
+
+ For basic application creation, see \l {Bar Graph}.
+
+ \section2 Simple Surface with Generated Data
+
+ First, instantiate a new QSurfaceDataProxy and attach it to a new QSurface3DSeries:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 0
+
+ Then, fill the proxy with a simple square root and sine wave data. Create a new
+ \c QSurfaceDataArray instance, and add \c QSurfaceDataRow elements to it.
+ Set the created \c QSurfaceDataArray as the data array for the QSurfaceDataProxy by calling
+ \c{resetArray()}.
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 1
+
+ \section2 Multiseries Height Map Data
+
+ Create the height map by instantiating a QHeightMapSurfaceDataProxy with a QImage containing
+ the height data. Use QHeightMapSurfaceDataProxy::setValueRanges() to define the
+ value range of the map. In the example, the map is from an imaginary position of
+ 34.0\unicode 0x00B0 N - 40.0\unicode 0x00B0 N and 18.0\unicode 0x00B0 E - 24.0\unicode 0x00B0 E.
+ These values are used to position the map on the axes.
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 2
+
+ Add the other surface layers the same way, by creating a proxy and a series for them using
+ height map images.
+
+ \section2 Topographic Map Data
+
+ The topographic data is obtained from the National Land Survey of Finland. It provides a product
+ called \c{Elevation Model 2 m}, which is suitable for this example.
+ The topography data is from Levi fell. The accuracy of the data is well beyond the need, and
+ therefore it is compressed and encoded into a PNG file. The height value of the original
+ ASCII data is encoded into RGB format using a multiplier, which you will see later in
+ a code extract. The multiplier is calculated by dividing the largest 24-bit value with the
+ highest point in Finland.
+
+ QHeightMapSurfaceDataProxy converts only one-byte values. To utilize the higher accuracy of
+ the data from the National Land Survey of Finland, read the data from the PNG file and decode
+ it into QSurface3DSeries.
+
+ First, define the encoding multiplier:
+
+ \snippet graphgallery/topographicseries.cpp 0
+
+ Then, perform the actual decoding:
+
+ \snippet graphgallery/topographicseries.cpp 1
+
+ Now, the data is usable by the proxy.
+
+ \section2 Selecting the Data Set
+
+ To demonstrate different proxies, \uicontrol {Surface Graph} has three radio buttons to
+ switch between the series.
+
+ With \uicontrol {Sqrt & Sin}, the simple generated series is activated. First, set
+ the decorative features, such as enabling the grid for the surface, and selecting the flat
+ shading mode. Next, define the axis label format and value ranges. Set automatic label rotation
+ to improve label readability at low camera angles. Finally, make sure the correct series is
+ added to the graph and the others are not:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 3
+
+ With \uicontrol {Multiseries Height Map}, the height map series are activated and others
+ disabled. Auto-adjusting Y-axis range works well for the height map surface, so ensure it is
+ set.
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 4
+
+ With \uicontrol {Textured Topography}, the topographic series is activated and others disabled.
+ Activate a custom input handler for this series, to be able to highlight areas on it:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 5
+
+ See \l {Use Custom Input Handler to Enable Zooming and Panning} for information about the
+ custom input handler for this data set.
+
+ \section2 Selection Modes
+
+ The three selection modes supported by Q3DSurface can be used with radio buttons.
+ To activate the selected mode or to clear it, add the following inline methods:
+
+ \snippet graphgallery/surfacegraphmodifier.h 0
+
+ Add \c{QAbstract3DGraph::SelectionSlice} and \c{QAbstract3DGraph::SelectionMultiSeries} flags
+ for the row and column selection modes to support doing a slice selection to all visible series
+ in the graph simultaneously.
+
+ \section2 Axis Ranges for Studying the Graph
+
+ The example has four slider controls for adjusting the min and max values for X and Z
+ axes. When selecting the proxy, these sliders are adjusted to match the axis ranges of the
+ current data set:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 6
+
+ Add support for setting the X range from the widget controls to the graph:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 7
+
+ Add the support for Z range the same way.
+
+ \section2 Custom Surface Gradients
+
+ With the \uicontrol {Sqrt & Sin} data set, custom surface gradients can be taken into use
+ with two push buttons. Define the gradient with QLinearGradient, where the desired colors are
+ set. Also, change the color style to Q3DTheme::ColorStyleRangeGradient to use the gradient.
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 8
+
+ \section2 Adding Custom Meshes to the Application
+
+ Add the mesh files to \c{CMakeLists.txt} for cmake build:
+
+ \badcode
+ set(graphgallery_resource_files
+ ...
+ "data/oilrig.obj"
+ "data/pipe.obj"
+ "data/refinery.obj"
+ ...
+ )
+
+ qt6_add_resources(graphgallery "graphgallery"
+ PREFIX
+ "/"
+ FILES
+ ${graphgallery_resource_files}
+ )
+ \endcode
+
+ Also, add them in the qrc resource file for use with qmake:
+
+ \badcode
+ <RCC>
+ <qresource prefix="/">
+ ...
+ <file>data/refinery.obj</file>
+ <file>data/oilrig.obj</file>
+ <file>data/pipe.obj</file>
+ ...
+ </qresource>
+ </RCC>
+ \endcode
+
+ \section2 Adding Custom Item to a Graph
+
+ With the \uicontrol {Multiseries Height Map} data set, custom items are inserted into the
+ graph and can be toggled on or off using checkboxes. Other visual qualities can also be
+ controlled with another set of checkboxes, including see-through for the two top layers, and
+ a highlight for the bottom layer.
+
+ Begin by creating a small QImage. Fill it with a single color to use as the color for the
+ custom object:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 9
+
+ Then, specify the position of the item in a variable. The position can then be used for
+ removing the correct item from the graph:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 10
+
+ Then, create a new QCustom3DItem with all the parameters:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 11
+
+ Finally, add the item to the graph:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 12
+
+ \section2 Adding Custom Label to a Graph
+
+ Adding a custom label is very similar to adding a custom item. For the label, a custom mesh is
+ not needed, but just a QCustom3DLabel instance:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 13
+
+ \section2 Removing Custom Item from a Graph
+
+ To remove a specific item from the graph, call \c removeCustomItemAt() with the position of
+ the item:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 14
+
+ \note Removing a custom item from the graph also deletes the object. If you want to preserve
+ the item, use the \c releaseCustomItem() method instead.
+
+ \section2 Texture to a Surface Series
+
+ With the \uicontrol {Textured Topography} data set, create a map texture to be used with the
+ topographic height map.
+
+ Set an image to be used as the texture on a surface with QSurface3DSeries::setTextureFile().
+ Add a check box to control if the texture is set or not, and a handler to react to the checkbox
+ state:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 15
+
+ The image in this example is read from a JPG file. Setting an empty file with the method clears
+ the texture, and the surface uses the gradients or colors from the theme.
+
+ \section2 Use Custom Input Handler to Enable Zooming and Panning
+
+ With the \uicontrol {Textured Topography} data set, create a custom input handler to
+ highlight the selection on the graph and allow panning the graph.
+
+ The panning implementation is similar to the one shown in \l{Implementing Axis Dragging}.
+ The difference is that, in this example, you follow only the X and Z axes and don't allow
+ dragging the surface outside the graph. To limit the dragging, follow the limits of the axes
+ and do nothing if going outside the graph:
+
+ \snippet graphgallery/custominputhandler.cpp 0
+
+ For zooming, catch the \c wheelEvent and adjust the X and Y axis ranges according to the delta
+ value on QWheelEvent. Adjust the Y axis so that the aspect ratio between the Y axis and the XZ
+ plane stays the same. This prevents getting a graph in which the height is exaggerated:
+
+ \snippet graphgallery/custominputhandler.cpp 1
+
+ Next, add some limits to the zoom level, so that it won't get too near to or far from the
+ surface. For instance, if the value for the X axis gets below the allowed limit, i.e. zooming
+ gets too far, the value is set to the minimum allowed value. If the range is going to below
+ the range minimum, both ends of the axis are adjusted so that the range stays at the limit:
+
+ \snippet graphgallery/custominputhandler.cpp 2
+
+ \section2 Highlight an Area of the Surface
+
+ To implement a highlight to be displayed on the surface, create a copy of the series and add
+ some offset to the y value. In this example, the class \c HighlightSeries implements the
+ creation of the copy in its \c handlePositionChange method.
+
+ First, give \c HighlightSeries the pointer to the original series, and then start listening to
+ the QSurface3DSeries::selectedPointChanged signal:
+
+ \snippet graphgallery/highlightseries.cpp 0
+
+ When the signal triggers, check that the position is valid. Then, calculate the ranges
+ for the copied area, and check that they stay within the bounds. Finally, fill the data array
+ of the highlight series with the range from the data array of the topography series:
+
+ \snippet graphgallery/highlightseries.cpp 1
+
+ \section2 A Gradient to the Highlight Series
+
+ Since the \c HighlightSeries is QSurface3DSeries, all the decoration methods a series can
+ have are available. In this example, add a gradient to emphasize the elevation. Because the
+ suitable gradient style depends on the range of the Y axis and we change the range when
+ zooming, the gradient color positions need to be adjusted as the range changes. Do this by
+ defining proportional values for the gradient color positions:
+
+ \snippet graphgallery/highlightseries.cpp 2
+
+ The gradient modification is done in the \c handleGradientChange method, so connect it to
+ react to changes on the Y axis:
+
+ \snippet graphgallery/surfacegraphmodifier.cpp 16
+
+ When a change in the Y axis max value happens, calculate the new gradient color positions:
+
+ \snippet graphgallery/highlightseries.cpp 3
+
+ \section1 Example Contents
+*/
diff --git a/examples/datavisualization/graphgallery/graphgallery.pro b/examples/datavisualization/graphgallery/graphgallery.pro
new file mode 100644
index 00000000..c9bd96f6
--- /dev/null
+++ b/examples/datavisualization/graphgallery/graphgallery.pro
@@ -0,0 +1,49 @@
+android|ios|winrt {
+ error( "This example is not supported for android, ios, or winrt." )
+}
+
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+QT += widgets
+requires(qtConfig(fontcombobox))
+requires(qtConfig(combobox))
+
+SOURCES += main.cpp \
+ bargraph.cpp \
+ graphmodifier.cpp \
+ rainfalldata.cpp \
+ variantdataset.cpp \
+ variantbardataproxy.cpp \
+ variantbardatamapping.cpp \
+ scattergraph.cpp \
+ scatterdatamodifier.cpp \
+ axesinputhandler.cpp \
+ surfacegraph.cpp \
+ surfacegraphmodifier.cpp \
+ custominputhandler.cpp \
+ highlightseries.cpp \
+ topographicseries.cpp
+
+HEADERS += \
+ bargraph.h \
+ graphmodifier.h \
+ rainfalldata.h \
+ variantdataset.h \
+ variantbardataproxy.h \
+ variantbardatamapping.h \
+ scattergraph.h \
+ scatterdatamodifier.h \
+ axesinputhandler.h \
+ surfacegraph.h \
+ surfacegraphmodifier.h \
+ custominputhandler.h \
+ highlightseries.h \
+ topographicseries.h
+
+RESOURCES += graphgallery.qrc
+
+OTHER_FILES += doc/src/* \
+ doc/images/* \
+ data/*
diff --git a/examples/datavisualization/graphgallery/graphgallery.qrc b/examples/datavisualization/graphgallery/graphgallery.qrc
new file mode 100644
index 00000000..6df5703d
--- /dev/null
+++ b/examples/datavisualization/graphgallery/graphgallery.qrc
@@ -0,0 +1,13 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/raindata.txt</file>
+ <file>data/layer_1.png</file>
+ <file>data/layer_2.png</file>
+ <file>data/layer_3.png</file>
+ <file>data/refinery.obj</file>
+ <file>data/oilrig.obj</file>
+ <file>data/pipe.obj</file>
+ <file>data/maptexture.jpg</file>
+ <file>data/topography.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/datavisualization/graphgallery/graphmodifier.cpp b/examples/datavisualization/graphgallery/graphmodifier.cpp
new file mode 100644
index 00000000..b0cb6f48
--- /dev/null
+++ b/examples/datavisualization/graphgallery/graphmodifier.cpp
@@ -0,0 +1,441 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "graphmodifier.h"
+#include "rainfalldata.h"
+
+#include <QtDataVisualization/qcategory3daxis.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+#include <QtDataVisualization/qbardataproxy.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QtDataVisualization/q3dcamera.h>
+#include <QtDataVisualization/qbar3dseries.h>
+#include <QtDataVisualization/q3dtheme.h>
+#include <QtCore/qmath.h>
+#include <QtWidgets/qcombobox.h>
+
+using namespace Qt::StringLiterals;
+
+// TODO: Many of the values do not affect custom proxy series now - should be fixed
+
+//! [0]
+GraphModifier::GraphModifier(Q3DBars *bargraph, QObject *parent) :
+ QObject(parent),
+ m_graph(bargraph),
+ //! [0]
+ //! [1]
+ m_temperatureAxis(new QValue3DAxis),
+ m_yearAxis(new QCategory3DAxis),
+ m_monthAxis(new QCategory3DAxis),
+ m_primarySeries(new QBar3DSeries),
+ m_secondarySeries(new QBar3DSeries),
+ m_celsiusString(u"°C"_s)
+ //! [1]
+{
+ //! [2]
+ m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftMedium);
+ m_graph->activeTheme()->setBackgroundEnabled(false);
+ m_graph->activeTheme()->setFont(QFont("Times New Roman", m_fontSize));
+ m_graph->activeTheme()->setLabelBackgroundEnabled(true);
+ m_graph->setMultiSeriesUniform(true);
+ //! [2]
+
+ m_months = {"January", "February", "March", "April", "May", "June" , "July",
+ "August", "September", "October" , "November", "December"};
+ m_years = {"2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022"};
+
+ //! [3]
+ m_temperatureAxis->setTitle("Average temperature");
+ m_temperatureAxis->setSegmentCount(m_segments);
+ m_temperatureAxis->setSubSegmentCount(m_subSegments);
+ m_temperatureAxis->setRange(m_minval, m_maxval);
+ m_temperatureAxis->setLabelFormat(u"%.1f "_s + m_celsiusString);
+ m_temperatureAxis->setLabelAutoRotation(30.0f);
+ m_temperatureAxis->setTitleVisible(true);
+
+ m_yearAxis->setTitle("Year");
+ m_yearAxis->setLabelAutoRotation(30.0f);
+ m_yearAxis->setTitleVisible(true);
+ m_monthAxis->setTitle("Month");
+ m_monthAxis->setLabelAutoRotation(30.0f);
+ m_monthAxis->setTitleVisible(true);
+
+ m_graph->setValueAxis(m_temperatureAxis);
+ m_graph->setRowAxis(m_yearAxis);
+ m_graph->setColumnAxis(m_monthAxis);
+ //! [3]
+
+ //! [4]
+ m_primarySeries->setItemLabelFormat(u"Oulu - @colLabel @rowLabel: @valueLabel"_s);
+ m_primarySeries->setMesh(QAbstract3DSeries::MeshBevelBar);
+ m_primarySeries->setMeshSmooth(false);
+
+ m_secondarySeries->setItemLabelFormat(u"Helsinki - @colLabel @rowLabel: @valueLabel"_s);
+ m_secondarySeries->setMesh(QAbstract3DSeries::MeshBevelBar);
+ m_secondarySeries->setMeshSmooth(false);
+ m_secondarySeries->setVisible(false);
+ //! [4]
+
+ //! [5]
+ m_graph->addSeries(m_primarySeries);
+ m_graph->addSeries(m_secondarySeries);
+ //! [5]
+
+ //! [6]
+ changePresetCamera();
+ //! [6]
+
+ //! [8]
+ resetTemperatureData();
+ //! [8]
+
+ // Set up property animations for zooming to the selected bar
+ //! [11]
+ Q3DCamera *camera = m_graph->scene()->activeCamera();
+ m_defaultAngleX = camera->xRotation();
+ m_defaultAngleY = camera->yRotation();
+ m_defaultZoom = camera->zoomLevel();
+ m_defaultTarget = camera->target();
+
+ m_animationCameraX.setTargetObject(camera);
+ m_animationCameraY.setTargetObject(camera);
+ m_animationCameraZoom.setTargetObject(camera);
+ m_animationCameraTarget.setTargetObject(camera);
+
+ m_animationCameraX.setPropertyName("xRotation");
+ m_animationCameraY.setPropertyName("yRotation");
+ m_animationCameraZoom.setPropertyName("zoomLevel");
+ m_animationCameraTarget.setPropertyName("target");
+
+ int duration = 1700;
+ m_animationCameraX.setDuration(duration);
+ m_animationCameraY.setDuration(duration);
+ m_animationCameraZoom.setDuration(duration);
+ m_animationCameraTarget.setDuration(duration);
+
+ // The zoom always first zooms out above the graph and then zooms in
+ qreal zoomOutFraction = 0.3;
+ m_animationCameraX.setKeyValueAt(zoomOutFraction, QVariant::fromValue(0.0f));
+ m_animationCameraY.setKeyValueAt(zoomOutFraction, QVariant::fromValue(90.0f));
+ m_animationCameraZoom.setKeyValueAt(zoomOutFraction, QVariant::fromValue(50.0f));
+ m_animationCameraTarget.setKeyValueAt(zoomOutFraction,
+ QVariant::fromValue(QVector3D(0.0f, 0.0f, 0.0f)));
+ //! [11]
+
+ m_customData = new RainfallData();
+}
+
+GraphModifier::~GraphModifier()
+{
+ delete m_customData;
+}
+
+void GraphModifier::resetTemperatureData()
+{
+ //! [9a]
+ // Set up data
+ static const float tempOulu[8][12] = {
+ {-7.4f, -2.4f, 0.0f, 3.0f, 8.2f, 11.6f, 14.7f, 15.4f, 11.4f, 4.2f, 2.1f, -2.3f}, // 2015
+ {-13.4f, -3.9f, -1.8f, 3.1f, 10.6f, 13.7f, 17.8f, 13.6f, 10.7f, 3.5f, -3.1f, -4.2f}, // 2016
+ //! [9a]
+ {-5.7f, -6.7f, -3.0f, -0.1f, 4.7f, 12.4f, 16.1f, 14.1f, 9.4f, 3.0f, -0.3f, -3.2f}, // 2017
+ {-6.4f, -11.9f, -7.4f, 1.9f, 11.4f, 12.4f, 21.5f, 16.1f, 11.0f, 4.4f, 2.1f, -4.1f}, // 2018
+ {-11.7f, -6.1f, -2.4f, 3.9f, 7.2f, 14.5f, 15.6f, 14.4f, 8.5f, 2.0f, -3.0f, -1.5f}, // 2019
+ {-2.1f, -3.4f, -1.8f, 0.6f, 7.0f, 17.1f, 15.6f, 15.4f, 11.1f, 5.6f, 1.9f, -1.7f}, // 2020
+ {-9.6f, -11.6f, -3.2f, 2.4f, 7.8f, 17.3f, 19.4f, 14.2f, 8.0f, 5.2f, -2.2f, -8.6f}, // 2021
+ {-7.3f, -6.4f, -1.8f, 1.3f, 8.1f, 15.5f, 17.6f, 17.6f, 9.1f, 5.4f, -1.5f, -4.4f} // 2022
+ };
+
+ static const float tempHelsinki[8][12] = {
+ {-2.0f, -0.1f, 1.8f, 5.1f, 9.7f, 13.7f, 16.3f, 17.3f, 12.7f, 5.4f, 4.6f, 2.1f}, // 2015
+ {-10.3f, -0.6f, 0.0f, 4.9f, 14.3f, 15.7f, 17.7f, 16.0f, 12.7f, 4.6f, -1.0f, -0.9f}, // 2016
+ {-2.9f, -3.3f, 0.7f, 2.3f, 9.9f, 13.8f, 16.1f, 15.9f, 11.4f, 5.0f, 2.7f, 0.7f}, // 2017
+ {-2.2f, -8.4f, -4.7f, 5.0f, 15.3f, 15.8f, 21.2f, 18.2f, 13.3f, 6.7f, 2.8f, -2.0f}, // 2018
+ {-6.2f, -0.5f, -0.3f, 6.8f, 10.6f, 17.9f, 17.5f, 16.8f, 11.3f, 5.2f, 1.8f, 1.4f}, // 2019
+ {1.9f, 0.5f, 1.7f, 4.5f, 9.5f, 18.4f, 16.5f, 16.8f, 13.0f, 8.2f, 4.4f, 0.9f}, // 2020
+ {-4.7f, -8.1f, -0.9f, 4.5f, 10.4f, 19.2f, 20.9f, 15.4f, 9.5f, 8.0f, 1.5f, -6.7f}, // 2021
+ {-3.3f, -2.2f, -0.2f, 3.3f, 9.6f, 16.9f, 18.1f, 18.9f, 9.2f, 7.6f, 2.3f, -3.4f} // 2022
+ };
+
+ // Create data arrays
+ //! [9b]
+ auto *dataSet = new QBarDataArray;
+ auto *dataSet2 = new QBarDataArray;
+
+ dataSet->reserve(m_years.size());
+ for (qsizetype year = 0; year < m_years.size(); ++year) {
+ // Create a data row
+ auto *dataRow = new QBarDataRow(m_months.size());
+ auto *dataRow2 = new QBarDataRow(m_months.size());
+ for (qsizetype month = 0; month < m_months.size(); ++month) {
+ // Add data to the row
+ (*dataRow)[month].setValue(tempOulu[year][month]);
+ (*dataRow2)[month].setValue(tempHelsinki[year][month]);
+ }
+ // Add the row to the set
+ dataSet->append(dataRow);
+ dataSet2->append(dataRow2);
+ }
+
+ // Add data to the data proxy (the data proxy assumes ownership of it)
+ m_primarySeries->dataProxy()->resetArray(dataSet, m_years, m_months);
+ m_secondarySeries->dataProxy()->resetArray(dataSet2, m_years, m_months);
+ //! [9b]
+}
+
+void GraphModifier::changeRange(int range)
+{
+ if (range >= m_years.count())
+ m_yearAxis->setRange(0, m_years.count() - 1);
+ else
+ m_yearAxis->setRange(range, range);
+}
+
+void GraphModifier::changeStyle(int style)
+{
+ auto *comboBox = qobject_cast<QComboBox *>(sender());
+ if (comboBox) {
+ m_barMesh = comboBox->itemData(style).value<QAbstract3DSeries::Mesh>();
+ m_primarySeries->setMesh(m_barMesh);
+ m_secondarySeries->setMesh(m_barMesh);
+ m_customData->customSeries()->setMesh(m_barMesh);
+ }
+}
+
+void GraphModifier::changePresetCamera()
+{
+ m_animationCameraX.stop();
+ m_animationCameraY.stop();
+ m_animationCameraZoom.stop();
+ m_animationCameraTarget.stop();
+
+ // Restore camera target in case animation has changed it
+ m_graph->scene()->activeCamera()->setTarget(QVector3D(0.0f, 0.0f, 0.0f));
+
+ //! [7]
+ static int preset = Q3DCamera::CameraPresetFront;
+
+ m_graph->scene()->activeCamera()->setCameraPreset((Q3DCamera::CameraPreset)preset);
+
+ if (++preset > Q3DCamera::CameraPresetDirectlyBelow)
+ preset = Q3DCamera::CameraPresetFrontLow;
+ //! [7]
+}
+
+void GraphModifier::changeTheme(int theme)
+{
+ Q3DTheme *currentTheme = m_graph->activeTheme();
+ currentTheme->setType(Q3DTheme::Theme(theme));
+ emit backgroundEnabledChanged(currentTheme->isBackgroundEnabled());
+ emit gridEnabledChanged(currentTheme->isGridEnabled());
+ emit fontChanged(currentTheme->font());
+ emit fontSizeChanged(currentTheme->font().pointSize());
+}
+
+void GraphModifier::changeLabelBackground()
+{
+ m_graph->activeTheme()->setLabelBackgroundEnabled(!m_graph->activeTheme()->isLabelBackgroundEnabled());
+}
+
+void GraphModifier::changeSelectionMode(int selectionMode)
+{
+ auto *comboBox = qobject_cast<QComboBox *>(sender());
+ if (comboBox) {
+ int flags = comboBox->itemData(selectionMode).toInt();
+ m_graph->setSelectionMode(QAbstract3DGraph::SelectionFlags(flags));
+ }
+}
+
+void GraphModifier::changeFont(const QFont &font)
+{
+ QFont newFont = font;
+ m_graph->activeTheme()->setFont(newFont);
+}
+
+void GraphModifier::changeFontSize(int fontsize)
+{
+ m_fontSize = fontsize;
+ QFont font = m_graph->activeTheme()->font();
+ font.setPointSize(m_fontSize);
+ m_graph->activeTheme()->setFont(font);
+}
+
+void GraphModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality sq)
+{
+ int quality = int(sq);
+ // Updates the UI component to show correct shadow quality
+ emit shadowQualityChanged(quality);
+}
+
+void GraphModifier::changeLabelRotation(int rotation)
+{
+ m_temperatureAxis->setLabelAutoRotation(float(rotation));
+ m_monthAxis->setLabelAutoRotation(float(rotation));
+ m_yearAxis->setLabelAutoRotation(float(rotation));
+}
+
+void GraphModifier::setAxisTitleVisibility(bool enabled)
+{
+ m_temperatureAxis->setTitleVisible(enabled);
+ m_monthAxis->setTitleVisible(enabled);
+ m_yearAxis->setTitleVisible(enabled);
+}
+
+void GraphModifier::setAxisTitleFixed(bool enabled)
+{
+ m_temperatureAxis->setTitleFixed(enabled);
+ m_monthAxis->setTitleFixed(enabled);
+ m_yearAxis->setTitleFixed(enabled);
+}
+
+void GraphModifier::zoomToSelectedBar()
+{
+ m_animationCameraX.stop();
+ m_animationCameraY.stop();
+ m_animationCameraZoom.stop();
+ m_animationCameraTarget.stop();
+
+ Q3DCamera *camera = m_graph->scene()->activeCamera();
+ float currentX = camera->xRotation();
+ float currentY = camera->yRotation();
+ float currentZoom = camera->zoomLevel();
+ QVector3D currentTarget = camera->target();
+
+ m_animationCameraX.setStartValue(QVariant::fromValue(currentX));
+ m_animationCameraY.setStartValue(QVariant::fromValue(currentY));
+ m_animationCameraZoom.setStartValue(QVariant::fromValue(currentZoom));
+ m_animationCameraTarget.setStartValue(QVariant::fromValue(currentTarget));
+
+ QPoint selectedBar = m_graph->selectedSeries()
+ ? m_graph->selectedSeries()->selectedBar()
+ : QBar3DSeries::invalidSelectionPosition();
+
+ if (selectedBar != QBar3DSeries::invalidSelectionPosition()) {
+ // Normalize selected bar position within axis range to determine target coordinates
+ //! [12]
+ QVector3D endTarget;
+ float xMin = m_graph->columnAxis()->min();
+ float xRange = m_graph->columnAxis()->max() - xMin;
+ float zMin = m_graph->rowAxis()->min();
+ float zRange = m_graph->rowAxis()->max() - zMin;
+ endTarget.setX((selectedBar.y() - xMin) / xRange * 2.0f - 1.0f);
+ endTarget.setZ((selectedBar.x() - zMin) / zRange * 2.0f - 1.0f);
+ //! [12]
+
+ // Rotate the camera so that it always points approximately to the graph center
+ //! [14]
+ qreal endAngleX = 90.0 - qRadiansToDegrees(qAtan(qreal(endTarget.z() / endTarget.x())));
+ if (endTarget.x() > 0.0f)
+ endAngleX -= 180.0f;
+ float barValue = m_graph->selectedSeries()->dataProxy()->itemAt(selectedBar.x(),
+ selectedBar.y())->value();
+ float endAngleY = barValue >= 0.0f ? 30.0f : -30.0f;
+ if (m_graph->valueAxis()->reversed())
+ endAngleY *= -1.0f;
+ //! [14]
+
+ m_animationCameraX.setEndValue(QVariant::fromValue(float(endAngleX)));
+ m_animationCameraY.setEndValue(QVariant::fromValue(endAngleY));
+ m_animationCameraZoom.setEndValue(QVariant::fromValue(250));
+ //! [13]
+ m_animationCameraTarget.setEndValue(QVariant::fromValue(endTarget));
+ //! [13]
+ } else {
+ // No selected bar, so return to the default view
+ m_animationCameraX.setEndValue(QVariant::fromValue(m_defaultAngleX));
+ m_animationCameraY.setEndValue(QVariant::fromValue(m_defaultAngleY));
+ m_animationCameraZoom.setEndValue(QVariant::fromValue(m_defaultZoom));
+ m_animationCameraTarget.setEndValue(QVariant::fromValue(m_defaultTarget));
+ }
+
+ m_animationCameraX.start();
+ m_animationCameraY.start();
+ m_animationCameraZoom.start();
+ m_animationCameraTarget.start();
+}
+
+void GraphModifier::setDataModeToWeather(bool enabled)
+{
+ if (enabled)
+ changeDataMode(false);
+}
+
+void GraphModifier::setDataModeToCustom(bool enabled)
+{
+ if (enabled)
+ changeDataMode(true);
+}
+
+void GraphModifier::changeShadowQuality(int quality)
+{
+ QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality);
+ m_graph->setShadowQuality(sq);
+ emit shadowQualityChanged(quality);
+}
+
+//! [10]
+void GraphModifier::rotateX(int rotation)
+{
+ m_xRotation = rotation;
+ m_graph->scene()->activeCamera()->setCameraPosition(m_xRotation, m_yRotation);
+}
+//! [10]
+
+void GraphModifier::rotateY(int rotation)
+{
+ m_yRotation = rotation;
+ m_graph->scene()->activeCamera()->setCameraPosition(m_xRotation, m_yRotation);
+}
+
+void GraphModifier::setBackgroundEnabled(int enabled)
+{
+ m_graph->activeTheme()->setBackgroundEnabled(bool(enabled));
+}
+
+void GraphModifier::setGridEnabled(int enabled)
+{
+ m_graph->activeTheme()->setGridEnabled(bool(enabled));
+}
+
+void GraphModifier::setSmoothBars(int smooth)
+{
+ m_smooth = bool(smooth);
+ m_primarySeries->setMeshSmooth(m_smooth);
+ m_secondarySeries->setMeshSmooth(m_smooth);
+ m_customData->customSeries()->setMeshSmooth(m_smooth);
+}
+
+void GraphModifier::setSeriesVisibility(int enabled)
+{
+ m_secondarySeries->setVisible(bool(enabled));
+}
+
+void GraphModifier::setReverseValueAxis(int enabled)
+{
+ m_graph->valueAxis()->setReversed(enabled);
+}
+
+void GraphModifier::setReflection(bool enabled)
+{
+ m_graph->setReflection(enabled);
+}
+
+void GraphModifier::changeDataMode(bool customData)
+{
+ // Change between weather data and data from custom proxy
+ if (customData) {
+ m_graph->removeSeries(m_primarySeries);
+ m_graph->removeSeries(m_secondarySeries);
+ m_graph->addSeries(m_customData->customSeries());
+ m_graph->setValueAxis(m_customData->valueAxis());
+ m_graph->setRowAxis(m_customData->rowAxis());
+ m_graph->setColumnAxis(m_customData->colAxis());
+ } else {
+ m_graph->removeSeries(m_customData->customSeries());
+ m_graph->addSeries(m_primarySeries);
+ m_graph->addSeries(m_secondarySeries);
+ m_graph->setValueAxis(m_temperatureAxis);
+ m_graph->setRowAxis(m_yearAxis);
+ m_graph->setColumnAxis(m_monthAxis);
+ }
+}
diff --git a/examples/datavisualization/graphgallery/graphmodifier.h b/examples/datavisualization/graphgallery/graphmodifier.h
new file mode 100644
index 00000000..0d112c0d
--- /dev/null
+++ b/examples/datavisualization/graphgallery/graphmodifier.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef GRAPHMODIFIER_H
+#define GRAPHMODIFIER_H
+
+#include <QtDataVisualization/q3dbars.h>
+#include <QtDataVisualization/qbardataproxy.h>
+#include <QtDataVisualization/qabstract3dseries.h>
+#include <QtCore/qpropertyanimation.h>
+
+class RainfallData;
+
+class GraphModifier : public QObject
+{
+ Q_OBJECT
+public:
+ explicit GraphModifier(Q3DBars *bargraph, QObject *parent);
+ ~GraphModifier();
+
+ void resetTemperatureData();
+ void changePresetCamera();
+ void changeLabelBackground();
+ void changeFont(const QFont &font);
+ void changeFontSize(int fontsize);
+ void rotateX(int rotation);
+ void rotateY(int rotation);
+ void setBackgroundEnabled(int enabled);
+ void setGridEnabled(int enabled);
+ void setSmoothBars(int smooth);
+ void setSeriesVisibility(int enabled);
+ void setReverseValueAxis(int enabled);
+ void setReflection(bool enabled);
+ void changeDataMode(bool customData);
+
+public Q_SLOTS:
+ void changeRange(int range);
+ void changeStyle(int style);
+ void changeSelectionMode(int selectionMode);
+ void changeTheme(int theme);
+ void changeShadowQuality(int quality);
+ void shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality shadowQuality);
+ void changeLabelRotation(int rotation);
+ void setAxisTitleVisibility(bool enabled);
+ void setAxisTitleFixed(bool enabled);
+ void zoomToSelectedBar();
+ void setDataModeToWeather(bool enabled);
+ void setDataModeToCustom(bool enabled);
+
+Q_SIGNALS:
+ void shadowQualityChanged(int quality);
+ void backgroundEnabledChanged(bool enabled);
+ void gridEnabledChanged(bool enabled);
+ void fontChanged(const QFont &font);
+ void fontSizeChanged(int size);
+
+private:
+ Q3DBars *m_graph = nullptr;
+ float m_xRotation = 0.f;
+ float m_yRotation = 0.f;
+ int m_fontSize = 30;
+ int m_segments = 4;
+ int m_subSegments = 3;
+ float m_minval = -20.f;
+ float m_maxval = 20.f;
+ QStringList m_months = {};
+ QStringList m_years = {};
+ QValue3DAxis *m_temperatureAxis = nullptr;
+ QCategory3DAxis *m_yearAxis = nullptr;
+ QCategory3DAxis *m_monthAxis = nullptr;
+ QBar3DSeries *m_primarySeries = nullptr;
+ QBar3DSeries *m_secondarySeries = nullptr;
+ QAbstract3DSeries::Mesh m_barMesh = QAbstract3DSeries::MeshBevelBar;
+ bool m_smooth = false;
+ QPropertyAnimation m_animationCameraX = {};
+ QPropertyAnimation m_animationCameraY = {};
+ QPropertyAnimation m_animationCameraZoom = {};
+ QPropertyAnimation m_animationCameraTarget = {};
+ float m_defaultAngleX = 0.f;
+ float m_defaultAngleY = 0.f;
+ float m_defaultZoom = 0.f;
+ QVector3D m_defaultTarget = {};
+ const QString m_celsiusString;
+ RainfallData *m_customData = nullptr;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/highlightseries.cpp b/examples/datavisualization/graphgallery/highlightseries.cpp
new file mode 100644
index 00000000..3f10b421
--- /dev/null
+++ b/examples/datavisualization/graphgallery/highlightseries.cpp
@@ -0,0 +1,101 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "highlightseries.h"
+
+//! [2]
+const float darkRedPos = 1.f;
+const float redPos = 0.8f;
+const float yellowPos = 0.6f;
+const float greenPos = 0.4f;
+const float darkGreenPos = 0.2f;
+//! [2]
+
+HighlightSeries::HighlightSeries()
+{
+ setDrawMode(QSurface3DSeries::DrawSurface);
+ setFlatShadingEnabled(true);
+ setVisible(false);
+}
+
+HighlightSeries::~HighlightSeries()
+{
+}
+
+//! [0]
+void HighlightSeries::setTopographicSeries(TopographicSeries *series)
+{
+ m_topographicSeries = series;
+ m_srcWidth = m_topographicSeries->dataProxy()->array()->at(0)->size();
+ m_srcHeight = m_topographicSeries->dataProxy()->array()->size();
+
+ QObject::connect(m_topographicSeries, &QSurface3DSeries::selectedPointChanged,
+ this, &HighlightSeries::handlePositionChange);
+}
+//! [0]
+
+//! [1]
+void HighlightSeries::handlePositionChange(const QPoint &position)
+{
+ m_position = position;
+
+ if (position == invalidSelectionPosition()) {
+ setVisible(false);
+ return;
+ }
+
+ int halfWidth = m_width / 2;
+ int halfHeight = m_height / 2;
+
+ int startX = position.y() - halfWidth;
+ if (startX < 0 )
+ startX = 0;
+ int endX = position.y() + halfWidth;
+ if (endX > (m_srcWidth - 1))
+ endX = m_srcWidth - 1;
+ int startZ = position.x() - halfHeight;
+ if (startZ < 0 )
+ startZ = 0;
+ int endZ = position.x() + halfHeight;
+ if (endZ > (m_srcHeight - 1))
+ endZ = m_srcHeight - 1;
+
+ QSurfaceDataProxy *srcProxy = m_topographicSeries->dataProxy();
+ const QSurfaceDataArray &srcArray = *srcProxy->array();
+
+ auto *dataArray = new QSurfaceDataArray;
+ dataArray->reserve(endZ - startZ);
+ for (int i = startZ; i < endZ; ++i) {
+ auto *newRow = new QSurfaceDataRow;
+ newRow->reserve(endX - startX);
+ QSurfaceDataRow *srcRow = srcArray.at(i);
+ for (int j = startX; j < endX; ++j) {
+ QVector3D pos = srcRow->at(j).position();
+ pos.setY(pos.y() + 0.1f);
+ newRow->append(QSurfaceDataItem(pos));
+ }
+ dataArray->append(newRow);
+ }
+
+ dataProxy()->resetArray(dataArray);
+ setVisible(true);
+}
+//! [1]
+
+//! [3]
+void HighlightSeries::handleGradientChange(float value)
+{
+ float ratio = m_minHeight / value;
+
+ QLinearGradient gr;
+ gr.setColorAt(0.f, Qt::black);
+ gr.setColorAt(darkGreenPos * ratio, Qt::darkGreen);
+ gr.setColorAt(greenPos * ratio, Qt::green);
+ gr.setColorAt(yellowPos * ratio, Qt::yellow);
+ gr.setColorAt(redPos * ratio, Qt::red);
+ gr.setColorAt(darkRedPos * ratio, Qt::darkRed);
+
+ setBaseGradient(gr);
+ setColorStyle(Q3DTheme::ColorStyleRangeGradient);
+}
+//! [3]
diff --git a/examples/datavisualization/graphgallery/highlightseries.h b/examples/datavisualization/graphgallery/highlightseries.h
new file mode 100644
index 00000000..c74a6b84
--- /dev/null
+++ b/examples/datavisualization/graphgallery/highlightseries.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef HIGHLIGHTSERIES_H
+#define HIGHLIGHTSERIES_H
+
+#include <QtDataVisualization/qsurface3dseries.h>
+
+#include "topographicseries.h"
+
+class HighlightSeries : public QSurface3DSeries
+{
+ Q_OBJECT
+public:
+ explicit HighlightSeries();
+ ~HighlightSeries();
+
+ void setTopographicSeries(TopographicSeries *series);
+ inline void setMinHeight(float height) { m_minHeight = height; }
+
+public Q_SLOTS:
+ void handlePositionChange(const QPoint &position);
+ void handleGradientChange(float value);
+
+private:
+ int m_width = 100;
+ int m_height = 100;
+ int m_srcWidth = 0;
+ int m_srcHeight = 0;
+ QPoint m_position = {};
+ TopographicSeries *m_topographicSeries = nullptr;
+ float m_minHeight = 0.f;
+};
+
+#endif // HIGHLIGHTSERIES_H
diff --git a/examples/datavisualization/graphgallery/main.cpp b/examples/datavisualization/graphgallery/main.cpp
new file mode 100644
index 00000000..4bffa1c1
--- /dev/null
+++ b/examples/datavisualization/graphgallery/main.cpp
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "bargraph.h"
+#include "scattergraph.h"
+#include "surfacegraph.h"
+
+#include <QtWidgets/qapplication.h>
+#include <QtWidgets/qmessagebox.h>
+#include <QtWidgets/qwidget.h>
+#include <QtWidgets/qtabwidget.h>
+#include <QtGui/qscreen.h>
+
+using namespace Qt::StringLiterals;
+
+int main(int argc, char **argv)
+{
+ qputenv("QSG_RHI_BACKEND", "opengl");
+
+ QApplication app(argc, argv);
+
+ // Create a tab widget for creating own tabs for Q3DBars, Q3DScatter, and Q3DSurface
+ QTabWidget tabWidget;
+ tabWidget.setWindowTitle(u"Graph Gallery"_s);
+
+ const QSize screenSize = tabWidget.screen()->size();
+ const QSize minimumGraphSize{screenSize.width() / 2, qRound(screenSize.height() / 1.75)};
+
+ // Create bar graph
+ BarGraph bars;
+ // Create scatter graph
+ ScatterGraph scatter;
+ // Create surface graph
+ SurfaceGraph surface;
+
+ if (!bars.initialize(minimumGraphSize, screenSize)
+ || !scatter.initialize(minimumGraphSize, screenSize)
+ || !surface.initialize(minimumGraphSize, screenSize)) {
+ QMessageBox::warning(nullptr, u"Graph Gallery"_s, u"Couldn't initialize the OpenGL context."_s);
+ return -1;
+ }
+
+ // Add bars widget
+ tabWidget.addTab(bars.barsWidget(), u"Bar Graph"_s);
+ // Add scatter widget
+ tabWidget.addTab(scatter.scatterWidget(), u"Scatter Graph"_s);
+ // Add surface widget
+ tabWidget.addTab(surface.surfaceWidget(), u"Surface Graph"_s);
+
+ tabWidget.show();
+ return app.exec();
+}
diff --git a/examples/datavisualization/graphgallery/rainfalldata.cpp b/examples/datavisualization/graphgallery/rainfalldata.cpp
new file mode 100644
index 00000000..66a2553a
--- /dev/null
+++ b/examples/datavisualization/graphgallery/rainfalldata.cpp
@@ -0,0 +1,117 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "rainfalldata.h"
+#include <QtDataVisualization/q3dscene.h>
+#include <QtDataVisualization/q3dcamera.h>
+#include <QtDataVisualization/qbar3dseries.h>
+#include <QtDataVisualization/q3dtheme.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qfile.h>
+
+using namespace Qt::StringLiterals;
+
+RainfallData::RainfallData()
+{
+ // In data file the months are in numeric format, so create custom list
+ for (int i = 1; i <= 12; ++i)
+ m_numericMonths << QString::number(i);
+
+ m_columnCount = m_numericMonths.size();
+
+ updateYearsList(2010, 2022);
+
+ // Create proxy and series
+ //! [0]
+ m_proxy = new VariantBarDataProxy;
+ m_series = new QBar3DSeries(m_proxy);
+ //! [0]
+
+ m_series->setItemLabelFormat(u"%.1f mm"_s);
+
+ // Create the axes
+ m_rowAxis = new QCategory3DAxis(this);
+ m_colAxis = new QCategory3DAxis(this);
+ m_valueAxis = new QValue3DAxis(this);
+ m_rowAxis->setAutoAdjustRange(true);
+ m_colAxis->setAutoAdjustRange(true);
+ m_valueAxis->setAutoAdjustRange(true);
+
+ // Set axis labels and titles
+ QStringList months{"January", "February", "March", "April",
+ "May", "June", "July", "August", "September", "October",
+ "November","December"};
+ m_rowAxis->setTitle("Year");
+ m_colAxis->setTitle("Month");
+ m_valueAxis->setTitle("rainfall (mm)");
+ m_valueAxis->setSegmentCount(5);
+ m_rowAxis->setLabels(m_years);
+ m_colAxis->setLabels(months);
+ m_rowAxis->setTitleVisible(true);
+ m_colAxis->setTitleVisible(true);
+ m_valueAxis->setTitleVisible(true);
+
+ addDataSet();
+}
+
+RainfallData::~RainfallData()
+{
+ delete m_mapping;
+ delete m_dataSet;
+ delete m_proxy;
+}
+
+void RainfallData::updateYearsList(int start, int end)
+{
+ m_years.clear();
+
+ for (int i = start; i <= end; ++i)
+ m_years << QString::number(i);
+
+ m_rowCount = m_years.size();
+}
+
+//! [1]
+void RainfallData::addDataSet()
+{
+ // Create a new variant data set and data item list
+ m_dataSet = new VariantDataSet;
+ auto *itemList = new VariantDataItemList;
+
+ // Read data from a data file into the data item list
+ QFile dataFile(":/data/raindata.txt");
+ if (dataFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream stream(&dataFile);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine();
+ if (line.startsWith('#')) // Ignore comments
+ continue;
+ const auto strList = QStringView{line}.split(',', Qt::SkipEmptyParts);
+ // Each line has three data items: Year, month, and rainfall value
+ if (strList.size() < 3) {
+ qWarning() << "Invalid row read from data:" << line;
+ continue;
+ }
+ // Store year and month as strings, and rainfall value as double
+ // into a variant data item and add the item to the item list.
+ auto *newItem = new VariantDataItem;
+ for (int i = 0; i < 2; ++i)
+ newItem->append(strList.at(i).trimmed().toString());
+ newItem->append(strList.at(2).trimmed().toDouble());
+ itemList->append(newItem);
+ }
+ } else {
+ qWarning() << "Unable to open data file:" << dataFile.fileName();
+ }
+ //! [1]
+
+ //! [2]
+ // Add items to the data set and set it to the proxy
+ m_dataSet->addItems(itemList);
+ m_proxy->setDataSet(m_dataSet);
+
+ // Create new mapping for the data and set it to the proxy
+ m_mapping = new VariantBarDataMapping(0, 1, 2, m_years, m_numericMonths);
+ m_proxy->setMapping(m_mapping);
+ //! [2]
+}
diff --git a/examples/datavisualization/graphgallery/rainfalldata.h b/examples/datavisualization/graphgallery/rainfalldata.h
new file mode 100644
index 00000000..c71f072b
--- /dev/null
+++ b/examples/datavisualization/graphgallery/rainfalldata.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef RAINFALLDATA_H
+#define RAINFALLDATA_H
+
+#include "variantbardataproxy.h"
+#include <QtDataVisualization/qcategory3daxis.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+
+class RainfallData : public QObject
+{
+ Q_OBJECT
+public:
+ explicit RainfallData();
+ ~RainfallData();
+
+ void addDataSet();
+
+ //! [0]
+ QBar3DSeries *customSeries() { return m_series; }
+ //! [0]
+
+ QValue3DAxis *valueAxis() { return m_valueAxis; }
+ QCategory3DAxis *rowAxis() { return m_rowAxis; }
+ QCategory3DAxis *colAxis() { return m_colAxis; }
+
+private:
+ void updateYearsList(int start, int end);
+ int m_columnCount;
+ int m_rowCount;
+ QStringList m_years;
+ QStringList m_numericMonths;
+ VariantBarDataProxy *m_proxy;
+ VariantBarDataMapping *m_mapping;
+ VariantDataSet *m_dataSet;
+ QBar3DSeries *m_series;
+ QValue3DAxis *m_valueAxis;
+ QCategory3DAxis *m_rowAxis;
+ QCategory3DAxis *m_colAxis;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/scatterdatamodifier.cpp b/examples/datavisualization/graphgallery/scatterdatamodifier.cpp
new file mode 100644
index 00000000..1f3ec7ed
--- /dev/null
+++ b/examples/datavisualization/graphgallery/scatterdatamodifier.cpp
@@ -0,0 +1,191 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "scatterdatamodifier.h"
+#include <QtDataVisualization/qscatterdataproxy.h>
+#include <QtDataVisualization/qvalue3daxis.h>
+#include <QtDataVisualization/q3dscene.h>
+#include <QtDataVisualization/q3dcamera.h>
+#include <QtDataVisualization/qscatter3dseries.h>
+#include <QtDataVisualization/q3dtheme.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qrandom.h>
+#include <QtWidgets/qcombobox.h>
+
+using namespace Qt::StringLiterals;
+
+//#define RANDOM_SCATTER // Uncomment this to switch to random scatter
+
+const int numberOfItems = 10000;
+const float curveDivider = 7.5f;
+const int lowerNumberOfItems = 900;
+const float lowerCurveDivider = 0.75f;
+
+ScatterDataModifier::ScatterDataModifier(Q3DScatter *scatter, QObject *parent) :
+ QObject(parent),
+ m_graph(scatter),
+ m_itemCount(lowerNumberOfItems),
+ m_curveDivider(lowerCurveDivider),
+ //! [7]
+ m_inputHandler(new AxesInputHandler(scatter))
+ //! [7]
+{
+ //! [0]
+ m_graph->activeTheme()->setType(Q3DTheme::ThemeStoneMoss);
+ m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftHigh);
+ m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront);
+ m_graph->scene()->activeCamera()->setZoomLevel(80.f);
+ //! [0]
+
+ //! [1]
+ auto *proxy = new QScatterDataProxy;
+ auto *series = new QScatter3DSeries(proxy);
+ series->setItemLabelFormat(u"@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel"_s);
+ series->setMeshSmooth(m_smooth);
+ m_graph->addSeries(series);
+ //! [1]
+
+ //! [8]
+ // Give ownership of the handler to the graph and make it the active handler
+ m_graph->setActiveInputHandler(m_inputHandler);
+ //! [8]
+
+ //! [9]
+ // Give our axes to the input handler
+ m_inputHandler->setAxes(m_graph->axisX(), m_graph->axisZ(), m_graph->axisY());
+ //! [9]
+
+ //! [2]
+ addData();
+ //! [2]
+}
+
+void ScatterDataModifier::addData()
+{
+ // Configure the axes according to the data
+ //! [3]
+ m_graph->axisX()->setTitle("X");
+ m_graph->axisY()->setTitle("Y");
+ m_graph->axisZ()->setTitle("Z");
+ //! [3]
+
+ //! [4]
+ auto *dataArray = new QScatterDataArray;
+ dataArray->reserve(m_itemCount);
+ //! [4]
+
+#ifdef RANDOM_SCATTER
+ for (int i = 0; i < m_itemCount; ++i)
+ dataArray->append(QScatterDataItem(randVector()));
+#else
+ //! [5]
+ const float limit = qSqrt(m_itemCount) / 2.0f;
+ for (int i = -limit; i < limit; ++i) {
+ for (int j = -limit; j < limit; ++j) {
+ const float x = float(i) + 0.5f;
+ const float y = qCos(qDegreesToRadians(float(i * j) / m_curveDivider));
+ const float z = float(j) + 0.5f;
+ dataArray->append(QScatterDataItem({x, y, z}));
+ }
+ }
+ //! [5]
+#endif
+
+ //! [6]
+ m_graph->seriesList().at(0)->dataProxy()->resetArray(dataArray);
+ //! [6]
+}
+
+void ScatterDataModifier::changeStyle(int style)
+{
+ QComboBox *comboBox = qobject_cast<QComboBox *>(sender());
+ if (comboBox) {
+ m_style = comboBox->itemData(style).value<QAbstract3DSeries::Mesh>();
+ if (!m_graph->seriesList().isEmpty())
+ m_graph->seriesList().at(0)->setMesh(m_style);
+ }
+}
+
+void ScatterDataModifier::setSmoothDots(int smooth)
+{
+ m_smooth = bool(smooth);
+ QScatter3DSeries *series = m_graph->seriesList().at(0);
+ series->setMeshSmooth(m_smooth);
+}
+
+void ScatterDataModifier::changeTheme(int theme)
+{
+ Q3DTheme *currentTheme = m_graph->activeTheme();
+ currentTheme->setType(Q3DTheme::Theme(theme));
+ emit backgroundEnabledChanged(currentTheme->isBackgroundEnabled());
+ emit gridEnabledChanged(currentTheme->isGridEnabled());
+}
+
+void ScatterDataModifier::changePresetCamera()
+{
+ static int preset = Q3DCamera::CameraPresetFrontLow;
+
+ m_graph->scene()->activeCamera()->setCameraPreset((Q3DCamera::CameraPreset)preset);
+
+ if (++preset > Q3DCamera::CameraPresetDirectlyBelow)
+ preset = Q3DCamera::CameraPresetFrontLow;
+}
+
+void ScatterDataModifier::shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality sq)
+{
+ int quality = int(sq);
+ emit shadowQualityChanged(quality); // connected to a checkbox in scattergraph.cpp
+}
+
+void ScatterDataModifier::changeShadowQuality(int quality)
+{
+ QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality);
+ m_graph->setShadowQuality(sq);
+}
+
+void ScatterDataModifier::setBackgroundEnabled(int enabled)
+{
+ m_graph->activeTheme()->setBackgroundEnabled(enabled == Qt::Checked);
+}
+
+void ScatterDataModifier::setGridEnabled(int enabled)
+{
+ m_graph->activeTheme()->setGridEnabled(enabled == Qt::Checked);
+}
+
+void ScatterDataModifier::toggleItemCount()
+{
+ if (m_itemCount == numberOfItems) {
+ m_itemCount = lowerNumberOfItems;
+ m_curveDivider = lowerCurveDivider;
+ } else {
+ m_itemCount = numberOfItems;
+ m_curveDivider = curveDivider;
+ }
+ m_graph->seriesList().at(0)->dataProxy()->resetArray(0);
+ addData();
+}
+
+void ScatterDataModifier::toggleRanges()
+{
+ if (!m_autoAdjust) {
+ m_graph->axisX()->setAutoAdjustRange(true);
+ m_graph->axisZ()->setAutoAdjustRange(true);
+ m_inputHandler->setDragSpeedModifier(1.5f);
+ m_autoAdjust = true;
+ } else {
+ m_graph->axisX()->setRange(-10.0f, 10.0f);
+ m_graph->axisZ()->setRange(-10.0f, 10.0f);
+ m_inputHandler->setDragSpeedModifier(15.0f);
+ m_autoAdjust = false;
+ }
+}
+
+QVector3D ScatterDataModifier::randVector()
+{
+ auto *generator = QRandomGenerator::global();
+ const auto x = float(generator->bounded(100)) / 2.0f - float(generator->bounded(100)) / 2.0f;
+ const auto y = float(generator->bounded(100)) / 100.0f - float(generator->bounded(100)) / 100.0f;
+ const auto z = float(generator->bounded(100)) / 2.0f - float(generator->bounded(100)) / 2.0f;
+ return {x, y, z};
+}
diff --git a/examples/datavisualization/graphgallery/scatterdatamodifier.h b/examples/datavisualization/graphgallery/scatterdatamodifier.h
new file mode 100644
index 00000000..53f557e6
--- /dev/null
+++ b/examples/datavisualization/graphgallery/scatterdatamodifier.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SCATTERDATAMODIFIER_H
+#define SCATTERDATAMODIFIER_H
+
+#include "axesinputhandler.h"
+
+#include <QtDataVisualization/q3dscatter.h>
+#include <QtDataVisualization/qabstract3dseries.h>
+
+class ScatterDataModifier : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ScatterDataModifier(Q3DScatter *scatter, QObject *parent);
+
+ void addData();
+
+public Q_SLOTS:
+ void setBackgroundEnabled(int enabled);
+ void setGridEnabled(int enabled);
+ void setSmoothDots(int smooth);
+ void changePresetCamera();
+ void toggleItemCount();
+ void toggleRanges();
+ void changeStyle(int style);
+ void changeTheme(int theme);
+ void changeShadowQuality(int quality);
+ void shadowQualityUpdatedByVisual(QAbstract3DGraph::ShadowQuality shadowQuality);
+
+Q_SIGNALS:
+ void backgroundEnabledChanged(bool enabled);
+ void gridEnabledChanged(bool enabled);
+ void shadowQualityChanged(int quality);
+
+private:
+ QVector3D randVector();
+ Q3DScatter *m_graph = nullptr;
+ QAbstract3DSeries::Mesh m_style = QAbstract3DSeries::MeshSphere;
+ bool m_smooth = true;
+ int m_itemCount;
+ float m_curveDivider;
+
+ AxesInputHandler *m_inputHandler;
+ bool m_autoAdjust = true;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/scattergraph.cpp b/examples/datavisualization/graphgallery/scattergraph.cpp
new file mode 100644
index 00000000..a426c10a
--- /dev/null
+++ b/examples/datavisualization/graphgallery/scattergraph.cpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "scattergraph.h"
+#include "scatterdatamodifier.h"
+
+#include <QtWidgets/qboxlayout.h>
+#include <QtWidgets/qcheckbox.h>
+#include <QtWidgets/qcombobox.h>
+#include <QtWidgets/qlabel.h>
+#include <QtWidgets/qcommandlinkbutton.h>
+
+using namespace Qt::StringLiterals;
+
+ScatterGraph::ScatterGraph()
+{
+ m_scatterGraph = new Q3DScatter();
+}
+
+ScatterGraph::~ScatterGraph() = default;
+
+bool ScatterGraph::initialize(const QSize &minimumGraphSize, const QSize &maximumGraphSize)
+{
+ if (!m_scatterGraph->hasContext())
+ return false;
+
+ m_scatterWidget = new QWidget;
+ auto *hLayout = new QHBoxLayout(m_scatterWidget);
+ m_container = QWidget::createWindowContainer(m_scatterGraph, m_scatterWidget);
+ m_container->setMinimumSize(minimumGraphSize);
+ m_container->setMaximumSize(maximumGraphSize);
+ m_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_container->setFocusPolicy(Qt::StrongFocus);
+ hLayout->addWidget(m_container, 1);
+
+ auto *vLayout = new QVBoxLayout();
+ hLayout->addLayout(vLayout);
+
+ auto *cameraButton = new QCommandLinkButton(m_scatterWidget);
+ cameraButton->setText(u"Change camera preset"_s);
+ cameraButton->setDescription(u"Switch between a number of preset camera positions"_s);
+ cameraButton->setIconSize(QSize(0, 0));
+
+ auto *itemCountButton = new QCommandLinkButton(m_scatterWidget);
+ itemCountButton->setText(u"Toggle item count"_s);
+ itemCountButton->setDescription(u"Switch between 900 and 10000 data points"_s);
+ itemCountButton->setIconSize(QSize(0, 0));
+
+ auto *rangeButton = new QCommandLinkButton(m_scatterWidget);
+ rangeButton->setText(u"Toggle axis ranges"_s);
+ rangeButton->setDescription(u"Switch between automatic axis ranges and preset ranges"_s);
+ rangeButton->setIconSize(QSize(0, 0));
+
+ auto *backgroundCheckBox = new QCheckBox(m_scatterWidget);
+ backgroundCheckBox->setText(u"Show background"_s);
+ backgroundCheckBox->setChecked(true);
+
+ auto *gridCheckBox = new QCheckBox(m_scatterWidget);
+ gridCheckBox->setText(u"Show grid"_s);
+ gridCheckBox->setChecked(true);
+
+ auto *smoothCheckBox = new QCheckBox(m_scatterWidget);
+ smoothCheckBox->setText(u"Smooth dots"_s);
+ smoothCheckBox->setChecked(true);
+
+ auto *itemStyleList = new QComboBox(m_scatterWidget);
+ itemStyleList->addItem(u"Sphere"_s, QAbstract3DSeries::MeshSphere);
+ itemStyleList->addItem(u"Cube"_s, QAbstract3DSeries::MeshCube);
+ itemStyleList->addItem(u"Minimal"_s, QAbstract3DSeries::MeshMinimal);
+ itemStyleList->addItem(u"Point"_s, QAbstract3DSeries::MeshPoint);
+ itemStyleList->setCurrentIndex(0);
+
+ auto *themeList = new QComboBox(m_scatterWidget);
+ themeList->addItem(u"Qt"_s);
+ themeList->addItem(u"Primary Colors"_s);
+ themeList->addItem(u"Digia"_s);
+ themeList->addItem(u"Stone Moss"_s);
+ themeList->addItem(u"Army Blue"_s);
+ themeList->addItem(u"Retro"_s);
+ themeList->addItem(u"Ebony"_s);
+ themeList->addItem(u"Isabelle"_s);
+ themeList->setCurrentIndex(3);
+
+ auto *shadowQuality = new QComboBox(m_scatterWidget);
+ shadowQuality->addItem(u"None"_s);
+ shadowQuality->addItem(u"Low"_s);
+ shadowQuality->addItem(u"Medium"_s);
+ shadowQuality->addItem(u"High"_s);
+ shadowQuality->addItem(u"Low Soft"_s);
+ shadowQuality->addItem(u"Medium Soft"_s);
+ shadowQuality->addItem(u"High Soft"_s);
+ shadowQuality->setCurrentIndex(6);
+
+ vLayout->addWidget(cameraButton);
+ vLayout->addWidget(itemCountButton);
+ vLayout->addWidget(rangeButton);
+ vLayout->addWidget(backgroundCheckBox);
+ vLayout->addWidget(gridCheckBox);
+ vLayout->addWidget(smoothCheckBox);
+ vLayout->addWidget(new QLabel(u"Change dot style"_s));
+ vLayout->addWidget(itemStyleList);
+ vLayout->addWidget(new QLabel(u"Change theme"_s));
+ vLayout->addWidget(themeList);
+ vLayout->addWidget(new QLabel(u"Adjust shadow quality"_s));
+ vLayout->addWidget(shadowQuality, 1, Qt::AlignTop);
+
+ auto *modifier = new ScatterDataModifier(m_scatterGraph, this);
+
+ QObject::connect(cameraButton, &QCommandLinkButton::clicked, modifier,
+ &ScatterDataModifier::changePresetCamera);
+ QObject::connect(itemCountButton, &QCommandLinkButton::clicked, modifier,
+ &ScatterDataModifier::toggleItemCount);
+ QObject::connect(rangeButton, &QCommandLinkButton::clicked, modifier,
+ &ScatterDataModifier::toggleRanges);
+
+ QObject::connect(backgroundCheckBox, &QCheckBox::stateChanged, modifier,
+ &ScatterDataModifier::setBackgroundEnabled);
+ QObject::connect(gridCheckBox, &QCheckBox::stateChanged, modifier,
+ &ScatterDataModifier::setGridEnabled);
+ QObject::connect(smoothCheckBox, &QCheckBox::stateChanged, modifier,
+ &ScatterDataModifier::setSmoothDots);
+
+ QObject::connect(modifier, &ScatterDataModifier::backgroundEnabledChanged,
+ backgroundCheckBox, &QCheckBox::setChecked);
+ QObject::connect(modifier, &ScatterDataModifier::gridEnabledChanged,
+ gridCheckBox, &QCheckBox::setChecked);
+ QObject::connect(itemStyleList, &QComboBox::currentIndexChanged, modifier,
+ &ScatterDataModifier::changeStyle);
+
+ QObject::connect(themeList, &QComboBox::currentIndexChanged, modifier,
+ &ScatterDataModifier::changeTheme);
+
+ QObject::connect(shadowQuality, &QComboBox::currentIndexChanged, modifier,
+ &ScatterDataModifier::changeShadowQuality);
+
+ QObject::connect(modifier, &ScatterDataModifier::shadowQualityChanged, shadowQuality,
+ &QComboBox::setCurrentIndex);
+ QObject::connect(m_scatterGraph, &Q3DScatter::shadowQualityChanged, modifier,
+ &ScatterDataModifier::shadowQualityUpdatedByVisual);
+
+ return true;
+}
diff --git a/examples/datavisualization/graphgallery/scattergraph.h b/examples/datavisualization/graphgallery/scattergraph.h
new file mode 100644
index 00000000..eb8c7c52
--- /dev/null
+++ b/examples/datavisualization/graphgallery/scattergraph.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SCATTERGRAPH_H
+#define SCATTERGRAPH_H
+
+#include <QtCore/qobject.h>
+#include <QtDataVisualization/q3dscatter.h>
+
+class ScatterGraph : public QObject
+{
+ Q_OBJECT
+public:
+ ScatterGraph();
+ ~ScatterGraph();
+
+ bool initialize(const QSize &minimumGraphSize, const QSize &maximumGraphSize);
+ QWidget *scatterWidget() { return m_scatterWidget; }
+
+private:
+ Q3DScatter *m_scatterGraph = nullptr;
+ QWidget *m_container = nullptr;
+ QWidget *m_scatterWidget = nullptr;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/surfacegraph.cpp b/examples/datavisualization/graphgallery/surfacegraph.cpp
new file mode 100644
index 00000000..88cbc72f
--- /dev/null
+++ b/examples/datavisualization/graphgallery/surfacegraph.cpp
@@ -0,0 +1,346 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "surfacegraph.h"
+#include "surfacegraphmodifier.h"
+
+#include <QtWidgets/qboxlayout.h>
+#include <QtWidgets/qcheckbox.h>
+#include <QtWidgets/qcombobox.h>
+#include <QtWidgets/qradiobutton.h>
+#include <QtWidgets/qgroupbox.h>
+#include <QtWidgets/qlabel.h>
+#include <QtWidgets/qcommandlinkbutton.h>
+#include <QtGui/qpainter.h>
+
+using namespace Qt::StringLiterals;
+
+static QPixmap gradientBtoYPB_Pixmap()
+{
+ QLinearGradient grBtoY(0, 0, 1, 100);
+ grBtoY.setColorAt(1.f, Qt::black);
+ grBtoY.setColorAt(0.67f, Qt::blue);
+ grBtoY.setColorAt(0.33f, Qt::red);
+ grBtoY.setColorAt(0.f, Qt::yellow);
+ QPixmap pm(24, 100);
+ QPainter pmp(&pm);
+ pmp.setBrush(QBrush(grBtoY));
+ pmp.setPen(Qt::NoPen);
+ pmp.drawRect(0, 0, 24, 100);
+ return pm;
+}
+
+static QPixmap gradientGtoRPB_Pixmap()
+{
+ QLinearGradient grGtoR(0, 0, 1, 100);
+ grGtoR.setColorAt(1.f, Qt::darkGreen);
+ grGtoR.setColorAt(0.5f, Qt::yellow);
+ grGtoR.setColorAt(0.2f, Qt::red);
+ grGtoR.setColorAt(0.f, Qt::darkRed);
+ QPixmap pm(24, 100);
+ QPainter pmp(&pm);
+ pmp.setBrush(QBrush(grGtoR));
+ pmp.drawRect(0, 0, 24, 100);
+ return pm;
+}
+
+static QPixmap highlightPixmap()
+{
+ constexpr int height = 400;
+ constexpr int width = 110;
+ constexpr int border = 10;
+ QLinearGradient gr(0, 0, 1, height - 2 * border);
+ gr.setColorAt(1.f, Qt::black);
+ gr.setColorAt(0.8f, Qt::darkGreen);
+ gr.setColorAt(0.6f, Qt::green);
+ gr.setColorAt(0.4f, Qt::yellow);
+ gr.setColorAt(0.2f, Qt::red);
+ gr.setColorAt(0.f, Qt::darkRed);
+
+ QPixmap pmHighlight(width, height);
+ pmHighlight.fill(Qt::transparent);
+ QPainter pmpHighlight(&pmHighlight);
+ pmpHighlight.setBrush(QBrush(gr));
+ pmpHighlight.setPen(Qt::NoPen);
+ pmpHighlight.drawRect(border, border, 35, height - 2 * border);
+ pmpHighlight.setPen(Qt::black);
+ int step = (height - 2 * border) / 5;
+ for (int i = 0; i < 6; ++i) {
+ int yPos = i * step + border;
+ pmpHighlight.drawLine(border, yPos, 55, yPos);
+ const int height = 550 - (i * 110);
+ pmpHighlight.drawText(60, yPos + 2, QString::number(height) + u" m"_s);
+ }
+ return pmHighlight;
+}
+
+SurfaceGraph::SurfaceGraph()
+{
+ m_surfaceGraph = new Q3DSurface();
+}
+
+SurfaceGraph::~SurfaceGraph() = default;
+
+bool SurfaceGraph::initialize(const QSize &minimumGraphSize, const QSize &maximumGraphSize)
+{
+ if (!m_surfaceGraph->hasContext())
+ return false;
+
+ m_surfaceWidget = new QWidget;
+ auto *hLayout = new QHBoxLayout(m_surfaceWidget);
+ m_container = QWidget::createWindowContainer(m_surfaceGraph, m_surfaceWidget);
+ m_container->setMinimumSize(minimumGraphSize);
+ m_container->setMaximumSize(maximumGraphSize);
+ m_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_container->setFocusPolicy(Qt::StrongFocus);
+ hLayout->addWidget(m_container, 1);
+
+ auto *vLayout = new QVBoxLayout();
+ hLayout->addLayout(vLayout);
+ vLayout->setAlignment(Qt::AlignTop);
+
+ // Create control widgets
+ auto *modelGroupBox = new QGroupBox(u"Model"_s);
+
+ auto *sqrtSinModelRB = new QRadioButton(m_surfaceWidget);
+ sqrtSinModelRB->setText(u"Sqrt && Sin"_s);
+ sqrtSinModelRB->setChecked(false);
+
+ auto *heightMapModelRB = new QRadioButton(m_surfaceWidget);
+ heightMapModelRB->setText(u"Multiseries\nHeight Map"_s);
+ heightMapModelRB->setChecked(false);
+
+ auto *texturedModelRB = new QRadioButton(m_surfaceWidget);
+ texturedModelRB->setText(u"Textured\nTopography"_s);
+ texturedModelRB->setChecked(false);
+
+ auto *modelVBox = new QVBoxLayout;
+ modelVBox->addWidget(sqrtSinModelRB);
+ modelVBox->addWidget(heightMapModelRB);
+ modelVBox->addWidget(texturedModelRB);
+ modelGroupBox->setLayout(modelVBox);
+
+ auto *selectionGroupBox = new QGroupBox(u"Graph Selection Mode"_s);
+
+ auto *modeNoneRB = new QRadioButton(m_surfaceWidget);
+ modeNoneRB->setText(u"No selection"_s);
+ modeNoneRB->setChecked(false);
+
+ auto *modeItemRB = new QRadioButton(m_surfaceWidget);
+ modeItemRB->setText(u"Item"_s);
+ modeItemRB->setChecked(false);
+
+ auto *modeSliceRowRB = new QRadioButton(m_surfaceWidget);
+ modeSliceRowRB->setText(u"Row Slice"_s);
+ modeSliceRowRB->setChecked(false);
+
+ auto *modeSliceColumnRB = new QRadioButton(m_surfaceWidget);
+ modeSliceColumnRB->setText(u"Column Slice"_s);
+ modeSliceColumnRB->setChecked(false);
+
+ auto *selectionVBox = new QVBoxLayout;
+ selectionVBox->addWidget(modeNoneRB);
+ selectionVBox->addWidget(modeItemRB);
+ selectionVBox->addWidget(modeSliceRowRB);
+ selectionVBox->addWidget(modeSliceColumnRB);
+ selectionGroupBox->setLayout(selectionVBox);
+
+ auto *axisGroupBox = new QGroupBox(u"Axis ranges"_s);
+
+ auto *axisMinSliderX = new QSlider(Qt::Horizontal);
+ axisMinSliderX->setMinimum(0);
+ axisMinSliderX->setTickInterval(1);
+ axisMinSliderX->setEnabled(true);
+ auto *axisMaxSliderX = new QSlider(Qt::Horizontal);
+ axisMaxSliderX->setMinimum(1);
+ axisMaxSliderX->setTickInterval(1);
+ axisMaxSliderX->setEnabled(true);
+ auto *axisMinSliderZ = new QSlider(Qt::Horizontal);
+ axisMinSliderZ->setMinimum(0);
+ axisMinSliderZ->setTickInterval(1);
+ axisMinSliderZ->setEnabled(true);
+ auto *axisMaxSliderZ = new QSlider(Qt::Horizontal);
+ axisMaxSliderZ->setMinimum(1);
+ axisMaxSliderZ->setTickInterval(1);
+ axisMaxSliderZ->setEnabled(true);
+
+ auto *axisVBox = new QVBoxLayout;
+ axisVBox->addWidget(new QLabel(u"Column range"_s));
+ axisVBox->addWidget(axisMinSliderX);
+ axisVBox->addWidget(axisMaxSliderX);
+ axisVBox->addWidget(new QLabel(u"Row range"_s));
+ axisVBox->addWidget(axisMinSliderZ);
+ axisVBox->addWidget(axisMaxSliderZ);
+ axisGroupBox->setLayout(axisVBox);
+
+ // Mode-dependent controls
+ // sqrt-sin
+ auto *colorGroupBox = new QGroupBox(u"Custom gradient"_s);
+
+ QPixmap pixmap = gradientBtoYPB_Pixmap();
+ auto *gradientBtoYPB = new QPushButton(m_surfaceWidget);
+ gradientBtoYPB->setIcon(QIcon(pixmap));
+ gradientBtoYPB->setIconSize(pixmap.size());
+
+ pixmap = gradientGtoRPB_Pixmap();
+ auto *gradientGtoRPB = new QPushButton(m_surfaceWidget);
+ gradientGtoRPB->setIcon(QIcon(pixmap));
+ gradientGtoRPB->setIconSize(pixmap.size());
+ auto *colorHBox = new QHBoxLayout;
+ colorHBox->addWidget(gradientBtoYPB);
+ colorHBox->addWidget(gradientGtoRPB);
+ colorGroupBox->setLayout(colorHBox);
+
+ // Multiseries heightmap
+ auto *showGroupBox = new QGroupBox(u"_show Object"_s);
+ showGroupBox->setVisible(false);
+
+ auto *checkboxShowOilRigOne = new QCheckBox(u"Oil Rig 1"_s);
+ checkboxShowOilRigOne->setChecked(true);
+
+ auto *checkboxShowOilRigTwo = new QCheckBox(u"Oil Rig 2"_s);
+ checkboxShowOilRigTwo->setChecked(true);
+
+ auto *checkboxShowRefinery = new QCheckBox(u"Refinery"_s);
+
+ auto *showVBox = new QVBoxLayout;
+ showVBox->addWidget(checkboxShowOilRigOne);
+ showVBox->addWidget(checkboxShowOilRigTwo);
+ showVBox->addWidget(checkboxShowRefinery);
+ showGroupBox->setLayout(showVBox);
+
+ auto *visualsGroupBox = new QGroupBox(u"Visuals"_s);
+ visualsGroupBox->setVisible(false);
+
+ auto *checkboxVisualsSeeThrough = new QCheckBox(u"See-Through"_s);
+
+ auto *checkboxHighlightOil = new QCheckBox(u"Highlight Oil"_s);
+
+ auto *checkboxShowShadows = new QCheckBox(u"Shadows"_s);
+ checkboxShowShadows->setChecked(true);
+
+ auto *visualVBox = new QVBoxLayout;
+ visualVBox->addWidget(checkboxVisualsSeeThrough);
+ visualVBox->addWidget(checkboxHighlightOil);
+ visualVBox->addWidget(checkboxShowShadows);
+ visualsGroupBox->setLayout(visualVBox);
+
+ auto *labelSelection = new QLabel(u"Selection:"_s);
+ labelSelection->setVisible(false);
+
+ auto *labelSelectedItem = new QLabel(u"Nothing"_s);
+ labelSelectedItem->setVisible(false);
+
+ // Textured topography heightmap
+ auto *enableTexture = new QCheckBox(u"Surface texture"_s);
+ enableTexture->setVisible(false);
+
+ auto *label = new QLabel(m_surfaceWidget);
+ label->setPixmap(highlightPixmap());
+
+ auto *heightMapGroupBox = new QGroupBox(u"Highlight color map"_s);
+ auto *colorMapVBox = new QVBoxLayout;
+ colorMapVBox->addWidget(label);
+ heightMapGroupBox->setLayout(colorMapVBox);
+ heightMapGroupBox->setVisible(false);
+
+ // Populate vertical layout
+ // Common
+ vLayout->addWidget(modelGroupBox);
+ vLayout->addWidget(selectionGroupBox);
+ vLayout->addWidget(axisGroupBox);
+
+ // Sqrt Sin
+ vLayout->addWidget(colorGroupBox);
+
+ // Multiseries heightmap
+ vLayout->addWidget(showGroupBox);
+ vLayout->addWidget(visualsGroupBox);
+ vLayout->addWidget(labelSelection);
+ vLayout->addWidget(labelSelectedItem);
+
+ // Textured topography
+ vLayout->addWidget(heightMapGroupBox);
+ vLayout->addWidget(enableTexture);
+
+ // Create the controller
+ auto *modifier = new SurfaceGraphModifier(m_surfaceGraph, labelSelectedItem, this);
+
+ // Connect widget controls to controller
+ QObject::connect(heightMapModelRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::enableHeightMapModel);
+ QObject::connect(sqrtSinModelRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::enableSqrtSinModel);
+ QObject::connect(texturedModelRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::enableTopographyModel);
+
+ QObject::connect(modeNoneRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::toggleModeNone);
+ QObject::connect(modeItemRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::toggleModeItem);
+ QObject::connect(modeSliceRowRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::toggleModeSliceRow);
+ QObject::connect(modeSliceColumnRB, &QRadioButton::toggled,
+ modifier, &SurfaceGraphModifier::toggleModeSliceColumn);
+
+ QObject::connect(axisMinSliderX, &QSlider::valueChanged,
+ modifier, &SurfaceGraphModifier::adjustXMin);
+ QObject::connect(axisMaxSliderX, &QSlider::valueChanged,
+ modifier, &SurfaceGraphModifier::adjustXMax);
+ QObject::connect(axisMinSliderZ, &QSlider::valueChanged,
+ modifier, &SurfaceGraphModifier::adjustZMin);
+ QObject::connect(axisMaxSliderZ, &QSlider::valueChanged,
+ modifier, &SurfaceGraphModifier::adjustZMax);
+
+ // Mode dependent connections
+ QObject::connect(gradientBtoYPB, &QPushButton::pressed,
+ modifier, &SurfaceGraphModifier::setBlackToYellowGradient);
+ QObject::connect(gradientGtoRPB, &QPushButton::pressed,
+ modifier, &SurfaceGraphModifier::setGreenToRedGradient);
+
+ QObject::connect(checkboxShowOilRigOne, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleItemOne);
+ QObject::connect(checkboxShowOilRigTwo, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleItemTwo);
+ QObject::connect(checkboxShowRefinery, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleItemThree);
+
+ QObject::connect(checkboxVisualsSeeThrough, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleSeeThrough);
+ QObject::connect(checkboxHighlightOil, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleOilHighlight);
+ QObject::connect(checkboxShowShadows, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleShadows);
+
+ QObject::connect(enableTexture, &QCheckBox::stateChanged,
+ modifier, &SurfaceGraphModifier::toggleSurfaceTexture);
+
+ // Connections to disable features depending on mode
+ QObject::connect(sqrtSinModelRB, &QRadioButton::toggled,
+ colorGroupBox, &QGroupBox::setVisible);
+
+ QObject::connect(heightMapModelRB, &QRadioButton::toggled,
+ showGroupBox, &QGroupBox::setVisible);
+ QObject::connect(heightMapModelRB, &QRadioButton::toggled,
+ visualsGroupBox, &QGroupBox::setVisible);
+ QObject::connect(heightMapModelRB, &QRadioButton::toggled,
+ labelSelection, &QLabel::setVisible);
+ QObject::connect(heightMapModelRB, &QRadioButton::toggled,
+ labelSelectedItem, &QLabel::setVisible);
+
+ QObject::connect(texturedModelRB, &QRadioButton::toggled,
+ enableTexture, &QLabel::setVisible);
+ QObject::connect(texturedModelRB, &QRadioButton::toggled,
+ heightMapGroupBox, &QGroupBox::setVisible);
+
+ modifier->setAxisMinSliderX(axisMinSliderX);
+ modifier->setAxisMaxSliderX(axisMaxSliderX);
+ modifier->setAxisMinSliderZ(axisMinSliderZ);
+ modifier->setAxisMaxSliderZ(axisMaxSliderZ);
+
+ sqrtSinModelRB->setChecked(true);
+ modeItemRB->setChecked(true);
+ enableTexture->setChecked(true);
+
+ return true;
+}
diff --git a/examples/datavisualization/graphgallery/surfacegraph.h b/examples/datavisualization/graphgallery/surfacegraph.h
new file mode 100644
index 00000000..5ec29930
--- /dev/null
+++ b/examples/datavisualization/graphgallery/surfacegraph.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SURFACEGRAPH_H
+#define SURFACEGRAPH_H
+
+#include <QtCore/qobject.h>
+#include <QtDataVisualization/q3dsurface.h>
+
+class SurfaceGraph : public QObject
+{
+ Q_OBJECT
+public:
+ SurfaceGraph();
+ ~SurfaceGraph();
+
+ bool initialize(const QSize &minimumGraphSize, const QSize &maximumGraphSize);
+ QWidget *surfaceWidget() { return m_surfaceWidget; }
+
+private:
+ Q3DSurface *m_surfaceGraph = nullptr;
+ QWidget *m_container = nullptr;
+ QWidget *m_surfaceWidget = nullptr;
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/surfacegraphmodifier.cpp b/examples/datavisualization/graphgallery/surfacegraphmodifier.cpp
new file mode 100644
index 00000000..190a96b9
--- /dev/null
+++ b/examples/datavisualization/graphgallery/surfacegraphmodifier.cpp
@@ -0,0 +1,647 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "surfacegraphmodifier.h"
+#include "highlightseries.h"
+#include "topographicseries.h"
+#include "custominputhandler.h"
+
+#include <QtDataVisualization/qvalue3daxis.h>
+#include <QtDataVisualization/q3dtheme.h>
+#include <QtGui/qimage.h>
+#include <QtCore/qmath.h>
+
+using namespace Qt::StringLiterals;
+
+const int sampleCountX = 150;
+const int sampleCountZ = 150;
+const int heightMapGridStepX = 6;
+const int heightMapGridStepZ = 6;
+const float sampleMin = -8.f;
+const float sampleMax = 8.f;
+
+const float areaWidth = 8000.f;
+const float areaHeight = 8000.f;
+const float aspectRatio = 0.1389f;
+const float minRange = areaWidth * 0.49f;
+
+SurfaceGraphModifier::SurfaceGraphModifier(Q3DSurface *surface, QLabel *label, QObject *parent) :
+ QObject(parent),
+ m_graph(surface),
+ m_textField(label)
+{
+ m_graph->scene()->activeCamera()->setZoomLevel(85.f);
+ m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetIsometricRight);
+ m_graph->activeTheme()->setType(Q3DTheme::ThemeRetro);
+
+ m_graph->setAxisX(new QValue3DAxis);
+ m_graph->setAxisY(new QValue3DAxis);
+ m_graph->setAxisZ(new QValue3DAxis);
+
+ //
+ // Sqrt Sin
+ //
+ //! [0]
+ m_sqrtSinProxy = new QSurfaceDataProxy();
+ m_sqrtSinSeries = new QSurface3DSeries(m_sqrtSinProxy);
+ //! [0]
+ fillSqrtSinProxy();
+
+ //
+ // Multisurface heightmap
+ //
+ //! [2]
+ // Create the first surface layer
+ QImage heightMapImageOne(":/data/layer_1.png");
+ m_heightMapProxyOne = new QHeightMapSurfaceDataProxy(heightMapImageOne);
+ m_heightMapSeriesOne = new QSurface3DSeries(m_heightMapProxyOne);
+ m_heightMapSeriesOne->setItemLabelFormat(u"(@xLabel, @zLabel): @yLabel"_s);
+ m_heightMapProxyOne->setValueRanges(34.f, 40.f, 18.f, 24.f);
+ //! [2]
+
+ // Create the other 2 surface layers
+ QImage heightMapImageTwo(":/data/layer_2.png");
+ m_heightMapProxyTwo = new QHeightMapSurfaceDataProxy(heightMapImageTwo);
+ m_heightMapSeriesTwo = new QSurface3DSeries(m_heightMapProxyTwo);
+ m_heightMapSeriesTwo->setItemLabelFormat(u"(@xLabel, @zLabel): @yLabel"_s);
+ m_heightMapProxyTwo->setValueRanges(34.f, 40.f, 18.f, 24.f);
+
+ QImage heightMapImageThree(":/data/layer_3.png");
+ m_heightMapProxyThree = new QHeightMapSurfaceDataProxy(heightMapImageThree);
+ m_heightMapSeriesThree = new QSurface3DSeries(m_heightMapProxyThree);
+ m_heightMapSeriesThree->setItemLabelFormat(u"(@xLabel, @zLabel): @yLabel"_s);
+ m_heightMapProxyThree->setValueRanges(34.f, 40.f, 18.f, 24.f);
+
+ // The images are the same size, so it's enough to get the dimensions from one
+ m_heightMapWidth = heightMapImageOne.width();
+ m_heightMapHeight = heightMapImageOne.height();
+
+ // Set the gradients for multi-surface layers
+ QLinearGradient grOne;
+ grOne.setColorAt(0.f, Qt::black);
+ grOne.setColorAt(0.38f, Qt::darkYellow);
+ grOne.setColorAt(0.39f, Qt::darkGreen);
+ grOne.setColorAt(0.5f, Qt::darkGray);
+ grOne.setColorAt(1.f, Qt::gray);
+ m_heightMapSeriesOne->setBaseGradient(grOne);
+ m_heightMapSeriesOne->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
+
+ QLinearGradient grTwo;
+ grTwo.setColorAt(0.39f, Qt::blue);
+ grTwo.setColorAt(0.4f, Qt::white);
+ m_heightMapSeriesTwo->setBaseGradient(grTwo);
+ m_heightMapSeriesTwo->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
+
+ QLinearGradient grThree;
+ grThree.setColorAt(0.f, Qt::white);
+ grThree.setColorAt(0.05f, Qt::black);
+ m_heightMapSeriesThree->setBaseGradient(grThree);
+ m_heightMapSeriesThree->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
+
+ // Custom items and label
+ connect(m_graph, &QAbstract3DGraph::selectedElementChanged,
+ this, &SurfaceGraphModifier::handleElementSelected);
+
+ m_selectionAnimation = new QPropertyAnimation(this);
+ m_selectionAnimation->setPropertyName("scaling");
+ m_selectionAnimation->setDuration(500);
+ m_selectionAnimation->setLoopCount(-1);
+
+ QFont titleFont = QFont("Century Gothic", 30);
+ titleFont.setBold(true);
+ m_titleLabel = new QCustom3DLabel("Oil Rigs on Imaginary Sea", titleFont,
+ QVector3D(0.f, 1.2f, 0.f),
+ QVector3D(1.f, 1.f, 0.f),
+ QQuaternion());
+ m_titleLabel->setPositionAbsolute(true);
+ m_titleLabel->setFacingCamera(true);
+ m_titleLabel->setBackgroundColor(QColor(0x66cdaa));
+ m_graph->addCustomItem(m_titleLabel);
+ m_titleLabel->setVisible(false);
+
+ // Make two of the custom object visible
+ toggleItemOne(true);
+ toggleItemTwo(true);
+
+ //
+ // Topographic map
+ //
+ m_topography = new TopographicSeries();
+ m_topography->setTopographyFile(":/data/topography.png", areaWidth, areaHeight);
+ m_topography->setItemLabelFormat(u"@yLabel m"_s);
+
+ m_highlight = new HighlightSeries();
+ m_highlight->setTopographicSeries(m_topography);
+ m_highlight->setMinHeight(minRange * aspectRatio);
+ m_highlight->handleGradientChange(areaWidth * aspectRatio);
+ //! [16]
+ QObject::connect(m_graph->axisY(), &QValue3DAxis::maxChanged,
+ m_highlight, &HighlightSeries::handleGradientChange);
+ //! [16]
+
+ m_customInputHandler = new CustomInputHandler(m_graph);
+ m_customInputHandler->setHighlightSeries(m_highlight);
+ m_customInputHandler->setAxes(m_graph->axisX(), m_graph->axisY(), m_graph->axisZ());
+ m_customInputHandler->setLimits(0.f, areaWidth, minRange);
+ m_customInputHandler->setAspectRatio(aspectRatio);
+}
+
+void SurfaceGraphModifier::fillSqrtSinProxy()
+{
+ float stepX = (sampleMax - sampleMin) / float(sampleCountX - 1);
+ float stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1);
+
+ //! [1]
+ auto *dataArray = new QSurfaceDataArray;
+ dataArray->reserve(sampleCountZ);
+ for (int i = 0 ; i < sampleCountZ ; ++i) {
+ auto *newRow = new QSurfaceDataRow;
+ newRow->reserve(sampleCountX);
+ // Keep values within range bounds, since just adding step can cause minor drift due
+ // to the rounding errors.
+ float z = qMin(sampleMax, (i * stepZ + sampleMin));
+ for (int j = 0; j < sampleCountX; ++j) {
+ float x = qMin(sampleMax, (j * stepX + sampleMin));
+ float R = qSqrt(z * z + x * x) + 0.01f;
+ float y = (qSin(R) / R + 0.24f) * 1.61f;
+ newRow->append(QSurfaceDataItem({x, y, z}));
+ }
+ dataArray->append(newRow);
+ }
+
+ m_sqrtSinProxy->resetArray(dataArray);
+ //! [1]
+}
+
+void SurfaceGraphModifier::enableSqrtSinModel(bool enable)
+{
+ if (enable) {
+ //! [3]
+ m_sqrtSinSeries->setDrawMode(QSurface3DSeries::DrawSurfaceAndWireframe);
+ m_sqrtSinSeries->setFlatShadingEnabled(true);
+
+ m_graph->axisX()->setLabelFormat("%.2f");
+ m_graph->axisZ()->setLabelFormat("%.2f");
+ m_graph->axisX()->setRange(sampleMin, sampleMax);
+ m_graph->axisY()->setRange(0.f, 2.f);
+ m_graph->axisZ()->setRange(sampleMin, sampleMax);
+ m_graph->axisX()->setLabelAutoRotation(30.f);
+ m_graph->axisY()->setLabelAutoRotation(90.f);
+ m_graph->axisZ()->setLabelAutoRotation(30.f);
+
+ m_graph->removeSeries(m_heightMapSeriesOne);
+ m_graph->removeSeries(m_heightMapSeriesTwo);
+ m_graph->removeSeries(m_heightMapSeriesThree);
+ m_graph->removeSeries(m_topography);
+ m_graph->removeSeries(m_highlight);
+
+ m_graph->addSeries(m_sqrtSinSeries);
+ //! [3]
+
+ m_titleLabel->setVisible(false);
+ m_graph->axisX()->setTitleVisible(false);
+ m_graph->axisY()->setTitleVisible(false);
+ m_graph->axisZ()->setTitleVisible(false);
+
+ m_graph->axisX()->setTitle({});
+ m_graph->axisY()->setTitle({});
+ m_graph->axisZ()->setTitle({});
+
+ m_graph->setActiveInputHandler(m_defaultInputHandler);
+
+ //! [6]
+ // Reset range sliders for Sqrt & Sin
+ m_rangeMinX = sampleMin;
+ m_rangeMinZ = sampleMin;
+ m_stepX = (sampleMax - sampleMin) / float(sampleCountX - 1);
+ m_stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1);
+ m_axisMinSliderX->setMinimum(0);
+ m_axisMinSliderX->setMaximum(sampleCountX - 2);
+ m_axisMinSliderX->setValue(0);
+ m_axisMaxSliderX->setMinimum(1);
+ m_axisMaxSliderX->setMaximum(sampleCountX - 1);
+ m_axisMaxSliderX->setValue(sampleCountX - 1);
+ m_axisMinSliderZ->setMinimum(0);
+ m_axisMinSliderZ->setMaximum(sampleCountZ - 2);
+ m_axisMinSliderZ->setValue(0);
+ m_axisMaxSliderZ->setMinimum(1);
+ m_axisMaxSliderZ->setMaximum(sampleCountZ - 1);
+ m_axisMaxSliderZ->setValue(sampleCountZ - 1);
+ //! [6]
+ }
+}
+
+void SurfaceGraphModifier::enableHeightMapModel(bool enable)
+{
+ if (enable) {
+ m_heightMapSeriesOne->setDrawMode(QSurface3DSeries::DrawSurface);
+ m_heightMapSeriesOne->setFlatShadingEnabled(false);
+ m_heightMapSeriesTwo->setDrawMode(QSurface3DSeries::DrawSurface);
+ m_heightMapSeriesTwo->setFlatShadingEnabled(false);
+ m_heightMapSeriesThree->setDrawMode(QSurface3DSeries::DrawSurface);
+ m_heightMapSeriesThree->setFlatShadingEnabled(false);
+
+ m_graph->axisX()->setLabelFormat("%.1f N");
+ m_graph->axisZ()->setLabelFormat("%.1f E");
+ m_graph->axisX()->setRange(34.f, 40.f);
+ //! [4]
+ m_graph->axisY()->setAutoAdjustRange(true);
+ //! [4]
+ m_graph->axisZ()->setRange(18.f, 24.f);
+
+ m_graph->axisX()->setTitle(u"Latitude"_s);
+ m_graph->axisY()->setTitle(u"Height"_s);
+ m_graph->axisZ()->setTitle(u"Longitude"_s);
+
+ m_graph->removeSeries(m_sqrtSinSeries);
+ m_graph->removeSeries(m_topography);
+ m_graph->removeSeries(m_highlight);
+ m_graph->addSeries(m_heightMapSeriesOne);
+ m_graph->addSeries(m_heightMapSeriesTwo);
+ m_graph->addSeries(m_heightMapSeriesThree);
+
+ m_graph->setActiveInputHandler(m_defaultInputHandler);
+
+ m_titleLabel->setVisible(true);
+ m_graph->axisX()->setTitleVisible(true);
+ m_graph->axisY()->setTitleVisible(true);
+ m_graph->axisZ()->setTitleVisible(true);
+
+ // Reset range sliders for height map
+ int mapGridCountX = m_heightMapWidth / heightMapGridStepX;
+ int mapGridCountZ = m_heightMapHeight / heightMapGridStepZ;
+ m_rangeMinX = 34.f;
+ m_rangeMinZ = 18.f;
+ m_stepX = 6.f / float(mapGridCountX - 1);
+ m_stepZ = 6.f / float(mapGridCountZ - 1);
+ m_axisMinSliderX->setMinimum(0);
+ m_axisMinSliderX->setMaximum(mapGridCountX - 2);
+ m_axisMinSliderX->setValue(0);
+ m_axisMaxSliderX->setMinimum(1);
+ m_axisMaxSliderX->setMaximum(mapGridCountX - 1);
+ m_axisMaxSliderX->setValue(mapGridCountX - 1);
+ m_axisMinSliderZ->setMinimum(0);
+ m_axisMinSliderZ->setMaximum(mapGridCountZ - 2);
+ m_axisMinSliderZ->setValue(0);
+ m_axisMaxSliderZ->setMinimum(1);
+ m_axisMaxSliderZ->setMaximum(mapGridCountZ - 1);
+ m_axisMaxSliderZ->setValue(mapGridCountZ - 1);
+ }
+}
+
+void SurfaceGraphModifier::enableTopographyModel(bool enable)
+{
+ if (enable) {
+ m_graph->axisX()->setLabelFormat("%i");
+ m_graph->axisZ()->setLabelFormat("%i");
+ m_graph->axisX()->setRange(0.f, areaWidth);
+ m_graph->axisY()->setRange(100.f, areaWidth * aspectRatio);
+ m_graph->axisZ()->setRange(0.f, areaHeight);
+ m_graph->axisX()->setLabelAutoRotation(30.f);
+ m_graph->axisY()->setLabelAutoRotation(90.f);
+ m_graph->axisZ()->setLabelAutoRotation(30.f);
+
+ m_graph->removeSeries(m_heightMapSeriesOne);
+ m_graph->removeSeries(m_heightMapSeriesTwo);
+ m_graph->removeSeries(m_heightMapSeriesThree);
+ m_graph->addSeries(m_topography);
+ m_graph->addSeries(m_highlight);
+
+ m_titleLabel->setVisible(false);
+ m_graph->axisX()->setTitleVisible(false);
+ m_graph->axisY()->setTitleVisible(false);
+ m_graph->axisZ()->setTitleVisible(false);
+
+ m_graph->axisX()->setTitle({});
+ m_graph->axisY()->setTitle({});
+ m_graph->axisZ()->setTitle({});
+
+ //! [5]
+ m_graph->setActiveInputHandler(m_customInputHandler);
+ //! [5]
+
+ // Reset range sliders for topography map
+ m_rangeMinX = 0.f;
+ m_rangeMinZ = 0.f;
+ m_stepX = 1.f;
+ m_stepZ = 1.f;
+ m_axisMinSliderX->setMinimum(0);
+ m_axisMinSliderX->setMaximum(areaWidth - 200);
+ m_axisMinSliderX->setValue(0);
+ m_axisMaxSliderX->setMinimum(200);
+ m_axisMaxSliderX->setMaximum(areaWidth);
+ m_axisMaxSliderX->setValue(areaWidth);
+ m_axisMinSliderZ->setMinimum(0);
+ m_axisMinSliderZ->setMaximum(areaHeight - 200);
+ m_axisMinSliderZ->setValue(0);
+ m_axisMaxSliderZ->setMinimum(200);
+ m_axisMaxSliderZ->setMaximum(areaHeight);
+ m_axisMaxSliderZ->setValue(areaHeight);
+ }
+}
+
+void SurfaceGraphModifier::adjustXMin(int min)
+{
+ float minX = m_stepX * float(min) + m_rangeMinX;
+
+ int max = m_axisMaxSliderX->value();
+ if (min >= max) {
+ max = min + 1;
+ m_axisMaxSliderX->setValue(max);
+ }
+ float maxX = m_stepX * max + m_rangeMinX;
+
+ setAxisXRange(minX, maxX);
+}
+
+void SurfaceGraphModifier::adjustXMax(int max)
+{
+ float maxX = m_stepX * float(max) + m_rangeMinX;
+
+ int min = m_axisMinSliderX->value();
+ if (max <= min) {
+ min = max - 1;
+ m_axisMinSliderX->setValue(min);
+ }
+ float minX = m_stepX * min + m_rangeMinX;
+
+ setAxisXRange(minX, maxX);
+}
+
+void SurfaceGraphModifier::adjustZMin(int min)
+{
+ float minZ = m_stepZ * float(min) + m_rangeMinZ;
+
+ int max = m_axisMaxSliderZ->value();
+ if (min >= max) {
+ max = min + 1;
+ m_axisMaxSliderZ->setValue(max);
+ }
+ float maxZ = m_stepZ * max + m_rangeMinZ;
+
+ setAxisZRange(minZ, maxZ);
+}
+
+void SurfaceGraphModifier::adjustZMax(int max)
+{
+ float maxX = m_stepZ * float(max) + m_rangeMinZ;
+
+ int min = m_axisMinSliderZ->value();
+ if (max <= min) {
+ min = max - 1;
+ m_axisMinSliderZ->setValue(min);
+ }
+ float minX = m_stepZ * min + m_rangeMinZ;
+
+ setAxisZRange(minX, maxX);
+}
+
+//! [7]
+void SurfaceGraphModifier::setAxisXRange(float min, float max)
+{
+ m_graph->axisX()->setRange(min, max);
+}
+//! [7]
+
+void SurfaceGraphModifier::setAxisZRange(float min, float max)
+{
+ m_graph->axisZ()->setRange(min, max);
+}
+
+void SurfaceGraphModifier::setBlackToYellowGradient()
+{
+ //! [8]
+ QLinearGradient gr;
+ gr.setColorAt(0.f, Qt::black);
+ gr.setColorAt(0.33f, Qt::blue);
+ gr.setColorAt(0.67f, Qt::red);
+ gr.setColorAt(1.f, Qt::yellow);
+
+ m_sqrtSinSeries->setBaseGradient(gr);
+ m_sqrtSinSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
+ //! [8]
+}
+
+void SurfaceGraphModifier::setGreenToRedGradient()
+{
+ QLinearGradient gr;
+ gr.setColorAt(0.f, Qt::darkGreen);
+ gr.setColorAt(0.5f, Qt::yellow);
+ gr.setColorAt(0.8f, Qt::red);
+ gr.setColorAt(1.f, Qt::darkRed);
+
+ m_sqrtSinSeries->setBaseGradient(gr);
+ m_sqrtSinSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
+}
+
+void SurfaceGraphModifier::toggleItemOne(bool show)
+{
+ //! [10]
+ QVector3D positionOne = QVector3D(39.f, 77.f, 19.2f);
+ //! [10]
+ QVector3D positionOnePipe = QVector3D(39.f, 45.f, 19.2f);
+ QVector3D positionOneLabel = QVector3D(39.f, 107.f, 19.2f);
+ if (show) {
+ //! [9]
+ QImage color = QImage(2, 2, QImage::Format_RGB32);
+ color.fill(Qt::red);
+ //! [9]
+ //! [11]
+ auto *item = new QCustom3DItem(":/data/oilrig.obj", positionOne,
+ QVector3D(0.025f, 0.025f, 0.025f),
+ QQuaternion::fromAxisAndAngle(0.f, 1.f, 0.f, 45.f),
+ color);
+ //! [11]
+ //! [12]
+ m_graph->addCustomItem(item);
+ //! [12]
+ item = new QCustom3DItem(":/data/pipe.obj", positionOnePipe,
+ QVector3D(0.005f, 0.5f, 0.005f),
+ QQuaternion(),
+ color);
+ item->setShadowCasting(false);
+ m_graph->addCustomItem(item);
+
+ //! [13]
+ auto *label = new QCustom3DLabel();
+ label->setText("Oil Rig One");
+ label->setPosition(positionOneLabel);
+ label->setScaling(QVector3D(1.f, 1.f, 1.f));
+ m_graph->addCustomItem(label);
+ //! [13]
+ } else {
+ resetSelection();
+ //! [14]
+ m_graph->removeCustomItemAt(positionOne);
+ //! [14]
+ m_graph->removeCustomItemAt(positionOnePipe);
+ m_graph->removeCustomItemAt(positionOneLabel);
+ }
+}
+
+void SurfaceGraphModifier::toggleItemTwo(bool show)
+{
+ QVector3D positionTwo = QVector3D(34.5f, 77.f, 23.4f);
+ QVector3D positionTwoPipe = QVector3D(34.5f, 45.f, 23.4f);
+ QVector3D positionTwoLabel = QVector3D(34.5f, 107.f, 23.4f);
+ if (show) {
+ QImage color = QImage(2, 2, QImage::Format_RGB32);
+ color.fill(Qt::red);
+ auto *item = new QCustom3DItem();
+ item->setMeshFile(":/data/oilrig.obj");
+ item->setPosition(positionTwo);
+ item->setScaling(QVector3D(0.025f, 0.025f, 0.025f));
+ item->setRotation(QQuaternion::fromAxisAndAngle(0.f, 1.f, 0.f, 25.f));
+ item->setTextureImage(color);
+ m_graph->addCustomItem(item);
+ item = new QCustom3DItem(":/data/pipe.obj", positionTwoPipe,
+ QVector3D(0.005f, 0.5f, 0.005f),
+ QQuaternion(),
+ color);
+ item->setShadowCasting(false);
+ m_graph->addCustomItem(item);
+
+ auto *label = new QCustom3DLabel();
+ label->setText("Oil Rig Two");
+ label->setPosition(positionTwoLabel);
+ label->setScaling(QVector3D(1.f, 1.f, 1.f));
+ m_graph->addCustomItem(label);
+ } else {
+ resetSelection();
+ m_graph->removeCustomItemAt(positionTwo);
+ m_graph->removeCustomItemAt(positionTwoPipe);
+ m_graph->removeCustomItemAt(positionTwoLabel);
+ }
+}
+
+void SurfaceGraphModifier::toggleItemThree(bool show)
+{
+ QVector3D positionThree = QVector3D(34.5f, 86.f, 19.1f);
+ QVector3D positionThreeLabel = QVector3D(34.5f, 116.f, 19.1f);
+ if (show) {
+ QImage color = QImage(2, 2, QImage::Format_RGB32);
+ color.fill(Qt::darkMagenta);
+ auto *item = new QCustom3DItem();
+ item->setMeshFile(":/data/refinery.obj");
+ item->setPosition(positionThree);
+ item->setScaling(QVector3D(0.04f, 0.04f, 0.04f));
+ item->setRotation(QQuaternion::fromAxisAndAngle(0.f, 1.f, 0.f, 75.f));
+ item->setTextureImage(color);
+ m_graph->addCustomItem(item);
+
+ auto *label = new QCustom3DLabel();
+ label->setText("Refinery");
+ label->setPosition(positionThreeLabel);
+ label->setScaling(QVector3D(1.f, 1.f, 1.f));
+ m_graph->addCustomItem(label);
+ } else {
+ resetSelection();
+ m_graph->removeCustomItemAt(positionThree);
+ m_graph->removeCustomItemAt(positionThreeLabel);
+ }
+}
+
+void SurfaceGraphModifier::toggleSeeThrough(bool seethrough)
+{
+ if (seethrough) {
+ m_graph->seriesList().at(0)->setDrawMode(QSurface3DSeries::DrawWireframe);
+ m_graph->seriesList().at(1)->setDrawMode(QSurface3DSeries::DrawWireframe);
+ } else {
+ m_graph->seriesList().at(0)->setDrawMode(QSurface3DSeries::DrawSurface);
+ m_graph->seriesList().at(1)->setDrawMode(QSurface3DSeries::DrawSurface);
+ }
+}
+
+void SurfaceGraphModifier::toggleOilHighlight(bool highlight)
+{
+ if (highlight) {
+ QLinearGradient grThree;
+ grThree.setColorAt(0.0, Qt::black);
+ grThree.setColorAt(0.05, Qt::red);
+ m_graph->seriesList().at(2)->setBaseGradient(grThree);
+ } else {
+ QLinearGradient grThree;
+ grThree.setColorAt(0.0, Qt::white);
+ grThree.setColorAt(0.05, Qt::black);
+ m_graph->seriesList().at(2)->setBaseGradient(grThree);
+ }
+}
+
+void SurfaceGraphModifier::toggleShadows(bool shadows)
+{
+ if (shadows)
+ m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityMedium);
+ else
+ m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
+}
+
+//! [15]
+void SurfaceGraphModifier::toggleSurfaceTexture(bool enable)
+{
+ if (enable)
+ m_topography->setTextureFile(":/data/maptexture.jpg");
+ else
+ m_topography->setTextureFile("");
+}
+//! [15]
+
+void SurfaceGraphModifier::handleElementSelected(QAbstract3DGraph::ElementType type)
+{
+ resetSelection();
+ if (type == QAbstract3DGraph::ElementCustomItem) {
+ QCustom3DItem *item = m_graph->selectedCustomItem();
+ QString text;
+ if (qobject_cast<QCustom3DLabel *>(item) != 0) {
+ text.append("Custom label: ");
+ } else {
+ QStringList split = item->meshFile().split("/");
+ text.append(split.last());
+ text.append(": ");
+ }
+ int index = m_graph->selectedCustomItemIndex();
+ text.append(QString::number(index));
+ m_textField->setText(text);
+ m_previouslyAnimatedItem = item;
+ m_previousScaling = item->scaling();
+ m_selectionAnimation->setTargetObject(item);
+ m_selectionAnimation->setStartValue(item->scaling());
+ m_selectionAnimation->setEndValue(item->scaling() * 1.5f);
+ m_selectionAnimation->start();
+ } else if (type == QAbstract3DGraph::ElementSeries) {
+ QString text = "Surface (";
+ QSurface3DSeries *series = m_graph->selectedSeries();
+ if (series) {
+ QPoint point = series->selectedPoint();
+ QString posStr;
+ posStr.setNum(point.x());
+ text.append(posStr);
+ text.append(", ");
+ posStr.setNum(point.y());
+ text.append(posStr);
+ }
+ text.append(")");
+ m_textField->setText(text);
+ } else if (type > QAbstract3DGraph::ElementSeries
+ && type < QAbstract3DGraph::ElementCustomItem) {
+ int index = m_graph->selectedLabelIndex();
+ QString text;
+ if (type == QAbstract3DGraph::ElementAxisXLabel)
+ text.append("Axis X label: ");
+ else if (type == QAbstract3DGraph::ElementAxisYLabel)
+ text.append("Axis Y label: ");
+ else
+ text.append("Axis Z label: ");
+ text.append(QString::number(index));
+ m_textField->setText(text);
+ } else {
+ m_textField->setText("Nothing");
+ }
+}
+
+void SurfaceGraphModifier::resetSelection()
+{
+ m_selectionAnimation->stop();
+ if (m_previouslyAnimatedItem)
+ m_previouslyAnimatedItem->setScaling(m_previousScaling);
+ m_previouslyAnimatedItem = nullptr;
+}
diff --git a/examples/datavisualization/graphgallery/surfacegraphmodifier.h b/examples/datavisualization/graphgallery/surfacegraphmodifier.h
new file mode 100644
index 00000000..1a54958e
--- /dev/null
+++ b/examples/datavisualization/graphgallery/surfacegraphmodifier.h
@@ -0,0 +1,109 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SURFACEGRAPHMODIFIER_H
+#define SURFACEGRAPHMODIFIER_H
+
+#include <QtDataVisualization/q3dsurface.h>
+#include <QtDataVisualization/qsurfacedataproxy.h>
+#include <QtDataVisualization/qheightmapsurfacedataproxy.h>
+#include <QtDataVisualization/qsurface3dseries.h>
+#include <QtDataVisualization/qcustom3ditem.h>
+#include <QtDataVisualization/qcustom3dlabel.h>
+#include <QtDataVisualization/q3dinputhandler.h>
+#include <QtWidgets/qslider.h>
+#include <QtWidgets/qlabel.h>
+#include <QtCore/qpropertyanimation.h>
+
+class TopographicSeries;
+class HighlightSeries;
+class CustomInputHandler;
+
+class SurfaceGraphModifier : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SurfaceGraphModifier(Q3DSurface *surface, QLabel *label, QObject *parent);
+
+ //! [0]
+ void toggleModeNone() { m_graph->setSelectionMode(QAbstract3DGraph::SelectionNone); }
+ void toggleModeItem() { m_graph->setSelectionMode(QAbstract3DGraph::SelectionItem); }
+ void toggleModeSliceRow() { m_graph->setSelectionMode(QAbstract3DGraph::SelectionItemAndRow
+ | QAbstract3DGraph::SelectionSlice
+ | QAbstract3DGraph::SelectionMultiSeries); }
+ void toggleModeSliceColumn() { m_graph->setSelectionMode(QAbstract3DGraph::SelectionItemAndColumn
+ | QAbstract3DGraph::SelectionSlice
+ | QAbstract3DGraph::SelectionMultiSeries); }
+ //! [0]
+
+ void setBlackToYellowGradient();
+ void setGreenToRedGradient();
+
+ void setAxisMinSliderX(QSlider *slider) { m_axisMinSliderX = slider; }
+ void setAxisMaxSliderX(QSlider *slider) { m_axisMaxSliderX = slider; }
+ void setAxisMinSliderZ(QSlider *slider) { m_axisMinSliderZ = slider; }
+ void setAxisMaxSliderZ(QSlider *slider) { m_axisMaxSliderZ = slider; }
+
+ void adjustXMin(int min);
+ void adjustXMax(int max);
+ void adjustZMin(int min);
+ void adjustZMax(int max);
+
+public Q_SLOTS:
+ void enableSqrtSinModel(bool enable);
+ void enableHeightMapModel(bool enable);
+ void enableTopographyModel(bool enable);
+
+ void toggleItemOne(bool show);
+ void toggleItemTwo(bool show);
+ void toggleItemThree(bool show);
+ void toggleSeeThrough(bool seethrough);
+ void toggleOilHighlight(bool highlight);
+ void toggleShadows(bool shadows);
+ void toggleSurfaceTexture(bool enable);
+
+private:
+ void setAxisXRange(float min, float max);
+ void setAxisZRange(float min, float max);
+ void fillSqrtSinProxy();
+ void handleElementSelected(QAbstract3DGraph::ElementType type);
+ void resetSelection();
+
+private:
+ Q3DSurface *m_graph = nullptr;
+ QSurfaceDataProxy *m_sqrtSinProxy = nullptr;
+ QSurface3DSeries *m_sqrtSinSeries = nullptr;
+ QHeightMapSurfaceDataProxy *m_heightMapProxyOne = nullptr;
+ QHeightMapSurfaceDataProxy *m_heightMapProxyTwo = nullptr;
+ QHeightMapSurfaceDataProxy *m_heightMapProxyThree = nullptr;
+ QSurface3DSeries *m_heightMapSeriesOne = nullptr;
+ QSurface3DSeries *m_heightMapSeriesTwo = nullptr;
+ QSurface3DSeries *m_heightMapSeriesThree = nullptr;
+
+ QSlider *m_axisMinSliderX = nullptr;
+ QSlider *m_axisMaxSliderX = nullptr;
+ QSlider *m_axisMinSliderZ = nullptr;
+ QSlider *m_axisMaxSliderZ = nullptr;
+ float m_rangeMinX = 0.f;
+ float m_rangeMinZ = 0.f;
+ float m_stepX = 0.f;
+ float m_stepZ = 0.f;
+ int m_heightMapWidth = 0;
+ int m_heightMapHeight = 0;
+
+ QLabel *m_textField = nullptr;
+ QPropertyAnimation *m_selectionAnimation = nullptr;
+ QCustom3DLabel *m_titleLabel = nullptr;
+ QCustom3DItem *m_previouslyAnimatedItem = nullptr;
+ QVector3D m_previousScaling = {};
+
+ TopographicSeries *m_topography = nullptr;
+ HighlightSeries *m_highlight = nullptr;
+ int m_highlightWidth = 0;
+ int m_highlightHeight = 0;
+
+ CustomInputHandler *m_customInputHandler = nullptr;
+ Q3DInputHandler *m_defaultInputHandler = new Q3DInputHandler();
+};
+
+#endif // SURFACEGRAPHMODIFIER_H
diff --git a/examples/datavisualization/graphgallery/topographicseries.cpp b/examples/datavisualization/graphgallery/topographicseries.cpp
new file mode 100644
index 00000000..201a275e
--- /dev/null
+++ b/examples/datavisualization/graphgallery/topographicseries.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "topographicseries.h"
+
+//! [0]
+// Value used to encode height data as RGB value on PNG file
+const float packingFactor = 11983.f;
+//! [0]
+
+TopographicSeries::TopographicSeries()
+{
+ setDrawMode(QSurface3DSeries::DrawSurface);
+ setFlatShadingEnabled(true);
+ setBaseColor(Qt::white);
+}
+
+TopographicSeries::~TopographicSeries() = default;
+
+void TopographicSeries::setTopographyFile(const QString file, float width, float height)
+{
+ //! [1]
+ QImage heightMapImage(file);
+ uchar *bits = heightMapImage.bits();
+ int imageHeight = heightMapImage.height();
+ int imageWidth = heightMapImage.width();
+ int widthBits = imageWidth * 4;
+ float stepX = width / float(imageWidth);
+ float stepZ = height / float(imageHeight);
+
+ auto *dataArray = new QSurfaceDataArray;
+ dataArray->reserve(imageHeight);
+ for (int i = 0; i < imageHeight; ++i) {
+ int p = i * widthBits;
+ float z = height - float(i) * stepZ;
+ auto *newRow = new QSurfaceDataRow;
+ newRow->reserve(imageWidth);
+ for (int j = 0; j < imageWidth; ++j) {
+ uchar aa = bits[p + 0];
+ uchar rr = bits[p + 1];
+ uchar gg = bits[p + 2];
+ uint color = uint((gg << 16) + (rr << 8) + aa);
+ float y = float(color) / packingFactor;
+ newRow->append(QSurfaceDataItem({float(j) * stepX, y, z}));
+ p += 4;
+ }
+ dataArray->append(newRow);
+ }
+
+ dataProxy()->resetArray(dataArray);
+ //! [1]
+
+ m_sampleCountX = float(imageWidth);
+ m_sampleCountZ = float(imageHeight);
+}
diff --git a/examples/datavisualization/graphgallery/topographicseries.h b/examples/datavisualization/graphgallery/topographicseries.h
new file mode 100644
index 00000000..41e03b1e
--- /dev/null
+++ b/examples/datavisualization/graphgallery/topographicseries.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef TOPOGRAPHICSERIES_H
+#define TOPOGRAPHICSERIES_H
+
+#include <QtDataVisualization/qsurface3dseries.h>
+
+class TopographicSeries : public QSurface3DSeries
+{
+ Q_OBJECT
+public:
+ TopographicSeries();
+ ~TopographicSeries();
+
+ void setTopographyFile(const QString file, float width, float height);
+
+ float sampleCountX() { return m_sampleCountX; }
+ float sampleCountZ() { return m_sampleCountZ; }
+
+private:
+ float m_sampleCountX = 0.f;
+ float m_sampleCountZ = 0.f;
+};
+
+#endif // TOPOGRAPHICSERIES_H
diff --git a/examples/datavisualization/graphgallery/variantbardatamapping.cpp b/examples/datavisualization/graphgallery/variantbardatamapping.cpp
new file mode 100644
index 00000000..7a2a6cc7
--- /dev/null
+++ b/examples/datavisualization/graphgallery/variantbardatamapping.cpp
@@ -0,0 +1,85 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "variantbardatamapping.h"
+
+VariantBarDataMapping::VariantBarDataMapping(int rowIndex, int columnIndex, int valueIndex,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories)
+ : QObject(nullptr)
+{
+ m_rowIndex = rowIndex;
+ m_columnIndex = columnIndex;
+ m_valueIndex = valueIndex;
+ m_rowCategories = rowCategories;
+ m_columnCategories = columnCategories;
+}
+
+VariantBarDataMapping::~VariantBarDataMapping() = default;
+
+void VariantBarDataMapping::setRowIndex(int index)
+{
+ m_rowIndex = index;
+ emit mappingChanged();
+}
+
+int VariantBarDataMapping::rowIndex() const
+{
+ return m_rowIndex;
+}
+
+void VariantBarDataMapping::setColumnIndex(int index)
+{
+ m_columnIndex = index;
+ emit mappingChanged();
+}
+
+int VariantBarDataMapping::columnIndex() const
+{
+ return m_columnIndex;
+}
+
+void VariantBarDataMapping::setValueIndex(int index)
+{
+ m_valueIndex = index;
+ emit mappingChanged();
+}
+
+int VariantBarDataMapping::valueIndex() const
+{
+ return m_valueIndex;
+}
+
+void VariantBarDataMapping::setRowCategories(const QStringList &categories)
+{
+ m_rowCategories = categories;
+ emit mappingChanged();
+}
+
+const QStringList &VariantBarDataMapping::rowCategories() const
+{
+ return m_rowCategories;
+}
+
+void VariantBarDataMapping::setColumnCategories(const QStringList &categories)
+{
+ m_columnCategories = categories;
+ emit mappingChanged();
+}
+
+const QStringList &VariantBarDataMapping::columnCategories() const
+{
+ return m_columnCategories;
+}
+
+void VariantBarDataMapping::remap(int rowIndex, int columnIndex, int valueIndex,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories)
+{
+ m_rowIndex = rowIndex;
+ m_columnIndex = columnIndex;
+ m_valueIndex = valueIndex;
+ m_rowCategories = rowCategories;
+ m_columnCategories = columnCategories;
+ emit mappingChanged();
+}
diff --git a/examples/datavisualization/graphgallery/variantbardatamapping.h b/examples/datavisualization/graphgallery/variantbardatamapping.h
new file mode 100644
index 00000000..25bacebd
--- /dev/null
+++ b/examples/datavisualization/graphgallery/variantbardatamapping.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef VARIANTBARDATAMAPPING_H
+#define VARIANTBARDATAMAPPING_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstringlist.h>
+
+class VariantBarDataMapping : public QObject
+{
+ Q_OBJECT
+ //! [0]
+ Q_PROPERTY(int rowIndex READ rowIndex WRITE setRowIndex NOTIFY rowIndexChanged)
+ Q_PROPERTY(int columnIndex READ columnIndex WRITE setColumnIndex NOTIFY columnIndexChanged)
+ Q_PROPERTY(int valueIndex READ valueIndex WRITE setValueIndex NOTIFY valueIndexChanged)
+ Q_PROPERTY(QStringList rowCategories READ rowCategories WRITE setRowCategories NOTIFY rowCategoriesChanged)
+ Q_PROPERTY(QStringList columnCategories READ columnCategories WRITE setColumnCategories NOTIFY columnCategoriesChanged)
+ //! [0]
+public:
+ //! [1]
+ explicit VariantBarDataMapping(int rowIndex, int columnIndex, int valueIndex,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories);
+ //! [1]
+ virtual ~VariantBarDataMapping();
+
+ void setRowIndex(int index);
+ int rowIndex() const;
+ void setColumnIndex(int index);
+ int columnIndex() const;
+ void setValueIndex(int index);
+ int valueIndex() const;
+
+ void setRowCategories(const QStringList &categories);
+ const QStringList &rowCategories() const;
+ void setColumnCategories(const QStringList &categories);
+ const QStringList &columnCategories() const;
+
+ //! [2]
+ void remap(int rowIndex, int columnIndex, int valueIndex,
+ const QStringList &rowCategories,
+ const QStringList &columnCategories);
+ //! [2]
+Q_SIGNALS:
+ void rowIndexChanged();
+ void columnIndexChanged();
+ void valueIndexChanged();
+ void rowCategoriesChanged();
+ void columnCategoriesChanged();
+ //! [3]
+ void mappingChanged();
+ //! [3]
+
+private:
+ // Indexes of the mapped items in the VariantDataItem
+ int m_rowIndex = 0;
+ int m_columnIndex = 1;
+ int m_valueIndex = 2;
+
+ // For row/column items, sort items into these categories. Other categories are ignored.
+ QStringList m_rowCategories = {};
+ QStringList m_columnCategories = {};
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/variantbardataproxy.cpp b/examples/datavisualization/graphgallery/variantbardataproxy.cpp
new file mode 100644
index 00000000..8fe73abc
--- /dev/null
+++ b/examples/datavisualization/graphgallery/variantbardataproxy.cpp
@@ -0,0 +1,114 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "variantbardataproxy.h"
+
+VariantBarDataProxy::VariantBarDataProxy() = default;
+
+VariantBarDataProxy::~VariantBarDataProxy()
+{
+ delete m_dataSet;
+}
+
+void VariantBarDataProxy::setDataSet(VariantDataSet *newSet)
+{
+ if (!m_dataSet.isNull())
+ QObject::disconnect(m_dataSet.data(), nullptr, this, nullptr);
+
+ m_dataSet = newSet;
+
+ if (!m_dataSet.isNull()) {
+ QObject::connect(m_dataSet.data(), &VariantDataSet::itemsAdded, this,
+ &VariantBarDataProxy::handleItemsAdded);
+ QObject::connect(m_dataSet.data(), &VariantDataSet::dataCleared, this,
+ &VariantBarDataProxy::handleDataCleared);
+ }
+ resolveDataSet();
+}
+
+VariantDataSet *VariantBarDataProxy::dataSet()
+{
+ return m_dataSet.data();
+}
+
+void VariantBarDataProxy::setMapping(VariantBarDataMapping *mapping)
+{
+ if (!m_mapping.isNull()) {
+ QObject::disconnect(m_mapping.data(), &VariantBarDataMapping::mappingChanged, this,
+ &VariantBarDataProxy::handleMappingChanged);
+ }
+
+ m_mapping = mapping;
+
+ if (!m_mapping.isNull()) {
+ QObject::connect(m_mapping.data(), &VariantBarDataMapping::mappingChanged, this,
+ &VariantBarDataProxy::handleMappingChanged);
+ }
+
+ resolveDataSet();
+}
+
+VariantBarDataMapping *VariantBarDataProxy::mapping()
+{
+ return m_mapping.data();
+}
+
+void VariantBarDataProxy::handleItemsAdded(int index, int count)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(count);
+
+ // Resolve new items
+ resolveDataSet();
+}
+
+void VariantBarDataProxy::handleDataCleared()
+{
+ // Data cleared, reset array
+ resetArray(nullptr);
+}
+
+void VariantBarDataProxy::handleMappingChanged()
+{
+ resolveDataSet();
+}
+
+// Resolve entire dataset into QBarDataArray.
+//! [0]
+void VariantBarDataProxy::resolveDataSet()
+{
+ // If we have no data or mapping, or the categories are not defined, simply clear the array
+ if (m_dataSet.isNull() || m_mapping.isNull() || !m_mapping->rowCategories().size()
+ || !m_mapping->columnCategories().size()) {
+ resetArray(nullptr);
+ return;
+ }
+ const VariantDataItemList &itemList = m_dataSet->itemList();
+
+ int rowIndex = m_mapping->rowIndex();
+ int columnIndex = m_mapping->columnIndex();
+ int valueIndex = m_mapping->valueIndex();
+ const QStringList &rowList = m_mapping->rowCategories();
+ const QStringList &columnList = m_mapping->columnCategories();
+
+ // Sort values into rows and columns
+ using ColumnValueMap = QHash<QString, float>;
+ QHash <QString, ColumnValueMap> itemValueMap;
+ for (const VariantDataItem *item : itemList) {
+ itemValueMap[item->at(rowIndex).toString()][item->at(columnIndex).toString()]
+ = item->at(valueIndex).toReal();
+ }
+
+ // Create a new data array in format the parent class understands
+ auto *newProxyArray = new QBarDataArray;
+ for (const QString &rowKey : rowList) {
+ auto *newProxyRow = new QBarDataRow(columnList.size());
+ for (qsizetype i = 0; i < columnList.size(); ++i)
+ (*newProxyRow)[i].setValue(itemValueMap[rowKey][columnList.at(i)]);
+ newProxyArray->append(newProxyRow);
+ }
+
+ // Finally, reset the data array in the parent class
+ resetArray(newProxyArray);
+}
+//! [0]
diff --git a/examples/datavisualization/graphgallery/variantbardataproxy.h b/examples/datavisualization/graphgallery/variantbardataproxy.h
new file mode 100644
index 00000000..6a4d2f31
--- /dev/null
+++ b/examples/datavisualization/graphgallery/variantbardataproxy.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef VARIANTBARDATAPROXY_H
+#define VARIANTBARDATAPROXY_H
+
+#include "variantdataset.h"
+#include "variantbardatamapping.h"
+#include <QtDataVisualization/qbardataproxy.h>
+#include <QtCore/qpointer.h>
+
+//! [0]
+class VariantBarDataProxy : public QBarDataProxy
+//! [0]
+{
+ Q_OBJECT
+
+public:
+ VariantBarDataProxy();
+ virtual ~VariantBarDataProxy();
+
+ //! [1]
+ // Doesn't gain ownership of the dataset, but does connect to it to listen for data changes.
+ void setDataSet(VariantDataSet *newSet);
+ VariantDataSet *dataSet();
+
+ // Map key (row, column, value) to value index in data item (VariantItem).
+ // Doesn't gain ownership of mapping, but does connect to it to listen for mapping changes.
+ // Modifying mapping that is set to proxy will trigger dataset re-resolving.
+ void setMapping(VariantBarDataMapping *mapping);
+ VariantBarDataMapping *mapping();
+ //! [1]
+
+public Q_SLOTS:
+ void handleItemsAdded(int index, int count);
+ void handleDataCleared();
+ void handleMappingChanged();
+
+private:
+ void resolveDataSet();
+
+ QPointer<VariantDataSet> m_dataSet;
+ QPointer<VariantBarDataMapping> m_mapping;
+
+ Q_DISABLE_COPY(VariantBarDataProxy)
+};
+
+#endif
diff --git a/examples/datavisualization/graphgallery/variantdataset.cpp b/examples/datavisualization/graphgallery/variantdataset.cpp
new file mode 100644
index 00000000..3892f02b
--- /dev/null
+++ b/examples/datavisualization/graphgallery/variantdataset.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "variantdataset.h"
+
+VariantDataSet::VariantDataSet() = default;
+
+VariantDataSet::~VariantDataSet()
+{
+ clear();
+}
+
+void VariantDataSet::clear()
+{
+ for (VariantDataItem *item : m_variantData) {
+ item->clear();
+ delete item;
+ }
+ m_variantData.clear();
+ emit dataCleared();
+}
+
+int VariantDataSet::addItem(VariantDataItem *item)
+{
+ m_variantData.append(item);
+ int addIndex = m_variantData.size();
+
+ emit itemsAdded(addIndex, 1);
+ return addIndex;
+}
+
+int VariantDataSet::addItems(VariantDataItemList *itemList)
+{
+ int newCount = itemList->size();
+ int addIndex = m_variantData.size();
+ m_variantData.append(*itemList);
+ delete itemList;
+ emit itemsAdded(addIndex, newCount);
+ return addIndex;
+}
+
+const VariantDataItemList &VariantDataSet::itemList() const
+{
+ return m_variantData;
+}
diff --git a/examples/datavisualization/graphgallery/variantdataset.h b/examples/datavisualization/graphgallery/variantdataset.h
new file mode 100644
index 00000000..ca0d7ffd
--- /dev/null
+++ b/examples/datavisualization/graphgallery/variantdataset.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef VARIANTDATASET_H
+#define VARIANTDATASET_H
+
+#include <QtCore/qvariantlist.h>
+
+//! [0]
+using VariantDataItem = QVariantList;
+using VariantDataItemList = QList<VariantDataItem *>;
+//! [0]
+
+class VariantDataSet : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit VariantDataSet();
+ ~VariantDataSet();
+
+ //! [1]
+ void clear();
+
+ int addItem(VariantDataItem *item);
+ int addItems(VariantDataItemList *itemList);
+
+ const VariantDataItemList &itemList() const;
+
+Q_SIGNALS:
+ void itemsAdded(int index, int count);
+ void dataCleared();
+ //! [1]
+
+private:
+ VariantDataItemList m_variantData;
+
+ Q_DISABLE_COPY(VariantDataSet)
+};
+
+#endif