diff options
Diffstat (limited to 'examples')
44 files changed, 4560 insertions, 14 deletions
diff --git a/examples/datavisualization/audiolevels/audiolevels.cpp b/examples/datavisualization/audiolevels/audiolevels.cpp index 672e4984..c4a6b78c 100644 --- a/examples/datavisualization/audiolevels/audiolevels.cpp +++ b/examples/datavisualization/audiolevels/audiolevels.cpp @@ -74,7 +74,7 @@ AudioLevels::AudioLevels(Q3DBars *graph, QObject *parent) m_audioInput = new QAudioInput(inputDevice, formatAudio, this); #ifdef Q_OS_MAC - // Mac seems to wait for entire buffer to fill before calling writeData, so use smaller buffer + // OS X seems to wait for entire buffer to fill before calling writeData, so use smaller buffer m_audioInput->setBufferSize(256); #else m_audioInput->setBufferSize(1024); diff --git a/examples/datavisualization/bars/doc/images/bars-example.png b/examples/datavisualization/bars/doc/images/bars-example.png Binary files differindex fb79668d..c06fe2c1 100644 --- a/examples/datavisualization/bars/doc/images/bars-example.png +++ b/examples/datavisualization/bars/doc/images/bars-example.png diff --git a/examples/datavisualization/bars/doc/src/bars.qdoc b/examples/datavisualization/bars/doc/src/bars.qdoc index 9717fe8a..1117376f 100644 --- a/examples/datavisualization/bars/doc/src/bars.qdoc +++ b/examples/datavisualization/bars/doc/src/bars.qdoc @@ -188,6 +188,30 @@ You can use the same method with \c SelectionSlice and \c SelectionItem flags, as long as you have either \c SelectionRow or \c SelectionColumn set as well. + \section1 Zooming to selection + + As an example of adjusting camera target we have implemented an animation of zooming to + selection via a button press. Animation initializations are done in the constructor: + + \snippet bars/graphmodifier.cpp 12 + + The function \c{GraphModifier::zoomToSelectedBar()} contains the rest of the functionality: + + \snippet bars/graphmodifier.cpp 11 + + The QPropertyAnimation \c m_animationCameraTarget targets Q3DCamera::target property, + which takes a value normalized to the range (-1, 1). We figure out where the selected bar + is relative to axes, and use that as the end value for \c{m_animationCameraTarget}: + + \snippet bars/graphmodifier.cpp 13 + \dots + \snippet bars/graphmodifier.cpp 14 + + Likewise, we want to angle the camera so that it always points approximately to the center of + the graph at the end of the animation: + + \snippet bars/graphmodifier.cpp 15 + \section1 Example contents */ diff --git a/examples/datavisualization/bars/graphmodifier.cpp b/examples/datavisualization/bars/graphmodifier.cpp index 9c280bfb..587bc1d6 100644 --- a/examples/datavisualization/bars/graphmodifier.cpp +++ b/examples/datavisualization/bars/graphmodifier.cpp @@ -26,6 +26,7 @@ #include <QtDataVisualization/q3dtheme.h> #include <QtCore/QTime> #include <QtWidgets/QComboBox> +#include <QtCore/qmath.h> using namespace QtDataVisualization; @@ -106,6 +107,39 @@ GraphModifier::GraphModifier(Q3DBars *bargraph) //! [9] resetTemperatureData(); //! [9] + + // Set up property animations for zooming to the selected bar + //! [12] + 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))); + //! [12] } //! [0] @@ -187,6 +221,14 @@ void GraphModifier::changeStyle(int style) 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)); + //! [10] static int preset = Q3DCamera::CameraPresetFront; @@ -263,6 +305,74 @@ void GraphModifier::setAxisTitleFixed(bool enabled) m_yearAxis->setTitleFixed(enabled); } +//! [11] +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 + //! [13] + 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); + //! [13] + + // Rotate the camera so that it always points approximately to the graph center + //! [15] + qreal endAngleX = qAtan(qreal(endTarget.z() / endTarget.x())) / M_PI * -180.0 + 90.0; + 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; + //! [15] + + m_animationCameraX.setEndValue(QVariant::fromValue(float(endAngleX))); + m_animationCameraY.setEndValue(QVariant::fromValue(endAngleY)); + m_animationCameraZoom.setEndValue(QVariant::fromValue(250)); + //! [14] + m_animationCameraTarget.setEndValue(QVariant::fromValue(endTarget)); + //! [14] + } 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(); +} +//! [11] + void GraphModifier::changeShadowQuality(int quality) { QAbstract3DGraph::ShadowQuality sq = QAbstract3DGraph::ShadowQuality(quality); @@ -310,3 +420,8 @@ void GraphModifier::setReverseValueAxis(int enabled) { m_graph->valueAxis()->setReversed(enabled); } + +void GraphModifier::setReflection(bool enabled) +{ + m_graph->setReflection(enabled); +} diff --git a/examples/datavisualization/bars/graphmodifier.h b/examples/datavisualization/bars/graphmodifier.h index 107ffbab..22b00923 100644 --- a/examples/datavisualization/bars/graphmodifier.h +++ b/examples/datavisualization/bars/graphmodifier.h @@ -27,6 +27,7 @@ #include <QtCore/QDebug> #include <QtCore/QStringList> #include <QtCore/QPointer> +#include <QtCore/QPropertyAnimation> using namespace QtDataVisualization; @@ -49,6 +50,7 @@ public: void setSmoothBars(int smooth); void setSeriesVisibility(int enabled); void setReverseValueAxis(int enabled); + void setReflection(bool enabled); public slots: void changeRange(int range); @@ -60,6 +62,7 @@ public slots: void changeLabelRotation(int rotation); void setAxisTitleVisibility(bool enabled); void setAxisTitleFixed(bool enabled); + void zoomToSelectedBar(); signals: void shadowQualityChanged(int quality); @@ -86,6 +89,14 @@ private: QBar3DSeries *m_secondarySeries; QAbstract3DSeries::Mesh m_barMesh; bool m_smooth; + QPropertyAnimation m_animationCameraX; + QPropertyAnimation m_animationCameraY; + QPropertyAnimation m_animationCameraZoom; + QPropertyAnimation m_animationCameraTarget; + float m_defaultAngleX; + float m_defaultAngleY; + float m_defaultZoom; + QVector3D m_defaultTarget; }; #endif diff --git a/examples/datavisualization/bars/main.cpp b/examples/datavisualization/bars/main.cpp index 96abdc51..a7df14e0 100644 --- a/examples/datavisualization/bars/main.cpp +++ b/examples/datavisualization/bars/main.cpp @@ -72,6 +72,7 @@ int main(int argc, char **argv) smoothCheckBox->setText(QStringLiteral("Smooth bars")); smoothCheckBox->setChecked(false); + QComboBox *barStyleList = new QComboBox(widget); barStyleList->addItem(QStringLiteral("Bar"), int(QAbstract3DSeries::MeshBar)); barStyleList->addItem(QStringLiteral("Pyramid"), int(QAbstract3DSeries::MeshPyramid)); @@ -84,6 +85,9 @@ int main(int argc, char **argv) QPushButton *cameraButton = new QPushButton(widget); cameraButton->setText(QStringLiteral("Change camera preset")); + QPushButton *zoomToSelectedButton = new QPushButton(widget); + zoomToSelectedButton->setText(QStringLiteral("Zoom to selected bar")); + QComboBox *selectionModeList = new QComboBox(widget); selectionModeList->addItem(QStringLiteral("None"), int(QAbstract3DGraph::SelectionNone)); @@ -136,6 +140,10 @@ int main(int argc, char **argv) reverseValueAxisCheckBox->setText(QStringLiteral("Reverse value axis")); reverseValueAxisCheckBox->setChecked(false); + QCheckBox *reflectionCheckBox = new QCheckBox(widget); + reflectionCheckBox->setText(QStringLiteral("Show reflections")); + reflectionCheckBox->setChecked(false); + //! [4] QSlider *rotationSliderX = new QSlider(Qt::Horizontal, widget); rotationSliderX->setTickInterval(30); @@ -206,9 +214,11 @@ int main(int argc, char **argv) //! [5] 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); @@ -243,6 +253,8 @@ int main(int argc, char **argv) &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); @@ -254,6 +266,8 @@ int main(int argc, char **argv) &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); diff --git a/examples/datavisualization/customproxy/doc/images/customproxy-example.png b/examples/datavisualization/customproxy/doc/images/customproxy-example.png Binary files differindex 753b8951..4f82943a 100644 --- a/examples/datavisualization/customproxy/doc/images/customproxy-example.png +++ b/examples/datavisualization/customproxy/doc/images/customproxy-example.png diff --git a/examples/datavisualization/customproxy/rainfallgraph.cpp b/examples/datavisualization/customproxy/rainfallgraph.cpp index 024fc2a1..bcd67acc 100644 --- a/examples/datavisualization/customproxy/rainfallgraph.cpp +++ b/examples/datavisualization/customproxy/rainfallgraph.cpp @@ -49,7 +49,7 @@ RainfallGraph::RainfallGraph(Q3DBars *rainfall) // Set up bar specifications; make the bars as wide as they are deep, // and add a small space between the bars m_graph->setBarThickness(1.0f); - m_graph->setBarSpacing(QSizeF(0.2, 0.2)); + m_graph->setBarSpacing(QSizeF(1.1, 1.1)); // Set axis labels and titles QStringList months; @@ -85,6 +85,9 @@ RainfallGraph::RainfallGraph(Q3DBars *rainfall) // Set window title m_graph->setTitle(QStringLiteral("Monthly rainfall in Northern Finland")); + + // Set reflections on + m_graph->setReflection(true); } RainfallGraph::~RainfallGraph() diff --git a/examples/datavisualization/datavisualization.pro b/examples/datavisualization/datavisualization.pro index 1f72820c..b6ece48d 100644 --- a/examples/datavisualization/datavisualization.pro +++ b/examples/datavisualization/datavisualization.pro @@ -1,14 +1,17 @@ TEMPLATE = subdirs -SUBDIRS += qmlbars \ - qmlscatter \ - qmlsurface \ - qmlcustominput \ - qmllegend \ - qmlmultigraph \ - qmloscilloscope \ - qmlsurfacelayers \ - qmlaxisformatter \ - qmlaxisdrag +qtHaveModule(quick) { + SUBDIRS += qmlbars \ + qmlscatter \ + qmlsurface \ + qmlcustominput \ + qmllegend \ + qmlmultigraph \ + qmloscilloscope \ + qmlsurfacelayers \ + qmlaxisformatter \ + qmlaxisdrag \ + qmlspectrogram +} !android:!ios { SUBDIRS += bars \ @@ -19,7 +22,10 @@ SUBDIRS += qmlbars \ surface \ rotations \ draggableaxes \ - customitems + customitems \ + texturesurface \ + volumetric + + qtHaveModule(multimedia): SUBDIRS += audiolevels } -qtHaveModule(multimedia):!android:!ios: SUBDIRS += audiolevels diff --git a/examples/datavisualization/qmlspectrogram/doc/images/qmlspectrogram-example.png b/examples/datavisualization/qmlspectrogram/doc/images/qmlspectrogram-example.png Binary files differnew file mode 100644 index 00000000..de376cd9 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/doc/images/qmlspectrogram-example.png diff --git a/examples/datavisualization/qmlspectrogram/doc/src/qmlspectrogram.qdoc b/examples/datavisualization/qmlspectrogram/doc/src/qmlspectrogram.qdoc new file mode 100644 index 00000000..0aebdde0 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/doc/src/qmlspectrogram.qdoc @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +/*! + \example qmlspectrogram + \title Qt Quick 2 Spectrogram Example + \ingroup qtdatavisualization_examples + \brief Showing spectrogram graph in a QML application. + + The Qt Quick 2 Spectrogram example demonstrates how to show a polar and cartesian spectrograms + and how to utilize orthographic projection to show them in 2D. + + \image qmlspectrogram-example.png + + Spectrogram is simply a surface graph with a range gradient used to emphasize the different + values. Typically spectrograms are shown with two dimensional surfaces, which we simulate + with a top down orthographic view of the graph. To enforce the 2D effect, we disable the + graph rotation via mouse or touch when in the orthographic mode. + + The focus in this example is on showing how to display spectrograms, so the basic + functionality is not explained. For more detailed QML example documentation, + see \l{Qt Quick 2 Scatter Example}. + + \section1 Creating a spectrogram + + To create a 2D spectrogram, we define a Surface3D item: + + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 0 + + The key properties for enabling the 2D effect are + \l{AbstractGraph3D::orthoProjection}{orthoProjection} and + \l{Camera3D::cameraPreset}{scene.activeCamera.cameraPreset}. We remove the perspective by + enabling orthographic projection for the graph, and then we eliminate the Y-dimension by + viewing the graph directly from above: + + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 1 + + Since this viewpoint causes the horizontal axis grid to be mostly obscured by the surface, + we also specify that the horizontal grid should be drawn on top of the graph: + + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 2 + + \section1 Polar spectrogram + + Depending on the data, it is sometimes more natural to use a polar graph instead of a cartesian + one. Qt Data Visualization supports this via \l{AbstractGraph3D::polar}{polar} property. + In this example we provide a button to switch between polar and cartesian modes: + + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 3 + + In the polar mode, the X-axis is converted into the angular polar axis, and the Z-axis is + converted into the radial polar axis. The surface points are recalculated according to new axes. + + The radial axis labels are drawn outside the graph by default, but in this example we want to + draw them right next to the 0 degree angular axis inside the graph, so we define only a tiny + offset for them: + + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 4 + + To enforce the 2D effect, graph rotation via user input is disabled when in orthographic mode. + We do this by specifying a new input handler: + + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 5 + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 7 + \dots 0 + \snippet qmlspectrogram/qml/qmlspectrogram/main.qml 6 + \dots 0 + + When the projection mode changes, we adjust the value of the + \l{InputHandler3D::rotationEnabled}{rotationEnabled} property of the \c{customInputHandler} + to control the rotation. + + \section1 Example contents +*/ diff --git a/examples/datavisualization/qmlspectrogram/main.cpp b/examples/datavisualization/qmlspectrogram/main.cpp new file mode 100644 index 00000000..87665564 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/main.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include <QtGui/QGuiApplication> +#include <QtCore/QDir> +#include <QtQuick/QQuickView> +#include <QtQml/QQmlApplicationEngine> + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + + // The following are needed to make examples run without having to install the module + // in desktop environments. +#ifdef Q_OS_WIN + QString extraImportPath(QStringLiteral("%1/../../../../%2")); +#else + QString extraImportPath(QStringLiteral("%1/../../../%2")); +#endif + engine.addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(), + QString::fromLatin1("qml"))); + engine.load(QUrl(QStringLiteral("qrc:/qml/qml/qmlspectrogram/main.qml"))); + + return app.exec(); +} diff --git a/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/Data.qml b/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/Data.qml new file mode 100644 index 00000000..fc54edf4 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/Data.qml @@ -0,0 +1,1560 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +import QtQuick 2.1 + +Item { + property alias model: dataModel + + ListModel { + id: dataModel + ListElement{ radius: "0"; angle: "0"; value: "50"; } + ListElement{ radius: "0"; angle: "5"; value: "54.3578"; } + ListElement{ radius: "0"; angle: "10"; value: "58.6824"; } + ListElement{ radius: "0"; angle: "15"; value: "62.941"; } + ListElement{ radius: "0"; angle: "20"; value: "67.101"; } + ListElement{ radius: "0"; angle: "25"; value: "71.1309"; } + ListElement{ radius: "0"; angle: "30"; value: "75"; } + ListElement{ radius: "0"; angle: "35"; value: "78.6788"; } + ListElement{ radius: "0"; angle: "40"; value: "82.1394"; } + ListElement{ radius: "0"; angle: "45"; value: "85.3553"; } + ListElement{ radius: "0"; angle: "50"; value: "88.3022"; } + ListElement{ radius: "0"; angle: "55"; value: "90.9576"; } + ListElement{ radius: "0"; angle: "60"; value: "93.3013"; } + ListElement{ radius: "0"; angle: "65"; value: "95.3154"; } + ListElement{ radius: "0"; angle: "70"; value: "96.9846"; } + ListElement{ radius: "0"; angle: "75"; value: "98.2963"; } + ListElement{ radius: "0"; angle: "80"; value: "99.2404"; } + ListElement{ radius: "0"; angle: "85"; value: "99.8097"; } + ListElement{ radius: "0"; angle: "90"; value: "100"; } + ListElement{ radius: "0"; angle: "95"; value: "99.8097"; } + ListElement{ radius: "0"; angle: "100"; value: "99.2404"; } + ListElement{ radius: "0"; angle: "105"; value: "98.2963"; } + ListElement{ radius: "0"; angle: "110"; value: "96.9846"; } + ListElement{ radius: "0"; angle: "115"; value: "95.3154"; } + ListElement{ radius: "0"; angle: "120"; value: "93.3013"; } + ListElement{ radius: "0"; angle: "125"; value: "90.9576"; } + ListElement{ radius: "0"; angle: "130"; value: "88.3022"; } + ListElement{ radius: "0"; angle: "135"; value: "85.3553"; } + ListElement{ radius: "0"; angle: "140"; value: "82.1394"; } + ListElement{ radius: "0"; angle: "145"; value: "78.6788"; } + ListElement{ radius: "0"; angle: "150"; value: "75"; } + ListElement{ radius: "0"; angle: "155"; value: "71.1309"; } + ListElement{ radius: "0"; angle: "160"; value: "67.101"; } + ListElement{ radius: "0"; angle: "165"; value: "62.941"; } + ListElement{ radius: "0"; angle: "170"; value: "58.6824"; } + ListElement{ radius: "0"; angle: "175"; value: "54.3578"; } + ListElement{ radius: "0"; angle: "180"; value: "50"; } + ListElement{ radius: "0"; angle: "185"; value: "45.6422"; } + ListElement{ radius: "0"; angle: "190"; value: "41.3176"; } + ListElement{ radius: "0"; angle: "195"; value: "37.059"; } + ListElement{ radius: "0"; angle: "200"; value: "32.899"; } + ListElement{ radius: "0"; angle: "205"; value: "28.8691"; } + ListElement{ radius: "0"; angle: "210"; value: "25"; } + ListElement{ radius: "0"; angle: "215"; value: "21.3212"; } + ListElement{ radius: "0"; angle: "220"; value: "17.8606"; } + ListElement{ radius: "0"; angle: "225"; value: "14.6447"; } + ListElement{ radius: "0"; angle: "230"; value: "11.6978"; } + ListElement{ radius: "0"; angle: "235"; value: "9.0424"; } + ListElement{ radius: "0"; angle: "240"; value: "6.69873"; } + ListElement{ radius: "0"; angle: "245"; value: "4.68461"; } + ListElement{ radius: "0"; angle: "250"; value: "3.01537"; } + ListElement{ radius: "0"; angle: "255"; value: "1.70371"; } + ListElement{ radius: "0"; angle: "260"; value: "0.759612"; } + ListElement{ radius: "0"; angle: "265"; value: "0.190265"; } + ListElement{ radius: "0"; angle: "270"; value: "0"; } + ListElement{ radius: "0"; angle: "275"; value: "0.190265"; } + ListElement{ radius: "0"; angle: "280"; value: "0.759612"; } + ListElement{ radius: "0"; angle: "285"; value: "1.70371"; } + ListElement{ radius: "0"; angle: "290"; value: "3.01537"; } + ListElement{ radius: "0"; angle: "295"; value: "4.68461"; } + ListElement{ radius: "0"; angle: "300"; value: "6.69873"; } + ListElement{ radius: "0"; angle: "305"; value: "9.0424"; } + ListElement{ radius: "0"; angle: "310"; value: "11.6978"; } + ListElement{ radius: "0"; angle: "315"; value: "14.6447"; } + ListElement{ radius: "0"; angle: "320"; value: "17.8606"; } + ListElement{ radius: "0"; angle: "325"; value: "21.3212"; } + ListElement{ radius: "0"; angle: "330"; value: "25"; } + ListElement{ radius: "0"; angle: "335"; value: "28.8691"; } + ListElement{ radius: "0"; angle: "340"; value: "32.899"; } + ListElement{ radius: "0"; angle: "345"; value: "37.059"; } + ListElement{ radius: "0"; angle: "350"; value: "41.3176"; } + ListElement{ radius: "0"; angle: "355"; value: "45.6422"; } + ListElement{ radius: "0"; angle: "360"; value: "50"; } + ListElement{ radius: "5"; angle: "0"; value: "49.3844"; } + ListElement{ radius: "5"; angle: "5"; value: "53.7422"; } + ListElement{ radius: "5"; angle: "10"; value: "58.0668"; } + ListElement{ radius: "5"; angle: "15"; value: "62.3254"; } + ListElement{ radius: "5"; angle: "20"; value: "66.4854"; } + ListElement{ radius: "5"; angle: "25"; value: "70.5153"; } + ListElement{ radius: "5"; angle: "30"; value: "74.3844"; } + ListElement{ radius: "5"; angle: "35"; value: "78.0632"; } + ListElement{ radius: "5"; angle: "40"; value: "81.5238"; } + ListElement{ radius: "5"; angle: "45"; value: "84.7398"; } + ListElement{ radius: "5"; angle: "50"; value: "87.6866"; } + ListElement{ radius: "5"; angle: "55"; value: "90.342"; } + ListElement{ radius: "5"; angle: "60"; value: "92.6857"; } + ListElement{ radius: "5"; angle: "65"; value: "94.6998"; } + ListElement{ radius: "5"; angle: "70"; value: "96.369"; } + ListElement{ radius: "5"; angle: "75"; value: "97.6807"; } + ListElement{ radius: "5"; angle: "80"; value: "98.6248"; } + ListElement{ radius: "5"; angle: "85"; value: "99.1942"; } + ListElement{ radius: "5"; angle: "90"; value: "99.3844"; } + ListElement{ radius: "5"; angle: "95"; value: "99.1942"; } + ListElement{ radius: "5"; angle: "100"; value: "98.6248"; } + ListElement{ radius: "5"; angle: "105"; value: "97.6807"; } + ListElement{ radius: "5"; angle: "110"; value: "96.369"; } + ListElement{ radius: "5"; angle: "115"; value: "94.6998"; } + ListElement{ radius: "5"; angle: "120"; value: "92.6857"; } + ListElement{ radius: "5"; angle: "125"; value: "90.342"; } + ListElement{ radius: "5"; angle: "130"; value: "87.6866"; } + ListElement{ radius: "5"; angle: "135"; value: "84.7398"; } + ListElement{ radius: "5"; angle: "140"; value: "81.5238"; } + ListElement{ radius: "5"; angle: "145"; value: "78.0632"; } + ListElement{ radius: "5"; angle: "150"; value: "74.3844"; } + ListElement{ radius: "5"; angle: "155"; value: "70.5153"; } + ListElement{ radius: "5"; angle: "160"; value: "66.4854"; } + ListElement{ radius: "5"; angle: "165"; value: "62.3254"; } + ListElement{ radius: "5"; angle: "170"; value: "58.0668"; } + ListElement{ radius: "5"; angle: "175"; value: "53.7422"; } + ListElement{ radius: "5"; angle: "180"; value: "49.3844"; } + ListElement{ radius: "5"; angle: "185"; value: "45.0266"; } + ListElement{ radius: "5"; angle: "190"; value: "40.702"; } + ListElement{ radius: "5"; angle: "195"; value: "36.4435"; } + ListElement{ radius: "5"; angle: "200"; value: "32.2834"; } + ListElement{ radius: "5"; angle: "205"; value: "28.2535"; } + ListElement{ radius: "5"; angle: "210"; value: "24.3844"; } + ListElement{ radius: "5"; angle: "215"; value: "20.7056"; } + ListElement{ radius: "5"; angle: "220"; value: "17.245"; } + ListElement{ radius: "5"; angle: "225"; value: "14.0291"; } + ListElement{ radius: "5"; angle: "230"; value: "11.0822"; } + ListElement{ radius: "5"; angle: "235"; value: "8.42681"; } + ListElement{ radius: "5"; angle: "240"; value: "6.08315"; } + ListElement{ radius: "5"; angle: "245"; value: "4.06903"; } + ListElement{ radius: "5"; angle: "250"; value: "2.39979"; } + ListElement{ radius: "5"; angle: "255"; value: "1.08813"; } + ListElement{ radius: "5"; angle: "260"; value: "0.144029"; } + ListElement{ radius: "5"; angle: "265"; value: "-0.425318"; } + ListElement{ radius: "5"; angle: "270"; value: "-0.615583"; } + ListElement{ radius: "5"; angle: "275"; value: "-0.425318"; } + ListElement{ radius: "5"; angle: "280"; value: "0.144029"; } + ListElement{ radius: "5"; angle: "285"; value: "1.08813"; } + ListElement{ radius: "5"; angle: "290"; value: "2.39979"; } + ListElement{ radius: "5"; angle: "295"; value: "4.06903"; } + ListElement{ radius: "5"; angle: "300"; value: "6.08315"; } + ListElement{ radius: "5"; angle: "305"; value: "8.42681"; } + ListElement{ radius: "5"; angle: "310"; value: "11.0822"; } + ListElement{ radius: "5"; angle: "315"; value: "14.0291"; } + ListElement{ radius: "5"; angle: "320"; value: "17.245"; } + ListElement{ radius: "5"; angle: "325"; value: "20.7056"; } + ListElement{ radius: "5"; angle: "330"; value: "24.3844"; } + ListElement{ radius: "5"; angle: "335"; value: "28.2535"; } + ListElement{ radius: "5"; angle: "340"; value: "32.2834"; } + ListElement{ radius: "5"; angle: "345"; value: "36.4435"; } + ListElement{ radius: "5"; angle: "350"; value: "40.702"; } + ListElement{ radius: "5"; angle: "355"; value: "45.0266"; } + ListElement{ radius: "5"; angle: "360"; value: "49.3844"; } + ListElement{ radius: "10"; angle: "0"; value: "47.5528"; } + ListElement{ radius: "10"; angle: "5"; value: "51.9106"; } + ListElement{ radius: "10"; angle: "10"; value: "56.2352"; } + ListElement{ radius: "10"; angle: "15"; value: "60.4938"; } + ListElement{ radius: "10"; angle: "20"; value: "64.6538"; } + ListElement{ radius: "10"; angle: "25"; value: "68.6837"; } + ListElement{ radius: "10"; angle: "30"; value: "72.5528"; } + ListElement{ radius: "10"; angle: "35"; value: "76.2316"; } + ListElement{ radius: "10"; angle: "40"; value: "79.6922"; } + ListElement{ radius: "10"; angle: "45"; value: "82.9082"; } + ListElement{ radius: "10"; angle: "50"; value: "85.855"; } + ListElement{ radius: "10"; angle: "55"; value: "88.5104"; } + ListElement{ radius: "10"; angle: "60"; value: "90.8541"; } + ListElement{ radius: "10"; angle: "65"; value: "92.8682"; } + ListElement{ radius: "10"; angle: "70"; value: "94.5375"; } + ListElement{ radius: "10"; angle: "75"; value: "95.8491"; } + ListElement{ radius: "10"; angle: "80"; value: "96.7932"; } + ListElement{ radius: "10"; angle: "85"; value: "97.3626"; } + ListElement{ radius: "10"; angle: "90"; value: "97.5528"; } + ListElement{ radius: "10"; angle: "95"; value: "97.3626"; } + ListElement{ radius: "10"; angle: "100"; value: "96.7932"; } + ListElement{ radius: "10"; angle: "105"; value: "95.8491"; } + ListElement{ radius: "10"; angle: "110"; value: "94.5375"; } + ListElement{ radius: "10"; angle: "115"; value: "92.8682"; } + ListElement{ radius: "10"; angle: "120"; value: "90.8541"; } + ListElement{ radius: "10"; angle: "125"; value: "88.5104"; } + ListElement{ radius: "10"; angle: "130"; value: "85.855"; } + ListElement{ radius: "10"; angle: "135"; value: "82.9082"; } + ListElement{ radius: "10"; angle: "140"; value: "79.6922"; } + ListElement{ radius: "10"; angle: "145"; value: "76.2316"; } + ListElement{ radius: "10"; angle: "150"; value: "72.5528"; } + ListElement{ radius: "10"; angle: "155"; value: "68.6837"; } + ListElement{ radius: "10"; angle: "160"; value: "64.6538"; } + ListElement{ radius: "10"; angle: "165"; value: "60.4938"; } + ListElement{ radius: "10"; angle: "170"; value: "56.2352"; } + ListElement{ radius: "10"; angle: "175"; value: "51.9106"; } + ListElement{ radius: "10"; angle: "180"; value: "47.5528"; } + ListElement{ radius: "10"; angle: "185"; value: "43.195"; } + ListElement{ radius: "10"; angle: "190"; value: "38.8704"; } + ListElement{ radius: "10"; angle: "195"; value: "34.6119"; } + ListElement{ radius: "10"; angle: "200"; value: "30.4518"; } + ListElement{ radius: "10"; angle: "205"; value: "26.4219"; } + ListElement{ radius: "10"; angle: "210"; value: "22.5528"; } + ListElement{ radius: "10"; angle: "215"; value: "18.874"; } + ListElement{ radius: "10"; angle: "220"; value: "15.4134"; } + ListElement{ radius: "10"; angle: "225"; value: "12.1975"; } + ListElement{ radius: "10"; angle: "230"; value: "9.2506"; } + ListElement{ radius: "10"; angle: "235"; value: "6.59522"; } + ListElement{ radius: "10"; angle: "240"; value: "4.25156"; } + ListElement{ radius: "10"; angle: "245"; value: "2.23744"; } + ListElement{ radius: "10"; angle: "250"; value: "0.568195"; } + ListElement{ radius: "10"; angle: "255"; value: "-0.743465"; } + ListElement{ radius: "10"; angle: "260"; value: "-1.68756"; } + ListElement{ radius: "10"; angle: "265"; value: "-2.25691"; } + ListElement{ radius: "10"; angle: "270"; value: "-2.44717"; } + ListElement{ radius: "10"; angle: "275"; value: "-2.25691"; } + ListElement{ radius: "10"; angle: "280"; value: "-1.68756"; } + ListElement{ radius: "10"; angle: "285"; value: "-0.743465"; } + ListElement{ radius: "10"; angle: "290"; value: "0.568195"; } + ListElement{ radius: "10"; angle: "295"; value: "2.23744"; } + ListElement{ radius: "10"; angle: "300"; value: "4.25156"; } + ListElement{ radius: "10"; angle: "305"; value: "6.59522"; } + ListElement{ radius: "10"; angle: "310"; value: "9.2506"; } + ListElement{ radius: "10"; angle: "315"; value: "12.1975"; } + ListElement{ radius: "10"; angle: "320"; value: "15.4134"; } + ListElement{ radius: "10"; angle: "325"; value: "18.874"; } + ListElement{ radius: "10"; angle: "330"; value: "22.5528"; } + ListElement{ radius: "10"; angle: "335"; value: "26.4219"; } + ListElement{ radius: "10"; angle: "340"; value: "30.4518"; } + ListElement{ radius: "10"; angle: "345"; value: "34.6119"; } + ListElement{ radius: "10"; angle: "350"; value: "38.8704"; } + ListElement{ radius: "10"; angle: "355"; value: "43.195"; } + ListElement{ radius: "10"; angle: "360"; value: "47.5528"; } + ListElement{ radius: "15"; angle: "0"; value: "44.5503"; } + ListElement{ radius: "15"; angle: "5"; value: "48.9081"; } + ListElement{ radius: "15"; angle: "10"; value: "53.2327"; } + ListElement{ radius: "15"; angle: "15"; value: "57.4913"; } + ListElement{ radius: "15"; angle: "20"; value: "61.6513"; } + ListElement{ radius: "15"; angle: "25"; value: "65.6812"; } + ListElement{ radius: "15"; angle: "30"; value: "69.5503"; } + ListElement{ radius: "15"; angle: "35"; value: "73.2291"; } + ListElement{ radius: "15"; angle: "40"; value: "76.6897"; } + ListElement{ radius: "15"; angle: "45"; value: "79.9057"; } + ListElement{ radius: "15"; angle: "50"; value: "82.8525"; } + ListElement{ radius: "15"; angle: "55"; value: "85.5079"; } + ListElement{ radius: "15"; angle: "60"; value: "87.8516"; } + ListElement{ radius: "15"; angle: "65"; value: "89.8657"; } + ListElement{ radius: "15"; angle: "70"; value: "91.535"; } + ListElement{ radius: "15"; angle: "75"; value: "92.8466"; } + ListElement{ radius: "15"; angle: "80"; value: "93.7907"; } + ListElement{ radius: "15"; angle: "85"; value: "94.3601"; } + ListElement{ radius: "15"; angle: "90"; value: "94.5503"; } + ListElement{ radius: "15"; angle: "95"; value: "94.3601"; } + ListElement{ radius: "15"; angle: "100"; value: "93.7907"; } + ListElement{ radius: "15"; angle: "105"; value: "92.8466"; } + ListElement{ radius: "15"; angle: "110"; value: "91.535"; } + ListElement{ radius: "15"; angle: "115"; value: "89.8657"; } + ListElement{ radius: "15"; angle: "120"; value: "87.8516"; } + ListElement{ radius: "15"; angle: "125"; value: "85.5079"; } + ListElement{ radius: "15"; angle: "130"; value: "82.8525"; } + ListElement{ radius: "15"; angle: "135"; value: "79.9057"; } + ListElement{ radius: "15"; angle: "140"; value: "76.6897"; } + ListElement{ radius: "15"; angle: "145"; value: "73.2291"; } + ListElement{ radius: "15"; angle: "150"; value: "69.5503"; } + ListElement{ radius: "15"; angle: "155"; value: "65.6812"; } + ListElement{ radius: "15"; angle: "160"; value: "61.6513"; } + ListElement{ radius: "15"; angle: "165"; value: "57.4913"; } + ListElement{ radius: "15"; angle: "170"; value: "53.2327"; } + ListElement{ radius: "15"; angle: "175"; value: "48.9081"; } + ListElement{ radius: "15"; angle: "180"; value: "44.5503"; } + ListElement{ radius: "15"; angle: "185"; value: "40.1925"; } + ListElement{ radius: "15"; angle: "190"; value: "35.8679"; } + ListElement{ radius: "15"; angle: "195"; value: "31.6094"; } + ListElement{ radius: "15"; angle: "200"; value: "27.4493"; } + ListElement{ radius: "15"; angle: "205"; value: "23.4194"; } + ListElement{ radius: "15"; angle: "210"; value: "19.5503"; } + ListElement{ radius: "15"; angle: "215"; value: "15.8715"; } + ListElement{ radius: "15"; angle: "220"; value: "12.4109"; } + ListElement{ radius: "15"; angle: "225"; value: "9.19499"; } + ListElement{ radius: "15"; angle: "230"; value: "6.2481"; } + ListElement{ radius: "15"; angle: "235"; value: "3.59272"; } + ListElement{ radius: "15"; angle: "240"; value: "1.24906"; } + ListElement{ radius: "15"; angle: "245"; value: "-0.765063"; } + ListElement{ radius: "15"; angle: "250"; value: "-2.4343"; } + ListElement{ radius: "15"; angle: "255"; value: "-3.74597"; } + ListElement{ radius: "15"; angle: "260"; value: "-4.69006"; } + ListElement{ radius: "15"; angle: "265"; value: "-5.25941"; } + ListElement{ radius: "15"; angle: "270"; value: "-5.44967"; } + ListElement{ radius: "15"; angle: "275"; value: "-5.25941"; } + ListElement{ radius: "15"; angle: "280"; value: "-4.69006"; } + ListElement{ radius: "15"; angle: "285"; value: "-3.74597"; } + ListElement{ radius: "15"; angle: "290"; value: "-2.4343"; } + ListElement{ radius: "15"; angle: "295"; value: "-0.765063"; } + ListElement{ radius: "15"; angle: "300"; value: "1.24906"; } + ListElement{ radius: "15"; angle: "305"; value: "3.59272"; } + ListElement{ radius: "15"; angle: "310"; value: "6.2481"; } + ListElement{ radius: "15"; angle: "315"; value: "9.19499"; } + ListElement{ radius: "15"; angle: "320"; value: "12.4109"; } + ListElement{ radius: "15"; angle: "325"; value: "15.8715"; } + ListElement{ radius: "15"; angle: "330"; value: "19.5503"; } + ListElement{ radius: "15"; angle: "335"; value: "23.4194"; } + ListElement{ radius: "15"; angle: "340"; value: "27.4493"; } + ListElement{ radius: "15"; angle: "345"; value: "31.6094"; } + ListElement{ radius: "15"; angle: "350"; value: "35.8679"; } + ListElement{ radius: "15"; angle: "355"; value: "40.1925"; } + ListElement{ radius: "15"; angle: "360"; value: "44.5503"; } + ListElement{ radius: "20"; angle: "0"; value: "40.4508"; } + ListElement{ radius: "20"; angle: "5"; value: "44.8086"; } + ListElement{ radius: "20"; angle: "10"; value: "49.1333"; } + ListElement{ radius: "20"; angle: "15"; value: "53.3918"; } + ListElement{ radius: "20"; angle: "20"; value: "57.5519"; } + ListElement{ radius: "20"; angle: "25"; value: "61.5818"; } + ListElement{ radius: "20"; angle: "30"; value: "65.4508"; } + ListElement{ radius: "20"; angle: "35"; value: "69.1297"; } + ListElement{ radius: "20"; angle: "40"; value: "72.5902"; } + ListElement{ radius: "20"; angle: "45"; value: "75.8062"; } + ListElement{ radius: "20"; angle: "50"; value: "78.7531"; } + ListElement{ radius: "20"; angle: "55"; value: "81.4085"; } + ListElement{ radius: "20"; angle: "60"; value: "83.7521"; } + ListElement{ radius: "20"; angle: "65"; value: "85.7662"; } + ListElement{ radius: "20"; angle: "70"; value: "87.4355"; } + ListElement{ radius: "20"; angle: "75"; value: "88.7471"; } + ListElement{ radius: "20"; angle: "80"; value: "89.6912"; } + ListElement{ radius: "20"; angle: "85"; value: "90.2606"; } + ListElement{ radius: "20"; angle: "90"; value: "90.4508"; } + ListElement{ radius: "20"; angle: "95"; value: "90.2606"; } + ListElement{ radius: "20"; angle: "100"; value: "89.6912"; } + ListElement{ radius: "20"; angle: "105"; value: "88.7471"; } + ListElement{ radius: "20"; angle: "110"; value: "87.4355"; } + ListElement{ radius: "20"; angle: "115"; value: "85.7662"; } + ListElement{ radius: "20"; angle: "120"; value: "83.7521"; } + ListElement{ radius: "20"; angle: "125"; value: "81.4085"; } + ListElement{ radius: "20"; angle: "130"; value: "78.7531"; } + ListElement{ radius: "20"; angle: "135"; value: "75.8062"; } + ListElement{ radius: "20"; angle: "140"; value: "72.5902"; } + ListElement{ radius: "20"; angle: "145"; value: "69.1297"; } + ListElement{ radius: "20"; angle: "150"; value: "65.4508"; } + ListElement{ radius: "20"; angle: "155"; value: "61.5818"; } + ListElement{ radius: "20"; angle: "160"; value: "57.5519"; } + ListElement{ radius: "20"; angle: "165"; value: "53.3918"; } + ListElement{ radius: "20"; angle: "170"; value: "49.1333"; } + ListElement{ radius: "20"; angle: "175"; value: "44.8086"; } + ListElement{ radius: "20"; angle: "180"; value: "40.4508"; } + ListElement{ radius: "20"; angle: "185"; value: "36.0931"; } + ListElement{ radius: "20"; angle: "190"; value: "31.7684"; } + ListElement{ radius: "20"; angle: "195"; value: "27.5099"; } + ListElement{ radius: "20"; angle: "200"; value: "23.3498"; } + ListElement{ radius: "20"; angle: "205"; value: "19.3199"; } + ListElement{ radius: "20"; angle: "210"; value: "15.4508"; } + ListElement{ radius: "20"; angle: "215"; value: "11.772"; } + ListElement{ radius: "20"; angle: "220"; value: "8.31147"; } + ListElement{ radius: "20"; angle: "225"; value: "5.09551"; } + ListElement{ radius: "20"; angle: "230"; value: "2.14863"; } + ListElement{ radius: "20"; angle: "235"; value: "-0.506752"; } + ListElement{ radius: "20"; angle: "240"; value: "-2.85042"; } + ListElement{ radius: "20"; angle: "245"; value: "-4.86454"; } + ListElement{ radius: "20"; angle: "250"; value: "-6.53378"; } + ListElement{ radius: "20"; angle: "255"; value: "-7.84544"; } + ListElement{ radius: "20"; angle: "260"; value: "-8.78954"; } + ListElement{ radius: "20"; angle: "265"; value: "-9.35889"; } + ListElement{ radius: "20"; angle: "270"; value: "-9.54915"; } + ListElement{ radius: "20"; angle: "275"; value: "-9.35889"; } + ListElement{ radius: "20"; angle: "280"; value: "-8.78954"; } + ListElement{ radius: "20"; angle: "285"; value: "-7.84544"; } + ListElement{ radius: "20"; angle: "290"; value: "-6.53378"; } + ListElement{ radius: "20"; angle: "295"; value: "-4.86454"; } + ListElement{ radius: "20"; angle: "300"; value: "-2.85042"; } + ListElement{ radius: "20"; angle: "305"; value: "-0.506752"; } + ListElement{ radius: "20"; angle: "310"; value: "2.14863"; } + ListElement{ radius: "20"; angle: "315"; value: "5.09551"; } + ListElement{ radius: "20"; angle: "320"; value: "8.31147"; } + ListElement{ radius: "20"; angle: "325"; value: "11.772"; } + ListElement{ radius: "20"; angle: "330"; value: "15.4508"; } + ListElement{ radius: "20"; angle: "335"; value: "19.3199"; } + ListElement{ radius: "20"; angle: "340"; value: "23.3498"; } + ListElement{ radius: "20"; angle: "345"; value: "27.5099"; } + ListElement{ radius: "20"; angle: "350"; value: "31.7684"; } + ListElement{ radius: "20"; angle: "355"; value: "36.0931"; } + ListElement{ radius: "20"; angle: "360"; value: "40.4508"; } + ListElement{ radius: "25"; angle: "0"; value: "35.3553"; } + ListElement{ radius: "25"; angle: "5"; value: "39.7131"; } + ListElement{ radius: "25"; angle: "10"; value: "44.0377"; } + ListElement{ radius: "25"; angle: "15"; value: "48.2963"; } + ListElement{ radius: "25"; angle: "20"; value: "52.4563"; } + ListElement{ radius: "25"; angle: "25"; value: "56.4863"; } + ListElement{ radius: "25"; angle: "30"; value: "60.3553"; } + ListElement{ radius: "25"; angle: "35"; value: "64.0342"; } + ListElement{ radius: "25"; angle: "40"; value: "67.4947"; } + ListElement{ radius: "25"; angle: "45"; value: "70.7107"; } + ListElement{ radius: "25"; angle: "50"; value: "73.6576"; } + ListElement{ radius: "25"; angle: "55"; value: "76.3129"; } + ListElement{ radius: "25"; angle: "60"; value: "78.6566"; } + ListElement{ radius: "25"; angle: "65"; value: "80.6707"; } + ListElement{ radius: "25"; angle: "70"; value: "82.34"; } + ListElement{ radius: "25"; angle: "75"; value: "83.6516"; } + ListElement{ radius: "25"; angle: "80"; value: "84.5957"; } + ListElement{ radius: "25"; angle: "85"; value: "85.1651"; } + ListElement{ radius: "25"; angle: "90"; value: "85.3553"; } + ListElement{ radius: "25"; angle: "95"; value: "85.1651"; } + ListElement{ radius: "25"; angle: "100"; value: "84.5957"; } + ListElement{ radius: "25"; angle: "105"; value: "83.6516"; } + ListElement{ radius: "25"; angle: "110"; value: "82.34"; } + ListElement{ radius: "25"; angle: "115"; value: "80.6707"; } + ListElement{ radius: "25"; angle: "120"; value: "78.6566"; } + ListElement{ radius: "25"; angle: "125"; value: "76.3129"; } + ListElement{ radius: "25"; angle: "130"; value: "73.6576"; } + ListElement{ radius: "25"; angle: "135"; value: "70.7107"; } + ListElement{ radius: "25"; angle: "140"; value: "67.4947"; } + ListElement{ radius: "25"; angle: "145"; value: "64.0342"; } + ListElement{ radius: "25"; angle: "150"; value: "60.3553"; } + ListElement{ radius: "25"; angle: "155"; value: "56.4863"; } + ListElement{ radius: "25"; angle: "160"; value: "52.4563"; } + ListElement{ radius: "25"; angle: "165"; value: "48.2963"; } + ListElement{ radius: "25"; angle: "170"; value: "44.0377"; } + ListElement{ radius: "25"; angle: "175"; value: "39.7131"; } + ListElement{ radius: "25"; angle: "180"; value: "35.3553"; } + ListElement{ radius: "25"; angle: "185"; value: "30.9976"; } + ListElement{ radius: "25"; angle: "190"; value: "26.6729"; } + ListElement{ radius: "25"; angle: "195"; value: "22.4144"; } + ListElement{ radius: "25"; angle: "200"; value: "18.2543"; } + ListElement{ radius: "25"; angle: "205"; value: "14.2244"; } + ListElement{ radius: "25"; angle: "210"; value: "10.3553"; } + ListElement{ radius: "25"; angle: "215"; value: "6.67652"; } + ListElement{ radius: "25"; angle: "220"; value: "3.21596"; } + ListElement{ radius: "25"; angle: "225"; value: "5.55112e-15"; } + ListElement{ radius: "25"; angle: "230"; value: "-2.94688"; } + ListElement{ radius: "25"; angle: "235"; value: "-5.60226"; } + ListElement{ radius: "25"; angle: "240"; value: "-7.94593"; } + ListElement{ radius: "25"; angle: "245"; value: "-9.96005"; } + ListElement{ radius: "25"; angle: "250"; value: "-11.6293"; } + ListElement{ radius: "25"; angle: "255"; value: "-12.941"; } + ListElement{ radius: "25"; angle: "260"; value: "-13.885"; } + ListElement{ radius: "25"; angle: "265"; value: "-14.4544"; } + ListElement{ radius: "25"; angle: "270"; value: "-14.6447"; } + ListElement{ radius: "25"; angle: "275"; value: "-14.4544"; } + ListElement{ radius: "25"; angle: "280"; value: "-13.885"; } + ListElement{ radius: "25"; angle: "285"; value: "-12.941"; } + ListElement{ radius: "25"; angle: "290"; value: "-11.6293"; } + ListElement{ radius: "25"; angle: "295"; value: "-9.96005"; } + ListElement{ radius: "25"; angle: "300"; value: "-7.94593"; } + ListElement{ radius: "25"; angle: "305"; value: "-5.60226"; } + ListElement{ radius: "25"; angle: "310"; value: "-2.94688"; } + ListElement{ radius: "25"; angle: "315"; value: "-5.55112e-15"; } + ListElement{ radius: "25"; angle: "320"; value: "3.21596"; } + ListElement{ radius: "25"; angle: "325"; value: "6.67652"; } + ListElement{ radius: "25"; angle: "330"; value: "10.3553"; } + ListElement{ radius: "25"; angle: "335"; value: "14.2244"; } + ListElement{ radius: "25"; angle: "340"; value: "18.2543"; } + ListElement{ radius: "25"; angle: "345"; value: "22.4144"; } + ListElement{ radius: "25"; angle: "350"; value: "26.6729"; } + ListElement{ radius: "25"; angle: "355"; value: "30.9976"; } + ListElement{ radius: "25"; angle: "360"; value: "35.3553"; } + ListElement{ radius: "30"; angle: "0"; value: "29.3893"; } + ListElement{ radius: "30"; angle: "5"; value: "33.747"; } + ListElement{ radius: "30"; angle: "10"; value: "38.0717"; } + ListElement{ radius: "30"; angle: "15"; value: "42.3302"; } + ListElement{ radius: "30"; angle: "20"; value: "46.4903"; } + ListElement{ radius: "30"; angle: "25"; value: "50.5202"; } + ListElement{ radius: "30"; angle: "30"; value: "54.3893"; } + ListElement{ radius: "30"; angle: "35"; value: "58.0681"; } + ListElement{ radius: "30"; angle: "40"; value: "61.5286"; } + ListElement{ radius: "30"; angle: "45"; value: "64.7446"; } + ListElement{ radius: "30"; angle: "50"; value: "67.6915"; } + ListElement{ radius: "30"; angle: "55"; value: "70.3469"; } + ListElement{ radius: "30"; angle: "60"; value: "72.6905"; } + ListElement{ radius: "30"; angle: "65"; value: "74.7047"; } + ListElement{ radius: "30"; angle: "70"; value: "76.3739"; } + ListElement{ radius: "30"; angle: "75"; value: "77.6856"; } + ListElement{ radius: "30"; angle: "80"; value: "78.6297"; } + ListElement{ radius: "30"; angle: "85"; value: "79.199"; } + ListElement{ radius: "30"; angle: "90"; value: "79.3893"; } + ListElement{ radius: "30"; angle: "95"; value: "79.199"; } + ListElement{ radius: "30"; angle: "100"; value: "78.6297"; } + ListElement{ radius: "30"; angle: "105"; value: "77.6856"; } + ListElement{ radius: "30"; angle: "110"; value: "76.3739"; } + ListElement{ radius: "30"; angle: "115"; value: "74.7047"; } + ListElement{ radius: "30"; angle: "120"; value: "72.6905"; } + ListElement{ radius: "30"; angle: "125"; value: "70.3469"; } + ListElement{ radius: "30"; angle: "130"; value: "67.6915"; } + ListElement{ radius: "30"; angle: "135"; value: "64.7446"; } + ListElement{ radius: "30"; angle: "140"; value: "61.5286"; } + ListElement{ radius: "30"; angle: "145"; value: "58.0681"; } + ListElement{ radius: "30"; angle: "150"; value: "54.3893"; } + ListElement{ radius: "30"; angle: "155"; value: "50.5202"; } + ListElement{ radius: "30"; angle: "160"; value: "46.4903"; } + ListElement{ radius: "30"; angle: "165"; value: "42.3302"; } + ListElement{ radius: "30"; angle: "170"; value: "38.0717"; } + ListElement{ radius: "30"; angle: "175"; value: "33.747"; } + ListElement{ radius: "30"; angle: "180"; value: "29.3893"; } + ListElement{ radius: "30"; angle: "185"; value: "25.0315"; } + ListElement{ radius: "30"; angle: "190"; value: "20.7069"; } + ListElement{ radius: "30"; angle: "195"; value: "16.4483"; } + ListElement{ radius: "30"; angle: "200"; value: "12.2883"; } + ListElement{ radius: "30"; angle: "205"; value: "8.25835"; } + ListElement{ radius: "30"; angle: "210"; value: "4.38926"; } + ListElement{ radius: "30"; angle: "215"; value: "0.710441"; } + ListElement{ radius: "30"; angle: "220"; value: "-2.75012"; } + ListElement{ radius: "30"; angle: "225"; value: "-5.96608"; } + ListElement{ radius: "30"; angle: "230"; value: "-8.91296"; } + ListElement{ radius: "30"; angle: "235"; value: "-11.5683"; } + ListElement{ radius: "30"; angle: "240"; value: "-13.912"; } + ListElement{ radius: "30"; angle: "245"; value: "-15.9261"; } + ListElement{ radius: "30"; angle: "250"; value: "-17.5954"; } + ListElement{ radius: "30"; angle: "255"; value: "-18.907"; } + ListElement{ radius: "30"; angle: "260"; value: "-19.8511"; } + ListElement{ radius: "30"; angle: "265"; value: "-20.4205"; } + ListElement{ radius: "30"; angle: "270"; value: "-20.6107"; } + ListElement{ radius: "30"; angle: "275"; value: "-20.4205"; } + ListElement{ radius: "30"; angle: "280"; value: "-19.8511"; } + ListElement{ radius: "30"; angle: "285"; value: "-18.907"; } + ListElement{ radius: "30"; angle: "290"; value: "-17.5954"; } + ListElement{ radius: "30"; angle: "295"; value: "-15.9261"; } + ListElement{ radius: "30"; angle: "300"; value: "-13.912"; } + ListElement{ radius: "30"; angle: "305"; value: "-11.5683"; } + ListElement{ radius: "30"; angle: "310"; value: "-8.91296"; } + ListElement{ radius: "30"; angle: "315"; value: "-5.96608"; } + ListElement{ radius: "30"; angle: "320"; value: "-2.75012"; } + ListElement{ radius: "30"; angle: "325"; value: "0.710441"; } + ListElement{ radius: "30"; angle: "330"; value: "4.38926"; } + ListElement{ radius: "30"; angle: "335"; value: "8.25835"; } + ListElement{ radius: "30"; angle: "340"; value: "12.2883"; } + ListElement{ radius: "30"; angle: "345"; value: "16.4483"; } + ListElement{ radius: "30"; angle: "350"; value: "20.7069"; } + ListElement{ radius: "30"; angle: "355"; value: "25.0315"; } + ListElement{ radius: "30"; angle: "360"; value: "29.3893"; } + ListElement{ radius: "35"; angle: "0"; value: "22.6995"; } + ListElement{ radius: "35"; angle: "5"; value: "27.0573"; } + ListElement{ radius: "35"; angle: "10"; value: "31.3819"; } + ListElement{ radius: "35"; angle: "15"; value: "35.6405"; } + ListElement{ radius: "35"; angle: "20"; value: "39.8005"; } + ListElement{ radius: "35"; angle: "25"; value: "43.8304"; } + ListElement{ radius: "35"; angle: "30"; value: "47.6995"; } + ListElement{ radius: "35"; angle: "35"; value: "51.3783"; } + ListElement{ radius: "35"; angle: "40"; value: "54.8389"; } + ListElement{ radius: "35"; angle: "45"; value: "58.0549"; } + ListElement{ radius: "35"; angle: "50"; value: "61.0017"; } + ListElement{ radius: "35"; angle: "55"; value: "63.6571"; } + ListElement{ radius: "35"; angle: "60"; value: "66.0008"; } + ListElement{ radius: "35"; angle: "65"; value: "68.0149"; } + ListElement{ radius: "35"; angle: "70"; value: "69.6842"; } + ListElement{ radius: "35"; angle: "75"; value: "70.9958"; } + ListElement{ radius: "35"; angle: "80"; value: "71.9399"; } + ListElement{ radius: "35"; angle: "85"; value: "72.5093"; } + ListElement{ radius: "35"; angle: "90"; value: "72.6995"; } + ListElement{ radius: "35"; angle: "95"; value: "72.5093"; } + ListElement{ radius: "35"; angle: "100"; value: "71.9399"; } + ListElement{ radius: "35"; angle: "105"; value: "70.9958"; } + ListElement{ radius: "35"; angle: "110"; value: "69.6842"; } + ListElement{ radius: "35"; angle: "115"; value: "68.0149"; } + ListElement{ radius: "35"; angle: "120"; value: "66.0008"; } + ListElement{ radius: "35"; angle: "125"; value: "63.6571"; } + ListElement{ radius: "35"; angle: "130"; value: "61.0017"; } + ListElement{ radius: "35"; angle: "135"; value: "58.0549"; } + ListElement{ radius: "35"; angle: "140"; value: "54.8389"; } + ListElement{ radius: "35"; angle: "145"; value: "51.3783"; } + ListElement{ radius: "35"; angle: "150"; value: "47.6995"; } + ListElement{ radius: "35"; angle: "155"; value: "43.8304"; } + ListElement{ radius: "35"; angle: "160"; value: "39.8005"; } + ListElement{ radius: "35"; angle: "165"; value: "35.6405"; } + ListElement{ radius: "35"; angle: "170"; value: "31.3819"; } + ListElement{ radius: "35"; angle: "175"; value: "27.0573"; } + ListElement{ radius: "35"; angle: "180"; value: "22.6995"; } + ListElement{ radius: "35"; angle: "185"; value: "18.3417"; } + ListElement{ radius: "35"; angle: "190"; value: "14.0171"; } + ListElement{ radius: "35"; angle: "195"; value: "9.75857"; } + ListElement{ radius: "35"; angle: "200"; value: "5.59852"; } + ListElement{ radius: "35"; angle: "205"; value: "1.56861"; } + ListElement{ radius: "35"; angle: "210"; value: "-2.30048"; } + ListElement{ radius: "35"; angle: "215"; value: "-5.9793"; } + ListElement{ radius: "35"; angle: "220"; value: "-9.43986"; } + ListElement{ radius: "35"; angle: "225"; value: "-12.6558"; } + ListElement{ radius: "35"; angle: "230"; value: "-15.6027"; } + ListElement{ radius: "35"; angle: "235"; value: "-18.2581"; } + ListElement{ radius: "35"; angle: "240"; value: "-20.6017"; } + ListElement{ radius: "35"; angle: "245"; value: "-22.6159"; } + ListElement{ radius: "35"; angle: "250"; value: "-24.2851"; } + ListElement{ radius: "35"; angle: "255"; value: "-25.5968"; } + ListElement{ radius: "35"; angle: "260"; value: "-26.5409"; } + ListElement{ radius: "35"; angle: "265"; value: "-27.1102"; } + ListElement{ radius: "35"; angle: "270"; value: "-27.3005"; } + ListElement{ radius: "35"; angle: "275"; value: "-27.1102"; } + ListElement{ radius: "35"; angle: "280"; value: "-26.5409"; } + ListElement{ radius: "35"; angle: "285"; value: "-25.5968"; } + ListElement{ radius: "35"; angle: "290"; value: "-24.2851"; } + ListElement{ radius: "35"; angle: "295"; value: "-22.6159"; } + ListElement{ radius: "35"; angle: "300"; value: "-20.6017"; } + ListElement{ radius: "35"; angle: "305"; value: "-18.2581"; } + ListElement{ radius: "35"; angle: "310"; value: "-15.6027"; } + ListElement{ radius: "35"; angle: "315"; value: "-12.6558"; } + ListElement{ radius: "35"; angle: "320"; value: "-9.43986"; } + ListElement{ radius: "35"; angle: "325"; value: "-5.9793"; } + ListElement{ radius: "35"; angle: "330"; value: "-2.30048"; } + ListElement{ radius: "35"; angle: "335"; value: "1.56861"; } + ListElement{ radius: "35"; angle: "340"; value: "5.59852"; } + ListElement{ radius: "35"; angle: "345"; value: "9.75857"; } + ListElement{ radius: "35"; angle: "350"; value: "14.0171"; } + ListElement{ radius: "35"; angle: "355"; value: "18.3417"; } + ListElement{ radius: "35"; angle: "360"; value: "22.6995"; } + ListElement{ radius: "40"; angle: "0"; value: "15.4508"; } + ListElement{ radius: "40"; angle: "5"; value: "19.8086"; } + ListElement{ radius: "40"; angle: "10"; value: "24.1333"; } + ListElement{ radius: "40"; angle: "15"; value: "28.3918"; } + ListElement{ radius: "40"; angle: "20"; value: "32.5519"; } + ListElement{ radius: "40"; angle: "25"; value: "36.5818"; } + ListElement{ radius: "40"; angle: "30"; value: "40.4508"; } + ListElement{ radius: "40"; angle: "35"; value: "44.1297"; } + ListElement{ radius: "40"; angle: "40"; value: "47.5902"; } + ListElement{ radius: "40"; angle: "45"; value: "50.8062"; } + ListElement{ radius: "40"; angle: "50"; value: "53.7531"; } + ListElement{ radius: "40"; angle: "55"; value: "56.4085"; } + ListElement{ radius: "40"; angle: "60"; value: "58.7521"; } + ListElement{ radius: "40"; angle: "65"; value: "60.7662"; } + ListElement{ radius: "40"; angle: "70"; value: "62.4355"; } + ListElement{ radius: "40"; angle: "75"; value: "63.7471"; } + ListElement{ radius: "40"; angle: "80"; value: "64.6912"; } + ListElement{ radius: "40"; angle: "85"; value: "65.2606"; } + ListElement{ radius: "40"; angle: "90"; value: "65.4508"; } + ListElement{ radius: "40"; angle: "95"; value: "65.2606"; } + ListElement{ radius: "40"; angle: "100"; value: "64.6912"; } + ListElement{ radius: "40"; angle: "105"; value: "63.7471"; } + ListElement{ radius: "40"; angle: "110"; value: "62.4355"; } + ListElement{ radius: "40"; angle: "115"; value: "60.7662"; } + ListElement{ radius: "40"; angle: "120"; value: "58.7521"; } + ListElement{ radius: "40"; angle: "125"; value: "56.4085"; } + ListElement{ radius: "40"; angle: "130"; value: "53.7531"; } + ListElement{ radius: "40"; angle: "135"; value: "50.8062"; } + ListElement{ radius: "40"; angle: "140"; value: "47.5902"; } + ListElement{ radius: "40"; angle: "145"; value: "44.1297"; } + ListElement{ radius: "40"; angle: "150"; value: "40.4508"; } + ListElement{ radius: "40"; angle: "155"; value: "36.5818"; } + ListElement{ radius: "40"; angle: "160"; value: "32.5519"; } + ListElement{ radius: "40"; angle: "165"; value: "28.3918"; } + ListElement{ radius: "40"; angle: "170"; value: "24.1333"; } + ListElement{ radius: "40"; angle: "175"; value: "19.8086"; } + ListElement{ radius: "40"; angle: "180"; value: "15.4508"; } + ListElement{ radius: "40"; angle: "185"; value: "11.0931"; } + ListElement{ radius: "40"; angle: "190"; value: "6.76844"; } + ListElement{ radius: "40"; angle: "195"; value: "2.5099"; } + ListElement{ radius: "40"; angle: "200"; value: "-1.65016"; } + ListElement{ radius: "40"; angle: "205"; value: "-5.68006"; } + ListElement{ radius: "40"; angle: "210"; value: "-9.54915"; } + ListElement{ radius: "40"; angle: "215"; value: "-13.228"; } + ListElement{ radius: "40"; angle: "220"; value: "-16.6885"; } + ListElement{ radius: "40"; angle: "225"; value: "-19.9045"; } + ListElement{ radius: "40"; angle: "230"; value: "-22.8514"; } + ListElement{ radius: "40"; angle: "235"; value: "-25.5068"; } + ListElement{ radius: "40"; angle: "240"; value: "-27.8504"; } + ListElement{ radius: "40"; angle: "245"; value: "-29.8645"; } + ListElement{ radius: "40"; angle: "250"; value: "-31.5338"; } + ListElement{ radius: "40"; angle: "255"; value: "-32.8454"; } + ListElement{ radius: "40"; angle: "260"; value: "-33.7895"; } + ListElement{ radius: "40"; angle: "265"; value: "-34.3589"; } + ListElement{ radius: "40"; angle: "270"; value: "-34.5492"; } + ListElement{ radius: "40"; angle: "275"; value: "-34.3589"; } + ListElement{ radius: "40"; angle: "280"; value: "-33.7895"; } + ListElement{ radius: "40"; angle: "285"; value: "-32.8454"; } + ListElement{ radius: "40"; angle: "290"; value: "-31.5338"; } + ListElement{ radius: "40"; angle: "295"; value: "-29.8645"; } + ListElement{ radius: "40"; angle: "300"; value: "-27.8504"; } + ListElement{ radius: "40"; angle: "305"; value: "-25.5068"; } + ListElement{ radius: "40"; angle: "310"; value: "-22.8514"; } + ListElement{ radius: "40"; angle: "315"; value: "-19.9045"; } + ListElement{ radius: "40"; angle: "320"; value: "-16.6885"; } + ListElement{ radius: "40"; angle: "325"; value: "-13.228"; } + ListElement{ radius: "40"; angle: "330"; value: "-9.54915"; } + ListElement{ radius: "40"; angle: "335"; value: "-5.68006"; } + ListElement{ radius: "40"; angle: "340"; value: "-1.65016"; } + ListElement{ radius: "40"; angle: "345"; value: "2.5099"; } + ListElement{ radius: "40"; angle: "350"; value: "6.76844"; } + ListElement{ radius: "40"; angle: "355"; value: "11.0931"; } + ListElement{ radius: "40"; angle: "360"; value: "15.4508"; } + ListElement{ radius: "45"; angle: "0"; value: "7.82172"; } + ListElement{ radius: "45"; angle: "5"; value: "12.1795"; } + ListElement{ radius: "45"; angle: "10"; value: "16.5041"; } + ListElement{ radius: "45"; angle: "15"; value: "20.7627"; } + ListElement{ radius: "45"; angle: "20"; value: "24.9227"; } + ListElement{ radius: "45"; angle: "25"; value: "28.9526"; } + ListElement{ radius: "45"; angle: "30"; value: "32.8217"; } + ListElement{ radius: "45"; angle: "35"; value: "36.5005"; } + ListElement{ radius: "45"; angle: "40"; value: "39.9611"; } + ListElement{ radius: "45"; angle: "45"; value: "43.1771"; } + ListElement{ radius: "45"; angle: "50"; value: "46.1239"; } + ListElement{ radius: "45"; angle: "55"; value: "48.7793"; } + ListElement{ radius: "45"; angle: "60"; value: "51.123"; } + ListElement{ radius: "45"; angle: "65"; value: "53.1371"; } + ListElement{ radius: "45"; angle: "70"; value: "54.8064"; } + ListElement{ radius: "45"; angle: "75"; value: "56.118"; } + ListElement{ radius: "45"; angle: "80"; value: "57.0621"; } + ListElement{ radius: "45"; angle: "85"; value: "57.6315"; } + ListElement{ radius: "45"; angle: "90"; value: "57.8217"; } + ListElement{ radius: "45"; angle: "95"; value: "57.6315"; } + ListElement{ radius: "45"; angle: "100"; value: "57.0621"; } + ListElement{ radius: "45"; angle: "105"; value: "56.118"; } + ListElement{ radius: "45"; angle: "110"; value: "54.8064"; } + ListElement{ radius: "45"; angle: "115"; value: "53.1371"; } + ListElement{ radius: "45"; angle: "120"; value: "51.123"; } + ListElement{ radius: "45"; angle: "125"; value: "48.7793"; } + ListElement{ radius: "45"; angle: "130"; value: "46.1239"; } + ListElement{ radius: "45"; angle: "135"; value: "43.1771"; } + ListElement{ radius: "45"; angle: "140"; value: "39.9611"; } + ListElement{ radius: "45"; angle: "145"; value: "36.5005"; } + ListElement{ radius: "45"; angle: "150"; value: "32.8217"; } + ListElement{ radius: "45"; angle: "155"; value: "28.9526"; } + ListElement{ radius: "45"; angle: "160"; value: "24.9227"; } + ListElement{ radius: "45"; angle: "165"; value: "20.7627"; } + ListElement{ radius: "45"; angle: "170"; value: "16.5041"; } + ListElement{ radius: "45"; angle: "175"; value: "12.1795"; } + ListElement{ radius: "45"; angle: "180"; value: "7.82172"; } + ListElement{ radius: "45"; angle: "185"; value: "3.46394"; } + ListElement{ radius: "45"; angle: "190"; value: "-0.860686"; } + ListElement{ radius: "45"; angle: "195"; value: "-5.11923"; } + ListElement{ radius: "45"; angle: "200"; value: "-9.27928"; } + ListElement{ radius: "45"; angle: "205"; value: "-13.3092"; } + ListElement{ radius: "45"; angle: "210"; value: "-17.1783"; } + ListElement{ radius: "45"; angle: "215"; value: "-20.8571"; } + ListElement{ radius: "45"; angle: "220"; value: "-24.3177"; } + ListElement{ radius: "45"; angle: "225"; value: "-27.5336"; } + ListElement{ radius: "45"; angle: "230"; value: "-30.4805"; } + ListElement{ radius: "45"; angle: "235"; value: "-33.1359"; } + ListElement{ radius: "45"; angle: "240"; value: "-35.4795"; } + ListElement{ radius: "45"; angle: "245"; value: "-37.4937"; } + ListElement{ radius: "45"; angle: "250"; value: "-39.1629"; } + ListElement{ radius: "45"; angle: "255"; value: "-40.4746"; } + ListElement{ radius: "45"; angle: "260"; value: "-41.4187"; } + ListElement{ radius: "45"; angle: "265"; value: "-41.988"; } + ListElement{ radius: "45"; angle: "270"; value: "-42.1783"; } + ListElement{ radius: "45"; angle: "275"; value: "-41.988"; } + ListElement{ radius: "45"; angle: "280"; value: "-41.4187"; } + ListElement{ radius: "45"; angle: "285"; value: "-40.4746"; } + ListElement{ radius: "45"; angle: "290"; value: "-39.1629"; } + ListElement{ radius: "45"; angle: "295"; value: "-37.4937"; } + ListElement{ radius: "45"; angle: "300"; value: "-35.4795"; } + ListElement{ radius: "45"; angle: "305"; value: "-33.1359"; } + ListElement{ radius: "45"; angle: "310"; value: "-30.4805"; } + ListElement{ radius: "45"; angle: "315"; value: "-27.5336"; } + ListElement{ radius: "45"; angle: "320"; value: "-24.3177"; } + ListElement{ radius: "45"; angle: "325"; value: "-20.8571"; } + ListElement{ radius: "45"; angle: "330"; value: "-17.1783"; } + ListElement{ radius: "45"; angle: "335"; value: "-13.3092"; } + ListElement{ radius: "45"; angle: "340"; value: "-9.27928"; } + ListElement{ radius: "45"; angle: "345"; value: "-5.11923"; } + ListElement{ radius: "45"; angle: "350"; value: "-0.860686"; } + ListElement{ radius: "45"; angle: "355"; value: "3.46394"; } + ListElement{ radius: "45"; angle: "360"; value: "7.82172"; } + ListElement{ radius: "50"; angle: "0"; value: "3.06162e-15"; } + ListElement{ radius: "50"; angle: "5"; value: "4.35779"; } + ListElement{ radius: "50"; angle: "10"; value: "8.68241"; } + ListElement{ radius: "50"; angle: "15"; value: "12.941"; } + ListElement{ radius: "50"; angle: "20"; value: "17.101"; } + ListElement{ radius: "50"; angle: "25"; value: "21.1309"; } + ListElement{ radius: "50"; angle: "30"; value: "25"; } + ListElement{ radius: "50"; angle: "35"; value: "28.6788"; } + ListElement{ radius: "50"; angle: "40"; value: "32.1394"; } + ListElement{ radius: "50"; angle: "45"; value: "35.3553"; } + ListElement{ radius: "50"; angle: "50"; value: "38.3022"; } + ListElement{ radius: "50"; angle: "55"; value: "40.9576"; } + ListElement{ radius: "50"; angle: "60"; value: "43.3013"; } + ListElement{ radius: "50"; angle: "65"; value: "45.3154"; } + ListElement{ radius: "50"; angle: "70"; value: "46.9846"; } + ListElement{ radius: "50"; angle: "75"; value: "48.2963"; } + ListElement{ radius: "50"; angle: "80"; value: "49.2404"; } + ListElement{ radius: "50"; angle: "85"; value: "49.8097"; } + ListElement{ radius: "50"; angle: "90"; value: "50"; } + ListElement{ radius: "50"; angle: "95"; value: "49.8097"; } + ListElement{ radius: "50"; angle: "100"; value: "49.2404"; } + ListElement{ radius: "50"; angle: "105"; value: "48.2963"; } + ListElement{ radius: "50"; angle: "110"; value: "46.9846"; } + ListElement{ radius: "50"; angle: "115"; value: "45.3154"; } + ListElement{ radius: "50"; angle: "120"; value: "43.3013"; } + ListElement{ radius: "50"; angle: "125"; value: "40.9576"; } + ListElement{ radius: "50"; angle: "130"; value: "38.3022"; } + ListElement{ radius: "50"; angle: "135"; value: "35.3553"; } + ListElement{ radius: "50"; angle: "140"; value: "32.1394"; } + ListElement{ radius: "50"; angle: "145"; value: "28.6788"; } + ListElement{ radius: "50"; angle: "150"; value: "25"; } + ListElement{ radius: "50"; angle: "155"; value: "21.1309"; } + ListElement{ radius: "50"; angle: "160"; value: "17.101"; } + ListElement{ radius: "50"; angle: "165"; value: "12.941"; } + ListElement{ radius: "50"; angle: "170"; value: "8.68241"; } + ListElement{ radius: "50"; angle: "175"; value: "4.35779"; } + ListElement{ radius: "50"; angle: "180"; value: "9.18485e-15"; } + ListElement{ radius: "50"; angle: "185"; value: "-4.35779"; } + ListElement{ radius: "50"; angle: "190"; value: "-8.68241"; } + ListElement{ radius: "50"; angle: "195"; value: "-12.941"; } + ListElement{ radius: "50"; angle: "200"; value: "-17.101"; } + ListElement{ radius: "50"; angle: "205"; value: "-21.1309"; } + ListElement{ radius: "50"; angle: "210"; value: "-25"; } + ListElement{ radius: "50"; angle: "215"; value: "-28.6788"; } + ListElement{ radius: "50"; angle: "220"; value: "-32.1394"; } + ListElement{ radius: "50"; angle: "225"; value: "-35.3553"; } + ListElement{ radius: "50"; angle: "230"; value: "-38.3022"; } + ListElement{ radius: "50"; angle: "235"; value: "-40.9576"; } + ListElement{ radius: "50"; angle: "240"; value: "-43.3013"; } + ListElement{ radius: "50"; angle: "245"; value: "-45.3154"; } + ListElement{ radius: "50"; angle: "250"; value: "-46.9846"; } + ListElement{ radius: "50"; angle: "255"; value: "-48.2963"; } + ListElement{ radius: "50"; angle: "260"; value: "-49.2404"; } + ListElement{ radius: "50"; angle: "265"; value: "-49.8097"; } + ListElement{ radius: "50"; angle: "270"; value: "-50"; } + ListElement{ radius: "50"; angle: "275"; value: "-49.8097"; } + ListElement{ radius: "50"; angle: "280"; value: "-49.2404"; } + ListElement{ radius: "50"; angle: "285"; value: "-48.2963"; } + ListElement{ radius: "50"; angle: "290"; value: "-46.9846"; } + ListElement{ radius: "50"; angle: "295"; value: "-45.3154"; } + ListElement{ radius: "50"; angle: "300"; value: "-43.3013"; } + ListElement{ radius: "50"; angle: "305"; value: "-40.9576"; } + ListElement{ radius: "50"; angle: "310"; value: "-38.3022"; } + ListElement{ radius: "50"; angle: "315"; value: "-35.3553"; } + ListElement{ radius: "50"; angle: "320"; value: "-32.1394"; } + ListElement{ radius: "50"; angle: "325"; value: "-28.6788"; } + ListElement{ radius: "50"; angle: "330"; value: "-25"; } + ListElement{ radius: "50"; angle: "335"; value: "-21.1309"; } + ListElement{ radius: "50"; angle: "340"; value: "-17.101"; } + ListElement{ radius: "50"; angle: "345"; value: "-12.941"; } + ListElement{ radius: "50"; angle: "350"; value: "-8.68241"; } + ListElement{ radius: "50"; angle: "355"; value: "-4.35779"; } + ListElement{ radius: "50"; angle: "360"; value: "-9.18485e-15"; } + ListElement{ radius: "55"; angle: "0"; value: "-7.82172"; } + ListElement{ radius: "55"; angle: "5"; value: "-3.46394"; } + ListElement{ radius: "55"; angle: "10"; value: "0.860686"; } + ListElement{ radius: "55"; angle: "15"; value: "5.11923"; } + ListElement{ radius: "55"; angle: "20"; value: "9.27928"; } + ListElement{ radius: "55"; angle: "25"; value: "13.3092"; } + ListElement{ radius: "55"; angle: "30"; value: "17.1783"; } + ListElement{ radius: "55"; angle: "35"; value: "20.8571"; } + ListElement{ radius: "55"; angle: "40"; value: "24.3177"; } + ListElement{ radius: "55"; angle: "45"; value: "27.5336"; } + ListElement{ radius: "55"; angle: "50"; value: "30.4805"; } + ListElement{ radius: "55"; angle: "55"; value: "33.1359"; } + ListElement{ radius: "55"; angle: "60"; value: "35.4795"; } + ListElement{ radius: "55"; angle: "65"; value: "37.4937"; } + ListElement{ radius: "55"; angle: "70"; value: "39.1629"; } + ListElement{ radius: "55"; angle: "75"; value: "40.4746"; } + ListElement{ radius: "55"; angle: "80"; value: "41.4187"; } + ListElement{ radius: "55"; angle: "85"; value: "41.988"; } + ListElement{ radius: "55"; angle: "90"; value: "42.1783"; } + ListElement{ radius: "55"; angle: "95"; value: "41.988"; } + ListElement{ radius: "55"; angle: "100"; value: "41.4187"; } + ListElement{ radius: "55"; angle: "105"; value: "40.4746"; } + ListElement{ radius: "55"; angle: "110"; value: "39.1629"; } + ListElement{ radius: "55"; angle: "115"; value: "37.4937"; } + ListElement{ radius: "55"; angle: "120"; value: "35.4795"; } + ListElement{ radius: "55"; angle: "125"; value: "33.1359"; } + ListElement{ radius: "55"; angle: "130"; value: "30.4805"; } + ListElement{ radius: "55"; angle: "135"; value: "27.5336"; } + ListElement{ radius: "55"; angle: "140"; value: "24.3177"; } + ListElement{ radius: "55"; angle: "145"; value: "20.8571"; } + ListElement{ radius: "55"; angle: "150"; value: "17.1783"; } + ListElement{ radius: "55"; angle: "155"; value: "13.3092"; } + ListElement{ radius: "55"; angle: "160"; value: "9.27928"; } + ListElement{ radius: "55"; angle: "165"; value: "5.11923"; } + ListElement{ radius: "55"; angle: "170"; value: "0.860686"; } + ListElement{ radius: "55"; angle: "175"; value: "-3.46394"; } + ListElement{ radius: "55"; angle: "180"; value: "-7.82172"; } + ListElement{ radius: "55"; angle: "185"; value: "-12.1795"; } + ListElement{ radius: "55"; angle: "190"; value: "-16.5041"; } + ListElement{ radius: "55"; angle: "195"; value: "-20.7627"; } + ListElement{ radius: "55"; angle: "200"; value: "-24.9227"; } + ListElement{ radius: "55"; angle: "205"; value: "-28.9526"; } + ListElement{ radius: "55"; angle: "210"; value: "-32.8217"; } + ListElement{ radius: "55"; angle: "215"; value: "-36.5005"; } + ListElement{ radius: "55"; angle: "220"; value: "-39.9611"; } + ListElement{ radius: "55"; angle: "225"; value: "-43.1771"; } + ListElement{ radius: "55"; angle: "230"; value: "-46.1239"; } + ListElement{ radius: "55"; angle: "235"; value: "-48.7793"; } + ListElement{ radius: "55"; angle: "240"; value: "-51.123"; } + ListElement{ radius: "55"; angle: "245"; value: "-53.1371"; } + ListElement{ radius: "55"; angle: "250"; value: "-54.8064"; } + ListElement{ radius: "55"; angle: "255"; value: "-56.118"; } + ListElement{ radius: "55"; angle: "260"; value: "-57.0621"; } + ListElement{ radius: "55"; angle: "265"; value: "-57.6315"; } + ListElement{ radius: "55"; angle: "270"; value: "-57.8217"; } + ListElement{ radius: "55"; angle: "275"; value: "-57.6315"; } + ListElement{ radius: "55"; angle: "280"; value: "-57.0621"; } + ListElement{ radius: "55"; angle: "285"; value: "-56.118"; } + ListElement{ radius: "55"; angle: "290"; value: "-54.8064"; } + ListElement{ radius: "55"; angle: "295"; value: "-53.1371"; } + ListElement{ radius: "55"; angle: "300"; value: "-51.123"; } + ListElement{ radius: "55"; angle: "305"; value: "-48.7793"; } + ListElement{ radius: "55"; angle: "310"; value: "-46.1239"; } + ListElement{ radius: "55"; angle: "315"; value: "-43.1771"; } + ListElement{ radius: "55"; angle: "320"; value: "-39.9611"; } + ListElement{ radius: "55"; angle: "325"; value: "-36.5005"; } + ListElement{ radius: "55"; angle: "330"; value: "-32.8217"; } + ListElement{ radius: "55"; angle: "335"; value: "-28.9526"; } + ListElement{ radius: "55"; angle: "340"; value: "-24.9227"; } + ListElement{ radius: "55"; angle: "345"; value: "-20.7627"; } + ListElement{ radius: "55"; angle: "350"; value: "-16.5041"; } + ListElement{ radius: "55"; angle: "355"; value: "-12.1795"; } + ListElement{ radius: "55"; angle: "360"; value: "-7.82172"; } + ListElement{ radius: "60"; angle: "0"; value: "-15.4508"; } + ListElement{ radius: "60"; angle: "5"; value: "-11.0931"; } + ListElement{ radius: "60"; angle: "10"; value: "-6.76844"; } + ListElement{ radius: "60"; angle: "15"; value: "-2.5099"; } + ListElement{ radius: "60"; angle: "20"; value: "1.65016"; } + ListElement{ radius: "60"; angle: "25"; value: "5.68006"; } + ListElement{ radius: "60"; angle: "30"; value: "9.54915"; } + ListElement{ radius: "60"; angle: "35"; value: "13.228"; } + ListElement{ radius: "60"; angle: "40"; value: "16.6885"; } + ListElement{ radius: "60"; angle: "45"; value: "19.9045"; } + ListElement{ radius: "60"; angle: "50"; value: "22.8514"; } + ListElement{ radius: "60"; angle: "55"; value: "25.5068"; } + ListElement{ radius: "60"; angle: "60"; value: "27.8504"; } + ListElement{ radius: "60"; angle: "65"; value: "29.8645"; } + ListElement{ radius: "60"; angle: "70"; value: "31.5338"; } + ListElement{ radius: "60"; angle: "75"; value: "32.8454"; } + ListElement{ radius: "60"; angle: "80"; value: "33.7895"; } + ListElement{ radius: "60"; angle: "85"; value: "34.3589"; } + ListElement{ radius: "60"; angle: "90"; value: "34.5492"; } + ListElement{ radius: "60"; angle: "95"; value: "34.3589"; } + ListElement{ radius: "60"; angle: "100"; value: "33.7895"; } + ListElement{ radius: "60"; angle: "105"; value: "32.8454"; } + ListElement{ radius: "60"; angle: "110"; value: "31.5338"; } + ListElement{ radius: "60"; angle: "115"; value: "29.8645"; } + ListElement{ radius: "60"; angle: "120"; value: "27.8504"; } + ListElement{ radius: "60"; angle: "125"; value: "25.5068"; } + ListElement{ radius: "60"; angle: "130"; value: "22.8514"; } + ListElement{ radius: "60"; angle: "135"; value: "19.9045"; } + ListElement{ radius: "60"; angle: "140"; value: "16.6885"; } + ListElement{ radius: "60"; angle: "145"; value: "13.228"; } + ListElement{ radius: "60"; angle: "150"; value: "9.54915"; } + ListElement{ radius: "60"; angle: "155"; value: "5.68006"; } + ListElement{ radius: "60"; angle: "160"; value: "1.65016"; } + ListElement{ radius: "60"; angle: "165"; value: "-2.5099"; } + ListElement{ radius: "60"; angle: "170"; value: "-6.76844"; } + ListElement{ radius: "60"; angle: "175"; value: "-11.0931"; } + ListElement{ radius: "60"; angle: "180"; value: "-15.4508"; } + ListElement{ radius: "60"; angle: "185"; value: "-19.8086"; } + ListElement{ radius: "60"; angle: "190"; value: "-24.1333"; } + ListElement{ radius: "60"; angle: "195"; value: "-28.3918"; } + ListElement{ radius: "60"; angle: "200"; value: "-32.5519"; } + ListElement{ radius: "60"; angle: "205"; value: "-36.5818"; } + ListElement{ radius: "60"; angle: "210"; value: "-40.4508"; } + ListElement{ radius: "60"; angle: "215"; value: "-44.1297"; } + ListElement{ radius: "60"; angle: "220"; value: "-47.5902"; } + ListElement{ radius: "60"; angle: "225"; value: "-50.8062"; } + ListElement{ radius: "60"; angle: "230"; value: "-53.7531"; } + ListElement{ radius: "60"; angle: "235"; value: "-56.4085"; } + ListElement{ radius: "60"; angle: "240"; value: "-58.7521"; } + ListElement{ radius: "60"; angle: "245"; value: "-60.7662"; } + ListElement{ radius: "60"; angle: "250"; value: "-62.4355"; } + ListElement{ radius: "60"; angle: "255"; value: "-63.7471"; } + ListElement{ radius: "60"; angle: "260"; value: "-64.6912"; } + ListElement{ radius: "60"; angle: "265"; value: "-65.2606"; } + ListElement{ radius: "60"; angle: "270"; value: "-65.4508"; } + ListElement{ radius: "60"; angle: "275"; value: "-65.2606"; } + ListElement{ radius: "60"; angle: "280"; value: "-64.6912"; } + ListElement{ radius: "60"; angle: "285"; value: "-63.7471"; } + ListElement{ radius: "60"; angle: "290"; value: "-62.4355"; } + ListElement{ radius: "60"; angle: "295"; value: "-60.7662"; } + ListElement{ radius: "60"; angle: "300"; value: "-58.7521"; } + ListElement{ radius: "60"; angle: "305"; value: "-56.4085"; } + ListElement{ radius: "60"; angle: "310"; value: "-53.7531"; } + ListElement{ radius: "60"; angle: "315"; value: "-50.8062"; } + ListElement{ radius: "60"; angle: "320"; value: "-47.5902"; } + ListElement{ radius: "60"; angle: "325"; value: "-44.1297"; } + ListElement{ radius: "60"; angle: "330"; value: "-40.4508"; } + ListElement{ radius: "60"; angle: "335"; value: "-36.5818"; } + ListElement{ radius: "60"; angle: "340"; value: "-32.5519"; } + ListElement{ radius: "60"; angle: "345"; value: "-28.3918"; } + ListElement{ radius: "60"; angle: "350"; value: "-24.1333"; } + ListElement{ radius: "60"; angle: "355"; value: "-19.8086"; } + ListElement{ radius: "60"; angle: "360"; value: "-15.4508"; } + ListElement{ radius: "65"; angle: "0"; value: "-22.6995"; } + ListElement{ radius: "65"; angle: "5"; value: "-18.3417"; } + ListElement{ radius: "65"; angle: "10"; value: "-14.0171"; } + ListElement{ radius: "65"; angle: "15"; value: "-9.75857"; } + ListElement{ radius: "65"; angle: "20"; value: "-5.59852"; } + ListElement{ radius: "65"; angle: "25"; value: "-1.56861"; } + ListElement{ radius: "65"; angle: "30"; value: "2.30048"; } + ListElement{ radius: "65"; angle: "35"; value: "5.9793"; } + ListElement{ radius: "65"; angle: "40"; value: "9.43986"; } + ListElement{ radius: "65"; angle: "45"; value: "12.6558"; } + ListElement{ radius: "65"; angle: "50"; value: "15.6027"; } + ListElement{ radius: "65"; angle: "55"; value: "18.2581"; } + ListElement{ radius: "65"; angle: "60"; value: "20.6017"; } + ListElement{ radius: "65"; angle: "65"; value: "22.6159"; } + ListElement{ radius: "65"; angle: "70"; value: "24.2851"; } + ListElement{ radius: "65"; angle: "75"; value: "25.5968"; } + ListElement{ radius: "65"; angle: "80"; value: "26.5409"; } + ListElement{ radius: "65"; angle: "85"; value: "27.1102"; } + ListElement{ radius: "65"; angle: "90"; value: "27.3005"; } + ListElement{ radius: "65"; angle: "95"; value: "27.1102"; } + ListElement{ radius: "65"; angle: "100"; value: "26.5409"; } + ListElement{ radius: "65"; angle: "105"; value: "25.5968"; } + ListElement{ radius: "65"; angle: "110"; value: "24.2851"; } + ListElement{ radius: "65"; angle: "115"; value: "22.6159"; } + ListElement{ radius: "65"; angle: "120"; value: "20.6017"; } + ListElement{ radius: "65"; angle: "125"; value: "18.2581"; } + ListElement{ radius: "65"; angle: "130"; value: "15.6027"; } + ListElement{ radius: "65"; angle: "135"; value: "12.6558"; } + ListElement{ radius: "65"; angle: "140"; value: "9.43986"; } + ListElement{ radius: "65"; angle: "145"; value: "5.9793"; } + ListElement{ radius: "65"; angle: "150"; value: "2.30048"; } + ListElement{ radius: "65"; angle: "155"; value: "-1.56861"; } + ListElement{ radius: "65"; angle: "160"; value: "-5.59852"; } + ListElement{ radius: "65"; angle: "165"; value: "-9.75857"; } + ListElement{ radius: "65"; angle: "170"; value: "-14.0171"; } + ListElement{ radius: "65"; angle: "175"; value: "-18.3417"; } + ListElement{ radius: "65"; angle: "180"; value: "-22.6995"; } + ListElement{ radius: "65"; angle: "185"; value: "-27.0573"; } + ListElement{ radius: "65"; angle: "190"; value: "-31.3819"; } + ListElement{ radius: "65"; angle: "195"; value: "-35.6405"; } + ListElement{ radius: "65"; angle: "200"; value: "-39.8005"; } + ListElement{ radius: "65"; angle: "205"; value: "-43.8304"; } + ListElement{ radius: "65"; angle: "210"; value: "-47.6995"; } + ListElement{ radius: "65"; angle: "215"; value: "-51.3783"; } + ListElement{ radius: "65"; angle: "220"; value: "-54.8389"; } + ListElement{ radius: "65"; angle: "225"; value: "-58.0549"; } + ListElement{ radius: "65"; angle: "230"; value: "-61.0017"; } + ListElement{ radius: "65"; angle: "235"; value: "-63.6571"; } + ListElement{ radius: "65"; angle: "240"; value: "-66.0008"; } + ListElement{ radius: "65"; angle: "245"; value: "-68.0149"; } + ListElement{ radius: "65"; angle: "250"; value: "-69.6842"; } + ListElement{ radius: "65"; angle: "255"; value: "-70.9958"; } + ListElement{ radius: "65"; angle: "260"; value: "-71.9399"; } + ListElement{ radius: "65"; angle: "265"; value: "-72.5093"; } + ListElement{ radius: "65"; angle: "270"; value: "-72.6995"; } + ListElement{ radius: "65"; angle: "275"; value: "-72.5093"; } + ListElement{ radius: "65"; angle: "280"; value: "-71.9399"; } + ListElement{ radius: "65"; angle: "285"; value: "-70.9958"; } + ListElement{ radius: "65"; angle: "290"; value: "-69.6842"; } + ListElement{ radius: "65"; angle: "295"; value: "-68.0149"; } + ListElement{ radius: "65"; angle: "300"; value: "-66.0008"; } + ListElement{ radius: "65"; angle: "305"; value: "-63.6571"; } + ListElement{ radius: "65"; angle: "310"; value: "-61.0017"; } + ListElement{ radius: "65"; angle: "315"; value: "-58.0549"; } + ListElement{ radius: "65"; angle: "320"; value: "-54.8389"; } + ListElement{ radius: "65"; angle: "325"; value: "-51.3783"; } + ListElement{ radius: "65"; angle: "330"; value: "-47.6995"; } + ListElement{ radius: "65"; angle: "335"; value: "-43.8304"; } + ListElement{ radius: "65"; angle: "340"; value: "-39.8005"; } + ListElement{ radius: "65"; angle: "345"; value: "-35.6405"; } + ListElement{ radius: "65"; angle: "350"; value: "-31.3819"; } + ListElement{ radius: "65"; angle: "355"; value: "-27.0573"; } + ListElement{ radius: "65"; angle: "360"; value: "-22.6995"; } + ListElement{ radius: "70"; angle: "0"; value: "-29.3893"; } + ListElement{ radius: "70"; angle: "5"; value: "-25.0315"; } + ListElement{ radius: "70"; angle: "10"; value: "-20.7069"; } + ListElement{ radius: "70"; angle: "15"; value: "-16.4483"; } + ListElement{ radius: "70"; angle: "20"; value: "-12.2883"; } + ListElement{ radius: "70"; angle: "25"; value: "-8.25835"; } + ListElement{ radius: "70"; angle: "30"; value: "-4.38926"; } + ListElement{ radius: "70"; angle: "35"; value: "-0.710441"; } + ListElement{ radius: "70"; angle: "40"; value: "2.75012"; } + ListElement{ radius: "70"; angle: "45"; value: "5.96608"; } + ListElement{ radius: "70"; angle: "50"; value: "8.91296"; } + ListElement{ radius: "70"; angle: "55"; value: "11.5683"; } + ListElement{ radius: "70"; angle: "60"; value: "13.912"; } + ListElement{ radius: "70"; angle: "65"; value: "15.9261"; } + ListElement{ radius: "70"; angle: "70"; value: "17.5954"; } + ListElement{ radius: "70"; angle: "75"; value: "18.907"; } + ListElement{ radius: "70"; angle: "80"; value: "19.8511"; } + ListElement{ radius: "70"; angle: "85"; value: "20.4205"; } + ListElement{ radius: "70"; angle: "90"; value: "20.6107"; } + ListElement{ radius: "70"; angle: "95"; value: "20.4205"; } + ListElement{ radius: "70"; angle: "100"; value: "19.8511"; } + ListElement{ radius: "70"; angle: "105"; value: "18.907"; } + ListElement{ radius: "70"; angle: "110"; value: "17.5954"; } + ListElement{ radius: "70"; angle: "115"; value: "15.9261"; } + ListElement{ radius: "70"; angle: "120"; value: "13.912"; } + ListElement{ radius: "70"; angle: "125"; value: "11.5683"; } + ListElement{ radius: "70"; angle: "130"; value: "8.91296"; } + ListElement{ radius: "70"; angle: "135"; value: "5.96608"; } + ListElement{ radius: "70"; angle: "140"; value: "2.75012"; } + ListElement{ radius: "70"; angle: "145"; value: "-0.710441"; } + ListElement{ radius: "70"; angle: "150"; value: "-4.38926"; } + ListElement{ radius: "70"; angle: "155"; value: "-8.25835"; } + ListElement{ radius: "70"; angle: "160"; value: "-12.2883"; } + ListElement{ radius: "70"; angle: "165"; value: "-16.4483"; } + ListElement{ radius: "70"; angle: "170"; value: "-20.7069"; } + ListElement{ radius: "70"; angle: "175"; value: "-25.0315"; } + ListElement{ radius: "70"; angle: "180"; value: "-29.3893"; } + ListElement{ radius: "70"; angle: "185"; value: "-33.747"; } + ListElement{ radius: "70"; angle: "190"; value: "-38.0717"; } + ListElement{ radius: "70"; angle: "195"; value: "-42.3302"; } + ListElement{ radius: "70"; angle: "200"; value: "-46.4903"; } + ListElement{ radius: "70"; angle: "205"; value: "-50.5202"; } + ListElement{ radius: "70"; angle: "210"; value: "-54.3893"; } + ListElement{ radius: "70"; angle: "215"; value: "-58.0681"; } + ListElement{ radius: "70"; angle: "220"; value: "-61.5286"; } + ListElement{ radius: "70"; angle: "225"; value: "-64.7446"; } + ListElement{ radius: "70"; angle: "230"; value: "-67.6915"; } + ListElement{ radius: "70"; angle: "235"; value: "-70.3469"; } + ListElement{ radius: "70"; angle: "240"; value: "-72.6905"; } + ListElement{ radius: "70"; angle: "245"; value: "-74.7047"; } + ListElement{ radius: "70"; angle: "250"; value: "-76.3739"; } + ListElement{ radius: "70"; angle: "255"; value: "-77.6856"; } + ListElement{ radius: "70"; angle: "260"; value: "-78.6297"; } + ListElement{ radius: "70"; angle: "265"; value: "-79.199"; } + ListElement{ radius: "70"; angle: "270"; value: "-79.3893"; } + ListElement{ radius: "70"; angle: "275"; value: "-79.199"; } + ListElement{ radius: "70"; angle: "280"; value: "-78.6297"; } + ListElement{ radius: "70"; angle: "285"; value: "-77.6856"; } + ListElement{ radius: "70"; angle: "290"; value: "-76.3739"; } + ListElement{ radius: "70"; angle: "295"; value: "-74.7047"; } + ListElement{ radius: "70"; angle: "300"; value: "-72.6905"; } + ListElement{ radius: "70"; angle: "305"; value: "-70.3469"; } + ListElement{ radius: "70"; angle: "310"; value: "-67.6915"; } + ListElement{ radius: "70"; angle: "315"; value: "-64.7446"; } + ListElement{ radius: "70"; angle: "320"; value: "-61.5286"; } + ListElement{ radius: "70"; angle: "325"; value: "-58.0681"; } + ListElement{ radius: "70"; angle: "330"; value: "-54.3893"; } + ListElement{ radius: "70"; angle: "335"; value: "-50.5202"; } + ListElement{ radius: "70"; angle: "340"; value: "-46.4903"; } + ListElement{ radius: "70"; angle: "345"; value: "-42.3302"; } + ListElement{ radius: "70"; angle: "350"; value: "-38.0717"; } + ListElement{ radius: "70"; angle: "355"; value: "-33.747"; } + ListElement{ radius: "70"; angle: "360"; value: "-29.3893"; } + ListElement{ radius: "75"; angle: "0"; value: "-35.3553"; } + ListElement{ radius: "75"; angle: "5"; value: "-30.9976"; } + ListElement{ radius: "75"; angle: "10"; value: "-26.6729"; } + ListElement{ radius: "75"; angle: "15"; value: "-22.4144"; } + ListElement{ radius: "75"; angle: "20"; value: "-18.2543"; } + ListElement{ radius: "75"; angle: "25"; value: "-14.2244"; } + ListElement{ radius: "75"; angle: "30"; value: "-10.3553"; } + ListElement{ radius: "75"; angle: "35"; value: "-6.67652"; } + ListElement{ radius: "75"; angle: "40"; value: "-3.21596"; } + ListElement{ radius: "75"; angle: "45"; value: "5.55112e-15"; } + ListElement{ radius: "75"; angle: "50"; value: "2.94688"; } + ListElement{ radius: "75"; angle: "55"; value: "5.60226"; } + ListElement{ radius: "75"; angle: "60"; value: "7.94593"; } + ListElement{ radius: "75"; angle: "65"; value: "9.96005"; } + ListElement{ radius: "75"; angle: "70"; value: "11.6293"; } + ListElement{ radius: "75"; angle: "75"; value: "12.941"; } + ListElement{ radius: "75"; angle: "80"; value: "13.885"; } + ListElement{ radius: "75"; angle: "85"; value: "14.4544"; } + ListElement{ radius: "75"; angle: "90"; value: "14.6447"; } + ListElement{ radius: "75"; angle: "95"; value: "14.4544"; } + ListElement{ radius: "75"; angle: "100"; value: "13.885"; } + ListElement{ radius: "75"; angle: "105"; value: "12.941"; } + ListElement{ radius: "75"; angle: "110"; value: "11.6293"; } + ListElement{ radius: "75"; angle: "115"; value: "9.96005"; } + ListElement{ radius: "75"; angle: "120"; value: "7.94593"; } + ListElement{ radius: "75"; angle: "125"; value: "5.60226"; } + ListElement{ radius: "75"; angle: "130"; value: "2.94688"; } + ListElement{ radius: "75"; angle: "135"; value: "5.55112e-15"; } + ListElement{ radius: "75"; angle: "140"; value: "-3.21596"; } + ListElement{ radius: "75"; angle: "145"; value: "-6.67652"; } + ListElement{ radius: "75"; angle: "150"; value: "-10.3553"; } + ListElement{ radius: "75"; angle: "155"; value: "-14.2244"; } + ListElement{ radius: "75"; angle: "160"; value: "-18.2543"; } + ListElement{ radius: "75"; angle: "165"; value: "-22.4144"; } + ListElement{ radius: "75"; angle: "170"; value: "-26.6729"; } + ListElement{ radius: "75"; angle: "175"; value: "-30.9976"; } + ListElement{ radius: "75"; angle: "180"; value: "-35.3553"; } + ListElement{ radius: "75"; angle: "185"; value: "-39.7131"; } + ListElement{ radius: "75"; angle: "190"; value: "-44.0377"; } + ListElement{ radius: "75"; angle: "195"; value: "-48.2963"; } + ListElement{ radius: "75"; angle: "200"; value: "-52.4563"; } + ListElement{ radius: "75"; angle: "205"; value: "-56.4863"; } + ListElement{ radius: "75"; angle: "210"; value: "-60.3553"; } + ListElement{ radius: "75"; angle: "215"; value: "-64.0342"; } + ListElement{ radius: "75"; angle: "220"; value: "-67.4947"; } + ListElement{ radius: "75"; angle: "225"; value: "-70.7107"; } + ListElement{ radius: "75"; angle: "230"; value: "-73.6576"; } + ListElement{ radius: "75"; angle: "235"; value: "-76.3129"; } + ListElement{ radius: "75"; angle: "240"; value: "-78.6566"; } + ListElement{ radius: "75"; angle: "245"; value: "-80.6707"; } + ListElement{ radius: "75"; angle: "250"; value: "-82.34"; } + ListElement{ radius: "75"; angle: "255"; value: "-83.6516"; } + ListElement{ radius: "75"; angle: "260"; value: "-84.5957"; } + ListElement{ radius: "75"; angle: "265"; value: "-85.1651"; } + ListElement{ radius: "75"; angle: "270"; value: "-85.3553"; } + ListElement{ radius: "75"; angle: "275"; value: "-85.1651"; } + ListElement{ radius: "75"; angle: "280"; value: "-84.5957"; } + ListElement{ radius: "75"; angle: "285"; value: "-83.6516"; } + ListElement{ radius: "75"; angle: "290"; value: "-82.34"; } + ListElement{ radius: "75"; angle: "295"; value: "-80.6707"; } + ListElement{ radius: "75"; angle: "300"; value: "-78.6566"; } + ListElement{ radius: "75"; angle: "305"; value: "-76.3129"; } + ListElement{ radius: "75"; angle: "310"; value: "-73.6576"; } + ListElement{ radius: "75"; angle: "315"; value: "-70.7107"; } + ListElement{ radius: "75"; angle: "320"; value: "-67.4947"; } + ListElement{ radius: "75"; angle: "325"; value: "-64.0342"; } + ListElement{ radius: "75"; angle: "330"; value: "-60.3553"; } + ListElement{ radius: "75"; angle: "335"; value: "-56.4863"; } + ListElement{ radius: "75"; angle: "340"; value: "-52.4563"; } + ListElement{ radius: "75"; angle: "345"; value: "-48.2963"; } + ListElement{ radius: "75"; angle: "350"; value: "-44.0377"; } + ListElement{ radius: "75"; angle: "355"; value: "-39.7131"; } + ListElement{ radius: "75"; angle: "360"; value: "-35.3553"; } + ListElement{ radius: "80"; angle: "0"; value: "-40.4508"; } + ListElement{ radius: "80"; angle: "5"; value: "-36.0931"; } + ListElement{ radius: "80"; angle: "10"; value: "-31.7684"; } + ListElement{ radius: "80"; angle: "15"; value: "-27.5099"; } + ListElement{ radius: "80"; angle: "20"; value: "-23.3498"; } + ListElement{ radius: "80"; angle: "25"; value: "-19.3199"; } + ListElement{ radius: "80"; angle: "30"; value: "-15.4508"; } + ListElement{ radius: "80"; angle: "35"; value: "-11.772"; } + ListElement{ radius: "80"; angle: "40"; value: "-8.31147"; } + ListElement{ radius: "80"; angle: "45"; value: "-5.09551"; } + ListElement{ radius: "80"; angle: "50"; value: "-2.14863"; } + ListElement{ radius: "80"; angle: "55"; value: "0.506752"; } + ListElement{ radius: "80"; angle: "60"; value: "2.85042"; } + ListElement{ radius: "80"; angle: "65"; value: "4.86454"; } + ListElement{ radius: "80"; angle: "70"; value: "6.53378"; } + ListElement{ radius: "80"; angle: "75"; value: "7.84544"; } + ListElement{ radius: "80"; angle: "80"; value: "8.78954"; } + ListElement{ radius: "80"; angle: "85"; value: "9.35889"; } + ListElement{ radius: "80"; angle: "90"; value: "9.54915"; } + ListElement{ radius: "80"; angle: "95"; value: "9.35889"; } + ListElement{ radius: "80"; angle: "100"; value: "8.78954"; } + ListElement{ radius: "80"; angle: "105"; value: "7.84544"; } + ListElement{ radius: "80"; angle: "110"; value: "6.53378"; } + ListElement{ radius: "80"; angle: "115"; value: "4.86454"; } + ListElement{ radius: "80"; angle: "120"; value: "2.85042"; } + ListElement{ radius: "80"; angle: "125"; value: "0.506752"; } + ListElement{ radius: "80"; angle: "130"; value: "-2.14863"; } + ListElement{ radius: "80"; angle: "135"; value: "-5.09551"; } + ListElement{ radius: "80"; angle: "140"; value: "-8.31147"; } + ListElement{ radius: "80"; angle: "145"; value: "-11.772"; } + ListElement{ radius: "80"; angle: "150"; value: "-15.4508"; } + ListElement{ radius: "80"; angle: "155"; value: "-19.3199"; } + ListElement{ radius: "80"; angle: "160"; value: "-23.3498"; } + ListElement{ radius: "80"; angle: "165"; value: "-27.5099"; } + ListElement{ radius: "80"; angle: "170"; value: "-31.7684"; } + ListElement{ radius: "80"; angle: "175"; value: "-36.0931"; } + ListElement{ radius: "80"; angle: "180"; value: "-40.4508"; } + ListElement{ radius: "80"; angle: "185"; value: "-44.8086"; } + ListElement{ radius: "80"; angle: "190"; value: "-49.1333"; } + ListElement{ radius: "80"; angle: "195"; value: "-53.3918"; } + ListElement{ radius: "80"; angle: "200"; value: "-57.5519"; } + ListElement{ radius: "80"; angle: "205"; value: "-61.5818"; } + ListElement{ radius: "80"; angle: "210"; value: "-65.4508"; } + ListElement{ radius: "80"; angle: "215"; value: "-69.1297"; } + ListElement{ radius: "80"; angle: "220"; value: "-72.5902"; } + ListElement{ radius: "80"; angle: "225"; value: "-75.8062"; } + ListElement{ radius: "80"; angle: "230"; value: "-78.7531"; } + ListElement{ radius: "80"; angle: "235"; value: "-81.4085"; } + ListElement{ radius: "80"; angle: "240"; value: "-83.7521"; } + ListElement{ radius: "80"; angle: "245"; value: "-85.7662"; } + ListElement{ radius: "80"; angle: "250"; value: "-87.4355"; } + ListElement{ radius: "80"; angle: "255"; value: "-88.7471"; } + ListElement{ radius: "80"; angle: "260"; value: "-89.6912"; } + ListElement{ radius: "80"; angle: "265"; value: "-90.2606"; } + ListElement{ radius: "80"; angle: "270"; value: "-90.4508"; } + ListElement{ radius: "80"; angle: "275"; value: "-90.2606"; } + ListElement{ radius: "80"; angle: "280"; value: "-89.6912"; } + ListElement{ radius: "80"; angle: "285"; value: "-88.7471"; } + ListElement{ radius: "80"; angle: "290"; value: "-87.4355"; } + ListElement{ radius: "80"; angle: "295"; value: "-85.7662"; } + ListElement{ radius: "80"; angle: "300"; value: "-83.7521"; } + ListElement{ radius: "80"; angle: "305"; value: "-81.4085"; } + ListElement{ radius: "80"; angle: "310"; value: "-78.7531"; } + ListElement{ radius: "80"; angle: "315"; value: "-75.8062"; } + ListElement{ radius: "80"; angle: "320"; value: "-72.5902"; } + ListElement{ radius: "80"; angle: "325"; value: "-69.1297"; } + ListElement{ radius: "80"; angle: "330"; value: "-65.4508"; } + ListElement{ radius: "80"; angle: "335"; value: "-61.5818"; } + ListElement{ radius: "80"; angle: "340"; value: "-57.5519"; } + ListElement{ radius: "80"; angle: "345"; value: "-53.3918"; } + ListElement{ radius: "80"; angle: "350"; value: "-49.1333"; } + ListElement{ radius: "80"; angle: "355"; value: "-44.8086"; } + ListElement{ radius: "80"; angle: "360"; value: "-40.4508"; } + ListElement{ radius: "85"; angle: "0"; value: "-44.5503"; } + ListElement{ radius: "85"; angle: "5"; value: "-40.1925"; } + ListElement{ radius: "85"; angle: "10"; value: "-35.8679"; } + ListElement{ radius: "85"; angle: "15"; value: "-31.6094"; } + ListElement{ radius: "85"; angle: "20"; value: "-27.4493"; } + ListElement{ radius: "85"; angle: "25"; value: "-23.4194"; } + ListElement{ radius: "85"; angle: "30"; value: "-19.5503"; } + ListElement{ radius: "85"; angle: "35"; value: "-15.8715"; } + ListElement{ radius: "85"; angle: "40"; value: "-12.4109"; } + ListElement{ radius: "85"; angle: "45"; value: "-9.19499"; } + ListElement{ radius: "85"; angle: "50"; value: "-6.2481"; } + ListElement{ radius: "85"; angle: "55"; value: "-3.59272"; } + ListElement{ radius: "85"; angle: "60"; value: "-1.24906"; } + ListElement{ radius: "85"; angle: "65"; value: "0.765063"; } + ListElement{ radius: "85"; angle: "70"; value: "2.4343"; } + ListElement{ radius: "85"; angle: "75"; value: "3.74597"; } + ListElement{ radius: "85"; angle: "80"; value: "4.69006"; } + ListElement{ radius: "85"; angle: "85"; value: "5.25941"; } + ListElement{ radius: "85"; angle: "90"; value: "5.44967"; } + ListElement{ radius: "85"; angle: "95"; value: "5.25941"; } + ListElement{ radius: "85"; angle: "100"; value: "4.69006"; } + ListElement{ radius: "85"; angle: "105"; value: "3.74597"; } + ListElement{ radius: "85"; angle: "110"; value: "2.4343"; } + ListElement{ radius: "85"; angle: "115"; value: "0.765063"; } + ListElement{ radius: "85"; angle: "120"; value: "-1.24906"; } + ListElement{ radius: "85"; angle: "125"; value: "-3.59272"; } + ListElement{ radius: "85"; angle: "130"; value: "-6.2481"; } + ListElement{ radius: "85"; angle: "135"; value: "-9.19499"; } + ListElement{ radius: "85"; angle: "140"; value: "-12.4109"; } + ListElement{ radius: "85"; angle: "145"; value: "-15.8715"; } + ListElement{ radius: "85"; angle: "150"; value: "-19.5503"; } + ListElement{ radius: "85"; angle: "155"; value: "-23.4194"; } + ListElement{ radius: "85"; angle: "160"; value: "-27.4493"; } + ListElement{ radius: "85"; angle: "165"; value: "-31.6094"; } + ListElement{ radius: "85"; angle: "170"; value: "-35.8679"; } + ListElement{ radius: "85"; angle: "175"; value: "-40.1925"; } + ListElement{ radius: "85"; angle: "180"; value: "-44.5503"; } + ListElement{ radius: "85"; angle: "185"; value: "-48.9081"; } + ListElement{ radius: "85"; angle: "190"; value: "-53.2327"; } + ListElement{ radius: "85"; angle: "195"; value: "-57.4913"; } + ListElement{ radius: "85"; angle: "200"; value: "-61.6513"; } + ListElement{ radius: "85"; angle: "205"; value: "-65.6812"; } + ListElement{ radius: "85"; angle: "210"; value: "-69.5503"; } + ListElement{ radius: "85"; angle: "215"; value: "-73.2291"; } + ListElement{ radius: "85"; angle: "220"; value: "-76.6897"; } + ListElement{ radius: "85"; angle: "225"; value: "-79.9057"; } + ListElement{ radius: "85"; angle: "230"; value: "-82.8525"; } + ListElement{ radius: "85"; angle: "235"; value: "-85.5079"; } + ListElement{ radius: "85"; angle: "240"; value: "-87.8516"; } + ListElement{ radius: "85"; angle: "245"; value: "-89.8657"; } + ListElement{ radius: "85"; angle: "250"; value: "-91.535"; } + ListElement{ radius: "85"; angle: "255"; value: "-92.8466"; } + ListElement{ radius: "85"; angle: "260"; value: "-93.7907"; } + ListElement{ radius: "85"; angle: "265"; value: "-94.3601"; } + ListElement{ radius: "85"; angle: "270"; value: "-94.5503"; } + ListElement{ radius: "85"; angle: "275"; value: "-94.3601"; } + ListElement{ radius: "85"; angle: "280"; value: "-93.7907"; } + ListElement{ radius: "85"; angle: "285"; value: "-92.8466"; } + ListElement{ radius: "85"; angle: "290"; value: "-91.535"; } + ListElement{ radius: "85"; angle: "295"; value: "-89.8657"; } + ListElement{ radius: "85"; angle: "300"; value: "-87.8516"; } + ListElement{ radius: "85"; angle: "305"; value: "-85.5079"; } + ListElement{ radius: "85"; angle: "310"; value: "-82.8525"; } + ListElement{ radius: "85"; angle: "315"; value: "-79.9057"; } + ListElement{ radius: "85"; angle: "320"; value: "-76.6897"; } + ListElement{ radius: "85"; angle: "325"; value: "-73.2291"; } + ListElement{ radius: "85"; angle: "330"; value: "-69.5503"; } + ListElement{ radius: "85"; angle: "335"; value: "-65.6812"; } + ListElement{ radius: "85"; angle: "340"; value: "-61.6513"; } + ListElement{ radius: "85"; angle: "345"; value: "-57.4913"; } + ListElement{ radius: "85"; angle: "350"; value: "-53.2327"; } + ListElement{ radius: "85"; angle: "355"; value: "-48.9081"; } + ListElement{ radius: "85"; angle: "360"; value: "-44.5503"; } + ListElement{ radius: "90"; angle: "0"; value: "-47.5528"; } + ListElement{ radius: "90"; angle: "5"; value: "-43.195"; } + ListElement{ radius: "90"; angle: "10"; value: "-38.8704"; } + ListElement{ radius: "90"; angle: "15"; value: "-34.6119"; } + ListElement{ radius: "90"; angle: "20"; value: "-30.4518"; } + ListElement{ radius: "90"; angle: "25"; value: "-26.4219"; } + ListElement{ radius: "90"; angle: "30"; value: "-22.5528"; } + ListElement{ radius: "90"; angle: "35"; value: "-18.874"; } + ListElement{ radius: "90"; angle: "40"; value: "-15.4134"; } + ListElement{ radius: "90"; angle: "45"; value: "-12.1975"; } + ListElement{ radius: "90"; angle: "50"; value: "-9.2506"; } + ListElement{ radius: "90"; angle: "55"; value: "-6.59522"; } + ListElement{ radius: "90"; angle: "60"; value: "-4.25156"; } + ListElement{ radius: "90"; angle: "65"; value: "-2.23744"; } + ListElement{ radius: "90"; angle: "70"; value: "-0.568195"; } + ListElement{ radius: "90"; angle: "75"; value: "0.743465"; } + ListElement{ radius: "90"; angle: "80"; value: "1.68756"; } + ListElement{ radius: "90"; angle: "85"; value: "2.25691"; } + ListElement{ radius: "90"; angle: "90"; value: "2.44717"; } + ListElement{ radius: "90"; angle: "95"; value: "2.25691"; } + ListElement{ radius: "90"; angle: "100"; value: "1.68756"; } + ListElement{ radius: "90"; angle: "105"; value: "0.743465"; } + ListElement{ radius: "90"; angle: "110"; value: "-0.568195"; } + ListElement{ radius: "90"; angle: "115"; value: "-2.23744"; } + ListElement{ radius: "90"; angle: "120"; value: "-4.25156"; } + ListElement{ radius: "90"; angle: "125"; value: "-6.59522"; } + ListElement{ radius: "90"; angle: "130"; value: "-9.2506"; } + ListElement{ radius: "90"; angle: "135"; value: "-12.1975"; } + ListElement{ radius: "90"; angle: "140"; value: "-15.4134"; } + ListElement{ radius: "90"; angle: "145"; value: "-18.874"; } + ListElement{ radius: "90"; angle: "150"; value: "-22.5528"; } + ListElement{ radius: "90"; angle: "155"; value: "-26.4219"; } + ListElement{ radius: "90"; angle: "160"; value: "-30.4518"; } + ListElement{ radius: "90"; angle: "165"; value: "-34.6119"; } + ListElement{ radius: "90"; angle: "170"; value: "-38.8704"; } + ListElement{ radius: "90"; angle: "175"; value: "-43.195"; } + ListElement{ radius: "90"; angle: "180"; value: "-47.5528"; } + ListElement{ radius: "90"; angle: "185"; value: "-51.9106"; } + ListElement{ radius: "90"; angle: "190"; value: "-56.2352"; } + ListElement{ radius: "90"; angle: "195"; value: "-60.4938"; } + ListElement{ radius: "90"; angle: "200"; value: "-64.6538"; } + ListElement{ radius: "90"; angle: "205"; value: "-68.6837"; } + ListElement{ radius: "90"; angle: "210"; value: "-72.5528"; } + ListElement{ radius: "90"; angle: "215"; value: "-76.2316"; } + ListElement{ radius: "90"; angle: "220"; value: "-79.6922"; } + ListElement{ radius: "90"; angle: "225"; value: "-82.9082"; } + ListElement{ radius: "90"; angle: "230"; value: "-85.855"; } + ListElement{ radius: "90"; angle: "235"; value: "-88.5104"; } + ListElement{ radius: "90"; angle: "240"; value: "-90.8541"; } + ListElement{ radius: "90"; angle: "245"; value: "-92.8682"; } + ListElement{ radius: "90"; angle: "250"; value: "-94.5375"; } + ListElement{ radius: "90"; angle: "255"; value: "-95.8491"; } + ListElement{ radius: "90"; angle: "260"; value: "-96.7932"; } + ListElement{ radius: "90"; angle: "265"; value: "-97.3626"; } + ListElement{ radius: "90"; angle: "270"; value: "-97.5528"; } + ListElement{ radius: "90"; angle: "275"; value: "-97.3626"; } + ListElement{ radius: "90"; angle: "280"; value: "-96.7932"; } + ListElement{ radius: "90"; angle: "285"; value: "-95.8491"; } + ListElement{ radius: "90"; angle: "290"; value: "-94.5375"; } + ListElement{ radius: "90"; angle: "295"; value: "-92.8682"; } + ListElement{ radius: "90"; angle: "300"; value: "-90.8541"; } + ListElement{ radius: "90"; angle: "305"; value: "-88.5104"; } + ListElement{ radius: "90"; angle: "310"; value: "-85.855"; } + ListElement{ radius: "90"; angle: "315"; value: "-82.9082"; } + ListElement{ radius: "90"; angle: "320"; value: "-79.6922"; } + ListElement{ radius: "90"; angle: "325"; value: "-76.2316"; } + ListElement{ radius: "90"; angle: "330"; value: "-72.5528"; } + ListElement{ radius: "90"; angle: "335"; value: "-68.6837"; } + ListElement{ radius: "90"; angle: "340"; value: "-64.6538"; } + ListElement{ radius: "90"; angle: "345"; value: "-60.4938"; } + ListElement{ radius: "90"; angle: "350"; value: "-56.2352"; } + ListElement{ radius: "90"; angle: "355"; value: "-51.9106"; } + ListElement{ radius: "90"; angle: "360"; value: "-47.5528"; } + ListElement{ radius: "95"; angle: "0"; value: "-49.3844"; } + ListElement{ radius: "95"; angle: "5"; value: "-45.0266"; } + ListElement{ radius: "95"; angle: "10"; value: "-40.702"; } + ListElement{ radius: "95"; angle: "15"; value: "-36.4435"; } + ListElement{ radius: "95"; angle: "20"; value: "-32.2834"; } + ListElement{ radius: "95"; angle: "25"; value: "-28.2535"; } + ListElement{ radius: "95"; angle: "30"; value: "-24.3844"; } + ListElement{ radius: "95"; angle: "35"; value: "-20.7056"; } + ListElement{ radius: "95"; angle: "40"; value: "-17.245"; } + ListElement{ radius: "95"; angle: "45"; value: "-14.0291"; } + ListElement{ radius: "95"; angle: "50"; value: "-11.0822"; } + ListElement{ radius: "95"; angle: "55"; value: "-8.42681"; } + ListElement{ radius: "95"; angle: "60"; value: "-6.08315"; } + ListElement{ radius: "95"; angle: "65"; value: "-4.06903"; } + ListElement{ radius: "95"; angle: "70"; value: "-2.39979"; } + ListElement{ radius: "95"; angle: "75"; value: "-1.08813"; } + ListElement{ radius: "95"; angle: "80"; value: "-0.144029"; } + ListElement{ radius: "95"; angle: "85"; value: "0.425318"; } + ListElement{ radius: "95"; angle: "90"; value: "0.615583"; } + ListElement{ radius: "95"; angle: "95"; value: "0.425318"; } + ListElement{ radius: "95"; angle: "100"; value: "-0.144029"; } + ListElement{ radius: "95"; angle: "105"; value: "-1.08813"; } + ListElement{ radius: "95"; angle: "110"; value: "-2.39979"; } + ListElement{ radius: "95"; angle: "115"; value: "-4.06903"; } + ListElement{ radius: "95"; angle: "120"; value: "-6.08315"; } + ListElement{ radius: "95"; angle: "125"; value: "-8.42681"; } + ListElement{ radius: "95"; angle: "130"; value: "-11.0822"; } + ListElement{ radius: "95"; angle: "135"; value: "-14.0291"; } + ListElement{ radius: "95"; angle: "140"; value: "-17.245"; } + ListElement{ radius: "95"; angle: "145"; value: "-20.7056"; } + ListElement{ radius: "95"; angle: "150"; value: "-24.3844"; } + ListElement{ radius: "95"; angle: "155"; value: "-28.2535"; } + ListElement{ radius: "95"; angle: "160"; value: "-32.2834"; } + ListElement{ radius: "95"; angle: "165"; value: "-36.4435"; } + ListElement{ radius: "95"; angle: "170"; value: "-40.702"; } + ListElement{ radius: "95"; angle: "175"; value: "-45.0266"; } + ListElement{ radius: "95"; angle: "180"; value: "-49.3844"; } + ListElement{ radius: "95"; angle: "185"; value: "-53.7422"; } + ListElement{ radius: "95"; angle: "190"; value: "-58.0668"; } + ListElement{ radius: "95"; angle: "195"; value: "-62.3254"; } + ListElement{ radius: "95"; angle: "200"; value: "-66.4854"; } + ListElement{ radius: "95"; angle: "205"; value: "-70.5153"; } + ListElement{ radius: "95"; angle: "210"; value: "-74.3844"; } + ListElement{ radius: "95"; angle: "215"; value: "-78.0632"; } + ListElement{ radius: "95"; angle: "220"; value: "-81.5238"; } + ListElement{ radius: "95"; angle: "225"; value: "-84.7398"; } + ListElement{ radius: "95"; angle: "230"; value: "-87.6866"; } + ListElement{ radius: "95"; angle: "235"; value: "-90.342"; } + ListElement{ radius: "95"; angle: "240"; value: "-92.6857"; } + ListElement{ radius: "95"; angle: "245"; value: "-94.6998"; } + ListElement{ radius: "95"; angle: "250"; value: "-96.369"; } + ListElement{ radius: "95"; angle: "255"; value: "-97.6807"; } + ListElement{ radius: "95"; angle: "260"; value: "-98.6248"; } + ListElement{ radius: "95"; angle: "265"; value: "-99.1942"; } + ListElement{ radius: "95"; angle: "270"; value: "-99.3844"; } + ListElement{ radius: "95"; angle: "275"; value: "-99.1942"; } + ListElement{ radius: "95"; angle: "280"; value: "-98.6248"; } + ListElement{ radius: "95"; angle: "285"; value: "-97.6807"; } + ListElement{ radius: "95"; angle: "290"; value: "-96.369"; } + ListElement{ radius: "95"; angle: "295"; value: "-94.6998"; } + ListElement{ radius: "95"; angle: "300"; value: "-92.6857"; } + ListElement{ radius: "95"; angle: "305"; value: "-90.342"; } + ListElement{ radius: "95"; angle: "310"; value: "-87.6866"; } + ListElement{ radius: "95"; angle: "315"; value: "-84.7398"; } + ListElement{ radius: "95"; angle: "320"; value: "-81.5238"; } + ListElement{ radius: "95"; angle: "325"; value: "-78.0632"; } + ListElement{ radius: "95"; angle: "330"; value: "-74.3844"; } + ListElement{ radius: "95"; angle: "335"; value: "-70.5153"; } + ListElement{ radius: "95"; angle: "340"; value: "-66.4854"; } + ListElement{ radius: "95"; angle: "345"; value: "-62.3254"; } + ListElement{ radius: "95"; angle: "350"; value: "-58.0668"; } + ListElement{ radius: "95"; angle: "355"; value: "-53.7422"; } + ListElement{ radius: "95"; angle: "360"; value: "-49.3844"; } + ListElement{ radius: "100"; angle: "0"; value: "-50"; } + ListElement{ radius: "100"; angle: "5"; value: "-45.6422"; } + ListElement{ radius: "100"; angle: "10"; value: "-41.3176"; } + ListElement{ radius: "100"; angle: "15"; value: "-37.059"; } + ListElement{ radius: "100"; angle: "20"; value: "-32.899"; } + ListElement{ radius: "100"; angle: "25"; value: "-28.8691"; } + ListElement{ radius: "100"; angle: "30"; value: "-25"; } + ListElement{ radius: "100"; angle: "35"; value: "-21.3212"; } + ListElement{ radius: "100"; angle: "40"; value: "-17.8606"; } + ListElement{ radius: "100"; angle: "45"; value: "-14.6447"; } + ListElement{ radius: "100"; angle: "50"; value: "-11.6978"; } + ListElement{ radius: "100"; angle: "55"; value: "-9.0424"; } + ListElement{ radius: "100"; angle: "60"; value: "-6.69873"; } + ListElement{ radius: "100"; angle: "65"; value: "-4.68461"; } + ListElement{ radius: "100"; angle: "70"; value: "-3.01537"; } + ListElement{ radius: "100"; angle: "75"; value: "-1.70371"; } + ListElement{ radius: "100"; angle: "80"; value: "-0.759612"; } + ListElement{ radius: "100"; angle: "85"; value: "-0.190265"; } + ListElement{ radius: "100"; angle: "90"; value: "0"; } + ListElement{ radius: "100"; angle: "95"; value: "-0.190265"; } + ListElement{ radius: "100"; angle: "100"; value: "-0.759612"; } + ListElement{ radius: "100"; angle: "105"; value: "-1.70371"; } + ListElement{ radius: "100"; angle: "110"; value: "-3.01537"; } + ListElement{ radius: "100"; angle: "115"; value: "-4.68461"; } + ListElement{ radius: "100"; angle: "120"; value: "-6.69873"; } + ListElement{ radius: "100"; angle: "125"; value: "-9.0424"; } + ListElement{ radius: "100"; angle: "130"; value: "-11.6978"; } + ListElement{ radius: "100"; angle: "135"; value: "-14.6447"; } + ListElement{ radius: "100"; angle: "140"; value: "-17.8606"; } + ListElement{ radius: "100"; angle: "145"; value: "-21.3212"; } + ListElement{ radius: "100"; angle: "150"; value: "-25"; } + ListElement{ radius: "100"; angle: "155"; value: "-28.8691"; } + ListElement{ radius: "100"; angle: "160"; value: "-32.899"; } + ListElement{ radius: "100"; angle: "165"; value: "-37.059"; } + ListElement{ radius: "100"; angle: "170"; value: "-41.3176"; } + ListElement{ radius: "100"; angle: "175"; value: "-45.6422"; } + ListElement{ radius: "100"; angle: "180"; value: "-50"; } + ListElement{ radius: "100"; angle: "185"; value: "-54.3578"; } + ListElement{ radius: "100"; angle: "190"; value: "-58.6824"; } + ListElement{ radius: "100"; angle: "195"; value: "-62.941"; } + ListElement{ radius: "100"; angle: "200"; value: "-67.101"; } + ListElement{ radius: "100"; angle: "205"; value: "-71.1309"; } + ListElement{ radius: "100"; angle: "210"; value: "-75"; } + ListElement{ radius: "100"; angle: "215"; value: "-78.6788"; } + ListElement{ radius: "100"; angle: "220"; value: "-82.1394"; } + ListElement{ radius: "100"; angle: "225"; value: "-85.3553"; } + ListElement{ radius: "100"; angle: "230"; value: "-88.3022"; } + ListElement{ radius: "100"; angle: "235"; value: "-90.9576"; } + ListElement{ radius: "100"; angle: "240"; value: "-93.3013"; } + ListElement{ radius: "100"; angle: "245"; value: "-95.3154"; } + ListElement{ radius: "100"; angle: "250"; value: "-96.9846"; } + ListElement{ radius: "100"; angle: "255"; value: "-98.2963"; } + ListElement{ radius: "100"; angle: "260"; value: "-99.2404"; } + ListElement{ radius: "100"; angle: "265"; value: "-99.8097"; } + ListElement{ radius: "100"; angle: "270"; value: "-100"; } + ListElement{ radius: "100"; angle: "275"; value: "-99.8097"; } + ListElement{ radius: "100"; angle: "280"; value: "-99.2404"; } + ListElement{ radius: "100"; angle: "285"; value: "-98.2963"; } + ListElement{ radius: "100"; angle: "290"; value: "-96.9846"; } + ListElement{ radius: "100"; angle: "295"; value: "-95.3154"; } + ListElement{ radius: "100"; angle: "300"; value: "-93.3013"; } + ListElement{ radius: "100"; angle: "305"; value: "-90.9576"; } + ListElement{ radius: "100"; angle: "310"; value: "-88.3022"; } + ListElement{ radius: "100"; angle: "315"; value: "-85.3553"; } + ListElement{ radius: "100"; angle: "320"; value: "-82.1394"; } + ListElement{ radius: "100"; angle: "325"; value: "-78.6788"; } + ListElement{ radius: "100"; angle: "330"; value: "-75"; } + ListElement{ radius: "100"; angle: "335"; value: "-71.1309"; } + ListElement{ radius: "100"; angle: "340"; value: "-67.101"; } + ListElement{ radius: "100"; angle: "345"; value: "-62.941"; } + ListElement{ radius: "100"; angle: "350"; value: "-58.6824"; } + ListElement{ radius: "100"; angle: "355"; value: "-54.3578"; } + ListElement{ radius: "100"; angle: "360"; value: "-50"; } + } +} diff --git a/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/NewButton.qml b/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/NewButton.qml new file mode 100644 index 00000000..e4fb99d2 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/NewButton.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + +Item { + id: newbutton + + property alias text: buttonText.text + + signal clicked + + implicitWidth: buttonText.implicitWidth + 5 + implicitHeight: buttonText.implicitHeight + 10 + + Button { + id: buttonText + width: parent.width + height: parent.height + + style: ButtonStyle { + label: Component { + Text { + text: buttonText.text + clip: true + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + anchors.fill: parent + } + } + } + onClicked: newbutton.clicked() + } +} diff --git a/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/main.qml b/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/main.qml new file mode 100644 index 00000000..4c77fd45 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/qml/qmlspectrogram/main.qml @@ -0,0 +1,293 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Window 2.1 +import QtDataVisualization 1.2 +import "." + +Window { + id: mainview + title: "Qt Quick 2 Spectrogram Example" + visible: true + width: 1024 + height: 768 + color: surfaceGraph.theme.windowColor + + Data { + id: surfaceData + } + + Item { + id: surfaceView + width: mainview.width + height: mainview.height + anchors.top: mainview.top + anchors.left: mainview.left + + ColorGradient { + id: surfaceGradient + ColorGradientStop { position: 0.0; color: "black" } + ColorGradientStop { position: 0.2; color: "red" } + ColorGradientStop { position: 0.5; color: "blue" } + ColorGradientStop { position: 0.8; color: "yellow" } + ColorGradientStop { position: 1.0; color: "white" } + } + + ValueAxis3D { + id: xAxis + segmentCount: 8 + labelFormat: "%i\u00B0" + title: "Angle" + titleVisible: true + titleFixed: false + } + + ValueAxis3D { + id: yAxis + segmentCount: 8 + labelFormat: "%i \%" + title: "Value" + titleVisible: true + labelAutoRotation: 0 + titleFixed: false + } + + ValueAxis3D { + id: zAxis + segmentCount: 5 + labelFormat: "%i nm" + title: "Radius" + titleVisible: true + titleFixed: false + } + + Theme3D { + id: customTheme + type: Theme3D.ThemeQt + // Don't show specular spotlight as we don't want it to distort the colors + lightStrength: 0.0 + ambientLightStrength: 1.0 + backgroundEnabled: false + gridLineColor: "#AAAAAA" + windowColor: "#EEEEEE" + } + + + //! [5] + TouchInputHandler3D { + id: customInputHandler + rotationEnabled: false + } + //! [5] + + //! [0] + //! [7] + Surface3D { + //! [7] + id: surfaceGraph + width: surfaceView.width + height: surfaceView.height + + shadowQuality: AbstractGraph3D.ShadowQualityNone + selectionMode: AbstractGraph3D.SelectionSlice | AbstractGraph3D.SelectionItemAndColumn + axisX: xAxis + axisY: yAxis + axisZ: zAxis + + theme: customTheme + //! [6] + inputHandler: customInputHandler + //! [6] + + // Remove the perspective and view the graph from top down to achieve 2D effect + //! [1] + orthoProjection: true + scene.activeCamera.cameraPreset: Camera3D.CameraPresetDirectlyAbove + //! [1] + + //! [2] + flipHorizontalGrid: true + //! [2] + + //! [4] + radialLabelOffset: 0.01 + //! [4] + + horizontalAspectRatio: 1 + scene.activeCamera.zoomLevel: 85 + + Surface3DSeries { + id: surfaceSeries + flatShadingEnabled: false + drawMode: Surface3DSeries.DrawSurface + baseGradient: surfaceGradient + colorStyle: Theme3D.ColorStyleRangeGradient + itemLabelFormat: "(@xLabel, @zLabel): @yLabel" + + ItemModelSurfaceDataProxy { + itemModel: surfaceData.model + rowRole: "radius" + columnRole: "angle" + yPosRole: "value" + } + } + } + //! [0] + } + + RowLayout { + id: buttonLayout + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + opacity: 0.5 + + //! [3] + NewButton { + id: polarToggle + Layout.fillWidth: true + Layout.fillHeight: true + text: "Switch to polar" + onClicked: { + if (surfaceGraph.polar === false) { + surfaceGraph.polar = true + text = "Switch to cartesian" + } else { + surfaceGraph.polar = false + text = "Switch to polar" + } + } + } + //! [3] + + NewButton { + id: orthoToggle + Layout.fillWidth: true + Layout.fillHeight: true + text: "Switch to perspective" + onClicked: { + if (surfaceGraph.orthoProjection === true) { + surfaceGraph.orthoProjection = false; + xAxis.labelAutoRotation = 30 + yAxis.labelAutoRotation = 30 + zAxis.labelAutoRotation = 30 + customInputHandler.rotationEnabled = true + text = "Switch to orthographic" + } else { + surfaceGraph.orthoProjection = true; + surfaceGraph.scene.activeCamera.cameraPreset = Camera3D.CameraPresetDirectlyAbove + surfaceSeries.drawMode &= ~Surface3DSeries.DrawWireframe; + xAxis.labelAutoRotation = 0 + yAxis.labelAutoRotation = 0 + zAxis.labelAutoRotation = 0 + customInputHandler.rotationEnabled = false + text = "Switch to perspective" + } + } + } + + NewButton { + id: flipGridToggle + Layout.fillWidth: true + Layout.fillHeight: true + text: "Toggle axis grid on top" + onClicked: { + onClicked: { + if (surfaceGraph.flipHorizontalGrid === true) { + surfaceGraph.flipHorizontalGrid = false; + } else { + surfaceGraph.flipHorizontalGrid = true; + } + } + } + } + + NewButton { + id: labelOffsetToggle + Layout.fillWidth: true + Layout.fillHeight: true + text: "Toggle radial label position" + visible: surfaceGraph.polar + onClicked: { + if (surfaceGraph.radialLabelOffset >= 1.0) { + surfaceGraph.radialLabelOffset = 0.01 + } else { + surfaceGraph.radialLabelOffset = 1.0 + } + } + } + + NewButton { + id: surfaceGridToggle + Layout.fillWidth: true + Layout.fillHeight: true + text: "Toggle surface grid" + visible: !surfaceGraph.orthoProjection + onClicked: { + if (surfaceSeries.drawMode & Surface3DSeries.DrawWireframe) { + surfaceSeries.drawMode &= ~Surface3DSeries.DrawWireframe; + } else { + surfaceSeries.drawMode |= Surface3DSeries.DrawWireframe; + } + } + } + + } + + Rectangle { + id: legend + anchors.margins: 20 + anchors.bottom: parent.bottom + anchors.top: buttonLayout.bottom + anchors.right: parent.right + border.color: "black" + border.width: 1 + width: 50 + rotation: 180 + gradient: Gradient { + GradientStop { position: 0.0; color: "black" } + GradientStop { position: 0.2; color: "red" } + GradientStop { position: 0.5; color: "blue" } + GradientStop { position: 0.8; color: "yellow" } + GradientStop { position: 1.0; color: "white" } + } + } + + Text { + anchors.verticalCenter: legend.bottom + anchors.right: legend.left + anchors.margins: 2 + text: surfaceGraph.axisY.min + "%" + } + + Text { + anchors.verticalCenter: legend.verticalCenter + anchors.right: legend.left + anchors.margins: 2 + text: (surfaceGraph.axisY.max + surfaceGraph.axisY.min) / 2 + "%" + } + + Text { + anchors.verticalCenter: legend.top + anchors.right: legend.left + anchors.margins: 2 + text: surfaceGraph.axisY.max + "%" + } +} diff --git a/examples/datavisualization/qmlspectrogram/qmlspectrogram.pro b/examples/datavisualization/qmlspectrogram/qmlspectrogram.pro new file mode 100644 index 00000000..655fb0b8 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/qmlspectrogram.pro @@ -0,0 +1,12 @@ +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +# The .cpp file which was generated for your project. Feel free to hack it. +SOURCES += main.cpp + +RESOURCES += qmlspectrogram.qrc + +OTHER_FILES += doc/src/* \ + doc/images/* \ + qml/qmlspectrogram/* diff --git a/examples/datavisualization/qmlspectrogram/qmlspectrogram.qrc b/examples/datavisualization/qmlspectrogram/qmlspectrogram.qrc new file mode 100644 index 00000000..9f024404 --- /dev/null +++ b/examples/datavisualization/qmlspectrogram/qmlspectrogram.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/qml"> + <file>qml/qmlspectrogram/Data.qml</file> + <file>qml/qmlspectrogram/main.qml</file> + <file>qml/qmlspectrogram/NewButton.qml</file> + </qresource> +</RCC> diff --git a/examples/datavisualization/qmlsurfacelayers/layer_2.png b/examples/datavisualization/qmlsurfacelayers/layer_2.png Binary files differindex 61631ae8..3af154e2 100644 --- a/examples/datavisualization/qmlsurfacelayers/layer_2.png +++ b/examples/datavisualization/qmlsurfacelayers/layer_2.png diff --git a/examples/datavisualization/texturesurface/custominputhandler.cpp b/examples/datavisualization/texturesurface/custominputhandler.cpp new file mode 100644 index 00000000..2510df54 --- /dev/null +++ b/examples/datavisualization/texturesurface/custominputhandler.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "custominputhandler.h" + +#include <QtDataVisualization/Q3DCamera> +#include <QtCore/qmath.h> + +CustomInputHandler::CustomInputHandler(QAbstract3DGraph *graph, QObject *parent) : + Q3DInputHandler(parent), + m_highlight(0), + m_mousePressed(false), + m_state(StateNormal), + m_axisX(0), + m_axisZ(0), + m_speedModifier(20.0f) +{ + // 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->delta()); + + 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.0f, 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.0f; + + // 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.0f; + 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.0f; + m_axisZMinValue -= adjust; + m_axisZMaxValue += adjust; + } +} diff --git a/examples/datavisualization/texturesurface/custominputhandler.h b/examples/datavisualization/texturesurface/custominputhandler.h new file mode 100644 index 00000000..8bef990e --- /dev/null +++ b/examples/datavisualization/texturesurface/custominputhandler.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef CUSTOMINPUTHANDLER_H +#define CUSTOMINPUTHANDLER_H + +#include <QtDataVisualization/Q3DInputHandler> +#include <QtDataVisualization/QAbstract3DGraph> +#include <QtDataVisualization/QValue3DAxis> +#include "highlightseries.h" + +using namespace QtDataVisualization; + +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; } + + 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; + bool m_mousePressed; + InputState m_state; + QValue3DAxis *m_axisX; + QValue3DAxis *m_axisY; + QValue3DAxis *m_axisZ; + float m_speedModifier; + float m_aspectRatio; + float m_axisXMinValue; + float m_axisXMaxValue; + float m_axisXMinRange; + float m_axisZMinValue; + float m_axisZMaxValue; + float m_axisZMinRange; + float m_areaMinValue; + float m_areaMaxValue; +}; + +#endif diff --git a/examples/datavisualization/texturesurface/doc/images/texturesurface-example.png b/examples/datavisualization/texturesurface/doc/images/texturesurface-example.png Binary files differnew file mode 100644 index 00000000..76819607 --- /dev/null +++ b/examples/datavisualization/texturesurface/doc/images/texturesurface-example.png diff --git a/examples/datavisualization/texturesurface/doc/src/texturesurface.qdoc b/examples/datavisualization/texturesurface/doc/src/texturesurface.qdoc new file mode 100644 index 00000000..483b8110 --- /dev/null +++ b/examples/datavisualization/texturesurface/doc/src/texturesurface.qdoc @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +/*! + \example texturesurface + \title Textured Surface Example + \ingroup qtdatavisualization_examples + \brief Using texture with Q3DSurface. + \since QtDataVisualization 1.2 + + The textured surface example shows how to add an image as a texture for a surface. The example + shows also how to: + + \list + \li Create a surface series from an image + \li Use custom input handler to enable zooming and panning + \li Highlight an area of the surface + \endlist + + \image texturesurface-example.png + + \section1 Texture to a surface series + + The image to be set as a texture to a surface can be set using QSurface3DSeries::setTextureFile(). + In this example we have added a check box to control if the texture is set or not. The + following code extract is for reacting to the check box selections. The image in this + example is read from the resource file where it is as a JPG file. Setting an empty file + with the method clears the texture, and the surface uses the gradients or colors from the theme. + + \snippet texturesurface/surfacegraph.cpp 0 + + \section1 Topographic surface series + + The topographic data for this example is obtained from National Land Survey of Finland. It + provides a product called \c{Elevation Model 2 m}, which was suitable for our needs. We selected + Levi fell to be shown. The accuracy of the data was well beyond our needs and therefore it + is compressed and encoded into a PNG file. The height value from the original ASCII data is + encoded into RGB format using a multiplier, which you will see later on a code extract. + The multiplier is calculated simply by dividing the largest 24 bit value with the highest point + in Finland. + + Qt Data Visualization has a special proxy for height map image files, but it converts + only one byte values. So to utilize the bigger accuracy on the data from National Land + Survey of Finland, we read the data from the PNG file and decode it into QSurface3DSeries. + The following code samples show how this is done. + + First the encoding multiplier. + \snippet texturesurface/topographicseries.cpp 0 + + And then the actual decoding. + \snippet texturesurface/topographicseries.cpp 1 + + \section1 Use custom input handler to enable zooming and panning + + For the panning the implementation is similar to the \l{Axis Range Dragging With Labels Example}. + The difference is that in this example we follow only dragging of X and Z axis and we don't + allow dragging the surface outside the graph. The control for this is very simple and done as + on the following example for the X axis. + + \snippet texturesurface/custominputhandler.cpp 0 + + For the zooming we catch the \c wheelEvent and adjust the X and Y axis ranges according to delta + value on QWheelEvent. The Y axis is also adjusted so that the aspect ratio between Y axis and + XZ plane stays the same, and we don't get silly looking graph with height exaggerated too much. + + \snippet texturesurface/custominputhandler.cpp 1 + + In this case we want to control 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, 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 texturesurface/custominputhandler.cpp 2 + + \section1 Highlight an area of the surface + + The main idea on creating a highlight on the surface is to create a copy of the series and add + a bit of offset to the y value. On this example the class \c HighlightSeries implements the + creation of the copy on its \c handlePositionChange method. Firstly the \c HighlightSeries + needs to get the pointer to the original series and then it starts to listen the + QSurface3DSeries::selectedPointChanged signal. + + \snippet texturesurface/highlightseries.cpp 0 + + When the signal arrives, first thing is to check that the position is valid. Then the ranges + for the copied area are calculated and checked that they stay within the bounds. Finally + we simply fill the data array of the highlight series with the range from the data array of + topography series. + + \snippet texturesurface/highlightseries.cpp 1 + + \section1 A gradient to the highlight series + + Since the \c HighlightSeries is QSurface3DSeries, we can use all the decoration methods series can + have. In this example we added 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, we need to adjust + the gradient color positions as the range change. + + For the gradient color positions we define proportional values. + + \snippet texturesurface/highlightseries.cpp 2 + + The gradient modification is done on \c handleGradientChange method and we connect it to react to + changes on Y axis. + + \snippet texturesurface/surfacegraph.cpp 1 + + When a change on Y axis max value happens, we calculate the gradient color positions. + + \snippet texturesurface/highlightseries.cpp 3 +*/ diff --git a/examples/datavisualization/texturesurface/highlightseries.cpp b/examples/datavisualization/texturesurface/highlightseries.cpp new file mode 100644 index 00000000..13d1fba3 --- /dev/null +++ b/examples/datavisualization/texturesurface/highlightseries.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "highlightseries.h" + +using namespace QtDataVisualization; + +//! [2] +const float darkRedPos = 1.0f; +const float redPos = 0.8f; +const float yellowPos = 0.6f; +const float greenPos = 0.4f; +const float darkGreenPos = 0.2f; +//! [2] + +HighlightSeries::HighlightSeries() + : m_width(100), + m_height(100) +{ + 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(); + + QSurfaceDataArray *dataArray = new QSurfaceDataArray; + dataArray->reserve(endZ - startZ); + for (int i = startZ; i < endZ; i++) { + QSurfaceDataRow *newRow = new QSurfaceDataRow(endX - startX); + QSurfaceDataRow *srcRow = srcArray.at(i); + for (int j = startX, p = 0; j < endX; j++, p++) { + QVector3D pos = srcRow->at(j).position(); + (*newRow)[p].setPosition(QVector3D(pos.x(), pos.y() + 0.1f, pos.z())); + } + *dataArray << newRow; + } + + dataProxy()->resetArray(dataArray); + setVisible(true); +} +//! [1] + +//! [3] +void HighlightSeries::handleGradientChange(float value) +{ + float ratio = m_minHeight / value; + + QLinearGradient gr; + gr.setColorAt(0.0f, 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/texturesurface/highlightseries.h b/examples/datavisualization/texturesurface/highlightseries.h new file mode 100644 index 00000000..aa1590e5 --- /dev/null +++ b/examples/datavisualization/texturesurface/highlightseries.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef HIGHLIGHTSERIES_H +#define HIGHLIGHTSERIES_H + +#include <QtDataVisualization/QSurface3DSeries> + +#include "topographicseries.h" + +using namespace QtDataVisualization; + +class HighlightSeries : public QSurface3DSeries +{ + Q_OBJECT +public: + explicit HighlightSeries(); + ~HighlightSeries(); + + void setTopographicSeries(TopographicSeries *series); + inline void setMinHeight(float height) { m_minHeight = height; } + +public slots: + void handlePositionChange(const QPoint &position); + void handleGradientChange(float value); + +private: + int m_width; + int m_height; + int m_srcWidth; + int m_srcHeight; + QPoint m_position; + TopographicSeries *m_topographicSeries; + float m_minHeight; +}; + +#endif // HIGHLIGHTSERIES_H diff --git a/examples/datavisualization/texturesurface/license.txt b/examples/datavisualization/texturesurface/license.txt new file mode 100644 index 00000000..749daf31 --- /dev/null +++ b/examples/datavisualization/texturesurface/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/texturesurface/main.cpp b/examples/datavisualization/texturesurface/main.cpp new file mode 100644 index 00000000..ed1a9be4 --- /dev/null +++ b/examples/datavisualization/texturesurface/main.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "surfacegraph.h" + +#include <QtWidgets/QApplication> +#include <QtWidgets/QWidget> +#include <QtWidgets/QHBoxLayout> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QGroupBox> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QLabel> +#include <QtGui/QScreen> +#include <QtGui/QPainter> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + Q3DSurface *graph = new Q3DSurface(); + QWidget *container = QWidget::createWindowContainer(graph); + + QSize screenSize = graph->screen()->size(); + container->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 1.6)); + container->setMaximumSize(screenSize); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + container->setFocusPolicy(Qt::StrongFocus); + + QWidget *widget = new QWidget; + QHBoxLayout *hLayout = new QHBoxLayout(widget); + QVBoxLayout *vLayout = new QVBoxLayout(); + hLayout->addWidget(container, 1); + hLayout->addLayout(vLayout); + vLayout->setAlignment(Qt::AlignTop); + + widget->setWindowTitle(QStringLiteral("Textured surface example")); + + QCheckBox *enableTexture = new QCheckBox(widget); + enableTexture->setText(QStringLiteral("Surface texture")); + + int height = 400; + int width = 100; + int border = 10; + QLinearGradient gr(0, 0, 1, height - 2 * border); + gr.setColorAt(1.0f, 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.0f, Qt::darkRed); + + QPixmap pm(width, height); + pm.fill(Qt::transparent); + QPainter pmp(&pm); + pmp.setBrush(QBrush(gr)); + pmp.setPen(Qt::NoPen); + pmp.drawRect(border, border, 35, height - 2 * border); + pmp.setPen(Qt::black); + int step = (height - 2 * border) / 5; + for (int i = 0; i < 6; i++) { + int yPos = i * step + border; + pmp.drawLine(border, yPos, 55, yPos); + pmp.drawText(60, yPos + 2, QString("%1 m").arg(550 - (i * 110))); + } + + QLabel *label = new QLabel(widget); + label->setPixmap(pm); + + QGroupBox *heightMapGroupBox = new QGroupBox(QStringLiteral("Height color map")); + QVBoxLayout *colorMapVBox = new QVBoxLayout; + colorMapVBox->addWidget(label); + heightMapGroupBox->setLayout(colorMapVBox); + + vLayout->addWidget(enableTexture); + vLayout->addWidget(heightMapGroupBox); + + widget->show(); + + SurfaceGraph *modifier = new SurfaceGraph(graph); + + QObject::connect(enableTexture, &QCheckBox::stateChanged, + modifier, &SurfaceGraph::toggleSurfaceTexture); + + enableTexture->setChecked(true); + + return app.exec(); +} diff --git a/examples/datavisualization/texturesurface/maptexture.jpg b/examples/datavisualization/texturesurface/maptexture.jpg Binary files differnew file mode 100644 index 00000000..ae5d66eb --- /dev/null +++ b/examples/datavisualization/texturesurface/maptexture.jpg diff --git a/examples/datavisualization/texturesurface/surfacegraph.cpp b/examples/datavisualization/texturesurface/surfacegraph.cpp new file mode 100644 index 00000000..e01a329d --- /dev/null +++ b/examples/datavisualization/texturesurface/surfacegraph.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "surfacegraph.h" +#include "topographicseries.h" + +#include <QtDataVisualization/QValue3DAxis> +#include <QtDataVisualization/Q3DTheme> + +using namespace QtDataVisualization; + +const float areaWidth = 8000.0f; +const float areaHeight = 8000.0f; +const float aspectRatio = 0.1389f; +const float minRange = areaWidth * 0.49f; + +SurfaceGraph::SurfaceGraph(Q3DSurface *surface) + : m_graph(surface) +{ + m_graph->setAxisX(new QValue3DAxis); + m_graph->setAxisY(new QValue3DAxis); + m_graph->setAxisZ(new QValue3DAxis); + m_graph->axisX()->setLabelFormat("%i"); + m_graph->axisZ()->setLabelFormat("%i"); + m_graph->axisX()->setRange(0.0f, areaWidth); + m_graph->axisY()->setRange(100.0f, areaWidth * aspectRatio); + m_graph->axisZ()->setRange(0.0f, areaHeight); + m_graph->axisX()->setLabelAutoRotation(30); + m_graph->axisY()->setLabelAutoRotation(90); + m_graph->axisZ()->setLabelAutoRotation(30); + m_graph->activeTheme()->setType(Q3DTheme::ThemePrimaryColors); + + QFont font = m_graph->activeTheme()->font(); + font.setPointSize(20); + m_graph->activeTheme()->setFont(font); + + m_topography = new TopographicSeries(); + m_topography->setTopographyFile(":/maps/topography", areaWidth, areaHeight); + m_topography->setItemLabelFormat(QStringLiteral("@yLabel m")); + + m_highlight = new HighlightSeries(); + m_highlight->setTopographicSeries(m_topography); + m_highlight->setMinHeight(minRange * aspectRatio); + m_highlight->handleGradientChange(areaWidth * aspectRatio); +//! [1] + QObject::connect(m_graph->axisY(), &QValue3DAxis::maxChanged, + m_highlight, &HighlightSeries::handleGradientChange); +//! [1] + + m_graph->addSeries(m_topography); + m_graph->addSeries(m_highlight); + + m_inputHandler = new CustomInputHandler(m_graph); + m_inputHandler->setHighlightSeries(m_highlight); + m_inputHandler->setAxes(m_graph->axisX(), m_graph->axisY(), m_graph->axisZ()); + m_inputHandler->setLimits(0.0f, areaWidth, minRange); + m_inputHandler->setAspectRatio(aspectRatio); + + m_graph->setActiveInputHandler(m_inputHandler); +} + +SurfaceGraph::~SurfaceGraph() +{ + delete m_graph; +} + +//! [0] +void SurfaceGraph::toggleSurfaceTexture(bool enable) +{ + if (enable) + m_topography->setTextureFile(":/maps/maptexture"); + else + m_topography->setTextureFile(""); +} +//! [0] diff --git a/examples/datavisualization/texturesurface/surfacegraph.h b/examples/datavisualization/texturesurface/surfacegraph.h new file mode 100644 index 00000000..c1d81595 --- /dev/null +++ b/examples/datavisualization/texturesurface/surfacegraph.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef SURFACEGRAPH_H +#define SURFACEGRAPH_H + +#include <QtDataVisualization/Q3DSurface> +#include <QtDataVisualization/QSurface3DSeries> +#include <QtWidgets/QSlider> +#include "topographicseries.h" +#include "highlightseries.h" + +#include "custominputhandler.h" + +using namespace QtDataVisualization; + +class SurfaceGraph : public QObject +{ + Q_OBJECT +public: + explicit SurfaceGraph(Q3DSurface *surface); + ~SurfaceGraph(); + + void toggleSurfaceTexture(bool enable); + +private: + Q3DSurface *m_graph; + + TopographicSeries *m_topography; + HighlightSeries *m_highlight; + int m_highlightWidth; + int m_highlightHeight; + + CustomInputHandler *m_inputHandler; +}; + +#endif // SURFACEGRAPH_H diff --git a/examples/datavisualization/texturesurface/texturedsurface.qrc b/examples/datavisualization/texturesurface/texturedsurface.qrc new file mode 100644 index 00000000..94b96d24 --- /dev/null +++ b/examples/datavisualization/texturesurface/texturedsurface.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/maps"> + <file alias="topography">topography.png</file> + <file alias="maptexture">maptexture.jpg</file> + </qresource> +</RCC> diff --git a/examples/datavisualization/texturesurface/texturesurface.pro b/examples/datavisualization/texturesurface/texturesurface.pro new file mode 100644 index 00000000..f24c3d17 --- /dev/null +++ b/examples/datavisualization/texturesurface/texturesurface.pro @@ -0,0 +1,25 @@ +android|ios { + error( "This example is not supported for android or ios." ) +} + +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +SOURCES += main.cpp \ + surfacegraph.cpp \ + topographicseries.cpp \ + highlightseries.cpp \ + custominputhandler.cpp + +HEADERS += surfacegraph.h \ + topographicseries.h \ + highlightseries.h \ + custominputhandler.h + +QT += widgets + +RESOURCES += texturedsurface.qrc + +OTHER_FILES += doc/src/* \ + doc/images/* diff --git a/examples/datavisualization/texturesurface/topographicseries.cpp b/examples/datavisualization/texturesurface/topographicseries.cpp new file mode 100644 index 00000000..530e56b4 --- /dev/null +++ b/examples/datavisualization/texturesurface/topographicseries.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "topographicseries.h" + +using namespace QtDataVisualization; + +//! [0] +// Value used to encode height data as RGB value on PNG file +const float packingFactor = 11983.0f; +//! [0] + +TopographicSeries::TopographicSeries() +{ + setDrawMode(QSurface3DSeries::DrawSurface); + setFlatShadingEnabled(true); +} + +TopographicSeries::~TopographicSeries() +{ +} + +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); + + QSurfaceDataArray *dataArray = new QSurfaceDataArray; + dataArray->reserve(imageHeight); + for (int i = 0; i < imageHeight; i++) { + int p = i * widthBits; + float z = height - float(i) * stepZ; + QSurfaceDataRow *newRow = new QSurfaceDataRow(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)[j].setPosition(QVector3D(float(j) * stepX, y, z)); + p = p + 4; + } + *dataArray << newRow; + } + + dataProxy()->resetArray(dataArray); +//! [1] + + m_sampleCountX = float(imageWidth); + m_sampleCountZ = float(imageHeight); +} diff --git a/examples/datavisualization/texturesurface/topographicseries.h b/examples/datavisualization/texturesurface/topographicseries.h new file mode 100644 index 00000000..06530c63 --- /dev/null +++ b/examples/datavisualization/texturesurface/topographicseries.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef TOPOGRAPHICSERIES_H +#define TOPOGRAPHICSERIES_H + +#include <QtDataVisualization/QSurface3DSeries> + +using namespace QtDataVisualization; + +class TopographicSeries : public QSurface3DSeries +{ + Q_OBJECT +public: + explicit TopographicSeries(); + ~TopographicSeries(); + + void setTopographyFile(const QString file, float width, float height); + + float sampleCountX() { return m_sampleCountX; } + float sampleCountZ() { return m_sampleCountZ; } + +public slots: + +private: + float m_sampleCountX; + float m_sampleCountZ; +}; + +#endif // TOPOGRAPHICSERIES_H diff --git a/examples/datavisualization/texturesurface/topography.png b/examples/datavisualization/texturesurface/topography.png Binary files differnew file mode 100644 index 00000000..9349cdb3 --- /dev/null +++ b/examples/datavisualization/texturesurface/topography.png diff --git a/examples/datavisualization/volumetric/doc/images/volumetric-example.png b/examples/datavisualization/volumetric/doc/images/volumetric-example.png Binary files differnew file mode 100644 index 00000000..277d4fe4 --- /dev/null +++ b/examples/datavisualization/volumetric/doc/images/volumetric-example.png diff --git a/examples/datavisualization/volumetric/doc/src/volumetric.qdoc b/examples/datavisualization/volumetric/doc/src/volumetric.qdoc new file mode 100644 index 00000000..39616670 --- /dev/null +++ b/examples/datavisualization/volumetric/doc/src/volumetric.qdoc @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +/*! + \example volumetric + \title Volumetric rendering Example + \ingroup qtdatavisualization_examples + \brief Rendering volumetric objects. + \since QtDataVisualization 1.2 + + This example shows how to use QCustom3DVolume items to display volumetric data. + + \image volumetric-example.png + + \section1 Initializing volume item + + The QCustom3DVolume items are special custom items (see QCustom3DItem), which can be used + to display volumetric data. The volume items are only supported with orthographic projection, + so first we make sure the graph is using it: + + \snippet volumetric/volumetric.cpp 6 + + The following code shows how to create a volumetric item tied to the data ranges of the axes: + + \snippet volumetric/volumetric.cpp 0 + + By setting the QCustom3DItem::scalingAbsolute property to \c{false}, we indicate that the + scaling of the volume should follow the changes in the data ranges. Next we define the + internal contents of the volume: + + \snippet volumetric/volumetric.cpp 1 + + We use eight bit indexed color for our texture, as it is compact and makes it easy to adjust the + colors without needing to reset the whole texture. For the texture data we use the data we + created earlier based on some height maps. + Typically the data for volume items comes pregenerated in a form of a stack of images, so we are + not going to explain the data generation in detail. Please refer to the example code if you + are interested in the actual data generation process. + + Since we are using eight bit indexed colors, we need a color table to map the eight bit color + indexes to actual colors. We use one we populated on our own, but in a typical use case you + would get the color table from the source images: + + \snippet volumetric/volumetric.cpp 2 + + We want to optionally show slice frames around the volume, so we initialize their properties. + Initially, the frames will be hidden: + + \snippet volumetric/volumetric.cpp 5 + + Finally we add the volume as a custom item to the graph to display it: + + \snippet volumetric/volumetric.cpp 3 + + \section1 Slicing into the volume + + Unless the volume is largely transparent, you can only see the surface of it, which is often + not very helpful. One way to inspect the internal structure of the volume is to view the slices + of the volume. QCustom3DVolume provides two ways to display the slices. The first is to show + the selected slices in place of the volume. For example, to specify a slice perpendicular to + the X-axis, you can use the following method: + + \snippet volumetric/volumetric.cpp 7 + + To actually draw the slice specified above, the QCustom3DVolume::drawSlices property must be + also set: + + \snippet volumetric/volumetric.cpp 8 + + The second way to view slices is to use QCustom3DVolume::renderSlice() method, which produces + a QImage from the specified slice. This image can then be displayed on another widget, such + as a QLabel here: + + \snippet volumetric/volumetric.cpp 9 + + \section1 Adjusting volume transparency + + Sometimes viewing just the slices doesn't give you a good understanding of the volume's internal + structure. QCustom3DVolume provides two properties that can be used to adjust the volume + transparency: + + \snippet volumetric/volumetric.cpp 11 + \dots + \snippet volumetric/volumetric.cpp 10 + + The QCustom3DVolume::alphaMultiplier is a general multiplier that is applied to the alpha value + of each voxel of the volume. It makes it possible to add uniform transparency to the already + somewhat transparent portions of the volume to reveal internal opaque details. This multiplier + doesn't affect colors that are fully opaque, unless the QCustom3DVolume::preserveOpacity + property is set to \c{false}. + + An alternative way to adjust the transparency of the volume is adjust the alpha values of the + voxels directly. For eight bit indexed textures, this is done simply by modifying and + resetting the color table: + + \snippet volumetric/volumetric.cpp 12 + + \section1 High definition vs. low definition shader + + By default the volume rendering uses the high definition shader. It accounts for each + voxel of the volume with correct weight when ray-tracing the volume contents, + providing an accurate representation of even the finer details of the volume. + However, this is computationally very expensive, so the frame rate suffers. + If rendering speed is more important than pixel-perfect + accuracy of the volume contents, you can take the much faster low definition shader into use + by setting \c{false} for QCustom3DVolume::useHighDefShader property. The low definition shader + achieves the speed by making compromises on the accuracy, so it doesn't guarantee each voxel + of the volume will be sampled. This can lead to flickering and/or other rendering artifacts + on the finer details of the volume. + + \snippet volumetric/volumetric.cpp 13 + + \section1 Example contents +*/ diff --git a/examples/datavisualization/volumetric/layer_ground.png b/examples/datavisualization/volumetric/layer_ground.png Binary files differnew file mode 100644 index 00000000..3f96a122 --- /dev/null +++ b/examples/datavisualization/volumetric/layer_ground.png diff --git a/examples/datavisualization/volumetric/layer_magma.png b/examples/datavisualization/volumetric/layer_magma.png Binary files differnew file mode 100644 index 00000000..01434d35 --- /dev/null +++ b/examples/datavisualization/volumetric/layer_magma.png diff --git a/examples/datavisualization/volumetric/layer_water.png b/examples/datavisualization/volumetric/layer_water.png Binary files differnew file mode 100644 index 00000000..4d57563e --- /dev/null +++ b/examples/datavisualization/volumetric/layer_water.png diff --git a/examples/datavisualization/volumetric/main.cpp b/examples/datavisualization/volumetric/main.cpp new file mode 100644 index 00000000..faf379ec --- /dev/null +++ b/examples/datavisualization/volumetric/main.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "volumetric.h" + +#include <QtWidgets/QApplication> +#include <QtWidgets/QWidget> +#include <QtWidgets/QHBoxLayout> +#include <QtWidgets/QVBoxLayout> +#include <QtWidgets/QRadioButton> +#include <QtWidgets/QSlider> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QLabel> +#include <QtWidgets/QGroupBox> +#include <QtGui/QScreen> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + Q3DScatter *graph = new Q3DScatter(); + QWidget *container = QWidget::createWindowContainer(graph); + + QSize screenSize = graph->screen()->size(); + container->setMinimumSize(QSize(screenSize.width() / 3, screenSize.height() / 3)); + container->setMaximumSize(screenSize); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + container->setFocusPolicy(Qt::StrongFocus); + + QWidget *widget = new QWidget(); + QHBoxLayout *hLayout = new QHBoxLayout(widget); + QVBoxLayout *vLayout = new QVBoxLayout(); + QVBoxLayout *vLayout2 = new QVBoxLayout(); + hLayout->addWidget(container, 1); + hLayout->addLayout(vLayout); + hLayout->addLayout(vLayout2); + + widget->setWindowTitle(QStringLiteral("Volumetric object example - 3D terrain")); + + QCheckBox *sliceXCheckBox = new QCheckBox(widget); + sliceXCheckBox->setText(QStringLiteral("Slice volume on X axis")); + sliceXCheckBox->setChecked(false); + QCheckBox *sliceYCheckBox = new QCheckBox(widget); + sliceYCheckBox->setText(QStringLiteral("Slice volume on Y axis")); + sliceYCheckBox->setChecked(false); + QCheckBox *sliceZCheckBox = new QCheckBox(widget); + sliceZCheckBox->setText(QStringLiteral("Slice volume on Z axis")); + sliceZCheckBox->setChecked(false); + + QSlider *sliceXSlider = new QSlider(Qt::Horizontal, widget); + sliceXSlider->setMinimum(0); + sliceXSlider->setMaximum(1024); + sliceXSlider->setValue(512); + sliceXSlider->setEnabled(true); + QSlider *sliceYSlider = new QSlider(Qt::Horizontal, widget); + sliceYSlider->setMinimum(0); + sliceYSlider->setMaximum(1024); + sliceYSlider->setValue(512); + sliceYSlider->setEnabled(true); + QSlider *sliceZSlider = new QSlider(Qt::Horizontal, widget); + sliceZSlider->setMinimum(0); + sliceZSlider->setMaximum(1024); + sliceZSlider->setValue(512); + sliceZSlider->setEnabled(true); + + QCheckBox *fpsCheckBox = new QCheckBox(widget); + fpsCheckBox->setText(QStringLiteral("Show FPS")); + fpsCheckBox->setChecked(false); + QLabel *fpsLabel = new QLabel(QStringLiteral(""), widget); + + QGroupBox *textureDetailGroupBox = new QGroupBox(QStringLiteral("Texture detail")); + + QRadioButton *lowDetailRB = new QRadioButton(widget); + lowDetailRB->setText(QStringLiteral("Low (128x64x128)")); + lowDetailRB->setChecked(true); + + QRadioButton *mediumDetailRB = new QRadioButton(widget); + mediumDetailRB->setText(QStringLiteral("Generating...")); + mediumDetailRB->setChecked(false); + mediumDetailRB->setEnabled(false); + + QRadioButton *highDetailRB = new QRadioButton(widget); + highDetailRB->setText(QStringLiteral("Generating...")); + highDetailRB->setChecked(false); + highDetailRB->setEnabled(false); + + QVBoxLayout *textureDetailVBox = new QVBoxLayout; + textureDetailVBox->addWidget(lowDetailRB); + textureDetailVBox->addWidget(mediumDetailRB); + textureDetailVBox->addWidget(highDetailRB); + textureDetailGroupBox->setLayout(textureDetailVBox); + + QGroupBox *areaGroupBox = new QGroupBox(QStringLiteral("Show area")); + + QRadioButton *areaAllRB = new QRadioButton(widget); + areaAllRB->setText(QStringLiteral("Whole region")); + areaAllRB->setChecked(true); + + QRadioButton *areaMineRB = new QRadioButton(widget); + areaMineRB->setText(QStringLiteral("The mine")); + areaMineRB->setChecked(false); + + QRadioButton *areaMountainRB = new QRadioButton(widget); + areaMountainRB->setText(QStringLiteral("The mountain")); + areaMountainRB->setChecked(false); + + QVBoxLayout *areaVBox = new QVBoxLayout; + areaVBox->addWidget(areaAllRB); + areaVBox->addWidget(areaMineRB); + areaVBox->addWidget(areaMountainRB); + areaGroupBox->setLayout(areaVBox); + + QCheckBox *colorTableCheckBox = new QCheckBox(widget); + colorTableCheckBox->setText(QStringLiteral("Alternate color table")); + colorTableCheckBox->setChecked(false); + + QLabel *sliceImageXLabel = new QLabel(widget); + QLabel *sliceImageYLabel = new QLabel(widget); + QLabel *sliceImageZLabel = new QLabel(widget); + sliceImageXLabel->setMinimumSize(QSize(200, 100)); + sliceImageYLabel->setMinimumSize(QSize(200, 200)); + sliceImageZLabel->setMinimumSize(QSize(200, 100)); + sliceImageXLabel->setMaximumSize(QSize(200, 100)); + sliceImageYLabel->setMaximumSize(QSize(200, 200)); + sliceImageZLabel->setMaximumSize(QSize(200, 100)); + sliceImageXLabel->setFrameShape(QFrame::Box); + sliceImageYLabel->setFrameShape(QFrame::Box); + sliceImageZLabel->setFrameShape(QFrame::Box); + sliceImageXLabel->setScaledContents(true); + sliceImageYLabel->setScaledContents(true); + sliceImageZLabel->setScaledContents(true); + + QSlider *alphaMultiplierSlider = new QSlider(Qt::Horizontal, widget); + alphaMultiplierSlider->setMinimum(0); + alphaMultiplierSlider->setMaximum(139); + alphaMultiplierSlider->setValue(100); + alphaMultiplierSlider->setEnabled(true); + QLabel *alphaMultiplierLabel = new QLabel(QStringLiteral("Alpha multiplier: 1.0")); + + QCheckBox *preserveOpacityCheckBox = new QCheckBox(widget); + preserveOpacityCheckBox->setText(QStringLiteral("Preserve opacity")); + preserveOpacityCheckBox->setChecked(true); + + QCheckBox *transparentGroundCheckBox = new QCheckBox(widget); + transparentGroundCheckBox->setText(QStringLiteral("Transparent ground")); + transparentGroundCheckBox->setChecked(false); + + QCheckBox *useHighDefShaderCheckBox = new QCheckBox(widget); + useHighDefShaderCheckBox->setText(QStringLiteral("Use HD shader")); + useHighDefShaderCheckBox->setChecked(true); + + QLabel *performanceNoteLabel = + new QLabel(QStringLiteral( + "Note: A high end graphics card is\nrecommended with the HD shader\nwhen the volume contains a lot of\ntransparent areas.")); + performanceNoteLabel->setFrameShape(QFrame::Box); + + QCheckBox *drawSliceFramesCheckBox = new QCheckBox(widget); + drawSliceFramesCheckBox->setText(QStringLiteral("Draw slice frames")); + drawSliceFramesCheckBox->setChecked(false); + + vLayout->addWidget(sliceXCheckBox); + vLayout->addWidget(sliceXSlider); + vLayout->addWidget(sliceImageXLabel); + vLayout->addWidget(sliceYCheckBox); + vLayout->addWidget(sliceYSlider); + vLayout->addWidget(sliceImageYLabel); + vLayout->addWidget(sliceZCheckBox); + vLayout->addWidget(sliceZSlider); + vLayout->addWidget(sliceImageZLabel); + vLayout->addWidget(drawSliceFramesCheckBox, 1, Qt::AlignTop); + vLayout2->addWidget(fpsCheckBox); + vLayout2->addWidget(fpsLabel); + vLayout2->addWidget(textureDetailGroupBox); + vLayout2->addWidget(areaGroupBox); + vLayout2->addWidget(colorTableCheckBox); + vLayout2->addWidget(alphaMultiplierLabel); + vLayout2->addWidget(alphaMultiplierSlider); + vLayout2->addWidget(preserveOpacityCheckBox); + vLayout2->addWidget(transparentGroundCheckBox); + vLayout2->addWidget(useHighDefShaderCheckBox); + vLayout2->addWidget(performanceNoteLabel, 1, Qt::AlignTop); + + VolumetricModifier *modifier = new VolumetricModifier(graph); + modifier->setFpsLabel(fpsLabel); + modifier->setMediumDetailRB(mediumDetailRB); + modifier->setHighDetailRB(highDetailRB); + modifier->setSliceSliders(sliceXSlider, sliceYSlider, sliceZSlider); + modifier->setSliceLabels(sliceImageXLabel, sliceImageYLabel, sliceImageZLabel); + modifier->setAlphaMultiplierLabel(alphaMultiplierLabel); + modifier->setTransparentGround(transparentGroundCheckBox->isChecked()); + + QObject::connect(fpsCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::setFpsMeasurement); + QObject::connect(sliceXCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::sliceX); + QObject::connect(sliceYCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::sliceY); + QObject::connect(sliceZCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::sliceZ); + QObject::connect(sliceXSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustSliceX); + QObject::connect(sliceYSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustSliceY); + QObject::connect(sliceZSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustSliceZ); + QObject::connect(lowDetailRB, &QRadioButton::toggled, modifier, + &VolumetricModifier::toggleLowDetail); + QObject::connect(mediumDetailRB, &QRadioButton::toggled, modifier, + &VolumetricModifier::toggleMediumDetail); + QObject::connect(highDetailRB, &QRadioButton::toggled, modifier, + &VolumetricModifier::toggleHighDetail); + QObject::connect(colorTableCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::changeColorTable); + QObject::connect(preserveOpacityCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::setPreserveOpacity); + QObject::connect(transparentGroundCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::setTransparentGround); + QObject::connect(useHighDefShaderCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::setUseHighDefShader); + QObject::connect(alphaMultiplierSlider, &QSlider::valueChanged, modifier, + &VolumetricModifier::adjustAlphaMultiplier); + QObject::connect(areaAllRB, &QRadioButton::toggled, modifier, + &VolumetricModifier::toggleAreaAll); + QObject::connect(areaMineRB, &QRadioButton::toggled, modifier, + &VolumetricModifier::toggleAreaMine); + QObject::connect(areaMountainRB, &QRadioButton::toggled, modifier, + &VolumetricModifier::toggleAreaMountain); + QObject::connect(drawSliceFramesCheckBox, &QCheckBox::stateChanged, modifier, + &VolumetricModifier::setDrawSliceFrames); + + widget->show(); + return app.exec(); +} diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp new file mode 100644 index 00000000..20338598 --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.cpp @@ -0,0 +1,764 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#include "volumetric.h" +#include <QtDataVisualization/qvalue3daxis.h> +#include <QtDataVisualization/q3dscene.h> +#include <QtDataVisualization/q3dcamera.h> +#include <QtDataVisualization/q3dtheme.h> +#include <QtDataVisualization/qcustom3dlabel.h> +#include <QtDataVisualization/q3dscatter.h> +#include <QtDataVisualization/q3dinputhandler.h> +#include <QtCore/qmath.h> +#include <QtWidgets/QLabel> +#include <QtWidgets/QRadioButton> +#include <QtWidgets/QSlider> +#include <QtCore/QDebug> +#include <QtGui/QOpenGLContext> + +using namespace QtDataVisualization; + +const int lowDetailSize(128); +const int mediumDetailSize(256); +const int highDetailSize(512); +const int colorTableSize(256); +const int layerDataSize(512); +const int mineShaftDiameter(1); + +const int airColorIndex(254); +const int mineShaftColorIndex(255); +const int layerColorThickness(60); +const int heightToColorDiv(140); +const int magmaColorsMin(0); +const int magmaColorsMax(layerColorThickness); +const int aboveWaterGroundColorsMin(magmaColorsMax + 1); +const int aboveWaterGroundColorsMax(aboveWaterGroundColorsMin + layerColorThickness); +const int underWaterGroundColorsMin(aboveWaterGroundColorsMax + 1); +const int underWaterGroundColorsMax(underWaterGroundColorsMin + layerColorThickness); +const int waterColorsMin(underWaterGroundColorsMax + 1); +const int waterColorsMax(waterColorsMin + layerColorThickness); +const int terrainTransparency(12); + +static bool isOpenGLES() +{ +#if defined(QT_OPENGL_ES_2) + return true; +#elif (QT_VERSION < QT_VERSION_CHECK(5, 3, 0)) + return false; +#else + return QOpenGLContext::currentContext()->isOpenGLES(); +#endif +} + +VolumetricModifier::VolumetricModifier(Q3DScatter *scatter) + : m_graph(scatter), + m_volumeItem(0), + m_sliceIndexX(lowDetailSize / 2), + m_sliceIndexY(lowDetailSize / 4), + m_sliceIndexZ(lowDetailSize / 2), + m_slicingX(false), + m_slicingY(false), + m_slicingZ(false), + m_mediumDetailRB(0), + m_highDetailRB(0), + m_lowDetailData(0), + m_mediumDetailData(0), + m_highDetailData(0), + m_mediumDetailIndex(0), + m_highDetailIndex(0), + m_mediumDetailShaftIndex(0), + m_highDetailShaftIndex(0), + m_sliceSliderX(0), + m_sliceSliderY(0), + m_sliceSliderZ(0), + m_usingPrimaryTable(true), + m_sliceLabelX(0), + m_sliceLabelY(0), + m_sliceLabelZ(0) +{ + m_graph->activeTheme()->setType(Q3DTheme::ThemeQt); + m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone); + m_graph->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPresetFront); + //! [6] + m_graph->setOrthoProjection(true); + //! [6] + m_graph->activeTheme()->setBackgroundEnabled(false); + + // Only allow zooming at the center and limit the zoom to 200% to avoid clipping issues + static_cast<Q3DInputHandler *>(m_graph->activeInputHandler())->setZoomAtTargetEnabled(false); + m_graph->scene()->activeCamera()->setMaxZoomLevel(200.0f); + + toggleAreaAll(true); + + if (!isOpenGLES()) { + m_lowDetailData = new QVector<uchar>(lowDetailSize * lowDetailSize * lowDetailSize / 2); + m_mediumDetailData = new QVector<uchar>(mediumDetailSize * mediumDetailSize * mediumDetailSize / 2); + m_highDetailData = new QVector<uchar>(highDetailSize * highDetailSize * highDetailSize / 2); + + initHeightMap(QStringLiteral(":/heightmaps/layer_ground.png"), m_groundLayer); + initHeightMap(QStringLiteral(":/heightmaps/layer_water.png"), m_waterLayer); + initHeightMap(QStringLiteral(":/heightmaps/layer_magma.png"), m_magmaLayer); + + initMineShaftArray(); + + createVolume(lowDetailSize, 0, lowDetailSize, m_lowDetailData); + excavateMineShaft(lowDetailSize, 0, m_mineShaftArray.size(), m_lowDetailData); + + //! [0] + m_volumeItem = new QCustom3DVolume; + // Adjust water level to zero with a minor tweak to y-coordinate position and scaling + m_volumeItem->setScaling( + QVector3D(m_graph->axisX()->max() - m_graph->axisX()->min(), + (m_graph->axisY()->max() - m_graph->axisY()->min()) * 0.91f, + m_graph->axisZ()->max() - m_graph->axisZ()->min())); + m_volumeItem->setPosition( + QVector3D((m_graph->axisX()->max() + m_graph->axisX()->min()) / 2.0f, + -0.045f * (m_graph->axisY()->max() - m_graph->axisY()->min()) + + (m_graph->axisY()->max() + m_graph->axisY()->min()) / 2.0f, + (m_graph->axisZ()->max() + m_graph->axisZ()->min()) / 2.0f)); + m_volumeItem->setScalingAbsolute(false); + //! [0] + //! [1] + m_volumeItem->setTextureWidth(lowDetailSize); + m_volumeItem->setTextureHeight(lowDetailSize / 2); + m_volumeItem->setTextureDepth(lowDetailSize); + m_volumeItem->setTextureFormat(QImage::Format_Indexed8); + m_volumeItem->setTextureData(new QVector<uchar>(*m_lowDetailData)); + //! [1] + + // Generate color tables. + m_colorTable1.resize(colorTableSize); + m_colorTable2.resize(colorTableSize); + + for (int i = 0; i < colorTableSize - 2; i++) { + if (i < magmaColorsMax) { + m_colorTable1[i] = qRgba(130 - (i * 2), 0, 0, 255); + } else if (i < aboveWaterGroundColorsMax) { + m_colorTable1[i] = qRgba((i - magmaColorsMax) * 4, + ((i - magmaColorsMax) * 2) + 120, + (i - magmaColorsMax) * 5, terrainTransparency); + } else if (i < underWaterGroundColorsMax) { + m_colorTable1[i] = qRgba(((layerColorThickness - i - aboveWaterGroundColorsMax)) + 70, + ((layerColorThickness - i - aboveWaterGroundColorsMax) * 2) + 20, + ((layerColorThickness - i - aboveWaterGroundColorsMax)) + 50, + terrainTransparency); + } else if (i < waterColorsMax) { + m_colorTable1[i] = qRgba(0, 0, ((i - underWaterGroundColorsMax) * 2) + 120, + terrainTransparency); + } else { + m_colorTable1[i] = qRgba(0, 0, 0, 0); // Not used + } + } + m_colorTable1[airColorIndex] = qRgba(0, 0, 0, 0); + m_colorTable1[mineShaftColorIndex] = qRgba(50, 50, 50, 255); + + // The alternate color table just has gray gradients for all terrain except water + for (int i = 0; i < colorTableSize - 2; i++) { + if (i < magmaColorsMax) { + m_colorTable2[i] = qRgba(((i - aboveWaterGroundColorsMax) * 2), + ((i - aboveWaterGroundColorsMax) * 2), + ((i - aboveWaterGroundColorsMax) * 2), 255); + } else if (i < underWaterGroundColorsMax) { + m_colorTable2[i] = qRgba(((i - aboveWaterGroundColorsMax) * 2), + ((i - aboveWaterGroundColorsMax) * 2), + ((i - aboveWaterGroundColorsMax) * 2), terrainTransparency); + } else if (i < waterColorsMax) { + m_colorTable2[i] = qRgba(0, 0, ((i - underWaterGroundColorsMax) * 2) + 120, + terrainTransparency); + } else { + m_colorTable2[i] = qRgba(0, 0, 0, 0); // Not used + } + } + m_colorTable2[airColorIndex] = qRgba(0, 0, 0, 0); + m_colorTable2[mineShaftColorIndex] = qRgba(255, 255, 0, 255); + + //! [2] + m_volumeItem->setColorTable(m_colorTable1); + //! [2] + + //! [5] + m_volumeItem->setSliceFrameGaps(QVector3D(0.01f, 0.02f, 0.01f)); + m_volumeItem->setSliceFrameThicknesses(QVector3D(0.0025f, 0.005f, 0.0025f)); + m_volumeItem->setSliceFrameWidths(QVector3D(0.0025f, 0.005f, 0.0025f)); + m_volumeItem->setDrawSliceFrames(false); + //! [5] + handleSlicingChanges(); + + //! [3] + m_graph->addCustomItem(m_volumeItem); + //! [3] + + m_timer.start(0); + } else { + // OpenGL ES2 doesn't support 3D textures, so show a warning label instead + QCustom3DLabel *warningLabel = new QCustom3DLabel( + "QCustom3DVolume is not supported with OpenGL ES2", + QFont(), + QVector3D(0.0f, 0.5f, 0.0f), + QVector3D(1.5f, 1.5f, 0.0f), + QQuaternion()); + warningLabel->setPositionAbsolute(true); + warningLabel->setFacingCamera(true); + m_graph->addCustomItem(warningLabel); + } + + QObject::connect(m_graph, &QAbstract3DGraph::currentFpsChanged, this, + &VolumetricModifier::handleFpsChange); + QObject::connect(&m_timer, &QTimer::timeout, this, + &VolumetricModifier::handleTimeout); + +} + +VolumetricModifier::~VolumetricModifier() +{ + delete m_graph; +} + +void VolumetricModifier::setFpsLabel(QLabel *fpsLabel) +{ + m_fpsLabel = fpsLabel; +} + +void VolumetricModifier::setMediumDetailRB(QRadioButton *button) +{ + m_mediumDetailRB = button; +} + +void VolumetricModifier::setHighDetailRB(QRadioButton *button) +{ + m_highDetailRB = button; +} + +void VolumetricModifier::setSliceLabels(QLabel *xLabel, QLabel *yLabel, QLabel *zLabel) +{ + m_sliceLabelX = xLabel; + m_sliceLabelY = yLabel; + m_sliceLabelZ = zLabel; + + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); +} + +void VolumetricModifier::setAlphaMultiplierLabel(QLabel *label) +{ + m_alphaMultiplierLabel = label; +} + +void VolumetricModifier::sliceX(int enabled) +{ + m_slicingX = enabled; + handleSlicingChanges(); +} + +void VolumetricModifier::sliceY(int enabled) +{ + m_slicingY = enabled; + handleSlicingChanges(); +} + +void VolumetricModifier::sliceZ(int enabled) +{ + m_slicingZ = enabled; + handleSlicingChanges(); +} + +void VolumetricModifier::adjustSliceX(int value) +{ + if (m_volumeItem) { + m_sliceIndexX = value / (1024 / m_volumeItem->textureWidth()); + if (m_sliceIndexX == m_volumeItem->textureWidth()) + m_sliceIndexX--; + if (m_volumeItem->sliceIndexX() != -1) + //! [7] + m_volumeItem->setSliceIndexX(m_sliceIndexX); + //! [7] + //! [9] + m_sliceLabelX->setPixmap( + QPixmap::fromImage(m_volumeItem->renderSlice(Qt::XAxis, m_sliceIndexX))); + //! [9] + } +} + +void VolumetricModifier::adjustSliceY(int value) +{ + if (m_volumeItem) { + m_sliceIndexY = value / (1024 / m_volumeItem->textureHeight()); + if (m_sliceIndexY == m_volumeItem->textureHeight()) + m_sliceIndexY--; + if (m_volumeItem->sliceIndexY() != -1) + m_volumeItem->setSliceIndexY(m_sliceIndexY); + m_sliceLabelY->setPixmap( + QPixmap::fromImage(m_volumeItem->renderSlice(Qt::YAxis, m_sliceIndexY))); + } +} + +void VolumetricModifier::adjustSliceZ(int value) +{ + if (m_volumeItem) { + m_sliceIndexZ = value / (1024 / m_volumeItem->textureDepth()); + if (m_sliceIndexZ == m_volumeItem->textureDepth()) + m_sliceIndexZ--; + if (m_volumeItem->sliceIndexZ() != -1) + m_volumeItem->setSliceIndexZ(m_sliceIndexZ); + m_sliceLabelZ->setPixmap( + QPixmap::fromImage(m_volumeItem->renderSlice(Qt::ZAxis, m_sliceIndexZ))); + } +} + +void VolumetricModifier::handleFpsChange(qreal fps) +{ + const QString fpsFormat = QStringLiteral("FPS: %1"); + int fps10 = int(fps * 10.0); + m_fpsLabel->setText(fpsFormat.arg(qreal(fps10) / 10.0)); +} + +void VolumetricModifier::handleTimeout() +{ + if (!m_mediumDetailRB->isEnabled()) { + if (m_mediumDetailIndex != mediumDetailSize) { + m_mediumDetailIndex = createVolume(mediumDetailSize, m_mediumDetailIndex, 4, + m_mediumDetailData); + } else if (m_mediumDetailShaftIndex != m_mineShaftArray.size()) { + m_mediumDetailShaftIndex = excavateMineShaft(mediumDetailSize, m_mediumDetailShaftIndex, + 1, m_mediumDetailData ); + } else { + m_mediumDetailRB->setEnabled(true); + QString label = QStringLiteral("Medium (%1x%2x%1)"); + m_mediumDetailRB->setText(label.arg(mediumDetailSize).arg(mediumDetailSize / 2)); + } + } else if (!m_highDetailRB->isEnabled()) { + if (m_highDetailIndex != highDetailSize) { + m_highDetailIndex = createVolume(highDetailSize, m_highDetailIndex, 1, + m_highDetailData); + } else if (m_highDetailShaftIndex != m_mineShaftArray.size()) { + m_highDetailShaftIndex = excavateMineShaft(highDetailSize, m_highDetailShaftIndex, 1, + m_highDetailData); + } else { + m_highDetailRB->setEnabled(true); + QString label = QStringLiteral("High (%1x%2x%1)"); + m_highDetailRB->setText(label.arg(highDetailSize).arg(highDetailSize / 2)); + m_timer.stop(); + } + } +} + +void VolumetricModifier::toggleLowDetail(bool enabled) +{ + if (enabled && m_volumeItem) { + m_volumeItem->setTextureData(new QVector<uchar>(*m_lowDetailData)); + m_volumeItem->setTextureDimensions(lowDetailSize, lowDetailSize / 2, lowDetailSize); + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::toggleMediumDetail(bool enabled) +{ + if (enabled && m_volumeItem) { + m_volumeItem->setTextureData(new QVector<uchar>(*m_mediumDetailData)); + m_volumeItem->setTextureDimensions(mediumDetailSize, mediumDetailSize / 2, mediumDetailSize); + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::toggleHighDetail(bool enabled) +{ + if (enabled && m_volumeItem) { + m_volumeItem->setTextureData(new QVector<uchar>(*m_highDetailData)); + m_volumeItem->setTextureDimensions(highDetailSize, highDetailSize / 2, highDetailSize); + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::setFpsMeasurement(bool enabled) +{ + m_graph->setMeasureFps(enabled); + if (enabled) + m_fpsLabel->setText(QStringLiteral("Measuring...")); + else + m_fpsLabel->setText(QString()); +} + +void VolumetricModifier::setSliceSliders(QSlider *sliderX, QSlider *sliderY, QSlider *sliderZ) +{ + m_sliceSliderX = sliderX; + m_sliceSliderY = sliderY; + m_sliceSliderZ = sliderZ; + + // Set sliders to interesting values + m_sliceSliderX->setValue(715); + m_sliceSliderY->setValue(612); + m_sliceSliderZ->setValue(715); +} + +void VolumetricModifier::changeColorTable(int enabled) +{ + if (m_volumeItem) { + if (enabled) + m_volumeItem->setColorTable(m_colorTable2); + else + m_volumeItem->setColorTable(m_colorTable1); + + m_usingPrimaryTable = !enabled; + + // Rerender image labels + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::setPreserveOpacity(bool enabled) +{ + + if (m_volumeItem) { + //! [10] + m_volumeItem->setPreserveOpacity(enabled); + //! [10] + + // Rerender image labels + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::setTransparentGround(bool enabled) +{ + if (m_volumeItem) { + //! [12] + int newAlpha = enabled ? terrainTransparency : 255; + for (int i = aboveWaterGroundColorsMin; i < underWaterGroundColorsMax; i++) { + QRgb oldColor1 = m_colorTable1.at(i); + QRgb oldColor2 = m_colorTable2.at(i); + m_colorTable1[i] = qRgba(qRed(oldColor1), qGreen(oldColor1), qBlue(oldColor1), newAlpha); + m_colorTable2[i] = qRgba(qRed(oldColor2), qGreen(oldColor2), qBlue(oldColor2), newAlpha); + } + if (m_usingPrimaryTable) + m_volumeItem->setColorTable(m_colorTable1); + else + m_volumeItem->setColorTable(m_colorTable2); + //! [12] + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::setUseHighDefShader(bool enabled) +{ + if (m_volumeItem) { + //! [13] + m_volumeItem->setUseHighDefShader(enabled); + //! [13] + } +} + +void VolumetricModifier::adjustAlphaMultiplier(int value) +{ + if (m_volumeItem) { + float mult; + if (value > 100) + mult = float(value - 99) / 2.0f; + else + mult = float(value) / float(500 - value * 4); + //! [11] + m_volumeItem->setAlphaMultiplier(mult); + //! [11] + QString labelFormat = QStringLiteral("Alpha multiplier: %1"); + m_alphaMultiplierLabel->setText(labelFormat.arg( + QString::number(m_volumeItem->alphaMultiplier(), 'f', 3))); + + // Rerender image labels + adjustSliceX(m_sliceSliderX->value()); + adjustSliceY(m_sliceSliderY->value()); + adjustSliceZ(m_sliceSliderZ->value()); + } +} + +void VolumetricModifier::toggleAreaAll(bool enabled) +{ + if (enabled) { + m_graph->axisX()->setRange(0.0f, 1000.0f); + m_graph->axisY()->setRange(-600.0f, 600.0f); + m_graph->axisZ()->setRange(0.0f, 1000.0f); + m_graph->axisX()->setSegmentCount(5); + m_graph->axisY()->setSegmentCount(6); + m_graph->axisZ()->setSegmentCount(5); + } +} + +void VolumetricModifier::toggleAreaMine(bool enabled) +{ + if (enabled) { + m_graph->axisX()->setRange(350.0f, 850.0f); + m_graph->axisY()->setRange(-500.0f, 100.0f); + m_graph->axisZ()->setRange(350.0f, 900.0f); + m_graph->axisX()->setSegmentCount(10); + m_graph->axisY()->setSegmentCount(6); + m_graph->axisZ()->setSegmentCount(11); + } +} + +void VolumetricModifier::toggleAreaMountain(bool enabled) +{ + if (enabled) { + m_graph->axisX()->setRange(300.0f, 600.0f); + m_graph->axisY()->setRange(-100.0f, 400.0f); + m_graph->axisZ()->setRange(300.0f, 600.0f); + m_graph->axisX()->setSegmentCount(9); + m_graph->axisY()->setSegmentCount(5); + m_graph->axisZ()->setSegmentCount(9); + } +} + +void VolumetricModifier::setDrawSliceFrames(int enabled) +{ + if (m_volumeItem) + m_volumeItem->setDrawSliceFrames(enabled); +} + +void VolumetricModifier::initHeightMap(QString fileName, QVector<uchar> &layerData) +{ + QImage heightImage(fileName); + + layerData.resize(layerDataSize * layerDataSize); + const uchar *bits = heightImage.bits(); + int index = 0; + QVector<QRgb> colorTable = heightImage.colorTable(); + for (int i = 0; i < layerDataSize; i++) { + for (int j = 0; j < layerDataSize; j++) { + layerData[index] = qRed(colorTable.at(bits[index])); + index++; + } + } +} + +int VolumetricModifier::createVolume(int textureSize, int startIndex, int count, + QVector<uchar> *textureData) +{ + // Generate volume from layer data. + int index = startIndex * textureSize * textureSize / 2.0f; + int endIndex = startIndex + count; + if (endIndex > textureSize) + endIndex = textureSize; + QVector<uchar> magmaHeights(textureSize); + QVector<uchar> waterHeights(textureSize); + QVector<uchar> groundHeights(textureSize); + float multiplier = float(layerDataSize) / float(textureSize); + for (int i = startIndex; i < endIndex; i++) { + // Generate layer height arrays + for (int l = 0; l < textureSize; l++) { + int layerIndex = (int(i * multiplier) * layerDataSize + int(l * multiplier)); + magmaHeights[l] = int(m_magmaLayer.at(layerIndex)); + waterHeights[l] = int(m_waterLayer.at(layerIndex)); + groundHeights[l] = int(m_groundLayer.at(layerIndex)); + } + for (int j = 0; j < textureSize / 2; j++) { + for (int k = 0; k < textureSize; k++) { + int colorIndex; + int height((layerDataSize - (j * 2 * multiplier)) / 2); + if (height < magmaHeights.at(k)) { + // Magma layer + colorIndex = int((float(height) / heightToColorDiv) + * float(layerColorThickness)) + magmaColorsMin; + } else if (height < groundHeights.at(k) && height < waterHeights.at(k)) { + // Ground layer below water + colorIndex = int((float(waterHeights.at(k) - height) / heightToColorDiv) + * float(layerColorThickness)) + underWaterGroundColorsMin; + } else if (height < waterHeights.at(k)) { + // Water layer where water goes over ground + colorIndex = int((float(height - magmaHeights.at(k)) / heightToColorDiv) + * float(layerColorThickness)) + waterColorsMin; + } else if (height <= groundHeights.at(k)) { + // Ground above water + colorIndex = int((float(height - waterHeights.at(k)) / heightToColorDiv) + * float(layerColorThickness)) + aboveWaterGroundColorsMin; + } else { + // Rest is air + colorIndex = airColorIndex; + } + + (*textureData)[index] = colorIndex; + index++; + } + } + } + return endIndex; +} + +int VolumetricModifier::excavateMineShaft(int textureSize, int startIndex, int count, + QVector<uchar> *textureData) +{ + int endIndex = startIndex + count; + if (endIndex > m_mineShaftArray.size()) + endIndex = m_mineShaftArray.size(); + int shaftSize = mineShaftDiameter * textureSize / lowDetailSize; + for (int i = startIndex; i < endIndex; i++) { + QVector3D shaftStart(m_mineShaftArray.at(i).first); + QVector3D shaftEnd(m_mineShaftArray.at(i).second); + int shaftLen = (shaftEnd - shaftStart).length() * lowDetailSize; + int dataX = shaftStart.x() * textureSize - (shaftSize / 2); + int dataY = (shaftStart.y() * textureSize - (shaftSize / 2)) / 2; + int dataZ = shaftStart.z() * textureSize - (shaftSize / 2); + int dataIndex = dataX + (dataY * textureSize) + dataZ * (textureSize * textureSize / 2); + if (shaftStart.x() != shaftEnd.x()) { + for (int j = 0; j <= shaftLen; j++) { + excavateMineBlock(textureSize, dataIndex, shaftSize, textureData); + dataIndex += shaftSize; + } + } else if (shaftStart.y() != shaftEnd.y()) { + shaftLen /= 2; // Vertical shafts are half as long + for (int j = 0; j <= shaftLen; j++) { + excavateMineBlock(textureSize, dataIndex, shaftSize, textureData); + dataIndex += textureSize * shaftSize; + } + } else { + for (int j = 0; j <= shaftLen; j++) { + excavateMineBlock(textureSize, dataIndex, shaftSize, textureData); + dataIndex += (textureSize * textureSize / 2) * shaftSize; + } + } + + + } + return endIndex; +} + +void VolumetricModifier::excavateMineBlock(int textureSize, int dataIndex, int size, + QVector<uchar> *textureData) +{ + for (int k = 0; k < size; k++) { + int curIndex = dataIndex + (k * textureSize * textureSize / 2); + for (int l = 0; l < size; l++) { + curIndex = dataIndex + (k * textureSize * textureSize / 2) + + (l * textureSize); + for (int m = 0; m < size; m++) { + if (textureData->at(curIndex) != airColorIndex) + (*textureData)[curIndex] = mineShaftColorIndex; + curIndex++; + } + + } + } +} + +void VolumetricModifier::handleSlicingChanges() +{ + if (m_volumeItem) { + if (m_slicingX || m_slicingY || m_slicingZ) { + // Only show slices of selected dimensions + //! [8] + m_volumeItem->setDrawSlices(true); + //! [8] + m_volumeItem->setSliceIndexX(m_slicingX ? m_sliceIndexX : -1); + m_volumeItem->setSliceIndexY(m_slicingY ? m_sliceIndexY : -1); + m_volumeItem->setSliceIndexZ(m_slicingZ ? m_sliceIndexZ : -1); + } else { + // Show slice frames for all dimenstions when not actually slicing + m_volumeItem->setDrawSlices(false); + m_volumeItem->setSliceIndexX(m_sliceIndexX); + m_volumeItem->setSliceIndexY(m_sliceIndexY); + m_volumeItem->setSliceIndexZ(m_sliceIndexZ); + } + } +} + +void VolumetricModifier::initMineShaftArray() +{ + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.1f, 0.7f), + QVector3D(0.7f, 0.8f, 0.7f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.7f, 0.5f), + QVector3D(0.7f, 0.7f, 0.7f)); + + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.4f, 0.7f, 0.7f), + QVector3D(0.7f, 0.7f, 0.7f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.4f, 0.7f, 0.7f), + QVector3D(0.4f, 0.7f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.45f, 0.7f, 0.7f), + QVector3D(0.45f, 0.7f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.5f, 0.7f, 0.7f), + QVector3D(0.5f, 0.7f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.55f, 0.7f, 0.7f), + QVector3D(0.55f, 0.7f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.7f), + QVector3D(0.6f, 0.7f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.65f, 0.7f, 0.7f), + QVector3D(0.65f, 0.7f, 0.8f)); + + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.5f, 0.6f, 0.7f), + QVector3D(0.7f, 0.6f, 0.7f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.5f, 0.6f, 0.7f), + QVector3D(0.5f, 0.6f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.55f, 0.6f, 0.7f), + QVector3D(0.55f, 0.6f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.7f), + QVector3D(0.6f, 0.6f, 0.8f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.65f, 0.6f, 0.7f), + QVector3D(0.65f, 0.6f, 0.8f)); + + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.6f, 0.4f), + QVector3D(0.7f, 0.6f, 0.7f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.45f), + QVector3D(0.8f, 0.6f, 0.45f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.5f), + QVector3D(0.8f, 0.6f, 0.5f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.55f), + QVector3D(0.8f, 0.6f, 0.55f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.6f), + QVector3D(0.8f, 0.6f, 0.6f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.65f), + QVector3D(0.8f, 0.6f, 0.65f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.6f, 0.7f), + QVector3D(0.8f, 0.6f, 0.7f)); + + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.7f, 0.4f), + QVector3D(0.7f, 0.7f, 0.7f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.45f), + QVector3D(0.8f, 0.7f, 0.45f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.5f), + QVector3D(0.8f, 0.7f, 0.5f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.55f), + QVector3D(0.8f, 0.7f, 0.55f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.6f), + QVector3D(0.8f, 0.7f, 0.6f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.65f), + QVector3D(0.8f, 0.7f, 0.65f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.7f, 0.7f), + QVector3D(0.8f, 0.7f, 0.7f)); + + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.8f, 0.5f), + QVector3D(0.7f, 0.8f, 0.7f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.55f), + QVector3D(0.8f, 0.8f, 0.55f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.6f), + QVector3D(0.8f, 0.8f, 0.6f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.65f), + QVector3D(0.8f, 0.8f, 0.65f)); + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.6f, 0.8f, 0.7f), + QVector3D(0.8f, 0.8f, 0.7f)); + + m_mineShaftArray << QPair<QVector3D, QVector3D>(QVector3D(0.7f, 0.1f, 0.4f), + QVector3D(0.7f, 0.7f, 0.4f)); +} diff --git a/examples/datavisualization/volumetric/volumetric.h b/examples/datavisualization/volumetric/volumetric.h new file mode 100644 index 00000000..8d28b524 --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtDataVisualization module. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** +****************************************************************************/ + +#ifndef VOLUMETRICMODIFIER_H +#define VOLUMETRICMODIFIER_H + +#include <QtDataVisualization/q3dscatter.h> +#include <QtDataVisualization/qcustom3dvolume.h> +#include <QtCore/QTimer> +#include <QtGui/QRgb> + +class QLabel; +class QRadioButton; +class QSlider; + +using namespace QtDataVisualization; + +class VolumetricModifier : public QObject +{ + Q_OBJECT +public: + explicit VolumetricModifier(Q3DScatter *scatter); + ~VolumetricModifier(); + + void setFpsLabel(QLabel *fpsLabel); + void setMediumDetailRB(QRadioButton *button); + void setHighDetailRB(QRadioButton *button); + void setSliceLabels(QLabel *xLabel, QLabel *yLabel, QLabel *zLabel); + void setAlphaMultiplierLabel(QLabel *label); + +public slots: + void sliceX(int enabled); + void sliceY(int enabled); + void sliceZ(int enabled); + void adjustSliceX(int value); + void adjustSliceY(int value); + void adjustSliceZ(int value); + void handleFpsChange(qreal fps); + void handleTimeout(); + void toggleLowDetail(bool enabled); + void toggleMediumDetail(bool enabled); + void toggleHighDetail(bool enabled); + void setFpsMeasurement(bool enabled); + void setSliceSliders(QSlider *sliderX, QSlider *sliderY, QSlider *sliderZ); + void changeColorTable(int enabled); + void setPreserveOpacity(bool enabled); + void setTransparentGround(bool enabled); + void setUseHighDefShader(bool enabled); + void adjustAlphaMultiplier(int value); + void toggleAreaAll(bool enabled); + void toggleAreaMine(bool enabled); + void toggleAreaMountain(bool enabled); + void setDrawSliceFrames(int enabled); + +private: + + void initHeightMap(QString fileName, QVector<uchar> &layerData); + void initMineShaftArray(); + int createVolume(int textureSize, int startIndex, int count, + QVector<uchar> *textureData); + int excavateMineShaft(int textureSize, int startIndex, int count, + QVector<uchar> *textureData); + void excavateMineBlock(int textureSize, int dataIndex, int size, QVector<uchar> *textureData); + void handleSlicingChanges(); + + Q3DScatter *m_graph; + QCustom3DVolume *m_volumeItem; + int m_sliceIndexX; + int m_sliceIndexY; + int m_sliceIndexZ; + bool m_slicingX; + bool m_slicingY; + bool m_slicingZ; + QLabel *m_fpsLabel; + QRadioButton *m_mediumDetailRB; + QRadioButton *m_highDetailRB; + QVector<uchar> *m_lowDetailData; + QVector<uchar> *m_mediumDetailData; + QVector<uchar> *m_highDetailData; + QTimer m_timer; + int m_mediumDetailIndex; + int m_highDetailIndex; + int m_mediumDetailShaftIndex; + int m_highDetailShaftIndex; + QSlider *m_sliceSliderX; + QSlider *m_sliceSliderY; + QSlider *m_sliceSliderZ; + QVector<QRgb> m_colorTable1; + QVector<QRgb> m_colorTable2; + bool m_usingPrimaryTable; + QLabel *m_sliceLabelX; + QLabel *m_sliceLabelY; + QLabel *m_sliceLabelZ; + QLabel *m_alphaMultiplierLabel; + QVector<uchar> m_magmaLayer; + QVector<uchar> m_waterLayer; + QVector<uchar> m_groundLayer; + QVector<QPair<QVector3D, QVector3D> > m_mineShaftArray; +}; + +#endif diff --git a/examples/datavisualization/volumetric/volumetric.pro b/examples/datavisualization/volumetric/volumetric.pro new file mode 100644 index 00000000..fa355692 --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.pro @@ -0,0 +1,17 @@ +android|ios { + error( "This example is not supported for android or ios." ) +} + +!include( ../examples.pri ) { + error( "Couldn't find the examples.pri file!" ) +} + +SOURCES += main.cpp volumetric.cpp +HEADERS += volumetric.h + +QT += widgets + +OTHER_FILES += doc/src/* \ + doc/images/* + +RESOURCES += volumetric.qrc diff --git a/examples/datavisualization/volumetric/volumetric.qrc b/examples/datavisualization/volumetric/volumetric.qrc new file mode 100644 index 00000000..920fd1d2 --- /dev/null +++ b/examples/datavisualization/volumetric/volumetric.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/heightmaps"> + <file>layer_ground.png</file> + <file>layer_magma.png</file> + <file>layer_water.png</file> + </qresource> +</RCC> |