1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2008 Torsten Rahn <tackat@kde.org>
4 // SPDX-FileCopyrightText: 2011-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
5 //
6 
7 #include "StarsPlugin.h"
8 
9 #include "ui_StarsConfigWidget.h"
10 #include <QRectF>
11 #include <QSize>
12 #include <QDateTime>
13 #include <QRegion>
14 #include <QContextMenuEvent>
15 #include <QMenu>
16 #include <QColorDialog>
17 #include <QPainterPath>
18 #include <qmath.h>
19 
20 #include "MarbleClock.h"
21 #include "MarbleColors.h"
22 #include "MarbleDebug.h"
23 #include "MarbleDirs.h"
24 #include "MarbleModel.h"
25 #include "MarbleWidget.h"
26 #include "AbstractFloatItem.h"
27 #include "GeoPainter.h"
28 #include "Planet.h"
29 #include "PlanetFactory.h"
30 #include "SunLocator.h"
31 #include "ViewportParams.h"
32 
33 #include "src/lib/astro/solarsystem.h"
34 
35 namespace Marble
36 {
37 
StarsPlugin(const MarbleModel * marbleModel)38 StarsPlugin::StarsPlugin( const MarbleModel *marbleModel )
39     : RenderPlugin( marbleModel ),
40       m_nameIndex( 0 ),
41       m_configDialog( nullptr ),
42       ui_configWidget( nullptr ),
43       m_renderStars( true ),
44       m_renderConstellationLines( true ),
45       m_renderConstellationLabels( true ),
46       m_renderDsos( true ),
47       m_renderDsoLabels( true ),
48       m_renderSun( true ),
49       m_renderMoon( true ),
50       m_renderEcliptic( true ),
51       m_renderCelestialEquator( true ),
52       m_renderCelestialPole( true ),
53       m_starsLoaded( false ),
54       m_starPixmapsCreated( false ),
55       m_constellationsLoaded( false ),
56       m_dsosLoaded( false ),
57       m_zoomSunMoon( true ),
58       m_viewSolarSystemLabel( true ),
59       m_magnitudeLimit( 100 ),
60       m_zoomCoefficient( 4 ),
61       m_constellationBrush( Marble::Oxygen::aluminumGray5 ),
62       m_constellationLabelBrush( Marble::Oxygen::aluminumGray5 ),
63       m_dsoLabelBrush( Marble::Oxygen::aluminumGray5 ),
64       m_eclipticBrush( Marble::Oxygen::aluminumGray5 ),
65       m_celestialEquatorBrush( Marble::Oxygen::aluminumGray5 ),
66       m_celestialPoleBrush( Marble::Oxygen::aluminumGray5 ),
67       m_contextMenu(nullptr),
68       m_constellationsAction(nullptr),
69       m_sunMoonAction(nullptr),
70       m_planetsAction(nullptr),
71       m_dsoAction(nullptr),
72       m_doRender( false )
73 {
74     bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
75     if (smallScreen) m_magnitudeLimit = 5;
76 
77     prepareNames();
78 }
79 
~StarsPlugin()80 StarsPlugin::~StarsPlugin()
81 {
82     delete m_contextMenu;
83 }
84 
backendTypes() const85 QStringList StarsPlugin::backendTypes() const
86 {
87     return QStringList(QStringLiteral("stars"));
88 }
89 
renderPolicy() const90 QString StarsPlugin::renderPolicy() const
91 {
92     return QStringLiteral("SPECIFIED_ALWAYS");
93 }
94 
renderPosition() const95 QStringList StarsPlugin::renderPosition() const
96 {
97     return QStringList(QStringLiteral("STARS"));
98 }
99 
renderType() const100 RenderPlugin::RenderType StarsPlugin::renderType() const
101 {
102     return RenderPlugin::ThemeRenderType;
103 }
104 
name() const105 QString StarsPlugin::name() const
106 {
107     return tr( "Stars" );
108 }
109 
guiString() const110 QString StarsPlugin::guiString() const
111 {
112     return tr( "&Stars" );
113 }
114 
nameId() const115 QString StarsPlugin::nameId() const
116 {
117     return QStringLiteral("stars");
118 }
119 
version() const120 QString StarsPlugin::version() const
121 {
122     return QStringLiteral("1.2");
123 }
124 
description() const125 QString StarsPlugin::description() const
126 {
127     return tr( "A plugin that shows the Starry Sky and the Sun." );
128 }
129 
copyrightYears() const130 QString StarsPlugin::copyrightYears() const
131 {
132     return QStringLiteral("2008-2012");
133 }
134 
pluginAuthors() const135 QVector<PluginAuthor> StarsPlugin::pluginAuthors() const
136 {
137     return QVector<PluginAuthor>()
138            << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org"))
139            << PluginAuthor(QStringLiteral("Rene Kuettner"), QStringLiteral("rene@bitkanal.net"))
140            << PluginAuthor(QStringLiteral("Timothy Lanzi"), QStringLiteral("trlanzi@gmail.com"));
141 }
142 
icon() const143 QIcon StarsPlugin::icon() const
144 {
145     return QIcon(QStringLiteral(":/icons/stars.png"));
146 }
147 
initialize()148 void StarsPlugin::initialize()
149 {
150 }
151 
isInitialized() const152 bool StarsPlugin::isInitialized() const
153 {
154     return true;
155 }
156 
configDialog()157 QDialog *StarsPlugin::configDialog()
158 {
159     if (!m_configDialog) {
160         // Initializing configuration dialog
161         m_configDialog = new QDialog;
162         ui_configWidget = new Ui::StarsConfigWidget;
163         ui_configWidget->setupUi( m_configDialog );
164 
165         readSettings();
166 
167         connect( ui_configWidget->m_buttonBox, SIGNAL(accepted()), SLOT(writeSettings()) );
168         connect( ui_configWidget->m_buttonBox, SIGNAL(rejected()), SLOT(readSettings()) );
169 
170         connect( ui_configWidget->m_constellationColorButton, SIGNAL(clicked()), this,
171                 SLOT(constellationGetColor()) );
172 
173         connect( ui_configWidget->m_constellationLabelColorButton, SIGNAL(clicked()), this,
174                 SLOT(constellationLabelGetColor()) );
175 
176         connect( ui_configWidget->m_dsoLabelColorButton, SIGNAL(clicked()), this,
177                 SLOT(dsoLabelGetColor()) );
178 
179         connect( ui_configWidget->m_eclipticColorButton, SIGNAL(clicked()), this,
180                 SLOT(eclipticGetColor()) );
181 
182         connect( ui_configWidget->m_celestialEquatorColorButton, SIGNAL(clicked()), this,
183                 SLOT(celestialEquatorGetColor()) );
184 
185         connect( ui_configWidget->m_celestialPoleColorButton, SIGNAL(clicked()), this,
186                 SLOT(celestialPoleGetColor()) );
187     }
188 
189     return m_configDialog;
190 }
191 
settings() const192 QHash<QString, QVariant> StarsPlugin::settings() const
193 {
194     QHash<QString, QVariant> settings = RenderPlugin::settings();
195 
196     settings.insert(QStringLiteral("nameIndex"), m_nameIndex);
197     settings.insert(QStringLiteral("renderStars"), m_renderStars);
198     settings.insert(QStringLiteral("renderConstellationLines"), m_renderConstellationLines);
199     settings.insert(QStringLiteral("renderConstellationLabels"), m_renderConstellationLabels);
200     settings.insert(QStringLiteral("renderDsos"), m_renderDsos);
201     settings.insert(QStringLiteral("renderDsoLabels"), m_renderDsoLabels);
202     settings.insert(QStringLiteral("renderSun"), m_renderSun);
203     settings.insert(QStringLiteral("renderMoon"), m_renderMoon);
204 
205     QStringList planetState;
206     for (const QString &key: m_renderPlanet.keys())
207         planetState += key + QLatin1Char(':') + QString::number((int)m_renderPlanet[key]);
208     settings.insert(QStringLiteral("renderPlanet"), planetState.join(QLatin1Char('|')));
209 
210     settings.insert(QStringLiteral("renderEcliptic"), m_renderEcliptic);
211     settings.insert(QStringLiteral("renderCelestialEquator"), m_renderCelestialEquator);
212     settings.insert(QStringLiteral("renderCelestialPole"), m_renderCelestialPole);
213     settings.insert(QStringLiteral("zoomSunMoon"), m_zoomSunMoon);
214     settings.insert(QStringLiteral("viewSolarSystemLabel"), m_viewSolarSystemLabel);
215     settings.insert(QStringLiteral("magnitudeLimit"), m_magnitudeLimit);
216     settings.insert(QStringLiteral("constellationBrush"), m_constellationBrush.color().rgb());
217     settings.insert(QStringLiteral("constellationLabelBrush"), m_constellationLabelBrush.color().rgb());
218     settings.insert(QStringLiteral("dsoLabelBrush"), m_dsoLabelBrush.color().rgb());
219     settings.insert(QStringLiteral("eclipticBrush"), m_eclipticBrush.color().rgb());
220     settings.insert(QStringLiteral("celestialEaquatorBrush"), m_celestialEquatorBrush.color().rgb());
221     settings.insert(QStringLiteral("celestialPoleBrush"), m_celestialPoleBrush.color().rgb());
222 
223     return settings;
224 }
225 
setSettings(const QHash<QString,QVariant> & settings)226 void StarsPlugin::setSettings( const QHash<QString, QVariant> &settings )
227 {
228     RenderPlugin::setSettings( settings );
229 
230     m_nameIndex = readSetting<int>(settings, QStringLiteral("nameIndex"), 0);
231     m_renderStars = readSetting<bool>(settings, QStringLiteral("renderStars"), true);
232     m_renderConstellationLines = readSetting<bool>(settings, QStringLiteral("renderConstellationLines"), true);
233     m_renderConstellationLabels = readSetting<bool>(settings, QStringLiteral("renderConstellationLabels"), true);
234     m_renderDsos = readSetting<bool>(settings, QStringLiteral("renderDsos"), true);
235     m_renderDsoLabels = readSetting<bool>(settings, QStringLiteral("renderDsoLabels"), true);
236     m_renderSun = readSetting<bool>(settings, QStringLiteral("renderSun"), true);
237     m_renderMoon = readSetting<bool>(settings, QStringLiteral("renderMoon"), true);
238 
239     m_renderPlanet.clear();
240     const QString renderPlanet = readSetting<QString>(settings, QStringLiteral("renderPlanet"), QString());
241     const QStringList renderStates = renderPlanet.split(QLatin1Char('|'));
242     for(const QString &state: renderStates) {
243         const QStringList stateList = state.split(QLatin1Char(':'));
244         if (stateList.size() == 2)
245             m_renderPlanet[stateList[0]] = (bool)stateList[1].toInt();
246     }
247 
248     m_renderEcliptic = readSetting<bool>(settings, QStringLiteral("renderEcliptic"), true);
249     m_renderCelestialEquator = readSetting<bool>(settings, QStringLiteral("renderCelestialEquator"), true);
250     m_renderCelestialPole = readSetting<bool>(settings, QStringLiteral("renderCelestialPole"), true);
251     m_zoomSunMoon = readSetting<bool>(settings, QStringLiteral("zoomSunMoon"), true);
252     m_viewSolarSystemLabel = readSetting<bool>(settings, QStringLiteral("viewSolarSystemLabel"), true);
253     m_magnitudeLimit = readSetting<int>(settings, QStringLiteral("magnitudeLimit"), 100);
254     QColor const defaultColor = Marble::Oxygen::aluminumGray5;
255     m_constellationBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("constellationBrush"), defaultColor.rgb()));
256     m_constellationLabelBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("constellationLabelBrush"), defaultColor.rgb()));
257     m_dsoLabelBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("dsoLabelBrush"), defaultColor.rgb()));
258     m_eclipticBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("eclipticBrush"), defaultColor.rgb()));
259     m_celestialEquatorBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("celestialEquatorBrush"), defaultColor.rgb()));
260     m_celestialPoleBrush = QColor(readSetting<QRgb>(settings, QStringLiteral("celestialPoleBrush"), defaultColor.rgb()));
261 }
262 
starPixmap(qreal mag,int colorId) const263 QPixmap StarsPlugin::starPixmap(qreal mag, int colorId) const
264 {
265    if ( mag < -1 ) {
266        return m_pixN1Stars.at(colorId);
267    } else if ( mag < 0 ) {
268        return m_pixP0Stars.at(colorId);
269    } else if ( mag < 1 ) {
270        return m_pixP1Stars.at(colorId);
271    } else if ( mag < 2 ) {
272        return m_pixP2Stars.at(colorId);
273    } else if ( mag < 3 ) {
274        return m_pixP3Stars.at(colorId);
275    } else if ( mag < 4 ) {
276        return m_pixP4Stars.at(colorId);
277    } else if ( mag < 5 ) {
278        return m_pixP5Stars.at(colorId);
279    } else if ( mag < 6 ) {
280        return m_pixP6Stars.at(colorId);
281    } else {
282        return m_pixP7Stars.at(colorId);
283    }
284 
285    return QPixmap();
286 }
287 
prepareNames()288 void StarsPlugin::prepareNames()
289 {
290 
291     QFile names(MarbleDirs::path(QStringLiteral("stars/names.csv")));
292     if ( !names.open( QIODevice::ReadOnly ) ) {
293         return;
294     }
295 
296     QTextStream in( &names );
297     while ( !in.atEnd() ) {
298         QString line = in.readLine();
299         const QStringList list = line.split(QLatin1Char(';'));
300         if ( list.size() == 3 ) {
301             m_nativeHash[ list.at( 0 ) ] = QCoreApplication::translate( "StarNames", list.at( 1 ).toUtf8().constData() );
302             m_abbrHash[ list.at( 0 ) ] = list.at( 2 );
303         }
304     }
305     names.close();
306 
307 }
308 
assembledConstellation(const QString & name)309 QString StarsPlugin::assembledConstellation(const QString &name)
310 {
311     switch (m_nameIndex) {
312     case 0:
313         return name;
314     case 1:
315         return m_nativeHash[name];
316     case 2:
317         return m_abbrHash[name];
318     default:
319         return name;
320     }
321 }
322 
readSettings()323 void StarsPlugin::readSettings()
324 {
325     if ( !m_configDialog ) {
326         return;
327     }
328 
329     ui_configWidget->constellationNamesComboBox->setCurrentIndex(m_nameIndex);
330 
331     Qt::CheckState const constellationLineState = m_renderConstellationLines ? Qt::Checked : Qt::Unchecked;
332     ui_configWidget->m_viewConstellationLinesCheckbox->setCheckState( constellationLineState );
333 
334     Qt::CheckState const constellationLabelState = m_renderConstellationLabels ? Qt::Checked : Qt::Unchecked;
335     ui_configWidget->m_viewConstellationLabelsCheckbox->setCheckState( constellationLabelState );
336 
337     Qt::CheckState const dsoState = m_renderDsos ? Qt::Checked : Qt::Unchecked;
338     ui_configWidget->m_viewDsosCheckbox->setCheckState( dsoState );
339 
340     Qt::CheckState const dsoLabelState = m_renderDsoLabels ? Qt::Checked : Qt::Unchecked;
341     ui_configWidget->m_viewDsoLabelCheckbox->setCheckState( dsoLabelState );
342 
343     Qt::CheckState const sunState = m_renderSun ? Qt::Checked : Qt::Unchecked;
344     ui_configWidget->m_solarSystemListWidget->item( 0 )->setCheckState( sunState );
345 
346     Qt::CheckState const moonState = m_renderMoon ? Qt::Checked : Qt::Unchecked;
347     ui_configWidget->m_solarSystemListWidget->item( 1 )->setCheckState( moonState );
348 
349     Qt::CheckState const mercuryState = m_renderPlanet["mercury"] ? Qt::Checked : Qt::Unchecked;
350     ui_configWidget->m_solarSystemListWidget->item( 2 )->setCheckState(mercuryState);
351 
352     Qt::CheckState const venusState = m_renderPlanet["venus"] ? Qt::Checked : Qt::Unchecked;
353     ui_configWidget->m_solarSystemListWidget->item( 3 )->setCheckState(venusState);
354 
355     Qt::CheckState const marsState = m_renderPlanet["mars"] ? Qt::Checked : Qt::Unchecked;
356     ui_configWidget->m_solarSystemListWidget->item( 5 )->setCheckState(marsState);
357 
358     Qt::CheckState const jupiterState = m_renderPlanet["jupiter"] ? Qt::Checked : Qt::Unchecked;
359     ui_configWidget->m_solarSystemListWidget->item( 6 )->setCheckState(jupiterState);
360 
361     Qt::CheckState const saturnState = m_renderPlanet["saturn"] ? Qt::Checked : Qt::Unchecked;
362     ui_configWidget->m_solarSystemListWidget->item( 7 )->setCheckState(saturnState);
363 
364     Qt::CheckState const uranusState = m_renderPlanet["uranus"] ? Qt::Checked : Qt::Unchecked;
365     ui_configWidget->m_solarSystemListWidget->item( 8 )->setCheckState(uranusState);
366 
367     Qt::CheckState const neptuneState = m_renderPlanet["neptune"] ? Qt::Checked : Qt::Unchecked;
368     ui_configWidget->m_solarSystemListWidget->item( 9 )->setCheckState(neptuneState);
369 
370     Qt::CheckState const eclipticState = m_renderEcliptic ? Qt::Checked : Qt::Unchecked;
371     ui_configWidget->m_viewEclipticCheckbox->setCheckState( eclipticState );
372 
373     Qt::CheckState const celestialEquatorState = m_renderCelestialEquator ? Qt::Checked : Qt::Unchecked;
374     ui_configWidget->m_viewCelestialEquatorCheckbox->setCheckState( celestialEquatorState );
375 
376     Qt::CheckState const celestialPoleState = m_renderCelestialPole ? Qt::Checked : Qt::Unchecked;
377     ui_configWidget->m_viewCelestialPoleCheckbox->setCheckState( celestialPoleState );
378 
379     Qt::CheckState const zoomSunMoonState = m_zoomSunMoon ? Qt::Checked : Qt::Unchecked;
380     ui_configWidget->m_zoomSunMoonCheckbox->setCheckState( zoomSunMoonState );
381 
382     Qt::CheckState const viewSolarSystemLabelState = m_viewSolarSystemLabel ? Qt::Checked : Qt::Unchecked;
383     ui_configWidget->m_viewSolarSystemLabelCheckbox->setCheckState( viewSolarSystemLabelState );
384 
385     int magState = m_magnitudeLimit;
386     if ( magState < ui_configWidget->m_magnitudeSlider->minimum() ) {
387         magState = ui_configWidget->m_magnitudeSlider->minimum();
388     }
389     else if ( magState > ui_configWidget->m_magnitudeSlider->maximum() ) {
390         magState = ui_configWidget->m_magnitudeSlider->maximum();
391     }
392 
393     ui_configWidget->m_magnitudeSlider->setValue(magState);
394 
395     QPalette constellationPalette;
396     constellationPalette.setColor( QPalette::Button, m_constellationBrush.color() );
397     ui_configWidget->m_constellationColorButton->setPalette( constellationPalette );
398 
399     QPalette constellationLabelPalette;
400     constellationLabelPalette.setColor( QPalette::Button, m_constellationLabelBrush.color() );
401     ui_configWidget->m_constellationLabelColorButton->setPalette( constellationLabelPalette );
402 
403     QPalette dsoLabelPalette;
404     dsoLabelPalette.setColor( QPalette::Button, m_dsoLabelBrush.color() );
405     ui_configWidget->m_dsoLabelColorButton->setPalette( dsoLabelPalette );
406 
407     QPalette eclipticPalette;
408     eclipticPalette.setColor( QPalette::Button, m_eclipticBrush.color() );
409     ui_configWidget->m_eclipticColorButton->setPalette( eclipticPalette );
410 
411     QPalette celestialEquatorPalette;
412     celestialEquatorPalette.setColor( QPalette::Button, m_celestialEquatorBrush.color() );
413     ui_configWidget->m_celestialEquatorColorButton->setPalette( celestialEquatorPalette );
414 
415     QPalette celestialPolePalette;
416     celestialPolePalette.setColor( QPalette::Button, m_celestialPoleBrush.color() );
417     ui_configWidget->m_celestialPoleColorButton->setPalette( celestialPolePalette );
418 
419 
420 }
421 
writeSettings()422 void StarsPlugin::writeSettings()
423 {
424     m_nameIndex = ui_configWidget->constellationNamesComboBox->currentIndex();
425     m_renderConstellationLines = ui_configWidget->m_viewConstellationLinesCheckbox->checkState() == Qt::Checked;
426     m_renderConstellationLabels = ui_configWidget->m_viewConstellationLabelsCheckbox->checkState() == Qt::Checked;
427     m_renderDsos = ui_configWidget->m_viewDsosCheckbox->checkState() == Qt::Checked;
428     m_renderDsoLabels = ui_configWidget->m_viewDsoLabelCheckbox->checkState() == Qt::Checked;
429     m_renderSun = ui_configWidget->m_solarSystemListWidget->item( 0 )->checkState() == Qt::Checked;
430     m_renderMoon = ui_configWidget->m_solarSystemListWidget->item( 1 )->checkState() == Qt::Checked;
431 
432     m_renderPlanet["mercury"] = ui_configWidget->m_solarSystemListWidget->item( 2 )->checkState()
433             == Qt::Checked;
434     m_renderPlanet["venus"] = ui_configWidget->m_solarSystemListWidget->item( 3 )->checkState()
435             == Qt::Checked;
436     m_renderPlanet["mars"] = ui_configWidget->m_solarSystemListWidget->item( 5 )->checkState()
437             == Qt::Checked;
438     m_renderPlanet["jupiter"] = ui_configWidget->m_solarSystemListWidget->item( 6 )->checkState()
439             == Qt::Checked;
440     m_renderPlanet["saturn"] = ui_configWidget->m_solarSystemListWidget->item( 7 )->checkState()
441             == Qt::Checked;
442     m_renderPlanet["uranus"] = ui_configWidget->m_solarSystemListWidget->item( 8 )->checkState()
443             == Qt::Checked;
444     m_renderPlanet["neptune"] = ui_configWidget->m_solarSystemListWidget->item( 9 )->checkState()
445             == Qt::Checked;
446 
447     m_renderEcliptic = ui_configWidget->m_viewEclipticCheckbox->checkState() == Qt::Checked;
448     m_renderCelestialEquator = ui_configWidget->m_viewCelestialEquatorCheckbox->checkState() == Qt::Checked;
449     m_renderCelestialPole = ui_configWidget->m_viewCelestialPoleCheckbox->checkState() == Qt::Checked;
450     m_zoomSunMoon = ui_configWidget->m_zoomSunMoonCheckbox->checkState() == Qt::Checked;
451     m_viewSolarSystemLabel = ui_configWidget->m_viewSolarSystemLabelCheckbox->checkState() == Qt::Checked;
452     m_magnitudeLimit = ui_configWidget->m_magnitudeSlider->value();
453     m_constellationBrush = QBrush( ui_configWidget->m_constellationColorButton->palette().color( QPalette::Button) );
454     m_constellationLabelBrush = QBrush( ui_configWidget->m_constellationLabelColorButton->palette().color( QPalette::Button) );
455     m_dsoLabelBrush = QBrush( ui_configWidget->m_dsoLabelColorButton->palette().color( QPalette::Button) );
456     m_eclipticBrush = QBrush( ui_configWidget->m_eclipticColorButton->palette().color( QPalette::Button) );
457     m_celestialEquatorBrush = QBrush( ui_configWidget->m_celestialEquatorColorButton->palette().color( QPalette::Button) );
458     m_celestialPoleBrush = QBrush( ui_configWidget->m_celestialPoleColorButton->palette().color( QPalette::Button) );
459     emit settingsChanged( nameId() );
460 }
461 
constellationGetColor()462 void StarsPlugin::constellationGetColor()
463 {
464     const QColor c = QColorDialog::getColor( m_constellationBrush.color(), nullptr, tr("Please choose the color for the constellation lines.") );
465 
466     if ( c.isValid() ) {
467         QPalette palette = ui_configWidget->m_constellationColorButton->palette();
468         palette.setColor( QPalette::Button, c );
469         ui_configWidget->m_constellationColorButton->setPalette( palette );
470     }
471 }
472 
constellationLabelGetColor()473 void StarsPlugin::constellationLabelGetColor()
474 {
475     const QColor c = QColorDialog::getColor( m_constellationLabelBrush.color(), nullptr, tr("Please choose the color for the constellation labels.") );
476 
477     if ( c.isValid() ) {
478         QPalette palette = ui_configWidget->m_constellationLabelColorButton->palette();
479         palette.setColor( QPalette::Button, c );
480         ui_configWidget->m_constellationLabelColorButton->setPalette( palette );
481     }
482 }
483 
dsoLabelGetColor()484 void StarsPlugin::dsoLabelGetColor()
485 {
486     const QColor c = QColorDialog::getColor( m_dsoLabelBrush.color(), nullptr, tr("Please choose the color for the dso labels.") );
487 
488     if ( c.isValid() ) {
489         QPalette palette = ui_configWidget->m_dsoLabelColorButton->palette();
490         palette.setColor( QPalette::Button, c );
491         ui_configWidget->m_dsoLabelColorButton->setPalette( palette );
492     }
493 }
494 
eclipticGetColor()495 void StarsPlugin::eclipticGetColor()
496 {
497     const QColor c = QColorDialog::getColor( m_eclipticBrush.color(), nullptr, tr("Please choose the color for the ecliptic.") );
498 
499     if ( c.isValid() ) {
500         QPalette palette = ui_configWidget->m_eclipticColorButton->palette();
501         palette.setColor( QPalette::Button, c );
502         ui_configWidget->m_eclipticColorButton->setPalette( palette );
503     }
504 }
505 
celestialEquatorGetColor()506 void StarsPlugin::celestialEquatorGetColor()
507 {
508     const QColor c = QColorDialog::getColor( m_celestialEquatorBrush.color(), nullptr, tr("Please choose the color for the celestial equator.") );
509 
510     if ( c.isValid() ) {
511         QPalette palette = ui_configWidget->m_celestialEquatorColorButton->palette();
512         palette.setColor( QPalette::Button, c );
513         ui_configWidget->m_celestialEquatorColorButton->setPalette( palette );
514     }
515 }
516 
celestialPoleGetColor()517 void StarsPlugin::celestialPoleGetColor()
518 {
519     const QColor c = QColorDialog::getColor( m_celestialPoleBrush.color(), nullptr, tr("Please choose the color for the celestial equator.") );
520 
521     if ( c.isValid() ) {
522         QPalette palette = ui_configWidget->m_celestialPoleColorButton->palette();
523         palette.setColor( QPalette::Button, c );
524         ui_configWidget->m_celestialPoleColorButton->setPalette( palette );
525     }
526 }
527 
loadStars()528 void StarsPlugin::loadStars()
529 {
530     //mDebug() << Q_FUNC_INFO;
531     // Load star data
532     m_stars.clear();
533 
534     QFile starFile(MarbleDirs::path(QStringLiteral("stars/stars.dat")));
535     starFile.open( QIODevice::ReadOnly );
536     QDataStream in( &starFile );
537 
538     // Read and check the header
539     quint32 magic;
540     in >> magic;
541     if ( magic != 0x73746172 ) {
542         return;
543     }
544 
545     // Read the version
546     qint32 version;
547     in >> version;
548     if ( version > 004 ) {
549         mDebug() << "stars.dat: file too new.";
550         return;
551     }
552 
553     if ( version == 003 ) {
554         mDebug() << "stars.dat: file version no longer supported.";
555         return;
556     }
557 
558     int maxid = 0;
559     int id = 0;
560     int starIndex = 0;
561     double ra;
562     double de;
563     double mag;
564     int colorId = 2;
565 
566     mDebug() << "Star Catalog Version " << version;
567 
568     while ( !in.atEnd() ) {
569         if ( version >= 2 ) {
570             in >> id;
571         }
572         if ( id > maxid ) {
573             maxid = id;
574         }
575         in >> ra;
576         in >> de;
577         in >> mag;
578 
579         if ( version >= 4 ) {
580             in >> colorId;
581         }
582 
583         StarPoint star( id, ( qreal )( ra ), ( qreal )( de ), ( qreal )( mag ), colorId );
584         // Create entry in stars database
585         m_stars << star;
586         // Create key,value pair in idHash table to map from star id to
587         // index in star database vector
588         m_idHash[id] = starIndex;
589         // Increment Index for use in hash
590         ++starIndex;
591     }
592 
593     // load the Sun pixmap
594     // TODO: adjust pixmap size according to distance
595     m_pixmapSun.load(MarbleDirs::path(QStringLiteral("svg/sun.png")));
596     m_pixmapMoon.load(MarbleDirs::path(QStringLiteral("svg/moon.png")));
597 
598     m_starsLoaded = true;
599 }
600 
createStarPixmaps()601 void StarsPlugin::createStarPixmaps()
602 {
603     // Load star pixmaps
604     QVector<QPixmap> pixBigStars;
605     pixBigStars.clear();
606     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_blue.png"))));
607     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_bluewhite.png"))));
608     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_white.png"))));
609     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_yellow.png"))));
610     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_orange.png"))));
611     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_red.png"))));
612     pixBigStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_0_garnetred.png"))));
613 
614     QVector<QPixmap> pixSmallStars;
615     pixSmallStars.clear();
616     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_blue.png"))));
617     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_bluewhite.png"))));
618     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_white.png"))));
619     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_yellow.png"))));
620     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_orange.png"))));
621     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_red.png"))));
622     pixSmallStars.append(QPixmap(MarbleDirs::path(QStringLiteral("bitmaps/stars/star_3_garnetred.png"))));
623 
624 
625     // Pre-Scale Star Pixmaps
626     m_pixN1Stars.clear();
627     for ( int p=0; p < pixBigStars.size(); ++p) {
628         int width = 1.0*pixBigStars.at(p).width();
629         m_pixN1Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
630     }
631 
632     m_pixP0Stars.clear();
633     for ( int p=0; p < pixBigStars.size(); ++p) {
634         int width = 0.90*pixBigStars.at(p).width();
635         m_pixP0Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
636     }
637 
638     m_pixP1Stars.clear();
639     for ( int p=0; p < pixBigStars.size(); ++p) {
640         int width = 0.80*pixBigStars.at(p).width();
641         m_pixP1Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
642     }
643 
644     m_pixP2Stars.clear();
645     for ( int p=0; p < pixBigStars.size(); ++p) {
646         int width = 0.70*pixBigStars.at(p).width();
647         m_pixP2Stars.append(pixBigStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
648     }
649 
650     m_pixP3Stars.clear();
651     for ( int p=0; p < pixSmallStars.size(); ++p) {
652         int width = 14;
653         m_pixP3Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
654     }
655 
656     m_pixP4Stars.clear();
657     for ( int p=0; p < pixSmallStars.size(); ++p) {
658         int width = 10;
659         m_pixP4Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
660     }
661 
662     m_pixP5Stars.clear();
663     for ( int p=0; p < pixSmallStars.size(); ++p) {
664         int width = 6;
665         m_pixP5Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
666     }
667 
668     m_pixP6Stars.clear();
669     for ( int p=0; p < pixSmallStars.size(); ++p) {
670         int width = 4;
671         m_pixP6Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
672     }
673 
674     m_pixP7Stars.clear();
675     for ( int p=0; p < pixSmallStars.size(); ++p) {
676         int width = 1;
677         m_pixP7Stars.append(pixSmallStars.at(p).scaledToWidth(width,Qt::SmoothTransformation));
678     }
679 
680     m_starPixmapsCreated = true;
681 }
682 
loadConstellations()683 void StarsPlugin::loadConstellations()
684 {
685     // Load star data
686     m_constellations.clear();
687 
688     QFile constellationFile(MarbleDirs::path(QStringLiteral("stars/constellations.dat")));
689     constellationFile.open( QIODevice::ReadOnly );
690     QTextStream in( &constellationFile );
691     QString line;
692     QString indexList;
693 
694     while ( !in.atEnd() ) {
695         line = in.readLine();
696 
697         // Check for null line at end of file
698         if ( line.isNull() ) {
699             continue;
700         }
701 
702         // Ignore Comment lines in header and
703         // between constellation entries
704         if (line.startsWith(QLatin1Char('#'))) {
705             continue;
706         }
707 
708         indexList = in.readLine();
709 
710         // Make sure we have a valid label and indexList
711         if ( indexList.isNull() ) {
712             break;
713         }
714 
715         Constellation constellation( this, line, indexList );
716         m_constellations << constellation;
717 
718     }
719     m_constellationsLoaded = true;
720 
721 }
722 
loadDsos()723 void StarsPlugin::loadDsos()
724 {
725     // Load star data
726     m_dsos.clear();
727 
728     QFile dsoFile(MarbleDirs::path(QStringLiteral("stars/dso.dat")));
729     dsoFile.open( QIODevice::ReadOnly );
730     QTextStream in( &dsoFile );
731     QString line;
732 
733     while ( !in.atEnd() ) {
734         line = in.readLine();
735 
736         // Check for null line at end of file
737         if ( line.isNull() ) {
738             continue;
739         }
740 
741         // Ignore Comment lines in header and
742         // between dso entries
743         if (line.startsWith(QLatin1Char('#'))) {
744             continue;
745         }
746 
747         QStringList entries = line.split( QLatin1Char( ',' ) );
748 
749         QString id = entries.at( 0 );
750 
751         double raH = entries.at( 1 ).toDouble();
752         double raM = entries.at( 2 ).toDouble();
753         double raS = entries.at( 3 ).toDouble();
754         double decD = entries.at( 4 ).toDouble();
755         double decM = entries.at( 5 ).toDouble();
756         double decS = entries.at( 6 ).toDouble();
757 
758         double raRad = ( raH+raM/60.0+raS/3600.0 )*15.0*M_PI/180.0;
759         double decRad;
760 
761         if ( decD >= 0.0 ) {
762             decRad = ( decD+decM/60.0+decS/3600.0 )*M_PI/180.0;
763         }
764         else {
765             decRad = ( decD-decM/60.0-decS/3600.0 )*M_PI/180.0;
766         }
767 
768         DsoPoint dso( id, ( qreal )( raRad ), ( qreal )( decRad ) );
769         // Create entry in stars database
770         m_dsos << dso;
771     }
772 
773     m_dsoImage.load(MarbleDirs::path(QStringLiteral("stars/deepsky.png")));
774     m_dsosLoaded = true;
775 }
776 
render(GeoPainter * painter,ViewportParams * viewport,const QString & renderPos,GeoSceneLayer * layer)777 bool StarsPlugin::render( GeoPainter *painter, ViewportParams *viewport,
778                           const QString& renderPos, GeoSceneLayer * layer )
779 {
780     Q_UNUSED( renderPos )
781     Q_UNUSED( layer )
782 
783     QString planetId = marbleModel()->planetId();
784     const bool doRender = !viewport->mapCoversViewport() &&
785                              ( (viewport->projection() == Spherical || viewport->projection() == VerticalPerspective) &&
786                              planetId == QLatin1String("earth")); // So far displaying stars is only supported on earth.
787 
788     if ( doRender != m_doRender ) {
789         if ( doRender ) {
790             connect( marbleModel()->clock(), SIGNAL(timeChanged()),
791                      this, SLOT(requestRepaint()) );
792         } else {
793             disconnect( marbleModel()->clock(), SIGNAL(timeChanged()),
794                         this, SLOT(requestRepaint()) );
795         }
796 
797         m_doRender = doRender;
798     }
799 
800     painter->save();
801 
802     SolarSystem sys;
803     QDateTime dateTime = marbleModel()->clock()->dateTime();
804     sys.setCurrentMJD(
805                 dateTime.date().year(), dateTime.date().month(), dateTime.date().day(),
806                 dateTime.time().hour(), dateTime.time().minute(),
807                 (double)dateTime.time().second());
808     QString const pname = planetId.at(0).toUpper() + planetId.right(planetId.size() - 1);
809     QByteArray name = pname.toLatin1();
810     sys.setCentralBody( name.data() );
811 
812     Vec3 skyVector = sys.getPlanetocentric (0.0, 0.0);
813     qreal skyRotationAngle = -atan2(skyVector[1], skyVector[0]);
814 
815     const qreal centerLon = viewport->centerLongitude();
816     const qreal centerLat = viewport->centerLatitude();
817 
818     const qreal  skyRadius      = 0.6 * sqrt( ( qreal )viewport->width() * viewport->width() + viewport->height() * viewport->height() );
819 
820     if ( doRender ) {
821         if (!m_starPixmapsCreated) {
822             createStarPixmaps();
823             m_starPixmapsCreated = true;
824         }
825 
826         // Delayed initialization:
827         // Load the star database only if the sky is actually being painted...
828         if ( !m_starsLoaded ) {
829             loadStars();
830             m_starsLoaded = true;
831         }
832 
833         if ( !m_constellationsLoaded ) {
834             loadConstellations();
835             m_constellationsLoaded = true;
836         }
837 
838         if ( !m_dsosLoaded ) {
839             loadDsos();
840             m_dsosLoaded = true;
841         }
842 
843         const qreal  earthRadius    = viewport->radius();
844 
845         // List of Pens used to draw the sky
846         QPen polesPen( m_celestialPoleBrush, 2, Qt::SolidLine );
847         QPen constellationPenSolid( m_constellationBrush, 1, Qt::SolidLine );
848         QPen constellationPenDash(  m_constellationBrush, 1, Qt::DashLine );
849         QPen constellationLabelPen( m_constellationLabelBrush, 1, Qt::SolidLine );
850         QPen eclipticPen( m_eclipticBrush, 1, Qt::DotLine );
851         QPen equatorPen( m_celestialEquatorBrush, 1, Qt::DotLine );
852         QPen dsoLabelPen (m_dsoLabelBrush, 1, Qt::SolidLine);
853 
854 
855         const Quaternion skyAxis = Quaternion::fromEuler( -centerLat , centerLon + skyRotationAngle, 0.0 );
856         matrix skyAxisMatrix;
857         skyAxis.inverse().toMatrix( skyAxisMatrix );
858 
859         if ( m_renderCelestialPole ) {
860 
861             polesPen.setWidth( 2 );
862             painter->setPen( polesPen );
863 
864             Quaternion qpos1;
865             qpos1 = Quaternion::fromSpherical( 0, 90 * DEG2RAD );
866             qpos1.rotateAroundAxis( skyAxisMatrix );
867 
868             if ( qpos1.v[Q_Z] < 0 ) {
869                 const int x1 = ( int )( viewport->width()  / 2 + skyRadius * qpos1.v[Q_X] );
870                 const int y1 = ( int )( viewport->height() / 2 - skyRadius * qpos1.v[Q_Y] );
871                 painter->drawLine( x1, y1, x1+10, y1 );
872                 painter->drawLine( x1+5, y1-5, x1+5, y1+5 );
873                 painter->drawText( x1+8, y1+12, "NP" );
874             }
875 
876             Quaternion qpos2;
877             qpos2 = Quaternion::fromSpherical( 0, -90 * DEG2RAD );
878             qpos2.rotateAroundAxis( skyAxisMatrix );
879             if ( qpos2.v[Q_Z] < 0 ) {
880                 const int x1 = ( int )( viewport->width()  / 2 + skyRadius * qpos2.v[Q_X] );
881                 const int y1 = ( int )( viewport->height() / 2 - skyRadius * qpos2.v[Q_Y] );
882                 painter->drawLine( x1, y1, x1+10, y1 );
883                 painter->drawLine( x1+5, y1-5, x1+5, y1+5 );
884                 painter->drawText( x1+8, y1+12, "SP" );
885             }
886         }
887 
888         if( m_renderEcliptic ) {
889             const Quaternion eclipticAxis = Quaternion::fromEuler( 0.0, 0.0, -marbleModel()->planet()->epsilon() );
890             matrix eclipticAxisMatrix;
891             (eclipticAxis * skyAxis).inverse().toMatrix( eclipticAxisMatrix );
892 
893             painter->setPen(eclipticPen);
894 
895             int previousX = -1;
896             int previousY = -1;
897             for ( int i = 0; i <= 36; ++i) {
898                 Quaternion qpos;
899                 qpos = Quaternion::fromSpherical( i * 10 * DEG2RAD, 0 );
900                 qpos.rotateAroundAxis( eclipticAxisMatrix );
901 
902                 int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
903                 int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
904 
905                 if ( qpos.v[Q_Z] < 0 && previousX >= 0 ) painter->drawLine(previousX, previousY, x, y);
906 
907                 previousX = x;
908                 previousY = y;
909             }
910         }
911 
912         if( m_renderCelestialEquator ) {
913             painter->setPen(equatorPen);
914 
915             int previousX = -1;
916             int previousY = -1;
917             for ( int i = 0; i <= 36; ++i) {
918                 Quaternion qpos;
919                 qpos = Quaternion::fromSpherical( i * 10 * DEG2RAD, 0 );
920                 qpos.rotateAroundAxis( skyAxisMatrix );
921 
922                 int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
923                 int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
924 
925                 if ( qpos.v[Q_Z] < 0 && previousX > 0 ) painter->drawLine(previousX, previousY, x, y);
926 
927                 previousX = x;
928                 previousY = y;
929             }
930         }
931 
932         if ( m_renderDsos ) {
933             painter->setPen(dsoLabelPen);
934             // Render Deep Space Objects
935             for ( int d = 0; d < m_dsos.size(); ++d ) {
936                 Quaternion qpos = m_dsos.at( d ).quaternion();
937                 qpos.rotateAroundAxis( skyAxisMatrix );
938 
939                 if ( qpos.v[Q_Z] > 0 ) {
940                     continue;
941                 }
942 
943                 qreal earthCenteredX = qpos.v[Q_X] * skyRadius;
944                 qreal earthCenteredY = qpos.v[Q_Y] * skyRadius;
945 
946                 // Don't draw high placemarks (e.g. satellites) that aren't visible.
947                 if ( qpos.v[Q_Z] < 0
948                         && ( ( earthCenteredX * earthCenteredX
949                                + earthCenteredY * earthCenteredY )
950                              < earthRadius * earthRadius ) ) {
951                     continue;
952                 }
953 
954                 // Let (x, y) be the position on the screen of the placemark..
955                 const int x = ( int )( viewport->width()  / 2 + skyRadius * qpos.v[Q_X] );
956                 const int y = ( int )( viewport->height() / 2 - skyRadius * qpos.v[Q_Y] );
957 
958                 // Skip placemarks that are outside the screen area
959                 if ( x < 0 || x >= viewport->width() ||
960                      y < 0 || y >= viewport->height() ) {
961                     continue;
962                 }
963 
964                 // Hard Code DSO Size for now
965                 qreal size = 20;
966 
967                 // Center Image on x,y location
968                 painter->drawImage( QRectF( x-size/2, y-size/2, size, size ),m_dsoImage );
969                 if (m_renderDsoLabels) {
970                     painter->drawText( x+8, y+12, m_dsos.at( d ).id() );
971                 }
972             }
973         }
974 
975         if ( m_renderConstellationLines ||  m_renderConstellationLabels )
976         {
977             // Render Constellations
978             for ( int c = 0; c < m_constellations.size(); ++c ) {
979                 int xMean = 0;
980                 int yMean = 0;
981                 int endptCount = 0;
982                 painter->setPen( constellationPenSolid );
983 
984                 for ( int s = 0; s < ( m_constellations.at( c ).size() - 1 ); ++s ) {
985                     int starId1 = m_constellations.at( c ).at( s );
986                     int starId2 = m_constellations.at( c ).at( s + 1 );
987 
988                     if ( starId1 == -1 || starId2 == -1 ) {
989                         // starId == -1 means we don't draw this segment
990                         continue;
991                     } else if ( starId1 == -2 || starId2 == -2 ) {
992                         painter->setPen( constellationPenDash );
993                     } else if ( starId1 == -3 || starId2 == -3 ) {
994                         painter->setPen( constellationPenSolid );
995                     }
996 
997                     int idx1 = m_idHash.value( starId1,-1 );
998                     int idx2 = m_idHash.value( starId2,-1 );
999 
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 
renderPlanet(const QString & planetId,GeoPainter * painter,SolarSystem & sys,ViewportParams * viewport,qreal skyRadius,matrix & skyAxisMatrix) const1257 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 
requestRepaint()1326 void StarsPlugin::requestRepaint()
1327 {
1328     emit repaintNeeded( QRegion() );
1329 }
1330 
toggleSunMoon(bool on)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 
toggleDsos(bool on)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 
toggleConstellations(bool on)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 
togglePlanets(bool on)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 
executeConfigDialog()1406 void StarsPlugin::executeConfigDialog()
1407 {
1408     QDialog *dialog = configDialog();
1409     Q_ASSERT( dialog );
1410     dialog->exec();
1411 }
1412 
eventFilter(QObject * object,QEvent * e)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"
1486