• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 5926409083

21 Aug 2023 12:45PM UTC coverage: 11.905% (+0.01%) from 11.891%
5926409083

Pull #3373

github

gzotti
Reduce verbosity a bit.
Pull Request #3373: Fix: unambiguous comet names

264 of 264 new or added lines in 9 files covered. (100.0%)

14845 of 124700 relevant lines covered (11.9%)

23289.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/core/modules/SolarSystem.cpp
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

47
#include "AstroCalcDialog.hpp"
48
#include "StelObserver.hpp"
49

50
#include <algorithm>
51

52
#include <QTextStream>
53
#include <QSettings>
54
#include <QVariant>
55
#include <QString>
56
#include <QStringList>
57
#include <QMap>
58
#include <QMultiMap>
59
#include <QMapIterator>
60
#include <QDebug>
61
#include <QDir>
62
#include <QHash>
63

64
SolarSystem::SolarSystem() : StelObjectModule()
×
65
        , shadowPlanetCount(0)
×
66
        , earthShadowEnlargementDanjon(false)
×
67
        , flagMoonScale(false)
×
68
        , moonScale(1.0)
×
69
        , flagMinorBodyScale(false)
×
70
        , minorBodyScale(1.0)
×
71
        , flagPlanetScale(false)
×
72
        , planetScale(1.0)
×
73
        , flagSunScale(false)
×
74
        , sunScale(1.0)
×
75
        , labelsAmount(false)
×
76
        , flagPermanentSolarCorona(true)
×
77
        , flagOrbits(false)
×
78
        , flagLightTravelTime(true)
×
79
        , flagUseObjModels(false)
×
80
        , flagShowObjSelfShadows(true)
×
81
        , flagShow(false)
×
82
        , flagPointer(false)
×
83
        , flagNativePlanetNames(false)
×
84
        , flagIsolatedTrails(true)
×
85
        , numberIsolatedTrails(0)
×
86
        , maxTrailPoints(5000)
×
87
        , maxTrailTimeExtent(1)
×
88
        , trailsThickness(1)
×
89
        , flagIsolatedOrbits(true)
×
90
        , flagPlanetsOrbitsOnly(false)
×
91
        , flagOrbitsWithMoons(false)
×
92
        , ephemerisMarkersDisplayed(true)
×
93
        , ephemerisDatesDisplayed(false)
×
94
        , ephemerisMagnitudesDisplayed(false)
×
95
        , ephemerisHorizontalCoordinates(false)
×
96
        , ephemerisLineDisplayed(false)
×
97
        , ephemerisAlwaysOn(false)
×
98
        , ephemerisNow(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
        connect(this, SIGNAL(flagOrbitsChanged(bool)),            this, SLOT(reconfigureOrbits()));
×
121
        connect(this, SIGNAL(flagPlanetsOrbitsOnlyChanged(bool)), this, SLOT(reconfigureOrbits()));
×
122
        connect(this, SIGNAL(flagIsolatedOrbitsChanged(bool)),    this, SLOT(reconfigureOrbits()));
×
123
        connect(this, SIGNAL(flagOrbitsWithMoonsChanged(bool)),   this, SLOT(reconfigureOrbits()));
×
124
}
×
125

126
void SolarSystem::setFontSize(int newFontSize)
×
127
{
128
        planetNameFont.setPixelSize(newFontSize);
×
129
}
×
130

131
SolarSystem::~SolarSystem()
×
132
{
133
        // release selected:
134
        selected.clear();
×
135
        selectedSSO.clear();
×
136
        for (auto* orb : qAsConst(orbits))
×
137
        {
138
                delete orb;
×
139
                orb = Q_NULLPTR;
×
140
        }
141
        sun.clear();
×
142
        moon.clear();
×
143
        earth.clear();
×
144
        Planet::hintCircleTex.clear();
×
145
        Planet::texEarthShadow.clear();
×
146

147
        texEphemerisMarker.clear();
×
148
        texEphemerisCometMarker.clear();
×
149
        texEphemerisNowMarker.clear();
×
150
        texPointer.clear();
×
151

152
        delete allTrails;
×
153
        allTrails = Q_NULLPTR;
×
154

155
        // Get rid of circular reference between the shared pointers which prevent proper destruction of the Planet objects.
156
        for (const auto& p : qAsConst(systemPlanets))
×
157
        {
158
                p->satellites.clear();
×
159
        }
160

161
        //delete comet textures created in loadPlanets
162
        Comet::comaTexture.clear();
×
163
        Comet::tailTexture.clear();
×
164

165
        //deinit of SolarSystem is NOT called at app end automatically
166
        SolarSystem::deinit();
×
167
}
×
168

169
/*************************************************************************
170
 Re-implementation of the getCallOrder method
171
*************************************************************************/
172
double SolarSystem::getCallOrder(StelModuleActionName actionName) const
×
173
{
174
        if (actionName==StelModule::ActionDraw)
×
175
                return StelApp::getInstance().getModuleMgr().getModule("StarMgr")->getCallOrder(actionName)+10;
×
176
        return 0;
×
177
}
178

179
// Init and load the solar system data
180
void SolarSystem::init()
×
181
{
182
        Q_ASSERT(conf);
×
183

184
        Planet::init();
×
185
        loadPlanets();        // Load planets data
×
186

187
        // Compute position and matrix of sun and all the satellites (ie planets)
188
        // for the first initialization Q_ASSERT that center is sun center (only impacts on light speed correction)        
189
        computePositions(StelApp::getInstance().getCore()->getJDE(), getSun());
×
190

191
        setSelected("");        // Fix a bug on macosX! Thanks Fumio!
×
192
        setFlagDrawMoonHalo(conf->value("viewing/flag_draw_moon_halo", true).toBool());
×
193
        setFlagDrawSunHalo(conf->value("viewing/flag_draw_sun_halo", true).toBool());
×
194
        setFlagMoonScale(conf->value("viewing/flag_moon_scaled", conf->value("viewing/flag_init_moon_scaled", false).toBool()).toBool());  // name change
×
195
        setMoonScale(conf->value("viewing/moon_scale", 4.0).toDouble());
×
196
        setMinorBodyScale(conf->value("viewing/minorbodies_scale", 10.0).toDouble());
×
197
        setFlagMinorBodyScale(conf->value("viewing/flag_minorbodies_scaled", false).toBool());
×
198
        setFlagPlanetScale(conf->value("viewing/flag_planets_scaled", false).toBool());
×
199
        setPlanetScale(conf->value("viewing/planets_scale", 150.0).toDouble());
×
200
        setFlagSunScale(conf->value("viewing/flag_sun_scaled", false).toBool());
×
201
        setSunScale(conf->value("viewing/sun_scale", 4.0).toDouble());
×
202
        setFlagPlanets(conf->value("astro/flag_planets").toBool());
×
203
        setFlagHints(conf->value("astro/flag_planets_hints").toBool());
×
204
        setFlagLabels(conf->value("astro/flag_planets_labels", true).toBool());
×
205
        setLabelsAmount(conf->value("astro/labels_amount", 3.).toDouble());
×
206
        setFlagOrbits(conf->value("astro/flag_planets_orbits").toBool());
×
207
        setFlagLightTravelTime(conf->value("astro/flag_light_travel_time", true).toBool());
×
208
        setFlagUseObjModels(conf->value("astro/flag_use_obj_models", false).toBool());
×
209
        setFlagShowObjSelfShadows(conf->value("astro/flag_show_obj_self_shadows", true).toBool());
×
210
        setFlagPointer(conf->value("astro/flag_planets_pointers", true).toBool());
×
211
        // Set the algorithm from Astronomical Almanac for computation of apparent magnitudes for
212
        // planets in case  observer on the Earth by default
213
        setApparentMagnitudeAlgorithmOnEarth(conf->value("astro/apparent_magnitude_algorithm", "Mallama2018").toString());
×
214
        setFlagNativePlanetNames(conf->value("viewing/flag_planets_native_names", true).toBool());
×
215
        // Is enabled the showing of isolated trails for selected objects only?
216
        setFlagIsolatedTrails(conf->value("viewing/flag_isolated_trails", true).toBool());
×
217
        setNumberIsolatedTrails(conf->value("viewing/number_isolated_trails", 1).toInt());
×
218
        setMaxTrailPoints(conf->value("viewing/max_trail_points", 5000).toInt());
×
219
        setMaxTrailTimeExtent(conf->value("viewing/max_trail_time_extent", 1).toInt());
×
220
        setFlagIsolatedOrbits(conf->value("viewing/flag_isolated_orbits", true).toBool());
×
221
        setFlagPlanetsOrbitsOnly(conf->value("viewing/flag_planets_orbits_only", false).toBool());
×
222
        setFlagOrbitsWithMoons(conf->value("viewing/flag_orbits_with_moons", false).toBool());
×
223
        setFlagPermanentOrbits(conf->value("astro/flag_permanent_orbits", false).toBool());
×
224
        setOrbitColorStyle(conf->value("astro/planets_orbits_color_style", "one_color").toString());
×
225

226
        // Settings for calculation of position of Great Red Spot on Jupiter
227
        setGrsLongitude(conf->value("astro/grs_longitude", 216).toInt());
×
228
        setGrsDrift(conf->value("astro/grs_drift", 15.).toDouble());
×
229
        setGrsJD(conf->value("astro/grs_jd", 2456901.5).toDouble());
×
230

231
        setFlagEarthShadowEnlargementDanjon(conf->value("astro/shadow_enlargement_danjon", false).toBool());
×
232
        setFlagPermanentSolarCorona(conf->value("viewing/flag_draw_sun_corona", true).toBool());
×
233

234
        // Load colors from config file
235
        QString defaultColor = conf->value("color/default_color").toString();
×
236
        setLabelsColor(                    Vec3f(conf->value("color/planet_names_color", defaultColor).toString()));
×
237
        setOrbitsColor(                    Vec3f(conf->value("color/sso_orbits_color", defaultColor).toString()));
×
238
        setMajorPlanetsOrbitsColor(        Vec3f(conf->value("color/major_planet_orbits_color", "0.7,0.2,0.2").toString()));
×
239
        setMoonsOrbitsColor(               Vec3f(conf->value("color/moon_orbits_color", "0.7,0.2,0.2").toString()));
×
240
        setMinorPlanetsOrbitsColor(        Vec3f(conf->value("color/minor_planet_orbits_color", "0.7,0.5,0.5").toString()));
×
241
        setDwarfPlanetsOrbitsColor(        Vec3f(conf->value("color/dwarf_planet_orbits_color", "0.7,0.5,0.5").toString()));
×
242
        setCubewanosOrbitsColor(           Vec3f(conf->value("color/cubewano_orbits_color", "0.7,0.5,0.5").toString()));
×
243
        setPlutinosOrbitsColor(            Vec3f(conf->value("color/plutino_orbits_color", "0.7,0.5,0.5").toString()));
×
244
        setScatteredDiskObjectsOrbitsColor(Vec3f(conf->value("color/sdo_orbits_color", "0.7,0.5,0.5").toString()));
×
245
        setOortCloudObjectsOrbitsColor(    Vec3f(conf->value("color/oco_orbits_color", "0.7,0.5,0.5").toString()));
×
246
        setCometsOrbitsColor(              Vec3f(conf->value("color/comet_orbits_color", "0.7,0.8,0.8").toString()));
×
247
        setSednoidsOrbitsColor(            Vec3f(conf->value("color/sednoid_orbits_color", "0.7,0.5,0.5").toString()));
×
248
        setInterstellarOrbitsColor(        Vec3f(conf->value("color/interstellar_orbits_color", "1.0,0.6,1.0").toString()));
×
249
        setMercuryOrbitColor(              Vec3f(conf->value("color/mercury_orbit_color", "0.5,0.5,0.5").toString()));
×
250
        setVenusOrbitColor(                Vec3f(conf->value("color/venus_orbit_color", "0.9,0.9,0.7").toString()));
×
251
        setEarthOrbitColor(                Vec3f(conf->value("color/earth_orbit_color", "0.0,0.0,1.0").toString()));
×
252
        setMarsOrbitColor(                 Vec3f(conf->value("color/mars_orbit_color", "0.8,0.4,0.1").toString()));
×
253
        setJupiterOrbitColor(              Vec3f(conf->value("color/jupiter_orbit_color", "1.0,0.6,0.0").toString()));
×
254
        setSaturnOrbitColor(               Vec3f(conf->value("color/saturn_orbit_color", "1.0,0.8,0.0").toString()));
×
255
        setUranusOrbitColor(               Vec3f(conf->value("color/uranus_orbit_color", "0.0,0.7,1.0").toString()));
×
256
        setNeptuneOrbitColor(              Vec3f(conf->value("color/neptune_orbit_color", "0.0,0.3,1.0").toString()));
×
257
        setTrailsColor(                    Vec3f(conf->value("color/object_trails_color", defaultColor).toString()));
×
258
        setPointerColor(                   Vec3f(conf->value("color/planet_pointers_color", "1.0,0.3,0.3").toString()));
×
259

260
        // Ephemeris stuff
261
        setFlagEphemerisMarkers(conf->value("astrocalc/flag_ephemeris_markers", true).toBool());
×
262
        setFlagEphemerisAlwaysOn(conf->value("astrocalc/flag_ephemeris_alwayson", true).toBool());
×
263
        setFlagEphemerisNow(conf->value("astrocalc/flag_ephemeris_now", false).toBool());
×
264
        setFlagEphemerisDates(conf->value("astrocalc/flag_ephemeris_dates", false).toBool());
×
265
        setFlagEphemerisMagnitudes(conf->value("astrocalc/flag_ephemeris_magnitudes", false).toBool());
×
266
        setFlagEphemerisHorizontalCoordinates(conf->value("astrocalc/flag_ephemeris_horizontal", false).toBool());
×
267
        setFlagEphemerisLine(conf->value("astrocalc/flag_ephemeris_line", false).toBool());
×
268
        setEphemerisLineThickness(conf->value("astrocalc/ephemeris_line_thickness", 1).toInt());
×
269
        setFlagEphemerisSkipData(conf->value("astrocalc/flag_ephemeris_skip_data", false).toBool());
×
270
        setFlagEphemerisSkipMarkers(conf->value("astrocalc/flag_ephemeris_skip_markers", false).toBool());
×
271
        setEphemerisDataStep(conf->value("astrocalc/ephemeris_data_step", 1).toInt());        
×
272
        setFlagEphemerisSmartDates(conf->value("astrocalc/flag_ephemeris_smart_dates", true).toBool());
×
273
        setFlagEphemerisScaleMarkers(conf->value("astrocalc/flag_ephemeris_scale_markers", false).toBool());
×
274
        setEphemerisGenericMarkerColor( Vec3f(conf->value("color/ephemeris_generic_marker_color", "1.0,1.0,0.0").toString()));
×
275
        setEphemerisSecondaryMarkerColor( Vec3f(conf->value("color/ephemeris_secondary_marker_color", "0.7,0.7,1.0").toString()));
×
276
        setEphemerisSelectedMarkerColor(Vec3f(conf->value("color/ephemeris_selected_marker_color", "1.0,0.7,0.0").toString()));
×
277
        setEphemerisMercuryMarkerColor( Vec3f(conf->value("color/ephemeris_mercury_marker_color", "1.0,1.0,0.0").toString()));
×
278
        setEphemerisVenusMarkerColor(   Vec3f(conf->value("color/ephemeris_venus_marker_color", "1.0,1.0,1.0").toString()));
×
279
        setEphemerisMarsMarkerColor(    Vec3f(conf->value("color/ephemeris_mars_marker_color", "1.0,0.0,0.0").toString()));
×
280
        setEphemerisJupiterMarkerColor( Vec3f(conf->value("color/ephemeris_jupiter_marker_color", "0.3,1.0,1.0").toString()));
×
281
        setEphemerisSaturnMarkerColor(  Vec3f(conf->value("color/ephemeris_saturn_marker_color", "0.0,1.0,0.0").toString()));
×
282

283
        setOrbitsThickness(conf->value("astro/object_orbits_thickness", 1).toInt());
×
284
        setTrailsThickness(conf->value("astro/object_trails_thickness", 1).toInt());
×
285
        recreateTrails();
×
286
        setFlagTrails(conf->value("astro/flag_object_trails", false).toBool());
×
287

288
        StelObjectMgr *objectManager = GETSTELMODULE(StelObjectMgr);
×
289
        objectManager->registerStelObjectMgr(this);
×
290
        connect(objectManager, SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)),
×
291
                this, SLOT(selectedObjectChange(StelModule::StelModuleSelectAction)));
292

293
        texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur4.png");
×
294
        texEphemerisMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/disk.png");
×
295
        texEphemerisNowMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/gear.png");
×
296
        texEphemerisCometMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/cometIcon.png");
×
297
        Planet::hintCircleTex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/planet-indicator.png");
×
298
        
299
        StelApp *app = &StelApp::getInstance();
×
300
        connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
×
301
        connect(&app->getSkyCultureMgr(), SIGNAL(currentSkyCultureChanged(QString)), this, SLOT(updateSkyCulture(QString)));
×
302
        connect(&StelMainView::getInstance(), SIGNAL(reloadShadersRequested()), this, SLOT(reloadShaders()));
×
303
        StelCore *core = app->getCore();
×
304
        connect(core, SIGNAL(locationChanged(StelLocation)), this, SLOT(recreateTrails()));
×
305
        connect(core, SIGNAL(dateChangedForTrails()), this, SLOT(recreateTrails()));
×
306

307
        QString displayGroup = N_("Display Options");
×
308
        addAction("actionShow_Planets", displayGroup, N_("Planets"), "planetsDisplayed", "P");
×
309
        addAction("actionShow_Planets_Labels", displayGroup, N_("Planet labels"), "labelsDisplayed", "Alt+P");
×
310
        addAction("actionShow_Planets_Orbits", displayGroup, N_("Planet orbits"), "flagOrbits", "O");
×
311
        addAction("actionShow_Planets_Trails", displayGroup, N_("Planet trails"), "trailsDisplayed", "Shift+T");
×
312
        addAction("actionShow_Planets_Trails_Reset", displayGroup, N_("Planet trails reset"), "recreateTrails()"); // No hotkey predefined.
×
313
        //there is a small discrepancy in the GUI: "Show planet markers" actually means show planet hints
314
        addAction("actionShow_Planets_Hints", displayGroup, N_("Planet markers"), "flagHints", "Ctrl+P");
×
315
        addAction("actionShow_Planets_Pointers", displayGroup, N_("Planet selection marker"), "flagPointer", "Ctrl+Shift+P");
×
316
        addAction("actionShow_Planets_EnlargeMoon", displayGroup, N_("Enlarge Moon"), "flagMoonScale");
×
317
        addAction("actionShow_Planets_EnlargeMinor", displayGroup, N_("Enlarge minor bodies"), "flagMinorBodyScale");
×
318
        addAction("actionShow_Planets_EnlargePlanets", displayGroup, N_("Enlarge Planets"), "flagPlanetScale");
×
319
        addAction("actionShow_Planets_EnlargeSun", displayGroup, N_("Enlarge Sun"), "flagSunScale");
×
320
        addAction("actionShow_Skyculture_NativePlanetNames", displayGroup, N_("Native planet names (from starlore)"), "flagNativePlanetNames", "Ctrl+Shift+N");
×
321

322
        connect(StelApp::getInstance().getModule("HipsMgr"), SIGNAL(gotNewSurvey(HipsSurveyP)),
×
323
                        this, SLOT(onNewSurvey(HipsSurveyP)));
324

325
        // Fill ephemeris dates
326
        connect(this, SIGNAL(requestEphemerisVisualization()), this, SLOT(fillEphemerisDates()));
×
327
        connect(this, SIGNAL(ephemerisDataStepChanged(int)), this, SLOT(fillEphemerisDates()));
×
328
        connect(this, SIGNAL(ephemerisSkipDataChanged(bool)), this, SLOT(fillEphemerisDates()));
×
329
        connect(this, SIGNAL(ephemerisSkipMarkersChanged(bool)), this, SLOT(fillEphemerisDates()));
×
330
        connect(this, SIGNAL(ephemerisSmartDatesChanged(bool)), this, SLOT(fillEphemerisDates()));
×
331
}
×
332

333
void SolarSystem::deinit()
×
334
{
335
        Planet::deinitShader();
×
336
        Planet::deinitFBO();
×
337
}
×
338

339
void SolarSystem::resetTextures(const QString &planetName)
×
340
{
341
        if (planetName.isEmpty())
×
342
        {
343
                for (const auto& p : qAsConst(systemPlanets))
×
344
                {
345
                        p->resetTextures();
×
346
                }
347
        }
348
        else
349
        {
350
                PlanetP planet = searchByEnglishName(planetName);
×
351
                if (!planet.isNull())
×
352
                        planet->resetTextures();
×
353
        }
×
354
}
×
355

356
void SolarSystem::setTextureForPlanet(const QString& planetName, const QString& texName)
×
357
{
358
        PlanetP planet = searchByEnglishName(planetName);
×
359
        if (!planet.isNull())
×
360
                planet->replaceTexture(texName);
×
361
        else
362
                qWarning() << "The planet" << planetName << "was not found. Please check the name.";
×
363
}
×
364

