1 /*
2 * Stellarium
3 * Copyright (C) 2002 Fabien Chereau
4 * Copyright (C) 2010 Bogdan Marinov
5 * Copyright (C) 2011 Alexander Wolf
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
20 */
21
22 #include "SolarSystem.hpp"
23 #include "StelTexture.hpp"
24 #include "EphemWrapper.hpp"
25 #include "Orbit.hpp"
26
27 #include "StelProjector.hpp"
28 #include "StelApp.hpp"
29 #include "StelCore.hpp"
30 #include "StelTextureMgr.hpp"
31 #include "StelObjectMgr.hpp"
32 #include "StelLocaleMgr.hpp"
33 #include "StelSkyCultureMgr.hpp"
34 #include "StelFileMgr.hpp"
35 #include "StelModuleMgr.hpp"
36 #include "StelIniParser.hpp"
37 #include "Planet.hpp"
38 #include "MinorPlanet.hpp"
39 #include "Comet.hpp"
40 #include "StelMainView.hpp"
41
42 #include "StelSkyDrawer.hpp"
43 #include "StelUtils.hpp"
44 #include "StelPainter.hpp"
45 #include "TrailGroup.hpp"
46 #include "RefractionExtinction.hpp"
47
48 #include "AstroCalcDialog.hpp"
49 #include "StelObserver.hpp"
50
51 #include <functional>
52 #include <algorithm>
53
54 #include <QTextStream>
55 #include <QSettings>
56 #include <QVariant>
57 #include <QString>
58 #include <QStringList>
59 #include <QMap>
60 #include <QMultiMap>
61 #include <QMapIterator>
62 #include <QDebug>
63 #include <QDir>
64 #include <QHash>
65
SolarSystem()66 SolarSystem::SolarSystem() : StelObjectModule()
67 , shadowPlanetCount(0)
68 , earthShadowEnlargementDanjon(false)
69 , flagMoonScale(false)
70 , moonScale(1.0)
71 , flagMinorBodyScale(false)
72 , minorBodyScale(1.0)
73 , flagPlanetScale(false)
74 , planetScale(1.0)
75 , flagSunScale(false)
76 , sunScale(1.0)
77 , labelsAmount(false)
78 , flagPermanentSolarCorona(true)
79 , flagOrbits(false)
80 , flagLightTravelTime(true)
81 , flagUseObjModels(false)
82 , flagShowObjSelfShadows(true)
83 , flagShow(false)
84 , flagPointer(false)
85 , flagNativePlanetNames(false)
86 , flagIsolatedTrails(true)
87 , numberIsolatedTrails(0)
88 , maxTrailPoints(5000)
89 , maxTrailTimeExtent(1)
90 , trailsThickness(1)
91 , flagIsolatedOrbits(true)
92 , flagPlanetsOrbitsOnly(false)
93 , ephemerisMarkersDisplayed(true)
94 , ephemerisDatesDisplayed(false)
95 , ephemerisMagnitudesDisplayed(false)
96 , ephemerisHorizontalCoordinates(false)
97 , ephemerisLineDisplayed(false)
98 , ephemerisAlwaysOn(false)
99 , ephemerisLineThickness(1)
100 , ephemerisSkipDataDisplayed(false)
101 , ephemerisSkipMarkersDisplayed(false)
102 , ephemerisDataStep(1)
103 , ephemerisDataLimit(1)
104 , ephemerisSmartDatesDisplayed(true)
105 , ephemerisScaleMarkersDisplayed(false)
106 , ephemerisGenericMarkerColor(Vec3f(1.0f, 1.0f, 0.0f))
107 , ephemerisSecondaryMarkerColor(Vec3f(0.7f, 0.7f, 1.0f))
108 , ephemerisSelectedMarkerColor(Vec3f(1.0f, 0.7f, 0.0f))
109 , ephemerisMercuryMarkerColor(Vec3f(1.0f, 1.0f, 0.0f))
110 , ephemerisVenusMarkerColor(Vec3f(1.0f, 1.0f, 1.0f))
111 , ephemerisMarsMarkerColor(Vec3f(1.0f, 0.0f, 0.0f))
112 , ephemerisJupiterMarkerColor(Vec3f(0.3f, 1.0f, 1.0f))
113 , ephemerisSaturnMarkerColor(Vec3f(0.0f, 1.0f, 0.0f))
114 , allTrails(Q_NULLPTR)
115 , conf(StelApp::getInstance().getSettings())
116 {
117 planetNameFont.setPixelSize(StelApp::getInstance().getScreenFontSize());
118 connect(&StelApp::getInstance(), SIGNAL(screenFontSizeChanged(int)), this, SLOT(setFontSize(int)));
119 setObjectName("SolarSystem");
120 }
121
setFontSize(int newFontSize)122 void SolarSystem::setFontSize(int newFontSize)
123 {
124 planetNameFont.setPixelSize(newFontSize);
125 }
126
~SolarSystem()127 SolarSystem::~SolarSystem()
128 {
129 // release selected:
130 selected.clear();
131 selectedSSO.clear();
132 for (auto* orb : qAsConst(orbits))
133 {
134 delete orb;
135 orb = Q_NULLPTR;
136 }
137 sun.clear();
138 moon.clear();
139 earth.clear();
140 Planet::hintCircleTex.clear();
141 Planet::texEarthShadow.clear();
142
143 texEphemerisMarker.clear();
144 texEphemerisCometMarker.clear();
145 texPointer.clear();
146
147 delete allTrails;
148 allTrails = Q_NULLPTR;
149
150 // Get rid of circular reference between the shared pointers which prevent proper destruction of the Planet objects.
151 for (const auto& p : qAsConst(systemPlanets))
152 {
153 p->satellites.clear();
154 }
155
156 //delete comet textures created in loadPlanets
157 Comet::comaTexture.clear();
158 Comet::tailTexture.clear();
159
160 //deinit of SolarSystem is NOT called at app end automatically
161 deinit();
162 }
163
164 /*************************************************************************
165 Re-implementation of the getCallOrder method
166 *************************************************************************/
getCallOrder(StelModuleActionName actionName) const167 double SolarSystem::getCallOrder(StelModuleActionName actionName) const
168 {
169 if (actionName==StelModule::ActionDraw)
170 return StelApp::getInstance().getModuleMgr().getModule("StarMgr")->getCallOrder(actionName)+10;
171 return 0;
172 }
173
174 // Init and load the solar system data
init()175 void SolarSystem::init()
176 {
177 Q_ASSERT(conf);
178
179 Planet::init();
180 loadPlanets(); // Load planets data
181
182 // Compute position and matrix of sun and all the satellites (ie planets)
183 // for the first initialization Q_ASSERT that center is sun center (only impacts on light speed correction)
184 computePositions(StelApp::getInstance().getCore()->getJDE(), getSun());
185
186 setSelected(""); // Fix a bug on macosX! Thanks Fumio!
187 setFlagDrawMoonHalo(conf->value("viewing/flag_draw_moon_halo", true).toBool());
188 setFlagDrawSunHalo(conf->value("viewing/flag_draw_sun_halo", true).toBool());
189 setFlagMoonScale(conf->value("viewing/flag_moon_scaled", conf->value("viewing/flag_init_moon_scaled", false).toBool()).toBool()); // name change
190 setMoonScale(conf->value("viewing/moon_scale", 4.0).toDouble());
191 setMinorBodyScale(conf->value("viewing/minorbodies_scale", 10.0).toDouble());
192 setFlagMinorBodyScale(conf->value("viewing/flag_minorbodies_scaled", false).toBool());
193 setFlagPlanetScale(conf->value("viewing/flag_planets_scaled", false).toBool());
194 setPlanetScale(conf->value("viewing/planets_scale", 150.0).toDouble());
195 setFlagSunScale(conf->value("viewing/flag_sun_scaled", false).toBool());
196 setSunScale(conf->value("viewing/sun_scale", 4.0).toDouble());
197 setFlagPlanets(conf->value("astro/flag_planets").toBool());
198 setFlagHints(conf->value("astro/flag_planets_hints").toBool());
199 setFlagLabels(conf->value("astro/flag_planets_labels", true).toBool());
200 setLabelsAmount(conf->value("astro/labels_amount", 3.).toDouble());
201 setFlagOrbits(conf->value("astro/flag_planets_orbits").toBool());
202 setFlagLightTravelTime(conf->value("astro/flag_light_travel_time", true).toBool());
203 setFlagUseObjModels(conf->value("astro/flag_use_obj_models", false).toBool());
204 setFlagShowObjSelfShadows(conf->value("astro/flag_show_obj_self_shadows", true).toBool());
205 setFlagPointer(conf->value("astro/flag_planets_pointers", true).toBool());
206 // Set the algorithm from Astronomical Almanac for computation of apparent magnitudes for
207 // planets in case observer on the Earth by default
208 setApparentMagnitudeAlgorithmOnEarth(conf->value("astro/apparent_magnitude_algorithm", "Mallama2018").toString());
209 setFlagNativePlanetNames(conf->value("viewing/flag_planets_native_names", true).toBool());
210 // Is enabled the showing of isolated trails for selected objects only?
211 setFlagIsolatedTrails(conf->value("viewing/flag_isolated_trails", true).toBool());
212 setNumberIsolatedTrails(conf->value("viewing/number_isolated_trails", 1).toInt());
213 setMaxTrailPoints(conf->value("viewing/max_trail_points", 5000).toInt());
214 setMaxTrailTimeExtent(conf->value("viewing/max_trail_time_extent", 1).toInt());
215 setFlagIsolatedOrbits(conf->value("viewing/flag_isolated_orbits", true).toBool());
216 setFlagPlanetsOrbitsOnly(conf->value("viewing/flag_planets_orbits_only", false).toBool());
217 setFlagPermanentOrbits(conf->value("astro/flag_permanent_orbits", false).toBool());
218 setOrbitColorStyle(conf->value("astro/planets_orbits_color_style", "one_color").toString());
219
220 // Settings for calculation of position of Great Red Spot on Jupiter
221 setFlagCustomGrsSettings(conf->value("astro/flag_grs_custom", false).toBool());
222 setCustomGrsLongitude(conf->value("astro/grs_longitude", 216).toInt());
223 setCustomGrsDrift(conf->value("astro/grs_drift", 15.).toDouble());
224 setCustomGrsJD(conf->value("astro/grs_jd", 2456901.5).toDouble());
225
226 setFlagEarthShadowEnlargementDanjon(conf->value("astro/shadow_enlargement_danjon", false).toBool());
227 setFlagPermanentSolarCorona(conf->value("viewing/flag_draw_sun_corona", true).toBool());
228
229 // Load colors from config file
230 QString defaultColor = conf->value("color/default_color").toString();
231 setLabelsColor( Vec3f(conf->value("color/planet_names_color", defaultColor).toString()));
232 setOrbitsColor( Vec3f(conf->value("color/sso_orbits_color", defaultColor).toString()));
233 setMajorPlanetsOrbitsColor( Vec3f(conf->value("color/major_planet_orbits_color", "0.7,0.2,0.2").toString()));
234 setMoonsOrbitsColor( Vec3f(conf->value("color/moon_orbits_color", "0.7,0.2,0.2").toString()));
235 setMinorPlanetsOrbitsColor( Vec3f(conf->value("color/minor_planet_orbits_color", "0.7,0.5,0.5").toString()));
236 setDwarfPlanetsOrbitsColor( Vec3f(conf->value("color/dwarf_planet_orbits_color", "0.7,0.5,0.5").toString()));
237 setCubewanosOrbitsColor( Vec3f(conf->value("color/cubewano_orbits_color", "0.7,0.5,0.5").toString()));
238 setPlutinosOrbitsColor( Vec3f(conf->value("color/plutino_orbits_color", "0.7,0.5,0.5").toString()));
239 setScatteredDiskObjectsOrbitsColor(Vec3f(conf->value("color/sdo_orbits_color", "0.7,0.5,0.5").toString()));
240 setOortCloudObjectsOrbitsColor( Vec3f(conf->value("color/oco_orbits_color", "0.7,0.5,0.5").toString()));
241 setCometsOrbitsColor( Vec3f(conf->value("color/comet_orbits_color", "0.7,0.8,0.8").toString()));
242 setSednoidsOrbitsColor( Vec3f(conf->value("color/sednoid_orbits_color", "0.7,0.5,0.5").toString()));
243 setInterstellarOrbitsColor( Vec3f(conf->value("color/interstellar_orbits_color", "1.0,0.6,1.0").toString()));
244 setMercuryOrbitColor( Vec3f(conf->value("color/mercury_orbit_color", "0.5,0.5,0.5").toString()));
245 setVenusOrbitColor( Vec3f(conf->value("color/venus_orbit_color", "0.9,0.9,0.7").toString()));
246 setEarthOrbitColor( Vec3f(conf->value("color/earth_orbit_color", "0.0,0.0,1.0").toString()));
247 setMarsOrbitColor( Vec3f(conf->value("color/mars_orbit_color", "0.8,0.4,0.1").toString()));
248 setJupiterOrbitColor( Vec3f(conf->value("color/jupiter_orbit_color", "1.0,0.6,0.0").toString()));
249 setSaturnOrbitColor( Vec3f(conf->value("color/saturn_orbit_color", "1.0,0.8,0.0").toString()));
250 setUranusOrbitColor( Vec3f(conf->value("color/uranus_orbit_color", "0.0,0.7,1.0").toString()));
251 setNeptuneOrbitColor( Vec3f(conf->value("color/neptune_orbit_color", "0.0,0.3,1.0").toString()));
252 setTrailsColor( Vec3f(conf->value("color/object_trails_color", defaultColor).toString()));
253 setPointerColor( Vec3f(conf->value("color/planet_pointers_color", "1.0,0.3,0.3").toString()));
254
255 // Ephemeris stuff
256 setFlagEphemerisMarkers(conf->value("astrocalc/flag_ephemeris_markers", true).toBool());
257 setFlagEphemerisAlwaysOn(conf->value("astrocalc/flag_ephemeris_alwayson", true).toBool());
258 setFlagEphemerisDates(conf->value("astrocalc/flag_ephemeris_dates", false).toBool());
259 setFlagEphemerisMagnitudes(conf->value("astrocalc/flag_ephemeris_magnitudes", false).toBool());
260 setFlagEphemerisHorizontalCoordinates(conf->value("astrocalc/flag_ephemeris_horizontal", false).toBool());
261 setFlagEphemerisLine(conf->value("astrocalc/flag_ephemeris_line", false).toBool());
262 setEphemerisLineThickness(conf->value("astrocalc/ephemeris_line_thickness", 1).toInt());
263 setFlagEphemerisSkipData(conf->value("astrocalc/flag_ephemeris_skip_data", false).toBool());
264 setFlagEphemerisSkipMarkers(conf->value("astrocalc/flag_ephemeris_skip_markers", false).toBool());
265 setEphemerisDataStep(conf->value("astrocalc/ephemeris_data_step", 1).toInt());
266 setFlagEphemerisSmartDates(conf->value("astrocalc/flag_ephemeris_smart_dates", true).toBool());
267 setFlagEphemerisScaleMarkers(conf->value("astrocalc/flag_ephemeris_scale_markers", false).toBool());
268 setEphemerisGenericMarkerColor( Vec3f(conf->value("color/ephemeris_generic_marker_color", "1.0,1.0,0.0").toString()));
269 setEphemerisSecondaryMarkerColor( Vec3f(conf->value("color/ephemeris_secondary_marker_color", "0.7,0.7,1.0").toString()));
270 setEphemerisSelectedMarkerColor(Vec3f(conf->value("color/ephemeris_selected_marker_color", "1.0,0.7,0.0").toString()));
271 setEphemerisMercuryMarkerColor( Vec3f(conf->value("color/ephemeris_mercury_marker_color", "1.0,1.0,0.0").toString()));
272 setEphemerisVenusMarkerColor( Vec3f(conf->value("color/ephemeris_venus_marker_color", "1.0,1.0,1.0").toString()));
273 setEphemerisMarsMarkerColor( Vec3f(conf->value("color/ephemeris_mars_marker_color", "1.0,0.0,0.0").toString()));
274 setEphemerisJupiterMarkerColor( Vec3f(conf->value("color/ephemeris_jupiter_marker_color", "0.3,1.0,1.0").toString()));
275 setEphemerisSaturnMarkerColor( Vec3f(conf->value("color/ephemeris_saturn_marker_color", "0.0,1.0,0.0").toString()));
276
277 setOrbitsThickness(conf->value("astro/object_orbits_thickness", 1).toBool());
278 setTrailsThickness(conf->value("astro/object_trails_thickness", 1).toBool());
279 recreateTrails();
280 setFlagTrails(conf->value("astro/flag_object_trails", false).toBool());
281
282 StelObjectMgr *objectManager = GETSTELMODULE(StelObjectMgr);
283 objectManager->registerStelObjectMgr(this);
284 connect(objectManager, SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)),
285 this, SLOT(selectedObjectChange(StelModule::StelModuleSelectAction)));
286
287 texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur4.png");
288 texEphemerisMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/disk.png");
289 texEphemerisCometMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/cometIcon.png");
290 Planet::hintCircleTex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/planet-indicator.png");
291
292 StelApp *app = &StelApp::getInstance();
293 connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
294 connect(&app->getSkyCultureMgr(), SIGNAL(currentSkyCultureChanged(QString)), this, SLOT(updateSkyCulture(QString)));
295 connect(&StelMainView::getInstance(), SIGNAL(reloadShadersRequested()), this, SLOT(reloadShaders()));
296 StelCore *core = app->getCore();
297 connect(core, SIGNAL(locationChanged(StelLocation)), this, SLOT(recreateTrails()));
298 connect(core, SIGNAL(dateChangedForTrails()), this, SLOT(recreateTrails()));
299
300 QString displayGroup = N_("Display Options");
301 addAction("actionShow_Planets", displayGroup, N_("Planets"), "planetsDisplayed", "P");
302 addAction("actionShow_Planets_Labels", displayGroup, N_("Planet labels"), "labelsDisplayed", "Alt+P");
303 addAction("actionShow_Planets_Orbits", displayGroup, N_("Planet orbits"), "flagOrbits", "O");
304 addAction("actionShow_Planets_Trails", displayGroup, N_("Planet trails"), "trailsDisplayed", "Shift+T");
305 addAction("actionShow_Planets_Trails_Reset", displayGroup, N_("Planet trails reset"), "recreateTrails()"); // No hotkey predefined.
306 //there is a small discrepancy in the GUI: "Show planet markers" actually means show planet hints
307 addAction("actionShow_Planets_Hints", displayGroup, N_("Planet markers"), "flagHints", "Ctrl+P");
308 addAction("actionShow_Planets_Pointers", displayGroup, N_("Planet selection marker"), "flagPointer", "Ctrl+Shift+P");
309 addAction("actionShow_Planets_EnlargeMoon", displayGroup, N_("Enlarge Moon"), "flagMoonScale");
310 addAction("actionShow_Planets_EnlargeMinor", displayGroup, N_("Enlarge minor bodies"), "flagMinorBodyScale");
311 addAction("actionShow_Planets_EnlargePlanets", displayGroup, N_("Enlarge Planets"), "flagPlanetScale");
312 addAction("actionShow_Planets_EnlargeSun", displayGroup, N_("Enlarge Sun"), "flagSunScale");
313 addAction("actionShow_Skyculture_NativePlanetNames", displayGroup, N_("Native planet names (from starlore)"), "flagNativePlanetNames", "Ctrl+Shift+N");
314
315 connect(StelApp::getInstance().getModule("HipsMgr"), SIGNAL(gotNewSurvey(HipsSurveyP)),
316 this, SLOT(onNewSurvey(HipsSurveyP)));
317
318 // Fill ephemeris dates
319 connect(this, SIGNAL(requestEphemerisVisualization()), this, SLOT(fillEphemerisDates()));
320 connect(this, SIGNAL(ephemerisDataStepChanged(int)), this, SLOT(fillEphemerisDates()));
321 connect(this, SIGNAL(ephemerisSkipDataChanged(bool)), this, SLOT(fillEphemerisDates()));
322 connect(this, SIGNAL(ephemerisSkipMarkersChanged(bool)), this, SLOT(fillEphemerisDates()));
323 connect(this, SIGNAL(ephemerisSmartDatesChanged(bool)), this, SLOT(fillEphemerisDates()));
324 }
325
deinit()326 void SolarSystem::deinit()
327 {
328 Planet::deinitShader();
329 Planet::deinitFBO();
330 }
331
resetTextures(const QString & planetName)332 void SolarSystem::resetTextures(const QString &planetName)
333 {
334 if (planetName.isEmpty())
335 {
336 for (const auto& p : qAsConst(systemPlanets))
337 {
338 p->resetTextures();
339 }
340 }
341 else
342 {
343 PlanetP planet = searchByEnglishName(planetName);
344 if (!planet.isNull())
345 planet->resetTextures();
346 }
347
348 }
349
setTextureForPlanet(const QString & planetName,const QString & texName)350 void SolarSystem::setTextureForPlanet(const QString& planetName, const QString& texName)
351 {
352 PlanetP planet = searchByEnglishName(planetName);
353 if (!planet.isNull())
354 planet->replaceTexture(texName);
355 else
356 qWarning() << "The planet" << planetName << "was not found. Please check the name.";
357 }
358
recreateTrails()359 void SolarSystem::recreateTrails()
360 {
361 // Create a trail group containing all the planets orbiting the sun (not including satellites)
362 if (allTrails!=Q_NULLPTR)
363 delete allTrails;
364 allTrails = new TrailGroup(maxTrailTimeExtent * 365.f, maxTrailPoints);
365
366 unsigned long cnt = static_cast<unsigned long>(selectedSSO.size());
367 if (cnt>0 && getFlagIsolatedTrails())
368 {
369 unsigned long limit = static_cast<unsigned long>(getNumberIsolatedTrails());
370 if (cnt<limit)
371 limit = cnt;
372 for (unsigned long i=0; i<limit; i++)
373 {
374 if (selectedSSO[cnt - i - 1]->getPlanetType() != Planet::isObserver)
375 allTrails->addObject(static_cast<QSharedPointer<StelObject>>(selectedSSO[cnt - i - 1]), &trailsColor);
376 }
377 }
378 else
379 {
380 for (const auto& p : getSun()->satellites)
381 {
382 if (p->getPlanetType() != Planet::isObserver)
383 allTrails->addObject(static_cast<QSharedPointer<StelObject>>(p), &trailsColor);
384 }
385 // Add moons of current planet
386 StelCore *core=StelApp::getInstance().getCore();
387 const StelObserver *obs=core->getCurrentObserver();
388 if (obs)
389 {
390 const QSharedPointer<Planet> planet=obs->getHomePlanet();
391 for (const auto& m : planet->satellites)
392 if (m->getPlanetType() != Planet::isObserver)
393 allTrails->addObject(static_cast<QSharedPointer<StelObject>>(m), &trailsColor);
394 }
395 }
396 }
397
398
updateSkyCulture(const QString & skyCultureDir)399 void SolarSystem::updateSkyCulture(const QString& skyCultureDir)
400 {
401 planetNativeNamesMap.clear();
402 planetNativeNamesMeaningMap.clear();
403
404 QString namesFile = StelFileMgr::findFile("skycultures/" + skyCultureDir + "/planet_names.fab");
405
406 if (namesFile.isEmpty())
407 {
408 for (const auto& p : qAsConst(systemPlanets))
409 {
410 if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
411 {
412 p->setNativeName("");
413 p->setNativeNameMeaning("");
414 }
415 }
416 updateI18n();
417 return;
418 }
419
420 // Open file
421 QFile planetNamesFile(namesFile);
422 if (!planetNamesFile.open(QIODevice::ReadOnly | QIODevice::Text))
423 {
424 qDebug() << " Cannot open file" << QDir::toNativeSeparators(namesFile);
425 return;
426 }
427
428 // Now parse the file
429 // lines to ignore which start with a # or are empty
430 QRegularExpression commentRx("^(\\s*#.*|\\s*)$");
431
432 // lines which look like records - we use the RE to extract the fields
433 // which will be available in recRx.capturedTexts()
434 QRegularExpression recRx("^\\s*(\\w+)\\s+\"(.+)\"\\s+_[(]\"(.+)\"[)]\\n");
435
436 QString record, planetId, nativeName, nativeNameMeaning;
437
438 // keep track of how many records we processed.
439 int totalRecords=0;
440 int readOk=0;
441 int lineNumber=0;
442 while (!planetNamesFile.atEnd())
443 {
444 record = QString::fromUtf8(planetNamesFile.readLine());
445 lineNumber++;
446
447 // Skip comments
448 if (commentRx.match(record).hasMatch())
449 continue;
450
451 totalRecords++;
452
453 QRegularExpressionMatch match=recRx.match(record);
454 if (!match.hasMatch())
455 {
456 qWarning() << "ERROR - cannot parse record at line" << lineNumber << "in planet names file" << QDir::toNativeSeparators(namesFile);
457 }
458 else
459 {
460 planetId = match.captured(1).trimmed();
461 nativeName = match.captured(2).trimmed();
462 nativeNameMeaning = match.captured(3).trimmed();
463 planetNativeNamesMap[planetId] = nativeName;
464 planetNativeNamesMeaningMap[planetId] = nativeNameMeaning;
465 readOk++;
466 }
467 }
468 planetNamesFile.close();
469 qDebug() << "Loaded" << readOk << "/" << totalRecords << "native names of planets";
470
471 for (const auto& p : qAsConst(systemPlanets))
472 {
473 if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
474 {
475 p->setNativeName(planetNativeNamesMap[p->getEnglishName()]);
476 p->setNativeNameMeaning(planetNativeNamesMeaningMap[p->getEnglishName()]);
477 }
478 }
479
480 updateI18n();
481 }
482
reloadShaders()483 void SolarSystem::reloadShaders()
484 {
485 Planet::deinitShader();
486 Planet::initShader();
487 }
488
drawPointer(const StelCore * core)489 void SolarSystem::drawPointer(const StelCore* core)
490 {
491 const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
492
493 const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet");
494 if (!newSelected.empty())
495 {
496 const StelObjectP obj = newSelected[0];
497 Vec3d pos=obj->getJ2000EquatorialPos(core);
498
499 Vec3d screenpos;
500 // Compute 2D pos and return if outside screen
501 if (!prj->project(pos, screenpos))
502 return;
503
504 StelPainter sPainter(prj);
505 sPainter.setColor(getPointerColor());
506
507 double size = obj->getAngularSize(core)*M_PI_180*prj->getPixelPerRadAtCenter()*2.;
508
509 const double scale = prj->getDevicePixelsPerPixel()*StelApp::getInstance().getGlobalScalingRatio();
510 size+= scale * (45. + 10.*std::sin(2. * StelApp::getInstance().getAnimationTime()));
511
512 texPointer->bind();
513
514 sPainter.setBlending(true);
515
516 size*=0.5;
517 const double angleBase = StelApp::getInstance().getAnimationTime() * 10;
518 // We draw 4 instances of the sprite at the corners of the pointer
519 for (int i = 0; i < 4; ++i)
520 {
521 const double angle = angleBase + i * 90;
522 const double x = screenpos[0] + size * cos(angle / 180 * M_PI);
523 const double y = screenpos[1] + size * sin(angle / 180 * M_PI);
524 sPainter.drawSprite2dMode(x, y, 10, angle);
525 }
526 }
527 }
528
keplerOrbitPosFunc(double jd,double xyz[3],double xyzdot[3],void * orbitPtr)529 void keplerOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
530 {
531 static_cast<KeplerOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
532 static_cast<KeplerOrbit*>(orbitPtr)->getVelocity(xyzdot);
533 }
534
gimbalOrbitPosFunc(double jd,double xyz[3],double xyzdot[3],void * orbitPtr)535 void gimbalOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
536 {
537 static_cast<GimbalOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
538 static_cast<GimbalOrbit*>(orbitPtr)->getVelocity(xyzdot);
539 }
540
541 // Init and load the solar system data (2 files)
loadPlanets()542 void SolarSystem::loadPlanets()
543 {
544 minorBodies.clear();
545 systemMinorBodies.clear();
546 qDebug() << "Loading Solar System data (1: planets and moons) ...";
547 QString solarSystemFile = StelFileMgr::findFile("data/ssystem_major.ini");
548 if (solarSystemFile.isEmpty())
549 {
550 qWarning() << "ERROR while loading ssystem_major.ini (unable to find data/ssystem_major.ini): " << StelUtils::getEndLineChar();
551 return;
552 }
553
554 if (!loadPlanets(solarSystemFile))
555 {
556 qWarning() << "ERROR while loading ssystem_major.ini: " << StelUtils::getEndLineChar();
557 return;
558 }
559
560 qDebug() << "Loading Solar System data (2: minor bodies)...";
561 QStringList solarSystemFiles = StelFileMgr::findFileInAllPaths("data/ssystem_minor.ini");
562 if (solarSystemFiles.isEmpty())
563 {
564 qWarning() << "ERROR while loading ssystem_minor.ini (unable to find data/ssystem_minor.ini): " << StelUtils::getEndLineChar();
565 return;
566 }
567
568 for (const auto& solarSystemFile : qAsConst(solarSystemFiles))
569 {
570 if (loadPlanets(solarSystemFile))
571 {
572 qDebug() << "File ssystem_minor.ini is loaded successfully...";
573 break;
574 }
575 else
576 {
577 // sun.clear();
578 // moon.clear();
579 // earth.clear();
580 //qCritical() << "We should not be here!";
581
582 qDebug() << "Removing minor bodies";
583 for (const auto& p : systemPlanets)
584 {
585 // We can only delete minor objects now!
586 if (p->pType >= Planet::isAsteroid)
587 {
588 p->satellites.clear();
589 }
590 }
591 systemPlanets.clear();
592 //Memory leak? What's the proper way of cleaning shared pointers?
593
594 // TODO: 0.16pre what about the orbits list?
595
596 //If the file is in the user data directory, rename it:
597 if (solarSystemFile.contains(StelFileMgr::getUserDir()))
598 {
599 QString newName = QString("%1/data/ssystem-%2.ini").arg(StelFileMgr::getUserDir()).arg(QDateTime::currentDateTime().toString("yyyyMMddThhmmss"));
600 if (QFile::rename(solarSystemFile, newName))
601 qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "has been renamed to" << QDir::toNativeSeparators(newName);
602 else
603 {
604 qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "cannot be removed!";
605 qWarning() << "Please either delete it, rename it or move it elsewhere.";
606 }
607 }
608 }
609 }
610
611 shadowPlanetCount = 0;
612
613 for (const auto& planet : qAsConst(systemPlanets))
614 if(planet->parent != sun || !planet->satellites.isEmpty())
615 shadowPlanetCount++;
616 }
617
BvToColorIndex(double bV)618 unsigned char SolarSystem::BvToColorIndex(double bV)
619 {
620 const double dBV = qBound(-500., static_cast<double>(bV)*1000.0, 3499.);
621 return static_cast<unsigned char>(floor(0.5+127.0*((500.0+dBV)/4000.0)));
622 }
623
loadPlanets(const QString & filePath)624 bool SolarSystem::loadPlanets(const QString& filePath)
625 {
626 StelSkyDrawer* skyDrawer = StelApp::getInstance().getCore()->getSkyDrawer();
627 qDebug() << "Loading from :" << filePath;
628 QSettings pd(filePath, StelIniFormat);
629 if (pd.status() != QSettings::NoError)
630 {
631 qWarning() << "ERROR while parsing" << QDir::toNativeSeparators(filePath);
632 return false;
633 }
634
635 // QSettings does not allow us to say that the sections of the file
636 // will be listed in the same order as in the file like the old
637 // InitParser used to so we can no longer assume that.
638 //
639 // This means we must first decide what order to read the sections
640 // of the file in (each section contains one planet/moon/asteroid/comet/...) to avoid setting
641 // the parent Planet* to one which has not yet been created.
642 //
643 // Stage 1: Make a map of body names back to the section names
644 // which they come from. Also make a map of body name to parent body
645 // name. These two maps can be made in a single pass through the
646 // sections of the file.
647 //
648 // Stage 2: Make an ordered list of section names such that each
649 // item is only ever dependent on items which appear earlier in the
650 // list.
651 // 2a: Make a QMultiMap relating the number of levels of dependency
652 // to the body name, i.e.
653 // 0 -> Sun
654 // 1 -> Mercury
655 // 1 -> Venus
656 // 1 -> Earth
657 // 2 -> Moon
658 // etc.
659 // 2b: Populate an ordered list of section names by iterating over
660 // the QMultiMap. This type of container is always sorted on the
661 // key in ascending order, so it's easy.
662 // i.e. [sun, earth, moon] is fine, but not [sun, moon, earth]
663 //
664 // Stage 3: iterate over the ordered sections decided in stage 2,
665 // creating the planet objects from the QSettings data.
666
667 // Stage 1 (as described above).
668 QMap<QString, QString> secNameMap;
669 QMap<QString, QString> parentMap;
670 QStringList sections = pd.childGroups();
671 // qDebug() << "Stage 1: load ini file with" << sections.size() << "entries: "<< sections;
672 for (int i=0; i<sections.size(); ++i)
673 {
674 const QString secname = sections.at(i);
675 const QString englishName = pd.value(secname+"/name").toString();
676 const QString strParent = pd.value(secname+"/parent", "Sun").toString();
677 secNameMap[englishName] = secname;
678 if (strParent!="none" && !strParent.isEmpty() && !englishName.isEmpty())
679 {
680 parentMap[englishName] = strParent;
681 // qDebug() << "parentmap[" << englishName << "] = " << strParent;
682 }
683 }
684
685 // Stage 2a (as described above).
686 QMultiMap<int, QString> depLevelMap;
687 for (int i=0; i<sections.size(); ++i)
688 {
689 const QString englishName = pd.value(sections.at(i)+"/name").toString();
690
691 // follow dependencies, incrementing level when we have one
692 // till we run out.
693 QString p=englishName;
694 int level = 0;
695 while(parentMap.contains(p) && parentMap[p]!="none")
696 {
697 level++;
698 p = parentMap[p];
699 }
700
701 depLevelMap.insert(level, secNameMap[englishName]);
702 // qDebug() << "2a: Level" << level << "secNameMap[" << englishName << "]="<< secNameMap[englishName];
703 }
704
705 // Stage 2b (as described above).
706 // qDebug() << "Stage 2b:";
707 QStringList orderedSections;
708 QMapIterator<int, QString> levelMapIt(depLevelMap);
709 while(levelMapIt.hasNext())
710 {
711 levelMapIt.next();
712 orderedSections << levelMapIt.value();
713 }
714 // qDebug() << orderedSections;
715
716 // Stage 3 (as described above).
717 int readOk=0;
718 //int totalPlanets=0;
719
720 // qDebug() << "Adding " << orderedSections.size() << "objects...";
721 for (int i = 0;i<orderedSections.size();++i)
722 {
723 // qDebug() << "Processing entry" << orderedSections.at(i);
724
725 //totalPlanets++;
726 const QString secname = orderedSections.at(i);
727 const QString englishName = pd.value(secname+"/name").toString().simplified();
728 const QString strParent = pd.value(secname+"/parent", "Sun").toString(); // Obvious default, keep file entries simple.
729 PlanetP parent;
730 if (strParent!="none")
731 {
732 // Look in the other planets the one named with strParent
733 for (const auto& p : qAsConst(systemPlanets))
734 {
735 if (p->getEnglishName()==strParent)
736 {
737 parent = p;
738 break;
739 }
740 }
741 if (parent.isNull())
742 {
743 qWarning() << "ERROR : can't find parent solar system body for " << englishName << ". Skipping.";
744 //abort();
745 continue;
746 }
747 }
748 Q_ASSERT(parent || englishName=="Sun");
749
750 const QString coordFuncName = pd.value(secname+"/coord_func", "kepler_orbit").toString(); // 0.20: new default for all non *_special.
751 // qDebug() << "englishName:" << englishName << ", parent:" << strParent << ", coord_func:" << coordFuncName;
752 posFuncType posfunc=Q_NULLPTR;
753 Orbit* orbitPtr=Q_NULLPTR;
754 OsculatingFunctType *osculatingFunc = Q_NULLPTR;
755 bool closeOrbit = true;
756 double semi_major_axis=0; // used again below.
757 const QString type = pd.value(secname+"/type").toString();
758
759
760 #ifdef USE_GIMBAL_ORBIT
761 // undefine the flag in Orbit.h to disable and use the old, static observer solution (on an infinitely slow KeplerOrbit)
762 // Note that for now we ignore any orbit-related config values from the ini file.
763 if (type=="observer")
764 {
765 // Create a pseudo orbit that allows interaction with keyboard
766 GimbalOrbit *orb = new GimbalOrbit(1, 0., 90.); // [1 AU over north pole]
767 orbits.push_back(orb);
768
769 orbitPtr = orb;
770 posfunc = &gimbalOrbitPosFunc;
771 }
772 else
773 #endif
774 if ((coordFuncName=="kepler_orbit") || (coordFuncName=="comet_orbit") || (coordFuncName=="ell_orbit")) // ell_orbit used for planet moons. TBD in V1.0: remove non-kepler_orbit!
775 {
776 // ell_orbit was used for planet moons, comet_orbit for minor bodies. The only difference is that pericenter distance for moons is given in km, not AU.
777 // Read the orbital elements
778 const double eccentricity = pd.value(secname+"/orbit_Eccentricity", 0.0).toDouble();
779 if (eccentricity >= 1.0) closeOrbit = false;
780 double pericenterDistance = pd.value(secname+"/orbit_PericenterDistance",-1e100).toDouble(); // AU, or km for ell_orbit!
781 if (pericenterDistance <= 0.0) {
782 semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis",-1e100).toDouble();
783 if (semi_major_axis <= -1e100) {
784 qDebug() << "ERROR loading " << englishName
785 << ": you must provide orbit_PericenterDistance or orbit_SemiMajorAxis. Skipping " << englishName;
786 continue;
787 } else {
788 Q_ASSERT(eccentricity != 1.0); // parabolic orbits have no semi_major_axis
789 pericenterDistance = semi_major_axis * (1.0-eccentricity);
790 }
791 } else {
792 semi_major_axis = (eccentricity == 1.0)
793 ? 0.0 // parabolic orbits have no semi_major_axis
794 : pericenterDistance / (1.0-eccentricity);
795 }
796 if (strParent!="Sun")
797 pericenterDistance /= AU; // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
798
799 double meanMotion = pd.value(secname+"/orbit_MeanMotion",-1e100).toDouble(); // degrees/day
800 if (meanMotion <= -1e100) {
801 const double period = pd.value(secname+"/orbit_Period",-1e100).toDouble();
802 if (period <= -1e100) {
803 if (parent->getParent()) {
804 qWarning() << "ERROR: " << englishName
805 << ": when the parent body is not the sun, you must provide "
806 << "either orbit_MeanMotion or orbit_Period";
807 } else {
808 // in case of parent=sun: use Gaussian gravitational constant for calculating meanMotion:
809 meanMotion = (eccentricity == 1.0)
810 ? 0.01720209895 * (1.5/pericenterDistance) * std::sqrt(0.5/pericenterDistance) // Heafner: Fund.Eph.Comp. W / dt
811 : 0.01720209895 / (fabs(semi_major_axis)*std::sqrt(fabs(semi_major_axis)));
812 }
813 } else {
814 meanMotion = 2.0*M_PI/period;
815 }
816 } else {
817 meanMotion *= (M_PI/180.0);
818 }
819
820 const double ascending_node = pd.value(secname+"/orbit_AscendingNode", 0.0).toDouble()*(M_PI/180.0);
821 double arg_of_pericenter = pd.value(secname+"/orbit_ArgOfPericenter",-1e100).toDouble();
822 double long_of_pericenter;
823 if (arg_of_pericenter <= -1e100) {
824 long_of_pericenter = pd.value(secname+"/orbit_LongOfPericenter", 0.0).toDouble()*(M_PI/180.0);
825 arg_of_pericenter = long_of_pericenter - ascending_node;
826 } else {
827 arg_of_pericenter *= (M_PI/180.0);
828 long_of_pericenter = arg_of_pericenter + ascending_node;
829 }
830
831 double time_at_pericenter = pd.value(secname+"/orbit_TimeAtPericenter",-1e100).toDouble();
832 // In earlier times (up to 0.21.2) we did not care much to store orbital epoch for comets but silently assumed T for it in various places.
833 // However, the distinction is relevant to discern element sets for various valid ranges.
834 // Comet orbits epoch should default to T while planets or moons default to J2000.
835 const double epoch = pd.value(secname+"/orbit_Epoch", type=="comet" ? time_at_pericenter : J2000).toDouble();
836 if (time_at_pericenter <= -1e100) {
837 double mean_anomaly = pd.value(secname+"/orbit_MeanAnomaly",-1e100).toDouble()*(M_PI/180.0);
838 if (mean_anomaly <= -1e10) {
839 double mean_longitude = pd.value(secname+"/orbit_MeanLongitude",-1e100).toDouble()*(M_PI/180.0);
840 if (mean_longitude <= -1e10) {
841 qWarning() << "ERROR: " << englishName
842 << ": when you do not provide orbit_TimeAtPericenter, you must provide orbit_Epoch"
843 << "and either one of orbit_MeanAnomaly or orbit_MeanLongitude. Skipping this object.";
844 //abort();
845 continue;
846 } else {
847 mean_anomaly = mean_longitude - long_of_pericenter;
848 }
849 }
850 time_at_pericenter = epoch - mean_anomaly / meanMotion;
851 }
852
853 static const QMap<QString, double>massMap={ // masses from DE430/431
854 { "Sun", 1.0},
855 { "Mercury", 6023682.155592},
856 { "Venus", 408523.718658},
857 { "Earth", 332946.048834},
858 { "Mars", 3098703.590291},
859 { "Jupiter", 1047.348625},
860 { "Saturn", 3497.901768},
861 { "Uranus", 22902.981613},
862 { "Neptune", 19412.259776},
863 { "Pluto", 135836683.768617}};
864
865 // Construct orbital elements relative to the parent body. This will construct orbits for J2000 only.
866 // Some planet axes move very slowly, this effect could be modelled by replicating these lines
867 // after recomputing obliquity and node (below) in Planet::computeTransMatrix().
868 // The effect is negligible for several millennia, though.
869 // When the parent is the sun use ecliptic rather than sun equator:
870 const double parentRotObliquity = parent->getParent() ? parent->getRotObliquity(J2000) : 0.0;
871 const double parent_rot_asc_node = parent->getParent() ? parent->getRotAscendingNode() : 0.0;
872 double parent_rot_j2000_longitude = 0.0;
873 if (parent->getParent()) {
874 const double c_obl = cos(parentRotObliquity);
875 const double s_obl = sin(parentRotObliquity);
876 const double c_nod = cos(parent_rot_asc_node);
877 const double s_nod = sin(parent_rot_asc_node);
878 const Vec3d OrbitAxis0( c_nod, s_nod, 0.0);
879 const Vec3d OrbitAxis1(-s_nod*c_obl, c_nod*c_obl,s_obl);
880 const Vec3d OrbitPole( s_nod*s_obl,-c_nod*s_obl,c_obl);
881 const Vec3d J2000Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(Vec3d(0,0,1)));
882 Vec3d J2000NodeOrigin(J2000Pole^OrbitPole);
883 J2000NodeOrigin.normalize();
884 parent_rot_j2000_longitude = atan2(J2000NodeOrigin*OrbitAxis1,J2000NodeOrigin*OrbitAxis0);
885 }
886
887 const double orbitGoodDays=pd.value(secname+"/orbit_good", parent->englishName!="Sun" ? 0. : -1.).toDouble(); // "Moons" have permanently good orbits.
888 const double inclination = pd.value(secname+"/orbit_Inclination", 0.0).toDouble()*(M_PI/180.0);
889
890 // Create a Keplerian orbit. This has been called CometOrbit before 0.20.
891 //qDebug() << "Creating KeplerOrbit for" << parent->englishName << "---" << englishName;
892 KeplerOrbit *orb = new KeplerOrbit(epoch, // JDE
893 pericenterDistance, // [AU]
894 eccentricity, // 0..>1 (>>1 for Interstellar objects)
895 inclination, // [radians]
896 ascending_node, // [radians]
897 arg_of_pericenter, // [radians]
898 time_at_pericenter, // JDE
899 orbitGoodDays, // orbitGoodDays. 0=always good, -1=compute_half_orbit_duration
900 meanMotion, // [radians/day]
901 parentRotObliquity, // [radians]
902 parent_rot_asc_node, // [radians]
903 parent_rot_j2000_longitude, // [radians]
904 1./massMap.value(parent->englishName, 1.)); // central mass [solar masses]
905 orbits.push_back(orb);
906
907 orbitPtr = orb;
908 posfunc = &keplerOrbitPosFunc;
909 }
910 else
911 {
912 static const QMap<QString, posFuncType>posfuncMap={
913 { "sun_special", &get_sun_helio_coordsv},
914 { "mercury_special", &get_mercury_helio_coordsv},
915 { "venus_special", &get_venus_helio_coordsv},
916 { "earth_special", &get_earth_helio_coordsv},
917 { "lunar_special", &get_lunar_parent_coordsv},
918 { "mars_special", &get_mars_helio_coordsv},
919 { "phobos_special", &get_phobos_parent_coordsv},
920 { "deimos_special", &get_deimos_parent_coordsv},
921 { "jupiter_special", &get_jupiter_helio_coordsv},
922 { "io_special", &get_io_parent_coordsv},
923 { "europa_special", &get_europa_parent_coordsv},
924 { "ganymede_special", &get_ganymede_parent_coordsv},
925 { "calisto_special", &get_callisto_parent_coordsv},
926 { "callisto_special", &get_callisto_parent_coordsv},
927 { "saturn_special", &get_saturn_helio_coordsv},
928 { "mimas_special", &get_mimas_parent_coordsv},
929 { "enceladus_special", &get_enceladus_parent_coordsv},
930 { "tethys_special", &get_tethys_parent_coordsv},
931 { "dione_special", &get_dione_parent_coordsv},
932 { "rhea_special", &get_rhea_parent_coordsv},
933 { "titan_special", &get_titan_parent_coordsv},
934 { "hyperion_special", &get_hyperion_parent_coordsv},
935 { "iapetus_special", &get_iapetus_parent_coordsv},
936 { "helene_special", &get_helene_parent_coordsv},
937 { "telesto_special", &get_telesto_parent_coordsv},
938 { "calypso_special", &get_calypso_parent_coordsv},
939 { "uranus_special", &get_uranus_helio_coordsv},
940 { "miranda_special", &get_miranda_parent_coordsv},
941 { "ariel_special", &get_ariel_parent_coordsv},
942 { "umbriel_special", &get_umbriel_parent_coordsv},
943 { "titania_special", &get_titania_parent_coordsv},
944 { "oberon_special", &get_oberon_parent_coordsv},
945 { "neptune_special", &get_neptune_helio_coordsv},
946 { "pluto_special", &get_pluto_helio_coordsv}};
947 static const QMap<QString, OsculatingFunctType*>osculatingMap={
948 { "mercury_special", &get_mercury_helio_osculating_coords},
949 { "venus_special", &get_venus_helio_osculating_coords},
950 { "earth_special", &get_earth_helio_osculating_coords},
951 { "mars_special", &get_mars_helio_osculating_coords},
952 { "jupiter_special", &get_jupiter_helio_osculating_coords},
953 { "saturn_special", &get_saturn_helio_osculating_coords},
954 { "uranus_special", &get_uranus_helio_osculating_coords},
955 { "neptune_special", &get_neptune_helio_osculating_coords}};
956 posfunc=posfuncMap.value(coordFuncName, Q_NULLPTR);
957 osculatingFunc=osculatingMap.value(coordFuncName, Q_NULLPTR);
958 }
959 if (posfunc==Q_NULLPTR)
960 {
961 qCritical() << "ERROR in section " << secname << ": can't find posfunc " << coordFuncName << " for " << englishName;
962 exit(-1);
963 }
964
965 // Create the Solar System body and add it to the list
966 //TODO: Refactor the subclass selection to reduce duplicate code mess here,
967 // by at least using this base class pointer and using setXXX functions instead of mega-constructors
968 // that have to pass most of it on to the Planet class
969 PlanetP newP;
970
971 // New class objects, named "plutino", "cubewano", "dwarf planet", "SDO", "OCO", has properties
972 // similar to asteroids and we should calculate their positions like for asteroids. Dwarf planets
973 // have one exception: Pluto - as long as we use a special function for calculation of Pluto's orbit.
974 if ((type == "asteroid" || type == "dwarf planet" || type == "cubewano" || type=="sednoid" || type == "plutino" || type == "scattered disc object" || type == "Oort cloud object" || type == "interstellar object") && !englishName.contains("Pluto"))
975 {
976 minorBodies << englishName;
977
978 Vec3f color = Vec3f(1.f, 1.f, 1.f);
979 const float bV = pd.value(secname+"/color_index_bv", 99.f).toFloat();
980 if (bV<99.f)
981 color = skyDrawer->indexToColor(BvToColorIndex(bV))*0.75f; // see ZoneArray.cpp:L490
982 else
983 color = Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString());
984
985 const bool hidden = pd.value(secname+"/hidden", false).toBool();
986 const QString normalMapName = ( hidden ? "" : englishName.toLower().append("_normals.png")); // no normal maps for invisible objects!
987
988 newP = PlanetP(new MinorPlanet(englishName,
989 pd.value(secname+"/radius", 1.0).toDouble()/AU,
990 pd.value(secname+"/oblateness", 0.0).toDouble(),
991 color, // halo color
992 pd.value(secname+"/albedo", 0.25f).toFloat(),
993 pd.value(secname+"/roughness",0.9f).toFloat(),
994 pd.value(secname+"/tex_map", "nomap.png").toString(),
995 pd.value(secname+"/normals_map", normalMapName).toString(),
996 pd.value(secname+"/model").toString(),
997 posfunc,
998 static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object created previously
999 osculatingFunc, // should be Q_NULLPTR
1000 closeOrbit,
1001 hidden,
1002 type));
1003 QSharedPointer<MinorPlanet> mp = newP.dynamicCast<MinorPlanet>();
1004 //Number, Provisional designation
1005 mp->setMinorPlanetNumber(pd.value(secname+"/minor_planet_number", 0).toInt());
1006 mp->setProvisionalDesignation(pd.value(secname+"/provisional_designation", "").toString());
1007
1008 //H-G magnitude system
1009 const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
1010 const float slope = pd.value(secname+"/slope_parameter", 0.15f).toFloat();
1011 if (magnitude > -99.f)
1012 {
1013 mp->setAbsoluteMagnitudeAndSlope(magnitude, qBound(0.0f, slope, 1.0f));
1014 }
1015
1016 mp->setColorIndexBV(bV);
1017 mp->setSpectralType(pd.value(secname+"/spec_t", "").toString(), pd.value(secname+"/spec_b", "").toString());
1018 if (semi_major_axis>0)
1019 mp->deltaJDE = 2.0*semi_major_axis*StelCore::JD_SECOND;
1020 else if ((semi_major_axis<=0.0) && (type!="interstellar object"))
1021 qWarning() << "WARNING: Minor Body" << englishName << "has no semimajor axis!";
1022
1023 systemMinorBodies.push_back(newP);
1024 }
1025 else if (type == "comet")
1026 {
1027 minorBodies << englishName;
1028 newP = PlanetP(new Comet(englishName,
1029 pd.value(secname+"/radius", 1.0).toDouble()/AU,
1030 pd.value(secname+"/oblateness", 0.0).toDouble(),
1031 Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
1032 pd.value(secname+"/albedo", 0.075f).toFloat(), // assume very dark surface
1033 pd.value(secname+"/roughness",0.9f).toFloat(),
1034 pd.value(secname+"/outgas_intensity",0.1f).toFloat(),
1035 pd.value(secname+"/outgas_falloff", 0.1f).toFloat(),
1036 pd.value(secname+"/tex_map", "nomap.png").toString(),
1037 pd.value(secname+"/model").toString(),
1038 posfunc,
1039 static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object
1040 osculatingFunc, // ALWAYS NULL for comets.
1041 closeOrbit,
1042 pd.value(secname+"/hidden", false).toBool(),
1043 type,
1044 pd.value(secname+"/dust_widthfactor", 1.5f).toFloat(),
1045 pd.value(secname+"/dust_lengthfactor", 0.4f).toFloat(),
1046 pd.value(secname+"/dust_brightnessfactor", 1.5f).toFloat()
1047 ));
1048 QSharedPointer<Comet> mp = newP.dynamicCast<Comet>();
1049
1050 //g,k magnitude system
1051 const float magnitude = pd.value(secname+"/absolute_magnitude", -99).toFloat();
1052 const float slope = qBound(-5.0f, pd.value(secname+"/slope_parameter", 4.0f).toFloat(), 30.0f);
1053 if (magnitude > -99)
1054 {
1055 mp->setAbsoluteMagnitudeAndSlope(magnitude, slope);
1056 }
1057
1058 systemMinorBodies.push_back(newP);
1059 }
1060 else // type==star|planet|moon|dwarf planet|observer|artificial
1061 {
1062 //qDebug() << type;
1063 Q_ASSERT(type=="star" || type=="planet" || type=="moon" || type=="artificial" || type=="observer" || type=="dwarf planet"); // TBD: remove Pluto...
1064 // Set possible default name of the normal map for avoiding yin-yang shaped moon
1065 // phase when normal map key not exists. Example: moon_normals.png
1066 // Details: https://bugs.launchpad.net/stellarium/+bug/1335609
1067 newP = PlanetP(new Planet(englishName,
1068 pd.value(secname+"/radius", 1.0).toDouble()/AU,
1069 pd.value(secname+"/oblateness", 0.0).toDouble(),
1070 Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
1071 pd.value(secname+"/albedo", 0.25f).toFloat(),
1072 pd.value(secname+"/roughness",0.9f).toFloat(),
1073 pd.value(secname+"/tex_map", "nomap.png").toString(),
1074 pd.value(secname+"/normals_map", englishName.toLower().append("_normals.png")).toString(),
1075 pd.value(secname+"/model").toString(),
1076 posfunc,
1077 static_cast<KeplerOrbit*>(orbitPtr), // This remains Q_NULLPTR for the major planets, or has a KeplerOrbit for planet moons.
1078 osculatingFunc,
1079 closeOrbit,
1080 pd.value(secname+"/hidden", false).toBool(),
1081 pd.value(secname+"/atmosphere", false).toBool(),
1082 pd.value(secname+"/halo", true).toBool(),
1083 type));
1084 newP->absoluteMagnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
1085
1086 // Moon designation (planet index + IAU moon number)
1087 QString moonDesignation = pd.value(secname+"/iau_moon_number", "").toString();
1088 if (!moonDesignation.isEmpty())
1089 {
1090 newP->setIAUMoonNumber(moonDesignation);
1091 }
1092 }
1093
1094 if (!parent.isNull())
1095 {
1096 parent->satellites.append(newP);
1097 newP->parent = parent;
1098 }
1099 if (secname=="earth") earth = newP;
1100 if (secname=="sun") sun = newP;
1101 if (secname=="moon") moon = newP;
1102
1103 // At this point the orbit and object type (class Planet and subclasses) have been fixed.
1104 // For many objects we have oriented spheroids with rotational parameters.
1105
1106 // There are two ways of defining the axis orientation:
1107 // obliquity and ascending node, which was used by Stellarium already before 2010 (based on Celestia?).
1108 double rotObliquity = pd.value(secname+"/rot_obliquity",0.).toDouble()*(M_PI_180);
1109 double rotAscNode = pd.value(secname+"/rot_equator_ascending_node",0.).toDouble()*(M_PI_180);
1110 // rot_periode given in hours (from which rotPeriod in days),
1111 // The default is useful for many moons in bound rotation
1112 double rotPeriod=pd.value(secname+"/rot_periode", pd.value(secname+"/orbit_Period", 1.).toDouble()*24.).toDouble()/24.;
1113 double rotOffset=pd.value(secname+"/rot_rotation_offset",0.).toDouble();
1114
1115 // 0.21+: Use WGCCRE planet North pole data if available
1116 // NB: N pole for J2000 epoch as defined by IAU (NOT right hand rotation rule)
1117 // Define only basic motion. Use special functions for more complicated axes.
1118 const double J2000NPoleRA = pd.value(secname+"/rot_pole_ra", 0.).toDouble()*M_PI_180;
1119 const double J2000NPoleRA1 = pd.value(secname+"/rot_pole_ra1", 0.).toDouble()*M_PI_180;
1120 const double J2000NPoleDE = pd.value(secname+"/rot_pole_de", 0.).toDouble()*M_PI_180;
1121 const double J2000NPoleDE1 = pd.value(secname+"/rot_pole_de1", 0.).toDouble()*M_PI_180;
1122 const double J2000NPoleW0 = pd.value(secname+"/rot_pole_w0", 0.).toDouble(); // [degrees] Basically the same idea as rot_rotation_offset, but W!=rotAngle
1123 const double J2000NPoleW1 = pd.value(secname+"/rot_pole_w1", 0.).toDouble(); // [degrees/d] Basically the same idea as 360/rot_periode
1124 if (fabs(J2000NPoleW1) > 0.0) // Patch possibly old period value with a more modern value.
1125 {
1126 // this is just another expression for rotational speed.
1127 rotPeriod=360.0/J2000NPoleW1;
1128 }
1129
1130 // IMPORTANT: For the planet moons with orbits relative to planets' equator plane,
1131 // re-compute the important bits from the updated axis elements.
1132 // Reactivated to re-establish Pluto/Charon lock #153
1133 if((J2000NPoleRA!=0.) || (J2000NPoleDE!=0.))
1134 {
1135 // If available, recompute obliquity and AscNode from the new data.
1136 // Solution since 0.16: Make this once for J2000.
1137 // Optional (future?): Repeat this block in Planet::computeTransMatrix() for planets with moving axes and update all Moons' KeplerOrbit if required.
1138 Vec3d J2000NPole;
1139 StelUtils::spheToRect(J2000NPoleRA,J2000NPoleDE,J2000NPole);
1140
1141 Vec3d vsop87Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(J2000NPole));
1142
1143 double lon, lat;
1144 StelUtils::rectToSphe(&lon, &lat, vsop87Pole);
1145
1146 rotObliquity = (M_PI_2 - lat);
1147 rotAscNode = (lon + M_PI_2);
1148
1149 //qDebug() << englishName << ": Compare these values to the older data in ssystem_major";
1150 //qDebug() << "\tCalculated rotational obliquity: " << rotObliquity*180./M_PI;
1151 //qDebug() << "\tCalculated rotational ascending node: " << rotAscNode*180./M_PI;
1152
1153 if (J2000NPoleW0 >0)
1154 {
1155 // W0 is counted from the ascending node with ICRF, but rotOffset from orbital plane.
1156 // Try this assumption by just counting Offset=W0+90+RA0.
1157 rotOffset=J2000NPoleW0 + lon*M_180_PI;
1158 //qDebug() << "\tCalculated rotational period (days // hours): " << rotPeriod << "//" << rotPeriod*24.;
1159 //qDebug() << "\tRotational offset (degrees): " << rotOffset;
1160 }
1161 }
1162 newP->setRotationElements(
1163 englishName,
1164 rotPeriod,
1165 rotOffset,
1166 pd.value(secname+"/rot_epoch", J2000).toDouble(),
1167 rotObliquity,
1168 rotAscNode,
1169 J2000NPoleRA,
1170 J2000NPoleRA1,
1171 J2000NPoleDE,
1172 J2000NPoleDE1,
1173 J2000NPoleW0,
1174 J2000NPoleW1);
1175 // orbit_Period or orbit_visualization_period given in days.
1176 // Elliptical Kepler orbits (ecc<0.9) will replace whatever is given by a value computed on the fly.
1177 newP->setSiderealPeriod(fabs(pd.value(secname+"/orbit_Period",
1178 pd.value(secname+"/orbit_visualization_period" )).toDouble()));
1179
1180 if (pd.contains(secname+"/tex_ring")) {
1181 const float rMin = pd.value(secname+"/ring_inner_size").toFloat()/AUf;
1182 const float rMax = pd.value(secname+"/ring_outer_size").toFloat()/AUf;
1183 Ring *r = new Ring(rMin,rMax,pd.value(secname+"/tex_ring").toString());
1184 newP->setRings(r);
1185 }
1186
1187 systemPlanets.push_back(newP);
1188 readOk++;
1189 }
1190
1191 if (systemPlanets.isEmpty())
1192 {
1193 qWarning() << "No Solar System objects loaded from" << QDir::toNativeSeparators(filePath);
1194 return false;
1195 }
1196 else qDebug() << "SolarSystem has " << systemPlanets.count() << "entries.";
1197
1198 // special case: load earth shadow texture
1199 if (!Planet::texEarthShadow)
1200 Planet::texEarthShadow = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/earth-shadow.png");
1201
1202 // Also comets just have static textures.
1203 if (!Comet::comaTexture)
1204 Comet::comaTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometComa.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
1205 //tail textures. We use paraboloid tail bodies, textured like a fisheye sphere, i.e. center=head. The texture should be something like a mottled star to give some structure.
1206 if (!Comet::tailTexture)
1207 Comet::tailTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometTail.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
1208
1209 if (readOk>0)
1210 qDebug() << "Loaded" << readOk << "Solar System bodies";
1211
1212 return true;
1213 }
1214
1215 // Compute the position for every elements of the solar system.
1216 // The order is not important since the position is computed relatively to the mother body
computePositions(double dateJDE,PlanetP observerPlanet)1217 void SolarSystem::computePositions(double dateJDE, PlanetP observerPlanet)
1218 {
1219 StelCore *core=StelApp::getInstance().getCore();
1220 const bool withAberration=core->getUseAberration();
1221 if (flagLightTravelTime) // switching off light time correction implies no aberration for the planets.
1222 {
1223 for (const auto& p : qAsConst(systemPlanets))
1224 {
1225 p->computePosition(dateJDE, Vec3d(0.));
1226 }
1227 const Vec3d obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
1228
1229 // For higher accuracy, we now make two iterations of light time and aberration correction. In the final round, we also compute rotation data.
1230 // May fix sub-arcsecond inaccuracies, and optionally apply aberration in the way described in Explanatory Supplement (2013), 7.55.
1231 // For reasons unknown (See discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!
1232 // Presumably the used ephemerides already provide aberration-corrected positions for the Moon?
1233 const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
1234 for (const auto& p : qAsConst(systemPlanets))
1235 {
1236 //p->setExtraInfoString(StelObject::DebugAid, "");
1237 const double lightTimeDays = (p->getHeliocentricEclipticPos()-obsPosJDE).length() * (AU / (SPEED_OF_LIGHT * 86400.));
1238 Vec3d aberrationPush(0.);
1239 if (withAberration && (observerPlanet->englishName!="Earth" || p->englishName!="Moon"))
1240 aberrationPush=lightTimeDays*aberrationPushSpeed;
1241 p->computePosition(dateJDE-lightTimeDays, aberrationPush);
1242 }
1243 // Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1244 for (const auto& p : qAsConst(systemPlanets))
1245 {
1246 //p->setExtraInfoString(StelObject::DebugAid, "");
1247 const double lightTimeDays = (p->getHeliocentricEclipticPos()-obsPosJDE).length() * (AU / (SPEED_OF_LIGHT * 86400.));
1248 Vec3d aberrationPush(0.);
1249 if (withAberration && (observerPlanet->englishName!="Earth" || p->englishName!="Moon"))
1250 aberrationPush=lightTimeDays*aberrationPushSpeed;
1251 // The next call may already do nothing if the time difference to the previous round is not large enough.
1252 p->computePosition(dateJDE-lightTimeDays, aberrationPush);
1253 // p->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1254 // .arg(QString::number(lightTimeDays, 'f', 3))
1255 // .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1256 // .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1257 // .arg(QString::number(aberrationPushSpeed[0], 'f', 3)));
1258
1259 if (p->englishName=="Moon") RotationElements::updatePlanetCorrections(dateJDE-lightTimeDays, RotationElements::EarthMoon);
1260 else if (p->englishName=="Mars") RotationElements::updatePlanetCorrections(dateJDE-lightTimeDays, RotationElements::Mars);
1261 else if (p->englishName=="Jupiter") RotationElements::updatePlanetCorrections(dateJDE-lightTimeDays, RotationElements::Jupiter);
1262 else if (p->englishName=="Saturn") RotationElements::updatePlanetCorrections(dateJDE-lightTimeDays, RotationElements::Saturn);
1263 else if (p->englishName=="Uranus") RotationElements::updatePlanetCorrections(dateJDE-lightTimeDays, RotationElements::Uranus);
1264 else if (p->englishName=="Neptune") RotationElements::updatePlanetCorrections(dateJDE-lightTimeDays, RotationElements::Neptune);
1265 }
1266 }
1267 else
1268 {
1269 for (const auto& p : qAsConst(systemPlanets))
1270 {
1271 p->setExtraInfoString(StelObject::DebugAid, "");
1272 p->computePosition(dateJDE, Vec3d(0.));
1273 if (p->englishName=="Moon") RotationElements::updatePlanetCorrections(dateJDE, RotationElements::EarthMoon);
1274 else if (p->englishName=="Mars") RotationElements::updatePlanetCorrections(dateJDE, RotationElements::Mars);
1275 else if (p->englishName=="Jupiter") RotationElements::updatePlanetCorrections(dateJDE, RotationElements::Jupiter);
1276 else if (p->englishName=="Saturn") RotationElements::updatePlanetCorrections(dateJDE, RotationElements::Saturn);
1277 else if (p->englishName=="Uranus") RotationElements::updatePlanetCorrections(dateJDE, RotationElements::Uranus);
1278 else if (p->englishName=="Neptune") RotationElements::updatePlanetCorrections(dateJDE, RotationElements::Neptune);
1279 }
1280 }
1281 computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
1282 }
1283
1284 // Compute the transformation matrix for every elements of the solar system.
1285 // The elements have to be ordered hierarchically, eg. it's important to compute earth before moon.
computeTransMatrices(double dateJDE,const Vec3d & observerPos)1286 void SolarSystem::computeTransMatrices(double dateJDE, const Vec3d& observerPos)
1287 {
1288 const double dateJD=dateJDE - (StelApp::getInstance().getCore()->computeDeltaT(dateJDE))/86400.0;
1289
1290 if (flagLightTravelTime)
1291 {
1292 for (const auto& p : qAsConst(systemPlanets))
1293 {
1294 const double light_speed_correction = (p->getHeliocentricEclipticPos()-observerPos).length() * (AU / (SPEED_OF_LIGHT * 86400));
1295 p->computeTransMatrix(dateJD-light_speed_correction, dateJDE-light_speed_correction);
1296 }
1297 }
1298 else
1299 {
1300 for (const auto& p : qAsConst(systemPlanets))
1301 {
1302 p->computeTransMatrix(dateJD, dateJDE);
1303 }
1304 }
1305 }
1306
1307 // And sort them from the furthest to the closest to the observer
1308 struct biggerDistance : public std::binary_function<PlanetP, PlanetP, bool>
1309 {
operator ()biggerDistance1310 bool operator()(PlanetP p1, PlanetP p2)
1311 {
1312 return p1->getDistance() > p2->getDistance();
1313 }
1314 };
1315
1316 // Draw all the elements of the solar system
1317 // We are supposed to be in heliocentric coordinate
draw(StelCore * core)1318 void SolarSystem::draw(StelCore* core)
1319 {
1320 // AstroCalcDialog
1321 drawEphemerisItems(core);
1322
1323 if (!flagShow)
1324 return;
1325
1326 // Compute each Planet distance to the observer
1327 const Vec3d obsHelioPos = core->getObserverHeliocentricEclipticPos();
1328
1329 for (const auto& p : qAsConst(systemPlanets))
1330 {
1331 p->computeDistance(obsHelioPos);
1332 }
1333
1334 // And sort them from the furthest to the closest
1335 sort(systemPlanets.begin(),systemPlanets.end(),biggerDistance());
1336
1337 if (trailFader.getInterstate()>0.0000001f)
1338 {
1339 StelPainter sPainter(core->getProjection2d());
1340 const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
1341 allTrails->setOpacity(trailFader.getInterstate());
1342 if (trailsThickness>1 || ppx>1.f)
1343 sPainter.setLineWidth(trailsThickness*ppx);
1344 allTrails->draw(core, &sPainter);
1345 if (trailsThickness>1 || ppx>1.f)
1346 sPainter.setLineWidth(1);
1347 }
1348
1349 // Make some voodoo to determine when labels should be displayed
1350 const float sdLimitMag=static_cast<float>(core->getSkyDrawer()->getLimitMagnitude());
1351 const float maxMagLabel = (sdLimitMag<5.f ? sdLimitMag :
1352 5.f+(sdLimitMag-5.f)*1.2f) +(static_cast<float>(labelsAmount)-3.f)*1.2f;
1353
1354 // Draw the elements
1355 for (const auto& p : qAsConst(systemPlanets))
1356 {
1357 p->draw(core, maxMagLabel, planetNameFont);
1358 }
1359
1360 if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer() && getFlagPointer())
1361 drawPointer(core);
1362 }
1363
drawEphemerisItems(const StelCore * core)1364 void SolarSystem::drawEphemerisItems(const StelCore* core)
1365 {
1366 if (flagShow || (!flagShow && getFlagEphemerisAlwaysOn()))
1367 {
1368 if (getFlagEphemerisMarkers())
1369 drawEphemerisMarkers(core);
1370 if (getFlagEphemerisLine())
1371 drawEphemerisLine(core);
1372 }
1373 }
1374
getEphemerisMarkerColor(int index) const1375 Vec3f SolarSystem::getEphemerisMarkerColor(int index) const
1376 {
1377 // Sync index with AstroCalcDialog::generateEphemeris(). If required, switch to using a QMap.
1378 const QVector<Vec3f> colors={
1379 ephemerisGenericMarkerColor,
1380 ephemerisSecondaryMarkerColor,
1381 ephemerisMercuryMarkerColor,
1382 ephemerisVenusMarkerColor,
1383 ephemerisMarsMarkerColor,
1384 ephemerisJupiterMarkerColor,
1385 ephemerisSaturnMarkerColor};
1386 return colors.value(index, ephemerisGenericMarkerColor);
1387 }
1388
drawEphemerisMarkers(const StelCore * core)1389 void SolarSystem::drawEphemerisMarkers(const StelCore *core)
1390 {
1391 const int fsize = AstroCalcDialog::EphemerisList.count();
1392 if (fsize==0) return;
1393
1394 StelProjectorP prj;
1395 if (getFlagEphemerisHorizontalCoordinates())
1396 prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
1397 else
1398 prj = core->getProjection(StelCore::FrameJ2000);
1399 StelPainter sPainter(prj);
1400
1401 float size, shift, baseSize = 4.f;
1402 const bool showDates = getFlagEphemerisDates();
1403 const bool showMagnitudes = getFlagEphemerisMagnitudes();
1404 const bool showSkippedData = getFlagEphemerisSkipData();
1405 const bool skipMarkers = getFlagEphemerisSkipMarkers();
1406 const int dataStep = getEphemerisDataStep();
1407 const int sizeCoeff = getEphemerisLineThickness() - 1;
1408 QString info = "";
1409 Vec3d win;
1410 Vec3f markerColor;
1411
1412 if (getFlagEphemerisLine() && getFlagEphemerisScaleMarkers())
1413 baseSize = 3.f; // The line lies through center of marker
1414
1415 for (int i =0; i < fsize; i++)
1416 {
1417 // Check visibility of pointer
1418 if (!(sPainter.getProjector()->projectCheck(AstroCalcDialog::EphemerisList[i].coord, win)))
1419 continue;
1420
1421 float solarAngle=0.f; // Angle to possibly rotate the texture. Degrees.
1422 QString debugStr; // Used temporarily for development
1423 const bool isComet=AstroCalcDialog::EphemerisList[i].isComet;
1424 if (i == AstroCalcDialog::DisplayedPositionIndex)
1425 {
1426 markerColor = getEphemerisSelectedMarkerColor();
1427 size = 6.f;
1428 }
1429 else
1430 {
1431 markerColor = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i].colorIndex);
1432 size = baseSize;
1433 }
1434 if (isComet) size += 16.f;
1435 size += sizeCoeff; //
1436 sPainter.setColor(markerColor);
1437 sPainter.setBlending(true, GL_ONE, GL_ONE);
1438 if (isComet)
1439 texEphemerisCometMarker->bind();
1440 else
1441 texEphemerisMarker->bind();
1442 if (skipMarkers)
1443 {
1444 if ((showDates || showMagnitudes) && showSkippedData && ((i + 1)%dataStep)!=1 && dataStep!=1)
1445 continue;
1446 }
1447 Vec3d win;
1448 if (prj->project(AstroCalcDialog::EphemerisList[i].coord, win))
1449 {
1450 if (isComet)
1451 {
1452 // compute solarAngle in screen space.
1453 Vec3d sunWin;
1454 prj->project(AstroCalcDialog::EphemerisList[i].sunCoord, sunWin);
1455 // TODO: In some projections, we may need to test result and flip/mirror the angle, or deal with wrap-around effects.
1456 // E.g., in cylindrical mode, the comet icon will flip as soon as the corresponding sun position wraps around the screen edge.
1457 solarAngle=M_180_PIf*static_cast<float>(atan2(-(win[1]-sunWin[1]), win[0]-sunWin[0]));
1458 // This will show projected positions and angles usable in labels.
1459 debugStr = QString("Sun: %1/%2 Obj: %3/%4 -->%5").arg(QString::number(sunWin[0]), QString::number(sunWin[1]), QString::number(win[0]), QString::number(win[1]), QString::number(solarAngle));
1460 }
1461 //sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 180.f+AstroCalcDialog::EphemerisList[i].solarAngle*M_180_PIf);
1462 sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 270.f-solarAngle);
1463 }
1464
1465 if (showDates || showMagnitudes)
1466 {
1467 if (showSkippedData && ((i + 1)%dataStep)!=1 && dataStep!=1)
1468 continue;
1469
1470 shift = 3.f + size/1.6f;
1471 if (showDates && showMagnitudes)
1472 info = QString("%1 (%2)").arg(AstroCalcDialog::EphemerisList[i].objDateStr, QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2));
1473 if (showDates && !showMagnitudes)
1474 info = AstroCalcDialog::EphemerisList[i].objDateStr;
1475 if (!showDates && showMagnitudes)
1476 info = QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2);
1477
1478 // Activate for debug labels.
1479 //info=debugStr;
1480 sPainter.drawText(AstroCalcDialog::EphemerisList[i].coord, info, 0, shift, shift, false);
1481 }
1482 }
1483 }
1484
drawEphemerisLine(const StelCore * core)1485 void SolarSystem::drawEphemerisLine(const StelCore *core)
1486 {
1487 const int size = AstroCalcDialog::EphemerisList.count();
1488 if (size==0) return;
1489
1490 // The array of data is not empty - good news!
1491 StelProjectorP prj;
1492 if (getFlagEphemerisHorizontalCoordinates())
1493 prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
1494 else
1495 prj = core->getProjection(StelCore::FrameJ2000);
1496 StelPainter sPainter(prj);
1497 const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
1498
1499 const float oldLineThickness=sPainter.getLineWidth();
1500 const float lineThickness = getEphemerisLineThickness()*ppx;
1501 if (!fuzzyEquals(lineThickness, oldLineThickness))
1502 sPainter.setLineWidth(lineThickness);
1503
1504 Vec3f color;
1505 QVector<Vec3d> vertexArray;
1506 QVector<Vec4f> colorArray;
1507 const int limit = getEphemerisDataLimit();
1508 const int nsize = static_cast<int>(size/limit);
1509 vertexArray.resize(nsize);
1510 colorArray.resize(nsize);
1511 for (int j=0; j<limit; j++)
1512 {
1513 for (int i =0; i < nsize; i++)
1514 {
1515 color = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i + j*nsize].colorIndex);
1516 colorArray[i]=Vec4f(color, 1.0f);
1517 vertexArray[i]=AstroCalcDialog::EphemerisList[i + j*nsize].coord;
1518 }
1519 sPainter.drawPath(vertexArray, colorArray);
1520 }
1521
1522 if (!fuzzyEquals(lineThickness, oldLineThickness))
1523 sPainter.setLineWidth(oldLineThickness); // restore line thickness
1524 }
1525
fillEphemerisDates()1526 void SolarSystem::fillEphemerisDates()
1527 {
1528 const int fsize = AstroCalcDialog::EphemerisList.count();
1529 if (fsize==0) return;
1530
1531 StelLocaleMgr* localeMgr = &StelApp::getInstance().getLocaleMgr();
1532 const bool showSmartDates = getFlagEphemerisSmartDates();
1533 double JD = AstroCalcDialog::EphemerisList.first().objDate;
1534 bool withTime = (fsize>1 && (AstroCalcDialog::EphemerisList[1].objDate-JD<1.0));
1535
1536 int fYear, fMonth, fDay, sYear, sMonth, sDay, h, m, s;
1537 QString info;
1538 const double shift = StelApp::getInstance().getCore()->getUTCOffset(JD)*0.041666666666;
1539 StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
1540 bool sFlag = true;
1541 sYear = fYear;
1542 sMonth = fMonth;
1543 sDay = fDay;
1544 const bool showSkippedData = getFlagEphemerisSkipData();
1545 const int dataStep = getEphemerisDataStep();
1546
1547 for (int i = 0; i < fsize; i++)
1548 {
1549 JD = AstroCalcDialog::EphemerisList[i].objDate;
1550 StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
1551
1552 if (showSkippedData && ((i + 1)%dataStep)!=1 && dataStep!=1)
1553 continue;
1554
1555 if (showSmartDates)
1556 {
1557 if (sFlag)
1558 info = QString("%1").arg(fYear);
1559
1560 if (info.isEmpty() && !sFlag && fYear!=sYear)
1561 info = QString("%1").arg(fYear);
1562
1563 if (!info.isEmpty())
1564 info.append(QString("/%1").arg(localeMgr->romanMonthName(fMonth)));
1565 else if (fMonth!=sMonth)
1566 info = QString("%1").arg(localeMgr->romanMonthName(fMonth));
1567
1568 if (!info.isEmpty())
1569 info.append(QString("/%1").arg(fDay));
1570 else
1571 info = QString("%1").arg(fDay);
1572
1573 if (withTime) // very short step
1574 {
1575 if (fDay==sDay && !sFlag)
1576 info.clear();
1577
1578 StelUtils::getTimeFromJulianDay(JD+shift, &h, &m, &s);
1579 if (!info.isEmpty())
1580 info.append(QString(" %1:%2").arg(h).arg(m));
1581 else
1582 info = QString("%1:%2").arg(h).arg(m);
1583 }
1584
1585 AstroCalcDialog::EphemerisList[i].objDateStr = info;
1586 info.clear();
1587 sYear = fYear;
1588 sMonth = fMonth;
1589 sDay = fDay;
1590 sFlag = false;
1591 }
1592 else
1593 {
1594 // OK, let's use standard formats for date and time (as defined for whole planetarium)
1595 if (withTime)
1596 AstroCalcDialog::EphemerisList[i].objDateStr = QString("%1 %2").arg(localeMgr->getPrintableDateLocal(JD), localeMgr->getPrintableTimeLocal(JD));
1597 else
1598 AstroCalcDialog::EphemerisList[i].objDateStr = localeMgr->getPrintableDateLocal(JD);
1599 }
1600 }
1601 }
1602
searchByEnglishName(QString planetEnglishName) const1603 PlanetP SolarSystem::searchByEnglishName(QString planetEnglishName) const
1604 {
1605 for (const auto& p : systemPlanets)
1606 {
1607 if (p->getEnglishName().toUpper() == planetEnglishName.toUpper() || p->getCommonEnglishName().toUpper() == planetEnglishName.toUpper())
1608 return p;
1609 }
1610 return PlanetP();
1611 }
1612
searchMinorPlanetByEnglishName(QString planetEnglishName) const1613 PlanetP SolarSystem::searchMinorPlanetByEnglishName(QString planetEnglishName) const
1614 {
1615 for (const auto& p : systemMinorBodies)
1616 {
1617 if (p->getCommonEnglishName().toUpper() == planetEnglishName.toUpper() || p->getEnglishName().toUpper() == planetEnglishName.toUpper())
1618 return p;
1619 }
1620 return PlanetP();
1621 }
1622
1623
searchByNameI18n(const QString & planetNameI18) const1624 StelObjectP SolarSystem::searchByNameI18n(const QString& planetNameI18) const
1625 {
1626 for (const auto& p : systemPlanets)
1627 {
1628 QString nativeName = p->getNativeNameI18n().toUpper();
1629 if (p->getNameI18n().toUpper() == planetNameI18.toUpper() || (!nativeName.isEmpty() && nativeName == planetNameI18.toUpper()))
1630 return qSharedPointerCast<StelObject>(p);
1631 }
1632 return StelObjectP();
1633 }
1634
1635
searchByName(const QString & name) const1636 StelObjectP SolarSystem::searchByName(const QString& name) const
1637 {
1638 for (const auto& p : systemPlanets)
1639 {
1640 QString nativeName = p->getNativeName().toUpper();
1641 if (p->getEnglishName().toUpper() == name.toUpper() || (!nativeName.isEmpty() && nativeName == name.toUpper()))
1642 return qSharedPointerCast<StelObject>(p);
1643 }
1644 return StelObjectP();
1645 }
1646
getPlanetVMagnitude(QString planetName,bool withExtinction) const1647 float SolarSystem::getPlanetVMagnitude(QString planetName, bool withExtinction) const
1648 {
1649 PlanetP p = searchByEnglishName(planetName);
1650 if (p.isNull()) // Possible was asked the common name of minor planet?
1651 p = searchMinorPlanetByEnglishName(planetName);
1652 float r = 0.f;
1653 if (withExtinction)
1654 r = p->getVMagnitudeWithExtinction(StelApp::getInstance().getCore());
1655 else
1656 r = p->getVMagnitude(StelApp::getInstance().getCore());
1657 return r;
1658 }
1659
getPlanetType(QString planetName) const1660 QString SolarSystem::getPlanetType(QString planetName) const
1661 {
1662 PlanetP p = searchByEnglishName(planetName);
1663 if (p.isNull()) // Possible was asked the common name of minor planet?
1664 p = searchMinorPlanetByEnglishName(planetName);
1665 if (p.isNull())
1666 return QString("UNDEFINED");
1667 return p->getPlanetTypeString();
1668 }
1669
getDistanceToPlanet(QString planetName) const1670 double SolarSystem::getDistanceToPlanet(QString planetName) const
1671 {
1672 PlanetP p = searchByEnglishName(planetName);
1673 if (p.isNull()) // Possible was asked the common name of minor planet?
1674 p = searchMinorPlanetByEnglishName(planetName);
1675 return p->getDistance();
1676 }
1677
getElongationForPlanet(QString planetName) const1678 double SolarSystem::getElongationForPlanet(QString planetName) const
1679 {
1680 PlanetP p = searchByEnglishName(planetName);
1681 if (p.isNull()) // Possible was asked the common name of minor planet?
1682 p = searchMinorPlanetByEnglishName(planetName);
1683 return p->getElongation(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
1684 }
1685
getPhaseAngleForPlanet(QString planetName) const1686 double SolarSystem::getPhaseAngleForPlanet(QString planetName) const
1687 {
1688 PlanetP p = searchByEnglishName(planetName);
1689 if (p.isNull()) // Possible was asked the common name of minor planet?
1690 p = searchMinorPlanetByEnglishName(planetName);
1691 return p->getPhaseAngle(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
1692 }
1693
getPhaseForPlanet(QString planetName) const1694 float SolarSystem::getPhaseForPlanet(QString planetName) const
1695 {
1696 PlanetP p = searchByEnglishName(planetName);
1697 if (p.isNull()) // Possible was asked the common name of minor planet?
1698 p = searchMinorPlanetByEnglishName(planetName);
1699 return p->getPhase(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
1700 }
1701
getObjectsList(QString objType) const1702 QStringList SolarSystem::getObjectsList(QString objType) const
1703 {
1704 QStringList r;
1705 if (objType.toLower()=="all")
1706 {
1707 r = listAllObjects(true);
1708 // Remove the Sun
1709 r.removeOne("Sun");
1710 // Remove special objects
1711 r.removeOne("Solar System Observer");
1712 r.removeOne("Earth Observer");
1713 r.removeOne("Mars Observer");
1714 r.removeOne("Jupiter Observer");
1715 r.removeOne("Saturn Observer");
1716 r.removeOne("Uranus Observer");
1717 r.removeOne("Neptune Observer");
1718 }
1719 else
1720 r = listAllObjectsByType(objType, true);
1721
1722 return r;
1723 }
1724
1725 // Search if any Planet is close to position given in earth equatorial position and return the distance
search(Vec3d pos,const StelCore * core) const1726 StelObjectP SolarSystem::search(Vec3d pos, const StelCore* core) const
1727 {
1728 pos.normalize();
1729 PlanetP closest;
1730 double cos_angle_closest = 0.;
1731 Vec3d equPos;
1732
1733 for (const auto& p : systemPlanets)
1734 {
1735 equPos = p->getEquinoxEquatorialPos(core);
1736 equPos.normalize();
1737 double cos_ang_dist = equPos*pos;
1738 if (cos_ang_dist>cos_angle_closest)
1739 {
1740 closest = p;
1741 cos_angle_closest = cos_ang_dist;
1742 }
1743 }
1744
1745 if (cos_angle_closest>0.999)
1746 {
1747 return qSharedPointerCast<StelObject>(closest);
1748 }
1749 else return StelObjectP();
1750 }
1751
1752 // Return a QList containing the planets located inside the limFov circle around position vv
searchAround(const Vec3d & vv,double limitFov,const StelCore * core) const1753 QList<StelObjectP> SolarSystem::searchAround(const Vec3d& vv, double limitFov, const StelCore* core) const
1754 {
1755 QList<StelObjectP> result;
1756 if (!getFlagPlanets())
1757 return result;
1758
1759 const bool withAberration=core->getUseAberration();
1760 Vec3d v(vv);
1761 v.normalize(); // TODO: start with vv already normalized?
1762 if (withAberration)
1763 {
1764 Vec3d vel=core->getCurrentPlanet()->getHeliocentricEclipticVelocity();
1765 StelCore::matVsop87ToJ2000.transfo(vel);
1766 vel*=core->getAberrationFactor()*(AU/(86400.0*SPEED_OF_LIGHT));
1767 v+=vel;
1768 v.normalize();
1769 }
1770
1771 double cosLimFov = std::cos(limitFov * M_PI/180.);
1772 Vec3d equPos;
1773 double cosAngularSize;
1774
1775 const QString weAreHere = core->getCurrentPlanet()->getEnglishName();
1776 for (const auto& p : systemPlanets)
1777 {
1778 equPos = p->getJ2000EquatorialPos(core);
1779 equPos.normalize();
1780
1781 cosAngularSize = std::cos(p->getSpheroidAngularSize(core) * M_PI/180.);
1782
1783 if (equPos*v>=std::min(cosLimFov, cosAngularSize) && p->getEnglishName()!=weAreHere)
1784 {
1785 result.append(qSharedPointerCast<StelObject>(p));
1786 }
1787 }
1788 return result;
1789 }
1790
1791 // Update i18 names from english names according to current sky culture translator
updateI18n()1792 void SolarSystem::updateI18n()
1793 {
1794 const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
1795 for (const auto& p : qAsConst(systemPlanets))
1796 p->translateName(trans);
1797 }
1798
listMatchingObjects(const QString & objPrefix,int maxNbItem,bool useStartOfWords) const1799 QStringList SolarSystem::listMatchingObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
1800 {
1801 QStringList result;
1802 if (getFlagPlanets())
1803 result = StelObjectModule::listMatchingObjects(objPrefix, maxNbItem, useStartOfWords);
1804 return result;
1805 }
1806
setFlagTrails(bool b)1807 void SolarSystem::setFlagTrails(bool b)
1808 {
1809 if (getFlagTrails() != b)
1810 {
1811 trailFader = b;
1812 if (b)
1813 {
1814 allTrails->reset(maxTrailPoints);
1815 recreateTrails();
1816 }
1817 emit trailsDisplayedChanged(b);
1818 }
1819 }
1820
getFlagTrails() const1821 bool SolarSystem::getFlagTrails() const
1822 {
1823 return static_cast<bool>(trailFader);
1824 }
1825
setMaxTrailPoints(int max)1826 void SolarSystem::setMaxTrailPoints(int max)
1827 {
1828 if (maxTrailPoints != max)
1829 {
1830 maxTrailPoints = max;
1831 allTrails->reset(max);
1832 recreateTrails();
1833 emit maxTrailPointsChanged(max);
1834 }
1835 }
1836
setMaxTrailTimeExtent(int max)1837 void SolarSystem::setMaxTrailTimeExtent(int max)
1838 {
1839 if (maxTrailTimeExtent != max && maxTrailTimeExtent > 0)
1840 {
1841 maxTrailTimeExtent = max;
1842 recreateTrails();
1843 emit maxTrailTimeExtentChanged(max);
1844 }
1845 }
1846
setTrailsThickness(int v)1847 void SolarSystem::setTrailsThickness(int v)
1848 {
1849 if (trailsThickness != v)
1850 {
1851 trailsThickness = v;
1852 emit trailsThicknessChanged(v);
1853 }
1854 }
1855
setFlagHints(bool b)1856 void SolarSystem::setFlagHints(bool b)
1857 {
1858 if (getFlagHints() != b)
1859 {
1860 for (const auto& p : qAsConst(systemPlanets))
1861 p->setFlagHints(b);
1862 emit flagHintsChanged(b);
1863 }
1864 }
1865
getFlagHints(void) const1866 bool SolarSystem::getFlagHints(void) const
1867 {
1868 for (const auto& p : systemPlanets)
1869 {
1870 if (p->getFlagHints())
1871 return true;
1872 }
1873 return false;
1874 }
1875
setFlagLabels(bool b)1876 void SolarSystem::setFlagLabels(bool b)
1877 {
1878 if (getFlagLabels() != b)
1879 {
1880 for (const auto& p : qAsConst(systemPlanets))
1881 p->setFlagLabels(b);
1882 emit labelsDisplayedChanged(b);
1883 }
1884 }
1885
getFlagLabels() const1886 bool SolarSystem::getFlagLabels() const
1887 {
1888 for (const auto& p : systemPlanets)
1889 {
1890 if (p->getFlagLabels())
1891 return true;
1892 }
1893 return false;
1894 }
1895
setFlagOrbits(bool b)1896 void SolarSystem::setFlagOrbits(bool b)
1897 {
1898 bool old = flagOrbits;
1899 flagOrbits = b;
1900 bool flagPlanetsOnly = getFlagPlanetsOrbitsOnly();
1901 if (!b || !selected || selected==sun)
1902 {
1903 if (flagPlanetsOnly)
1904 {
1905 for (const auto& p : qAsConst(systemPlanets))
1906 {
1907 if (p->getPlanetType()==Planet::isPlanet)
1908 p->setFlagOrbits(b);
1909 else
1910 p->setFlagOrbits(false);
1911 }
1912 }
1913 else
1914 {
1915 for (const auto& p : qAsConst(systemPlanets))
1916 p->setFlagOrbits(b);
1917 }
1918 }
1919 else if (getFlagIsolatedOrbits()) // If a Planet is selected and orbits are on, fade out non-selected ones
1920 {
1921 if (flagPlanetsOnly)
1922 {
1923 for (const auto& p : qAsConst(systemPlanets))
1924 {
1925 if (selected == p && p->getPlanetType()==Planet::isPlanet)
1926 p->setFlagOrbits(b);
1927 else
1928 p->setFlagOrbits(false);
1929 }
1930 }
1931 else
1932 {
1933 for (const auto& p : qAsConst(systemPlanets))
1934 {
1935 if (selected == p)
1936 p->setFlagOrbits(b);
1937 else
1938 p->setFlagOrbits(false);
1939 }
1940 }
1941 }
1942 else
1943 {
1944 // A planet is selected and orbits are on - draw orbits for the planet and their moons
1945 for (const auto& p : qAsConst(systemPlanets))
1946 {
1947 if (selected == p || selected == p->parent)
1948 p->setFlagOrbits(b);
1949 else
1950 p->setFlagOrbits(false);
1951 }
1952 }
1953 if(old != flagOrbits)
1954 emit flagOrbitsChanged(flagOrbits);
1955 }
1956
setFlagLightTravelTime(bool b)1957 void SolarSystem::setFlagLightTravelTime(bool b)
1958 {
1959 if(b!=flagLightTravelTime)
1960 {
1961 flagLightTravelTime = b;
1962 emit flagLightTravelTimeChanged(b);
1963 }
1964 }
1965
setFlagShowObjSelfShadows(bool b)1966 void SolarSystem::setFlagShowObjSelfShadows(bool b)
1967 {
1968 if(b!=flagShowObjSelfShadows)
1969 {
1970 flagShowObjSelfShadows = b;
1971 if(!b)
1972 Planet::deinitFBO();
1973 emit flagShowObjSelfShadowsChanged(b);
1974 }
1975 }
1976
setSelected(PlanetP obj)1977 void SolarSystem::setSelected(PlanetP obj)
1978 {
1979 if (obj && obj->getType() == "Planet")
1980 {
1981 selected = obj;
1982 selectedSSO.push_back(obj);
1983 }
1984 else
1985 selected.clear();
1986 // Undraw other objects hints, orbit, trails etc..
1987 setFlagHints(getFlagHints());
1988 setFlagOrbits(getFlagOrbits());
1989 }
1990
1991
update(double deltaTime)1992 void SolarSystem::update(double deltaTime)
1993 {
1994 trailFader.update(static_cast<int>(deltaTime*1000));
1995 if (trailFader.getInterstate()>0.f)
1996 {
1997 allTrails->update();
1998 }
1999
2000 for (const auto& p : qAsConst(systemPlanets))
2001 {
2002 p->update(static_cast<int>(deltaTime*1000));
2003 }
2004 }
2005
2006 // is a lunar eclipse close at hand?
nearLunarEclipse() const2007 bool SolarSystem::nearLunarEclipse() const
2008 {
2009 // TODO: could replace with simpler test
2010 // TODO Source?
2011
2012 const Vec3d sun = getSun()->getAberrationPush();
2013 const Vec3d e = getEarth()->getEclipticPos();
2014 const Vec3d m = getMoon()->getEclipticPos(); // relative to earth
2015 const Vec3d mh = getMoon()->getHeliocentricEclipticPos(); // relative to sun
2016
2017 // shadow location at earth + moon distance along earth vector from (aberrated) sun
2018 Vec3d en = e-sun;
2019 en.normalize();
2020 Vec3d shadow = en * (e.length() + m.length());
2021
2022 // find shadow radii in AU
2023 double r_penumbra = shadow.length()*702378.1/AU/e.length() - 696000./AU;
2024
2025 // modify shadow location for scaled moon
2026 Vec3d mdist = shadow - mh;
2027 if(mdist.length() > r_penumbra + 2000./AU) return false; // not visible so don't bother drawing
2028
2029 return true;
2030 }
2031
listAllObjects(bool inEnglish) const2032 QStringList SolarSystem::listAllObjects(bool inEnglish) const
2033 {
2034 QStringList result;
2035 if (inEnglish)
2036 {
2037 for (const auto& p : systemPlanets)
2038 {
2039 result << p->getEnglishName();
2040 }
2041 }
2042 else
2043 {
2044 for (const auto& p : systemPlanets)
2045 {
2046 result << p->getNameI18n();
2047 if (!p->getNativeNameI18n().isEmpty())
2048 result << p->getNativeNameI18n() << p->getNativeName();
2049 }
2050 }
2051 return result;
2052 }
2053
listAllObjectsByType(const QString & objType,bool inEnglish) const2054 QStringList SolarSystem::listAllObjectsByType(const QString &objType, bool inEnglish) const
2055 {
2056 QStringList result;
2057 if (inEnglish)
2058 {
2059 for (const auto& p : systemPlanets)
2060 {
2061 if (p->getPlanetTypeString()==objType)
2062 result << p->getEnglishName();
2063 }
2064 }
2065 else
2066 {
2067 for (const auto& p : systemPlanets)
2068 {
2069 if (p->getPlanetTypeString()==objType)
2070 result << p->getNameI18n();
2071 }
2072 }
2073 return result;
2074 }
2075
selectedObjectChange(StelModule::StelModuleSelectAction)2076 void SolarSystem::selectedObjectChange(StelModule::StelModuleSelectAction)
2077 {
2078 const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet");
2079 if (!newSelected.empty())
2080 {
2081 setSelected(qSharedPointerCast<Planet>(newSelected[0]));
2082 if (getFlagIsolatedTrails())
2083 recreateTrails();
2084 }
2085 else
2086 setSelected("");
2087 }
2088
2089 // Activate/Deactivate planets display
setFlagPlanets(bool b)2090 void SolarSystem::setFlagPlanets(bool b)
2091 {
2092 if (b!=flagShow)
2093 {
2094 flagShow=b;
2095 emit flagPlanetsDisplayedChanged(b);
2096 }
2097 }
2098
getFlagPlanets(void) const2099 bool SolarSystem::getFlagPlanets(void) const
2100 {
2101 return flagShow;
2102 }
2103
setFlagEphemerisMarkers(bool b)2104 void SolarSystem::setFlagEphemerisMarkers(bool b)
2105 {
2106 if (b!=ephemerisMarkersDisplayed)
2107 {
2108 ephemerisMarkersDisplayed=b;
2109 conf->setValue("astrocalc/flag_ephemeris_markers", b); // Immediate saving of state
2110 emit ephemerisMarkersChanged(b);
2111 }
2112 }
2113
getFlagEphemerisMarkers() const2114 bool SolarSystem::getFlagEphemerisMarkers() const
2115 {
2116 return ephemerisMarkersDisplayed;
2117 }
2118
setFlagEphemerisLine(bool b)2119 void SolarSystem::setFlagEphemerisLine(bool b)
2120 {
2121 if (b!=ephemerisLineDisplayed)
2122 {
2123 ephemerisLineDisplayed=b;
2124 conf->setValue("astrocalc/flag_ephemeris_line", b); // Immediate saving of state
2125 emit ephemerisLineChanged(b);
2126 }
2127 }
2128
getFlagEphemerisLine() const2129 bool SolarSystem::getFlagEphemerisLine() const
2130 {
2131 return ephemerisLineDisplayed;
2132 }
2133
getFlagEphemerisAlwaysOn() const2134 bool SolarSystem::getFlagEphemerisAlwaysOn() const
2135 {
2136 return ephemerisAlwaysOn;
2137 }
2138
setFlagEphemerisAlwaysOn(bool b)2139 void SolarSystem::setFlagEphemerisAlwaysOn(bool b)
2140 {
2141 if (b != ephemerisAlwaysOn)
2142 {
2143 ephemerisAlwaysOn = b;
2144 conf->setValue("astrocalc/flag_ephemeris_alwayson", b); // Immediate saving of state
2145 emit ephemerisAlwaysOnChanged(b);
2146 }
2147 }
2148
setFlagEphemerisHorizontalCoordinates(bool b)2149 void SolarSystem::setFlagEphemerisHorizontalCoordinates(bool b)
2150 {
2151 if (b!=ephemerisHorizontalCoordinates)
2152 {
2153 ephemerisHorizontalCoordinates=b;
2154 conf->setValue("astrocalc/flag_ephemeris_horizontal", b); // Immediate saving of state
2155 emit ephemerisHorizontalCoordinatesChanged(b);
2156 }
2157 }
2158
getFlagEphemerisHorizontalCoordinates() const2159 bool SolarSystem::getFlagEphemerisHorizontalCoordinates() const
2160 {
2161 return ephemerisHorizontalCoordinates;
2162 }
2163
setFlagEphemerisDates(bool b)2164 void SolarSystem::setFlagEphemerisDates(bool b)
2165 {
2166 if (b!=ephemerisDatesDisplayed)
2167 {
2168 ephemerisDatesDisplayed=b;
2169 conf->setValue("astrocalc/flag_ephemeris_dates", b); // Immediate saving of state
2170 emit ephemerisDatesChanged(b);
2171 }
2172 }
2173
getFlagEphemerisDates() const2174 bool SolarSystem::getFlagEphemerisDates() const
2175 {
2176 return ephemerisDatesDisplayed;
2177 }
2178
setFlagEphemerisMagnitudes(bool b)2179 void SolarSystem::setFlagEphemerisMagnitudes(bool b)
2180 {
2181 if (b!=ephemerisMagnitudesDisplayed)
2182 {
2183 ephemerisMagnitudesDisplayed=b;
2184 conf->setValue("astrocalc/flag_ephemeris_magnitudes", b); // Immediate saving of state
2185 emit ephemerisMagnitudesChanged(b);
2186 }
2187 }
2188
getFlagEphemerisMagnitudes() const2189 bool SolarSystem::getFlagEphemerisMagnitudes() const
2190 {
2191 return ephemerisMagnitudesDisplayed;
2192 }
2193
setFlagEphemerisSkipData(bool b)2194 void SolarSystem::setFlagEphemerisSkipData(bool b)
2195 {
2196 if (b!=ephemerisSkipDataDisplayed)
2197 {
2198 ephemerisSkipDataDisplayed=b;
2199 conf->setValue("astrocalc/flag_ephemeris_skip_data", b); // Immediate saving of state
2200 emit ephemerisSkipDataChanged(b);
2201 }
2202 }
2203
getFlagEphemerisSkipData() const2204 bool SolarSystem::getFlagEphemerisSkipData() const
2205 {
2206 return ephemerisSkipDataDisplayed;
2207 }
2208
setFlagEphemerisSkipMarkers(bool b)2209 void SolarSystem::setFlagEphemerisSkipMarkers(bool b)
2210 {
2211 if (b!=ephemerisSkipMarkersDisplayed)
2212 {
2213 ephemerisSkipMarkersDisplayed=b;
2214 conf->setValue("astrocalc/flag_ephemeris_skip_markers", b); // Immediate saving of state
2215 emit ephemerisSkipMarkersChanged(b);
2216 }
2217 }
2218
getFlagEphemerisSkipMarkers() const2219 bool SolarSystem::getFlagEphemerisSkipMarkers() const
2220 {
2221 return ephemerisSkipMarkersDisplayed;
2222 }
2223
setFlagEphemerisSmartDates(bool b)2224 void SolarSystem::setFlagEphemerisSmartDates(bool b)
2225 {
2226 if (b!=ephemerisSmartDatesDisplayed)
2227 {
2228 ephemerisSmartDatesDisplayed=b;
2229 conf->setValue("astrocalc/flag_ephemeris_smart_dates", b); // Immediate saving of state
2230 emit ephemerisSmartDatesChanged(b);
2231 }
2232 }
2233
getFlagEphemerisSmartDates() const2234 bool SolarSystem::getFlagEphemerisSmartDates() const
2235 {
2236 return ephemerisSmartDatesDisplayed;
2237 }
2238
setFlagEphemerisScaleMarkers(bool b)2239 void SolarSystem::setFlagEphemerisScaleMarkers(bool b)
2240 {
2241 if (b!=ephemerisScaleMarkersDisplayed)
2242 {
2243 ephemerisScaleMarkersDisplayed=b;
2244 conf->setValue("astrocalc/flag_ephemeris_scale_markers", b); // Immediate saving of state
2245 emit ephemerisScaleMarkersChanged(b);
2246 }
2247 }
2248
getFlagEphemerisScaleMarkers() const2249 bool SolarSystem::getFlagEphemerisScaleMarkers() const
2250 {
2251 return ephemerisScaleMarkersDisplayed;
2252 }
2253
setEphemerisDataStep(int step)2254 void SolarSystem::setEphemerisDataStep(int step)
2255 {
2256 ephemerisDataStep = step;
2257 // automatic saving of the setting
2258 conf->setValue("astrocalc/ephemeris_data_step", step);
2259 emit ephemerisDataStepChanged(step);
2260 }
2261
getEphemerisDataStep() const2262 int SolarSystem::getEphemerisDataStep() const
2263 {
2264 return ephemerisDataStep;
2265 }
2266
setEphemerisDataLimit(int limit)2267 void SolarSystem::setEphemerisDataLimit(int limit)
2268 {
2269 ephemerisDataLimit = limit;
2270 emit ephemerisDataLimitChanged(limit);
2271 }
2272
getEphemerisDataLimit() const2273 int SolarSystem::getEphemerisDataLimit() const
2274 {
2275 return ephemerisDataLimit;
2276 }
2277
setEphemerisLineThickness(int v)2278 void SolarSystem::setEphemerisLineThickness(int v)
2279 {
2280 ephemerisLineThickness = v;
2281 // automatic saving of the setting
2282 conf->setValue("astrocalc/ephemeris_line_thickness", v);
2283 emit ephemerisLineThicknessChanged(v);
2284 }
2285
getEphemerisLineThickness() const2286 int SolarSystem::getEphemerisLineThickness() const
2287 {
2288 return ephemerisLineThickness;
2289 }
2290
setEphemerisGenericMarkerColor(const Vec3f & color)2291 void SolarSystem::setEphemerisGenericMarkerColor(const Vec3f& color)
2292 {
2293 if (color!=ephemerisGenericMarkerColor)
2294 {
2295 ephemerisGenericMarkerColor = color;
2296 emit ephemerisGenericMarkerColorChanged(color);
2297 }
2298 }
2299
getEphemerisGenericMarkerColor() const2300 Vec3f SolarSystem::getEphemerisGenericMarkerColor() const
2301 {
2302 return ephemerisGenericMarkerColor;
2303 }
2304
setEphemerisSecondaryMarkerColor(const Vec3f & color)2305 void SolarSystem::setEphemerisSecondaryMarkerColor(const Vec3f& color)
2306 {
2307 if (color!=ephemerisSecondaryMarkerColor)
2308 {
2309 ephemerisSecondaryMarkerColor = color;
2310 emit ephemerisSecondaryMarkerColorChanged(color);
2311 }
2312 }
2313
getEphemerisSecondaryMarkerColor() const2314 Vec3f SolarSystem::getEphemerisSecondaryMarkerColor() const
2315 {
2316 return ephemerisSecondaryMarkerColor;
2317 }
2318
setEphemerisSelectedMarkerColor(const Vec3f & color)2319 void SolarSystem::setEphemerisSelectedMarkerColor(const Vec3f& color)
2320 {
2321 if (color!=ephemerisSelectedMarkerColor)
2322 {
2323 ephemerisSelectedMarkerColor = color;
2324 emit ephemerisSelectedMarkerColorChanged(color);
2325 }
2326 }
2327
getEphemerisSelectedMarkerColor() const2328 Vec3f SolarSystem::getEphemerisSelectedMarkerColor() const
2329 {
2330 return ephemerisSelectedMarkerColor;
2331 }
2332
setEphemerisMercuryMarkerColor(const Vec3f & color)2333 void SolarSystem::setEphemerisMercuryMarkerColor(const Vec3f& color)
2334 {
2335 if (color!=ephemerisMercuryMarkerColor)
2336 {
2337 ephemerisMercuryMarkerColor = color;
2338 emit ephemerisMercuryMarkerColorChanged(color);
2339 }
2340 }
2341
getEphemerisMercuryMarkerColor() const2342 Vec3f SolarSystem::getEphemerisMercuryMarkerColor() const
2343 {
2344 return ephemerisMercuryMarkerColor;
2345 }
2346
setEphemerisVenusMarkerColor(const Vec3f & color)2347 void SolarSystem::setEphemerisVenusMarkerColor(const Vec3f& color)
2348 {
2349 if (color!=ephemerisVenusMarkerColor)
2350 {
2351 ephemerisVenusMarkerColor = color;
2352 emit ephemerisVenusMarkerColorChanged(color);
2353 }
2354 }
2355
getEphemerisVenusMarkerColor() const2356 Vec3f SolarSystem::getEphemerisVenusMarkerColor() const
2357 {
2358 return ephemerisVenusMarkerColor;
2359 }
2360
setEphemerisMarsMarkerColor(const Vec3f & color)2361 void SolarSystem::setEphemerisMarsMarkerColor(const Vec3f& color)
2362 {
2363 if (color!=ephemerisMarsMarkerColor)
2364 {
2365 ephemerisMarsMarkerColor = color;
2366 emit ephemerisMarsMarkerColorChanged(color);
2367 }
2368 }
2369
getEphemerisMarsMarkerColor() const2370 Vec3f SolarSystem::getEphemerisMarsMarkerColor() const
2371 {
2372 return ephemerisMarsMarkerColor;
2373 }
2374
setEphemerisJupiterMarkerColor(const Vec3f & color)2375 void SolarSystem::setEphemerisJupiterMarkerColor(const Vec3f& color)
2376 {
2377 if (color!=ephemerisJupiterMarkerColor)
2378 {
2379 ephemerisJupiterMarkerColor = color;
2380 emit ephemerisJupiterMarkerColorChanged(color);
2381 }
2382 }
2383
getEphemerisJupiterMarkerColor() const2384 Vec3f SolarSystem::getEphemerisJupiterMarkerColor() const
2385 {
2386 return ephemerisJupiterMarkerColor;
2387 }
2388
setEphemerisSaturnMarkerColor(const Vec3f & color)2389 void SolarSystem::setEphemerisSaturnMarkerColor(const Vec3f& color)
2390 {
2391 if (color!=ephemerisSaturnMarkerColor)
2392 {
2393 ephemerisSaturnMarkerColor = color;
2394 emit ephemerisSaturnMarkerColorChanged(color);
2395 }
2396 }
2397
getEphemerisSaturnMarkerColor() const2398 Vec3f SolarSystem::getEphemerisSaturnMarkerColor() const
2399 {
2400 return ephemerisSaturnMarkerColor;
2401 }
2402
setFlagNativePlanetNames(bool b)2403 void SolarSystem::setFlagNativePlanetNames(bool b)
2404 {
2405 if (b!=flagNativePlanetNames)
2406 {
2407 flagNativePlanetNames=b;
2408 for (const auto& p : qAsConst(systemPlanets))
2409 {
2410 if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
2411 p->setFlagNativeName(flagNativePlanetNames);
2412 }
2413 updateI18n();
2414 emit flagNativePlanetNamesChanged(b);
2415 }
2416 }
2417
getFlagNativePlanetNames() const2418 bool SolarSystem::getFlagNativePlanetNames() const
2419 {
2420 return flagNativePlanetNames;
2421 }
2422
setFlagIsolatedTrails(bool b)2423 void SolarSystem::setFlagIsolatedTrails(bool b)
2424 {
2425 if(b!=flagIsolatedTrails)
2426 {
2427 flagIsolatedTrails = b;
2428 recreateTrails();
2429 emit flagIsolatedTrailsChanged(b);
2430 }
2431 }
2432
getFlagIsolatedTrails() const2433 bool SolarSystem::getFlagIsolatedTrails() const
2434 {
2435 return flagIsolatedTrails;
2436 }
2437
getNumberIsolatedTrails() const2438 int SolarSystem::getNumberIsolatedTrails() const
2439 {
2440 return numberIsolatedTrails;
2441 }
2442
setNumberIsolatedTrails(int n)2443 void SolarSystem::setNumberIsolatedTrails(int n)
2444 {
2445 // [1..5] - valid range for trails
2446 numberIsolatedTrails = qBound(1, n, 5);
2447
2448 if (getFlagIsolatedTrails())
2449 recreateTrails();
2450
2451 emit numberIsolatedTrailsChanged(numberIsolatedTrails);
2452 }
2453
setFlagIsolatedOrbits(bool b)2454 void SolarSystem::setFlagIsolatedOrbits(bool b)
2455 {
2456 if(b!=flagIsolatedOrbits)
2457 {
2458 flagIsolatedOrbits = b;
2459 emit flagIsolatedOrbitsChanged(b);
2460 // Reinstall flag for orbits to renew visibility of orbits
2461 setFlagOrbits(getFlagOrbits());
2462 }
2463 }
2464
getFlagIsolatedOrbits() const2465 bool SolarSystem::getFlagIsolatedOrbits() const
2466 {
2467 return flagIsolatedOrbits;
2468 }
2469
setFlagPlanetsOrbitsOnly(bool b)2470 void SolarSystem::setFlagPlanetsOrbitsOnly(bool b)
2471 {
2472 if(b!=flagPlanetsOrbitsOnly)
2473 {
2474 flagPlanetsOrbitsOnly = b;
2475 emit flagPlanetsOrbitsOnlyChanged(b);
2476 // Reinstall flag for orbits to renew visibility of orbits
2477 setFlagOrbits(getFlagOrbits());
2478 }
2479 }
2480
getFlagPlanetsOrbitsOnly() const2481 bool SolarSystem::getFlagPlanetsOrbitsOnly() const
2482 {
2483 return flagPlanetsOrbitsOnly;
2484 }
2485
2486 // Set/Get planets names color
setLabelsColor(const Vec3f & c)2487 void SolarSystem::setLabelsColor(const Vec3f& c)
2488 {
2489 if (c!=Planet::getLabelColor())
2490 {
2491 Planet::setLabelColor(c);
2492 emit labelsColorChanged(c);
2493 }
2494 }
2495
getLabelsColor(void) const2496 Vec3f SolarSystem::getLabelsColor(void) const
2497 {
2498 return Planet::getLabelColor();
2499 }
2500
2501 // Set/Get orbits lines color
setOrbitsColor(const Vec3f & c)2502 void SolarSystem::setOrbitsColor(const Vec3f& c)
2503 {
2504 if (c!=Planet::getOrbitColor())
2505 {
2506 Planet::setOrbitColor(c);
2507 emit orbitsColorChanged(c);
2508 }
2509 }
2510
getOrbitsColor(void) const2511 Vec3f SolarSystem::getOrbitsColor(void) const
2512 {
2513 return Planet::getOrbitColor();
2514 }
2515
setMajorPlanetsOrbitsColor(const Vec3f & c)2516 void SolarSystem::setMajorPlanetsOrbitsColor(const Vec3f &c)
2517 {
2518 if (c!=Planet::getMajorPlanetOrbitColor())
2519 {
2520 Planet::setMajorPlanetOrbitColor(c);
2521 emit majorPlanetsOrbitsColorChanged(c);
2522 }
2523 }
2524
getMajorPlanetsOrbitsColor(void) const2525 Vec3f SolarSystem::getMajorPlanetsOrbitsColor(void) const
2526 {
2527 return Planet::getMajorPlanetOrbitColor();
2528 }
2529
setMinorPlanetsOrbitsColor(const Vec3f & c)2530 void SolarSystem::setMinorPlanetsOrbitsColor(const Vec3f &c)
2531 {
2532 if (c!=Planet::getMinorPlanetOrbitColor())
2533 {
2534 Planet::setMinorPlanetOrbitColor(c);
2535 emit minorPlanetsOrbitsColorChanged(c);
2536 }
2537 }
2538
getMinorPlanetsOrbitsColor(void) const2539 Vec3f SolarSystem::getMinorPlanetsOrbitsColor(void) const
2540 {
2541 return Planet::getMinorPlanetOrbitColor();
2542 }
2543
setDwarfPlanetsOrbitsColor(const Vec3f & c)2544 void SolarSystem::setDwarfPlanetsOrbitsColor(const Vec3f &c)
2545 {
2546 if (c!=Planet::getDwarfPlanetOrbitColor())
2547 {
2548 Planet::setDwarfPlanetOrbitColor(c);
2549 emit dwarfPlanetsOrbitsColorChanged(c);
2550 }
2551 }
2552
getDwarfPlanetsOrbitsColor(void) const2553 Vec3f SolarSystem::getDwarfPlanetsOrbitsColor(void) const
2554 {
2555 return Planet::getDwarfPlanetOrbitColor();
2556 }
2557
setMoonsOrbitsColor(const Vec3f & c)2558 void SolarSystem::setMoonsOrbitsColor(const Vec3f &c)
2559 {
2560 if (c!=Planet::getMoonOrbitColor())
2561 {
2562 Planet::setMoonOrbitColor(c);
2563 emit moonsOrbitsColorChanged(c);
2564 }
2565 }
2566
getMoonsOrbitsColor(void) const2567 Vec3f SolarSystem::getMoonsOrbitsColor(void) const
2568 {
2569 return Planet::getMoonOrbitColor();
2570 }
2571
setCubewanosOrbitsColor(const Vec3f & c)2572 void SolarSystem::setCubewanosOrbitsColor(const Vec3f &c)
2573 {
2574 if (c!=Planet::getCubewanoOrbitColor())
2575 {
2576 Planet::setCubewanoOrbitColor(c);
2577 emit cubewanosOrbitsColorChanged(c);
2578 }
2579 }
2580
getCubewanosOrbitsColor(void) const2581 Vec3f SolarSystem::getCubewanosOrbitsColor(void) const
2582 {
2583 return Planet::getCubewanoOrbitColor();
2584 }
2585
setPlutinosOrbitsColor(const Vec3f & c)2586 void SolarSystem::setPlutinosOrbitsColor(const Vec3f &c)
2587 {
2588 if (c!=Planet::getPlutinoOrbitColor())
2589 {
2590 Planet::setPlutinoOrbitColor(c);
2591 emit plutinosOrbitsColorChanged(c);
2592 }
2593 }
2594
getPlutinosOrbitsColor(void) const2595 Vec3f SolarSystem::getPlutinosOrbitsColor(void) const
2596 {
2597 return Planet::getPlutinoOrbitColor();
2598 }
2599
setScatteredDiskObjectsOrbitsColor(const Vec3f & c)2600 void SolarSystem::setScatteredDiskObjectsOrbitsColor(const Vec3f &c)
2601 {
2602 if (c!=Planet::getScatteredDiscObjectOrbitColor())
2603 {
2604 Planet::setScatteredDiscObjectOrbitColor(c);
2605 emit scatteredDiskObjectsOrbitsColorChanged(c);
2606 }
2607 }
2608
getScatteredDiskObjectsOrbitsColor(void) const2609 Vec3f SolarSystem::getScatteredDiskObjectsOrbitsColor(void) const
2610 {
2611 return Planet::getScatteredDiscObjectOrbitColor();
2612 }
2613
setOortCloudObjectsOrbitsColor(const Vec3f & c)2614 void SolarSystem::setOortCloudObjectsOrbitsColor(const Vec3f &c)
2615 {
2616 if (c!=Planet::getOortCloudObjectOrbitColor())
2617 {
2618 Planet::setOortCloudObjectOrbitColor(c);
2619 emit oortCloudObjectsOrbitsColorChanged(c);
2620 }
2621 }
2622
getOortCloudObjectsOrbitsColor(void) const2623 Vec3f SolarSystem::getOortCloudObjectsOrbitsColor(void) const
2624 {
2625 return Planet::getOortCloudObjectOrbitColor();
2626 }
2627
setCometsOrbitsColor(const Vec3f & c)2628 void SolarSystem::setCometsOrbitsColor(const Vec3f& c)
2629 {
2630 if (c!=Planet::getCometOrbitColor())
2631 {
2632 Planet::setCometOrbitColor(c);
2633 emit cometsOrbitsColorChanged(c);
2634 }
2635 }
2636
getCometsOrbitsColor(void) const2637 Vec3f SolarSystem::getCometsOrbitsColor(void) const
2638 {
2639 return Planet::getCometOrbitColor();
2640 }
2641
setSednoidsOrbitsColor(const Vec3f & c)2642 void SolarSystem::setSednoidsOrbitsColor(const Vec3f& c)
2643 {
2644 if (c!=Planet::getSednoidOrbitColor())
2645 {
2646 Planet::setSednoidOrbitColor(c);
2647 emit sednoidsOrbitsColorChanged(c);
2648 }
2649 }
2650
getSednoidsOrbitsColor(void) const2651 Vec3f SolarSystem::getSednoidsOrbitsColor(void) const
2652 {
2653 return Planet::getSednoidOrbitColor();
2654 }
2655
setInterstellarOrbitsColor(const Vec3f & c)2656 void SolarSystem::setInterstellarOrbitsColor(const Vec3f& c)
2657 {
2658 if (c!=Planet::getInterstellarOrbitColor())
2659 {
2660 Planet::setInterstellarOrbitColor(c);
2661 emit interstellarOrbitsColorChanged(c);
2662 }
2663 }
2664
getInterstellarOrbitsColor(void) const2665 Vec3f SolarSystem::getInterstellarOrbitsColor(void) const
2666 {
2667 return Planet::getInterstellarOrbitColor();
2668 }
2669
setMercuryOrbitColor(const Vec3f & c)2670 void SolarSystem::setMercuryOrbitColor(const Vec3f &c)
2671 {
2672 if (c!=Planet::getMercuryOrbitColor())
2673 {
2674 Planet::setMercuryOrbitColor(c);
2675 emit mercuryOrbitColorChanged(c);
2676 }
2677 }
2678
getMercuryOrbitColor(void) const2679 Vec3f SolarSystem::getMercuryOrbitColor(void) const
2680 {
2681 return Planet::getMercuryOrbitColor();
2682 }
2683
setVenusOrbitColor(const Vec3f & c)2684 void SolarSystem::setVenusOrbitColor(const Vec3f &c)
2685 {
2686 if (c!=Planet::getVenusOrbitColor())
2687 {
2688 Planet::setVenusOrbitColor(c);
2689 emit venusOrbitColorChanged(c);
2690 }
2691 }
2692
getVenusOrbitColor(void) const2693 Vec3f SolarSystem::getVenusOrbitColor(void) const
2694 {
2695 return Planet::getVenusOrbitColor();
2696 }
2697
setEarthOrbitColor(const Vec3f & c)2698 void SolarSystem::setEarthOrbitColor(const Vec3f &c)
2699 {
2700 if (c!=Planet::getEarthOrbitColor())
2701 {
2702 Planet::setEarthOrbitColor(c);
2703 emit earthOrbitColorChanged(c);
2704 }
2705 }
2706
getEarthOrbitColor(void) const2707 Vec3f SolarSystem::getEarthOrbitColor(void) const
2708 {
2709 return Planet::getEarthOrbitColor();
2710 }
2711
setMarsOrbitColor(const Vec3f & c)2712 void SolarSystem::setMarsOrbitColor(const Vec3f &c)
2713 {
2714 if (c!=Planet::getMarsOrbitColor())
2715 {
2716 Planet::setMarsOrbitColor(c);
2717 emit marsOrbitColorChanged(c);
2718 }
2719 }
2720
getMarsOrbitColor(void) const2721 Vec3f SolarSystem::getMarsOrbitColor(void) const
2722 {
2723 return Planet::getMarsOrbitColor();
2724 }
2725
setJupiterOrbitColor(const Vec3f & c)2726 void SolarSystem::setJupiterOrbitColor(const Vec3f &c)
2727 {
2728 if (c!=Planet::getJupiterOrbitColor())
2729 {
2730 Planet::setJupiterOrbitColor(c);
2731 emit jupiterOrbitColorChanged(c);
2732 }
2733 }
2734
getJupiterOrbitColor(void) const2735 Vec3f SolarSystem::getJupiterOrbitColor(void) const
2736 {
2737 return Planet::getJupiterOrbitColor();
2738 }
2739
setSaturnOrbitColor(const Vec3f & c)2740 void SolarSystem::setSaturnOrbitColor(const Vec3f &c)
2741 {
2742 if (c!=Planet::getSaturnOrbitColor())
2743 {
2744 Planet::setSaturnOrbitColor(c);
2745 emit saturnOrbitColorChanged(c);
2746 }
2747 }
2748
getSaturnOrbitColor(void) const2749 Vec3f SolarSystem::getSaturnOrbitColor(void) const
2750 {
2751 return Planet::getSaturnOrbitColor();
2752 }
2753
setUranusOrbitColor(const Vec3f & c)2754 void SolarSystem::setUranusOrbitColor(const Vec3f &c)
2755 {
2756 if (c!=Planet::getUranusOrbitColor())
2757 {
2758 Planet::setUranusOrbitColor(c);
2759 emit uranusOrbitColorChanged(c);
2760 }
2761 }
2762
getUranusOrbitColor(void) const2763 Vec3f SolarSystem::getUranusOrbitColor(void) const
2764 {
2765 return Planet::getUranusOrbitColor();
2766 }
2767
setNeptuneOrbitColor(const Vec3f & c)2768 void SolarSystem::setNeptuneOrbitColor(const Vec3f &c)
2769 {
2770 if (c!=Planet::getNeptuneOrbitColor())
2771 {
2772 Planet::setNeptuneOrbitColor(c);
2773 emit neptuneOrbitColorChanged(c);
2774 }
2775 }
2776
getNeptuneOrbitColor(void) const2777 Vec3f SolarSystem::getNeptuneOrbitColor(void) const
2778 {
2779 return Planet::getNeptuneOrbitColor();
2780 }
2781
2782 // Set/Get if Moon display is scaled
setFlagMoonScale(bool b)2783 void SolarSystem::setFlagMoonScale(bool b)
2784 {
2785 if(b!=flagMoonScale)
2786 {
2787 if (b) getMoon()->setSphereScale(moonScale);
2788 else getMoon()->setSphereScale(1);
2789 flagMoonScale = b;
2790 emit flagMoonScaleChanged(b);
2791 }
2792 }
2793
2794 // Set/Get Moon display scaling factor. This goes directly to the Moon object.
setMoonScale(double f)2795 void SolarSystem::setMoonScale(double f)
2796 {
2797 if(!fuzzyEquals(moonScale, f))
2798 {
2799 moonScale = f;
2800 if (flagMoonScale)
2801 getMoon()->setSphereScale(moonScale);
2802 emit moonScaleChanged(f);
2803 }
2804 }
2805
2806 // Set if minor body display is scaled. This flag will be queried by all Planet objects except for the Moon.
setFlagMinorBodyScale(bool b)2807 void SolarSystem::setFlagMinorBodyScale(bool b)
2808 {
2809 if(b!=flagMinorBodyScale)
2810 {
2811 flagMinorBodyScale = b;
2812
2813 double newScale = b ? minorBodyScale : 1.0;
2814 //update the bodies with the new scale
2815 for (const auto& p : qAsConst(systemPlanets))
2816 {
2817 if(p == moon) continue;
2818 if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
2819 p->setSphereScale(newScale);
2820 }
2821 emit flagMinorBodyScaleChanged(b);
2822 }
2823 }
2824
2825 // Set minor body display scaling factor. This will be queried by all Planet objects except for the Moon.
setMinorBodyScale(double f)2826 void SolarSystem::setMinorBodyScale(double f)
2827 {
2828 if(!fuzzyEquals(minorBodyScale, f))
2829 {
2830 minorBodyScale = f;
2831 if(flagMinorBodyScale) //update the bodies with the new scale
2832 {
2833 for (const auto& p : qAsConst(systemPlanets))
2834 {
2835 if(p == moon) continue;
2836 if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
2837 p->setSphereScale(minorBodyScale);
2838 }
2839 }
2840 emit minorBodyScaleChanged(f);
2841 }
2842 }
2843
2844 // Set if Planet display is scaled
setFlagPlanetScale(bool b)2845 void SolarSystem::setFlagPlanetScale(bool b)
2846 {
2847 if(b!=flagPlanetScale)
2848 {
2849 double scale=(b ? planetScale : 1.);
2850 for (auto& p : systemPlanets)
2851 {
2852 if (p->pType==Planet::isPlanet)
2853 p->setSphereScale(scale);
2854 }
2855 flagPlanetScale = b;
2856 emit flagPlanetScaleChanged(b);
2857 }
2858 }
2859
2860 // Set Moon display scaling factor.
setPlanetScale(double f)2861 void SolarSystem::setPlanetScale(double f)
2862 {
2863 if(!fuzzyEquals(planetScale, f))
2864 {
2865 planetScale = f;
2866 if (flagPlanetScale)
2867 for (auto& p : systemPlanets)
2868 {
2869 if (p->pType==Planet::isPlanet)
2870 p->setSphereScale(planetScale);
2871 }
2872 emit planetScaleChanged(f);
2873 }
2874 }
2875
2876 // Set if Sun display is scaled
setFlagSunScale(bool b)2877 void SolarSystem::setFlagSunScale(bool b)
2878 {
2879 if(b!=flagSunScale)
2880 {
2881 if (b) getSun()->setSphereScale(sunScale);
2882 else getSun()->setSphereScale(1);
2883 flagSunScale = b;
2884 emit flagSunScaleChanged(b);
2885 }
2886 }
2887
2888 // Set Sun display scaling factor. This goes directly to the Sun object.
setSunScale(double f)2889 void SolarSystem::setSunScale(double f)
2890 {
2891 if(!fuzzyEquals(sunScale, f))
2892 {
2893 sunScale = f;
2894 if (flagSunScale)
2895 getSun()->setSphereScale(sunScale);
2896 emit sunScaleChanged(f);
2897 }
2898 }
2899
2900 // Set selected planets by englishName
setSelected(const QString & englishName)2901 void SolarSystem::setSelected(const QString& englishName)
2902 {
2903 setSelected(searchByEnglishName(englishName));
2904 }
2905
2906 // Get the list of all the planet english names
getAllPlanetEnglishNames() const2907 QStringList SolarSystem::getAllPlanetEnglishNames() const
2908 {
2909 QStringList res;
2910 for (const auto& p : systemPlanets)
2911 res.append(p->getEnglishName());
2912 return res;
2913 }
2914
getAllPlanetLocalizedNames() const2915 QStringList SolarSystem::getAllPlanetLocalizedNames() const
2916 {
2917 QStringList res;
2918 for (const auto& p : systemPlanets)
2919 res.append(p->getNameI18n());
2920 return res;
2921 }
2922
getAllMinorPlanetCommonEnglishNames() const2923 QStringList SolarSystem::getAllMinorPlanetCommonEnglishNames() const
2924 {
2925 QStringList res;
2926 for (const auto& p : systemMinorBodies)
2927 res.append(p->getCommonEnglishName());
2928 return res;
2929 }
2930
2931
2932 // GZ TODO: This could be modified to only delete&reload the minor objects. For now, we really load both parts again like in the 0.10?-0.15 series.
reloadPlanets()2933 void SolarSystem::reloadPlanets()
2934 {
2935 // Save flag states
2936 const bool flagScaleMoon = getFlagMoonScale();
2937 const double moonScale = getMoonScale();
2938 const bool flagScaleMinorBodies=getFlagMinorBodyScale();
2939 const double minorScale= getMinorBodyScale();
2940 const bool flagPlanets = getFlagPlanets();
2941 const bool flagHints = getFlagHints();
2942 const bool flagLabels = getFlagLabels();
2943 const bool flagOrbits = getFlagOrbits();
2944 const bool flagNative = getFlagNativePlanetNames();
2945 bool hasSelection = false;
2946
2947 // Save observer location (fix for LP bug # 969211)
2948 // TODO: This can probably be done better with a better understanding of StelObserver --BM
2949 StelCore* core = StelApp::getInstance().getCore();
2950 const StelLocation loc = core->getCurrentLocation();
2951 StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr);
2952
2953 // Whether any planet are selected? Save the current selection...
2954 const QList<StelObjectP> selectedObject = objMgr->getSelectedObject("Planet");
2955 if (!selectedObject.isEmpty())
2956 {
2957 // ... unselect current planet.
2958 hasSelection = true;
2959 objMgr->unSelect();
2960 }
2961 // Unload all Solar System objects
2962 selected.clear();//Release the selected one
2963
2964 // GZ TODO in case this methods gets converted to only reload minor bodies: Only delete Orbits which are not referenced by some Planet.
2965 for (auto* orb : qAsConst(orbits))
2966 {
2967 delete orb;
2968 }
2969 orbits.clear();
2970
2971 sun.clear();
2972 moon.clear();
2973 earth.clear();
2974 Planet::texEarthShadow.clear(); //Loaded in loadPlanets()
2975
2976 delete allTrails;
2977 allTrails = Q_NULLPTR;
2978
2979 for (const auto& p : qAsConst(systemPlanets))
2980 {
2981 p->satellites.clear();
2982 }
2983 systemPlanets.clear();
2984 systemMinorBodies.clear();
2985 // Memory leak? What's the proper way of cleaning shared pointers?
2986
2987 // Also delete Comet textures (loaded in loadPlanets()
2988 Comet::tailTexture.clear();
2989 Comet::comaTexture.clear();
2990
2991 // Re-load the ssystem_major.ini and ssystem_minor.ini file
2992 loadPlanets();
2993 computePositions(core->getJDE(), getSun());
2994 setSelected("");
2995 recreateTrails();
2996
2997 // Restore observer location
2998 core->moveObserverTo(loc, 0., 0.);
2999
3000 // Restore flag states
3001 setFlagMoonScale(flagScaleMoon);
3002 setMoonScale(moonScale);
3003 setFlagMinorBodyScale(flagScaleMinorBodies);
3004 setMinorBodyScale(1.0); // force-reset first to really reach the objects in the next call.
3005 setMinorBodyScale(minorScale);
3006 setFlagPlanets(flagPlanets);
3007 setFlagHints(flagHints);
3008 setFlagLabels(flagLabels);
3009 setFlagOrbits(flagOrbits);
3010 setFlagNativePlanetNames(flagNative);
3011
3012 // Restore translations
3013 updateI18n();
3014
3015 if (hasSelection)
3016 {
3017 // Restore selection...
3018 StelObjectP obj = selectedObject[0];
3019 objMgr->findAndSelect(obj->getEnglishName(), obj->getType());
3020 }
3021
3022 emit solarSystemDataReloaded();
3023 }
3024
3025 // Set the algorithm for computation of apparent magnitudes for planets in case observer on the Earth
setApparentMagnitudeAlgorithmOnEarth(QString algorithm)3026 void SolarSystem::setApparentMagnitudeAlgorithmOnEarth(QString algorithm)
3027 {
3028 Planet::setApparentMagnitudeAlgorithm(algorithm);
3029 emit apparentMagnitudeAlgorithmOnEarthChanged(algorithm);
3030 }
3031
3032 // Get the algorithm used for computation of apparent magnitudes for planets in case observer on the Earth
getApparentMagnitudeAlgorithmOnEarth() const3033 QString SolarSystem::getApparentMagnitudeAlgorithmOnEarth() const
3034 {
3035 return Planet::getApparentMagnitudeAlgorithmString();
3036 }
3037
setFlagDrawMoonHalo(bool b)3038 void SolarSystem::setFlagDrawMoonHalo(bool b)
3039 {
3040 Planet::drawMoonHalo=b;
3041 emit flagDrawMoonHaloChanged(b);
3042 }
3043
getFlagDrawMoonHalo() const3044 bool SolarSystem::getFlagDrawMoonHalo() const
3045 {
3046 return Planet::drawMoonHalo;
3047 }
3048
setFlagDrawSunHalo(bool b)3049 void SolarSystem::setFlagDrawSunHalo(bool b)
3050 {
3051 Planet::drawSunHalo=b;
3052 emit flagDrawSunHaloChanged(b);
3053 }
3054
getFlagDrawSunHalo() const3055 bool SolarSystem::getFlagDrawSunHalo() const
3056 {
3057 return Planet::drawSunHalo;
3058 }
3059
setFlagPermanentOrbits(bool b)3060 void SolarSystem::setFlagPermanentOrbits(bool b)
3061 {
3062 Planet::permanentDrawingOrbits=b;
3063 emit flagPermanentOrbitsChanged(b);
3064 }
3065
getFlagPermanentOrbits() const3066 bool SolarSystem::getFlagPermanentOrbits() const
3067 {
3068 return Planet::permanentDrawingOrbits;
3069 }
3070
setOrbitsThickness(int v)3071 void SolarSystem::setOrbitsThickness(int v)
3072 {
3073 Planet::orbitsThickness=v;
3074 emit orbitsThicknessChanged(v);
3075 }
3076
getOrbitsThickness() const3077 int SolarSystem::getOrbitsThickness() const
3078 {
3079 return Planet::orbitsThickness;
3080 }
3081
3082
setFlagCustomGrsSettings(bool b)3083 void SolarSystem::setFlagCustomGrsSettings(bool b)
3084 {
3085 RotationElements::flagCustomGrsSettings=b;
3086 // automatic saving of the setting
3087 conf->setValue("astro/flag_grs_custom", b);
3088 emit flagCustomGrsSettingsChanged(b);
3089 }
3090
getFlagCustomGrsSettings() const3091 bool SolarSystem::getFlagCustomGrsSettings() const
3092 {
3093 return RotationElements::flagCustomGrsSettings;
3094 }
3095
setCustomGrsLongitude(int longitude)3096 void SolarSystem::setCustomGrsLongitude(int longitude)
3097 {
3098 RotationElements::customGrsLongitude = longitude;
3099 // automatic saving of the setting
3100 conf->setValue("astro/grs_longitude", longitude);
3101 emit customGrsLongitudeChanged(longitude);
3102 }
3103
getCustomGrsLongitude() const3104 int SolarSystem::getCustomGrsLongitude() const
3105 {
3106 return RotationElements::customGrsLongitude;
3107 }
3108
setCustomGrsDrift(double drift)3109 void SolarSystem::setCustomGrsDrift(double drift)
3110 {
3111 RotationElements::customGrsDrift = drift;
3112 // automatic saving of the setting
3113 conf->setValue("astro/grs_drift", drift);
3114 emit customGrsDriftChanged(drift);
3115 }
3116
getCustomGrsDrift() const3117 double SolarSystem::getCustomGrsDrift() const
3118 {
3119 return RotationElements::customGrsDrift;
3120 }
3121
setCustomGrsJD(double JD)3122 void SolarSystem::setCustomGrsJD(double JD)
3123 {
3124 RotationElements::customGrsJD = JD;
3125 // automatic saving of the setting
3126 conf->setValue("astro/grs_jd", JD);
3127 emit customGrsJDChanged(JD);
3128 }
3129
getCustomGrsJD()3130 double SolarSystem::getCustomGrsJD()
3131 {
3132 return RotationElements::customGrsJD;
3133 }
3134
setFlagEarthShadowEnlargementDanjon(bool b)3135 void SolarSystem::setFlagEarthShadowEnlargementDanjon(bool b)
3136 {
3137 earthShadowEnlargementDanjon=b;
3138 emit earthShadowEnlargementDanjonChanged(b);
3139 }
3140
getFlagEarthShadowEnlargementDanjon() const3141 bool SolarSystem::getFlagEarthShadowEnlargementDanjon() const
3142 {
3143 return earthShadowEnlargementDanjon;
3144 }
3145
setOrbitColorStyle(QString style)3146 void SolarSystem::setOrbitColorStyle(QString style)
3147 {
3148 if (style.toLower()=="groups")
3149 Planet::orbitColorStyle = Planet::ocsGroups;
3150 else if (style.toLower()=="major_planets")
3151 Planet::orbitColorStyle = Planet::ocsMajorPlanets;
3152 else
3153 Planet::orbitColorStyle = Planet::ocsOneColor;
3154 }
3155
getOrbitColorStyle() const3156 QString SolarSystem::getOrbitColorStyle() const
3157 {
3158 QString r = "one_color";
3159 switch (Planet::orbitColorStyle)
3160 {
3161 case Planet::ocsOneColor:
3162 r = "one_color";
3163 break;
3164 case Planet::ocsGroups:
3165 r = "groups";
3166 break;
3167 case Planet::ocsMajorPlanets:
3168 r = "major_planets";
3169 break;
3170 }
3171 return r;
3172 }
3173
3174 // TODO: To make the code better understandable, get rid of planet->computeModelMatrix(trans, true) here.
getSolarEclipseFactor(const StelCore * core) const3175 QPair<double, PlanetP> SolarSystem::getSolarEclipseFactor(const StelCore* core) const
3176 {
3177 PlanetP p;
3178 const Vec3d Lp = sun->getEclipticPos() + sun->getAberrationPush();
3179 const Vec3d P3 = core->getObserverHeliocentricEclipticPos();
3180 const double RS = sun->getEquatorialRadius();
3181
3182 double final_illumination = 1.0;
3183
3184 for (const auto& planet : systemPlanets)
3185 {
3186 if(planet == sun || planet == core->getCurrentPlanet())
3187 continue;
3188
3189 Mat4d trans;
3190 planet->computeModelMatrix(trans, true);
3191
3192 const Vec3d C = trans * Vec3d(0., 0., 0.);
3193 const double radius = planet->getEquatorialRadius();
3194
3195 Vec3d v1 = Lp - P3;
3196 Vec3d v2 = C - P3;
3197 const double L = v1.length();
3198 const double l = v2.length();
3199 v1 /= L;
3200 v2 /= l;
3201
3202 const double R = RS / L;
3203 const double r = radius / l;
3204 const double d = ( v1 - v2 ).length();
3205 double illumination;
3206
3207 if(d >= R + r) // distance too far
3208 {
3209 illumination = 1.0;
3210 }
3211 else if(d <= r - R) // umbra
3212 {
3213 illumination = 0.0;
3214 }
3215 else if(d <= R - r) // penumbra completely inside
3216 {
3217 illumination = 1.0 - r * r / (R * R);
3218 }
3219 else // penumbra partially inside
3220 {
3221 const double x = (R * R + d * d - r * r) / (2.0 * d);
3222
3223 const double alpha = std::acos(x / R);
3224 const double beta = std::acos((d - x) / r);
3225
3226 const double AR = R * R * (alpha - 0.5 * std::sin(2.0 * alpha));
3227 const double Ar = r * r * (beta - 0.5 * std::sin(2.0 * beta));
3228 const double AS = R * R * 2.0 * std::asin(1.0);
3229
3230 illumination = 1.0 - (AR + Ar) / AS;
3231 }
3232
3233 if(illumination < final_illumination)
3234 {
3235 final_illumination = illumination;
3236 p = planet;
3237 }
3238 }
3239
3240 return QPair<double, PlanetP>(final_illumination, p);
3241 }
3242
3243 // Retrieve Radius of Umbra and Penumbra at the distance of the Moon.
3244 // Returns a pair (umbra, penumbra) in (geocentric_arcseconds, AU, geometric_AU).
3245 // * sizes in arcseconds are the usual result found as Bessel element in eclipse literature.
3246 // It includes scaling for effects of atmosphere either after Chauvenet (2%) or after Danjon. (see Espenak: 5000 Years Canon of Lunar Eclipses.)
3247 // * sizes in AU are the same, converted back to AU in Lunar distance.
3248 // * sizes in geometric_AU derived from pure geometrical evaluations without scalings applied.
getEarthShadowRadiiAtLunarDistance() const3249 QPair<Vec3d,Vec3d> SolarSystem::getEarthShadowRadiiAtLunarDistance() const
3250 {
3251 // Note: The application of this shadow enlargement is not according to the books, but looks close enough for now.
3252 static const double sun2earth=sun->getEquatorialRadius() / earth->getEquatorialRadius();
3253 PlanetP sun=getSun();
3254 PlanetP moon=getMoon();
3255 PlanetP earth=getEarth();
3256 const double lunarDistance=moon->getEclipticPos().length(); // Lunar distance [AU]
3257 const double earthDistance=earth->getHeliocentricEclipticPos().length(); // Earth distance [AU]
3258 const double sunHP =asin(earth->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec.
3259 const double moonHP=asin(earth->getEquatorialRadius()/lunarDistance) * M_180_PI*3600.; // arcsec.
3260 const double sunSD =atan(sun->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec.
3261
3262 // Compute umbra radius at lunar distance.
3263 const double lUmbra=earthDistance/(sun2earth-1.); // length of earth umbra [AU]
3264 const double rUmbraAU=earth->getEquatorialRadius()*(lUmbra-lunarDistance)/lUmbra; // radius of earth shadow at lunar distance [AU]
3265 // Penumbra:
3266 const double lPenumbra=earthDistance/(sun2earth + 1.); // distance between earth and point between sun and earth where penumbral border rays intersect
3267 const double rPenumbraAU=earth->getEquatorialRadius()*(lPenumbra+lunarDistance)/lPenumbra; // radius of penumbra at Lunar distance [AU]
3268
3269 //Classical Bessel elements instead
3270 double f1, f2;
3271 if (earthShadowEnlargementDanjon)
3272 {
3273 static const double danjonScale=1+1./85.-1./594.; // ~1.01, shadow magnification factor (see Espenak 5000 years Canon)
3274 f1=danjonScale*moonHP + sunHP + sunSD; // penumbra radius, arcsec
3275 f2=danjonScale*moonHP + sunHP - sunSD; // umbra radius, arcsec
3276 }
3277 else
3278 {
3279 const double mHP1=0.998340*moonHP;
3280 f1=1.02*(mHP1 + sunHP + sunSD); // penumbra radius, arcsec
3281 f2=1.02*(mHP1 + sunHP - sunSD); // umbra radius, arcsec
3282 }
3283 const double f1_AU=tan(f1/3600.*M_PI_180)*lunarDistance;
3284 const double f2_AU=tan(f2/3600.*M_PI_180)*lunarDistance;
3285 return QPair<Vec3d,Vec3d>(Vec3d(f2, f2_AU, rUmbraAU), Vec3d(f1, f1_AU, rPenumbraAU));
3286 }
3287
removeMinorPlanet(QString name)3288 bool SolarSystem::removeMinorPlanet(QString name)
3289 {
3290 PlanetP candidate = searchMinorPlanetByEnglishName(name);
3291 if (!candidate)
3292 {
3293 qWarning() << "Cannot remove planet " << name << ": Not found.";
3294 return false;
3295 }
3296 Orbit* orbPtr=static_cast<Orbit*>(candidate->orbitPtr);
3297 if (orbPtr)
3298 orbits.removeOne(orbPtr);
3299 systemPlanets.removeOne(candidate);
3300 systemMinorBodies.removeOne(candidate);
3301 candidate.clear();
3302 return true;
3303 }
3304
onNewSurvey(HipsSurveyP survey)3305 void SolarSystem::onNewSurvey(HipsSurveyP survey)
3306 {
3307 // For the moment we only consider the survey url to decide if we
3308 // assign it to a planet. It would be better to use some property
3309 // for that.
3310 QString planetName = QUrl(survey->getUrl()).fileName();
3311 PlanetP pl = searchByEnglishName(planetName);
3312 if (!pl || pl->survey)
3313 return;
3314 pl->survey = survey;
3315 survey->setProperty("planet", pl->getCommonEnglishName());
3316 // Not visible by default for the moment.
3317 survey->setProperty("visible", false);
3318 }
3319