diff options
Diffstat (limited to 'tests/manual/galaxy/galaxydata.cpp')
-rw-r--r-- | tests/manual/galaxy/galaxydata.cpp | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/tests/manual/galaxy/galaxydata.cpp b/tests/manual/galaxy/galaxydata.cpp new file mode 100644 index 00000000..33a4d16b --- /dev/null +++ b/tests/manual/galaxy/galaxydata.cpp @@ -0,0 +1,481 @@ +/****************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Data Visualization module. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ + +/* + * Galaxy creation code obtained from http://beltoforion.de/galaxy/galaxy_en.html + * Thanks to Ingo Berg, great work. + * Licensed under a Creative Commons Attribution 3.0 License + * http://creativecommons.org/licenses/by/3.0/ + */ + +#include "galaxydata.h" +#include "cumulativedistributor.h" +#include "star.h" +#include <QtDataVisualization/qscatterdataproxy.h> +#include <QtDataVisualization/qvalue3daxis.h> +#include <QtDataVisualization/q3dscene.h> +#include <QtDataVisualization/q3dcamera.h> +#include <QtDataVisualization/qscatter3dseries.h> +#include <QtDataVisualization/q3dtheme.h> +#include <QtCore/qmath.h> +#include <QPainter> + +#include <QDebug> + +using namespace QtDataVisualization; + +static const int numOfStars = 70000; +static const int numOfDust = numOfStars / 2; +static const int numOfH2 = 200; +static const qreal rand_max = qreal(RAND_MAX); + +GalaxyData::GalaxyData(Q3DScatter *scatter, + qreal rad, + qreal radCore, + qreal deltaAng, + qreal ex1, + qreal ex2) + : m_graph(scatter), + m_pStars(0), + m_pDust(0), + m_pH2(0), + m_radGalaxy(rad), + m_radCore(radCore), + m_angleOffset(deltaAng), + m_elEx1(ex1), + m_elEx2(ex2), + m_radFarField(m_radGalaxy * 2), + m_filtered(false), + m_minx(9999.9), + m_maxx(-9999.0), + m_miny(9999.9), + m_maxy(-9999.0) +{ + m_graph->activeTheme()->setType(Q3DTheme::ThemeEbony); + m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualitySoftLow); + + m_graph->axisX()->setRange(-25000.0f, 25000.0f); + m_graph->axisZ()->setRange(-25000.0f, 25000.0f); + m_graph->setOptimizationHints(QAbstract3DGraph::OptimizationStatic); + m_graph->activeTheme()->setBackgroundColor(QColor(31, 31, 31)); + m_graph->activeTheme()->setWindowColor(QColor(31, 31, 31)); + m_graph->activeTheme()->setLabelBackgroundColor(QColor(31, 31, 31)); + m_graph->activeTheme()->setLabelTextColor(QColor(31, 31, 31)); + + QObject::connect(m_graph, &QAbstract3DGraph::currentFpsChanged, + this, &GalaxyData::handleFpsChange); + m_graph->setMeasureFps(true); + + createSeries(); + createGalaxy(); +} + +GalaxyData::~GalaxyData() +{ + delete m_graph; + if (m_pStars) + delete [] m_pStars; + if (m_pDust) + delete [] m_pDust; + if (m_pH2) + delete [] m_pH2; +} + +void GalaxyData::createGalaxy() +{ + if (m_pStars) + delete [] m_pStars; + m_pStars = new Star[numOfStars]; + + if (m_pDust) + delete [] m_pDust; + m_pDust = new Star[numOfDust]; + + if (m_pH2) + delete [] m_pH2; + m_pH2 = new Star[numOfH2 * 2]; + + + m_minx = 9999.9; + m_maxx = -9999.0; + m_miny = 9999.9; + m_maxy = -9999.0; + + // First star is the black hole at the center + m_pStars[0].m_a = 0; + m_pStars[0].m_b = 0; + m_pStars[0].m_angle = 0; + m_pStars[0].m_theta = 0; + m_pStars[0].m_center = QVector2D(0.0f, 0.0f); + m_pStars[0].calcXY(); + + // second star is at the edge of the core area + m_pStars[1].m_a = m_radCore; + m_pStars[1].m_b = m_radCore * getExcentricity(m_radCore); + m_pStars[1].m_angle = getAngularOffset(m_radCore); + m_pStars[1].m_theta = 0; + m_pStars[1].m_center = QVector2D(0.0f, 0.0f); + m_pStars[1].calcXY(); + checkMinMax(m_pStars[1]); + + // third star is at the edge of the disk + m_pStars[2].m_a = m_radGalaxy; + m_pStars[2].m_b = m_radGalaxy * getExcentricity(m_radGalaxy); + m_pStars[2].m_angle = getAngularOffset(m_radGalaxy); + m_pStars[2].m_theta = 0; + m_pStars[2].m_center = QVector2D(0.0f, 0.0f); + m_pStars[2].calcXY(); + checkMinMax(m_pStars[2]); + + CumulativeDistributor cd; + cd.setupRealistic(1.0, // Maximalintensität + 0.02, // k (bulge) + m_radGalaxy/3.0, // disc skalenlänge + m_radCore, // bulge radius + 0, // start der intensitätskurve + m_radFarField, // ende der intensitätskurve + 1000.0); // Anzahl der stützstellen + + for (int i = 3; i < numOfStars; ++i) { + qreal rad = cd.valFromProp(qreal(qrand()) / rand_max); + + m_pStars[i].m_a = rad; + m_pStars[i].m_b = rad * getExcentricity(rad); + m_pStars[i].m_angle = getAngularOffset(rad); + m_pStars[i].m_theta = 360.0 * ((double)rand() / RAND_MAX); + m_pStars[i].m_center = QVector2D(0.0f, 0.0f); + m_pStars[i].calcXY(); + + checkMinMax(m_pStars[i]); + } + + // Initialize Dust + qreal x, y, rad; + for (int i = 0; i < numOfDust; ++i) + { + x = 2.0 * m_radGalaxy * ((double)rand() / RAND_MAX) - m_radGalaxy; + y = 2.0 * m_radGalaxy * ((double)rand() / RAND_MAX) - m_radGalaxy; + rad = sqrt(x*x + y*y); + + m_pDust[i].m_a = rad; + m_pDust[i].m_b = rad * getExcentricity(rad); + m_pDust[i].m_angle = getAngularOffset(rad); + m_pDust[i].m_theta = 360.0 * ((double)rand() / RAND_MAX); + m_pDust[i].m_center = QVector2D(0.0f, 0.0f); + m_pDust[i].calcXY(); + + checkMinMax(m_pDust[i]); + } + + // Initialize H2 + for (int i = 0; i < numOfH2; ++i) + { + x = 2*(m_radGalaxy) * ((double)rand() / RAND_MAX) - (m_radGalaxy); + y = 2*(m_radGalaxy) * ((double)rand() / RAND_MAX) - (m_radGalaxy); + rad = sqrt(x*x + y*y); + + int k1 = 2*i; + m_pH2[k1].m_a = rad; + m_pH2[k1].m_b = rad * getExcentricity(rad); + m_pH2[k1].m_angle = getAngularOffset(rad); + m_pH2[k1].m_theta = 360.0 * ((double)rand() / RAND_MAX); + m_pH2[k1].m_center = QVector2D(0.0f, 0.0f); + m_pH2[k1].calcXY(); + + int k2 = 2*i + 1; + m_pH2[k2].m_a = rad + 1000.0; + m_pH2[k2].m_b = rad * getExcentricity(rad); + m_pH2[k2].m_angle = m_pH2[k1].m_angle; + m_pH2[k2].m_theta = m_pH2[k1].m_theta; + m_pH2[k2].m_center = m_pH2[k1].m_center; + m_pH2[k2].calcXY(); + } + + qreal max = qMax(m_maxx, m_maxy); + qreal min = -qMin(m_minx, m_miny); + max = qMax(min, max); + m_range = int((max + 500.0) / 1000.0) * 1000; + m_graph->axisX()->setRange(-float(m_range), float(m_range)); + m_graph->axisZ()->setRange(-float(m_range), float(m_range)); + + if (!m_filtered) + createNormalDataView(); + else + createFilteredView(); +} + +void GalaxyData::createSeries() +{ + QScatterDataProxy *proxyNormal = new QScatterDataProxy; + m_normalSeries = new QScatter3DSeries(proxyNormal); + m_normalSeries->setMesh(QAbstract3DSeries::MeshPoint); + m_graph->addSeries(m_normalSeries); + + QScatterDataProxy *proxyDust = new QScatterDataProxy; + m_dustSeries = new QScatter3DSeries(proxyDust); + m_dustSeries->setMesh(QAbstract3DSeries::MeshPoint); + m_graph->addSeries(m_dustSeries); + + QScatterDataProxy *proxyH2 = new QScatterDataProxy; + m_H2Series = new QScatter3DSeries(proxyH2); + m_H2Series->setMesh(QAbstract3DSeries::MeshPoint); + m_graph->addSeries(m_H2Series); + + QScatterDataProxy *proxyFiltered = new QScatterDataProxy; + m_filteredSeries = new QScatter3DSeries(proxyFiltered); + m_filteredSeries->setMesh(QAbstract3DSeries::MeshCube); + m_graph->addSeries(m_filteredSeries); + +} + +void GalaxyData::createNormalDataView() +{ + QScatterDataArray *dataArray = new QScatterDataArray; + dataArray->resize(numOfStars); + QScatterDataItem *ptrToDataArray = &dataArray->first(); + + for (uint i = 0; i < numOfStars; i++) { + ptrToDataArray->setPosition(QVector3D(m_pStars[i].m_pos.x(), + 0.0f, + m_pStars[i].m_pos.y())); + ptrToDataArray++; + } + + m_normalSeries->dataProxy()->resetArray(dataArray); + m_normalSeries->setMesh(QAbstract3DSeries::MeshPoint); + m_normalSeries->setBaseColor(Qt::white); + + dataArray = new QScatterDataArray; + dataArray->resize(numOfDust); + ptrToDataArray = &dataArray->first(); + + for (uint i = 0; i < numOfDust; i++) { + ptrToDataArray->setPosition(QVector3D(m_pDust[i].m_pos.x(), + 0.0f, + m_pDust[i].m_pos.y())); + ptrToDataArray++; + } + + m_dustSeries->dataProxy()->resetArray(dataArray); + m_dustSeries->setMesh(QAbstract3DSeries::MeshPoint); + m_dustSeries->setBaseColor(QColor(131, 111, 255)); + + dataArray = new QScatterDataArray; + dataArray->resize(numOfDust); + ptrToDataArray = &dataArray->first(); + + uint H2Count = numOfH2 * 2; + for (uint i = 0; i < H2Count; i++) { + ptrToDataArray->setPosition(QVector3D(m_pH2[i].m_pos.x(), + 0.0f, + m_pH2[i].m_pos.y())); + ptrToDataArray++; + } + + m_H2Series->dataProxy()->resetArray(dataArray); + m_H2Series->setMesh(QAbstract3DSeries::MeshPoint); + m_H2Series->setBaseColor(Qt::red); +} + +void GalaxyData::createFilteredView() +{ + int steps = (m_range / 1000) * 2; + int tableSize = steps * steps; + int *table = new int[tableSize]; + for (int i = 0; i < tableSize; i++) + table[i] = 0; + qreal add = qreal(m_range); + int max = 0; + + for (uint i = 0; i < numOfStars; i++) { + int x = int(m_pStars[i].m_pos.x() + add) / 1000; + int y = int(m_pStars[i].m_pos.y() + add) / 1000; + table[y * steps + x] = table[y * steps + x] + 1; + + if (max < table[y * steps + x]) + max = table[y * steps + x]; + } + + // Count how many cells have data + int nActiveCell = 0; + for (int i = 0; i < tableSize; i++) { + if (table[i]) + nActiveCell++; + } + + + QScatterDataArray *dataArray = new QScatterDataArray; + dataArray->resize(nActiveCell); + QScatterDataItem *ptrToDataArray = &dataArray->first(); + + for (int y = 0; y < steps; y++) { + for (int x = 0; x < steps; x++) { + if (table[y * steps + x]) { + ptrToDataArray->setPosition(QVector3D(float(x) * 1000.0f - add + 500.0f, + float(table[y * steps + x]), + float(y) * 1000.0f - add + 500.0f)); + ptrToDataArray++; + } + } + } + + m_filteredSeries->dataProxy()->resetArray(dataArray); + m_filteredSeries->setMesh(QAbstract3DSeries::MeshCube); + m_filteredSeries->setItemSize(0.1f); + + m_graph->axisY()->setRange(0.0f, float(max + 1)); + + qDebug() << "max = " << max; +} + +void GalaxyData::checkMinMax(const Star &star) +{ + if (star.m_pos.x() < m_minx) + m_minx = star.m_pos.x(); + if (star.m_pos.x() > m_maxx) + m_maxx = star.m_pos.x(); + if (star.m_pos.y() < m_miny) + m_miny = star.m_pos.y(); + if (star.m_pos.y() > m_maxy) + m_maxy = star.m_pos.y(); +} + +qreal GalaxyData::getExcentricity(qreal r) const +{ + if (r < m_radCore) + { + // Core region of the galaxy. Innermost part is round + // excentricity increasing linear to the border of the core. + return 1 + (r / m_radCore) * (m_elEx1-1); + } else if (r > m_radCore && r <= m_radGalaxy) { + return m_elEx1 + (r - m_radCore) / (m_radGalaxy - m_radCore) * (m_elEx2 - m_elEx1); + } else if (r > m_radGalaxy && r < m_radFarField) { + // excentricity is slowly reduced to 1. + return m_elEx2 + (r - m_radGalaxy) / (m_radFarField - m_radGalaxy) * (1 - m_elEx2); + } else { + return 1.0; + } +} + +qreal GalaxyData::getAngularOffset(qreal rad) const +{ + return rad * m_angleOffset; +} + +void GalaxyData::radiusGalaxyChanged(int value) +{ + m_radGalaxy = qreal(value); + createGalaxy(); +} + +void GalaxyData::radiusCoreChanged(int value) +{ + m_radCore = qreal(value); + createGalaxy(); +} + +void GalaxyData::angleOffsetChanged(int value) +{ + m_angleOffset = qreal(value) / 100000.0; + createGalaxy(); +} + +void GalaxyData::eccentricityInnerChanged(int value) +{ + m_elEx1 = qreal(value) / 100.0; + createGalaxy(); +} + +void GalaxyData::eccentricityOuterChanged(int value) +{ + m_elEx2 = qreal(value) / 100.0; + createGalaxy(); +} + +void GalaxyData::setFilteredEnabled(bool enabled) +{ + m_filtered = enabled; + if (enabled) { + QLinearGradient gr(0, 0, 1, 100); + gr.setColorAt(0.0, Qt::white); + gr.setColorAt(0.04, Qt::green); + gr.setColorAt(0.1, Qt::darkGreen); + gr.setColorAt(1.0, Qt::red); + + m_filteredSeries->setBaseGradient(gr); + m_filteredSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient); + + m_normalSeries->setVisible(false); + + createFilteredView(); + + m_filteredSeries->setVisible(true); + } else { + m_normalSeries->setColorStyle(Q3DTheme::ColorStyleUniform); + m_graph->axisY()->setRange(-1.0f, 1.0f); + m_normalSeries->setItemSize(0.0f); + + m_filteredSeries->setVisible(false); + + createNormalDataView(); + + m_normalSeries->setVisible(true); + } +} + + +void GalaxyData::setStaticEnabled(bool enabled) +{ + if (enabled) + m_graph->setOptimizationHints(QAbstract3DGraph::OptimizationStatic); + else + m_graph->setOptimizationHints(QAbstract3DGraph::OptimizationDefault); +} + +void GalaxyData::setStarsVisible(bool enabled) +{ + m_normalSeries->setVisible(enabled); +} + +void GalaxyData::setDustVisible(bool enabled) +{ + m_dustSeries->setVisible(enabled); +} + +void GalaxyData::setH2Visible(bool enabled) +{ + m_H2Series->setVisible(enabled); +} + +void GalaxyData::resetValues() +{ + m_radiusGalaxySlider->setValue(15000); + m_radiusCoreSlider->setValue(4000); + m_angleOffsetSlider->setValue(40); + m_eccentricityInnerSlider->setValue(90); + m_eccentricityOuterSlider->setValue(90); +} + +void GalaxyData::handleFpsChange(qreal fps) +{ + static const QString fpsPrefix(QStringLiteral("FPS: ")); + m_fpsLabel->setText(fpsPrefix + QString::number(qRound(fps))); +} |