365
void SolarSystem::recreateTrails()
×
366
{
367
        // Create a trail group containing all the planets orbiting the sun (not including satellites)
368
        if (allTrails!=Q_NULLPTR)
×
369
                delete allTrails;
×
370
        allTrails = new TrailGroup(maxTrailTimeExtent * 365.f, maxTrailPoints);
×
371

372
        unsigned long cnt = static_cast<unsigned long>(selectedSSO.size());
×
373
        if (cnt>0 && getFlagIsolatedTrails())
×
374
        {
375
                unsigned long limit = static_cast<unsigned long>(getNumberIsolatedTrails());
×
376
                if (cnt<limit)
×
377
                        limit = cnt;
×
378
                for (unsigned long i=0; i<limit; i++)
×
379
                {
380
                        if (selectedSSO[cnt - i - 1]->getPlanetType() != Planet::isObserver)
×
381
                                allTrails->addObject(static_cast<QSharedPointer<StelObject>>(selectedSSO[cnt - i - 1]), &trailsColor);
×
382
                }
383
        }
384
        else
385
        {
386
                for (const auto& p : qAsConst(getSun()->satellites))
×
387
                {
388
                        if (p->getPlanetType() != Planet::isObserver)
×
389
                                allTrails->addObject(static_cast<QSharedPointer<StelObject>>(p), &trailsColor);
×
390
                }
391
                // Add moons of current planet
392
                StelCore *core=StelApp::getInstance().getCore();
×
393
                const StelObserver *obs=core->getCurrentObserver();
×
394
                if (obs)
×
395
                {
396
                        const QSharedPointer<Planet> planet=obs->getHomePlanet();
×
397
                        for (const auto& m : qAsConst(planet->satellites))
×
398
                                if (m->getPlanetType() != Planet::isObserver)
×
399
                                        allTrails->addObject(static_cast<QSharedPointer<StelObject>>(m), &trailsColor);
×
400
                }
×
401
        }
402
}
×
403

404

