File indexing completed on 2024-04-28 03:50:25

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2008 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2011-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
0005 //
0006 
0007 #include "StarsPlugin.h"
0008 
0009 #include "ui_StarsConfigWidget.h"
0010 #include <QRectF>
0011 #include <QSize>
0012 #include <QDateTime>
0013 #include <QRegion>
0014 #include <QContextMenuEvent>
0015 #include <QMenu>
0016 #include <QColorDialog>
0017 #include <QPainterPath>
0018 #include <qmath.h>
0019 
0020 #include "MarbleClock.h"
0021 #include "MarbleColors.h"
0022 #include "MarbleDebug.h"
0023 #include "MarbleDirs.h"
0024 #include "MarbleModel.h"
0025 #include "MarbleWidget.h"
0026 #include "AbstractFloatItem.h"
0027 #include "GeoPainter.h"
0028 #include "Planet.h"
0029 #include "PlanetFactory.h"
0030 #include "SunLocator.h"
0031 #include "ViewportParams.h"
0032 
0033 #include "src/lib/astro/solarsystem.h"
0034 
0035 namespace Marble
0036 {
0037 
0038 StarsPlugin::StarsPlugin( const MarbleModel *marbleModel )
0039     : RenderPlugin( marbleModel ),
0040       m_nameIndex( 0 ),
0041       m_configDialog( nullptr ),
0042       ui_configWidget( nullptr ),
0043       m_renderStars( true ),
0044       m_renderConstellationLines( true ),
0045       m_renderConstellationLabels( true ),
0046       m_renderDsos( true ),
0047       m_renderDsoLabels( true ),
0048       m_renderSun( true ),
0049       m_renderMoon( true ),
0050       m_renderEcliptic( true ),
0051       m_renderCelestialEquator( true ),
0052       m_renderCelestialPole( true ),
0053       m_starsLoaded( false ),
0054       m_starPixmapsCreated( false ),
0055       m_constellationsLoaded( false ),
0056       m_dsosLoaded( false ),
0057       m_zoomSunMoon( true ),
0058       m_viewSolarSystemLabel( true ),
0059       m_magnitudeLimit( 100 ),
0060       m_zoomCoefficient( 4 ),
0061       m_constellationBrush( Marble::Oxygen::aluminumGray5 ),
0062       m_constellationLabelBrush( Marble::Oxygen::aluminumGray5 ),
0063       m_dsoLabelBrush( Marble::Oxygen::aluminumGray5 ),
0064       m_eclipticBrush( Marble::Oxygen::aluminumGray5 ),
0065       m_celestialEquatorBrush( Marble::Oxygen::aluminumGray5 ),
0066       m_celestialPoleBrush( Marble::Oxygen::aluminumGray5 ),
0067       m_contextMenu(nullptr),
0068       m_constellationsAction(nullptr),
0069       m_sunMoonAction(nullptr),
0070       m_planetsAction(nullptr),
0071       m_dsoAction(nullptr),
0072       m_doRender( false )
0073 {
0074     bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
0075     if (smallScreen) m_magnitudeLimit = 5;
0076 
0077     prepareNames();
0078 }
0079 
0080 StarsPlugin::~StarsPlugin()
0081 {
0082     delete m_contextMenu;
0083 }
0084 
0085 QStringList StarsPlugin::backendTypes() const
0086 {
0087     return QStringList(QStringLiteral("stars"));
0088 }
0089 
0090 QString StarsPlugin::renderPolicy() const
0091 {
0092     return QStringLiteral("SPECIFIED_ALWAYS");
0093 }
0094 
0095 QStringList StarsPlugin::renderPosition() const
0096 {
0097     return QStringList(QStringLiteral("STARS"));
0098 }
0099 
0100 RenderPlugin::RenderType StarsPlugin::renderType() const
0101 {
0102     return RenderPlugin::ThemeRenderType;
0103 }
0104 
0105 QString StarsPlugin::name() const
0106 {
0107     return tr( "Stars" );
0108 }
0109 
0110 QString StarsPlugin::guiString() const
0111 {
0112     return tr( "&Stars" );
0113 }
0114 
0115 QString StarsPlugin::nameId() const
0116 {
0117     return QStringLiteral("stars");
0118 }
0119 
0120 QString StarsPlugin::version() const
0121 {
0122     return QStringLiteral("1.2");
0123 }
0124 
0125 QString StarsPlugin::description() const
0126 {
0127     return tr( "A plugin that shows the Starry Sky and the Sun." );
0128 }
0129 
0130 QString StarsPlugin::copyrightYears() const
0131 {
0132     return QStringLiteral("2008-2012");
0133 }
0134 
0135 QVector<PluginAuthor> StarsPlugin::pluginAuthors() const
0136 {
0137     return QVector<PluginAuthor>()
0138            << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org"))
0139            << PluginAuthor(QStringLiteral("Rene Kuettner"), QStringLiteral("rene@bitkanal.net"))
0140            << PluginAuthor(QStringLiteral("Timothy Lanzi"), QStringLiteral("trlanzi@gmail.com"));
0141 }
0142 
0143 QIcon StarsPlugin::icon() const
0144 {
0145     return QIcon(QStringLiteral(":/icons/stars.png"));
0146 }
0147 
0148 void StarsPlugin::initialize()
0149 {
0150 }
0151 
0152 bool StarsPlugin::isInitialized() const
0153 {
0154     return true;
0155 }
0156 
0157 QDialog *StarsPlugin::configDialog()
0158 {
0159     if (!m_configDialog) {
0160         // Initializing configuration dialog
0161         m_configDialog = new QDialog;
0162         ui_configWidget = new Ui::StarsConfigWidget;
0163         ui_configWidget->setupUi( m_configDialog );
0164 
0165         readSettings();
0166 
0167         connect( ui_configWidget->m_buttonBox, SIGNAL(accepted()), SLOT(writeSettings()) );
0168         connect( ui_configWidget->m_buttonBox, SIGNAL(rejected()), SLOT(readSettings()) );
0169 
0170         connect( ui_configWidget->m_constellationColorButton, SIGNAL(clicked()), this,
0171                 SLOT(constellationGetColor()) );
0172 
0173         connect( ui_configWidget->m_constellationLabelColorButton, SIGNAL(clicked()), this,
0174                 SLOT(constellationLabelGetColor()) );
0175 
0176         connect( ui_configWidget->m_dsoLabelColorButton, SIGNAL(clicked()), this,
0177                 SLOT(dsoLabelGetColor()) );
0178 
0179         connect( ui_configWidget->m_eclipticColorButton, SIGNAL(clicked()), this,
0180                 SLOT(eclipticGetColor()) );
0181 
0182         connect( ui_configWidget->m_celestialEquatorColorButton, SIGNAL(clicked()), this,
0183                 SLOT(celestialEquatorGetColor()) );
0184 
0185         connect( ui_configWidget->m_celestialPoleColorButton, SIGNAL(clicked()), this,
0186                 SLOT(celestialPoleGetColor()) );
0187     }
0188 
0189     return m_configDialog;
0190 }
0191 
0192 QHash<QString, QVariant> StarsPlugin::settings() const
0193 {
0194     QHash<QString, QVariant> settings = RenderPlugin::settings();
0195 
0196     settings.insert(QStringLiteral("nameIndex"), m_nameIndex);
0197     settings.insert(QStringLiteral("renderStars"), m_renderStars);
0198     settings.insert(QStringLiteral("renderConstellationLines"), m_renderConstellationLines);
0199     settings.insert(QStringLiteral("renderConstellationLabels"), m_renderConstellationLabels);
0200     settings.insert(QStringLiteral("renderDsos"), m_renderDsos);
0201     settings.insert(QStringLiteral("renderDsoLabels"), m_renderDsoLabels);
0202     settings.insert(QStringLiteral("renderSun"), m_renderSun);
0203     settings.insert(QStringLiteral("renderMoon"), m_renderMoon);
0204 
0205     QStringList planetState;
0206     for (const QString &key: m_renderPlanet.keys())
0207         planetState += key + QLatin1Char(':') + QString::number((int)m_renderPlanet[key]);
0208     settings.insert(QStringLiteral("renderPlanet"), planetState.join(QLatin1Char('|')));
0209 
0210     settings.insert(QStringLiteral("renderEcliptic"), m_renderEcliptic);
0211     settings.insert(QStringLiteral("renderCelestialEquator"), m_renderCelestialEquator);
0212     settings.insert(QStringLiteral("renderCelestialPole"), m_renderCelestialPole);
0213     settings.insert(QStringLiteral("zoomSunMoon"), m_zoomSunMoon);
0214     settings.insert(QStringLiteral("viewSolarSystemLabel"), m_viewSolarSystemLabel);
0215     settings.insert(QStringLiteral("magnitudeLimit"), m_magnitudeLimit);
0216     settings.insert(QStringLiteral("constellationBrush"), m_constellationBrush.color().rgb());
0217     settings.insert(QStringLiteral("constellationLabelBrush"), m_constellationLabelBrush.color().rgb());
0218     settings.insert(QStringLiteral("dsoLabelBrush"), m_dsoLabelBrush.color().rgb());
0219     settings.insert(QStringLiteral("eclipticBrush"), m_eclipticBrush.color().rgb());
0220     settings.insert(QStringLiteral("celestialEaquatorBrush"), m_celestialEquatorBrush.color().rgb());
0221     settings.insert(QStringLiteral("celestialPoleBrush"), m_celestialPoleBrush.color().rgb());
0222 
0223     return settings;
0224 }
0225 
0226 void StarsPlugin::setSettings( const QHash<QString, QVariant> &settings )
0227 {
0228     RenderPlugin::setSettings( settings );
0229 
0230     m_nameIndex = readSetting<int>(settings, QStringLiteral("nameIndex"), 0);
0231     m_renderStars = readSetting<bool>(settings, QStringLiteral("renderStars"), true);
0232     m_renderConstellationLines = readSetting<bool>(settings, QStringLiteral("renderConstellationLines"), true);
0233     m_renderConstellationLabels = readSetting<bool>(settings, QStringLiteral("renderConstellationLabels"), true);
0234     m_renderDsos = readSetting<bool>(settings, QStringLiteral("renderDsos"), true);
0235     m_renderDsoLabels = readSetting<bool>(settings, QStringLiteral("renderDsoLabels"), true);
0236     m_renderSun = readSetting<bool>(settings, QStringLiteral("renderSun"), true);
0237     m_renderMoon = readSetting<bool>(settings, QStringLiteral("renderMoon"), true);
0238 
0239     m_renderPlanet.clear();
0240     const QString renderPlanet = readSetting<QString>(settings, QStringLiteral("renderPlanet"), QString());
0241     const QStringList renderStates = renderPlanet.split(QLatin1Char('|'));
0242     for(const QString &state: renderStates) {
0243         const QStringList stateList = state.split(QLatin1Char(':'));
0244         if (stateList.size() == 2)
0245             m_renderPlanet[stateList[0]] = (bool)stateList[1].toInt();
0246     }
0247 
0248     m_renderEcliptic = readSetting<bool>(settings, QStringLiteral("renderEcliptic"), true);
0249     m_renderCelestialEquator = readSetting<bool>(settings, QStringLiteral("renderCelestialEquator"), true);
0250     m_renderCelestialPole = readSetting<bool>(settings, QStringLiteral("renderCelestialPole"), true);
0251     m_zoomSunMoon = readSetting<bool>(settings, QStringLiteral("zoomSunMoon"), true);
0252     m_viewSolarSystemLabel = readSetting<bool>(settings, QStringLiteral("viewSolarSystemLabel"), true);
0253     m_magnitudeLimit = readSetting<int>(settings, QStringLiteral("magnitudeLimit"), 100);
0254     QColor const defaultColor = Marble::Oxygen::aluminumGray5;
0255     m_constellationBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("constellationBrush"), defaultColor.rgb()));
0256     m_constellationLabelBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("constellationLabelBrush"), defaultColor.rgb()));
0257     m_dsoLabelBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("dsoLabelBrush"), defaultColor.rgb()));
0258     m_eclipticBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("eclipticBrush"), defaultColor.rgb()));
0259     m_celestialEquatorBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("celestialEquatorBrush"), defaultColor.rgb()));
0260     m_celestialPoleBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("celestialPoleBrush"), defaultColor.rgb()));
0261 }
0262 
0263 QPixmap StarsPlugin::starPixmap(qreal mag, int colorId) const
0264 {
0265    if ( mag < -1 ) {
0266        return m_pixN1Stars.at(colorId);
0267    } else if ( mag < 0 ) {
0268        return m_pixP0Stars.at(colorId);
0269    } else if ( mag < 1 ) {
0270        return m_pixP1Stars.at(colorId);
0271    } else if ( mag < 2 ) {
0272        return m_pixP2Stars.at(colorId);
0273    } else if ( mag < 3 ) {
0274        return m_pixP3Stars.at(colorId);
0275    } else if ( mag < 4 ) {
0276        return m_pixP4Stars.at(colorId);
0277    } else if ( mag < 5 ) {
0278        return m_pixP5Stars.at(colorId);
0279    } else if ( mag < 6 ) {
0280        return m_pixP6Stars.at(colorId);
0281    } else {
0282        return m_pixP7Stars.at(colorId);
0283    }
0284 
0285    return QPixmap();
0286 }
0287 
0288 void StarsPlugin::prepareNames()
0289 {
0290 
0291     QFile names(MarbleDirs::path(QStringLiteral("stars/names.csv")));
0292     if ( !names.open( QIODevice::ReadOnly ) ) {
0293         return;
0294     }
0295 
0296     QTextStream in( &names );
0297     while ( !in.atEnd() ) {
0298         QString line = in.readLine();
0299         const QStringList list = line.split(QLatin1Char(';'));
0300         if ( list.size() == 3 ) {
0301             m_nativeHash[ list.at( 0 ) ] = QCoreApplication::translate( "StarNames", list.at( 1 ).toUtf8().constData() );
0302             m_abbrHash[ list.at( 0 ) ] = list.at( 2 );
0303         }
0304     }
0305     names.close();
0306 
0307 }
0308 
0309 QString StarsPlugin::assembledConstellation(const QString &name)
0310 {
0311     switch (m_nameIndex) {
0312     case 0:
0313         return name;
0314     case 1:
0315         return m_nativeHash[name];
0316     case 2:
0317         return m_abbrHash[name];
0318     default:
0319         return name;
0320     }
0321 }
0322 
0323 void StarsPlugin::readSettings()
0324 {
0325     if ( !m_configDialog ) {
0326         return;
0327     }
0328 
0329     ui_configWidget->constellationNamesComboBox->setCurrentIndex(m_nameIndex);
0330 
0331     Qt::CheckState const constellationLineState = m_renderConstellationLines ? Qt::Checked : Qt::Unchecked;
0332     ui_configWidget->m_viewConstellationLinesCheckbox->setCheckState( constellationLineState );
0333 
0334     Qt::CheckState const constellationLabelState = m_renderConstellationLabels ? Qt::Checked : Qt::Unchecked;
0335     ui_configWidget->m_viewConstellationLabelsCheckbox->setCheckState( constellationLabelState );
0336 
0337     Qt::CheckState const dsoState = m_renderDsos ? Qt::Checked : Qt::Unchecked;
0338     ui_configWidget->m_viewDsosCheckbox->setCheckState( dsoState );
0339 
0340     Qt::CheckState const dsoLabelState = m_renderDsoLabels ? Qt::Checked : Qt::Unchecked;
0341     ui_configWidget->m_viewDsoLabelCheckbox->setCheckState( dsoLabelState );
0342 
0343     Qt::CheckState const sunState = m_renderSun ? Qt::Checked : Qt::Unchecked;
0344     ui_configWidget->m_solarSystemListWidget->item( 0 )->setCheckState( sunState );
0345 
0346     Qt::CheckState const moonState = m_renderMoon ? Qt::Checked : Qt::Unchecked;
0347     ui_configWidget->m_solarSystemListWidget->item( 1 )->setCheckState( moonState );
0348 
0349     Qt::CheckState const mercuryState = m_renderPlanet["mercury"] ? Qt::Checked : Qt::Unchecked;
0350     ui_configWidget->m_solarSystemListWidget->item( 2 )->setCheckState(mercuryState);
0351 
0352     Qt::CheckState const venusState = m_renderPlanet["venus"] ? Qt::Checked : Qt::Unchecked;
0353     ui_configWidget->m_solarSystemListWidget->item( 3 )->setCheckState(venusState);
0354 
0355     Qt::CheckState const marsState = m_renderPlanet["mars"] ? Qt::Checked : Qt::Unchecked;
0356     ui_configWidget->m_solarSystemListWidget->item( 5 )->setCheckState(marsState);
0357 
0358     Qt::CheckState const jupiterState = m_renderPlanet["jupiter"] ? Qt::Checked : Qt::Unchecked;
0359     ui_configWidget->m_solarSystemListWidget->item( 6 )->setCheckState(jupiterState);
0360 
0361     Qt::CheckState const saturnState = m_renderPlanet["saturn"] ? Qt::Checked : Qt::Unchecked;
0362     ui_configWidget->m_solarSystemListWidget->item( 7 )->setCheckState(saturnState);
0363 
0364     Qt::CheckState const uranusState = m_renderPlanet["uranus"] ? Qt::Checked : Qt::Unchecked;
0365     ui_configWidget->m_solarSystemListWidget->item( 8 )->setCheckState(uranusState);
0366 
0367     Qt::CheckState const neptuneState = m_renderPlanet["neptune"] ? Qt::Checked : Qt::Unchecked;
0368     ui_configWidget->m_solarSystemListWidget->item( 9 )->setCheckState(neptuneState);
0369 
0370     Qt::CheckState const eclipticState = m_renderEcliptic ? Qt::Checked : Qt::Unchecked;
0371     ui_configWidget->m_viewEclipticCheckbox->setCheckState( eclipticState );
0372 
0373     Qt::CheckState const celestialEquatorState = m_renderCelestialEquator ? Qt::Checked : Qt::Unchecked;
0374     ui_configWidget->m_viewCelestialEquatorCheckbox->setCheckState( celestialEquatorState );
0375 
0376     Qt::CheckState const celestialPoleState = m_renderCelestialPole ? Qt::Checked : Qt::Unchecked;
0377     ui_configWidget->m_viewCelestialPoleCheckbox->setCheckState( celestialPoleState );
0378 
0379     Qt::CheckState const zoomSunMoonState = m_zoomSunMoon ? Qt::Checked : Qt::Unchecked;
0380     ui_configWidget->m_zoomSunMoonCheckbox->setCheckState( zoomSunMoonState );
0381 
0382     Qt::CheckState const viewSolarSystemLabelState = m_viewSolarSystemLabel ? Qt::Checked : Qt::Unchecked;
0383     ui_configWidget->m_viewSolarSystemLabelCheckbox->setCheckState( viewSolarSystemLabelState );
0384 
0385     int magState = m_magnitudeLimit;
0386     if ( magState < ui_configWidget->m_magnitudeSlider->minimum() ) {
0387         magState = ui_configWidget->m_magnitudeSlider->minimum();
0388     }
0389     else if ( magState > ui_configWidget->m_magnitudeSlider->maximum() ) {
0390         magState = ui_configWidget->m_magnitudeSlider->maximum();
0391     }
0392 
0393     ui_configWidget->m_magnitudeSlider->setValue(magState);
0394 
0395     QPalette constellationPalette;
0396     constellationPalette.setColor( QPalette::Button, m_constellationBrush.color() );
0397     ui_configWidget->m_constellationColorButton->setPalette( constellationPalette );
0398 
0399     QPalette constellationLabelPalette;
0400     constellationLabelPalette.setColor( QPalette::Button, m_constellationLabelBrush.color() );
0401     ui_configWidget->m_constellationLabelColorButton->setPalette( constellationLabelPalette );
0402 
0403     QPalette dsoLabelPalette;
0404     dsoLabelPalette.setColor( QPalette::Button, m_dsoLabelBrush.color() );
0405     ui_configWidget->m_dsoLabelColorButton->setPalette( dsoLabelPalette );
0406 
0407     QPalette eclipticPalette;
0408     eclipticPalette.setColor( QPalette::Button, m_eclipticBrush.color() );
0409     ui_configWidget->m_eclipticColorButton->setPalette( eclipticPalette );
0410 
0411     QPalette celestialEquatorPalette;
0412     celestialEquatorPalette.setColor( QPalette::Button, m_celestialEquatorBrush.color() );
0413     ui_configWidget->m_celestialEquatorColorButton->setPalette( celestialEquatorPalette );
0414 
0415     QPalette celestialPolePalette;
0416     celestialPolePalette.setColor( QPalette::Button, m_celestialPoleBrush.color() );
0417     ui_configWidget->m_celestialPoleColorButton->setPalette( celestialPolePalette );
0418 
0419 
0420 }
0421 
0422 void StarsPlugin::writeSettings()
0423 {
0424     m_nameIndex = ui_configWidget->constellationNamesComboBox->currentIndex();
0425     m_renderConstellationLines = ui_configWidget->m_viewConstellationLinesCheckbox->checkState() == Qt::Checked;
0426     m_renderConstellationLabels = ui_configWidget->m_viewConstellationLabelsCheckbox->checkState() == Qt::Checked;
0427     m_renderDsos = ui_configWidget->m_viewDsosCheckbox->checkState() == Qt::Checked;
0428     m_renderDsoLabels = ui_configWidget->m_viewDsoLabelCheckbox->checkState() == Qt::Checked;
0429     m_renderSun = ui_configWidget->m_solarSystemListWidget->item( 0 )->checkState() == Qt::Checked;
0430     m_renderMoon = ui_configWidget->m_solarSystemListWidget->item( 1 )->checkState() == Qt::Checked;
0431 
0432     m_renderPlanet["mercury"] = ui_configWidget->m_solarSystemListWidget->item( 2 )->checkState()
0433             == Qt::Checked;
0434     m_renderPlanet["venus"] = ui_configWidget->m_solarSystemListWidget->item( 3 )->checkState()
0435             == Qt::Checked;
0436     m_renderPlanet["mars"] = ui_configWidget->m_solarSystemListWidget->item( 5 )->checkState()
0437             == Qt::Checked;
0438     m_renderPlanet["jupiter"] = ui_configWidget->m_solarSystemListWidget->item( 6 )->checkState()
0439             == Qt::Checked;
0440     m_renderPlanet["saturn"] = ui_configWidget->m_solarSystemListWidget->item( 7 )->checkState()
0441             == Qt::Checked;
0442     m_renderPlanet["uranus"] = ui_configWidget->m_solarSystemListWidget->item( 8 )->checkState()
0443             == Qt::Checked;
0444     m_renderPlanet["neptune"] = ui_configWidget->m_solarSystemListWidget->item( 9 )->checkState()
0445             == Qt::Checked;
0446 
0447     m_renderEcliptic = ui_configWidget->m_viewEclipticCheckbox->checkState() == Qt::Checked;
0448     m_renderCelestialEquator = ui_configWidget->m_viewCelestialEquatorCheckbox->checkState() == Qt::Checked;
0449     m_renderCelestialPole = ui_configWidget->m_viewCelestialPoleCheckbox->checkState() == Qt::Checked;
0450     m_zoomSunMoon = ui_configWidget->m_zoomSunMoonCheckbox->checkState() == Qt::Checked;
0451     m_viewSolarSystemLabel = ui_configWidget->m_viewSolarSystemLabelCheckbox->checkState() == Qt::Checked;
0452     m_magnitudeLimit = ui_configWidget->m_magnitudeSlider->value();
0453     m_constellationBrush = QBrush( ui_configWidget->m_constellationColorButton->palette().color( QPalette::Button) );
0454     m_constellationLabelBrush = QBrush( ui_configWidget->m_constellationLabelColorButton->palette().color( QPalette::Button) );
0455     m_dsoLabelBrush = QBrush( ui_configWidget->m_dsoLabelColorButton->palette().color( QPalette::Button) );
0456     m_eclipticBrush = QBrush( ui_configWidget->m_eclipticColorButton->palette().color( QPalette::Button) );
0457     m_celestialEquatorBrush = QBrush( ui_configWidget->m_celestialEquatorColorButton->palette().color( QPalette::Button) );
0458     m_celestialPoleBrush = QBrush( ui_configWidget->m_celestialPoleColorButton->palette().color( QPalette::Button) );
0459     emit settingsChanged( nameId() );
0460 }
0461 
0462 void StarsPlugin::constellationGetColor()
0463 {
0464     const QColor c = QColorDialog::getColor( m_constellationBrush.color(), nullptr, tr("Please choose the color for the constellation lines.") );
0465 
0466     if ( c.isValid() ) {
0467         QPalette palette = ui_configWidget->m_constellationColorButton->palette();
0468         palette.setColor( QPalette::Button, c );
0469         ui_configWidget->m_constellationColorButton->setPalette( palette );
0470     }
0471 }
0472 
0473 void StarsPlugin::constellationLabelGetColor()
0474 {
0475     const QColor c = QColorDialog::getColor( m_constellationLabelBrush.color(), nullptr, tr("Please choose the color for the constellation labels.") );
0476 
0477     if ( c.isValid() ) {
0478         QPalette palette = ui_configWidget->m_constellationLabelColorButton->palette();
0479         palette.setColor( QPalette::Button, c );
0480         ui_configWidget->m_constellationLabelColorButton->setPalette( palette );
0481     }
0482 }
0483 
0484 void StarsPlugin::dsoLabelGetColor()
0485 {
0486     const QColor c = QColorDialog::getColor( m_dsoLabelBrush.color(), nullptr, tr("Please choose the color for the dso labels.") );
0487 
0488     if ( c.isValid() ) {
0489         QPalette palette = ui_configWidget->m_dsoLabelColorButton->palette();
0490         palette.setColor( QPalette::Button, c );
0491         ui_configWidget->m_dsoLabelColorButton->setPalette( palette );
0492     }
0493 }
0494 
0495 void StarsPlugin::eclipticGetColor()
0496 {
0497     const QColor c = QColorDialog::getColor( m_eclipticBrush.color(), nullptr, tr("Please choose the color for the ecliptic.") );
0498 
0499     if ( c.isValid() ) {
0500         QPalette palette = ui_configWidget->m_eclipticColorButton->palette();
0501         palette.setColor( QPalette::Button, c );
0502         ui_configWidget->m_eclipticColorButton->setPalette( palette );
0503     }
0504 }
0505 
0506 void StarsPlugin::celestialEquatorGetColor()
0507 {
0508     const QColor c = QColorDialog::getColor( m_celestialEquatorBrush.color(), nullptr, tr("Please choose the color for the celestial equator.") );
0509 
0510     if ( c.isValid() ) {
0511         QPalette palette = ui_configWidget->m_celestialEquatorColorButton->palette();
0512         palette.setColor( QPalette::Button, c );
0513         ui_configWidget->m_celestialEquatorColorButton->setPalette( palette );
0514     }
0515 }
0516 
0517 void StarsPlugin::celestialPoleGetColor()
0518 {
0519     const QColor c = QColorDialog::getColor( m_celestialPoleBrush.color(), nullptr, tr("Please choose the color for the celestial equator.") );
0520 
0521     if ( c.isValid() ) {
0522         QPalette palette = ui_configWidget->m_celestialPoleColorButton->palette();
0523         palette.setColor( QPalette::Button, c );
0524         ui_configWidget->m_celestialPoleColorButton->setPalette( palette );
0525     }
0526 }
0527 
0528 void StarsPlugin::loadStars()
0529 {
0530     //mDebug();
0531     // Load star data
0532     m_stars.clear();
0533 
0534     QFile starFile(MarbleDirs::path(QStringLiteral("stars/stars.dat")));
0535     starFile.open( QIODevice::ReadOnly );
0536     QDataStream in( &starFile );
0537 
0538     // Read and check the header
0539     quint32 magic;
0540     in >> magic;
0541     if ( magic != 0x73746172 ) {
0542         return;
0543     }
0544 
0545     // Read the version
0546     qint32 version;
0547     in >> version;
0548     if ( version > 004 ) {
0549         mDebug() << "stars.dat: file too new.";
0550         return;
0551     }
0552 
0553     if ( version == 003 ) {
0554         mDebug() << "stars.dat: file version no longer supported.";
0555         return;
0556     }
0557 
0558     int maxid = 0;
0559     int id = 0;
0560     int starIndex = 0;
0561     double ra;
0562     double de;
0563     double mag;
0564     int colorId = 2;
0565 
0566     mDebug() << "Star Catalog Version " << version;
0567 
0568     while ( !in.atEnd() ) {
0569         if ( version >= 2 ) {
0570             in >> id;
0571         }
0572         if ( id > maxid ) {
0573             maxid = id;
0574         }
0575         in >> ra;
0576         in >> de;
0577         in >> mag;
0578 
0579         if ( version >= 4 ) {
0580             in >> colorId;
0581         }
0582 
0583         StarPoint star( id, ( qreal )( ra ), ( qreal )( de ), ( qreal )( mag ), colorId );
0584         // Create entry in stars database
0585         m_stars << star;
0586         // Create key,value pair in idHash table to map from star id to
0587         // index in star database vector
0588         m_idHash[id] = starIndex;
0589         // Increment Index for use in hash
0590         ++starIndex;
0591     }
0592 
0593     // load the Sun pixmap
0594     // TODO: adjust pixmap size according to distance
0595     m_pixmapSun.load(MarbleDirs::path(QStringLiteral("svg/sun.png")));
0596     m_pixmapMoon.load(MarbleDirs::path(QStringLiteral("svg/moon.png")));
0597 
0598     m_starsLoaded = true;
0599 }
0600 
0601 void StarsPlugin::createStarPixmaps()
0602 {
0603     // Load star pixmaps
0604     QVector<QPixmap> pixBigStars;
0605     pixBigStars.clear();
0606     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_blue.png"))));
0607     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_bluewhite.png"))));
0608     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_white.png"))));
0609     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_yellow.png"))));
0610     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_orange.png"))));
0611     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_red.png"))));
0612     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_garnetred.png"))));
0613 
0614     QVector<QPixmap> pixSmallStars;
0615     pixSmallStars.clear();
0616     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_blue.png"))));
0617     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_bluewhite.png"))));
0618     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_white.png"))));
0619     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_yellow.png"))));
0620     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_orange.png"))));
0621     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_red.png"))));
0622     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_garnetred.png"))));
0623 
0624 
0625     // Pre-Scale Star Pixmaps
0626     m_pixN1Stars.clear();
0627     for ( int p=0; p < pixBigStars.size(); ++p) {
0628         int width = 1.0*pixBigStars.at(p).width();
0629         m_pixN1Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0630     }
0631 
0632     m_pixP0Stars.clear();
0633     for ( int p=0; p < pixBigStars.size(); ++p) {
0634         int width = 0.90*pixBigStars.at(p).width();
0635         m_pixP0Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0636     }
0637 
0638     m_pixP1Stars.clear();
0639     for ( int p=0; p < pixBigStars.size(); ++p) {
0640         int width = 0.80*pixBigStars.at(p).width();
0641         m_pixP1Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0642     }
0643 
0644     m_pixP2Stars.clear();
0645     for ( int p=0; p < pixBigStars.size(); ++p) {
0646         int width = 0.70*pixBigStars.at(p).width();
0647         m_pixP2Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0648     }
0649 
0650     m_pixP3Stars.clear();
0651     for ( int p=0; p < pixSmallStars.size(); ++p) {
0652         int width = 14;
0653         m_pixP3Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0654     }
0655 
0656     m_pixP4Stars.clear();
0657     for ( int p=0; p < pixSmallStars.size(); ++p) {
0658         int width = 10;
0659         m_pixP4Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0660     }
0661 
0662     m_pixP5Stars.clear();
0663     for ( int p=0; p < pixSmallStars.size(); ++p) {
0664         int width = 6;
0665         m_pixP5Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0666     }
0667 
0668     m_pixP6Stars.clear();
0669     for ( int p=0; p < pixSmallStars.size(); ++p) {
0670         int width = 4;
0671         m_pixP6Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0672     }
0673 
0674     m_pixP7Stars.clear();
0675     for ( int p=0; p < pixSmallStars.size(); ++p) {
0676         int width = 1;
0677         m_pixP7Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
0678     }
0679 
0680     m_starPixmapsCreated = true;
0681 }
0682 
0683 void StarsPlugin::loadConstellations()
0684 {
0685     // Load star data
0686     m_constellations.clear();
0687 
0688     QFile constellationFile(MarbleDirs::path(QStringLiteral("stars/constellations.dat")));
0689     constellationFile.open( QIODevice::ReadOnly );
0690     QTextStream in( &constellationFile );
0691     QString line;
0692     QString indexList;
0693 
0694     while ( !in.atEnd() ) {
0695         line = in.readLine();
0696 
0697         // Check for null line at end of file
0698         if ( line.isNull() ) {
0699             continue;
0700         }
0701 
0702         // Ignore Comment lines in header and
0703         // between constellation entries
0704         if (line.startsWith(QLatin1Char('#'))) {
0705             continue;
0706         }
0707 
0708         indexList = in.readLine();
0709 
0710         // Make sure we have a valid label and indexList
0711         if ( indexList.isNull() ) {
0712             break;
0713         }
0714 
0715         Constellation constellation( this, line, indexList );
0716         m_constellations << constellation;
0717 
0718     }
0719     m_constellationsLoaded = true;
0720 
0721 }
0722 
0723 void StarsPlugin::loadDsos()
0724 {
0725     // Load star data
0726     m_dsos.clear();
0727 
0728     QFile dsoFile(MarbleDirs::path(QStringLiteral("stars/dso.dat")));
0729     dsoFile.open( QIODevice::ReadOnly );
0730     QTextStream in( &dsoFile );
0731     QString line;
0732 
0733     while ( !in.atEnd() ) {
0734         line = in.readLine();
0735 
0736         // Check for null line at end of file
0737         if ( line.isNull() ) {
0738             continue;
0739         }
0740 
0741         // Ignore Comment lines in header and
0742         // between dso entries
0743         if (line.startsWith(QLatin1Char('#'))) {
0744             continue;
0745         }
0746 
0747         QStringList entries = line.split( QLatin1Char( ',' ) );
0748     
0749         QString id = entries.at( 0 ); 
0750         
0751         double raH = entries.at( 1 ).toDouble();
0752         double raM = entries.at( 2 ).toDouble();
0753         double raS = entries.at( 3 ).toDouble();
0754         double decD = entries.at( 4 ).toDouble();
0755         double decM = entries.at( 5 ).toDouble();
0756         double decS = entries.at( 6 ).toDouble();
0757 
0758         double raRad = ( raH+raM/60.0+raS/3600.0 )*15.0*M_PI/180.0;
0759         double decRad;
0760 
0761         if ( decD >= 0.0 ) {
0762             decRad = ( decD+decM/60.0+decS/3600.0 )*M_PI/180.0;
0763         }
0764         else {
0765             decRad = ( decD-decM/60.0-decS/3600.0 )*M_PI/180.0;
0766         }
0767 
0768         DsoPoint dso( id, ( qreal )( raRad ), ( qreal )( decRad ) );
0769         // Create entry in stars database
0770         m_dsos << dso;
0771     }
0772 
0773     m_dsoImage.load(MarbleDirs::path(QStringLiteral("stars/deepsky.png")));
0774     m_dsosLoaded = true;
0775 }
0776 
0777 bool StarsPlugin::render( GeoPainter *painter, ViewportParams *viewport,
0778                           const QString& renderPos, GeoSceneLayer * layer )
0779 {
0780     Q_UNUSED( renderPos )
0781     Q_UNUSED( layer )
0782 
0783     QString planetId = marbleModel()->planetId();
0784     const bool doRender = !viewport->mapCoversViewport() &&
0785                              ( (viewport->projection() == Spherical || viewport->projection() == VerticalPerspective) &&
0786                              planetId == QLatin1String("earth")); // So far displaying stars is only supported on earth.
0787 
0788     if ( doRender != m_doRender ) {
0789         if ( doRender ) {
0790             connect( marbleModel()->clock(), SIGNAL(timeChanged()),
0791                      this, SLOT(requestRepaint()) );
0792         } else {
0793             disconnect( marbleModel()->clock(), SIGNAL(timeChanged()),
0794                         this, SLOT(requestRepaint()) );
0795         }
0796 
0797         m_doRender = doRender;
0798     }
0799 
0800     painter->save();
0801 
0802     SolarSystem sys;
0803     QDateTime dateTime = marbleModel()->clock()->dateTime();
0804     sys.setCurrentMJD(
0805                 dateTime.date().year(), dateTime.date().month(), dateTime.date().day(),
0806                 dateTime.time().hour(), dateTime.time().minute(),
0807                 (double)dateTime.time().second());
0808     QString const pname = planetId.at(0).toUpper() + planetId.right(planetId.size() - 1);
0809     QByteArray name = pname.toLatin1();
0810     sys.setCentralBody( name.data() );
0811 
0812     Vec3 skyVector = sys.getPlanetocentric (0.0, 0.0);
0813     qreal skyRotationAngle = -atan2(skyVector[1], skyVector[0]);
0814 
0815     const qreal centerLon = viewport->centerLongitude();
0816     const qreal centerLat = viewport->centerLatitude();
0817 
0818     const qreal  skyRadius      = 0.6 * sqrt( ( qreal )viewport->width() * viewport->width() + viewport->height() * viewport->height() );
0819 
0820     if ( doRender ) {
0821         if (!m_starPixmapsCreated) {
0822             createStarPixmaps();
0823             m_starPixmapsCreated = true;
0824         }
0825 
0826         // Delayed initialization:
0827         // Load the star database only if the sky is actually being painted...
0828         if ( !m_starsLoaded ) {
0829             loadStars();
0830             m_starsLoaded = true;
0831         }
0832 
0833         if ( !m_constellationsLoaded ) {
0834             loadConstellations();
0835             m_constellationsLoaded = true;
0836         }
0837 
0838         if ( !m_dsosLoaded ) {
0839             loadDsos();
0840             m_dsosLoaded = true;
0841         }
0842 
0843         const qreal  earthRadius    = viewport->radius();
0844 
0845         // List of Pens used to draw the sky
0846         QPen polesPen( m_celestialPoleBrush, 2, Qt::SolidLine );
0847         QPen constellationPenSolid( m_constellationBrush, 1, Qt::SolidLine );
0848         QPen constellationPenDash(  m_constellationBrush, 1, Qt::DashLine );
0849         QPen constellationLabelPen( m_constellationLabelBrush, 1, Qt::SolidLine );
0850         QPen eclipticPen( m_eclipticBrush, 1, Qt::DotLine );
0851         QPen equatorPen( m_celestialEquatorBrush, 1, Qt::DotLine );
0852         QPen dsoLabelPen (m_dsoLabelBrush, 1, Qt::SolidLine);
0853 
0854 
0855         const Quaternion skyAxis = Quaternion::fromEuler( -centerLat , centerLon + skyRotationAngle, 0.0 );
0856         matrix skyAxisMatrix;
0857         skyAxis.inverse().toMatrix( skyAxisMatrix );
0858 
0859         if ( m_renderCelestialPole ) {
0860 
0861             polesPen.setWidth( 2 );
0862             painter->setPen( polesPen );
0863 
0864             Quaternion qpos1;
0865             qpos1 = Quaternion::fromSpherical( 0, 90 * DEG2RAD );
0866             qpos1.rotateAroundAxis( skyAxisMatrix );
0867 
0868             if ( qpos1.v[Q_Z] < 0 ) {
0869                 const int x1 = ( int )( viewport->width()  / 2 + skyRadius * qpos1.v[Q_X] );
0870                 const int y1 = ( int )( viewport->height() / 2 - skyRadius * qpos1.v[Q_Y] );
0871                 painter->drawLine( x1, y1, x1+10, y1 );
0872                 painter->drawLine( x1+5, y1-5, x1+5, y1+5 );
0873                 painter->drawText( x1+8, y1+12, "NP" );
0874             }
0875 
0876             Quaternion qpos2;
0877             qpos2 = Quaternion::fromSpherical( 0, -90 * DEG2RAD );
0878             qpos2.rotateAroundAxis( skyAxisMatrix );
0879             if ( qpos2.v[Q_Z] < 0 ) {
0880                 const int x1 = ( int )( viewport->width()  / 2 + skyRadius * qpos2.v[Q_X] );
0881                 const int y1 = ( int )( viewport->height() / 2 - skyRadius * qpos2.v[Q_Y] );
0882                 painter->drawLine( x1, y1, x1+10, y1 );
0883                 painter->drawLine( x1+5, y1-5, x1+5, y1+5 );
0884                 painter->drawText( x1+8, y1+12, "SP" );
0885             }
0886         }
0887 
0888         if( m_renderEcliptic ) {
0889             const Quaternion eclipticAxis = Quaternion::fromEuler( 0.0, 0.0, -marbleModel()->planet()->epsilon() );
0890             matrix eclipticAxisMatrix;
0891             (eclipticAxis * skyAxis).inverse().toMatrix( eclipticAxisMatrix );
0892 
0893             painter->setPen(eclipticPen);
0894 
0895             int previousX = -1;
0896             int previousY = -1;
0897             for ( int i = 0; i <= 36; ++i) {
0898                 Quaternion qpos;
0899                 qpos = Quaternion::fromSpherical( i * 10 * DEG2RAD, 0 );
0900                 qpos.rotateAroundAxis( eclipticAxisMatrix );
0901 
0902                 int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
0903                 int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
0904 
0905                 if ( qpos.v[Q_Z] < 0 && previousX >= 0 ) painter->drawLine(previousX, previousY, x, y);
0906 
0907                 previousX = x;
0908                 previousY = y;
0909             }
0910         }
0911 
0912         if( m_renderCelestialEquator ) {
0913             painter->setPen(equatorPen);
0914 
0915             int previousX = -1;
0916             int previousY = -1;
0917             for ( int i = 0; i <= 36; ++i) {
0918                 Quaternion qpos;
0919                 qpos = Quaternion::fromSpherical( i * 10 * DEG2RAD, 0 );
0920                 qpos.rotateAroundAxis( skyAxisMatrix );
0921 
0922                 int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
0923                 int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
0924 
0925                 if ( qpos.v[Q_Z] < 0 && previousX > 0 ) painter->drawLine(previousX, previousY, x, y);
0926 
0927                 previousX = x;
0928                 previousY = y;
0929             }
0930         }
0931 
0932         if ( m_renderDsos ) {
0933             painter->setPen(dsoLabelPen);
0934             // Render Deep Space Objects
0935             for ( int d = 0; d < m_dsos.size(); ++d ) {
0936                 Quaternion qpos = m_dsos.at( d ).quaternion();
0937                 qpos.rotateAroundAxis( skyAxisMatrix );
0938 
0939                 if ( qpos.v[Q_Z] > 0 ) {
0940                     continue;
0941                 }
0942 
0943                 qreal earthCenteredX = qpos.v[Q_X] * skyRadius;
0944                 qreal earthCenteredY = qpos.v[Q_Y] * skyRadius;
0945 
0946                 // Don't draw high placemarks (e.g. satellites) that aren't visible.
0947                 if ( qpos.v[Q_Z] < 0
0948                         && ( ( earthCenteredX * earthCenteredX
0949                                + earthCenteredY * earthCenteredY )
0950                              < earthRadius * earthRadius ) ) {
0951                     continue;
0952                 }
0953 
0954                 // Let (x, y) be the position on the screen of the placemark..
0955                 const int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
0956                 const int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
0957 
0958                 // Skip placemarks that are outside the screen area
0959                 if ( x < 0 || x >= viewport->width() ||
0960                      y < 0 || y >= viewport->height() ) {
0961                     continue;
0962                 }
0963 
0964                 // Hard Code DSO Size for now
0965                 qreal size = 20;
0966 
0967                 // Center Image on x,y location
0968                 painter->drawImage( QRectF( x-size/2, y-size/2, size, size ),m_dsoImage );
0969                 if (m_renderDsoLabels) {
0970                     painter->drawText( x+8, y+12, m_dsos.at( d ).id() );
0971                 }
0972             }
0973         }
0974 
0975         if ( m_renderConstellationLines ||  m_renderConstellationLabels )
0976         {
0977             // Render Constellations
0978             for ( int c = 0; c < m_constellations.size(); ++c ) {
0979                 int xMean = 0;
0980                 int yMean = 0;
0981                 int endptCount = 0;
0982                 painter->setPen( constellationPenSolid );
0983 
0984                 for ( int s = 0; s < ( m_constellations.at( c ).size() - 1 ); ++s ) {
0985                     int starId1 = m_constellations.at( c ).at( s );
0986                     int starId2 = m_constellations.at( c ).at( s + 1 );
0987 
0988                     if ( starId1 == -1 || starId2 == -1 ) {
0989                         // starId == -1 means we don't draw this segment
0990                         continue;
0991                     } else if ( starId1 == -2 || starId2 == -2 ) {
0992                         painter->setPen( constellationPenDash );
0993                     } else if ( starId1 == -3 || starId2 == -3 ) {
0994                         painter->setPen( constellationPenSolid );
0995                     }
0996 
0997                     int idx1 = m_idHash.value( starId1,-1 );
0998                     int idx2 = m_idHash.value( starId2,-1 );
0999 
1000                    
1001                     if ( idx1 < 0 ) {
1002 //                        mDebug() << "unknown star, "
1003 //                                 << starId1 <<  ", in constellation "
1004 //                                 << m_constellations.at( c ).name();
1005                         continue;
1006                     }
1007 
1008                     if ( idx2 < 0 ) {
1009 //                        mDebug() << "unknown star, "
1010 //                                 << starId1 <<  ", in constellation "
1011 //                                 << m_constellations.at( c ).name();
1012                         continue;
1013                     }
1014                     // Fetch quaternion from star s in constellation c
1015                     Quaternion q1 = m_stars.at( idx1 ).quaternion();
1016                     // Fetch quaternion from star s+1 in constellation c
1017                     Quaternion q2 = m_stars.at( idx2 ).quaternion();
1018 
1019                     q1.rotateAroundAxis( skyAxisMatrix );
1020                     q2.rotateAroundAxis( skyAxisMatrix );
1021 
1022                     if ( q1.v[Q_Z] > 0 || q2.v[Q_Z] > 0 ) {
1023                         continue;
1024                     }
1025 
1026 
1027                     // Let (x, y) be the position on the screen of the placemark..
1028                     int x1 = ( int )( viewport->width()  / 2 + skyRadius * q1.v[Q_X] );
1029                     int y1 = ( int )( viewport->height() / 2 - skyRadius * q1.v[Q_Y] );
1030                     int x2 = ( int )( viewport->width()  / 2 + skyRadius * q2.v[Q_X] );
1031                     int y2 = ( int )( viewport->height() / 2 - skyRadius * q2.v[Q_Y] );
1032 
1033 
1034                     xMean = xMean + x1 + x2;
1035                     yMean = yMean + y1 + y2;
1036                     endptCount = endptCount + 2;
1037 
1038                     if ( m_renderConstellationLines ) {
1039                         painter->drawLine( x1, y1, x2, y2 );
1040                     }
1041 
1042                 }
1043 
1044                 // Skip constellation labels that are outside the screen area
1045                 if ( endptCount > 0 ) {
1046                     xMean = xMean / endptCount;
1047                     yMean = yMean / endptCount;
1048                 }
1049 
1050                 if ( endptCount < 1 || xMean < 0 || xMean >= viewport->width()
1051                         || yMean < 0 || yMean >= viewport->height() )
1052                     continue;
1053 
1054                 painter->setPen( constellationLabelPen );
1055                 if ( m_renderConstellationLabels ) {
1056                     painter->drawText( xMean, yMean, m_constellations.at( c ).name() );
1057                 }
1058 
1059             }
1060         }
1061 
1062         // Render Stars
1063 
1064         for ( int s = 0; s < m_stars.size(); ++s  ) {
1065             Quaternion  qpos = m_stars.at(s).quaternion();
1066 
1067             qpos.rotateAroundAxis( skyAxisMatrix );
1068 
1069             if ( qpos.v[Q_Z] > 0 ) {
1070                 continue;
1071             }
1072 
1073             qreal  earthCenteredX = qpos.v[Q_X] * skyRadius;
1074             qreal  earthCenteredY = qpos.v[Q_Y] * skyRadius;
1075 
1076             // Don't draw high placemarks (e.g. satellites) that aren't visible.
1077             if ( qpos.v[Q_Z] < 0
1078                     && ( ( earthCenteredX * earthCenteredX
1079                            + earthCenteredY * earthCenteredY )
1080                          < earthRadius * earthRadius ) ) {
1081                 continue;
1082             }
1083 
1084             // Let (x, y) be the position on the screen of the placemark..
1085             const int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
1086             const int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
1087 
1088             // Skip placemarks that are outside the screen area
1089             if ( x < 0 || x >= viewport->width()
1090                     || y < 0 || y >= viewport->height() )
1091                 continue;
1092 
1093             // Show star if it is brighter than magnitude threshold
1094             if ( m_stars.at(s).magnitude() < m_magnitudeLimit ) {
1095 
1096                 // colorId is used to select which pixmap in vector to display
1097                 int colorId = m_stars.at(s).colorId();
1098                 QPixmap s_pixmap = starPixmap(m_stars.at(s).magnitude(), colorId);
1099                 int sizeX = s_pixmap.width();
1100                 int sizeY = s_pixmap.height();
1101                 painter->drawPixmap( x-sizeX/2, y-sizeY/2 ,s_pixmap );
1102             }
1103         }
1104 
1105         if ( m_renderSun ) {
1106             // sun
1107             double ra = 0.0;
1108             double decl = 0.0;
1109             sys.getSun( ra, decl );
1110             ra = 15.0 * sys.DmsDegF( ra );
1111             decl = sys.DmsDegF( decl );
1112 
1113             Quaternion qpos = Quaternion::fromSpherical( ra * DEG2RAD, decl * DEG2RAD );
1114             qpos.rotateAroundAxis( skyAxisMatrix );
1115 
1116             if ( qpos.v[Q_Z] <= 0 ) {
1117                 QPixmap glow(MarbleDirs::path(QStringLiteral("svg/glow.png")));
1118                 qreal deltaX  = glow.width()  / 2.;
1119                 qreal deltaY  = glow.height() / 2.;
1120                 int x = (int)(viewport->width()  / 2 + skyRadius * qpos.v[Q_X]);
1121                 int y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]);
1122 
1123                 bool glowDrawn = false;
1124                 if (!(x < -glow.width() || x >= viewport->width() ||
1125                       y < -glow.height() || y >= viewport->height())) {
1126                     painter->drawPixmap( x - deltaX, y - deltaY, glow );
1127                     glowDrawn = true;
1128                 }
1129 
1130                 if (glowDrawn) {
1131                     double diameter = 0.0, mag = 0.0;
1132                     sys.getPhysSun(diameter, mag);
1133                     const int coefficient = m_zoomSunMoon ? m_zoomCoefficient : 1;
1134                     const qreal size = skyRadius * qSin(diameter) * coefficient;
1135                     const qreal factor = size/m_pixmapSun.width();
1136                     QPixmap sun = m_pixmapSun.transformed(QTransform().scale(factor, factor),
1137                                                           Qt::SmoothTransformation);
1138                     deltaX  = sun.width()  / 2.;
1139                     deltaY  = sun.height() / 2.;
1140                     x = (int)(viewport->width()  / 2 + skyRadius * qpos.v[Q_X]);
1141                     y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]);
1142 
1143                     painter->drawPixmap( x - deltaX, y - deltaY, sun );
1144                 }
1145 
1146                 // It's labels' time!
1147                 if (m_viewSolarSystemLabel)
1148                     painter->drawText(x+deltaX*1.5, y+deltaY*1.5, tr("Sun"));
1149             }
1150         }
1151 
1152         if ( m_renderMoon && marbleModel()->planetId() == QLatin1String("earth")) {
1153             // moon
1154             double ra=0.0;
1155             double decl=0.0;
1156             sys.getMoon(ra, decl);
1157             ra = 15.0 * sys.DmsDegF(ra);
1158             decl = sys.DmsDegF(decl);
1159 
1160             Quaternion qpos = Quaternion::fromSpherical( ra * DEG2RAD,
1161                                                          decl * DEG2RAD );
1162             qpos.rotateAroundAxis( skyAxisMatrix );
1163 
1164             if ( qpos.v[Q_Z] <= 0 ) {
1165                 // If zoom Sun and Moon is enabled size is multiplied by zoomCoefficient.
1166                 const int coefficient = m_zoomSunMoon ? m_zoomCoefficient : 1;
1167 
1168                 QPixmap moon = m_pixmapMoon.copy();
1169 
1170                 const qreal size = skyRadius * qSin(sys.getDiamMoon()) * coefficient;
1171                 qreal deltaX  = size  / 2.;
1172                 qreal deltaY  = size / 2.;
1173                 const int x = (int)(viewport->width()  / 2 + skyRadius * qpos.v[Q_X]);
1174                 const int y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]);
1175 
1176 
1177                 if (!(x < -size || x >= viewport->width() ||
1178                       y < -size || y >= viewport->height())) {
1179                     // Moon phases
1180                     double phase = 0.0, ildisk = 0.0, amag = 0.0;
1181                     sys.getLunarPhase(phase, ildisk, amag);
1182 
1183                     QPainterPath path;
1184 
1185                     QRectF fullMoonRect = moon.rect();
1186                     if (ildisk < 0.05) {
1187                         // small enough, so it's not visible
1188                         path.addEllipse(fullMoonRect);
1189                     } else if (ildisk < 0.95) { // makes sense to do smth
1190                         QRectF halfEllipseRect;
1191                         qreal ellipseWidth = 2 * qAbs(ildisk-0.5) * moon.width();
1192                         halfEllipseRect.setX((fullMoonRect.width() - ellipseWidth) * 0.5);
1193                         halfEllipseRect.setWidth(ellipseWidth);
1194                         halfEllipseRect.setHeight(moon.height());
1195 
1196                         if (phase < 0.5) {
1197                             if (ildisk < 0.5) {
1198                                 path.moveTo(fullMoonRect.width()/2, moon.height());
1199                                 path.arcTo(fullMoonRect, -90, -180);
1200                                 path.arcTo(halfEllipseRect, 90, -180);
1201                             } else {
1202                                 path.moveTo(fullMoonRect.width()/2, 0);
1203                                 path.arcTo(fullMoonRect, 90, 180);
1204                                 path.arcTo(halfEllipseRect, -90, -180);
1205                             }
1206                         } else {
1207                             if (ildisk < 0.5) {
1208                                 path.moveTo(fullMoonRect.width()/2, moon.height());
1209                                 path.arcTo(fullMoonRect, -90, 180);
1210                                 path.arcTo(halfEllipseRect, 90, 180);
1211                             } else {
1212                                 path.moveTo(fullMoonRect.width()/2, 0);
1213                                 path.arcTo(fullMoonRect, 90, -180);
1214                                 path.arcTo(halfEllipseRect, -90, 180);
1215                             }
1216                         }
1217 
1218                         path.closeSubpath();
1219                     }
1220 
1221                     QPainter overlay;
1222                     overlay.begin(&moon);
1223                     overlay.setPen(Qt::NoPen);
1224                     overlay.setBrush(QBrush(QColor(0, 0, 0, 180)));
1225                     overlay.setRenderHint(QPainter::Antialiasing, true);
1226                     overlay.drawPath(path);
1227                     overlay.end();
1228 
1229                     qreal angle = marbleModel()->planet()->epsilon() * qCos(ra * DEG2RAD) * RAD2DEG;
1230                     if (viewport->polarity() < 0) angle += 180;
1231 
1232                     QTransform form;
1233                     const qreal factor = size / moon.size().width();
1234                     moon = moon.transformed(form.rotate(angle).scale(factor, factor),
1235                                                             Qt::SmoothTransformation);
1236 
1237                     painter->drawPixmap( x - deltaX, y - deltaY, moon );
1238 
1239                     // It's labels' time!
1240                     if (m_viewSolarSystemLabel)
1241                         painter->drawText(x+deltaX, y+deltaY, PlanetFactory::localizedName("moon"));
1242                 }
1243             }
1244         }
1245 
1246         for(const QString &planet: m_renderPlanet.keys()) {
1247             if (m_renderPlanet[planet])
1248                 renderPlanet(planet, painter, sys, viewport, skyRadius, skyAxisMatrix);
1249         }
1250     }
1251 
1252     painter->restore();
1253 
1254     return true;
1255 }
1256 
1257 void StarsPlugin::renderPlanet(const QString &planetId,
1258                                GeoPainter *painter,
1259                                SolarSystem &sys,
1260                                ViewportParams *viewport,
1261                                qreal skyRadius,
1262                                matrix &skyAxisMatrix) const
1263 {
1264     double ra(.0), decl(.0), diam(.0), mag(.0), phase(.0);
1265     int color=0;
1266 
1267     // venus, mars, jupiter, uranus, neptune, saturn
1268     if (planetId == QLatin1String("venus")) {
1269         sys.getVenus(ra, decl);
1270         sys.getPhysVenus(diam, mag, phase);
1271         color = 2;
1272     } else if (planetId == QLatin1String("mars")) {
1273         sys.getMars(ra, decl);
1274         sys.getPhysMars(diam, mag, phase);
1275         color = 5;
1276     } else if (planetId == QLatin1String("jupiter")) {
1277         sys.getJupiter(ra, decl);
1278         sys.getPhysJupiter(diam, mag, phase);
1279         color = 2;
1280     } else if (planetId == QLatin1String("mercury")) {
1281         sys.getMercury(ra, decl);
1282         sys.getPhysMercury(diam, mag, phase);
1283         color = 3;
1284     } else if (planetId == QLatin1String("saturn")) {
1285         sys.getSaturn(ra, decl);
1286         sys.getPhysSaturn(diam, mag, phase);
1287         color = 3;
1288     } else if (planetId == QLatin1String("uranus")) {
1289         sys.getUranus(ra, decl);
1290         sys.getPhysUranus(diam, mag, phase);
1291         color = 0;
1292     } else if (planetId == QLatin1String("neptune")) {
1293         sys.getNeptune(ra, decl);
1294         sys.getPhysNeptune(diam, mag, phase);
1295         color = 0;
1296     } else {
1297         return;
1298     }
1299 
1300     ra = 15.0 * sys.DmsDegF(ra);
1301     decl = sys.DmsDegF(decl);
1302 
1303     Quaternion qpos = Quaternion::fromSpherical( ra * DEG2RAD,
1304                                                  decl * DEG2RAD );
1305     qpos.rotateAroundAxis( skyAxisMatrix );
1306 
1307     if ( qpos.v[Q_Z] <= 0 ) {
1308         QPixmap planetPixmap = starPixmap(mag, color);
1309 
1310         qreal deltaX  = planetPixmap.width()  / 2.;
1311         qreal deltaY  = planetPixmap.height() / 2.;
1312         const int x = (int)(viewport->width()  / 2 + skyRadius * qpos.v[Q_X]);
1313         const int y = (int)(viewport->height() / 2 - skyRadius * qpos.v[Q_Y]);
1314 
1315         if (!(x < 0 || x >= viewport->width() ||
1316              y < 0 || y >= viewport->height())) {
1317              painter->drawPixmap( x - deltaX, y - deltaY, planetPixmap );
1318         }
1319 
1320         // It's labels' time!
1321         if (m_viewSolarSystemLabel)
1322             painter->drawText(x+deltaX, y+deltaY, PlanetFactory::localizedName(planetId));
1323     }
1324 }
1325 
1326 void StarsPlugin::requestRepaint()
1327 {
1328     emit repaintNeeded( QRegion() );
1329 }
1330 
1331 void StarsPlugin::toggleSunMoon(bool on)
1332 {
1333     m_renderSun = on;
1334     m_renderMoon = on;
1335     if (on) {
1336         m_viewSolarSystemLabel = true;
1337     }
1338 
1339     const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked;
1340     if ( m_configDialog ) {
1341         ui_configWidget->m_solarSystemListWidget->item( 0 )->setCheckState( state );
1342         ui_configWidget->m_solarSystemListWidget->item( 1 )->setCheckState( state );
1343         ui_configWidget->m_viewSolarSystemLabelCheckbox->setChecked(m_viewSolarSystemLabel);
1344     }
1345     emit settingsChanged( nameId() );
1346     requestRepaint();
1347 }
1348 
1349 void StarsPlugin::toggleDsos(bool on)
1350 {
1351     m_renderDsos = on;
1352     // only enable labels if set to true
1353     if (on) {
1354         m_renderDsoLabels = true;
1355     }
1356 
1357     const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked;
1358     if ( m_configDialog ) {
1359         ui_configWidget->m_viewDsosCheckbox->setChecked(state);
1360         ui_configWidget->m_viewDsoLabelCheckbox->setChecked(state);
1361     }
1362     emit settingsChanged( nameId() );
1363     requestRepaint();
1364 }
1365 
1366 void StarsPlugin::toggleConstellations(bool on)
1367 {
1368     m_renderConstellationLines = on;
1369     m_renderConstellationLabels = on;
1370 
1371     const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked;
1372     if ( m_configDialog ) {
1373         ui_configWidget->m_viewConstellationLinesCheckbox->setChecked( state );
1374         ui_configWidget->m_viewConstellationLabelsCheckbox->setChecked( state );
1375     }
1376     emit settingsChanged( nameId() );
1377     requestRepaint();
1378 }
1379 
1380 void StarsPlugin::togglePlanets(bool on)
1381 {
1382     m_renderPlanet["venus"] = on;
1383     m_renderPlanet["mars"]  = on;
1384     m_renderPlanet["jupiter"] = on;
1385     m_renderPlanet["mercury"] = on;
1386     m_renderPlanet["saturn"] = on;
1387     m_renderPlanet["uranus"] = on;
1388     m_renderPlanet["neptune"] = on;
1389 
1390     const Qt::CheckState state = on ? Qt::Checked : Qt::Unchecked;
1391     if ( m_configDialog ) {
1392         // Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune
1393         ui_configWidget->m_solarSystemListWidget->item(2)->setCheckState(state);
1394         ui_configWidget->m_solarSystemListWidget->item(3)->setCheckState(state);
1395         ui_configWidget->m_solarSystemListWidget->item(5)->setCheckState(state);
1396         ui_configWidget->m_solarSystemListWidget->item(6)->setCheckState(state);
1397         ui_configWidget->m_solarSystemListWidget->item(7)->setCheckState(state);
1398         ui_configWidget->m_solarSystemListWidget->item(8)->setCheckState(state);
1399         ui_configWidget->m_solarSystemListWidget->item(9)->setCheckState(state);
1400     }
1401 
1402     emit settingsChanged( nameId() );
1403     requestRepaint();
1404 }
1405 
1406 void StarsPlugin::executeConfigDialog()
1407 {
1408     QDialog *dialog = configDialog();
1409     Q_ASSERT( dialog );
1410     dialog->exec();
1411 }
1412 
1413 bool StarsPlugin::eventFilter( QObject *object, QEvent *e )
1414 {
1415     if ( !enabled() || !visible() ) {
1416         return false;
1417     }
1418 
1419     if( e->type() == QEvent::ContextMenu )
1420     {
1421         MarbleWidget *widget = dynamic_cast<MarbleWidget *>( object );
1422         QContextMenuEvent *menuEvent = dynamic_cast<QContextMenuEvent *> ( e );
1423         if( widget && menuEvent )
1424         {
1425             qreal mouseLon, mouseLat;
1426             const bool aboveMap = widget->geoCoordinates( menuEvent->x(), menuEvent->y(),
1427                                                      mouseLon, mouseLat, GeoDataCoordinates::Radian );
1428             if ( aboveMap ) {
1429                 return false;
1430             }
1431 
1432             for ( AbstractFloatItem *floatItem: widget->floatItems() ) {
1433                 if ( floatItem->enabled() && floatItem->visible()
1434                      && floatItem->contains( menuEvent->pos() ) )
1435                 {
1436                     return false;
1437                 }
1438             }
1439 
1440             if (!m_contextMenu) {
1441                 m_contextMenu = new QMenu;
1442                 m_constellationsAction = m_contextMenu->addAction(tr("Show &Constellations"),
1443                                                                   this, SLOT(toggleConstellations(bool)));
1444                 m_constellationsAction->setCheckable(true);
1445 
1446                 m_sunMoonAction = m_contextMenu->addAction(tr("Show &Sun and Moon"),
1447                                                            this, SLOT(toggleSunMoon(bool)));
1448                 m_sunMoonAction->setCheckable(true);
1449 
1450                 m_planetsAction = m_contextMenu->addAction(tr("Show &Planets"),
1451                                                            this, SLOT(togglePlanets(bool)));
1452                 m_planetsAction->setCheckable(true);
1453 
1454                 m_dsoAction = m_contextMenu->addAction(tr("Show &Deep Sky Objects"),
1455                                                        this, SLOT(toggleDsos(bool)) );
1456                 m_dsoAction->setCheckable(true);
1457 
1458                 m_contextMenu->addSeparator();
1459                 m_contextMenu->addAction(tr("&Configure..."),
1460                                          this, SLOT(executeConfigDialog()));
1461             }
1462 
1463             // update action states
1464             m_constellationsAction->setChecked(m_renderConstellationLines || m_renderConstellationLabels);
1465             m_sunMoonAction->setChecked(m_renderSun || m_renderMoon);
1466             m_dsoAction->setChecked(m_renderDsos);
1467             const bool isAnyPlanetRendered =
1468                 m_renderPlanet["venus"] ||   m_renderPlanet["mars"] ||
1469                 m_renderPlanet["jupiter"] || m_renderPlanet["mercury"] ||
1470                 m_renderPlanet["saturn"] ||  m_renderPlanet["uranus"] ||
1471                 m_renderPlanet["neptune"];
1472             m_planetsAction->setChecked(isAnyPlanetRendered);
1473 
1474             m_contextMenu->exec(widget->mapToGlobal(menuEvent->pos()));
1475             return true;
1476         }
1477         return false;
1478     } else {
1479         return RenderPlugin::eventFilter( object, e );
1480     }
1481 }
1482 
1483 }
1484 
1485 #include "moc_StarsPlugin.cpp"