405
void SolarSystem::updateSkyCulture(const QString& skyCultureDir)
×
406
{
407
        planetNativeNamesMap.clear();
×
408
        planetNativeNamesMeaningMap.clear();
×
409

410
        QString namesFile = StelFileMgr::findFile("skycultures/" + skyCultureDir + "/planet_names.fab");
×
411

412
        if (namesFile.isEmpty())
×
413
        {
414
                for (const auto& p : qAsConst(systemPlanets))
×
415
                {
416
                        if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
×
417
                        {
418
                                p->setNativeName("");
×
419
                                p->setNativeNameMeaning("");
×
420
                        }
421
                }
422
                updateI18n();
×
423
                return;
×
424
        }
425

426
        // Open file
427
        QFile planetNamesFile(namesFile);
×
428
        if (!planetNamesFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
429
        {
430
                qDebug() << " Cannot open file" << QDir::toNativeSeparators(namesFile);
×
431
                return;
×
432
        }
433

434
        // Now parse the file
435
        // lines to ignore which start with a # or are empty
436
        static const QRegularExpression commentRx("^(\\s*#.*|\\s*)$");
×
437

438
        // lines which look like records - we use the RE to extract the fields
439
        // which will be available in recRx.capturedTexts()
440
        static const QRegularExpression recRx("^\\s*(\\w+)\\s+\"(.+)\"\\s+_[(]\"(.+)\"[)]\\n");
×
441

442
        QString record, planetId, nativeName, nativeNameMeaning;
×
443

444
        // keep track of how many records we processed.
445
        int totalRecords=0;
×
446
        int readOk=0;
×
447
        int lineNumber=0;
×
448
        while (!planetNamesFile.atEnd())
×
449
        {
450
                record = QString::fromUtf8(planetNamesFile.readLine());
×
451
                lineNumber++;
×
452

453
                // Skip comments
454
                if (commentRx.match(record).hasMatch())
×
455
                        continue;
×
456

457
                totalRecords++;
×
458

459
                QRegularExpressionMatch match=recRx.match(record);
×
460
                if (!match.hasMatch())
×
461
                {
462
                        qWarning() << "ERROR - cannot parse record at line" << lineNumber << "in planet names file" << QDir::toNativeSeparators(namesFile);
×
463
                }
464
                else
465
                {
466
                        planetId          = match.captured(1).trimmed();
×
467
                        nativeName        = match.captured(2).trimmed();
×
468
                        nativeNameMeaning = match.captured(3).trimmed();
×
469
                        planetNativeNamesMap[planetId] = nativeName;
×
470
                        planetNativeNamesMeaningMap[planetId] = nativeNameMeaning;
×
471
                        readOk++;
×
472
                }
473
        }
×
474
        planetNamesFile.close();
×
475
        qDebug() << "Loaded" << readOk << "/" << totalRecords << "native names of planets";
×
476

477
        for (const auto& p : qAsConst(systemPlanets))
×
478
        {
479
                if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
×
480
                {
481
                        p->setNativeName(planetNativeNamesMap[p->getEnglishName()]);
×
482
                        p->setNativeNameMeaning(planetNativeNamesMeaningMap[p->getEnglishName()]);
×
483
                }
484
        }
485

486
        updateI18n();
×
487
}
×
488

489
void SolarSystem::reloadShaders()
×
490
{
491
        Planet::deinitShader();
×
492
        Planet::initShader();
×
493
}
×
494

495
void SolarSystem::drawPointer(const StelCore* core)
×
496
{
497
        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
498

499
        const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet");
×
500
        if (!newSelected.empty())
×
501
        {
502
                const StelObjectP obj = newSelected[0];
×
503
                Vec3d pos=obj->getJ2000EquatorialPos(core);
×
504

505
                Vec3f screenpos;
×
506
                // Compute 2D pos and return if outside screen
507
                if (!prj->project(pos, screenpos))
×
508
                        return;
×
509

510
                StelPainter sPainter(prj);
×
511
                sPainter.setColor(getPointerColor());
×
512

513
                float screenSize = static_cast<float>(obj->getAngularRadius(core))*prj->getPixelPerRadAtCenter()*M_PI_180f*2.f;
×
514
                
515
                const float scale = static_cast<float>(prj->getDevicePixelsPerPixel())*StelApp::getInstance().getGlobalScalingRatio();
×
516
                screenSize+= scale * (45.f + 10.f*std::sin(2.f * static_cast<float>(StelApp::getInstance().getAnimationTime())));
×
517

518
                texPointer->bind();
×
519

520
                sPainter.setBlending(true);
×
521

522
                screenSize*=0.5f;
×
523
                const float angleBase = static_cast<float>(StelApp::getInstance().getAnimationTime()) * 10;
×
524
                // We draw 4 instances of the sprite at the corners of the pointer
525
                for (int i = 0; i < 4; ++i)
×
526
                {
527
                        const float angle = angleBase + i * 90;
×
528
                        const float x = screenpos[0] + screenSize * cos(angle * M_PI_180f);
×
529
                        const float y = screenpos[1] + screenSize * sin(angle * M_PI_180f);
×
530
                        sPainter.drawSprite2dMode(x, y, 10, angle);
×
531
                }
532
        }
×
533
}
×
534

535
void keplerOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
×
536
{
537
        static_cast<KeplerOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
×
538
        static_cast<KeplerOrbit*>(orbitPtr)->getVelocity(xyzdot);
×
539
}
×
540

541
void gimbalOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
×
542
{
543
        static_cast<GimbalOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
×
544
        static_cast<GimbalOrbit*>(orbitPtr)->getVelocity(xyzdot);
×
545
}
×
546

547
// Init and load the solar system data (2 files)
548
void SolarSystem::loadPlanets()
×
549
{
550
        minorBodies.clear();
×
551
        systemMinorBodies.clear();
×
552
        qDebug() << "Loading Solar System data (1: planets and moons) ...";
×
553
        QString solarSystemFile = StelFileMgr::findFile("data/ssystem_major.ini");
×
554
        if (solarSystemFile.isEmpty())
×
555
        {
556
                qWarning() << "ERROR while loading ssystem_major.ini (unable to find data/ssystem_major.ini):" << StelUtils::getEndLineChar();
×
557
                return;
×
558
        }
559

560
        if (!loadPlanets(solarSystemFile))
×
561
        {
562
                qWarning() << "ERROR while loading ssystem_major.ini:" << StelUtils::getEndLineChar();
×
563
                return;
×
564
        }
565

566
        qDebug() << "Loading Solar System data (2: minor bodies) ...";
×
567
        QStringList solarSystemFiles = StelFileMgr::findFileInAllPaths("data/ssystem_minor.ini");
×
568
        if (solarSystemFiles.isEmpty())
×
569
        {
570
                qWarning() << "ERROR while loading ssystem_minor.ini (unable to find data/ssystem_minor.ini):" << StelUtils::getEndLineChar();
×
571
                return;
×
572
        }
573

574
        for (const auto& solarSystemFile : qAsConst(solarSystemFiles))
×
575
        {
576
                if (loadPlanets(solarSystemFile))
×
577
                {
578
                        qDebug() << "File ssystem_minor.ini is loaded successfully...";
×
579
                        break;
×
580
                }
581
                else
582
                {
583
//                        sun.clear();
584
//                        moon.clear();
585
//                        earth.clear();
586
                        //qCritical() << "We should not be here!";
587

588
                        qDebug() << "Removing minor bodies";
×
589
                        for (const auto& p : qAsConst(systemPlanets))
×
590
                        {
591
                                // We can only delete minor objects now!
592
                                if (p->pType >= Planet::isAsteroid)
×
593
                                {
594
                                        p->satellites.clear();
×
595
                                }
596
                        }                        
597
                        systemPlanets.clear();                        
×
598
                        //Memory leak? What's the proper way of cleaning shared pointers?
599

600
                        // TODO: 0.16pre what about the orbits list?
601

602
                        //If the file is in the user data directory, rename it:
603
                        if (solarSystemFile.contains(StelFileMgr::getUserDir()))
×
604
                        {
605
                                QString newName = QString("%1/data/ssystem_minor-%2.ini").arg(StelFileMgr::getUserDir(), QDateTime::currentDateTime().toString("yyyyMMddThhmmss"));
×
606
                                if (QFile::rename(solarSystemFile, newName))
×
607
                                        qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "has been renamed to" << QDir::toNativeSeparators(newName);
×
608
                                else
609
                                {
610
                                        qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "cannot be removed!";
×
611
                                        qWarning() << "Please either delete it, rename it or move it elsewhere.";
×
612
                                }
613
                        }
×
614
                }
615
        }
616

617
        shadowPlanetCount = 0;
×
618

619
        for (const auto& planet : qAsConst(systemPlanets))
×
620
                if(planet->parent != sun || !planet->satellites.isEmpty())
×
621
                        shadowPlanetCount++;
×
622
}
×
623

624
unsigned char SolarSystem::BvToColorIndex(double bV)
×
625
{
626
        const double dBV = qBound(-500., static_cast<double>(bV)*1000.0, 3499.);
×
627
        return static_cast<unsigned char>(floor(0.5+127.0*((500.0+dBV)/4000.0)));
×
628
}
629

630
bool SolarSystem::loadPlanets(const QString& filePath)
×
631
{
632
        StelSkyDrawer* skyDrawer = StelApp::getInstance().getCore()->getSkyDrawer();
×
633
        qDebug().noquote() << "Loading from:"  << filePath;
×
634
        QSettings pd(filePath, StelIniFormat);
×
635
        if (pd.status() != QSettings::NoError)
×
636
        {
637
                qWarning().noquote() << "ERROR while parsing" << QDir::toNativeSeparators(filePath);
×
638
                return false;
×
639
        }
640

641
        // QSettings does not allow us to say that the sections of the file
642
        // will be listed in the same order  as in the file like the old
643
        // InitParser used to so we can no longer assume that.
644
        //
645
        // This means we must first decide what order to read the sections
646
        // of the file in (each section contains one planet/moon/asteroid/comet/...) to avoid setting
647
        // the parent Planet* to one which has not yet been created.
648
        //
649
        // Stage 1: Make a map of body names back to the section names
650
        // which they come from. Also make a map of body name to parent body
651
        // name. These two maps can be made in a single pass through the
652
        // sections of the file.
653
        //
654
        // Stage 2: Make an ordered list of section names such that each
655
        // item is only ever dependent on items which appear earlier in the
656
        // list.
657
        // 2a: Make a QMultiMap relating the number of levels of dependency
658
        //     to the body name, i.e.
659
        //     0 -> Sun
660
        //     1 -> Mercury
661
        //     1 -> Venus
662
        //     1 -> Earth
663
        //     2 -> Moon
664
        //     etc.
665
        // 2b: Populate an ordered list of section names by iterating over
666
        //     the QMultiMap.  This type of container is always sorted on the
667
        //     key in ascending order, so it's easy.
668
        //     i.e. [sun, earth, moon] is fine, but not [sun, moon, earth]
669
        //
670
        // Stage 3: iterate over the ordered sections decided in stage 2,
671
        // creating the planet objects from the QSettings data.
672

673
        // Stage 1 (as described above).
674
        QMap<QString, QString> secNameMap;
×
675
        QMap<QString, QString> parentMap;
×
676
        QStringList sections = pd.childGroups();
×
677
        // qDebug() << "Stage 1: load ini file with" << sections.size() << "entries: "<< sections;
678
        for (int i=0; i<sections.size(); ++i)
×
679
        {
680
                const QString secname = sections.at(i);
×
681
                const QString englishName = pd.value(secname+"/name", pd.value(secname+"/iau_designation")).toString();
×
682
                if (englishName.isEmpty())
×
683
                        qWarning() << "SSO without proper name found in" << filePath << "section" << secname;
×
684
                const QString strParent = pd.value(secname+"/parent", "Sun").toString();
×
685
                // Only for sorting here we must find our own temporary object name. This is similar but not equal to IAU practice, and must be exactly repeated in the next loop in Stage 2a.
686
                QString obName=englishName;
×
687
                const bool isMinor=QStringList({"asteroid", "plutino", "comet", "dwarf planet", "cubewano", "scattered disc object", "oco", "sednoid", "interstellar object"}).contains(pd.value(secname+"/type").toString());
×
688
                if (isMinor && englishName!="Pluto")
×
689
                {
690
                        const QString designation = pd.value(secname+"/iau_designation", pd.value(secname+"/minor_planet_number")).toString();
×
691
                        if (designation.isEmpty() && (pd.value(secname+"/type") != "comet"))
×
692
                                qWarning() << "Minor body " << englishName << "has incomplete data (missing iau_designation or minor_planet_number) in" << filePath << "section" << secname;
×
693
                        obName=(QString("%1 (%2)").arg(designation, englishName));
×
694
                }
×
695
                if (secNameMap.contains(obName))
×
696
                        qWarning() << "secNameMap already contains " << obName << ". Overwriting data.";
×
697
                secNameMap[obName] = secname;
×
698
                if (strParent!="none" && !strParent.isEmpty() && !englishName.isEmpty())
×
699
                {
700
                        parentMap[obName] = strParent;
×
701
                        // qDebug() << "parentmap[" << obName << "] = " << strParent;
702
                }
703
        }
×
704

705
        // Stage 2a (as described above).
706
        QMultiMap<int, QString> depLevelMap;
×
707
        for (int i=0; i<sections.size(); ++i)
×
708
        {
709
                const QString secname = sections.at(i);
×
710
                const QString englishName = pd.value(secname+"/name", pd.value(secname+"/iau_designation")).toString();
×
711
                QString obName=englishName;
×
712
                const bool isMinor=QStringList({"asteroid", "plutino", "comet", "dwarf planet", "cubewano", "scattered disc object", "oco", "sednoid", "interstellar object"}).contains(pd.value(secname+"/type").toString());
×
713
                if (isMinor && englishName!="Pluto")
×
714
                {
715
                        const QString designation = pd.value(secname+"/iau_designation", pd.value(secname+"/minor_planet_number")).toString();
×
716
                        obName=(QString("%1 (%2)").arg(designation, englishName));
×
717
                }
×
718
                // follow dependencies, incrementing level when we have one till we run out.
719
                QString p=obName;
×
720
                int level = 0;
×
721
                while(parentMap.contains(p) && parentMap[p]!="none")
×
722
                {
723
                        level++;
×
724
                        p = parentMap[p];
×
725
                }
726

727
                depLevelMap.insert(level, secNameMap[obName]);
×
728
                // qDebug() << "2a: Level" << level << "secNameMap[" << obName << "]="<< secNameMap[obName];
729
        }
×
730

731
        // Stage 2b (as described above).
732
        // qDebug() << "Stage 2b:";
733
        QStringList orderedSections;
×
734
#if (QT_VERSION>=QT_VERSION_CHECK(6,0,0))
735
        QMultiMapIterator<int, QString> levelMapIt(depLevelMap);
736
#else
737
        QMapIterator<int, QString> levelMapIt(depLevelMap);
×
738
#endif
739
        while(levelMapIt.hasNext())
×
740
        {
741
                levelMapIt.next();
×
742
                orderedSections << levelMapIt.value();
×
743
        }
744
        // qDebug() << orderedSections;
745

746
        // Stage 3 (as described above).
747
        int readOk=0;
×
748
        //int totalPlanets=0;
749

750
        // qDebug() << "Adding " << orderedSections.size() << "objects...";
751
        for (int i = 0;i<orderedSections.size();++i)
×
752
        {
753
                // qDebug() << "Processing entry" << orderedSections.at(i);
754

755
                //totalPlanets++;
756
                const QString secname = orderedSections.at(i);
×
757
                const QString type = pd.value(secname+"/type").toString();
×
758
                QString englishName = pd.value(secname+"/name").toString().simplified();
×
759
                // englishName alone may be a combination of several elements...
760
                if (type=="comet" || type == "interstellar object")
×
761
                {
762
                        static const QRegularExpression periodicRe("^([1-9][0-9]*[PD](-\\w+)?)"); // No "/" at end, there are nameless numbered comets! (e.g. 362P, 396P)
×
763
                        QRegularExpressionMatch periodMatch=periodicRe.match(englishName);
×
764

765
                        static const QRegularExpression iauDesignationRe("^([1-9][0-9]*[PD](-\\w+)?)|([CA]/[-0-9]+\\s[A-Y])");
×
766
                        QRegularExpressionMatch iauDesignationMatch=iauDesignationRe.match(englishName);
×
767

768
                        // Our name rules for the final englishName, which must contain one element in brackets.
769
                        // Numbered periodic comets: "1P/Halley (1986)"
770
                        // All others: C-AX/2023 A2 (discoverer)". (with optional fragment code -AX)
771
                        const QString iauDesignation = pd.value(secname+"/iau_designation").toString();
×
772
                        const QString dateCode =      pd.value(secname+"/date_code").toString();
×
773
                        const QString perihelCode =   pd.value(secname+"/perihelion_code").toString();
×
774
                        const QString discoveryCode = pd.value(secname+"/discovery_code").toString();
×
775
                        if (iauDesignation.isEmpty() && perihelCode.isEmpty() && discoveryCode.isEmpty() && !periodMatch.hasMatch() && !iauDesignationMatch.hasMatch())
×
776
                                qWarning() << "Comet " << englishName << "has no IAU designation, no perihelion code, no discovery code and seems not a numbered comet in section " << secname;
×
777
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
778

779
                        // The test here can be improved, e.g. with a regexp. In case the name is already reasonably complete, we do not re-build it from the available elements for now. However, the ini file should provide the elements separated!
780
                        if (iauDesignation.isEmpty() && !englishName.contains("("))
×
781
                                englishName.append(QString(" (%1)").arg(discoveryCode));
×
782
                        else if (!iauDesignation.isEmpty() && !englishName.contains("(") && !englishName.contains("/"))
×
783
                                englishName=QString("%1 (%2)").arg(iauDesignation, englishName); // recombine name and iau_designation if name is only the discoverer name.
×
784

785
                        if (!englishName.contains("("))
×
786
                        {
787
                                QString name;
×
788
                                if (!iauDesignation.isEmpty())
×
789
                                {
790
                                        name=iauDesignation;
×
791
                                        if (!englishName.isEmpty())
×
792
                                                name.append(QString(" (%1)").arg(englishName));
×
793
                                }
794
                                else if (!dateCode.isEmpty())
×
795
                                {
796
                                        name=dateCode;
×
797
                                        if (!englishName.isEmpty())
×
798
                                                name.append(QString(" (%1)").arg(englishName));
×
799
                                }
800
                                else if (!discoveryCode.isEmpty())
×
801
                                {
802
                                        name=discoveryCode;
×
803
                                        if (!englishName.isEmpty())
×
804
                                                name.append(QString(" (%1)").arg(englishName));
×
805
                                }
806
                                else if (!perihelCode.isEmpty())
×
807
                                {
808
                                        name.append(QString("C/%1").arg(perihelCode)); // This is not classic, but a final fallback before warning
×
809
                                        if (!englishName.isEmpty())
×
810
                                                name.append(QString(" (%1)").arg(englishName));
×
811
                                }
812

813
                                if (name.contains("("))
×
814
                                        englishName=name;
×
815
                                else
816
                                        qWarning() << "Comet " << englishName << "has no proper name elements in section " << secname;
×
817
                        }
×
818
                }
×
819
                else if (QStringList({"asteroid", "dwarf planet", "cubewano", "sednoid", "plutino", "scattered disc object", "Oort cloud object"}).contains(type) && !englishName.contains("Pluto"))
×
820
                {
821
                        const int minorPlanetNumber= pd.value(secname+"/minor_planet_number").toInt();
×
822
                        const QString iauDesignation = pd.value(secname+"/iau_designation", "").toString();
×
823
                        if (iauDesignation.isEmpty() && minorPlanetNumber==0)
×
824
                                qWarning() << "minor body " << englishName << "has no IAU code in section " << secname;
×
825
                        const QString discoveryCode = pd.value(secname+"/discovery_code").toString();
×
826

827
                        // The test here can be improved, e.g. with a regexp. In case the name is already reasonably complete, we do not re-build it from the available elements
828
                        if (englishName.isEmpty())
×
829
                        {
830
                                //if (minorPlanetNumber>0)
831
                                //        englishName=QString("(%1) ").arg(minorPlanetNumber);
832
                                if (!iauDesignation.isEmpty())
×
833
                                {
834
                                        englishName.append(iauDesignation);
×
835
                                }
836
                                else if (!discoveryCode.isEmpty())
×
837
                                {
838
                                        englishName.append(discoveryCode);
×
839
                                }
840
                                else
841
                                        qWarning() << "Minor body in section" << secname << "has no proper name elements";
×
842
                        }
843
                }
×
844

845
                const double bV = pd.value(secname+"/color_index_bv", 99.).toDouble();
×
846
                const QString strParent = pd.value(secname+"/parent", "Sun").toString(); // Obvious default, keep file entries simple.
×
847
                PlanetP parent;
×
848
                if (strParent!="none")
×
849
                {
850
                        // Look in the other planets the one named with strParent
851
                        for (const auto& p : qAsConst(systemPlanets))
×
852
                        {
853
                                if (p->getCommonEnglishName()==strParent)
×
854
                                {
855
                                        parent = p;
×
856
                                        break;
×
857
                                }
858
                        }
859
                        if (parent.isNull())
×
860
                        {
861
                                qWarning().noquote().nospace() << "ERROR: can't find parent solar system body for " << englishName << ". Skipping.";
×
862
                                //abort();
863
                                continue;
×
864
                        }
865
                }
866
                Q_ASSERT(parent || englishName=="Sun");
×
867

868
                const QString coordFuncName = pd.value(secname+"/coord_func", "kepler_orbit").toString(); // 0.20: new default for all non *_special.
×
869
                // qDebug() << "englishName:" << englishName << ", parent:" << strParent <<  ", coord_func:" << coordFuncName;
870
                posFuncType posfunc=Q_NULLPTR;
×
871
                Orbit* orbitPtr=Q_NULLPTR;
×
872
                OsculatingFunctType *osculatingFunc = Q_NULLPTR;
×
873
                bool closeOrbit = true;
×
874
                double semi_major_axis=0; // used again below.
×
875

876

877
#ifdef USE_GIMBAL_ORBIT
878
                // undefine the flag in Orbit.h to disable and use the old, static observer solution (on an infinitely slow KeplerOrbit)
879
                // Note that for now we ignore any orbit-related config values except orbit_SemiMajorAxis from the ini file.
880
                if (type=="observer")
×
881
                {
882
                        double unit = 1; // AU
×
883
                        double defaultSemiMajorAxis = 1;
×
884
                        if (strParent!="Sun")
×
885
                        {
886
                                unit /= AU;  // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
×
887
                                defaultSemiMajorAxis *= AU;
×
888
                        }
889
                        semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis", defaultSemiMajorAxis).toDouble() * unit;
×
890
                        // Create a pseudo orbit that allows interaction with keyboard
891
                        GimbalOrbit *orb = new GimbalOrbit(semi_major_axis, 0.*M_PI_180, 45.*M_PI_180); // [Over mid-north latitude]
×
892
                        orb->setMinDistance(parent->getEquatorialRadius()*1.5);
×
893
                        orbits.push_back(orb);
×
894

895
                        orbitPtr = orb;
×
896
                        posfunc = &gimbalOrbitPosFunc;
×
897
                }
898
                else
899
#endif
900
                if ((coordFuncName=="kepler_orbit") || (coordFuncName=="comet_orbit") || (coordFuncName=="ell_orbit")) // ell_orbit used for planet moons. TBD in V1.0: remove non-kepler_orbit!
×
901
                {
902
                        if (coordFuncName!="kepler_orbit")
×
903
                                qDebug() << "Old-fashioned entry" << coordFuncName << "found. Please delete line from " << filePath << "section" << secname;
×
904
                        // 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.
905
                        // Read the orbital elements                        
906
                        const double eccentricity = pd.value(secname+"/orbit_Eccentricity", 0.0).toDouble();
×
907
                        if (eccentricity >= 1.0) closeOrbit = false;
×
908
                        double pericenterDistance = pd.value(secname+"/orbit_PericenterDistance",-1e100).toDouble(); // AU, or km for Moons (those where parent!=sun)!
×
909
                        if (pericenterDistance <= 0.0) {
×
910
                                semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis",-1e100).toDouble();
×
911
                                if (semi_major_axis <= -1e100) {
×
912
                                        qDebug() << "ERROR loading " << englishName << "from section" << secname
×
913
                                                 << ": you must provide orbit_PericenterDistance or orbit_SemiMajorAxis. Skipping " << englishName;
×
914
                                        continue;
×
915
                                } else {
916
                                        Q_ASSERT(eccentricity != 1.0); // parabolic orbits have no semi_major_axis
×
917
                                        pericenterDistance = semi_major_axis * (1.0-eccentricity);
×
918
                                }
919
                        } else {
920
                                semi_major_axis = (eccentricity == 1.0)
×
921
                                                                ? 0.0 // parabolic orbits have no semi_major_axis
×
922
                                                                : pericenterDistance / (1.0-eccentricity);
×
923
                        }
924
                        if (strParent!="Sun")
×
925
                                pericenterDistance /= AU;  // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
×
926

927
                        double meanMotion = pd.value(secname+"/orbit_MeanMotion",-1e100).toDouble(); // degrees/day
×
928
                        if (meanMotion <= -1e100) {
×
929
                                const double period = pd.value(secname+"/orbit_Period",-1e100).toDouble();
×
930
                                if (period <= -1e100) {
×
931
                                        if (parent->getParent()) {
×
932
                                                qWarning().noquote() << "ERROR: " << englishName
×
933
                                                           << ": when the parent body is not the sun, you must provide "
×
934
                                                           << "either orbit_MeanMotion or orbit_Period";
×
935
                                        } else {
936
                                                // in case of parent=sun: use Gaussian gravitational constant for calculating meanMotion:
937
                                                meanMotion = (eccentricity == 1.0)
×
938
                                                                        ? 0.01720209895 * (1.5/pericenterDistance) * std::sqrt(0.5/pericenterDistance)  // Heafner: Fund.Eph.Comp. W / dt
×
939
                                                                        : 0.01720209895 / (fabs(semi_major_axis)*std::sqrt(fabs(semi_major_axis)));
×
940
                                        }
941
                                } else {
942
                                        meanMotion = 2.0*M_PI/period;
×
943
                                }
944
                        } else {
945
                                meanMotion *= (M_PI/180.0);
×
946
                        }
947

948
                        const double ascending_node = pd.value(secname+"/orbit_AscendingNode", 0.0).toDouble()*(M_PI/180.0);
×
949
                        double arg_of_pericenter = pd.value(secname+"/orbit_ArgOfPericenter",-1e100).toDouble();
×
950
                        double long_of_pericenter;
951
                        if (arg_of_pericenter <= -1e100) {
×
952
                                long_of_pericenter = pd.value(secname+"/orbit_LongOfPericenter", 0.0).toDouble()*(M_PI/180.0);
×
953
                                arg_of_pericenter = long_of_pericenter - ascending_node;
×
954
                        } else {
955
                                arg_of_pericenter *= (M_PI/180.0);
×
956
                                long_of_pericenter = arg_of_pericenter + ascending_node;
×
957
                        }
958

959
                        double time_at_pericenter = pd.value(secname+"/orbit_TimeAtPericenter",-1e100).toDouble();
×
960
                        // 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.
961
                        // However, the distinction is relevant to discern element sets for various valid ranges.
962
                        // Comet orbits epoch should default to T while planets or moons default to J2000.
963
                        const double epoch = pd.value(secname+"/orbit_Epoch", type=="comet" ? time_at_pericenter : J2000).toDouble();
×
964
                        if (time_at_pericenter <= -1e100) {
×
965
                                double mean_anomaly = pd.value(secname+"/orbit_MeanAnomaly",-1e100).toDouble()*(M_PI/180.0);
×
966
                                if (mean_anomaly <= -1e10) {
×
967
                                        double mean_longitude = pd.value(secname+"/orbit_MeanLongitude",-1e100).toDouble()*(M_PI/180.0);
×
968
                                        if (mean_longitude <= -1e10) {
×
969
                                                qWarning().noquote() << "ERROR: " << englishName
×
970
                                                           << ": when you do not provide orbit_TimeAtPericenter, you must provide orbit_Epoch"
×
971
                                                           << "and either one of orbit_MeanAnomaly or orbit_MeanLongitude. Skipping this object.";
×
972
                                                //abort();
973
                                                continue;
×
974
                                        } else {
975
                                                mean_anomaly = mean_longitude - long_of_pericenter;
×
976
                                        }
977
                                }
978
                                time_at_pericenter = epoch - mean_anomaly / meanMotion;
×
979
                        }
980

981
                        static const QMap<QString, double>massMap={ // masses from DE430/431
982
                                { "Sun",            1.0},
×
983
                                { "Mercury",  6023682.155592},
×
984
                                { "Venus",     408523.718658},
×
985
                                { "Earth",     332946.048834},
×
986
                                { "Mars",     3098703.590291},
×
987
                                { "Jupiter",     1047.348625},
×
988
                                { "Saturn",      3497.901768},
×
989
                                { "Uranus",     22902.981613},
×
990
                                { "Neptune",    19412.259776},
×
991
                                { "Pluto",  135836683.768617}};
×
992

993
                        // Construct orbital elements relative to the parent body. This will construct orbits for J2000 only.
994
                        // Some planet axes move very slowly, this effect could be modelled by replicating these lines
995
                        // after recomputing obliquity and node (below) in Planet::computeTransMatrix().
996
                        // The effect is negligible for several millennia, though.
997
                        // When the parent is the sun use ecliptic rather than sun equator:
998
                        const double parentRotObliquity  = parent->getParent() ? parent->getRotObliquity(J2000) : 0.0;
×
999
                        const double parent_rot_asc_node = parent->getParent() ? parent->getRotAscendingNode()  : 0.0;
×
1000
                        double parent_rot_j2000_longitude = 0.0;
×
1001
                        if (parent->getParent()) {
×
1002
                                const double c_obl = cos(parentRotObliquity);
×
1003
                                const double s_obl = sin(parentRotObliquity);
×
1004
                                const double c_nod = cos(parent_rot_asc_node);
×
1005
                                const double s_nod = sin(parent_rot_asc_node);
×
1006
                                const Vec3d OrbitAxis0( c_nod,       s_nod,        0.0);
×
1007
                                const Vec3d OrbitAxis1(-s_nod*c_obl, c_nod*c_obl,s_obl);
×
1008
                                const Vec3d OrbitPole(  s_nod*s_obl,-c_nod*s_obl,c_obl);
×
1009
                                const Vec3d J2000Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(Vec3d(0,0,1)));
×
1010
                                Vec3d J2000NodeOrigin(J2000Pole^OrbitPole);
×
1011
                                J2000NodeOrigin.normalize();
×
1012
                                parent_rot_j2000_longitude = atan2(J2000NodeOrigin*OrbitAxis1,J2000NodeOrigin*OrbitAxis0);
×
1013
                        }
1014

1015
                        const double orbitGoodDays=pd.value(secname+"/orbit_good", parent->englishName!="Sun" ? 0. : -1.).toDouble(); // "Moons" have permanently good orbits.
×
1016
                        const double inclination = pd.value(secname+"/orbit_Inclination", 0.0).toDouble()*(M_PI/180.0);
×
1017

1018
                        // Create a Keplerian orbit. This has been called CometOrbit before 0.20.
1019
                        //qDebug() << "Creating KeplerOrbit for" << parent->englishName << "---" << englishName;
1020
                        KeplerOrbit *orb = new KeplerOrbit(epoch,                  // JDE
1021
                                                           pericenterDistance,     // [AU]
1022
                                                           eccentricity,           // 0..>1 (>>1 for Interstellar objects)
1023
                                                           inclination,            // [radians]
1024
                                                           ascending_node,         // [radians]
1025
                                                           arg_of_pericenter,      // [radians]
1026
                                                           time_at_pericenter,     // JDE
1027
                                                           orbitGoodDays,          // orbitGoodDays. 0=always good, -1=compute_half_orbit_duration
1028
                                                           meanMotion,             // [radians/day]
1029
                                                           parentRotObliquity,     // [radians]
1030
                                                           parent_rot_asc_node,    // [radians]
1031
                                                           parent_rot_j2000_longitude, // [radians]
1032
                                                           1./massMap.value(parent->englishName, 1.)); // central mass [solar masses]
×
1033
                        orbits.push_back(orb);
×
1034

1035
                        orbitPtr = orb;
×
1036
                        posfunc = &keplerOrbitPosFunc;
×
1037
                }
1038
                else
1039
                {
1040
                        static const QMap<QString, posFuncType>posfuncMap={
1041
                                { "sun_special",       &get_sun_helio_coordsv},
×
1042
                                { "mercury_special",   &get_mercury_helio_coordsv},
×
1043
                                { "venus_special",     &get_venus_helio_coordsv},
×
1044
                                { "earth_special",     &get_earth_helio_coordsv},
×
1045
                                { "lunar_special",     &get_lunar_parent_coordsv},
×
1046
                                { "mars_special",      &get_mars_helio_coordsv},
×
1047
                                { "phobos_special",    &get_phobos_parent_coordsv},
×
1048
                                { "deimos_special",    &get_deimos_parent_coordsv},
×
1049
                                { "jupiter_special",   &get_jupiter_helio_coordsv},
×
1050
                                { "io_special",        &get_io_parent_coordsv},
×
1051
                                { "europa_special",    &get_europa_parent_coordsv},
×
1052
                                { "ganymede_special",  &get_ganymede_parent_coordsv},
×
1053
                                { "calisto_special",   &get_callisto_parent_coordsv},
×
1054
                                { "callisto_special",  &get_callisto_parent_coordsv},
×
1055
                                { "saturn_special",    &get_saturn_helio_coordsv},
×
1056
                                { "mimas_special",     &get_mimas_parent_coordsv},
×
1057
                                { "enceladus_special", &get_enceladus_parent_coordsv},
×
1058
                                { "tethys_special",    &get_tethys_parent_coordsv},
×
1059
                                { "dione_special",     &get_dione_parent_coordsv},
×
1060
                                { "rhea_special",      &get_rhea_parent_coordsv},
×
1061
                                { "titan_special",     &get_titan_parent_coordsv},
×
1062
                                { "hyperion_special",  &get_hyperion_parent_coordsv},
×
1063
                                { "iapetus_special",   &get_iapetus_parent_coordsv},
×
1064
                                { "helene_special",    &get_helene_parent_coordsv},
×
1065
                                { "telesto_special",   &get_telesto_parent_coordsv},
×
1066
                                { "calypso_special",   &get_calypso_parent_coordsv},
×
1067
                                { "uranus_special",    &get_uranus_helio_coordsv},
×
1068
                                { "miranda_special",   &get_miranda_parent_coordsv},
×
1069
                                { "ariel_special",     &get_ariel_parent_coordsv},
×
1070
                                { "umbriel_special",   &get_umbriel_parent_coordsv},
×
1071
                                { "titania_special",   &get_titania_parent_coordsv},
×
1072
                                { "oberon_special",    &get_oberon_parent_coordsv},
×
1073
                                { "neptune_special",   &get_neptune_helio_coordsv},
×
1074
                                { "pluto_special",     &get_pluto_helio_coordsv}};
×
1075
                        static const QMap<QString, OsculatingFunctType*>osculatingMap={
1076
                                { "mercury_special",   &get_mercury_helio_osculating_coords},
×
1077
                                { "venus_special",     &get_venus_helio_osculating_coords},
×
1078
                                { "earth_special",     &get_earth_helio_osculating_coords},
×
1079
                                { "mars_special",      &get_mars_helio_osculating_coords},
×
1080
                                { "jupiter_special",   &get_jupiter_helio_osculating_coords},
×
1081
                                { "saturn_special",    &get_saturn_helio_osculating_coords},
×
1082
                                { "uranus_special",    &get_uranus_helio_osculating_coords},
×
1083
                                { "neptune_special",   &get_neptune_helio_osculating_coords}};
×
1084
                        posfunc=posfuncMap.value(coordFuncName, Q_NULLPTR);
×
1085
                        osculatingFunc=osculatingMap.value(coordFuncName, Q_NULLPTR);
×
1086
                }
1087
                if (posfunc==Q_NULLPTR)
×
1088
                {
1089
                        qCritical() << "ERROR in section " << secname << ": can't find posfunc " << coordFuncName << " for " << englishName;
×
1090
                        exit(-1);
×
1091
                }
1092

1093
                // Create the Solar System body and add it to the list
1094
                //TODO: Refactor the subclass selection to reduce duplicate code mess here,
1095
                // by at least using this base class pointer and using setXXX functions instead of mega-constructors
1096
                // that have to pass most of it on to the Planet class
1097
                PlanetP newP;
×
1098

1099
                // New class objects, named "plutino", "cubewano", "dwarf planet", "SDO", "OCO", has properties
1100
                // similar to asteroids and we should calculate their positions like for asteroids. Dwarf planets
1101
                // have one exception: Pluto - as long as we use a special function for calculation of Pluto's orbit.
1102
                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"))
×
1103
                {
1104
                        minorBodies << englishName;
×
1105

1106
                        Vec3f color = Vec3f(1.f, 1.f, 1.f);
×
1107
                        if (bV<99.)
×
1108
                                color = skyDrawer->indexToColor(BvToColorIndex(bV))*0.75f; // see ZoneArray.cpp:L490
×
1109
                        else
1110
                                color = Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString());
×
1111

1112
                        const bool hidden = pd.value(secname+"/hidden", false).toBool();
×
1113
                        const QString normalMapName = ( hidden ? "" : englishName.toLower().append("_normals.png")); // no normal maps for invisible objects!
×
1114
                        const QString horizonMapName = ( hidden ? "" : englishName.toLower().append("_normals.png")); // no normal maps for invisible objects!
×
1115

1116
                        newP = PlanetP(new MinorPlanet(englishName,
×
1117
                                                    pd.value(secname+"/radius", 1.0).toDouble()/AU,
×
1118
                                                    pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1119
                                                    color, // halo color
1120
                                                    pd.value(secname+"/albedo", 0.25f).toFloat(),
×
1121
                                                    pd.value(secname+"/roughness",0.9f).toFloat(),
×
1122
                                                    pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1123
                                                    pd.value(secname+"/normals_map", normalMapName).toString(),
×
1124
                                                    pd.value(secname+"/horizon_map", horizonMapName).toString(),
×
1125
                                                    pd.value(secname+"/model").toString(),
×
1126
                                                    posfunc,
1127
                                                    static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object created previously
1128
                                                    osculatingFunc, // should be Q_NULLPTR
1129
                                                    closeOrbit,
1130
                                                    hidden,
1131
                                                    type));
×
1132
                        QSharedPointer<MinorPlanet> mp =  newP.dynamicCast<MinorPlanet>();
×
1133
                        //Number, IAU provisional designation
1134
                        mp->setMinorPlanetNumber(pd.value(secname+"/minor_planet_number", 0).toInt());
×
1135
                        mp->setIAUDesignation(pd.value(secname+"/iau_designation", "").toString());
×
1136

1137
                        //H-G magnitude system
1138
                        const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1139
                        const float slope = pd.value(secname+"/slope_parameter", 0.15f).toFloat();
×
1140
                        if (magnitude > -99.f)
×
1141
                        {
1142
                                mp->setAbsoluteMagnitudeAndSlope(magnitude, qBound(0.0f, slope, 1.0f));
×
1143
                        }
1144

1145
                        mp->setColorIndexBV(static_cast<float>(bV));
×
1146
                        mp->setSpectralType(pd.value(secname+"/spec_t", "").toString(), pd.value(secname+"/spec_b", "").toString());
×
1147

1148
                        // Discovery circumstances
1149
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1150
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1151
                        if (!discoveryDate.isEmpty())
×
1152
                                mp->setDiscoveryData(discoveryDate, discovererName);
×
1153

1154
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
1155
                        QStringList codes = { pd.value(secname+"/date_code", "").toString(),
×
1156
                                              pd.value(secname+"/perihelion_code", "").toString(),
×
1157
                                              pd.value(secname+"/discovery_code", "").toString() };
×
1158
                        codes.removeAll("");
×
1159
                        if (codes.count()>0)
×
1160
                                mp->setExtraDesignations(codes);
×
1161

1162
                        if (semi_major_axis>0)
×
1163
                                mp->deltaJDE = 2.0*semi_major_axis*StelCore::JD_SECOND;
×
1164
                         else if ((semi_major_axis<=0.0) && (type!="interstellar object"))
×
1165
                                qWarning().noquote() << "WARNING: Minor body" << englishName << "has no semimajor axis!";
×
1166

1167
                        systemMinorBodies.push_back(newP);
×
1168
                }
×
1169
                else if (type == "comet")
×
1170
                {
1171
                        minorBodies << englishName;
×
1172
                        newP = PlanetP(new Comet(englishName,
×
1173
                                              pd.value(secname+"/radius", 5.0).toDouble()/AU,
×
1174
                                              pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1175
                                              Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
×
1176
                                              pd.value(secname+"/albedo", 0.075f).toFloat(), // assume very dark surface
×
1177
                                              pd.value(secname+"/roughness",0.9f).toFloat(),
×
1178
                                              pd.value(secname+"/outgas_intensity",0.1f).toFloat(),
×
1179
                                              pd.value(secname+"/outgas_falloff", 0.1f).toFloat(),
×
1180
                                              pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1181
                                              pd.value(secname+"/model").toString(),
×
1182
                                              posfunc,
1183
                                              static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object
1184
                                              osculatingFunc, // ALWAYS NULL for comets.
1185
                                              closeOrbit,
1186
                                              pd.value(secname+"/hidden", false).toBool(),
×
1187
                                              type,
1188
                                              pd.value(secname+"/dust_widthfactor", 1.5f).toFloat(),
×
1189
                                              pd.value(secname+"/dust_lengthfactor", 0.4f).toFloat(),
×
1190
                                              pd.value(secname+"/dust_brightnessfactor", 1.5f).toFloat()
×
1191
                                              ));
×
1192
                        QSharedPointer<Comet> mp = newP.dynamicCast<Comet>();
×
1193

1194
                        //g,k magnitude system
1195
                        const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1196
                        const float slope = qBound(-5.0f, pd.value(secname+"/slope_parameter", 4.0f).toFloat(), 30.0f);
×
1197
                        if (magnitude > -99.f)
×
1198
                                        mp->setAbsoluteMagnitudeAndSlope(magnitude, slope);
×
1199

1200
                        QString iauDesignation = pd.value(secname+"/iau_designation", "").toString();
×
1201
                        if (!iauDesignation.isEmpty())
×
1202
                                mp->setIAUDesignation(iauDesignation);
×
1203
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
1204
                        QStringList codes = { pd.value(secname+"/date_code", "").toString(),
×
1205
                                              pd.value(secname+"/perihelion_code", "").toString(),
×
1206
                                              pd.value(secname+"/discovery_code", "").toString() };
×
1207
                        codes.removeAll("");
×
1208
                        if (codes.count()>0)
×
1209
                                mp->setExtraDesignations(codes);
×
1210

1211
                        // Discovery circumstances
1212
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1213
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1214
                        if (!discoveryDate.isEmpty())
×
1215
                                mp->setDiscoveryData(discoveryDate, discovererName);
×
1216

1217
                        systemMinorBodies.push_back(newP);
×
1218
                }
×
1219
                else // type==star|planet|moon|dwarf planet|observer|artificial
1220
                {
1221
                        //qDebug() << type;
1222
                        Q_ASSERT(type=="star" || type=="planet" || type=="moon" || type=="artificial" || type=="observer" || type=="dwarf planet"); // TBD: remove Pluto...
×
1223
                        // Set possible default name of the normal map for avoiding yin-yang shaped moon
1224
                        // phase when normal map key not exists. Example: moon_normals.png
1225
                        // Details: https://bugs.launchpad.net/stellarium/+bug/1335609                        
1226
                        newP = PlanetP(new Planet(englishName,
×
1227
                                               pd.value(secname+"/radius", 1.0).toDouble()/AU,
×
1228
                                               pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1229
                                               Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
×
1230
                                               pd.value(secname+"/albedo", 0.25f).toFloat(),
×
1231
                                               pd.value(secname+"/roughness",0.9f).toFloat(),
×
1232
                                               pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1233
                                               pd.value(secname+"/normals_map", englishName.toLower().append("_normals.png")).toString(),
×
1234
                                               pd.value(secname+"/horizon_map", englishName.toLower().append("_horizon.png")).toString(),
×
1235
                                               pd.value(secname+"/model").toString(),
×
1236
                                               posfunc,
1237
                                               static_cast<KeplerOrbit*>(orbitPtr), // This remains Q_NULLPTR for the major planets, or has a KeplerOrbit for planet moons.
1238
                                               osculatingFunc,
1239
                                               closeOrbit,
1240
                                               pd.value(secname+"/hidden", false).toBool(),
×
1241
                                               pd.value(secname+"/atmosphere", false).toBool(),
×
1242
                                               pd.value(secname+"/halo", true).toBool(),
×
1243
                                               type));
×
1244
                        newP->absoluteMagnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1245
                        newP->massKg = pd.value(secname+"/mass_kg", 0.).toDouble();
×
1246

1247
                        // Moon designation (planet index + IAU moon number)
1248
                        QString moonDesignation = pd.value(secname+"/iau_moon_number", "").toString();
×
1249
                        if (!moonDesignation.isEmpty())
×
1250
                                newP->setIAUMoonNumber(moonDesignation);
×
1251
                        newP->setColorIndexBV(static_cast<float>(bV));
×
1252
                        // Discovery circumstances
1253
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1254
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1255
                        if (!discoveryDate.isEmpty())
×
1256
                                newP->setDiscoveryData(discoveryDate, discovererName);
×
1257
                }
×
1258

1259
                if (!parent.isNull())
×
1260
                {
1261
                        parent->satellites.append(newP);
×
1262
                        newP->parent = parent;
×
1263
                }
1264
                if (secname=="earth") earth = newP;
×
1265
                if (secname=="sun") sun = newP;
×
1266
                if (secname=="moon") moon = newP;
×
1267

1268
                // At this point the orbit and object type (class Planet and subclasses) have been fixed.
1269
                // For many objects we have oriented spheroids with rotational parameters.
1270

1271
                // There are two ways of defining the axis orientation:
1272
                // obliquity and ascending node, which was used by Stellarium already before 2010 (based on Celestia?).
1273
                double rotObliquity = pd.value(secname+"/rot_obliquity",0.).toDouble()*(M_PI_180);
×
1274
                double rotAscNode = pd.value(secname+"/rot_equator_ascending_node",0.).toDouble()*(M_PI_180);
×
1275
                // rot_periode given in hours (from which rotPeriod in days),
1276
                // The default is useful for many moons in bound rotation
1277
                double rotPeriod=pd.value(secname+"/rot_periode", pd.value(secname+"/orbit_Period", 1.).toDouble()*24.).toDouble()/24.;
×
1278
                double rotOffset=pd.value(secname+"/rot_rotation_offset",0.).toDouble();
×
1279

1280
                // 0.21+: Use WGCCRE planet North pole data if available
1281
                // NB: N pole for J2000 epoch as defined by IAU (NOT right hand rotation rule)
1282
                // Define only basic motion. Use special functions for more complicated axes.
1283
                const double J2000NPoleRA  = pd.value(secname+"/rot_pole_ra",  0.).toDouble()*M_PI_180;
×
1284
                const double J2000NPoleRA1 = pd.value(secname+"/rot_pole_ra1", 0.).toDouble()*M_PI_180;
×
1285
                const double J2000NPoleDE  = pd.value(secname+"/rot_pole_de",  0.).toDouble()*M_PI_180;
×
1286
                const double J2000NPoleDE1 = pd.value(secname+"/rot_pole_de1", 0.).toDouble()*M_PI_180;
×
1287
                const double J2000NPoleW0  = pd.value(secname+"/rot_pole_w0",  0.).toDouble(); // [degrees]   Basically the same idea as rot_rotation_offset, but W!=rotAngle
×
1288
                const double J2000NPoleW1  = pd.value(secname+"/rot_pole_w1",  0.).toDouble(); // [degrees/d] Basically the same idea as 360/rot_periode
×
1289
                if (fabs(J2000NPoleW1) > 0.0) // Patch possibly old period value with a more modern value.
×
1290
                {
1291
                        // this is just another expression for rotational speed.
1292
                        rotPeriod=360.0/J2000NPoleW1;
×
1293
                }
1294

1295
                // IMPORTANT: For the planet moons with orbits relative to planets' equator plane,
1296
                // re-compute the important bits from the updated axis elements.
1297
                // Reactivated to re-establish Pluto/Charon lock #153
1298
                if((J2000NPoleRA!=0.) || (J2000NPoleDE!=0.))
×
1299
                {
1300
                        // If available, recompute obliquity and AscNode from the new data.
1301
                        // Solution since 0.16: Make this once for J2000.
1302
                        // Optional (future?): Repeat this block in Planet::computeTransMatrix() for planets with moving axes and update all Moons' KeplerOrbit if required.
1303
                        Vec3d J2000NPole;
×
1304
                        StelUtils::spheToRect(J2000NPoleRA,J2000NPoleDE,J2000NPole);
×
1305

1306
                        Vec3d vsop87Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(J2000NPole));
×
1307

1308
                        double lon, lat;
1309
                        StelUtils::rectToSphe(&lon, &lat, vsop87Pole);
×
1310

1311
                        rotObliquity = (M_PI_2 - lat);
×
1312
                        rotAscNode = (lon + M_PI_2);
×
1313

1314
                        //qDebug() << englishName << ": Compare these values to the older data in ssystem_major";
1315
                        //qDebug() << "\tCalculated rotational obliquity: " << rotObliquity*180./M_PI;
1316
                        //qDebug() << "\tCalculated rotational ascending node: " << rotAscNode*180./M_PI;
1317

1318
                        if (J2000NPoleW0 >0)
×
1319
                        {
1320
                                // W0 is counted from the ascending node with ICRF, but rotOffset from orbital plane.
1321
                                // Try this assumption by just counting Offset=W0+90+RA0.
1322
                                rotOffset=J2000NPoleW0 + lon*M_180_PI;
×
1323
                                //qDebug() << "\tCalculated rotational period (days // hours): " << rotPeriod << "//" << rotPeriod*24.;
1324
                                //qDebug() << "\tRotational offset (degrees): " << rotOffset;
1325
                        }
1326
                }
1327
                newP->setRotationElements(
×
1328
                        englishName,
1329
                        rotPeriod,
1330
                        rotOffset,
1331
                        pd.value(secname+"/rot_epoch", J2000).toDouble(),
×
1332
                        rotObliquity,
1333
                        rotAscNode,
1334
                        J2000NPoleRA,
1335
                        J2000NPoleRA1,
1336
                        J2000NPoleDE,
1337
                        J2000NPoleDE1,
1338
                        J2000NPoleW0,
1339
                        J2000NPoleW1);
1340
                // orbit_Period given in days.
1341
                // Elliptical Kepler orbits (ecc<0.9) will replace whatever is given by a value computed on the fly. Parabolic objects show 0.
1342
                newP->setSiderealPeriod(fabs(pd.value(secname+"/orbit_Period", 0.).toDouble()));
×
1343

1344
                if (pd.contains(secname+"/tex_ring")) {
×
1345
                        const float rMin = pd.value(secname+"/ring_inner_size").toFloat()/AUf;
×
1346
                        const float rMax = pd.value(secname+"/ring_outer_size").toFloat()/AUf;
×
1347
                        Ring *r = new Ring(rMin,rMax,pd.value(secname+"/tex_ring").toString());
×
1348
                        newP->setRings(r);
×
1349
                }
1350

1351
                systemPlanets.push_back(newP);
×
1352
                readOk++;
×
1353
        }
×
1354

1355
        if (systemPlanets.isEmpty())
×
1356
        {
1357
                qWarning().noquote() << "No Solar System objects loaded from" << QDir::toNativeSeparators(filePath);
×
1358
                return false;
×
1359
        }
1360
        else
1361
                qDebug() << "Solar System has" << systemPlanets.count() << "entries.";
×
1362

1363
        // special case: load earth shadow texture
1364
        if (!Planet::texEarthShadow)
×
1365
                Planet::texEarthShadow = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/earth-shadow.png");
×
1366

1367
        // Also comets just have static textures.
1368
        if (!Comet::comaTexture)
×
1369
                Comet::comaTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometComa.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
×
1370
        //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.
1371
        if (!Comet::tailTexture)
×
1372
                Comet::tailTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometTail.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
×
1373

1374
        if (readOk>0)
×
1375
                qDebug() << "Loaded" << readOk << "Solar System bodies";
×
1376

1377
        return true;
×
1378
}
×
1379

1380
// Compute the position for every elements of the solar system.
1381
// The order is not important since the position is computed relatively to the mother body
1382
void SolarSystem::computePositions(double dateJDE, PlanetP observerPlanet)
×
1383
{
1384
        StelCore *core=StelApp::getInstance().getCore();
×
1385
        const bool withAberration=core->getUseAberration();
×
1386
        if (flagLightTravelTime) // switching off light time correction implies no aberration for the planets.
×
1387
        {
1388
                for (const auto& p : qAsConst(systemPlanets))
×
1389
                {
1390
                        p->computePosition(dateJDE, Vec3d(0.));
×
1391
                }
1392
                const Vec3d obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1393

1394
                // For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1395
                // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1396
                // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1397
                // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1398
                // used ephemerides already provide aberration-corrected positions for the Moon?
1399
                const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1400
                for (const auto& p : qAsConst(systemPlanets))
×
1401
                {
1402
                        //p->setExtraInfoString(StelObject::DebugAid, "");
1403
                        const auto planetPos = p->getHeliocentricEclipticPos();
×
1404
                        const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1405
                        Vec3d aberrationPush(0.);
×
1406
                        if (withAberration && (observerPlanet->englishName!="Earth" || p->englishName!="Moon"))
×
1407
                                aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1408
                        p->computePosition(dateJDE-lightTimeDays, aberrationPush);
×
1409
                }
1410
                // Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1411
                for (const auto& p : qAsConst(systemPlanets))
×
1412
                {
1413
                        //p->setExtraInfoString(StelObject::DebugAid, "");
1414
                        const auto planetPos = p->getHeliocentricEclipticPos();
×
1415
                        const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1416
                        Vec3d aberrationPush(0.);
×
1417
                        if (withAberration && (observerPlanet->englishName!="Earth" || p->englishName!="Moon"))
×
1418
                                aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1419
                        // The next call may already do nothing if the time difference to the previous round is not large enough.
1420
                        p->computePosition(dateJDE-lightTimeDays, aberrationPush);
×
1421
//                        p->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1422
//                                              .arg(QString::number(lightTimeDays, 'f', 3))
1423
//                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1424
//                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1425
//                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3)));
1426

1427
                        const auto update = &RotationElements::updatePlanetCorrections;
×
1428
                        if      (p->englishName=="Moon")    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1429
                        else if (p->englishName=="Mars")    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1430
                        else if (p->englishName=="Jupiter") update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1431
                        else if (p->englishName=="Saturn")  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1432
                        else if (p->englishName=="Uranus")  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1433
                        else if (p->englishName=="Neptune") update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1434
                }
1435
        }
1436
        else
1437
        {
1438
                for (const auto& p : qAsConst(systemPlanets))
×
1439
                {
1440
                        p->setExtraInfoString(StelObject::DebugAid, "");
×
1441
                        p->computePosition(dateJDE, Vec3d(0.));
×
1442
                        const auto update = &RotationElements::updatePlanetCorrections;
×
1443
                        if      (p->englishName=="Moon")    update(dateJDE, RotationElements::EarthMoon);
×
1444
                        else if (p->englishName=="Mars")    update(dateJDE, RotationElements::Mars);
×
1445
                        else if (p->englishName=="Jupiter") update(dateJDE, RotationElements::Jupiter);
×
1446
                        else if (p->englishName=="Saturn")  update(dateJDE, RotationElements::Saturn);
×
1447
                        else if (p->englishName=="Uranus")  update(dateJDE, RotationElements::Uranus);
×
1448
                        else if (p->englishName=="Neptune") update(dateJDE, RotationElements::Neptune);
×
1449
                }
1450
        }
1451
        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1452
}
×
1453

1454
// Compute the transformation matrix for every elements of the solar system.
1455
// The elements have to be ordered hierarchically, eg. it's important to compute earth before moon.
1456
void SolarSystem::computeTransMatrices(double dateJDE, const Vec3d& observerPos)
×
1457
{
1458
        const double dateJD=dateJDE - (StelApp::getInstance().getCore()->computeDeltaT(dateJDE))/86400.0;
×
1459

1460
        if (flagLightTravelTime)
×
1461
        {
1462
                for (const auto& p : qAsConst(systemPlanets))
×
1463
                {
1464
                        const double light_speed_correction = (p->getHeliocentricEclipticPos()-observerPos).norm() * (AU / (SPEED_OF_LIGHT * 86400));
×
1465
                        p->computeTransMatrix(dateJD-light_speed_correction, dateJDE-light_speed_correction);
×
1466
                }
1467
        }
1468
        else
1469
        {
1470
                for (const auto& p : qAsConst(systemPlanets))
×
1471
                {
1472
                        p->computeTransMatrix(dateJD, dateJDE);
×
1473
                }
1474
        }
1475
}
×
1476

1477
// And sort them from the furthest to the closest to the observer
1478
// NOTE: std::binary_function is deprecated in C++11 and removed in C++17
1479
struct biggerDistance : public StelUtils::binary_function<PlanetP, PlanetP, bool>
1480
{
1481
        bool operator()(PlanetP p1, PlanetP p2)
×
1482
        {
1483
                return p1->getDistance() > p2->getDistance();
×
1484
        }
1485
};
1486

1487
// Draw all the elements of the solar system
1488
// We are supposed to be in heliocentric coordinate
1489
void SolarSystem::draw(StelCore* core)
×
1490
{
1491
        // AstroCalcDialog
1492
        drawEphemerisItems(core);
×
1493

1494
        if (!flagShow)
×
1495
                return;
×
1496

1497
        // Compute each Planet distance to the observer
1498
        const Vec3d obsHelioPos = core->getObserverHeliocentricEclipticPos();
×
1499

1500
        for (const auto& p : qAsConst(systemPlanets))
×
1501
        {
1502
                p->computeDistance(obsHelioPos);
×
1503
        }
1504

1505
        // And sort them from the furthest to the closest
1506
        std::sort(systemPlanets.begin(),systemPlanets.end(),biggerDistance());
×
1507

1508
        if (trailFader.getInterstate()>0.0000001f)
×
1509
        {
1510
                StelPainter sPainter(core->getProjection2d());
×
1511
                const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
×
1512
                allTrails->setOpacity(trailFader.getInterstate());
×
1513
                if (trailsThickness>1 || ppx>1.f)
×
1514
                        sPainter.setLineWidth(trailsThickness*ppx);
×
1515
                allTrails->draw(core, &sPainter);
×
1516
                if (trailsThickness>1 || ppx>1.f)
×
1517
                        sPainter.setLineWidth(1);
×
1518
        }
×
1519

1520
        // Make some voodoo to determine when labels should be displayed
1521
        const float sdLimitMag=static_cast<float>(core->getSkyDrawer()->getLimitMagnitude());
×
1522
        const float maxMagLabel = (sdLimitMag<5.f ? sdLimitMag :
×
1523
                        5.f+(sdLimitMag-5.f)*1.2f) +(static_cast<float>(labelsAmount)-3.f)*1.2f;
×
1524

1525
        // Draw the elements
1526
        for (const auto& p : qAsConst(systemPlanets))
×
1527
        {
1528
                if ( (p->getEnglishName() != "Sun") ||
×
1529
                                ((p->getEnglishName() == "Sun") && !(core->getSkyDrawer()->getFlagDrawSunAfterAtmosphere())))
×
1530
                        p->draw(core, maxMagLabel, planetNameFont);
×
1531
        }
1532

1533
        if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer() && getFlagPointer())
×
1534
                drawPointer(core);
×
1535
}
1536

1537
void SolarSystem::drawEphemerisItems(const StelCore* core)
×
1538
{
1539
        if (flagShow || (!flagShow && getFlagEphemerisAlwaysOn()))
×
1540
        {
1541
                if (getFlagEphemerisMarkers())
×
1542
                        drawEphemerisMarkers(core);
×
1543
                if (getFlagEphemerisLine())
×
1544
                        drawEphemerisLine(core);
×
1545
        }
1546
}
×
1547

1548
Vec3f SolarSystem::getEphemerisMarkerColor(int index) const
×
1549
{
1550
        // Sync index with AstroCalcDialog::generateEphemeris(). If required, switch to using a QMap.
1551
        const QVector<Vec3f> colors={
1552
                ephemerisGenericMarkerColor,
1553
                ephemerisSecondaryMarkerColor,
1554
                ephemerisMercuryMarkerColor,
1555
                ephemerisVenusMarkerColor,
1556
                ephemerisMarsMarkerColor,
1557
                ephemerisJupiterMarkerColor,
1558
                ephemerisSaturnMarkerColor};
×
1559
        return colors.value(index, ephemerisGenericMarkerColor);
×
1560
}
×
1561

1562
void SolarSystem::drawEphemerisMarkers(const StelCore *core)
×
1563
{
1564
        const int fsize = AstroCalcDialog::EphemerisList.count();
×
1565
        if (fsize==0) return;
×
1566

1567
        StelProjectorP prj;
×
1568
        if (getFlagEphemerisHorizontalCoordinates())
×
1569
                prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
1570
        else
1571
                prj = core->getProjection(StelCore::FrameJ2000);
×
1572
        StelPainter sPainter(prj);
×
1573

1574
        float size, shift, baseSize = 4.f;
×
1575
        const bool showDates = getFlagEphemerisDates();
×
1576
        const bool showMagnitudes = getFlagEphemerisMagnitudes();
×
1577
        const bool showSkippedData = getFlagEphemerisSkipData();
×
1578
        const bool skipMarkers = getFlagEphemerisSkipMarkers();
×
1579
        const bool isNowVisible = getFlagEphemerisNow();
×
1580
        const int dataStep = getEphemerisDataStep();
×
1581
        const int sizeCoeff = getEphemerisLineThickness() - 1;
×
1582
        QString info = "";
×
1583
        Vec3d win;
×
1584
        Vec3f markerColor;
×
1585
        bool skipFlag = false;
×
1586

1587
        if (getFlagEphemerisLine() && getFlagEphemerisScaleMarkers())
×
1588
                baseSize = 3.f; // The line lies through center of marker
×
1589

1590
        if (isNowVisible)
×
1591
        {
1592
                const int limit = getEphemerisDataLimit();
×
1593
                const int nsize = static_cast<int>(fsize/limit);
×
1594
                sPainter.setBlending(true, GL_ONE, GL_ONE);
×
1595
                texEphemerisNowMarker->bind();
×
1596
                Vec3d pos;
×
1597
                Vec3f win;
×
1598
                for (int i =0; i < limit; i++)
×
1599
                {
1600
                        sPainter.setColor(getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i*nsize].colorIndex));
×
1601
                        if (getFlagEphemerisHorizontalCoordinates())
×
1602
                                pos = AstroCalcDialog::EphemerisList[i*nsize].sso->getAltAzPosAuto(core);
×
1603
                        else
1604
                                pos = AstroCalcDialog::EphemerisList[i*nsize].sso->getJ2000EquatorialPos(core);
×
1605
                        if (prj->project(pos, win))
×
1606
                                sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), 6.f, 0.f);
×
1607
                }
1608
        }
1609

1610
        for (int i =0; i < fsize; i++)
×
1611
        {
1612
                skipFlag = (((i + 1)%dataStep)!=1 && dataStep!=1);
×
1613

1614
                // Check visibility of pointer
1615
                if (!(sPainter.getProjector()->projectCheck(AstroCalcDialog::EphemerisList[i].coord, win)))
×
1616
                        continue;
×
1617

1618
                QString debugStr; // Used temporarily for development
×
1619
                const bool isComet=AstroCalcDialog::EphemerisList[i].isComet;
×
1620
                if (i == AstroCalcDialog::DisplayedPositionIndex)
×
1621
                {
1622
                        markerColor = getEphemerisSelectedMarkerColor();
×
1623
                        size = 6.f;
×
1624
                }
1625
                else
1626
                {
1627
                        markerColor = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i].colorIndex);
×
1628
                        size = baseSize;
×
1629
                }
1630
                if (isComet) size += 16.f;
×
1631
                size += sizeCoeff;
×
1632
                sPainter.setColor(markerColor);
×
1633
                sPainter.setBlending(true, GL_ONE, GL_ONE);
×
1634
                if (isComet)
×
1635
                        texEphemerisCometMarker->bind();
×
1636
                else
1637
                        texEphemerisMarker->bind();
×
1638

1639
                if (skipMarkers && skipFlag)
×
1640
                        continue;
×
1641

1642
                Vec3f win;
×
1643
                float solarAngle=0.f; // Angle to possibly rotate the texture. Degrees.
×
1644
                if (prj->project(AstroCalcDialog::EphemerisList[i].coord, win))
×
1645
                {
1646
                        if (isComet)
×
1647
                        {
1648
                                // compute solarAngle in screen space.
1649
                                Vec3f sunWin;
×
1650
                                prj->project(AstroCalcDialog::EphemerisList[i].sunCoord, sunWin);
×
1651
                                // TODO: In some projections, we may need to test result and flip/mirror the angle, or deal with wrap-around effects.
1652
                                // E.g., in cylindrical mode, the comet icon will flip as soon as the corresponding sun position wraps around the screen edge.
1653
                                solarAngle=M_180_PIf*(atan2(-(win[1]-sunWin[1]), win[0]-sunWin[0]));
×
1654
                                // This will show projected positions and angles usable in labels.
1655
                                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));
×
1656
                        }
1657
                        //sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 180.f+AstroCalcDialog::EphemerisList[i].solarAngle*M_180_PIf);
1658
                        sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 270.f-solarAngle);
×
1659
                }
1660

1661
                if (showDates || showMagnitudes)
×
1662
                {
1663
                        if (showSkippedData && skipFlag)
×
1664
                                continue;
×
1665

1666
                        shift = 3.f + size/1.6f;
×
1667
                        if (showDates && showMagnitudes)
×
1668
                                info = QString("%1 (%2)").arg(AstroCalcDialog::EphemerisList[i].objDateStr, QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2));
×
1669
                        if (showDates && !showMagnitudes)
×
1670
                                info = AstroCalcDialog::EphemerisList[i].objDateStr;
×
1671
                        if (!showDates && showMagnitudes)
×
1672
                                info = QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2);
×
1673

1674
                        // Activate for debug labels.
1675
                        //info=debugStr;
1676
                        sPainter.drawText(AstroCalcDialog::EphemerisList[i].coord, info, 0, shift, shift, false);
×
1677
                }
1678
        }
×
1679
}
×
1680

1681
void SolarSystem::drawEphemerisLine(const StelCore *core)
×
1682
{
1683
        const int size = AstroCalcDialog::EphemerisList.count();
×
1684
        if (size==0) return;
×
1685

1686
        // The array of data is not empty - good news!
1687
        StelProjectorP prj;
×
1688
        if (getFlagEphemerisHorizontalCoordinates())
×
1689
                prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
1690
        else
1691
                prj = core->getProjection(StelCore::FrameJ2000);
×
1692
        StelPainter sPainter(prj);
×
1693
        const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
×
1694

1695
        const float oldLineThickness=sPainter.getLineWidth();
×
1696
        const float lineThickness = getEphemerisLineThickness()*ppx;
×
1697
        if (!fuzzyEquals(lineThickness, oldLineThickness))
×
1698
                sPainter.setLineWidth(lineThickness);
×
1699

1700
        Vec3f color;
×
1701
        QVector<Vec3d> vertexArray;
×
1702
        QVector<Vec4f> colorArray;
×
1703
        const int limit = getEphemerisDataLimit();
×
1704
        const int nsize = static_cast<int>(size/limit);
×
1705
        vertexArray.resize(nsize);
×
1706
        colorArray.resize(nsize);
×
1707
        for (int j=0; j<limit; j++)
×
1708
        {
1709
                for (int i =0; i < nsize; i++)
×
1710
                {
1711
                        color = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i + j*nsize].colorIndex);
×
1712
                        colorArray[i]=Vec4f(color, 1.0f);
×
1713
                        vertexArray[i]=AstroCalcDialog::EphemerisList[i + j*nsize].coord;
×
1714
                }
1715
                sPainter.drawPath(vertexArray, colorArray);
×
1716
        }
1717

1718
        if (!fuzzyEquals(lineThickness, oldLineThickness))
×
1719
                sPainter.setLineWidth(oldLineThickness); // restore line thickness
×
1720
}
×
1721

1722
void SolarSystem::fillEphemerisDates()
×
1723
{
1724
        const int fsize = AstroCalcDialog::EphemerisList.count();
×
1725
        if (fsize==0) return;
×
1726

1727
        StelLocaleMgr* localeMgr = &StelApp::getInstance().getLocaleMgr();
×
1728
        const bool showSmartDates = getFlagEphemerisSmartDates();
×
1729
        double JD = AstroCalcDialog::EphemerisList.first().objDate;
×
1730
        bool withTime = (fsize>1 && (AstroCalcDialog::EphemerisList[1].objDate-JD<1.0));
×
1731

1732
        int fYear, fMonth, fDay, sYear, sMonth, sDay, h, m, s;
1733
        QString info;
×
1734
        const double shift = StelApp::getInstance().getCore()->getUTCOffset(JD)*StelCore::JD_HOUR;
×
1735
        StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
×
1736
        bool sFlag = true;
×
1737
        sYear = fYear;
×
1738
        sMonth = fMonth;
×
1739
        sDay = fDay;
×
1740
        const bool showSkippedData = getFlagEphemerisSkipData();
×
1741
        const int dataStep = getEphemerisDataStep();
×
1742

1743
        for (int i = 0; i < fsize; i++)
×
1744
        {
1745
                JD = AstroCalcDialog::EphemerisList[i].objDate;
×
1746
                StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
×
1747

1748
                if (showSkippedData && ((i + 1)%dataStep)!=1 && dataStep!=1)
×
1749
                        continue;
×
1750

1751
                if (showSmartDates)
×
1752
                {
1753
                        if (sFlag)
×
1754
                                info = QString("%1").arg(fYear);
×
1755

1756
                        if (info.isEmpty() && !sFlag && fYear!=sYear)
×
1757
                                info = QString("%1").arg(fYear);
×
1758

1759
                        if (!info.isEmpty())
×
1760
                                info.append(QString("/%1").arg(localeMgr->romanMonthName(fMonth)));
×
1761
                        else if (fMonth!=sMonth)
×
1762
                                info = QString("%1").arg(localeMgr->romanMonthName(fMonth));
×
1763

1764
                        if (!info.isEmpty())
×
1765
                                info.append(QString("/%1").arg(fDay));
×
1766
                        else
1767
                                info = QString("%1").arg(fDay);
×
1768

1769
                        if (withTime) // very short step
×
1770
                        {
1771
                                if (fDay==sDay && !sFlag)
×
1772
                                        info.clear();
×
1773

1774
                                StelUtils::getTimeFromJulianDay(JD+shift, &h, &m, &s);
×
1775
                                QString hours = QString::number(h).rightJustified(2, '0');
×
1776
                                QString minutes = QString::number(m).rightJustified(2, '0');
×
1777
                                if (!info.isEmpty())
×
1778
                                        info.append(QString(" %1:%2").arg(hours, minutes));
×
1779
                                else
1780
                                        info = QString("%1:%2").arg(hours, minutes);
×
1781
                        }
×
1782

1783
                        AstroCalcDialog::EphemerisList[i].objDateStr = info;
×
1784
                        info.clear();
×
1785
                        sYear = fYear;
×
1786
                        sMonth = fMonth;
×
1787
                        sDay = fDay;
×
1788
                        sFlag = false;
×
1789
                }
1790
                else
1791
                {
1792
                        // OK, let's use standard formats for date and time (as defined for whole planetarium)
1793
                        if (withTime)
×
1794
                                AstroCalcDialog::EphemerisList[i].objDateStr = QString("%1 %2").arg(localeMgr->getPrintableDateLocal(JD), localeMgr->getPrintableTimeLocal(JD));
×
1795
                        else
1796
                                AstroCalcDialog::EphemerisList[i].objDateStr = localeMgr->getPrintableDateLocal(JD);
×
1797
                }
1798
        }
1799
}
×
1800

1801
PlanetP SolarSystem::searchByEnglishName(QString planetEnglishName) const
×
1802
{
1803
        for (const auto& p : systemPlanets)
×
1804
        {
1805
                if (p->getEnglishName().toUpper() == planetEnglishName.toUpper() || p->getCommonEnglishName().toUpper() == planetEnglishName.toUpper())
×
1806
                        return p;
×
1807

1808
                // IAU designation?
1809
                QString iau = p->getIAUDesignation();
×
1810
                if (!iau.isEmpty() && iau.toUpper()==planetEnglishName.toUpper())
×
1811
                        return p;
×
1812
        }
×
1813
        for (const auto& p : systemMinorBodies)
×
1814
        {
1815
                QStringList c;
×
1816
                // other comet designations?
1817
                if (p->getPlanetType()==Planet::isComet)
×
1818
                {
1819
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
1820
                        c = mp->getExtraDesignations();
×
1821
                } else {
×
1822
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
1823
                        c = mp->getExtraDesignations();
×
1824
                }
×
1825
                for (const auto& d : c)
×
1826
                {
1827
                        if (d.toUpper()==planetEnglishName.toUpper())
×
1828
                                return p;
×
1829
                }
1830
        }
×
1831
        return PlanetP();
×
1832
}
1833

1834
PlanetP SolarSystem::searchMinorPlanetByEnglishName(QString planetEnglishName) const
×
1835
{
1836
        for (const auto& p : systemMinorBodies)
×
1837
        {
1838
                if (p->getCommonEnglishName().toUpper() == planetEnglishName.toUpper() || p->getEnglishName().toUpper() == planetEnglishName.toUpper())
×
1839
                        return p;
×
1840

1841
                // IAU designation?
1842
                QString iau = p->getIAUDesignation();
×
1843
                if (!iau.isEmpty() && iau.toUpper()==planetEnglishName.toUpper())
×
1844
                        return p;
×
1845

1846
                QStringList c;
×
1847
                // other comet designations?
1848
                if (p->getPlanetType()==Planet::isComet)
×
1849
                {
1850
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
1851
                        c = mp->getExtraDesignations();
×
1852
                }
×
1853
                else
1854
                {
1855
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
1856
                        c = mp->getExtraDesignations();
×
1857
                }
×
1858
                for (const auto& d : c)
×
1859
                {
1860
                        if (d.toUpper()==planetEnglishName.toUpper())
×
1861
                                return p;
×
1862
                }
1863
        }
×
1864
        return PlanetP();
×
1865
}
1866

1867

1868
StelObjectP SolarSystem::searchByNameI18n(const QString& planetNameI18) const
×
1869
{
1870
        for (const auto& p : systemPlanets)
×
1871
        {
1872
                QString nativeName = p->getNativeNameI18n().toUpper();
×
1873
                if (p->getNameI18n().toUpper() == planetNameI18.toUpper() || (!nativeName.isEmpty() && nativeName == planetNameI18.toUpper()))
×
1874
                        return qSharedPointerCast<StelObject>(p);
×
1875
        }
×
1876
        return StelObjectP();
×
1877
}
1878

1879

1880
StelObjectP SolarSystem::searchByName(const QString& name) const
×
1881
{
1882
        for (const auto& p : systemPlanets)
×
1883
        {
1884
                QString nativeName = p->getNativeName().toUpper();
×
1885
                if (p->getEnglishName().toUpper() == name.toUpper() || (!nativeName.isEmpty() && nativeName == name.toUpper()))
×
1886
                        return qSharedPointerCast<StelObject>(p);
×
1887

1888
                // IAU designation?
1889
                QString iau = p->getIAUDesignation();
×
1890
                if (!iau.isEmpty() && iau.toUpper()==name.toUpper())
×
1891
                        return qSharedPointerCast<StelObject>(p);
×
1892
        }
×
1893
        for (const auto& p : systemMinorBodies)
×
1894
        {
1895
                QStringList c;
×
1896
                // other comet designations?
1897
                if (p->getPlanetType()==Planet::isComet)
×
1898
                {
1899
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
1900
                        c = mp->getExtraDesignations();
×
1901
                }
×
1902
                else
1903
                {
1904
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
1905
                        c = mp->getExtraDesignations();
×
1906
                }
×
1907
                for (const auto& d : c)
×
1908
                {
1909
                        if (d.toUpper()==name.toUpper())
×
1910
                                return qSharedPointerCast<StelObject>(p);
×
1911
                }
1912
        }
×
1913

1914
        return StelObjectP();
×
1915
}
1916

1917
float SolarSystem::getPlanetVMagnitude(QString planetName, bool withExtinction) const
×
1918
{
1919
        PlanetP p = searchByEnglishName(planetName);
×
1920
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
1921
                p = searchMinorPlanetByEnglishName(planetName);
×
1922
        float r = 0.f;
×
1923
        if (withExtinction)
×
1924
                r = p->getVMagnitudeWithExtinction(StelApp::getInstance().getCore());
×
1925
        else
1926
                r = p->getVMagnitude(StelApp::getInstance().getCore());
×
1927
        return r;
×
1928
}
×
1929

1930
QString SolarSystem::getPlanetType(QString planetName) const
×
1931
{
1932
        PlanetP p = searchByEnglishName(planetName);
×
1933
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
1934
                p = searchMinorPlanetByEnglishName(planetName);
×
1935
        if (p.isNull())
×
1936
                return QString("UNDEFINED");
×
1937
        return p->getObjectType();
×
1938
}
×
1939

1940
double SolarSystem::getDistanceToPlanet(QString planetName) const
×
1941
{
1942
        PlanetP p = searchByEnglishName(planetName);
×
1943
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
1944
                p = searchMinorPlanetByEnglishName(planetName);
×
1945
        return p->getDistance();
×
1946
}
×
1947

1948
double SolarSystem::getElongationForPlanet(QString planetName) const
×
1949
{
1950
        PlanetP p = searchByEnglishName(planetName);
×
1951
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
1952
                p = searchMinorPlanetByEnglishName(planetName);
×
1953
        return p->getElongation(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
1954
}
×
1955

1956
double SolarSystem::getPhaseAngleForPlanet(QString planetName) const
×
1957
{
1958
        PlanetP p = searchByEnglishName(planetName);
×
1959
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
1960
                p = searchMinorPlanetByEnglishName(planetName);
×
1961
        return p->getPhaseAngle(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
1962
}
×
1963

1964
float SolarSystem::getPhaseForPlanet(QString planetName) const
×
1965
{
1966
        PlanetP p = searchByEnglishName(planetName);
×
1967
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
1968
                p = searchMinorPlanetByEnglishName(planetName);
×
1969
        return p->getPhase(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
1970
}
×
1971

1972
QStringList SolarSystem::getObjectsList(QString objType) const
×
1973
{
1974
        QStringList r;
×
1975
        if (objType.toLower()=="all")
×
1976
        {
1977
                r = listAllObjects(true);
×
1978
                // Remove the Sun
1979
                r.removeOne("Sun");
×
1980
                // Remove special objects
1981
                r.removeOne("Solar System Observer");
×
1982
                r.removeOne("Earth Observer");
×
1983
                r.removeOne("Mars Observer");
×
1984
                r.removeOne("Jupiter Observer");
×
1985
                r.removeOne("Saturn Observer");
×
1986
                r.removeOne("Uranus Observer");
×
1987
                r.removeOne("Neptune Observer");
×
1988
        }
1989
        else
1990
                r = listAllObjectsByType(objType, true);
×
1991

1992
        return r;
×
1993
}
×
1994

1995
// Search if any Planet is close to position given in earth equatorial position and return the distance
1996
StelObjectP SolarSystem::search(Vec3d pos, const StelCore* core) const
×
1997
{
1998
        pos.normalize();
×
1999
        PlanetP closest;
×
2000
        double cos_angle_closest = 0.;
×
2001
        Vec3d equPos;
×
2002

2003
        for (const auto& p : systemPlanets)
×
2004
        {
2005
                equPos = p->getEquinoxEquatorialPos(core);
×
2006
                equPos.normalize();
×
2007
                double cos_ang_dist = equPos*pos;
×
2008
                if (cos_ang_dist>cos_angle_closest)
×
2009
                {
2010
                        closest = p;
×
2011
                        cos_angle_closest = cos_ang_dist;
×
2012
                }
2013
        }
2014

2015
        if (cos_angle_closest>0.999)
×
2016
        {
2017
                return qSharedPointerCast<StelObject>(closest);
×
2018
        }
2019
        else return StelObjectP();
×
2020
}
×
2021

2022
// Return a QList containing the planets located inside the limFov circle around position vv
2023
QList<StelObjectP> SolarSystem::searchAround(const Vec3d& vv, double limitFov, const StelCore* core) const
×
2024
{
2025
        QList<StelObjectP> result;
×
2026
        if (!getFlagPlanets())
×
2027
                return result;
×
2028

2029
        const bool withAberration=core->getUseAberration();
×
2030
        Vec3d v(vv);
×
2031
        v.normalize(); // TODO: start with vv already normalized?
×
2032
        if (withAberration)
×
2033
        {
2034
                Vec3d vel=core->getCurrentPlanet()->getHeliocentricEclipticVelocity();
×
2035
                StelCore::matVsop87ToJ2000.transfo(vel);
×
2036
                vel*=core->getAberrationFactor()*(AU/(86400.0*SPEED_OF_LIGHT));
×
2037
                v+=vel;
×
2038
                v.normalize();
×
2039
        }
2040

2041
        double cosLimFov = std::cos(limitFov * M_PI/180.);
×
2042
        Vec3d equPos;
×
2043
        double cosAngularSize;
2044

2045
        const QString weAreHere = core->getCurrentPlanet()->getEnglishName();
×
2046
        for (const auto& p : systemPlanets)
×
2047
        {
2048
                equPos = p->getJ2000EquatorialPos(core);
×
2049
                equPos.normalize();
×
2050

2051
                cosAngularSize = std::cos(p->getSpheroidAngularRadius(core) * M_PI/180.);
×
2052

2053
                if (equPos*v>=std::min(cosLimFov, cosAngularSize) && p->getEnglishName()!=weAreHere)
×
2054
                {
2055
                        result.append(qSharedPointerCast<StelObject>(p));
×
2056
                }
2057
        }
2058
        return result;
×
2059
}
×
2060

2061
// Update i18 names from english names according to current sky culture translator
2062
void SolarSystem::updateI18n()
×
2063
{
2064
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
2065
        for (const auto& p : qAsConst(systemPlanets))
×
2066
                p->translateName(trans);
×
2067
}
×
2068

2069
QStringList SolarSystem::listMatchingObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
×
2070
{
2071
        QStringList result;
×
2072
        if (getFlagPlanets())
×
2073
                result = StelObjectModule::listMatchingObjects(objPrefix, maxNbItem, useStartOfWords);
×
2074
        return result;
×
2075
}
×
2076

2077
void SolarSystem::setFlagTrails(bool b)
×
2078
{
2079
        if (getFlagTrails() != b)
×
2080
        {
2081
                trailFader = b;
×
2082
                if (b)
×
2083
                {
2084
                        allTrails->reset(maxTrailPoints);
×
2085
                        recreateTrails();
×
2086
                }
2087
                emit trailsDisplayedChanged(b);
×
2088
        }
2089
}
×
2090

2091
bool SolarSystem::getFlagTrails() const
×
2092
{
2093
        return static_cast<bool>(trailFader);
×
2094
}
2095

2096
void SolarSystem::setMaxTrailPoints(int max)
×
2097
{
2098
        if (maxTrailPoints != max)
×
2099
        {
2100
                maxTrailPoints = max;
×
2101
                allTrails->reset(max);
×
2102
                recreateTrails();
×
2103
                emit maxTrailPointsChanged(max);
×
2104
        }
2105
}
×
2106

2107
void SolarSystem::setMaxTrailTimeExtent(int max)
×
2108
{
2109
        if (maxTrailTimeExtent != max && maxTrailTimeExtent > 0)
×
2110
        {
2111
                maxTrailTimeExtent = max;
×
2112
                recreateTrails();
×
2113
                emit maxTrailTimeExtentChanged(max);
×
2114
        }
2115
}
×
2116

2117
void SolarSystem::setTrailsThickness(int v)
×
2118
{
2119
        if (trailsThickness != v)
×
2120
        {
2121
                trailsThickness = v;
×
2122
                emit trailsThicknessChanged(v);
×
2123
        }
2124
}
×
2125

2126
void SolarSystem::setFlagHints(bool b)
×
2127
{
2128
        if (getFlagHints() != b)
×
2129
        {
2130
                for (const auto& p : qAsConst(systemPlanets))
×
2131
                        p->setFlagHints(b);
×
2132
                emit flagHintsChanged(b);
×
2133
        }
2134
}
×
2135

2136
bool SolarSystem::getFlagHints(void) const
×
2137
{
2138
        for (const auto& p : systemPlanets)
×
2139
        {
2140
                if (p->getFlagHints())
×
2141
                        return true;
×
2142
        }
2143
        return false;
×
2144
}
2145

2146
void SolarSystem::setFlagLabels(bool b)
×
2147
{
2148
        if (getFlagLabels() != b)
×
2149
        {
2150
                for (const auto& p : qAsConst(systemPlanets))
×
2151
                        p->setFlagLabels(b);
×
2152
                emit labelsDisplayedChanged(b);
×
2153
        }
2154
}
×
2155

2156
bool SolarSystem::getFlagLabels() const
×
2157
{
2158
        for (const auto& p : systemPlanets)
×
2159
        {
2160
                if (p->getFlagLabels())
×
2161
                        return true;
×
2162
        }
2163
        return false;
×
2164
}
2165

2166
void SolarSystem::setFlagLightTravelTime(bool b)
×
2167
{
2168
        if(b!=flagLightTravelTime)
×
2169
        {
2170
                flagLightTravelTime = b;
×
2171
                emit flagLightTravelTimeChanged(b);
×
2172
        }
2173
}
×
2174

2175
void SolarSystem::setFlagShowObjSelfShadows(bool b)
×
2176
{
2177
        if(b!=flagShowObjSelfShadows)
×
2178
        {
2179
                flagShowObjSelfShadows = b;
×
2180
                if(!b)
×
2181
                        Planet::deinitFBO();
×
2182
                emit flagShowObjSelfShadowsChanged(b);
×
2183
        }
2184
}
×
2185

2186
void SolarSystem::setSelected(PlanetP obj)
×
2187
{
2188
        if (obj && obj->getType() == "Planet")
×
2189
        {
2190
                selected = obj;
×
2191
                selectedSSO.push_back(obj);
×
2192
        }
2193
        else
2194
                selected.clear();
×
2195
        // Undraw other objects hints, orbit, trails etc..
2196
        setFlagHints(getFlagHints());
×
2197
        reconfigureOrbits();
×
2198
}
×
2199

2200

2201
void SolarSystem::update(double deltaTime)
×
2202
{
2203
        trailFader.update(static_cast<int>(deltaTime*1000));
×
2204
        if (trailFader.getInterstate()>0.f)
×
2205
        {
2206
                allTrails->update();
×
2207
        }
2208

2209
        for (const auto& p : qAsConst(systemPlanets))
×
2210
        {
2211
                p->update(static_cast<int>(deltaTime*1000));
×
2212
        }
2213
}
×
2214

2215
// is a lunar eclipse close at hand?
2216
bool SolarSystem::nearLunarEclipse() const
×
2217
{
2218
        // TODO: could replace with simpler test
2219
        // TODO Source?
2220

2221
        const Vec3d sun = getSun()->getAberrationPush();
×
2222
        const Vec3d e = getEarth()->getEclipticPos();
×
2223
        const Vec3d m = getMoon()->getEclipticPos();  // relative to earth
×
2224
        const Vec3d mh = getMoon()->getHeliocentricEclipticPos();  // relative to sun
×
2225

2226
        // shadow location at earth + moon distance along earth vector from (aberrated) sun
2227
        Vec3d en = e-sun;
×
2228
        en.normalize();
×
2229
        Vec3d shadow = en * (e.norm() + m.norm());
×
2230

2231
        // find shadow radii in AU
2232
        double r_penumbra = shadow.norm()*702378.1/AU/e.norm() - SUN_RADIUS/AU;
×
2233

2234
        // modify shadow location for scaled moon
2235
        Vec3d mdist = shadow - mh;
×
2236
        if(mdist.norm() > r_penumbra + 2000./AU) return false;   // not visible so don't bother drawing
×
2237

2238
        return true;
×
2239
}
2240

2241
QStringList SolarSystem::listAllObjects(bool inEnglish) const
×
2242
{
2243
        QStringList result;
×
2244
        if (inEnglish)
×
2245
        {
2246
                for (const auto& p : systemPlanets)
×
2247
                {
2248
                        result << p->getEnglishName();
×
2249
                        if (!p->getIAUDesignation().isEmpty())
×
2250
                                result << p->getIAUDesignation();
×
2251
                }
2252
        }
2253
        else
2254
        {
2255
                for (const auto& p : systemPlanets)
×
2256
                {
2257
                        result << p->getNameI18n();
×
2258
                        if (!p->getNativeNameI18n().isEmpty())
×
2259
                                result << p->getNativeNameI18n() << p->getNativeName();
×
2260
                        if (!p->getIAUDesignation().isEmpty())
×
2261
                                result << p->getIAUDesignation();
×
2262
                }
2263
        }
2264
        for (const auto& p : systemMinorBodies)
×
2265
        {
2266
                QStringList c;
×
2267
                // other comet designations?
2268
                if (p->getPlanetType()==Planet::isComet)
×
2269
                {
2270
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2271
                        c = mp->getExtraDesignations();
×
2272
                } else {
×
2273
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2274
                        c = mp->getExtraDesignations();
×
2275
                }
×
2276
                if (c.count()>0)
×
2277
                        result << c;
×
2278
        }
×
2279
        return result;
×
2280
}
×
2281

2282
QStringList SolarSystem::listAllObjectsByType(const QString &objType, bool inEnglish) const
×
2283
{
2284
        QStringList result;
×
2285
        if (inEnglish)
×
2286
        {
2287
                for (const auto& p : systemPlanets)
×
2288
                {
2289
                        if (p->getObjectType()==objType)
×
2290
                        {
2291
                                result << p->getEnglishName();
×
2292
                                if (!p->getIAUDesignation().isEmpty())
×
2293
                                        result << p->getIAUDesignation();
×
2294
                        }
2295
                }
2296
        }
2297
        else
2298
        {
2299
                for (const auto& p : systemPlanets)
×
2300
                {
2301
                        if (p->getObjectType()==objType)
×
2302
                        {
2303
                                result << p->getNameI18n();
×
2304
                                if (!p->getIAUDesignation().isEmpty())
×
2305
                                        result << p->getIAUDesignation();
×
2306
                        }
2307
                }
2308
        }
2309
        for (const auto& p : systemMinorBodies)
×
2310
        {
2311
                if (p->getObjectType()==objType)
×
2312
                {
2313
                        QStringList c;
×
2314
                        // other comet designations?
2315
                        if (p->getPlanetType()==Planet::isComet)
×
2316
                        {
2317
                                QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2318
                                c = mp->getExtraDesignations();
×
2319
                        } else {
×
2320
                                QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2321
                                c = mp->getExtraDesignations();
×
2322
                        }
×
2323
                        if (c.count()>0)
×
2324
                                result << c;
×
2325
                }
×
2326
        }
2327
        return result;
×
2328
}
×
2329

2330
void SolarSystem::selectedObjectChange(StelModule::StelModuleSelectAction)
×
2331
{
2332
        const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet");
×
2333
        if (!newSelected.empty())
×
2334
        {
2335
                setSelected(qSharedPointerCast<Planet>(newSelected[0]));
×
2336
                if (getFlagIsolatedTrails())
×
2337
                        recreateTrails();
×
2338
        }
2339
        else
2340
                setSelected("");
×
2341
}
×
2342

2343
// Activate/Deactivate planets display
2344
void SolarSystem::setFlagPlanets(bool b)
×
2345
{
2346
        if (b!=flagShow)
×
2347
        {
2348
                flagShow=b;
×
2349
                emit flagPlanetsDisplayedChanged(b);
×
2350
        }
2351
}
×
2352

2353
bool SolarSystem::getFlagPlanets(void) const
×
2354
{
2355
        return flagShow;
×
2356
}
2357

2358
void SolarSystem::setFlagEphemerisMarkers(bool b)
×
2359
{
2360
        if (b!=ephemerisMarkersDisplayed)
×
2361
        {
2362
                ephemerisMarkersDisplayed=b;
×
2363
                conf->setValue("astrocalc/flag_ephemeris_markers", b); // Immediate saving of state
×
2364
                emit ephemerisMarkersChanged(b);
×
2365
        }
2366
}
×
2367

2368
bool SolarSystem::getFlagEphemerisMarkers() const
×
2369
{
2370
        return ephemerisMarkersDisplayed;
×
2371
}
2372

2373
void SolarSystem::setFlagEphemerisLine(bool b)
×
2374
{
2375
        if (b!=ephemerisLineDisplayed)
×
2376
        {
2377
                ephemerisLineDisplayed=b;
×
2378
                conf->setValue("astrocalc/flag_ephemeris_line", b); // Immediate saving of state
×
2379
                emit ephemerisLineChanged(b);
×
2380
        }
2381
}
×
2382

2383
bool SolarSystem::getFlagEphemerisLine() const
×
2384
{
2385
        return ephemerisLineDisplayed;
×
2386
}
2387

2388
bool SolarSystem::getFlagEphemerisAlwaysOn() const
×
2389
{
2390
        return ephemerisAlwaysOn;
×
2391
}
2392

2393
void SolarSystem::setFlagEphemerisAlwaysOn(bool b)
×
2394
{
2395
        if (b != ephemerisAlwaysOn)
×
2396
        {
2397
                ephemerisAlwaysOn = b;
×
2398
                conf->setValue("astrocalc/flag_ephemeris_alwayson", b); // Immediate saving of state
×
2399
                emit ephemerisAlwaysOnChanged(b);
×
2400
        }
2401
}
×
2402

2403
bool SolarSystem::getFlagEphemerisNow() const
×
2404
{
2405
        return ephemerisNow;
×
2406
}
2407

2408
void SolarSystem::setFlagEphemerisNow(bool b)
×
2409
{
2410
        if (b != ephemerisNow)
×
2411
        {
2412
                ephemerisNow = b;
×
2413
                conf->setValue("astrocalc/flag_ephemeris_now", b); // Immediate saving of state
×
2414
                emit ephemerisNowChanged(b);
×
2415
        }
2416
}
×
2417

2418
void SolarSystem::setFlagEphemerisHorizontalCoordinates(bool b)
×
2419
{
2420
        if (b!=ephemerisHorizontalCoordinates)
×
2421
        {
2422
                ephemerisHorizontalCoordinates=b;
×
2423
                conf->setValue("astrocalc/flag_ephemeris_horizontal", b); // Immediate saving of state
×
2424
                emit ephemerisHorizontalCoordinatesChanged(b);
×
2425
        }
2426
}
×
2427

2428
bool SolarSystem::getFlagEphemerisHorizontalCoordinates() const
×
2429
{
2430
        return ephemerisHorizontalCoordinates;
×
2431
}
2432

2433
void SolarSystem::setFlagEphemerisDates(bool b)
×
2434
{
2435
        if (b!=ephemerisDatesDisplayed)
×
2436
        {
2437
                ephemerisDatesDisplayed=b;
×
2438
                conf->setValue("astrocalc/flag_ephemeris_dates", b); // Immediate saving of state
×
2439
                emit ephemerisDatesChanged(b);
×
2440
        }
2441
}
×
2442

2443
bool SolarSystem::getFlagEphemerisDates() const
×
2444
{
2445
        return ephemerisDatesDisplayed;
×
2446
}
2447

2448
void SolarSystem::setFlagEphemerisMagnitudes(bool b)
×
2449
{
2450
        if (b!=ephemerisMagnitudesDisplayed)
×
2451
        {
2452
                ephemerisMagnitudesDisplayed=b;
×
2453
                conf->setValue("astrocalc/flag_ephemeris_magnitudes", b); // Immediate saving of state
×
2454
                emit ephemerisMagnitudesChanged(b);
×
2455
        }
2456
}
×
2457

2458
bool SolarSystem::getFlagEphemerisMagnitudes() const
×
2459
{
2460
        return ephemerisMagnitudesDisplayed;
×
2461
}
2462

2463
void SolarSystem::setFlagEphemerisSkipData(bool b)
×
2464
{
2465
        if (b!=ephemerisSkipDataDisplayed)
×
2466
        {
2467
                ephemerisSkipDataDisplayed=b;
×
2468
                conf->setValue("astrocalc/flag_ephemeris_skip_data", b); // Immediate saving of state
×
2469
                emit ephemerisSkipDataChanged(b);
×
2470
        }
2471
}
×
2472

2473
bool SolarSystem::getFlagEphemerisSkipData() const
×
2474
{
2475
        return ephemerisSkipDataDisplayed;
×
2476
}
2477

2478
void SolarSystem::setFlagEphemerisSkipMarkers(bool b)
×
2479
{
2480
        if (b!=ephemerisSkipMarkersDisplayed)
×
2481
        {
2482
                ephemerisSkipMarkersDisplayed=b;
×
2483
                conf->setValue("astrocalc/flag_ephemeris_skip_markers", b); // Immediate saving of state
×
2484
                emit ephemerisSkipMarkersChanged(b);
×
2485
        }
2486
}
×
2487

2488
bool SolarSystem::getFlagEphemerisSkipMarkers() const
×
2489
{
2490
        return ephemerisSkipMarkersDisplayed;
×
2491
}
2492

2493
void SolarSystem::setFlagEphemerisSmartDates(bool b)
×
2494
{
2495
        if (b!=ephemerisSmartDatesDisplayed)
×
2496
        {
2497
                ephemerisSmartDatesDisplayed=b;
×
2498
                conf->setValue("astrocalc/flag_ephemeris_smart_dates", b); // Immediate saving of state
×
2499
                emit ephemerisSmartDatesChanged(b);
×
2500
        }
2501
}
×
2502

2503
bool SolarSystem::getFlagEphemerisSmartDates() const
×
2504
{
2505
        return ephemerisSmartDatesDisplayed;
×
2506
}
2507

2508
void SolarSystem::setFlagEphemerisScaleMarkers(bool b)
×
2509
{
2510
        if (b!=ephemerisScaleMarkersDisplayed)
×
2511
        {
2512
                ephemerisScaleMarkersDisplayed=b;
×
2513
                conf->setValue("astrocalc/flag_ephemeris_scale_markers", b); // Immediate saving of state
×
2514
                emit ephemerisScaleMarkersChanged(b);
×
2515
        }
2516
}
×
2517

2518
bool SolarSystem::getFlagEphemerisScaleMarkers() const
×
2519
{
2520
        return ephemerisScaleMarkersDisplayed;
×
2521
}
2522

2523
void SolarSystem::setEphemerisDataStep(int step)
×
2524
{
2525
        ephemerisDataStep = step;
×
2526
        // automatic saving of the setting
2527
        conf->setValue("astrocalc/ephemeris_data_step", step);
×
2528
        emit ephemerisDataStepChanged(step);
×
2529
}
×
2530

2531
int SolarSystem::getEphemerisDataStep() const
×
2532
{
2533
        return ephemerisDataStep;
×
2534
}
2535

2536
void SolarSystem::setEphemerisDataLimit(int limit)
×
2537
{
2538
        ephemerisDataLimit = limit;
×
2539
        emit ephemerisDataLimitChanged(limit);
×
2540
}
×
2541

2542
int SolarSystem::getEphemerisDataLimit() const
×
2543
{
2544
        return ephemerisDataLimit;
×
2545
}
2546

2547
void SolarSystem::setEphemerisLineThickness(int v)
×
2548
{
2549
        ephemerisLineThickness = v;
×
2550
        // automatic saving of the setting
2551
        conf->setValue("astrocalc/ephemeris_line_thickness", v);
×
2552
        emit ephemerisLineThicknessChanged(v);
×
2553
}
×
2554

2555
int SolarSystem::getEphemerisLineThickness() const
×
2556
{
2557
        return ephemerisLineThickness;
×
2558
}
2559

2560
void SolarSystem::setEphemerisGenericMarkerColor(const Vec3f& color)
×
2561
{
2562
        if (color!=ephemerisGenericMarkerColor)
×
2563
        {
2564
                ephemerisGenericMarkerColor = color;
×
2565
                emit ephemerisGenericMarkerColorChanged(color);
×
2566
        }
2567
}
×
2568

2569
Vec3f SolarSystem::getEphemerisGenericMarkerColor() const
×
2570
{
2571
        return ephemerisGenericMarkerColor;
×
2572
}
2573

2574
void SolarSystem::setEphemerisSecondaryMarkerColor(const Vec3f& color)
×
2575
{
2576
        if (color!=ephemerisSecondaryMarkerColor)
×
2577
        {
2578
                ephemerisSecondaryMarkerColor = color;
×
2579
                emit ephemerisSecondaryMarkerColorChanged(color);
×
2580
        }
2581
}
×
2582

2583
Vec3f SolarSystem::getEphemerisSecondaryMarkerColor() const
×
2584
{
2585
        return ephemerisSecondaryMarkerColor;
×
2586
}
2587

2588
void SolarSystem::setEphemerisSelectedMarkerColor(const Vec3f& color)
×
2589
{
2590
        if (color!=ephemerisSelectedMarkerColor)
×
2591
        {
2592
                ephemerisSelectedMarkerColor = color;
×
2593
                emit ephemerisSelectedMarkerColorChanged(color);
×
2594
        }
2595
}
×
2596

2597
Vec3f SolarSystem::getEphemerisSelectedMarkerColor() const
×
2598
{
2599
        return ephemerisSelectedMarkerColor;
×
2600
}
2601

2602
void SolarSystem::setEphemerisMercuryMarkerColor(const Vec3f& color)
×
2603
{
2604
        if (color!=ephemerisMercuryMarkerColor)
×
2605
        {
2606
                ephemerisMercuryMarkerColor = color;
×
2607
                emit ephemerisMercuryMarkerColorChanged(color);
×
2608
        }
2609
}
×
2610

2611
Vec3f SolarSystem::getEphemerisMercuryMarkerColor() const
×
2612
{
2613
        return ephemerisMercuryMarkerColor;
×
2614
}
2615

2616
void SolarSystem::setEphemerisVenusMarkerColor(const Vec3f& color)
×
2617
{
2618
        if (color!=ephemerisVenusMarkerColor)
×
2619
        {
2620
                ephemerisVenusMarkerColor = color;
×
2621
                emit ephemerisVenusMarkerColorChanged(color);
×
2622
        }
2623
}
×
2624

2625
Vec3f SolarSystem::getEphemerisVenusMarkerColor() const
×
2626
{
2627
        return ephemerisVenusMarkerColor;
×
2628
}
2629

2630
void SolarSystem::setEphemerisMarsMarkerColor(const Vec3f& color)
×
2631
{
2632
        if (color!=ephemerisMarsMarkerColor)
×
2633
        {
2634
                ephemerisMarsMarkerColor = color;
×
2635
                emit ephemerisMarsMarkerColorChanged(color);
×
2636
        }
2637
}
×
2638

2639
Vec3f SolarSystem::getEphemerisMarsMarkerColor() const
×
2640
{
2641
        return ephemerisMarsMarkerColor;
×
2642
}
2643

2644
void SolarSystem::setEphemerisJupiterMarkerColor(const Vec3f& color)
×
2645
{
2646
        if (color!=ephemerisJupiterMarkerColor)
×
2647
        {
2648
                ephemerisJupiterMarkerColor = color;
×
2649
                emit ephemerisJupiterMarkerColorChanged(color);
×
2650
        }
2651
}
×
2652

2653
Vec3f SolarSystem::getEphemerisJupiterMarkerColor() const
×
2654
{
2655
        return ephemerisJupiterMarkerColor;
×
2656
}
2657

2658
void SolarSystem::setEphemerisSaturnMarkerColor(const Vec3f& color)
×
2659
{
2660
        if (color!=ephemerisSaturnMarkerColor)
×
2661
        {
2662
                ephemerisSaturnMarkerColor = color;
×
2663
                emit ephemerisSaturnMarkerColorChanged(color);
×
2664
        }
2665
}
×
2666

2667
Vec3f SolarSystem::getEphemerisSaturnMarkerColor() const
×
2668
{
2669
        return ephemerisSaturnMarkerColor;
×
2670
}
2671

2672
void SolarSystem::setFlagNativePlanetNames(bool b)
×
2673
{
2674
        if (b!=flagNativePlanetNames)
×
2675
        {
2676
                flagNativePlanetNames=b;
×
2677
                for (const auto& p : qAsConst(systemPlanets))
×
2678
                {
2679
                        if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
×
2680
                                p->setFlagNativeName(flagNativePlanetNames);
×
2681
                }
2682
                updateI18n();
×
2683
                emit flagNativePlanetNamesChanged(b);
×
2684
        }
2685
}
×
2686

2687
bool SolarSystem::getFlagNativePlanetNames() const
×
2688
{
2689
        return flagNativePlanetNames;
×
2690
}
2691

2692
void SolarSystem::setFlagIsolatedTrails(bool b)
×
2693
{
2694
        if(b!=flagIsolatedTrails)
×
2695
        {
2696
                flagIsolatedTrails = b;
×
2697
                recreateTrails();
×
2698
                emit flagIsolatedTrailsChanged(b);
×
2699
        }
2700
}
×
2701

2702
bool SolarSystem::getFlagIsolatedTrails() const
×
2703
{
2704
        return flagIsolatedTrails;
×
2705
}
2706

2707
int SolarSystem::getNumberIsolatedTrails() const
×
2708
{
2709
        return numberIsolatedTrails;
×
2710
}
2711

2712
void SolarSystem::setNumberIsolatedTrails(int n)
×
2713
{
2714
        // [1..5] - valid range for trails
2715
        numberIsolatedTrails = qBound(1, n, 5);
×
2716

2717
        if (getFlagIsolatedTrails())
×
2718
                recreateTrails();
×
2719

2720
        emit numberIsolatedTrailsChanged(numberIsolatedTrails);
×
2721
}
×
2722

2723
void SolarSystem::setFlagOrbits(bool b)
×
2724
{
2725
        if(b!=getFlagOrbits())
×
2726
        {
2727
                flagOrbits = b;
×
2728
                emit flagOrbitsChanged(b);
×
2729
        }
2730
}
×
2731

2732
// Connect this to all signals when orbit selection or selected object has changed.
2733
// This method goes through all planets and sets orbit drawing as configured by several flags
2734
void SolarSystem::reconfigureOrbits()
×
2735
{
2736
        // we have: flagOrbits O, flagIsolatedOrbits I, flagPlanetsOrbitsOnly P, flagOrbitsWithMoons M, flagPermanentOrbits and a possibly selected planet S
2737
        // permanentOrbits only influences local drawing of a single planet and can be ignored here.
2738
        // O S I P M
2739
        // 0 X X X X  NONE
2740
        // 1 0 1 X X  NONE
2741
        // 1 X 0 0 X  ALL
2742
        // 1 X 0 1 0  all planets only
2743
        // 1 X 0 1 1  all planets with their moons only
2744

2745
        // 1 1 1 0 0  only selected SSO
2746
        // 1 1 1 0 1  only selected SSO and orbits of its moon system
2747
        // 1 1 1 1 0  only selected SSO if it is a major planet
2748
        // 1 1 1 1 1  only selected SSO if it is a major planet, plus its system of moons
2749

2750
        if (!flagOrbits || (flagIsolatedOrbits && (!selected || selected==sun)))
×
2751
        {
2752
                for (const auto& p : qAsConst(systemPlanets))
×
2753
                        p->setFlagOrbits(false);
×
2754
                return;
×
2755
        }
2756
        // from here, flagOrbits is certainly on
2757
        if (!flagIsolatedOrbits)
×
2758
        {
2759
                for (const auto& p : qAsConst(systemPlanets))
×
2760
                        p->setFlagOrbits(!flagPlanetsOrbitsOnly || (p->getPlanetType()==Planet::isPlanet || (flagOrbitsWithMoons && p->parent && p->parent->getPlanetType()==Planet::isPlanet) ));
×
2761
                return;
×
2762
        }
2763
        else // flagIsolatedOrbits && selected
2764
        {
2765
                // Display only orbit for selected planet and, if requested, its moons.
2766
                for (const auto& p : qAsConst(systemPlanets))
×
2767
                        p->setFlagOrbits(   (p==selected && (  !flagPlanetsOrbitsOnly ||  p->getPlanetType()==Planet::isPlanet ) )
×
2768
                                         || (flagOrbitsWithMoons && p->getPlanetType()==Planet::isMoon && p->parent==selected ) );
×
2769
                return;
×
2770
        }
2771
}
2772

2773
void SolarSystem::setFlagIsolatedOrbits(bool b)
×
2774
{
2775
        if(b!=flagIsolatedOrbits)
×
2776
        {
2777
                flagIsolatedOrbits = b;
×
2778
                StelApp::immediateSave("viewing/flag_isolated_orbits", b);
×
2779
                emit flagIsolatedOrbitsChanged(b);
×
2780
        }
2781
}
×
2782

2783
bool SolarSystem::getFlagIsolatedOrbits() const
×
2784
{
2785
        return flagIsolatedOrbits;
×
2786
}
2787

2788
void SolarSystem::setFlagPlanetsOrbitsOnly(bool b)
×
2789
{
2790
        if(b!=flagPlanetsOrbitsOnly)
×
2791
        {
2792
                flagPlanetsOrbitsOnly = b;
×
2793
                StelApp::immediateSave("viewing/flag_planets_orbits_only", b);
×
2794
                emit flagPlanetsOrbitsOnlyChanged(b);
×
2795
        }
2796
}
×
2797

2798
bool SolarSystem::getFlagPlanetsOrbitsOnly() const
×
2799
{
2800
        return flagPlanetsOrbitsOnly;
×
2801
}
2802

2803
void SolarSystem::setFlagOrbitsWithMoons(bool b)
×
2804
{
2805
        if(b!=flagOrbitsWithMoons)
×
2806
        {
2807
                flagOrbitsWithMoons = b;
×
2808
                StelApp::immediateSave("viewing/flag_orbits_with_moons", b);
×
2809
                emit flagOrbitsWithMoonsChanged(b);
×
2810
        }
2811
}
×
2812

2813
bool SolarSystem::getFlagOrbitsWithMoons() const
×
2814
{
2815
        return flagOrbitsWithMoons;
×
2816
}
2817

2818
// Set/Get planets names color
2819
void SolarSystem::setLabelsColor(const Vec3f& c)
×
2820
{
2821
        if (c!=Planet::getLabelColor())
×
2822
        {
2823
                Planet::setLabelColor(c);
×
2824
                emit labelsColorChanged(c);
×
2825
        }
2826
}
×
2827

2828
Vec3f SolarSystem::getLabelsColor(void) const
×
2829
{
2830
        return Planet::getLabelColor();
×
2831
}
2832

2833
// Set/Get orbits lines color
2834
void SolarSystem::setOrbitsColor(const Vec3f& c)
×
2835
{
2836
        if (c!=Planet::getOrbitColor())
×
2837
        {
2838
                Planet::setOrbitColor(c);
×
2839
                emit orbitsColorChanged(c);
×
2840
        }
2841
}
×
2842

2843
Vec3f SolarSystem::getOrbitsColor(void) const
×
2844
{
2845
        return Planet::getOrbitColor();
×
2846
}
2847

2848
void SolarSystem::setMajorPlanetsOrbitsColor(const Vec3f &c)
×
2849
{
2850
        if (c!=Planet::getMajorPlanetOrbitColor())
×
2851
        {
2852
                Planet::setMajorPlanetOrbitColor(c);
×
2853
                emit majorPlanetsOrbitsColorChanged(c);
×
2854
        }
2855
}
×
2856

2857
Vec3f SolarSystem::getMajorPlanetsOrbitsColor(void) const
×
2858
{
2859
        return Planet::getMajorPlanetOrbitColor();
×
2860
}
2861

2862
void SolarSystem::setMinorPlanetsOrbitsColor(const Vec3f &c)
×
2863
{
2864
        if (c!=Planet::getMinorPlanetOrbitColor())
×
2865
        {
2866
                Planet::setMinorPlanetOrbitColor(c);
×
2867
                emit minorPlanetsOrbitsColorChanged(c);
×
2868
        }
2869
}
×
2870

2871
Vec3f SolarSystem::getMinorPlanetsOrbitsColor(void) const
×
2872
{
2873
        return Planet::getMinorPlanetOrbitColor();
×
2874
}
2875

2876
void SolarSystem::setDwarfPlanetsOrbitsColor(const Vec3f &c)
×
2877
{
2878
        if (c!=Planet::getDwarfPlanetOrbitColor())
×
2879
        {
2880
                Planet::setDwarfPlanetOrbitColor(c);
×
2881
                emit dwarfPlanetsOrbitsColorChanged(c);
×
2882
        }
2883
}
×
2884

2885
Vec3f SolarSystem::getDwarfPlanetsOrbitsColor(void) const
×
2886
{
2887
        return Planet::getDwarfPlanetOrbitColor();
×
2888
}
2889

2890
void SolarSystem::setMoonsOrbitsColor(const Vec3f &c)
×
2891
{
2892
        if (c!=Planet::getMoonOrbitColor())
×
2893
        {
2894
                Planet::setMoonOrbitColor(c);
×
2895
                emit moonsOrbitsColorChanged(c);
×
2896
        }
2897
}
×
2898

2899
Vec3f SolarSystem::getMoonsOrbitsColor(void) const
×
2900
{
2901
        return Planet::getMoonOrbitColor();
×
2902
}
2903

2904
void SolarSystem::setCubewanosOrbitsColor(const Vec3f &c)
×
2905
{
2906
        if (c!=Planet::getCubewanoOrbitColor())
×
2907
        {
2908
                Planet::setCubewanoOrbitColor(c);
×
2909
                emit cubewanosOrbitsColorChanged(c);
×
2910
        }
2911
}
×
2912

2913
Vec3f SolarSystem::getCubewanosOrbitsColor(void) const
×
2914
{
2915
        return Planet::getCubewanoOrbitColor();
×
2916
}
2917

2918
void SolarSystem::setPlutinosOrbitsColor(const Vec3f &c)
×
2919
{
2920
        if (c!=Planet::getPlutinoOrbitColor())
×
2921
        {
2922
                Planet::setPlutinoOrbitColor(c);
×
2923
                emit plutinosOrbitsColorChanged(c);
×
2924
        }
2925
}
×
2926

2927
Vec3f SolarSystem::getPlutinosOrbitsColor(void) const
×
2928
{
2929
        return Planet::getPlutinoOrbitColor();
×
2930
}
2931

2932
void SolarSystem::setScatteredDiskObjectsOrbitsColor(const Vec3f &c)
×
2933
{
2934
        if (c!=Planet::getScatteredDiscObjectOrbitColor())
×
2935
        {
2936
                Planet::setScatteredDiscObjectOrbitColor(c);
×
2937
                emit scatteredDiskObjectsOrbitsColorChanged(c);
×
2938
        }
2939
}
×
2940

2941
Vec3f SolarSystem::getScatteredDiskObjectsOrbitsColor(void) const
×
2942
{
2943
        return Planet::getScatteredDiscObjectOrbitColor();
×
2944
}
2945

2946
void SolarSystem::setOortCloudObjectsOrbitsColor(const Vec3f &c)
×
2947
{
2948
        if (c!=Planet::getOortCloudObjectOrbitColor())
×
2949
        {
2950
                Planet::setOortCloudObjectOrbitColor(c);
×
2951
                emit oortCloudObjectsOrbitsColorChanged(c);
×
2952
        }
2953
}
×
2954

2955
Vec3f SolarSystem::getOortCloudObjectsOrbitsColor(void) const
×
2956
{
2957
        return Planet::getOortCloudObjectOrbitColor();
×
2958
}
2959

2960
void SolarSystem::setCometsOrbitsColor(const Vec3f& c)
×
2961
{
2962
        if (c!=Planet::getCometOrbitColor())
×
2963
        {
2964
                Planet::setCometOrbitColor(c);
×
2965
                emit cometsOrbitsColorChanged(c);
×
2966
        }
2967
}
×
2968

2969
Vec3f SolarSystem::getCometsOrbitsColor(void) const
×
2970
{
2971
        return Planet::getCometOrbitColor();
×
2972
}
2973

2974
void SolarSystem::setSednoidsOrbitsColor(const Vec3f& c)
×
2975
{
2976
        if (c!=Planet::getSednoidOrbitColor())
×
2977
        {
2978
                Planet::setSednoidOrbitColor(c);
×
2979
                emit sednoidsOrbitsColorChanged(c);
×
2980
        }
2981
}
×
2982

2983
Vec3f SolarSystem::getSednoidsOrbitsColor(void) const
×
2984
{
2985
        return Planet::getSednoidOrbitColor();
×
2986
}
2987

2988
void SolarSystem::setInterstellarOrbitsColor(const Vec3f& c)
×
2989
{
2990
        if (c!=Planet::getInterstellarOrbitColor())
×
2991
        {
2992
                Planet::setInterstellarOrbitColor(c);
×
2993
                emit interstellarOrbitsColorChanged(c);
×
2994
        }
2995
}
×
2996

2997
Vec3f SolarSystem::getInterstellarOrbitsColor(void) const
×
2998
{
2999
        return Planet::getInterstellarOrbitColor();
×
3000
}
3001

3002
void SolarSystem::setMercuryOrbitColor(const Vec3f &c)
×
3003
{
3004
        if (c!=Planet::getMercuryOrbitColor())
×
3005
        {
3006
                Planet::setMercuryOrbitColor(c);
×
3007
                emit mercuryOrbitColorChanged(c);
×
3008
        }
3009
}
×
3010

3011
Vec3f SolarSystem::getMercuryOrbitColor(void) const
×
3012
{
3013
        return Planet::getMercuryOrbitColor();
×
3014
}
3015

3016
void SolarSystem::setVenusOrbitColor(const Vec3f &c)
×
3017
{
3018
        if (c!=Planet::getVenusOrbitColor())
×
3019
        {
3020
                Planet::setVenusOrbitColor(c);
×
3021
                emit venusOrbitColorChanged(c);
×
3022
        }
3023
}
×
3024

3025
Vec3f SolarSystem::getVenusOrbitColor(void) const
×
3026
{
3027
        return Planet::getVenusOrbitColor();
×
3028
}
3029

3030
void SolarSystem::setEarthOrbitColor(const Vec3f &c)
×
3031
{
3032
        if (c!=Planet::getEarthOrbitColor())
×
3033
        {
3034
                Planet::setEarthOrbitColor(c);
×
3035
                emit earthOrbitColorChanged(c);
×
3036
        }
3037
}
×
3038

3039
Vec3f SolarSystem::getEarthOrbitColor(void) const
×
3040
{
3041
        return Planet::getEarthOrbitColor();
×
3042
}
3043

3044
void SolarSystem::setMarsOrbitColor(const Vec3f &c)
×
3045
{
3046
        if (c!=Planet::getMarsOrbitColor())
×
3047
        {
3048
                Planet::setMarsOrbitColor(c);
×
3049
                emit marsOrbitColorChanged(c);
×
3050
        }
3051
}
×
3052

3053
Vec3f SolarSystem::getMarsOrbitColor(void) const
×
3054
{
3055
        return Planet::getMarsOrbitColor();
×
3056
}
3057

3058
void SolarSystem::setJupiterOrbitColor(const Vec3f &c)
×
3059
{
3060
        if (c!=Planet::getJupiterOrbitColor())
×
3061
        {
3062
                Planet::setJupiterOrbitColor(c);
×
3063
                emit jupiterOrbitColorChanged(c);
×
3064
        }
3065
}
×
3066

3067
Vec3f SolarSystem::getJupiterOrbitColor(void) const
×
3068
{
3069
        return Planet::getJupiterOrbitColor();
×
3070
}
3071

3072
void SolarSystem::setSaturnOrbitColor(const Vec3f &c)
×
3073
{
3074
        if (c!=Planet::getSaturnOrbitColor())
×
3075
        {
3076
                Planet::setSaturnOrbitColor(c);
×
3077
                emit saturnOrbitColorChanged(c);
×
3078
        }
3079
}
×
3080

3081
Vec3f SolarSystem::getSaturnOrbitColor(void) const
×
3082
{
3083
        return Planet::getSaturnOrbitColor();
×
3084
}
3085

3086
void SolarSystem::setUranusOrbitColor(const Vec3f &c)
×
3087
{
3088
        if (c!=Planet::getUranusOrbitColor())
×
3089
        {
3090
                Planet::setUranusOrbitColor(c);
×
3091
                emit uranusOrbitColorChanged(c);
×
3092
        }
3093
}
×
3094

3095
Vec3f SolarSystem::getUranusOrbitColor(void) const
×
3096
{
3097
        return Planet::getUranusOrbitColor();
×
3098
}
3099

3100
void SolarSystem::setNeptuneOrbitColor(const Vec3f &c)
×
3101
{
3102
        if (c!=Planet::getNeptuneOrbitColor())
×
3103
        {
3104
                Planet::setNeptuneOrbitColor(c);
×
3105
                emit neptuneOrbitColorChanged(c);
×
3106
        }
3107
}
×
3108

3109
Vec3f SolarSystem::getNeptuneOrbitColor(void) const
×
3110
{
3111
        return Planet::getNeptuneOrbitColor();
×
3112
}
3113

3114
// Set/Get if Moon display is scaled
3115
void SolarSystem::setFlagMoonScale(bool b)
×
3116
{
3117
        if(b!=flagMoonScale)
×
3118
        {
3119
                if (b) getMoon()->setSphereScale(moonScale);
×
3120
                else getMoon()->setSphereScale(1);
×
3121
                flagMoonScale = b;
×
3122
                emit flagMoonScaleChanged(b);
×
3123
        }
3124
}
×
3125

3126
// Set/Get Moon display scaling factor. This goes directly to the Moon object.
3127
void SolarSystem::setMoonScale(double f)
×
3128
{
3129
        if(!fuzzyEquals(moonScale, f))
×
3130
        {
3131
                moonScale = f;
×
3132
                if (flagMoonScale)
×
3133
                        getMoon()->setSphereScale(moonScale);
×
3134
                emit moonScaleChanged(f);
×
3135
        }
3136
}
×
3137

3138
// Set if minor body display is scaled. This flag will be queried by all Planet objects except for the Moon.
3139
void SolarSystem::setFlagMinorBodyScale(bool b)
×
3140
{
3141
        if(b!=flagMinorBodyScale)
×
3142
        {
3143
                flagMinorBodyScale = b;
×
3144

3145
                double newScale = b ? minorBodyScale : 1.0;
×
3146
                //update the bodies with the new scale
3147
                for (const auto& p : qAsConst(systemPlanets))
×
3148
                {
3149
                        if(p == moon) continue;
×
3150
                        if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
×
3151
                                p->setSphereScale(newScale);
×
3152
                }
3153
                emit flagMinorBodyScaleChanged(b);
×
3154
        }
3155
}
×
3156

3157
// Set minor body display scaling factor. This will be queried by all Planet objects except for the Moon.
3158
void SolarSystem::setMinorBodyScale(double f)
×
3159
{
3160
        if(!fuzzyEquals(minorBodyScale, f))
×
3161
        {
3162
                minorBodyScale = f;
×
3163
                if(flagMinorBodyScale) //update the bodies with the new scale
×
3164
                {
3165
                        for (const auto& p : qAsConst(systemPlanets))
×
3166
                        {
3167
                                if(p == moon) continue;
×
3168
                                if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
×
3169
                                        p->setSphereScale(minorBodyScale);
×
3170
                        }
3171
                }
3172
                emit minorBodyScaleChanged(f);
×
3173
        }
3174
}
×
3175

3176
// Set if Planet display is scaled
3177
void SolarSystem::setFlagPlanetScale(bool b)
×
3178
{
3179
        if(b!=flagPlanetScale)
×
3180
        {
3181
                double scale=(b ? planetScale : 1.);
×
3182
                for (auto& p : systemPlanets)
×
3183
                {
3184
                        if (p->pType==Planet::isPlanet)
×
3185
                                p->setSphereScale(scale);
×
3186
                }
3187
                flagPlanetScale = b;
×
3188
                emit flagPlanetScaleChanged(b);
×
3189
        }
3190
}
×
3191

3192
// Set Moon display scaling factor.
3193
void SolarSystem::setPlanetScale(double f)
×
3194
{
3195
        if(!fuzzyEquals(planetScale, f))
×
3196
        {
3197
                planetScale = f;
×
3198
                if (flagPlanetScale)
×
3199
                        for (auto& p : systemPlanets)
×
3200
                        {
3201
                                if (p->pType==Planet::isPlanet)
×
3202
                                        p->setSphereScale(planetScale);
×
3203
                        }
3204
                emit planetScaleChanged(f);
×
3205
        }
3206
}
×
3207

3208
// Set if Sun display is scaled
3209
void SolarSystem::setFlagSunScale(bool b)
×
3210
{
3211
        if(b!=flagSunScale)
×
3212
        {
3213
                if (b) getSun()->setSphereScale(sunScale);
×
3214
                else getSun()->setSphereScale(1);
×
3215
                flagSunScale = b;
×
3216
                emit flagSunScaleChanged(b);
×
3217
        }
3218
}
×
3219

3220
// Set Sun display scaling factor. This goes directly to the Sun object.
3221
void SolarSystem::setSunScale(double f)
×
3222
{
3223
        if(!fuzzyEquals(sunScale, f))
×
3224
        {
3225
                sunScale = f;
×
3226
                if (flagSunScale)
×
3227
                        getSun()->setSphereScale(sunScale);
×
3228
                emit sunScaleChanged(f);
×
3229
        }
3230
}
×
3231

3232
// Set selected planets by englishName
3233
void SolarSystem::setSelected(const QString& englishName)
×
3234
{
3235
        setSelected(searchByEnglishName(englishName));
×
3236
}
×
3237

3238
// Get the list of all the planet english names
3239
QStringList SolarSystem::getAllPlanetEnglishNames() const
×
3240
{
3241
        QStringList res;
×
3242
        for (const auto& p : systemPlanets)
×
3243
                res.append(p->getEnglishName());
×
3244
        return res;
×
3245
}
×
3246

3247
QStringList SolarSystem::getAllPlanetLocalizedNames() const
×
3248
{
3249
        QStringList res;
×
3250
        for (const auto& p : systemPlanets)
×
3251
                res.append(p->getNameI18n());
×
3252
        return res;
×
3253
}
×
3254

3255
QStringList SolarSystem::getAllMinorPlanetCommonEnglishNames() const
×
3256
{
3257
        QStringList res;
×
3258
        for (const auto& p : systemMinorBodies)
×
3259
                res.append(p->getCommonEnglishName());
×
3260
        return res;
×
3261
}
×
3262

3263

3264
// 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.
3265
void SolarSystem::reloadPlanets()
×
3266
{
3267
        // Save flag states
3268
        const bool flagScaleMoon = getFlagMoonScale();
×
3269
        const double moonScale = getMoonScale();
×
3270
        const bool flagScaleMinorBodies=getFlagMinorBodyScale();
×
3271
        const double minorScale= getMinorBodyScale();
×
3272
        const bool flagPlanets = getFlagPlanets();
×
3273
        const bool flagHints = getFlagHints();
×
3274
        const bool flagLabels = getFlagLabels();
×
3275
        const bool flagOrbits = getFlagOrbits();
×
3276
        const bool flagNative = getFlagNativePlanetNames();
×
3277
        bool hasSelection = false;
×
3278

3279
        // Save observer location (fix for LP bug # 969211)
3280
        // TODO: This can probably be done better with a better understanding of StelObserver --BM
3281
        StelCore* core = StelApp::getInstance().getCore();
×
3282
        const StelLocation loc = core->getCurrentLocation();
×
3283
        StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr);
×
3284

3285
        // Whether any planet are selected? Save the current selection...
3286
        const QList<StelObjectP> selectedObject = objMgr->getSelectedObject("Planet");
×
3287
        if (!selectedObject.isEmpty())
×
3288
        {
3289
                // ... unselect current planet.
3290
                hasSelection = true;
×
3291
                objMgr->unSelect();
×
3292
        }
3293
        // Unload all Solar System objects
3294
        selected.clear();//Release the selected one
×
3295

3296
        // GZ TODO in case this methods gets converted to only reload minor bodies: Only delete Orbits which are not referenced by some Planet.
3297
        for (auto* orb : qAsConst(orbits))
×
3298
        {
3299
                delete orb;
×
3300
        }
3301
        orbits.clear();
×
3302

3303
        sun.clear();
×
3304
        moon.clear();
×
3305
        earth.clear();
×
3306
        Planet::texEarthShadow.clear(); //Loaded in loadPlanets()
×
3307

3308
        delete allTrails;
×
3309
        allTrails = Q_NULLPTR;
×
3310

3311
        for (const auto& p : qAsConst(systemPlanets))
×
3312
        {
3313
                p->satellites.clear();
×
3314
        }
3315
        systemPlanets.clear();
×
3316
        systemMinorBodies.clear();
×
3317
        // Memory leak? What's the proper way of cleaning shared pointers?
3318

3319
        // Also delete Comet textures (loaded in loadPlanets()
3320
        Comet::tailTexture.clear();
×
3321
        Comet::comaTexture.clear();
×
3322

3323
        // Re-load the ssystem_major.ini and ssystem_minor.ini file
3324
        loadPlanets();        
×
3325
        computePositions(core->getJDE(), getSun());
×
3326
        setSelected("");
×
3327
        recreateTrails();
×
3328
        
3329
        // Restore observer location
3330
        core->moveObserverTo(loc, 0., 0.);
×
3331

3332
        // Restore flag states
3333
        setFlagMoonScale(flagScaleMoon);
×
3334
        setMoonScale(moonScale);
×
3335
        setFlagMinorBodyScale(flagScaleMinorBodies);
×
3336
        setMinorBodyScale(1.0); // force-reset first to really reach the objects in the next call.
×
3337
        setMinorBodyScale(minorScale);
×
3338
        setFlagPlanets(flagPlanets);
×
3339
        setFlagHints(flagHints);
×
3340
        setFlagLabels(flagLabels);
×
3341
        setFlagOrbits(flagOrbits);
×
3342
        setFlagNativePlanetNames(flagNative);
×
3343

3344
        // Restore translations
3345
        updateI18n();
×
3346

3347
        if (hasSelection)
×
3348
        {
3349
                // Restore selection...
3350
                StelObjectP obj = selectedObject[0];
×
3351
                objMgr->findAndSelect(obj->getEnglishName(), obj->getType());
×
3352
        }
×
3353

3354
        emit solarSystemDataReloaded();
×
3355
}
×
3356

3357
// Set the algorithm for computation of apparent magnitudes for planets in case  observer on the Earth
3358
void SolarSystem::setApparentMagnitudeAlgorithmOnEarth(QString algorithm)
×
3359
{
3360
        Planet::setApparentMagnitudeAlgorithm(algorithm);
×
3361
        emit apparentMagnitudeAlgorithmOnEarthChanged(algorithm);
×
3362
}
×
3363

3364
// Get the algorithm used for computation of apparent magnitudes for planets in case  observer on the Earth
3365
QString SolarSystem::getApparentMagnitudeAlgorithmOnEarth() const
×
3366
{
3367
        return Planet::getApparentMagnitudeAlgorithmString();
×
3368
}
3369

3370
void SolarSystem::setFlagDrawMoonHalo(bool b)
×
3371
{
3372
        Planet::drawMoonHalo=b;
×
3373
        emit flagDrawMoonHaloChanged(b);
×
3374
}
×
3375

3376
bool SolarSystem::getFlagDrawMoonHalo() const
×
3377
{
3378
        return Planet::drawMoonHalo;
×
3379
}
3380

3381
void SolarSystem::setFlagDrawSunHalo(bool b)
×
3382
{
3383
        Planet::drawSunHalo=b;
×
3384
        emit flagDrawSunHaloChanged(b);
×
3385
}
×
3386

3387
bool SolarSystem::getFlagDrawSunHalo() const
×
3388
{
3389
        return Planet::drawSunHalo;
×
3390
}
3391

3392
void SolarSystem::setFlagPermanentOrbits(bool b)
×
3393
{
3394
        if (Planet::permanentDrawingOrbits!=b)
×
3395
        {
3396
                Planet::permanentDrawingOrbits=b;
×
3397
                StelApp::immediateSave("astro/flag_permanent_orbits", b);
×
3398
                emit flagPermanentOrbitsChanged(b);
×
3399
        }
3400
}
×
3401

3402
bool SolarSystem::getFlagPermanentOrbits() const
×
3403
{
3404
        return Planet::permanentDrawingOrbits;
×
3405
}
3406

3407
void SolarSystem::setOrbitsThickness(int v)
×
3408
{
3409
        if (v!=Planet::orbitsThickness)
×
3410
        {
3411
                Planet::orbitsThickness=v;
×
3412
                StelApp::immediateSave("astro/object_orbits_thickness", v);
×
3413
                emit orbitsThicknessChanged(v);
×
3414
        }
3415
}
×
3416

3417
int SolarSystem::getOrbitsThickness() const
×
3418
{
3419
        return Planet::orbitsThickness;
×
3420
}
3421

3422
void SolarSystem::setGrsLongitude(int longitude)
×
3423
{
3424
        RotationElements::grsLongitude = longitude;
×
3425
        // automatic saving of the setting
3426
        conf->setValue("astro/grs_longitude", longitude);
×
3427
        emit grsLongitudeChanged(longitude);
×
3428
}
×
3429

3430
int SolarSystem::getGrsLongitude() const
×
3431
{
3432
        return static_cast<int>(RotationElements::grsLongitude);
×
3433
}
3434

3435
void SolarSystem::setGrsDrift(double drift)
×
3436
{
3437
        RotationElements::grsDrift = drift;
×
3438
        // automatic saving of the setting
3439
        conf->setValue("astro/grs_drift", drift);
×
3440
        emit grsDriftChanged(drift);
×
3441
}
×
3442

3443
double SolarSystem::getGrsDrift() const
×
3444
{
3445
        return RotationElements::grsDrift;
×
3446
}
3447

3448
void SolarSystem::setGrsJD(double JD)
×
3449
{
3450
        RotationElements::grsJD = JD;
×
3451
        // automatic saving of the setting
3452
        conf->setValue("astro/grs_jd", JD);
×
3453
        emit grsJDChanged(JD);
×
3454
}
×
3455

3456
double SolarSystem::getGrsJD()
×
3457
{
3458
        return RotationElements::grsJD;
×
3459
}
3460

3461
void SolarSystem::setFlagEarthShadowEnlargementDanjon(bool b)
×
3462
{
3463
        earthShadowEnlargementDanjon=b;
×
3464
        emit earthShadowEnlargementDanjonChanged(b);
×
3465
}
×
3466

3467
bool SolarSystem::getFlagEarthShadowEnlargementDanjon() const
×
3468
{
3469
        return earthShadowEnlargementDanjon;
×
3470
}
3471

3472
void SolarSystem::setOrbitColorStyle(QString style)
×
3473
{
3474
        if (style.toLower()=="groups")
×
3475
                Planet::orbitColorStyle = Planet::ocsGroups;
×
3476
        else if (style.toLower()=="major_planets")
×
3477
                Planet::orbitColorStyle = Planet::ocsMajorPlanets;
×
3478
        else
3479
                Planet::orbitColorStyle = Planet::ocsOneColor;
×
3480
}
×
3481

3482
QString SolarSystem::getOrbitColorStyle() const
×
3483
{
3484
        static const QMap<Planet::PlanetOrbitColorStyle, QString>map={
3485
                { Planet::ocsOneColor,     "one_color"},
×
3486
                { Planet::ocsGroups,       "groups"},
×
3487
                { Planet::ocsMajorPlanets, "major_planets"}
×
3488
        };
×
3489
        return map.value(Planet::orbitColorStyle, "one_color");
×
3490
}
3491

3492
// TODO: To make the code better understandable, get rid of planet->computeModelMatrix(trans, true) here.
3493
QPair<double, PlanetP> SolarSystem::getSolarEclipseFactor(const StelCore* core) const
×
3494
{
3495
        PlanetP p;
×
3496
        const Vec3d Lp = sun->getEclipticPos() + sun->getAberrationPush();
×
3497
        const Vec3d P3 = core->getObserverHeliocentricEclipticPos();
×
3498
        const double RS = sun->getEquatorialRadius();
×
3499

3500
        double final_illumination = 1.0;
×
3501

3502
        for (const auto& planet : systemPlanets)
×
3503
        {
3504
                if(planet == sun || planet == core->getCurrentPlanet())
×
3505
                        continue;
×
3506

3507
                Mat4d trans;
×
3508
                planet->computeModelMatrix(trans, true);
×
3509

3510
                const Vec3d C = trans * Vec3d(0., 0., 0.);
×
3511
                const double radius = planet->getEquatorialRadius();
×
3512

3513
                Vec3d v1 = Lp - P3;
×
3514
                Vec3d v2 = C - P3;
×
3515
                const double L = v1.norm();
×
3516
                const double l = v2.norm();
×
3517
                v1 /= L;
×
3518
                v2 /= l;
×
3519

3520
                const double R = RS / L;
×
3521
                const double r = radius / l;
×
3522
                const double d = ( v1 - v2 ).norm();
×
3523
                double illumination;
3524

3525
                if(d >= R + r) // distance too far
×
3526
                {
3527
                        illumination = 1.0;
×
3528
                }
3529
                else if(d <= r - R) // umbra
×
3530
                {
3531
                        illumination = 0.0;
×
3532
                }
3533
                else if(d <= R - r) // penumbra completely inside
×
3534
                {
3535
                        illumination = 1.0 - r * r / (R * R);
×
3536
                }
3537
                else // penumbra partially inside
3538
                {
3539
                        const double x = (R * R + d * d - r * r) / (2.0 * d);
×
3540

3541
                        const double alpha = std::acos(x / R);
×
3542
                        const double beta = std::acos((d - x) / r);
×
3543

3544
                        const double AR = R * R * (alpha - 0.5 * std::sin(2.0 * alpha));
×
3545
                        const double Ar = r * r * (beta - 0.5 * std::sin(2.0 * beta));
×
3546
                        const double AS = R * R * 2.0 * std::asin(1.0);
×
3547

3548
                        illumination = 1.0 - (AR + Ar) / AS;
×
3549
                }
3550

3551
                if(illumination < final_illumination)
×
3552
                {
3553
                        final_illumination = illumination;
×
3554
                        p = planet;
×
3555
                }
3556
        }
3557

3558
        return QPair<double, PlanetP>(final_illumination, p);
×
3559
}
×
3560

3561
// Retrieve Radius of Umbra and Penumbra at the distance of the Moon.
3562
// Returns a pair (umbra, penumbra) in (geocentric_arcseconds, AU, geometric_AU).
3563
// * sizes in arcseconds are the usual result found as Bessel element in eclipse literature.
3564
//   It includes scaling for effects of atmosphere either after Chauvenet (2%) or after Danjon. (see Espenak: 5000 Years Canon of Lunar Eclipses.)
3565
// * sizes in AU are the same, converted back to AU in Lunar distance.
3566
// * sizes in geometric_AU derived from pure geometrical evaluations without scalings applied.
3567
QPair<Vec3d,Vec3d> SolarSystem::getEarthShadowRadiiAtLunarDistance() const
×
3568
{
3569
        // Note: The application of this shadow enlargement is not according to the books, but looks close enough for now.
3570
        static const double sun2earth=sun->getEquatorialRadius() / earth->getEquatorialRadius();
×
3571
        PlanetP sun=getSun();
×
3572
        PlanetP moon=getMoon();
×
3573
        PlanetP earth=getEarth();
×
3574
        const double lunarDistance=moon->getEclipticPos().norm(); // Lunar distance [AU]
×
3575
        const double earthDistance=earth->getHeliocentricEclipticPos().norm(); // Earth distance [AU]
×
3576
        const double sunHP =asin(earth->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec.
×
3577
        const double moonHP=asin(earth->getEquatorialRadius()/lunarDistance) * M_180_PI*3600.; // arcsec.
×
3578
        const double sunSD  =atan(sun->getEquatorialRadius()/earthDistance)  * M_180_PI*3600.; // arcsec.
×
3579

3580
        // Compute umbra radius at lunar distance.
3581
        const double lUmbra=earthDistance/(sun2earth-1.); // length of earth umbra [AU]
×
3582
        const double rUmbraAU=earth->getEquatorialRadius()*(lUmbra-lunarDistance)/lUmbra; // radius of earth shadow at lunar distance [AU]
×
3583
        // Penumbra:
3584
        const double lPenumbra=earthDistance/(sun2earth + 1.); // distance between earth and point between sun and earth where penumbral border rays intersect
×
3585
        const double rPenumbraAU=earth->getEquatorialRadius()*(lPenumbra+lunarDistance)/lPenumbra; // radius of penumbra at Lunar distance [AU]
×
3586

3587
        //Classical Bessel elements instead
3588
        double f1, f2;
3589
        if (earthShadowEnlargementDanjon)
×
3590
        {
3591
                static const double danjonScale=1+1./85.-1./594.; // ~1.01, shadow magnification factor (see Espenak 5000 years Canon)
3592
                f1=danjonScale*moonHP + sunHP + sunSD; // penumbra radius, arcsec
×
3593
                f2=danjonScale*moonHP + sunHP - sunSD; // umbra radius, arcsec
×
3594
        }
3595
        else
3596
        {
3597
                const double mHP1=0.998340*moonHP;
×
3598
                f1=1.02*(mHP1 + sunHP + sunSD); // penumbra radius, arcsec
×
3599
                f2=1.02*(mHP1 + sunHP - sunSD); // umbra radius, arcsec
×
3600
        }
3601
        const double f1_AU=tan(f1/3600.*M_PI_180)*lunarDistance;
×
3602
        const double f2_AU=tan(f2/3600.*M_PI_180)*lunarDistance;
×
3603
        return QPair<Vec3d,Vec3d>(Vec3d(f2, f2_AU, rUmbraAU), Vec3d(f1, f1_AU, rPenumbraAU));
×
3604
}
×
3605

3606
bool SolarSystem::removeMinorPlanet(QString name)
×
3607
{
3608
        PlanetP candidate = searchMinorPlanetByEnglishName(name);
×
3609
        if (!candidate)
×
3610
        {
3611
                qWarning() << "Cannot remove planet " << name << ": Not found.";
×
3612
                return false;
×
3613
        }
3614
        Orbit* orbPtr=static_cast<Orbit*>(candidate->orbitPtr);
×
3615
        if (orbPtr)
×
3616
                orbits.removeOne(orbPtr);
×
3617
        systemPlanets.removeOne(candidate);
×
3618
        systemMinorBodies.removeOne(candidate);
×
3619
        candidate.clear();
×
3620
        return true;
×
3621
}
×
3622

3623
void SolarSystem::onNewSurvey(HipsSurveyP survey)
×
3624
{
3625
        // For the moment we only consider the survey url to decide if we
3626
        // assign it to a planet.  It would be better to use some property
3627
        // for that.
3628
        QString planetName = QUrl(survey->getUrl()).fileName();
×
3629
        PlanetP pl = searchByEnglishName(planetName);
×
3630
        if (!pl || pl->survey)
×
3631
                return;
×
3632
        pl->survey = survey;
×
3633
        survey->setProperty("planet", pl->getCommonEnglishName());
×
3634
        // Not visible by default for the moment.
3635
        survey->setProperty("visible", false);
×
3636
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc