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

Stellarium / stellarium / 15291801018

28 May 2025 04:52AM UTC coverage: 11.931% (-0.02%) from 11.951%
15291801018

push

github

alex-w
Added new set of navigational stars (XIX century)

0 of 6 new or added lines in 2 files covered. (0.0%)

14124 existing lines in 74 files now uncovered.

14635 of 122664 relevant lines covered (11.93%)

18291.42 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 <execution> // must be included before Qt because some versions of libtbb use "emit" identifier for their needs
23

24
#include "SolarSystem.hpp"
25
#include "StelTexture.hpp"
26
#include "EphemWrapper.hpp"
27
#include "Orbit.hpp"
28

29
#include "StelProjector.hpp"
30
#include "StelApp.hpp"
31
#include "StelCore.hpp"
32
#include "StelTextureMgr.hpp"
33
#include "StelObjectMgr.hpp"
34
#include "StelLocaleMgr.hpp"
35
#include "StelSkyCultureMgr.hpp"
36
#include "StelFileMgr.hpp"
37
#include "StelModuleMgr.hpp"
38
#include "StelIniParser.hpp"
39
#include "Planet.hpp"
40
#include "MinorPlanet.hpp"
41
#include "Comet.hpp"
42
#include "StelMainView.hpp"
43

44
#include "StelSkyDrawer.hpp"
45
#include "StelUtils.hpp"
46
#include "StelPainter.hpp"
47
#include "TrailGroup.hpp"
48

49
#include "AstroCalcDialog.hpp"
50
#include "StelObserver.hpp"
51

52
#include <algorithm>
53

54
#include <QTextStream>
55
#include <QSettings>
56
#include <QVariant>
57
#include <QString>
58
#include <QStringList>
59
#include <QMap>
60
#include <QMultiMap>
61
#include <QMapIterator>
62
#include <QDebug>
63
#include <QDir>
64
#include <QHash>
65
#include <QtConcurrent>
66
#include <QOpenGLBuffer>
67
#include <QOpenGLFunctions>
68
#include <QOpenGLShaderProgram>
69
#include <QOpenGLVertexArrayObject>
70

71

72
SolarSystem::SolarSystem() : StelObjectModule()
×
73
        , shadowPlanetCount(0)
×
74
        , earthShadowEnlargementDanjon(false)
×
75
        , flagMoonScale(false)
×
76
        , moonScale(1.0)
×
77
        , flagMinorBodyScale(false)
×
78
        , minorBodyScale(1.0)
×
79
        , flagPlanetScale(false)
×
80
        , planetScale(1.0)
×
81
        , flagSunScale(false)
×
82
        , sunScale(1.0)
×
83
        , labelsAmount(false)
×
84
        , flagPermanentSolarCorona(true)
×
85
        , flagOrbits(false)
×
86
        , flagLightTravelTime(true)
×
87
        , flagUseObjModels(false)
×
88
        , flagShowObjSelfShadows(true)
×
89
        , flagShow(false)
×
90
        , flagPointer(false)
×
91
        , flagIsolatedTrails(true)
×
92
        , numberIsolatedTrails(0)
×
93
        , maxTrailPoints(5000)
×
94
        , maxTrailTimeExtent(1)
×
95
        , trailsThickness(1)
×
96
        , flagIsolatedOrbits(true)
×
97
        , flagPlanetsOrbits(false)
×
98
        , flagPlanetsOrbitsOnly(false)
×
99
        , flagOrbitsWithMoons(false)
×
100
        , ephemerisMarkersDisplayed(true)
×
101
        , ephemerisDatesDisplayed(false)
×
102
        , ephemerisMagnitudesDisplayed(false)
×
103
        , ephemerisHorizontalCoordinates(false)
×
104
        , ephemerisLineDisplayed(false)
×
105
        , ephemerisAlwaysOn(false)
×
106
        , ephemerisNow(false)
×
107
        , ephemerisLineThickness(1)
×
108
        , ephemerisSkipDataDisplayed(false)
×
109
        , ephemerisSkipMarkersDisplayed(false)
×
110
        , ephemerisDataStep(1)
×
111
        , ephemerisDataLimit(1)
×
112
        , ephemerisSmartDatesDisplayed(true)
×
113
        , ephemerisScaleMarkersDisplayed(false)
×
114
        , ephemerisGenericMarkerColor(Vec3f(1.0f, 1.0f, 0.0f))
×
115
        , ephemerisSecondaryMarkerColor(Vec3f(0.7f, 0.7f, 1.0f))
×
116
        , ephemerisSelectedMarkerColor(Vec3f(1.0f, 0.7f, 0.0f))
×
117
        , ephemerisMercuryMarkerColor(Vec3f(1.0f, 1.0f, 0.0f))
×
118
        , ephemerisVenusMarkerColor(Vec3f(1.0f, 1.0f, 1.0f))
×
119
        , ephemerisMarsMarkerColor(Vec3f(1.0f, 0.0f, 0.0f))
×
120
        , ephemerisJupiterMarkerColor(Vec3f(0.3f, 1.0f, 1.0f))
×
121
        , ephemerisSaturnMarkerColor(Vec3f(0.0f, 1.0f, 0.0f))
×
122
        , allTrails(Q_NULLPTR)
×
123
        , conf(StelApp::getInstance().getSettings())
×
124
        , extraThreads(0)
×
125
        , nbMarkers(0)
×
126
        , vao(new QOpenGLVertexArrayObject)
×
127
        , vbo(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer))
×
128
        , markerMagThreshold(15.)
×
129
        , computePositionsAlgorithm(conf->value("devel/compute_positions_algorithm", 2).toInt())
×
130
{
UNCOV
131
        planetNameFont.setPixelSize(StelApp::getInstance().getScreenFontSize());
×
132
        connect(&StelApp::getInstance(), SIGNAL(screenFontSizeChanged(int)), this, SLOT(setFontSize(int)));
×
133
        setObjectName("SolarSystem");
×
134
        connect(this, SIGNAL(flagOrbitsChanged(bool)),            this, SLOT(reconfigureOrbits()));
×
135
        connect(this, SIGNAL(flagPlanetsOrbitsChanged(bool)),     this, SLOT(reconfigureOrbits()));
×
136
        connect(this, SIGNAL(flagPlanetsOrbitsOnlyChanged(bool)), this, SLOT(reconfigureOrbits()));
×
137
        connect(this, SIGNAL(flagIsolatedOrbitsChanged(bool)),    this, SLOT(reconfigureOrbits()));
×
138
        connect(this, SIGNAL(flagOrbitsWithMoonsChanged(bool)),   this, SLOT(reconfigureOrbits()));
×
139

UNCOV
140
        markerArray=new MarkerVertex[maxMarkers*6];
×
141
        textureCoordArray = new unsigned char[maxMarkers*6*2];
×
142
        for (unsigned int i=0;i<maxMarkers; ++i)
×
143
        {
144
                static const unsigned char texElems[] = {0, 0, 255, 0, 255, 255, 0, 0, 255, 255, 0, 255};
UNCOV
145
                unsigned char* elem = &textureCoordArray[i*6*2];
×
146
                std::memcpy(elem, texElems, 12);
×
147
        }
UNCOV
148
}
×
149

UNCOV
150
void SolarSystem::setFontSize(int newFontSize)
×
151
{
UNCOV
152
        planetNameFont.setPixelSize(newFontSize);
×
153
}
×
154

UNCOV
155
SolarSystem::~SolarSystem()
×
156
{
157
        // release selected:
UNCOV
158
        selected.clear();
×
159
        selectedSSO.clear();
×
160
        for (auto* orb : std::as_const(orbits))
×
161
        {
UNCOV
162
                delete orb;
×
163
                orb = Q_NULLPTR;
×
164
        }
UNCOV
165
        sun.clear();
×
166
        moon.clear();
×
167
        earth.clear();
×
168
        Planet::hintCircleTex.clear();
×
169
        Planet::texEarthShadow.clear();
×
170

UNCOV
171
        delete[] markerArray;
×
172
        markerArray = nullptr;
×
173
        delete[] textureCoordArray;
×
174
        textureCoordArray = nullptr;
×
175
        delete markerShaderProgram;
×
176
        markerShaderProgram = nullptr;
×
177

178

UNCOV
179
        texEphemerisMarker.clear();
×
180
        texEphemerisCometMarker.clear();
×
181
        texEphemerisNowMarker.clear();
×
182
        texPointer.clear();
×
183

UNCOV
184
        delete allTrails;
×
185
        allTrails = Q_NULLPTR;
×
186

187
        // Get rid of circular reference between the shared pointers which prevent proper destruction of the Planet objects.
UNCOV
188
        for (const auto& p : std::as_const(systemPlanets))
×
189
        {
UNCOV
190
                p->satellites.clear();
×
191
        }
192

193
        //delete comet textures created in loadPlanets
UNCOV
194
        Comet::comaTexture.clear();
×
195
        Comet::tailTexture.clear();
×
196

197
        //deinit of SolarSystem is NOT called at app end automatically
UNCOV
198
        SolarSystem::deinit();
×
199
}
×
200

201
/*************************************************************************
202
 Re-implementation of the getCallOrder method
203
*************************************************************************/
UNCOV
204
double SolarSystem::getCallOrder(StelModuleActionName actionName) const
×
205
{
UNCOV
206
        if (actionName==StelModule::ActionDraw)
×
207
                return StelApp::getInstance().getModuleMgr().getModule("StarMgr")->getCallOrder(actionName)+10;
×
208
        return 0;
×
209
}
210

211
// Init and load the solar system data
UNCOV
212
void SolarSystem::init()
×
213
{
UNCOV
214
        initializeOpenGLFunctions();
×
215

UNCOV
216
        Q_ASSERT(conf);
×
217
        StelApp *app = &StelApp::getInstance();
×
218
        StelCore *core=app->getCore();
×
219

UNCOV
220
        Planet::init();
×
221
        loadPlanets();        // Load planets data
×
222

223
        // Compute position and matrix of sun and all the satellites (ie planets)
224
        // for the first initialization Q_ASSERT that center is sun center (only impacts on light speed correction)
UNCOV
225
        setExtraThreads(conf->value("astro/solar_system_threads", 0).toInt());
×
226
        computePositions(core, core->getJDE(), getSun());
×
227

UNCOV
228
        setSelected("");        // Fix a bug on macosX! Thanks Fumio!
×
229
        setFlagDrawMoonHalo(conf->value("viewing/flag_draw_moon_halo", true).toBool());
×
230
        setFlagDrawSunHalo(conf->value("viewing/flag_draw_sun_halo", true).toBool());
×
231
        setFlagMoonScale(conf->value("viewing/flag_moon_scaled", conf->value("viewing/flag_init_moon_scaled", false).toBool()).toBool());  // name change
×
232
        setMoonScale(conf->value("viewing/moon_scale", 4.0).toDouble());
×
233
        setMinorBodyScale(conf->value("viewing/minorbodies_scale", 10.0).toDouble());
×
234
        setFlagMinorBodyScale(conf->value("viewing/flag_minorbodies_scaled", false).toBool());
×
235
        setFlagPlanetScale(conf->value("viewing/flag_planets_scaled", false).toBool());
×
236
        setPlanetScale(conf->value("viewing/planets_scale", 150.0).toDouble());
×
237
        setFlagSunScale(conf->value("viewing/flag_sun_scaled", false).toBool());
×
238
        setSunScale(conf->value("viewing/sun_scale", 4.0).toDouble());
×
239
        setFlagPlanets(conf->value("astro/flag_planets").toBool());
×
240
        setFlagHints(conf->value("astro/flag_planets_hints").toBool());
×
241
        setFlagMarkers(conf->value("astro/flag_planets_markers", false).toBool());
×
242
        setMarkerMagThreshold(conf->value("astro/planet_markers_mag_threshold", 15.).toDouble());
×
243
        setFlagLabels(conf->value("astro/flag_planets_labels", true).toBool());
×
244
        setLabelsAmount(conf->value("astro/labels_amount", 3.).toDouble());
×
245
        setFlagOrbits(conf->value("astro/flag_planets_orbits").toBool());
×
246
        setFlagLightTravelTime(conf->value("astro/flag_light_travel_time", true).toBool());
×
247
        setFlagUseObjModels(conf->value("astro/flag_use_obj_models", false).toBool());
×
248
        setFlagShowObjSelfShadows(conf->value("astro/flag_show_obj_self_shadows", true).toBool());
×
249
        setFlagPointer(conf->value("astro/flag_planets_pointers", true).toBool());
×
250
        // Set the algorithm from Astronomical Almanac for computation of apparent magnitudes for
251
        // planets in case  observer on the Earth by default
UNCOV
252
        setApparentMagnitudeAlgorithmOnEarth(conf->value("astro/apparent_magnitude_algorithm", "Mallama2018").toString());
×
253
        // Is enabled the showing of isolated trails for selected objects only?
254
        setFlagIsolatedTrails(conf->value("viewing/flag_isolated_trails", true).toBool());
×
UNCOV
255
        setNumberIsolatedTrails(conf->value("viewing/number_isolated_trails", 1).toInt());
×
256
        setMaxTrailPoints(conf->value("viewing/max_trail_points", 5000).toInt());
×
257
        setMaxTrailTimeExtent(conf->value("viewing/max_trail_time_extent", 1).toInt());
×
258
        setFlagIsolatedOrbits(conf->value("viewing/flag_isolated_orbits", true).toBool());
×
259
        setFlagPlanetsOrbits(conf->value("viewing/flag_planets_orbits", false).toBool());
×
260
        setFlagPlanetsOrbitsOnly(conf->value("viewing/flag_planets_orbits_only", false).toBool());
×
261
        setFlagOrbitsWithMoons(conf->value("viewing/flag_orbits_with_moons", false).toBool());
×
262
        setFlagPermanentOrbits(conf->value("astro/flag_permanent_orbits", false).toBool());
×
263
        setOrbitColorStyle(conf->value("astro/planets_orbits_color_style", "one_color").toString());
×
264

265
        // Settings for calculation of position of Great Red Spot on Jupiter
UNCOV
266
        setGrsLongitude(conf->value("astro/grs_longitude", 46).toInt());
×
UNCOV
267
        setGrsDrift(conf->value("astro/grs_drift", 15.).toDouble());
×
268
        setGrsJD(conf->value("astro/grs_jd", 2460218.5).toDouble());
×
269

270
        setFlagEarthShadowEnlargementDanjon(conf->value("astro/shadow_enlargement_danjon", false).toBool());
×
UNCOV
271
        setFlagPermanentSolarCorona(conf->value("viewing/flag_draw_sun_corona", true).toBool());
×
272

273
        // Load colors from config file
UNCOV
274
        QString defaultColor = conf->value("color/default_color").toString();
×
UNCOV
275
        setLabelsColor(                    Vec3f(conf->value("color/planet_names_color", defaultColor).toString()));
×
276
        setOrbitsColor(                    Vec3f(conf->value("color/sso_orbits_color", defaultColor).toString()));
×
277
        setMajorPlanetsOrbitsColor(        Vec3f(conf->value("color/major_planet_orbits_color", "0.7,0.2,0.2").toString()));
×
278
        setMoonsOrbitsColor(               Vec3f(conf->value("color/moon_orbits_color", "0.7,0.2,0.2").toString()));
×
279
        setMinorPlanetsOrbitsColor(        Vec3f(conf->value("color/minor_planet_orbits_color", "0.7,0.5,0.5").toString()));
×
280
        setDwarfPlanetsOrbitsColor(        Vec3f(conf->value("color/dwarf_planet_orbits_color", "0.7,0.5,0.5").toString()));
×
281
        setCubewanosOrbitsColor(           Vec3f(conf->value("color/cubewano_orbits_color", "0.7,0.5,0.5").toString()));
×
282
        setPlutinosOrbitsColor(            Vec3f(conf->value("color/plutino_orbits_color", "0.7,0.5,0.5").toString()));
×
283
        setScatteredDiskObjectsOrbitsColor(Vec3f(conf->value("color/sdo_orbits_color", "0.7,0.5,0.5").toString()));
×
284
        setOortCloudObjectsOrbitsColor(    Vec3f(conf->value("color/oco_orbits_color", "0.7,0.5,0.5").toString()));
×
285
        setCometsOrbitsColor(              Vec3f(conf->value("color/comet_orbits_color", "0.7,0.8,0.8").toString()));
×
286
        setSednoidsOrbitsColor(            Vec3f(conf->value("color/sednoid_orbits_color", "0.7,0.5,0.5").toString()));
×
287
        setInterstellarOrbitsColor(        Vec3f(conf->value("color/interstellar_orbits_color", "1.0,0.6,1.0").toString()));
×
288
        setMercuryOrbitColor(              Vec3f(conf->value("color/mercury_orbit_color", "0.5,0.5,0.5").toString()));
×
289
        setVenusOrbitColor(                Vec3f(conf->value("color/venus_orbit_color", "0.9,0.9,0.7").toString()));
×
290
        setEarthOrbitColor(                Vec3f(conf->value("color/earth_orbit_color", "0.0,0.0,1.0").toString()));
×
291
        setMarsOrbitColor(                 Vec3f(conf->value("color/mars_orbit_color", "0.8,0.4,0.1").toString()));
×
292
        setJupiterOrbitColor(              Vec3f(conf->value("color/jupiter_orbit_color", "1.0,0.6,0.0").toString()));
×
293
        setSaturnOrbitColor(               Vec3f(conf->value("color/saturn_orbit_color", "1.0,0.8,0.0").toString()));
×
294
        setUranusOrbitColor(               Vec3f(conf->value("color/uranus_orbit_color", "0.0,0.7,1.0").toString()));
×
295
        setNeptuneOrbitColor(              Vec3f(conf->value("color/neptune_orbit_color", "0.0,0.3,1.0").toString()));
×
296
        setTrailsColor(                    Vec3f(conf->value("color/object_trails_color", defaultColor).toString()));
×
297
        setPointerColor(                   Vec3f(conf->value("color/planet_pointers_color", "1.0,0.3,0.3").toString()));
×
298

299
        // Ephemeris stuff
UNCOV
300
        setFlagEphemerisMarkers(conf->value("astrocalc/flag_ephemeris_markers", true).toBool());
×
UNCOV
301
        setFlagEphemerisAlwaysOn(conf->value("astrocalc/flag_ephemeris_alwayson", true).toBool());
×
302
        setFlagEphemerisNow(conf->value("astrocalc/flag_ephemeris_now", false).toBool());
×
303
        setFlagEphemerisDates(conf->value("astrocalc/flag_ephemeris_dates", false).toBool());
×
304
        setFlagEphemerisMagnitudes(conf->value("astrocalc/flag_ephemeris_magnitudes", false).toBool());
×
305
        setFlagEphemerisHorizontalCoordinates(conf->value("astrocalc/flag_ephemeris_horizontal", false).toBool());
×
306
        setFlagEphemerisLine(conf->value("astrocalc/flag_ephemeris_line", false).toBool());
×
307
        setEphemerisLineThickness(conf->value("astrocalc/ephemeris_line_thickness", 1).toInt());
×
308
        setFlagEphemerisSkipData(conf->value("astrocalc/flag_ephemeris_skip_data", false).toBool());
×
309
        setFlagEphemerisSkipMarkers(conf->value("astrocalc/flag_ephemeris_skip_markers", false).toBool());
×
310
        setEphemerisDataStep(conf->value("astrocalc/ephemeris_data_step", 1).toInt());        
×
311
        setFlagEphemerisSmartDates(conf->value("astrocalc/flag_ephemeris_smart_dates", true).toBool());
×
312
        setFlagEphemerisScaleMarkers(conf->value("astrocalc/flag_ephemeris_scale_markers", false).toBool());
×
313
        setEphemerisGenericMarkerColor( Vec3f(conf->value("color/ephemeris_generic_marker_color", "1.0,1.0,0.0").toString()));
×
314
        setEphemerisSecondaryMarkerColor( Vec3f(conf->value("color/ephemeris_secondary_marker_color", "0.7,0.7,1.0").toString()));
×
315
        setEphemerisSelectedMarkerColor(Vec3f(conf->value("color/ephemeris_selected_marker_color", "1.0,0.7,0.0").toString()));
×
316
        setEphemerisMercuryMarkerColor( Vec3f(conf->value("color/ephemeris_mercury_marker_color", "1.0,1.0,0.0").toString()));
×
317
        setEphemerisVenusMarkerColor(   Vec3f(conf->value("color/ephemeris_venus_marker_color", "1.0,1.0,1.0").toString()));
×
318
        setEphemerisMarsMarkerColor(    Vec3f(conf->value("color/ephemeris_mars_marker_color", "1.0,0.0,0.0").toString()));
×
319
        setEphemerisJupiterMarkerColor( Vec3f(conf->value("color/ephemeris_jupiter_marker_color", "0.3,1.0,1.0").toString()));
×
320
        setEphemerisSaturnMarkerColor(  Vec3f(conf->value("color/ephemeris_saturn_marker_color", "0.0,1.0,0.0").toString()));
×
321

322
        setOrbitsThickness(conf->value("astro/object_orbits_thickness", 1).toInt());
×
UNCOV
323
        setTrailsThickness(conf->value("astro/object_trails_thickness", 1).toInt());
×
324
        recreateTrails();
×
325
        setFlagTrails(conf->value("astro/flag_object_trails", false).toBool());
×
326

327
        StelObjectMgr *objectManager = GETSTELMODULE(StelObjectMgr);
×
UNCOV
328
        objectManager->registerStelObjectMgr(this);
×
329
        connect(objectManager, SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)),
×
330
                this, SLOT(selectedObjectChange(StelModule::StelModuleSelectAction)));
331

UNCOV
332
        texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur4.png");
×
UNCOV
333
        texEphemerisMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/disk.png");
×
334
        texEphemerisNowMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/gear.png");
×
335
        texEphemerisCometMarker = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/cometIcon.png");
×
336
        Planet::hintCircleTex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/planet-indicator.png");
×
337
        markerCircleTex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/planet-marker.png");
×
338

339
        connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n()));
×
UNCOV
340
        connect(&app->getSkyCultureMgr(), &StelSkyCultureMgr::currentSkyCultureChanged, this, &SolarSystem::updateSkyCulture);
×
341
        connect(&StelMainView::getInstance(), SIGNAL(reloadShadersRequested()), this, SLOT(reloadShaders()));
×
342
        connect(core, SIGNAL(locationChanged(StelLocation)), this, SLOT(recreateTrails()));
×
343
        connect(core, SIGNAL(dateChangedForTrails()), this, SLOT(recreateTrails()));
×
344

345
        QString displayGroup = N_("Display Options");
×
UNCOV
346
        addAction("actionShow_Planets", displayGroup, N_("Planets"), "planetsDisplayed", "P");
×
347
        addAction("actionShow_Planets_Labels", displayGroup, N_("Planet labels"), "labelsDisplayed", "Alt+P");
×
348
        addAction("actionShow_Planets_Orbits", displayGroup, N_("Planet orbits"), "flagOrbits", "O");
×
349
        addAction("actionShow_Planets_Trails", displayGroup, N_("Planet trails"), "trailsDisplayed", "Shift+T");
×
350
        addAction("actionShow_Planets_Trails_Reset", displayGroup, N_("Planet trails reset"), "recreateTrails()"); // No hotkey predefined.
×
351
        //there is a small discrepancy in the GUI: "Show planet markers" actually means show planet hints
352
        addAction("actionShow_Planets_Hints", displayGroup, N_("Planet markers"), "flagHints", "Ctrl+P");
×
UNCOV
353
        addAction("actionShow_Planets_Pointers", displayGroup, N_("Planet selection marker"), "flagPointer", "Ctrl+Shift+P");
×
354
        addAction("actionShow_Planets_EnlargeMoon", displayGroup, N_("Enlarge Moon"), "flagMoonScale");
×
355
        addAction("actionShow_Planets_EnlargeMinor", displayGroup, N_("Enlarge minor bodies"), "flagMinorBodyScale");
×
356
        addAction("actionShow_Planets_EnlargePlanets", displayGroup, N_("Enlarge Planets"), "flagPlanetScale");
×
357
        addAction("actionShow_Planets_EnlargeSun", displayGroup, N_("Enlarge Sun"), "flagSunScale");
×
358
        addAction("actionShow_Planets_ShowMinorBodyMarkers", displayGroup, N_("Mark minor bodies"), "flagMarkers");
×
359

360
        connect(StelApp::getInstance().getModule("HipsMgr"), SIGNAL(gotNewSurvey(HipsSurveyP)),
×
361
                        this, SLOT(onNewSurvey(HipsSurveyP)));
362

363
        // Fill ephemeris dates
UNCOV
364
        connect(this, SIGNAL(requestEphemerisVisualization()), this, SLOT(fillEphemerisDates()));
×
UNCOV
365
        connect(this, SIGNAL(ephemerisDataStepChanged(int)), this, SLOT(fillEphemerisDates()));
×
UNCOV
366
        connect(this, SIGNAL(ephemerisSkipDataChanged(bool)), this, SLOT(fillEphemerisDates()));
×
367
        connect(this, SIGNAL(ephemerisSkipMarkersChanged(bool)), this, SLOT(fillEphemerisDates()));
×
368
        connect(this, SIGNAL(ephemerisSmartDatesChanged(bool)), this, SLOT(fillEphemerisDates()));
×
369

370

371
        // Create shader program for mass drawing of asteroid markers
UNCOV
372
        QOpenGLShader vshader(QOpenGLShader::Vertex);
×
UNCOV
373
        const char *vsrc =
×
374
                "ATTRIBUTE mediump vec2 pos;\n"
375
                "ATTRIBUTE mediump vec2 texCoord;\n"
376
                "ATTRIBUTE mediump vec3 color;\n"
377
                "uniform mediump mat4 projectionMatrix;\n"
378
                "VARYING mediump vec2 texc;\n"
379
                "VARYING mediump vec3 outColor;\n"
380
                "void main(void)\n"
381
                "{\n"
382
                "    gl_Position = projectionMatrix * vec4(pos.x, pos.y, 0, 1);\n"
383
                "    texc = texCoord;\n"
384
                "    outColor = color;\n"
385
                "}\n";
UNCOV
386
        vshader.compileSourceCode(StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) + vsrc);
×
UNCOV
387
        if (!vshader.log().isEmpty()) { qWarning() << "SolarSystem::init(): Warnings while compiling vshader: " << vshader.log(); }
×
388

389
        QOpenGLShader fshader(QOpenGLShader::Fragment);
×
390
        const char *fsrc =
×
391
                "VARYING mediump vec2 texc;\n"
392
                "VARYING mediump vec3 outColor;\n"
393
                "uniform sampler2D tex;\n"
394
                "void main(void)\n"
395
                "{\n"
396
                "    FRAG_COLOR = texture2D(tex, texc)*vec4(outColor, 1.);\n"
397
                "}\n";
UNCOV
398
        fshader.compileSourceCode(StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) + fsrc);
×
UNCOV
399
        if (!fshader.log().isEmpty()) { qWarning() << "SolarSystem::init(): Warnings while compiling fshader: " << fshader.log(); }
×
400

401
        markerShaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext());
×
402
        markerShaderProgram->addShader(&vshader);
×
UNCOV
403
        markerShaderProgram->addShader(&fshader);
×
404
        StelPainter::linkProg(markerShaderProgram, "starShader");
×
405
        markerShaderVars.projectionMatrix = markerShaderProgram->uniformLocation("projectionMatrix");
×
406
        markerShaderVars.texCoord = markerShaderProgram->attributeLocation("texCoord");
×
407
        markerShaderVars.pos = markerShaderProgram->attributeLocation("pos");
×
408
        markerShaderVars.color = markerShaderProgram->attributeLocation("color");
×
409
        markerShaderVars.texture = markerShaderProgram->uniformLocation("tex");
×
410

411
        vbo->create();
×
412
        vbo->bind();
×
UNCOV
413
        vbo->setUsagePattern(QOpenGLBuffer::StreamDraw);
×
414
        vbo->allocate(maxMarkers*6*sizeof(MarkerVertex) + maxMarkers*6*2);
×
415

416
        if(vao->create())
×
417
        {
UNCOV
418
                vao->bind();
×
419
                setupCurrentVAO();
×
UNCOV
420
                vao->release();
×
421
        }
422

423
        vbo->release();
×
UNCOV
424
}
×
425

426
void SolarSystem::setupCurrentVAO()
×
427
{
UNCOV
428
        vbo->bind();
×
429
        markerShaderProgram->setAttributeBuffer(markerShaderVars.pos, GL_FLOAT, 0, 2, sizeof(MarkerVertex));
×
UNCOV
430
        markerShaderProgram->setAttributeBuffer(markerShaderVars.color, GL_UNSIGNED_BYTE, offsetof(MarkerVertex,color), 3, sizeof(MarkerVertex));
×
431
        markerShaderProgram->setAttributeBuffer(markerShaderVars.texCoord, GL_UNSIGNED_BYTE, maxMarkers*6*sizeof(MarkerVertex), 2, 0);
×
432
        vbo->release();
×
433
        markerShaderProgram->enableAttributeArray(markerShaderVars.pos);
×
434
        markerShaderProgram->enableAttributeArray(markerShaderVars.color);
×
435
        markerShaderProgram->enableAttributeArray(markerShaderVars.texCoord);
×
436
}
×
437

438
void SolarSystem::bindVAO()
×
439
{
UNCOV
440
        if(vao->isCreated())
×
441
                vao->bind();
×
442
        else
443
                setupCurrentVAO();
×
444
}
×
445

446
void SolarSystem::releaseVAO()
×
447
{
UNCOV
448
        if(vao->isCreated())
×
449
        {
UNCOV
450
                vao->release();
×
451
        }
452
        else
453
        {
UNCOV
454
                markerShaderProgram->disableAttributeArray(markerShaderVars.pos);
×
UNCOV
455
                markerShaderProgram->disableAttributeArray(markerShaderVars.color);
×
UNCOV
456
                markerShaderProgram->disableAttributeArray(markerShaderVars.texCoord);
×
457
        }
458
}
×
459

UNCOV
460
void SolarSystem::deinit()
×
461
{
UNCOV
462
        Planet::deinitShader();
×
463
        Planet::deinitFBO();
×
UNCOV
464
}
×
465

466
void SolarSystem::resetTextures(const QString &planetName)
×
467
{
UNCOV
468
        if (planetName.isEmpty())
×
469
        {
UNCOV
470
                for (const auto& p : std::as_const(systemPlanets))
×
471
                {
UNCOV
472
                        p->resetTextures();
×
473
                }
474
        }
475
        else
476
        {
UNCOV
477
                PlanetP planet = searchByEnglishName(planetName);
×
UNCOV
478
                if (!planet.isNull())
×
UNCOV
479
                        planet->resetTextures();
×
480
        }
×
481
}
×
482

483
void SolarSystem::setTextureForPlanet(const QString& planetName, const QString& texName)
×
484
{
UNCOV
485
        PlanetP planet = searchByEnglishName(planetName);
×
486
        if (!planet.isNull())
×
UNCOV
487
                planet->replaceTexture(texName);
×
488
        else
489
                qWarning() << "The planet" << planetName << "was not found. Please check the name.";
×
490
}
×
491

492
void SolarSystem::recreateTrails()
×
493
{
494
        // Create a trail group containing all the planets orbiting the sun (not including satellites)
495
        if (allTrails!=Q_NULLPTR)
×
UNCOV
496
                delete allTrails;
×
UNCOV
497
        allTrails = new TrailGroup(maxTrailTimeExtent * 365.f, maxTrailPoints);
×
498

499
        unsigned long cnt = static_cast<unsigned long>(selectedSSO.size());
×
500
        if (cnt>0 && getFlagIsolatedTrails())
×
501
        {
502
                unsigned long limit = static_cast<unsigned long>(getNumberIsolatedTrails());
×
503
                if (cnt<limit)
×
UNCOV
504
                        limit = cnt;
×
505
                for (unsigned long i=0; i<limit; i++)
×
506
                {
507
                        if (selectedSSO[cnt - i - 1]->getPlanetType() != Planet::isObserver)
×
508
                                allTrails->addObject(static_cast<QSharedPointer<StelObject>>(selectedSSO[cnt - i - 1]), &trailsColor);
×
509
                }
510
        }
511
        else
512
        {
UNCOV
513
                for (const auto& p : std::as_const(getSun()->satellites))
×
514
                {
UNCOV
515
                        if (p->getPlanetType() != Planet::isObserver)
×
516
                                allTrails->addObject(static_cast<QSharedPointer<StelObject>>(p), &trailsColor);
×
517
                }
518
                // Add moons of current planet
519
                StelCore *core=StelApp::getInstance().getCore();
×
UNCOV
520
                const StelObserver *obs=core->getCurrentObserver();
×
UNCOV
521
                if (obs)
×
522
                {
523
                        const QSharedPointer<Planet> planet=obs->getHomePlanet();
×
524
                        for (const auto& m : std::as_const(planet->satellites))
×
UNCOV
525
                                if (m->getPlanetType() != Planet::isObserver)
×
526
                                        allTrails->addObject(static_cast<QSharedPointer<StelObject>>(m), &trailsColor);
×
527
                }
×
528
        }
529
}
×
530

531

532
void SolarSystem::updateSkyCulture(const StelSkyCulture& skyCulture)
×
533
{
UNCOV
534
        for (const auto& p : std::as_const(systemPlanets))
×
535
                p->removeAllCulturalNames();
×
536

537
        if (!skyCulture.names.isEmpty())
×
538
                loadCultureSpecificNames(skyCulture.names);
×
539

540
        updateI18n();
×
541
}
×
542

543
void SolarSystem::loadCultureSpecificNames(const QJsonObject& data)
×
544
{
UNCOV
545
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
546

UNCOV
547
        for (auto it = data.begin(); it != data.end(); ++it)
×
548
        {
UNCOV
549
                const auto key = it.key();
×
550

551
                if (key.startsWith("NAME "))
×
552
                {
553
                        const QString planetId = key.mid(5);
×
UNCOV
554
                        const QJsonArray names = it.value().toArray(); // The array of name dicts
×
555

556
                        PlanetP planet = searchByEnglishName(planetId);
×
UNCOV
557
                        if (!planet)
×
UNCOV
558
                                continue;
×
559

560
                        for (const auto& nameVal : names)
×
561
                        {
UNCOV
562
                                const QJsonObject json = nameVal.toObject();
×
563

564
                                StelObject::CulturalName cName;
×
565
                                cName.translated=json["english"].toString();
×
566
                                cName.native=json["native"].toString();
×
567
                                //if (cName.native.isEmpty()) cName.native=cName.translated;
568
                                cName.pronounce=json["pronounce"].toString();
×
UNCOV
569
                                if (cName.native.isEmpty())
×
570
                                {
571
                                        if (cName.pronounce.isEmpty())
×
572
                                                cName.native=cName.pronounce=cName.translated;
×
573
                                        else
574
                                                cName.native=cName.pronounce;
×
575
                                }
576

UNCOV
577
                                cName.translatedI18n=trans.qtranslate(cName.translated, json["context"].toString());
×
578
                                cName.pronounceI18n=trans.qtranslate(cName.pronounce, json["context"].toString());
×
UNCOV
579
                                cName.transliteration=json["transliteration"].toString();
×
580
                                cName.IPA=json["IPA"].toString();
×
581

582
                                planet->addCulturalName(cName);
×
583
                        }
×
UNCOV
584
                }
×
UNCOV
585
        }
×
586
}
×
587

588
void SolarSystem::reloadShaders()
×
589
{
590
        Planet::deinitShader();
×
591
        Planet::initShader();
×
592
}
×
593

594
void SolarSystem::drawPointer(const StelCore* core)
×
595
{
596
        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
597
        static StelObjectMgr *sObjMgr=GETSTELMODULE(StelObjectMgr);
×
598

599
        const QList<StelObjectP> newSelected = sObjMgr->getSelectedObject("Planet");
×
600
        if (!newSelected.empty())
×
601
        {
602
                const StelObjectP obj = newSelected[0];
×
603
                Vec3d pos=obj->getJ2000EquatorialPos(core);
×
604

605
                Vec3f screenpos;
×
606
                // Compute 2D pos and return if outside screen
607
                if (!prj->project(pos, screenpos))
×
608
                        return;
×
609

610
                StelPainter sPainter(prj);
×
611
                sPainter.setColor(getPointerColor());
×
612

613
                float screenSize = static_cast<float>(obj->getAngularRadius(core))*prj->getPixelPerRadAtCenter()*M_PI_180f*2.f;
×
614
                
615
                const float scale = static_cast<float>(prj->getDevicePixelsPerPixel());
×
616
                screenSize+= scale * (45.f + 10.f*std::sin(2.f * static_cast<float>(StelApp::getInstance().getAnimationTime())));
×
617

618
                texPointer->bind();
×
619

620
                sPainter.setBlending(true);
×
621

622
                screenSize*=0.5f;
×
623
                const float angleBase = static_cast<float>(StelApp::getInstance().getAnimationTime()) * 10;
×
624
                // We draw 4 instances of the sprite at the corners of the pointer
625
                for (int i = 0; i < 4; ++i)
×
626
                {
627
                        const float angle = angleBase + i * 90;
×
628
                        const float x = screenpos[0] + screenSize * cos(angle * M_PI_180f);
×
629
                        const float y = screenpos[1] + screenSize * sin(angle * M_PI_180f);
×
630
                        sPainter.drawSprite2dMode(x, y, 10, angle);
×
631
                }
632
        }
×
633
}
×
634

635
void keplerOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
×
636
{
637
        static_cast<KeplerOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
×
638
        static_cast<KeplerOrbit*>(orbitPtr)->getVelocity(xyzdot);
×
639
}
×
640

641
void gimbalOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
×
642
{
643
        static_cast<GimbalOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
×
644
        static_cast<GimbalOrbit*>(orbitPtr)->getVelocity(xyzdot);
×
645
}
×
646

647
// Init and load the solar system data (2 files)
648
void SolarSystem::loadPlanets()
×
649
{
650
        minorBodies.clear();
×
651
        systemMinorBodies.clear();
×
652
        qInfo() << "Loading Solar System data (1: planets and moons) ...";
×
653
        QString solarSystemFile = StelFileMgr::findFile("data/ssystem_major.ini");
×
654
        if (solarSystemFile.isEmpty())
×
655
        {
656
                qWarning() << "ERROR while loading ssystem_major.ini (unable to find data/ssystem_major.ini):" << StelUtils::getEndLineChar();
×
657
                return;
×
658
        }
659

660
        if (!loadPlanets(solarSystemFile))
×
661
        {
662
                qWarning() << "ERROR while loading ssystem_major.ini:" << StelUtils::getEndLineChar();
×
663
                return;
×
664
        }
665

666
        qInfo() << "Loading Solar System data (2: minor bodies) ...";
×
667
        QStringList solarSystemFiles = StelFileMgr::findFileInAllPaths("data/ssystem_minor.ini");
×
668
        if (solarSystemFiles.isEmpty())
×
669
        {
670
                qWarning() << "ERROR while loading ssystem_minor.ini (unable to find data/ssystem_minor.ini):" << StelUtils::getEndLineChar();
×
671
                return;
×
672
        }
673

674
        for (const auto& solarSystemFile : std::as_const(solarSystemFiles))
×
675
        {
676
                if (loadPlanets(solarSystemFile))
×
677
                {
678
                        qInfo().noquote() << "File ssystem_minor.ini is loaded successfully...";
×
679
                        break;
×
680
                }
681
                else
682
                {
683
//                        sun.clear();
684
//                        moon.clear();
685
//                        earth.clear();
686
                        //qCritical() << "We should not be here!";
687

688
                        qDebug() << "Removing minor bodies";
×
689
                        for (const auto& p : std::as_const(systemPlanets))
×
690
                        {
691
                                // We can only delete minor objects now!
692
                                if (p->pType >= Planet::isAsteroid)
×
693
                                {
694
                                        p->satellites.clear();
×
695
                                }
696
                        }                        
697
                        systemPlanets.clear();                        
×
698
                        //Memory leak? What's the proper way of cleaning shared pointers?
699

700
                        // TODO: 0.16pre what about the orbits list?
701

702
                        //If the file is in the user data directory, rename it:
703
                        if (solarSystemFile.contains(StelFileMgr::getUserDir()))
×
704
                        {
705
                                QString newName = QString("%1/data/ssystem_minor-%2.ini").arg(StelFileMgr::getUserDir(), QDateTime::currentDateTime().toString("yyyyMMddThhmmss"));
×
706
                                if (QFile::rename(solarSystemFile, newName))
×
707
                                        qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "has been renamed to" << QDir::toNativeSeparators(newName);
×
708
                                else
709
                                {
710
                                        qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "cannot be removed!";
×
711
                                        qWarning() << "Please either delete it, rename it or move it elsewhere.";
×
712
                                }
713
                        }
×
714
                }
715
        }
716

717
        shadowPlanetCount = 0;
×
718

719
        for (const auto& planet : std::as_const(systemPlanets))
×
720
                if(planet->parent != sun || !planet->satellites.isEmpty())
×
721
                        shadowPlanetCount++;
×
722
}
×
723

724
unsigned char SolarSystem::BvToColorIndex(double bV)
×
725
{
726
        const double dBV = qBound(-500., static_cast<double>(bV)*1000.0, 3499.);
×
727
        return static_cast<unsigned char>(std::floor(0.5+127.0*((500.0+dBV)/4000.0)));
×
728
}
729

730
bool SolarSystem::loadPlanets(const QString& filePath)
×
731
{
732
        StelSkyDrawer* skyDrawer = StelApp::getInstance().getCore()->getSkyDrawer();
×
733
        qInfo().noquote() << "Loading from:"  << filePath;
×
734
        QSettings pd(filePath, StelIniFormat);
×
735
        if (pd.status() != QSettings::NoError)
×
736
        {
737
                qWarning().noquote() << "ERROR while parsing" << QDir::toNativeSeparators(filePath);
×
738
                return false;
×
739
        }
740

741
        // QSettings does not allow us to say that the sections of the file
742
        // will be listed in the same order  as in the file like the old
743
        // InitParser used to so we can no longer assume that.
744
        //
745
        // This means we must first decide what order to read the sections
746
        // of the file in (each section contains one planet/moon/asteroid/comet/...) to avoid setting
747
        // the parent Planet* to one which has not yet been created.
748
        //
749
        // Stage 1: Make a map of body names back to the section names
750
        // which they come from. Also make a map of body name to parent body
751
        // name. These two maps can be made in a single pass through the
752
        // sections of the file.
753
        //
754
        // Stage 2: Make an ordered list of section names such that each
755
        // item is only ever dependent on items which appear earlier in the
756
        // list.
757
        // 2a: Make a QMultiMap relating the number of levels of dependency
758
        //     to the body name, i.e.
759
        //     0 -> Sun
760
        //     1 -> Mercury
761
        //     1 -> Venus
762
        //     1 -> Earth
763
        //     2 -> Moon
764
        //     etc.
765
        // 2b: Populate an ordered list of section names by iterating over
766
        //     the QMultiMap.  This type of container is always sorted on the
767
        //     key in ascending order, so it's easy.
768
        //     i.e. [sun, earth, moon] is fine, but not [sun, moon, earth]
769
        //
770
        // Stage 3: iterate over the ordered sections decided in stage 2,
771
        // creating the planet objects from the QSettings data.
772

773
        // Stage 1 (as described above).
774
        QMap<QString, QString> secNameMap;
×
775
        QMap<QString, QString> parentMap;
×
776
        QStringList sections = pd.childGroups();
×
777
        // qDebug() << "Stage 1: load ini file with" << sections.size() << "entries: "<< sections;
778
        for (int i=0; i<sections.size(); ++i)
×
779
        {
780
                const QString secname = sections.at(i);
×
781
                const QString englishName = pd.value(secname+"/name", pd.value(secname+"/iau_designation")).toString();
×
782
                if (englishName.isEmpty())
×
783
                        qWarning().noquote() << "SSO without proper name found in" << QDir::toNativeSeparators(filePath) << "section" << secname;
×
784
                const QString strParent = pd.value(secname+"/parent", "Sun").toString();
×
785
                // 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.
786
                QString obName=englishName;
×
787
                const bool isMinor=QStringList({"asteroid", "plutino", "comet", "dwarf planet", "cubewano", "scattered disc object", "oco", "sednoid", "interstellar object"}).contains(pd.value(secname+"/type").toString());
×
788
                if (isMinor && englishName!=L1S("Pluto"))
×
789
                {
790
                        const QString designation = pd.value(secname+"/iau_designation", pd.value(secname+"/minor_planet_number")).toString();
×
791
                        if (designation.isEmpty() && pd.value(secname+"/type") != L1S("comet"))
×
792
                                qWarning().noquote() << "Minor body " << englishName << "has incomplete data (missing iau_designation or minor_planet_number) in" << QDir::toNativeSeparators(filePath) << "section" << secname;
×
793
                        obName=(QString("%1 (%2)").arg(designation, englishName));
×
794
                }
×
795
                if (secNameMap.contains(obName))
×
796
                        qWarning() << "secNameMap already contains " << obName << ". Overwriting data.";
×
797
                secNameMap[obName] = secname;
×
798
                if (strParent!=L1S("none") && !strParent.isEmpty() && !englishName.isEmpty())
×
799
                {
800
                        parentMap[obName] = strParent;
×
801
                        // qDebug() << "parentmap[" << obName << "] = " << strParent;
802
                }
803
        }
×
804

805
        // Stage 2a (as described above).
806
        QMultiMap<int, QString> depLevelMap;
×
807
        for (int i=0; i<sections.size(); ++i)
×
808
        {
809
                const QString secname = sections.at(i);
×
810
                const QString englishName = pd.value(secname+"/name", pd.value(secname+"/iau_designation")).toString();
×
811
                QString obName=englishName;
×
812
                const bool isMinor=QStringList({"asteroid", "plutino", "comet", "dwarf planet", "cubewano", "scattered disc object", "oco", "sednoid", "interstellar object"}).contains(pd.value(secname+"/type").toString());
×
813
                if (isMinor && englishName!=L1S("Pluto"))
×
814
                {
815
                        const QString designation = pd.value(secname+"/iau_designation", pd.value(secname+"/minor_planet_number")).toString();
×
816
                        obName=(QString("%1 (%2)").arg(designation, englishName));
×
817
                }
×
818
                // follow dependencies, incrementing level when we have one till we run out.
819
                QString p=obName;
×
820
                int level = 0;
×
821
                while(parentMap.contains(p) && parentMap[p]!=L1S("none"))
×
822
                {
823
                        level++;
×
824
                        p = parentMap[p];
×
825
                }
826

827
                depLevelMap.insert(level, secNameMap[obName]);
×
828
                // qDebug() << "2a: Level" << level << "secNameMap[" << obName << "]="<< secNameMap[obName];
829
        }
×
830

831
        // Stage 2b (as described above).
832
        // qDebug() << "Stage 2b:";
833
        QStringList orderedSections;
×
834
#if (QT_VERSION>=QT_VERSION_CHECK(6,0,0))
835
        QMultiMapIterator<int, QString> levelMapIt(depLevelMap);
×
836
#else
837
        QMapIterator<int, QString> levelMapIt(depLevelMap);
838
#endif
839
        while(levelMapIt.hasNext())
×
840
        {
841
                levelMapIt.next();
×
842
                orderedSections << levelMapIt.value();
×
843
        }
844
        // qDebug() << orderedSections;
845

846
        // Stage 3 (as described above).
847
        int readOk=0;
×
848
        //int totalPlanets=0;
849

850
        // qDebug() << "Adding " << orderedSections.size() << "objects...";
851
        for (int i = 0;i<orderedSections.size();++i)
×
852
        {
853
                // qDebug() << "Processing entry" << orderedSections.at(i);
854

855
                //totalPlanets++;
856
                const QString secname = orderedSections.at(i);
×
857
                const QString type = pd.value(secname+"/type").toString();
×
858
                QString englishName = pd.value(secname+"/name").toString().simplified();
×
859
                // englishName alone may be a combination of several elements...
860
                if (type==L1S("comet") || type == L1S("interstellar object"))
×
861
                {
862
                        static const QRegularExpression periodicRe("^([1-9][0-9]*[PD](-\\w+)?)"); // No "/" at end, there are nameless numbered comets! (e.g. 362P, 396P)
×
863
                        QRegularExpressionMatch periodMatch=periodicRe.match(englishName);
×
864

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

868
                        // Our name rules for the final englishName, which must contain one element in brackets unless it starts with "A/".
869
                        // Numbered periodic comets: "1P/Halley (1986)"
870
                        // Reclassified Asteroid like "A/2022 B3"
871
                        // All others: C-AX/2023 A2 (discoverer)". (with optional fragment code -AX)
872
                        const QString iauDesignation = pd.value(secname+"/iau_designation").toString();
×
873
                        const QString dateCode =      pd.value(secname+"/date_code").toString();
×
874
                        const QString perihelCode =   pd.value(secname+"/perihelion_code").toString();
×
875
                        const QString discoveryCode = pd.value(secname+"/discovery_code").toString();
×
876
                        if (iauDesignation.isEmpty() && perihelCode.isEmpty() && discoveryCode.isEmpty() && !periodMatch.hasMatch() && !iauDesignationMatch.hasMatch())
×
877
                        {
878
                                qWarning() << "Comet " << englishName << "has no IAU designation, no perihelion code, no discovery code and seems not a numbered comet in section " << secname;
×
879
                        }
880
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
881

882
                        // 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!
883
                        if (iauDesignation.isEmpty() && !englishName.contains("(") && (!discoveryCode.isEmpty()))
×
884
                        {
885
                                        englishName.append(QString(" (%1)").arg(discoveryCode));
×
886
                        }
887
                        else if (iauDesignation.isEmpty() && !englishName.contains("("))
×
888
                        {
889
                                // Prepare perihel year to attach to the name when loading an old ssystem_minor.ini where this name component is missing
890
                                QString periStr;
×
891
                                double periJD=pd.value(secname+"/orbit_TimeAtPericenter").toDouble();
×
892
                                if (periJD)
×
893
                                {
894
                                        int day, month, year;
895
                                        StelUtils::getDateFromJulianDay(periJD, &year, &month, &day);
×
896
                                        periStr=QString::number(year);
×
897
                                }
898
                                if (!periStr.isEmpty())
×
899
                                        englishName.append(QString(" (%1)").arg(periStr));
×
900
                                else
901
                                        qWarning() << "orbit_TimeAtPericenter may be invalid for object" << englishName << "in section" << secname;
×
902
                        }
×
903
                        else if (!iauDesignation.isEmpty() && !englishName.contains("(") && !englishName.contains("/") && !englishName.startsWith("A/"))
×
904
                                englishName=QString("%1 (%2)").arg(iauDesignation, englishName); // recombine name and iau_designation if name is only the discoverer name.
×
905

906
                        if (!englishName.contains("(") && !englishName.startsWith("A/"))
×
907
                        {
908
                                QString name;
×
909
                                if (!iauDesignation.isEmpty())
×
910
                                {
911
                                        name=iauDesignation;
×
912
                                        if (!englishName.isEmpty())
×
913
                                                name.append(QString(" (%1)").arg(englishName));
×
914
                                }
915
                                else if (!dateCode.isEmpty())
×
916
                                {
917
                                        name=dateCode;
×
918
                                        if (!englishName.isEmpty())
×
919
                                                name.append(QString(" (%1)").arg(englishName));
×
920
                                }
921
                                else if (!discoveryCode.isEmpty())
×
922
                                {
923
                                        name=discoveryCode;
×
924
                                        if (!englishName.isEmpty())
×
925
                                                name.append(QString(" (%1)").arg(englishName));
×
926
                                }
927
                                else if (!perihelCode.isEmpty())
×
928
                                {
929
                                        name.append(QString("C/%1").arg(perihelCode)); // This is not classic, but a final fallback before warning
×
930
                                        if (!englishName.isEmpty())
×
931
                                                name.append(QString(" (%1)").arg(englishName));
×
932
                                }
933

934
                                if (name.contains("("))
×
935
                                        englishName=name;
×
936
                                else
937
                                        qWarning() << "Comet " << englishName << "has no proper name elements in section " << secname;
×
938
                        }
×
939
                }
×
940
                else if (QStringList({"asteroid", "dwarf planet", "cubewano", "sednoid", "plutino", "scattered disc object", "Oort cloud object"}).contains(type) && !englishName.contains("Pluto"))
×
941
                {
942
                        const int minorPlanetNumber= pd.value(secname+"/minor_planet_number").toInt();
×
943
                        const QString iauDesignation = pd.value(secname+"/iau_designation", "").toString();
×
944
                        if (iauDesignation.isEmpty() && minorPlanetNumber==0)
×
945
                                qWarning() << "minor body " << englishName << "has no IAU code in section " << secname;
×
946
                        const QString discoveryCode = pd.value(secname+"/discovery_code").toString();
×
947

948
                        // 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
949
                        if (englishName.isEmpty())
×
950
                        {
951
                                //if (minorPlanetNumber>0)
952
                                //        englishName=QString("(%1) ").arg(minorPlanetNumber);
953
                                if (!iauDesignation.isEmpty())
×
954
                                {
955
                                        englishName.append(iauDesignation);
×
956
                                }
957
                                else if (!discoveryCode.isEmpty())
×
958
                                {
959
                                        englishName.append(discoveryCode);
×
960
                                }
961
                                else
962
                                        qWarning() << "Minor body in section" << secname << "has no proper name elements";
×
963
                        }
964
                }
×
965

966
                const double bV = pd.value(secname+"/color_index_bv", 99.).toDouble();
×
967
                const QString strParent = pd.value(secname+"/parent", "Sun").toString(); // Obvious default, keep file entries simple.
×
968
                PlanetP parent;
×
969
                if (strParent!=L1S("none"))
×
970
                {
971
                        // Look in the other planets the one named with strParent
972
                        for (const auto& p : std::as_const(systemPlanets))
×
973
                        {
974
                                if (p->getEnglishName()==strParent)
×
975
                                {
976
                                        parent = p;
×
977
                                        break;
×
978
                                }
979
                        }
980
                        if (parent.isNull())
×
981
                        {
982
                                qWarning().noquote().nospace() << "ERROR: can't find parent solar system body for " << englishName << ". Skipping.";
×
983
                                //abort();
984
                                continue;
×
985
                        }
986
                }
987
                Q_ASSERT(parent || englishName==L1S("Sun"));
×
988

989
                const QString coordFuncName = pd.value(secname+"/coord_func", "kepler_orbit").toString(); // 0.20: new default for all non *_special.
×
990
                // qDebug() << "englishName:" << englishName << ", parent:" << strParent <<  ", coord_func:" << coordFuncName;
991
                posFuncType posfunc=Q_NULLPTR;
×
992
                Orbit* orbitPtr=Q_NULLPTR;
×
993
                OsculatingFunctType *osculatingFunc = Q_NULLPTR;
×
994
                bool closeOrbit = true;
×
995
                double semi_major_axis=0; // used again below.
×
996

997

998
#ifdef USE_GIMBAL_ORBIT
999
                // undefine the flag in Orbit.h to disable and use the old, static observer solution (on an infinitely slow KeplerOrbit)
1000
                // Note that for now we ignore any orbit-related config values except orbit_SemiMajorAxis from the ini file.
1001
                if (type==L1S("observer"))
×
1002
                {
1003
                        double unit = 1; // AU
×
1004
                        double defaultSemiMajorAxis = 1;
×
1005
                        if (strParent!=L1S("Sun"))
×
1006
                        {
1007
                                unit /= AU;  // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
×
1008
                                defaultSemiMajorAxis *= AU;
×
1009
                        }
1010
                        semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis", defaultSemiMajorAxis).toDouble() * unit;
×
1011
                        // Create a pseudo orbit that allows interaction with keyboard
1012
                        GimbalOrbit *orb = new GimbalOrbit(semi_major_axis, 0.*M_PI_180, 45.*M_PI_180); // [Over mid-north latitude]
×
1013
                        orb->setMinDistance(parent->getEquatorialRadius()*1.5);
×
1014
                        orbits.push_back(orb);
×
1015

1016
                        orbitPtr = orb;
×
1017
                        posfunc = &gimbalOrbitPosFunc;
×
1018
                }
1019
                else
1020
#endif
1021
                if (coordFuncName==L1S("kepler_orbit") || coordFuncName==L1S("comet_orbit") || coordFuncName==L1S("ell_orbit")) // ell_orbit used for planet moons. TBD in V1.0: remove non-kepler_orbit!
×
1022
                {
1023
                        if (coordFuncName!=L1S("kepler_orbit"))
×
1024
                                qDebug() << "Old-fashioned entry" << coordFuncName << "found. Please delete line from " << filePath << "section" << secname;
×
1025
                        // 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.
1026
                        // Read the orbital elements                        
1027
                        const double eccentricity = pd.value(secname+"/orbit_Eccentricity", 0.0).toDouble();
×
1028
                        if (eccentricity >= 1.0) closeOrbit = false;
×
1029
                        double pericenterDistance = pd.value(secname+"/orbit_PericenterDistance",-1e100).toDouble(); // AU, or km for Moons (those where parent!=sun)!
×
1030
                        if (pericenterDistance <= 0.0) {
×
1031
                                semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis",-1e100).toDouble();
×
1032
                                if (semi_major_axis <= -1e100) {
×
1033
                                        qDebug() << "ERROR loading " << englishName << "from section" << secname
×
1034
                                                 << ": you must provide orbit_PericenterDistance or orbit_SemiMajorAxis. Skipping " << englishName;
×
1035
                                        continue;
×
1036
                                } else {
1037
                                        Q_ASSERT(eccentricity != 1.0); // parabolic orbits have no semi_major_axis
×
1038
                                        pericenterDistance = semi_major_axis * (1.0-eccentricity);
×
1039
                                }
1040
                        } else {
1041
                                semi_major_axis = (eccentricity == 1.0)
×
1042
                                                                ? 0.0 // parabolic orbits have no semi_major_axis
×
1043
                                                                : pericenterDistance / (1.0-eccentricity);
×
1044
                        }
1045
                        if (strParent!=L1S("Sun"))
×
1046
                                pericenterDistance /= AU;  // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
×
1047

1048
                        double meanMotion = pd.value(secname+"/orbit_MeanMotion",-1e100).toDouble(); // degrees/day
×
1049
                        if (meanMotion <= -1e100) {
×
1050
                                const double period = pd.value(secname+"/orbit_Period",-1e100).toDouble();
×
1051
                                if (period <= -1e100) {
×
1052
                                        if (parent->getParent()) {
×
1053
                                                qWarning().noquote() << "ERROR: " << englishName
×
1054
                                                           << ": when the parent body is not the sun, you must provide "
×
1055
                                                           << "either orbit_MeanMotion or orbit_Period";
×
1056
                                        } else {
1057
                                                // in case of parent=sun: use Gaussian gravitational constant for calculating meanMotion:
1058
                                                meanMotion = (eccentricity == 1.0)
×
1059
                                                                        ? 0.01720209895 * (1.5/pericenterDistance) * std::sqrt(0.5/pericenterDistance)  // Heafner: Fund.Eph.Comp. W / dt
×
1060
                                                                        : 0.01720209895 / (fabs(semi_major_axis)*std::sqrt(fabs(semi_major_axis)));
×
1061
                                        }
1062
                                } else {
1063
                                        meanMotion = 2.0*M_PI/period;
×
1064
                                }
1065
                        } else {
1066
                                meanMotion *= (M_PI/180.0);
×
1067
                        }
1068

1069
                        const double ascending_node = pd.value(secname+"/orbit_AscendingNode", 0.0).toDouble()*(M_PI/180.0);
×
1070
                        double arg_of_pericenter = pd.value(secname+"/orbit_ArgOfPericenter",-1e100).toDouble();
×
1071
                        double long_of_pericenter;
1072
                        if (arg_of_pericenter <= -1e100) {
×
1073
                                long_of_pericenter = pd.value(secname+"/orbit_LongOfPericenter", 0.0).toDouble()*(M_PI/180.0);
×
1074
                                arg_of_pericenter = long_of_pericenter - ascending_node;
×
1075
                        } else {
1076
                                arg_of_pericenter *= (M_PI/180.0);
×
1077
                                long_of_pericenter = arg_of_pericenter + ascending_node;
×
1078
                        }
1079

1080
                        double time_at_pericenter = pd.value(secname+"/orbit_TimeAtPericenter",-1e100).toDouble();
×
1081
                        // 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.
1082
                        // However, the distinction is relevant to discern element sets for various valid ranges.
1083
                        // Comet orbits epoch should default to T while planets or moons default to J2000.
1084
                        const double epoch = pd.value(secname+"/orbit_Epoch", type==L1S("comet") ? time_at_pericenter : Planet::J2000).toDouble();
×
1085
                        if (time_at_pericenter <= -1e100) {
×
1086
                                double mean_anomaly = pd.value(secname+"/orbit_MeanAnomaly",-1e100).toDouble()*(M_PI/180.0);
×
1087
                                if (mean_anomaly <= -1e10) {
×
1088
                                        double mean_longitude = pd.value(secname+"/orbit_MeanLongitude",-1e100).toDouble()*(M_PI/180.0);
×
1089
                                        if (mean_longitude <= -1e10) {
×
1090
                                                qWarning().noquote() << "ERROR: " << englishName
×
1091
                                                           << ": when you do not provide orbit_TimeAtPericenter, you must provide orbit_Epoch"
×
1092
                                                           << "and either one of orbit_MeanAnomaly or orbit_MeanLongitude. Skipping this object.";
×
1093
                                                //abort();
1094
                                                continue;
×
1095
                                        } else {
1096
                                                mean_anomaly = mean_longitude - long_of_pericenter;
×
1097
                                        }
1098
                                }
1099
                                time_at_pericenter = epoch - mean_anomaly / meanMotion;
×
1100
                        }
1101

1102
                        static const QMap<QString, double>massMap={ // masses from DE430/431
1103
                                { "Sun",            1.0},
×
1104
                                { "Mercury",  6023682.155592},
×
1105
                                { "Venus",     408523.718658},
×
1106
                                { "Earth",     332946.048834},
×
1107
                                { "Mars",     3098703.590291},
×
1108
                                { "Jupiter",     1047.348625},
×
1109
                                { "Saturn",      3497.901768},
×
1110
                                { "Uranus",     22902.981613},
×
1111
                                { "Neptune",    19412.259776},
×
1112
                                { "Pluto",  135836683.768617}};
×
1113

1114
                        // Construct orbital elements relative to the parent body. This will construct orbits for J2000 only.
1115
                        // Some planet axes move very slowly, this effect could be modelled by replicating these lines
1116
                        // after recomputing obliquity and node (below) in Planet::computeTransMatrix().
1117
                        // The effect is negligible for several millennia, though.
1118
                        // When the parent is the sun use ecliptic rather than sun equator:
1119
                        const double parentRotObliquity  = parent->getParent() ? parent->getRotObliquity(Planet::J2000) : 0.0;
×
1120
                        const double parent_rot_asc_node = parent->getParent() ? parent->getRotAscendingNode()  : 0.0;
×
1121
                        double parent_rot_j2000_longitude = 0.0;
×
1122
                        if (parent->getParent()) {
×
1123
                                const double c_obl = cos(parentRotObliquity);
×
1124
                                const double s_obl = sin(parentRotObliquity);
×
1125
                                const double c_nod = cos(parent_rot_asc_node);
×
1126
                                const double s_nod = sin(parent_rot_asc_node);
×
1127
                                const Vec3d OrbitAxis0( c_nod,       s_nod,        0.0);
×
1128
                                const Vec3d OrbitAxis1(-s_nod*c_obl, c_nod*c_obl,s_obl);
×
1129
                                const Vec3d OrbitPole(  s_nod*s_obl,-c_nod*s_obl,c_obl);
×
1130
                                const Vec3d J2000Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(Vec3d(0,0,1)));
×
1131
                                Vec3d J2000NodeOrigin(J2000Pole^OrbitPole);
×
1132
                                J2000NodeOrigin.normalize();
×
1133
                                parent_rot_j2000_longitude = atan2(J2000NodeOrigin*OrbitAxis1,J2000NodeOrigin*OrbitAxis0);
×
1134
                        }
1135

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

1139
                        // Create a Keplerian orbit. This has been called CometOrbit before 0.20.
1140
                        //qDebug() << "Creating KeplerOrbit for" << parent->englishName << "---" << englishName;
1141
                        KeplerOrbit *orb = new KeplerOrbit(epoch,                  // JDE
1142
                                                           pericenterDistance,     // [AU]
1143
                                                           eccentricity,           // 0..>1 (>>1 for Interstellar objects)
1144
                                                           inclination,            // [radians]
1145
                                                           ascending_node,         // [radians]
1146
                                                           arg_of_pericenter,      // [radians]
1147
                                                           time_at_pericenter,     // JDE
1148
                                                           orbitGoodDays,          // orbitGoodDays. 0=always good, -1=compute_half_orbit_duration
1149
                                                           meanMotion,             // [radians/day]
1150
                                                           parentRotObliquity,     // [radians]
1151
                                                           parent_rot_asc_node,    // [radians]
1152
                                                           parent_rot_j2000_longitude, // [radians]
1153
                                                           1./massMap.value(parent->englishName, 1.)); // central mass [solar masses]
×
1154
                        orbits.push_back(orb);
×
1155

1156
                        orbitPtr = orb;
×
1157
                        posfunc = &keplerOrbitPosFunc;
×
1158
                }
1159
                else
1160
                {
1161
                        static const QMap<QString, posFuncType>posfuncMap={
1162
                                { "sun_special",       &get_sun_barycentric_coordsv},
×
1163
                                { "mercury_special",   &get_mercury_helio_coordsv},
×
1164
                                { "venus_special",     &get_venus_helio_coordsv},
×
1165
                                { "earth_special",     &get_earth_helio_coordsv},
×
1166
                                { "lunar_special",     &get_lunar_parent_coordsv},
×
1167
                                { "mars_special",      &get_mars_helio_coordsv},
×
1168
                                { "phobos_special",    &get_phobos_parent_coordsv},
×
1169
                                { "deimos_special",    &get_deimos_parent_coordsv},
×
1170
                                { "jupiter_special",   &get_jupiter_helio_coordsv},
×
1171
                                { "io_special",        &get_io_parent_coordsv},
×
1172
                                { "europa_special",    &get_europa_parent_coordsv},
×
1173
                                { "ganymede_special",  &get_ganymede_parent_coordsv},
×
1174
                                { "calisto_special",   &get_callisto_parent_coordsv},
×
1175
                                { "callisto_special",  &get_callisto_parent_coordsv},
×
1176
                                { "saturn_special",    &get_saturn_helio_coordsv},
×
1177
                                { "mimas_special",     &get_mimas_parent_coordsv},
×
1178
                                { "enceladus_special", &get_enceladus_parent_coordsv},
×
1179
                                { "tethys_special",    &get_tethys_parent_coordsv},
×
1180
                                { "dione_special",     &get_dione_parent_coordsv},
×
1181
                                { "rhea_special",      &get_rhea_parent_coordsv},
×
1182
                                { "titan_special",     &get_titan_parent_coordsv},
×
1183
                                { "hyperion_special",  &get_hyperion_parent_coordsv},
×
1184
                                { "iapetus_special",   &get_iapetus_parent_coordsv},
×
1185
                                { "helene_special",    &get_helene_parent_coordsv},
×
1186
                                { "telesto_special",   &get_telesto_parent_coordsv},
×
1187
                                { "calypso_special",   &get_calypso_parent_coordsv},
×
1188
                                { "uranus_special",    &get_uranus_helio_coordsv},
×
1189
                                { "miranda_special",   &get_miranda_parent_coordsv},
×
1190
                                { "ariel_special",     &get_ariel_parent_coordsv},
×
1191
                                { "umbriel_special",   &get_umbriel_parent_coordsv},
×
1192
                                { "titania_special",   &get_titania_parent_coordsv},
×
1193
                                { "oberon_special",    &get_oberon_parent_coordsv},
×
1194
                                { "neptune_special",   &get_neptune_helio_coordsv},
×
1195
                                { "pluto_special",     &get_pluto_helio_coordsv}};
×
1196
                        static const QMap<QString, OsculatingFunctType*>osculatingMap={
1197
                                { "mercury_special",   &get_mercury_helio_osculating_coords},
×
1198
                                { "venus_special",     &get_venus_helio_osculating_coords},
×
1199
                                { "earth_special",     &get_earth_helio_osculating_coords},
×
1200
                                { "mars_special",      &get_mars_helio_osculating_coords},
×
1201
                                { "jupiter_special",   &get_jupiter_helio_osculating_coords},
×
1202
                                { "saturn_special",    &get_saturn_helio_osculating_coords},
×
1203
                                { "uranus_special",    &get_uranus_helio_osculating_coords},
×
1204
                                { "neptune_special",   &get_neptune_helio_osculating_coords}};
×
1205
                        posfunc=posfuncMap.value(coordFuncName, Q_NULLPTR);
×
1206
                        osculatingFunc=osculatingMap.value(coordFuncName, Q_NULLPTR);
×
1207
                }
1208
                if (posfunc==Q_NULLPTR)
×
1209
                {
1210
                        qCritical() << "ERROR in section " << secname << ": can't find posfunc " << coordFuncName << " for " << englishName;
×
1211
                        exit(-1);
×
1212
                }
1213

1214
                // Create the Solar System body and add it to the list
1215
                //TODO: Refactor the subclass selection to reduce duplicate code mess here,
1216
                // by at least using this base class pointer and using setXXX functions instead of mega-constructors
1217
                // that have to pass most of it on to the Planet class
1218
                PlanetP newP;
×
1219

1220
                // New class objects, named "plutino", "cubewano", "dwarf planet", "SDO", "OCO", has properties
1221
                // similar to asteroids and we should calculate their positions like for asteroids. Dwarf planets
1222
                // have one exception: Pluto - as long as we use a special function for calculation of Pluto's orbit.
1223
                if ((type == L1S("asteroid") || type == L1S("dwarf planet") || type == L1S("cubewano") || type==L1S("sednoid") || type == L1S("plutino") || type == L1S("scattered disc object") || type == L1S("Oort cloud object") || type == L1S("interstellar object")) && !englishName.contains("Pluto"))
×
1224
                {
1225
                        minorBodies << englishName;
×
1226

1227
                        Vec3f color = Vec3f(1.f, 1.f, 1.f);
×
1228
                        if (bV<99.)
×
1229
                                color = skyDrawer->indexToColor(BvToColorIndex(bV))*0.75f; // see ZoneArray.cpp:L490
×
1230
                        else
1231
                                color = Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString());
×
1232

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

1237
                        newP = PlanetP(new MinorPlanet(englishName,
×
1238
                                                    pd.value(secname+"/radius", 0.0).toDouble()/AU,
×
1239
                                                    pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1240
                                                    color, // halo color
1241
                                                    pd.value(secname+"/albedo", 0.0f).toFloat(),
×
1242
                                                    pd.value(secname+"/roughness",0.9f).toFloat(),
×
1243
                                                    pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1244
                                                    pd.value(secname+"/normals_map", normalMapName).toString(),
×
1245
                                                    pd.value(secname+"/horizon_map", horizonMapName).toString(),
×
1246
                                                    pd.value(secname+"/model").toString(),
×
1247
                                                    posfunc,
1248
                                                    static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object created previously
1249
                                                    osculatingFunc, // should be Q_NULLPTR
1250
                                                    closeOrbit,
1251
                                                    hidden,
1252
                                                    type));
×
1253
                        QSharedPointer<MinorPlanet> mp =  newP.dynamicCast<MinorPlanet>();
×
1254
                        //Number, IAU provisional designation
1255
                        mp->setMinorPlanetNumber(pd.value(secname+"/minor_planet_number", 0).toInt());
×
1256
                        mp->setIAUDesignation(pd.value(secname+"/iau_designation", "").toString());
×
1257

1258
                        //H-G magnitude system
1259
                        const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1260
                        const float slope = pd.value(secname+"/slope_parameter", 0.15f).toFloat();
×
1261
                        if (magnitude > -99.f)
×
1262
                        {
1263
                                mp->setAbsoluteMagnitudeAndSlope(magnitude, qBound(0.0f, slope, 1.0f));
×
1264
                                mp->updateEquatorialRadius();
×
1265
                        }
1266

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

1270
                        // Discovery circumstances
1271
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1272
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1273
                        if (!discoveryDate.isEmpty())
×
1274
                                mp->setDiscoveryData(discoveryDate, discovererName);
×
1275

1276
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
1277
                        QStringList codes = { pd.value(secname+"/date_code", "").toString(),
×
1278
                                              pd.value(secname+"/perihelion_code", "").toString(),
×
1279
                                              pd.value(secname+"/discovery_code", "").toString() };
×
1280
                        codes.removeAll("");
×
1281
                        if (codes.count()>0)
×
1282
                                mp->setExtraDesignations(codes);
×
1283

1284
                        if (semi_major_axis>0)
×
1285
                                mp->deltaJDE = 2.0*semi_major_axis*StelCore::JD_SECOND;
×
1286
                         else if (semi_major_axis<=0.0 && type!=L1S("interstellar object"))
×
1287
                                qWarning().noquote() << "Minor body" << englishName << "has no semimajor axis!";
×
1288

1289
                        systemMinorBodies.push_back(newP);
×
1290
                }
×
1291
                else if (type == L1S("comet"))
×
1292
                {
1293
                        minorBodies << englishName;
×
1294
                        newP = PlanetP(new Comet(englishName,
×
1295
                                              pd.value(secname+"/radius", 5.0).toDouble()/AU,
×
1296
                                              pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1297
                                              Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
×
1298
                                              pd.value(secname+"/albedo", 0.075f).toFloat(), // assume very dark surface
×
1299
                                              pd.value(secname+"/roughness",0.9f).toFloat(),
×
1300
                                              pd.value(secname+"/outgas_intensity",0.1f).toFloat(),
×
1301
                                              pd.value(secname+"/outgas_falloff", 0.1f).toFloat(),
×
1302
                                              pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1303
                                              pd.value(secname+"/model").toString(),
×
1304
                                              posfunc,
1305
                                              static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object
1306
                                              osculatingFunc, // ALWAYS NULL for comets.
1307
                                              closeOrbit,
1308
                                              pd.value(secname+"/hidden", false).toBool(),
×
1309
                                              type,
1310
                                              pd.value(secname+"/dust_widthfactor", 1.5f).toFloat(),
×
1311
                                              pd.value(secname+"/dust_lengthfactor", 0.4f).toFloat(),
×
1312
                                              pd.value(secname+"/dust_brightnessfactor", 1.5f).toFloat()
×
1313
                                              ));
×
1314
                        QSharedPointer<Comet> comet = newP.dynamicCast<Comet>();
×
1315

1316
                        //g,k magnitude system
1317
                        const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1318
                        const float slope = qBound(-5.0f, pd.value(secname+"/slope_parameter", 4.0f).toFloat(), 30.0f);
×
1319
                        if (magnitude > -99.f)
×
1320
                                        comet->setAbsoluteMagnitudeAndSlope(magnitude, slope);
×
1321

1322
                        QString iauDesignation = pd.value(secname+"/iau_designation", "").toString();
×
1323
                        if (!iauDesignation.isEmpty())
×
1324
                                comet->setIAUDesignation(iauDesignation);
×
1325
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
1326
                        QStringList codes = { pd.value(secname+"/date_code", "").toString(),
×
1327
                                              pd.value(secname+"/perihelion_code", "").toString(),
×
1328
                                              pd.value(secname+"/discovery_code", "").toString() };
×
1329
                        codes.removeAll("");
×
1330
                        if (codes.count()>0)
×
1331
                                comet->setExtraDesignations(codes);
×
1332

1333
                        // Discovery circumstances
1334
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1335
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1336
                        if (!discoveryDate.isEmpty())
×
1337
                                comet->setDiscoveryData(discoveryDate, discovererName);
×
1338

1339
                        systemMinorBodies.push_back(newP);
×
1340
                }
×
1341
                else // type==star|planet|moon|dwarf planet|observer|artificial
1342
                {
1343
                        //qDebug() << type;
1344
                        Q_ASSERT(type==L1S("star") || type==L1S("planet") || type==L1S("moon") || type==L1S("artificial") || type==L1S("observer") || type==L1S("dwarf planet")); // TBD: remove Pluto...
×
1345
                        // Set possible default name of the normal map for avoiding yin-yang shaped moon
1346
                        // phase when normal map key not exists. Example: moon_normals.png
1347
                        // Details: https://bugs.launchpad.net/stellarium/+bug/1335609                        
1348
                        newP = PlanetP(new Planet(englishName,
×
1349
                                               pd.value(secname+"/radius", 1.0).toDouble()/AU,
×
1350
                                               pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1351
                                               Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
×
1352
                                               pd.value(secname+"/albedo", 0.25f).toFloat(),
×
1353
                                               pd.value(secname+"/roughness",0.9f).toFloat(),
×
1354
                                               pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1355
                                               pd.value(secname+"/normals_map", englishName.toLower().append("_normals.png")).toString(),
×
1356
                                               pd.value(secname+"/horizon_map", englishName.toLower().append("_horizon.png")).toString(),
×
1357
                                               pd.value(secname+"/model").toString(),
×
1358
                                               posfunc,
1359
                                               static_cast<KeplerOrbit*>(orbitPtr), // This remains Q_NULLPTR for the major planets, or has a KeplerOrbit for planet moons.
1360
                                               osculatingFunc,
1361
                                               closeOrbit,
1362
                                               pd.value(secname+"/hidden", false).toBool(),
×
1363
                                               pd.value(secname+"/atmosphere", false).toBool(),
×
1364
                                               pd.value(secname+"/halo", true).toBool(),
×
1365
                                               type));
×
1366
                        newP->absoluteMagnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1367
                        newP->massKg = pd.value(secname+"/mass_kg", 0.).toDouble();
×
1368

1369
                        // Moon designation (planet index + IAU moon number)
1370
                        QString moonDesignation = pd.value(secname+"/iau_moon_number", "").toString();
×
1371
                        if (!moonDesignation.isEmpty())
×
1372
                                newP->setIAUMoonNumber(moonDesignation);
×
1373
                        newP->setColorIndexBV(static_cast<float>(bV));
×
1374
                        // Discovery circumstances
1375
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1376
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1377
                        if (!discoveryDate.isEmpty())
×
1378
                                newP->setDiscoveryData(discoveryDate, discovererName);
×
1379
                }
×
1380

1381
                if (!parent.isNull())
×
1382
                {
1383
                        parent->satellites.append(newP);
×
1384
                        newP->parent = parent;
×
1385
                }
1386
                if (secname==L1S("earth")) earth = newP;
×
1387
                if (secname==L1S("sun")) sun = newP;
×
1388
                if (secname==L1S("moon")) moon = newP;
×
1389

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

1393
                // There are two ways of defining the axis orientation:
1394
                // obliquity and ascending node, which was used by Stellarium already before 2010 (based on Celestia?).
1395
                double rotObliquity = pd.value(secname+"/rot_obliquity",0.).toDouble()*(M_PI_180);
×
1396
                double rotAscNode = pd.value(secname+"/rot_equator_ascending_node",0.).toDouble()*(M_PI_180);
×
1397
                // rot_periode given in hours (from which rotPeriod in days),
1398
                // The default is useful for many moons in bound rotation
1399
                double rotPeriod=pd.value(secname+"/rot_periode", pd.value(secname+"/orbit_Period", 1.).toDouble()*24.).toDouble()/24.;
×
1400
                double rotOffset=pd.value(secname+"/rot_rotation_offset",0.).toDouble();
×
1401

1402
                // 0.21+: Use WGCCRE planet North pole data if available
1403
                // NB: N pole for J2000 epoch as defined by IAU (NOT right hand rotation rule)
1404
                // Define only basic motion. Use special functions for more complicated axes.
1405
                const double J2000NPoleRA  = pd.value(secname+"/rot_pole_ra",  0.).toDouble()*M_PI_180;
×
1406
                const double J2000NPoleRA1 = pd.value(secname+"/rot_pole_ra1", 0.).toDouble()*M_PI_180;
×
1407
                const double J2000NPoleDE  = pd.value(secname+"/rot_pole_de",  0.).toDouble()*M_PI_180;
×
1408
                const double J2000NPoleDE1 = pd.value(secname+"/rot_pole_de1", 0.).toDouble()*M_PI_180;
×
1409
                const double J2000NPoleW0  = pd.value(secname+"/rot_pole_w0",  0.).toDouble(); // [degrees]   Basically the same idea as rot_rotation_offset, but W!=rotAngle
×
1410
                const double J2000NPoleW1  = pd.value(secname+"/rot_pole_w1",  0.).toDouble(); // [degrees/d] Basically the same idea as 360/rot_periode
×
1411
                if (fabs(J2000NPoleW1) > 0.0) // Patch possibly old period value with a more modern value.
×
1412
                {
1413
                        // this is just another expression for rotational speed.
1414
                        rotPeriod=360.0/J2000NPoleW1;
×
1415
                }
1416

1417
                // IMPORTANT: For the planet moons with orbits relative to planets' equator plane,
1418
                // re-compute the important bits from the updated axis elements.
1419
                // Reactivated to re-establish Pluto/Charon lock #153
1420
                if((J2000NPoleRA!=0.) || (J2000NPoleDE!=0.))
×
1421
                {
1422
                        // If available, recompute obliquity and AscNode from the new data.
1423
                        // Solution since 0.16: Make this once for J2000.
1424
                        // Optional (future?): Repeat this block in Planet::computeTransMatrix() for planets with moving axes and update all Moons' KeplerOrbit if required.
1425
                        Vec3d J2000NPole;
×
1426
                        StelUtils::spheToRect(J2000NPoleRA,J2000NPoleDE,J2000NPole);
×
1427

1428
                        Vec3d vsop87Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(J2000NPole));
×
1429

1430
                        double lon, lat;
1431
                        StelUtils::rectToSphe(&lon, &lat, vsop87Pole);
×
1432

1433
                        rotObliquity = (M_PI_2 - lat);
×
1434
                        rotAscNode = (lon + M_PI_2);
×
1435

1436
                        //qDebug() << englishName << ": Compare these values to the older data in ssystem_major";
1437
                        //qDebug() << "\tCalculated rotational obliquity: " << rotObliquity*180./M_PI;
1438
                        //qDebug() << "\tCalculated rotational ascending node: " << rotAscNode*180./M_PI;
1439

1440
                        if (J2000NPoleW0 >0)
×
1441
                        {
1442
                                // W0 is counted from the ascending node with ICRF, but rotOffset from orbital plane.
1443
                                // Try this assumption by just counting Offset=W0+90+RA0.
1444
                                rotOffset=J2000NPoleW0 + lon*M_180_PI;
×
1445
                                //qDebug() << "\tCalculated rotational period (days // hours): " << rotPeriod << "//" << rotPeriod*24.;
1446
                                //qDebug() << "\tRotational offset (degrees): " << rotOffset;
1447
                        }
1448
                }
1449
                newP->setRotationElements(
×
1450
                        englishName,
1451
                        rotPeriod,
1452
                        rotOffset,
1453
                        pd.value(secname+"/rot_epoch", Planet::J2000).toDouble(),
×
1454
                        rotObliquity,
1455
                        rotAscNode,
1456
                        J2000NPoleRA,
1457
                        J2000NPoleRA1,
1458
                        J2000NPoleDE,
1459
                        J2000NPoleDE1,
1460
                        J2000NPoleW0,
1461
                        J2000NPoleW1);
1462
                // orbit_Period given in days.
1463
                // Elliptical Kepler orbits (ecc<0.9) will replace whatever is given by a value computed on the fly. Parabolic objects show 0.
1464
                newP->setSiderealPeriod(fabs(pd.value(secname+"/orbit_Period", 0.).toDouble()));
×
1465

1466
                if (pd.contains(secname+"/tex_ring")) {
×
1467
                        const float rMin = pd.value(secname+"/ring_inner_size").toFloat()/AUf;
×
1468
                        const float rMax = pd.value(secname+"/ring_outer_size").toFloat()/AUf;
×
1469
                        Ring *r = new Ring(rMin,rMax,pd.value(secname+"/tex_ring").toString());
×
1470
                        newP->setRings(r);
×
1471
                }
1472

1473
                systemPlanets.push_back(newP);
×
1474
                readOk++;
×
1475
        }
×
1476

1477
        // special case: load earth shadow texture
1478
        if (!Planet::texEarthShadow)
×
1479
                Planet::texEarthShadow = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/earth-shadow.png");
×
1480

1481
        // Also comets just have static textures.
1482
        if (!Comet::comaTexture)
×
1483
                Comet::comaTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometComa.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
×
1484
        //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.
1485
        if (!Comet::tailTexture)
×
1486
                Comet::tailTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometTail.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
×
1487

1488
        if (readOk==0)
×
1489
                qWarning().noquote() << "No Solar System objects loaded from" << QDir::toNativeSeparators(filePath);
×
1490
        else
1491
                qInfo().noquote() << "Loaded" << readOk << "Solar System bodies from " << filePath;
×
1492
        qInfo().noquote() << "Solar System now has" << systemPlanets.count() << "entries.";
×
1493
        return readOk>0;
×
1494
}
×
1495

1496
// Compute the position for every elements of the solar system.
1497
// The order is not important since the position is computed relatively to the mother body
1498
void SolarSystem::computePositions(StelCore *core, double dateJDE, PlanetP observerPlanet)
×
1499
{
1500
        const StelObserver *obs=core->getCurrentObserver();
×
1501
        const bool withAberration=core->getUseAberration();
×
1502
        // We distribute computing over a few threads from the current threadpool, but also compute one block in the main thread so that this does not starve.
1503
        // Given the comparably low impact of planetary positions on the overall frame time, we usually don't need more than about 4 extra threads. (Profiled with 12.000 objects.)
1504
        static bool threadMessage=true;
1505
        if (threadMessage)
×
1506
        {
1507
                qInfo() << "SolarSystem: We have configured" << extraThreads << "threads (plus main thread) for computePositions().";
×
1508
                if (extraThreads > QThreadPool::globalInstance()->maxThreadCount()-1)
×
1509
                {
1510
                        qWarning() << "This is more than the maximum additional thread count (" << QThreadPool::globalInstance()->maxThreadCount()-1 << ").";
×
1511
                        qWarning() << "Consider reducing this number to avoid oversubscription.";
×
1512
                }
1513
                threadMessage=false;
×
1514
        }
1515

1516
        if (flagLightTravelTime) // switching off light time correction implies no aberration for the planets.
×
1517
        {
1518
                const StelObserver *obs=core->getCurrentObserver();
×
1519
                const bool observerPlanetIsEarth = observerPlanet==getEarth();
×
1520
                //static StelObjectMgr* omgr=GETSTELMODULE(StelObjectMgr);
1521
                //omgr->removeExtraInfoStrings(StelObject::DebugAid);
1522

1523
                switch (computePositionsAlgorithm)
×
1524
                {
1525
                case 3: // Ruslan's 1-loop solution. This would be faster, but has problems with moons when the respective planet has not been computed yet.
×
1526
                {
1527
                        // Position of this planet will be used in the subsequent computations
1528
                        observerPlanet->computePosition(obs, dateJDE, Vec3d(0.));
×
1529
                        const bool observerIsEarth = observerPlanet->englishName==L1S("Earth");
×
1530
                        const Vec3d obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1531
                        const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1532
                        const double dateJD = dateJDE - (core->computeDeltaT(dateJDE))/86400.0;
×
1533

1534
                        const auto processPlanet = [this,dateJD,dateJDE,observerIsEarth,withAberration,observerPlanet,
×
1535
                                                   obsPosJDE,aberrationPushSpeed,obs](const PlanetP& p, const Vec3d& observerPosFinal)
1536
                        {
1537
                                // 1. First approximation.
1538
                                p->computePosition(obs, dateJDE, Vec3d(0.));
×
1539

1540
                                // For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1541
                                // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1542
                                // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1543
                                // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1544
                                // used ephemerides already provide aberration-corrected positions for the Moon?
1545
                                Vec3d planetPos = p->getHeliocentricEclipticPos();
×
1546
                                double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1547
                                const bool needToApplyAberration = withAberration && (!observerIsEarth || p != getMoon());
×
1548
                                Vec3d aberrationPush(0.);
×
1549
                                if(needToApplyAberration)
×
1550
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1551
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1552

1553
                                // Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1554
                                planetPos = p->getHeliocentricEclipticPos();
×
1555
                                lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1556
                                if(needToApplyAberration)
×
1557
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1558
                                // The next call may already do nothing if the time difference to the previous round is not large enough.
1559
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1560

1561
                                const auto update = &RotationElements::updatePlanetCorrections;
×
1562
                                if      (p->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1563
                                else if (p->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1564
                                else if (p->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1565
                                else if (p->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1566
                                else if (p->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1567
                                else if (p->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1568

1569
                                if(p != observerPlanet)
×
1570
                                {
1571
                                        const double light_speed_correction = (AU / (SPEED_OF_LIGHT * 86400)) *
1572
                                                                              (p->getHeliocentricEclipticPos()-obsPosJDE).norm();
×
1573
                                        p->computeTransMatrix(dateJD-light_speed_correction, dateJDE-light_speed_correction);
×
1574
                                }
1575
                        };
×
1576

1577
                        // This will be used for computation of transformation matrices
1578
                        processPlanet(observerPlanet, Vec3d(0.));
×
1579
                        observerPlanet->computeTransMatrix(dateJD, dateJDE);
×
1580
                        const Vec3d observerPosFinal = observerPlanet->getHeliocentricEclipticPos();
×
1581

1582
                        // Threadable loop function for self-set number of additional worker threads
1583
                        const auto loop = [&planets=std::as_const(systemPlanets),processPlanet,
×
1584
                                          observerPosFinal](const int indexMin, const int indexMax)
1585
                        {
1586
                                for(int i = indexMin; i <= indexMax; ++i)
×
1587
                                        processPlanet(planets[i], observerPosFinal);
×
1588
                        };
×
1589

1590
                        QList<QFuture<void>> futures;
×
1591
                        const int totalThreads = extraThreads+1;
×
1592
                        const auto blockSize = systemPlanets.size() / totalThreads;
×
1593
                        for(int threadN=0; threadN<totalThreads-1; ++threadN)
×
1594
                        {
1595
                                const int indexMin = blockSize*threadN;
×
1596
                                const int indexMax = blockSize*(threadN+1)-1;
×
1597
                                futures.append(QtConcurrent::run(loop, indexMin,indexMax));
×
1598
                        }
1599
                        // and the last thread is the current one
1600
                        loop(blockSize*(totalThreads-1), systemPlanets.size()-1);
×
1601
                        for(auto& f : futures)
×
1602

1603
                                f.waitForFinished();
×
1604
                }
×
1605
                break;
×
1606
                case 2:
×
1607
                {
1608
                        // Better 3-loop solution. This is still following the original solution:
1609
                        // First, compute approximate positions at JDE.
1610
                        // Then for each object, compute light time and repeat light-time corrected.
1611
                        // Third, check new light time, and recompute once more if needed.
1612

1613
                        // 1. First approximation.
1614
                        QList<QFuture<void>> futures;
×
1615
                        // This defines a function to be thrown onto a pool thread that computes every 'incr'th element.
1616
                        auto plCompLoopZero = [=](int offset){
×
1617
                                for (auto it=systemPlanets.cbegin()+offset, end=systemPlanets.cend(); it<end; it+=(extraThreads+1))
×
1618
                                {
1619
                                        it->data()->computePosition(obs, dateJDE, Vec3d(0.));
×
1620
                                }
1621
                        };
×
1622

1623
                        // Move to external threads, but also run a part in the main thread. The index 'availableThreads' is just the last group of objects.
1624
                        for (int stride=0; stride<extraThreads; stride++)
×
1625
                        {
1626
                                auto future=QtConcurrent::run(plCompLoopZero, stride);
×
1627
                                futures.append(future);
×
1628
                        }
×
1629
                        plCompLoopZero(extraThreads);
×
1630

1631
                        // Now the list is being computed by other threads. we can just wait sequentially for completion.
1632
                        for(auto f: futures)
×
1633
                                f.waitForFinished();
×
1634
                        futures.clear();
×
1635

1636
                        const Vec3d &obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1637

1638
                        // 2.&3.: For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1639
                        // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1640
                        // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1641
                        // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1642
                        // used ephemerides already provide aberration-corrected positions for the Moon?
1643
                        const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1644

1645
                        auto plCompLoopOne = [=](int offset){
×
1646
                                for (auto it=systemPlanets.cbegin()+offset, end=systemPlanets.cend(); it<end; it+=extraThreads+1)
×
1647
                                {
1648
                                        const auto planetPos = it->data()->getHeliocentricEclipticPos();
×
1649
                                        const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1650
                                        Vec3d aberrationPush(0.);
×
1651
                                        if (withAberration && (!observerPlanetIsEarth || it->data() != getMoon()))
×
1652
                                                aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1653
                                        it->data()->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1654
                                }
1655
                        };
×
1656
                        for (int stride=0; stride<extraThreads; stride++)
×
1657
                        {
1658
                                auto future=QtConcurrent::run(plCompLoopOne, stride);
×
1659
                                futures.append(future);
×
1660
                        }
×
1661
                        plCompLoopOne(extraThreads); // main thread's share of the computation task
×
1662
                        // Now the list is being computed by other threads. we can just wait sequentially for completion.
1663
                        for(auto f: futures)
×
1664
                                f.waitForFinished();
×
1665
                        futures.clear();
×
1666

1667
                        // 3. Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1668
                        auto plCompLoopTwo = [=](int offset){
×
1669
                                for (auto it=systemPlanets.cbegin()+offset, end=systemPlanets.cend(); it<end; it+=extraThreads+1)
×
1670
                                {
1671
                                        const auto planetPos = it->data()->getHeliocentricEclipticPos();
×
1672
                                        const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1673
                                        Vec3d aberrationPush(0.);
×
1674
                                        if (withAberration && (!observerPlanetIsEarth || it->data() != getMoon()))
×
1675
                                                aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1676
                                        // The next call may already do nothing if the time difference to the previous round is not large enough.
1677
                                        it->data()->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1678
                                        //it->data()->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1679
                                        //                                                        .arg(QString::number(lightTimeDays, 'f', 3))
1680
                                        //                                                        .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1681
                                        //                                                        .arg(QString::number(aberrationPushSpeed[1], 'f', 3))
1682
                                        //                                                        .arg(QString::number(aberrationPushSpeed[2], 'f', 3)));
1683

1684
                                        const auto update = &RotationElements::updatePlanetCorrections;
×
1685
                                        if      (it->data()->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1686
                                        else if (it->data()->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1687
                                        else if (it->data()->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1688
                                        else if (it->data()->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1689
                                        else if (it->data()->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1690
                                        else if (it->data()->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1691
                                }
1692
                        };
×
1693
                        for (int stride=0; stride<extraThreads; stride++)
×
1694
                        {
1695
                                auto future=QtConcurrent::run(plCompLoopTwo, stride);
×
1696
                                futures.append(future);
×
1697
                        }
×
1698
                        // At this point all available threads from the global ThreadPool should be active:
1699
                        //omgr->addToExtraInfoString(StelObject::DebugAid, QString("Threads: Ideal: %1, Pool max %2/active %3, SolarSystem using %4<br/>").
1700
                        //                           arg(QString::number(QThread::idealThreadCount()),
1701
                        //                               QString::number(QThreadPool::globalInstance()->maxThreadCount()),
1702
                        //                               QString::number(QThreadPool::globalInstance()->activeThreadCount()),
1703
                        //                               QString::number(extraThreads)));
1704
                        // and we still run the last stride in the main thread.
1705
                        plCompLoopTwo(extraThreads);
×
1706
                        // Now the list is being computed by other threads. we can just wait sequentially for completion.
1707
                        for(auto f: futures)
×
1708
                                f.waitForFinished();
×
1709
                        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1710
                }
×
1711
                break;
×
1712
                case 1: // Simple multithreading with QtConcurrent::blockingMap(). 3-loop solution. This is closely following the original solution:
×
1713
                {
1714
                        // First, compute approximate positions at JDE.
1715
                        // Then for each object, compute light time and repeat light-time corrected.
1716
                        // Third, check new light time, and recompute if needed.
1717

1718
                        // 1. First approximation.
1719
                        auto plCompPosJDEZero = [=](QSharedPointer<Planet> &pl){pl->computePosition(obs, dateJDE, Vec3d(0.));};
×
1720
                        QtConcurrent::blockingMap(systemPlanets, plCompPosJDEZero);
×
1721

1722
                        const Vec3d &obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1723

1724
                        // 2&3. For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1725
                        // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1726
                        // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1727
                        // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1728
                        // used ephemerides already provide aberration-corrected positions for the Moon?
1729
                        const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1730

1731
                        auto plCompPosJDEOne = [=](QSharedPointer<Planet> &p){
×
1732
                                const Vec3d planetPos = p->getHeliocentricEclipticPos();
×
1733
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1734
                                Vec3d aberrationPush(0.);
×
1735
                                if (withAberration && (!observerPlanetIsEarth || p != getMoon() ))
×
1736
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1737
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1738
                        };
×
1739
                        QtConcurrent::blockingMap(systemPlanets, plCompPosJDEOne);
×
1740

1741
                        // 3. Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1742
                        auto plCompPosJDETwo = [=](QSharedPointer<Planet> &p){
×
1743
                                const Vec3d planetPos = p->getHeliocentricEclipticPos();
×
1744
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1745
                                Vec3d aberrationPush(0.);
×
1746
                                if (withAberration && (!observerPlanetIsEarth || p != getMoon() ))
×
1747
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1748
                                // The next call may already do nothing if the time difference to the previous round is not large enough.
1749
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1750
                                //p->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1751
                                //                                              .arg(QString::number(lightTimeDays, 'f', 3))
1752
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1753
                                //                                              .arg(QString::number(aberrationPushSpeed[1], 'f', 3))
1754
                                //                                              .arg(QString::number(aberrationPushSpeed[2], 'f', 3)));
1755

1756
                                const auto update = &RotationElements::updatePlanetCorrections;
×
1757
                                if      (p->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1758
                                else if (p->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1759
                                else if (p->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1760
                                else if (p->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1761
                                else if (p->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1762
                                else if (p->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1763
                        };
×
1764
                        QtConcurrent::blockingMap(systemPlanets, plCompPosJDETwo);
×
1765
                        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1766
                }
1767
                break;
×
1768
                case 0:
×
1769
                default: // Original single-threaded.
1770
                {
1771
                        // First, compute approximate positions at JDE.
1772
                        // Then for each object, compute light time and repeat light-time corrected.
1773
                        // Third, check new light time, and recompute if needed.
1774

1775
                        for (const auto& p : std::as_const(systemPlanets))
×
1776
                        {
1777
                                p->computePosition(obs, dateJDE, Vec3d(0.));
×
1778
                        }
1779
                        const Vec3d obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1780

1781
                        // For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1782
                        // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1783
                        // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1784
                        // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1785
                        // used ephemerides already provide aberration-corrected positions for the Moon?
1786
                        const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1787
                        for (const auto& p : std::as_const(systemPlanets))
×
1788
                        {
1789
                                //p->setExtraInfoString(StelObject::DebugAid, "");
1790
                                const auto planetPos = p->getHeliocentricEclipticPos();
×
1791
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1792
                                Vec3d aberrationPush(0.);
×
1793
                                if (withAberration && (observerPlanet->englishName!=L1S("Earth") || p->englishName!=L1S("Moon")))
×
1794
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1795
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1796
                        }
1797
                        // Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1798
                        for (const auto& p : std::as_const(systemPlanets))
×
1799
                        {
1800
                                //p->setExtraInfoString(StelObject::DebugAid, "");
1801
                                const auto planetPos = p->getHeliocentricEclipticPos();
×
1802
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1803
                                Vec3d aberrationPush(0.);
×
1804
                                if (withAberration && (observerPlanet->englishName!=L1S("Earth") || p->englishName!=L1S("Moon")))
×
1805
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1806
                                // The next call may already do nothing if the time difference to the previous round is not large enough.
1807
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1808
                                //p->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1809
                                //                                              .arg(QString::number(lightTimeDays, 'f', 3))
1810
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1811
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1812
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3)));
1813

1814
                                const auto update = &RotationElements::updatePlanetCorrections;
×
1815
                                if      (p->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1816
                                else if (p->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1817
                                else if (p->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1818
                                else if (p->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1819
                                else if (p->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1820
                                else if (p->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1821
                        }
1822
                        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1823
                } // end of default (original single-threaded) solution
1824
                }
1825
        }
1826
        else
1827
        {
1828
                for (const auto& p : std::as_const(systemPlanets))
×
1829
                {
1830
                        //p->setExtraInfoString(StelObject::DebugAid, "");
1831
                        p->computePosition(obs, dateJDE, Vec3d(0.));
×
1832
                        const auto update = &RotationElements::updatePlanetCorrections;
×
1833
                        if      (p->englishName==L1S("Moon"))    update(dateJDE, RotationElements::EarthMoon);
×
1834
                        else if (p->englishName==L1S("Mars"))    update(dateJDE, RotationElements::Mars);
×
1835
                        else if (p->englishName==L1S("Jupiter")) update(dateJDE, RotationElements::Jupiter);
×
1836
                        else if (p->englishName==L1S("Saturn"))  update(dateJDE, RotationElements::Saturn);
×
1837
                        else if (p->englishName==L1S("Uranus"))  update(dateJDE, RotationElements::Uranus);
×
1838
                        else if (p->englishName==L1S("Neptune")) update(dateJDE, RotationElements::Neptune);
×
1839
                }
1840
                computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1841
        }
1842
}
×
1843

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

1850
        if (flagLightTravelTime)
×
1851
        {
1852
                for (const auto& p : std::as_const(systemPlanets))
×
1853
                {
1854
                        const double light_speed_correction = (p->getHeliocentricEclipticPos()-observerPos).norm() * (AU / (SPEED_OF_LIGHT * 86400));
×
1855
                        p->computeTransMatrix(dateJD-light_speed_correction, dateJDE-light_speed_correction);
×
1856
                }
1857
        }
1858
        else
1859
        {
1860
                for (const auto& p : std::as_const(systemPlanets))
×
1861
                {
1862
                        p->computeTransMatrix(dateJD, dateJDE);
×
1863
                }
1864
        }
1865
}
×
1866

1867
// And sort them from the furthest to the closest to the observer
1868
// NOTE: std::binary_function is deprecated in C++11 and removed in C++17
1869
struct biggerDistance : public StelUtils::binary_function<PlanetP, PlanetP, bool>
1870
{
1871
        bool operator()(PlanetP p1, PlanetP p2)
×
1872
        {
1873
                return p1->getDistance() > p2->getDistance();
×
1874
        }
1875
};
1876

1877
// Draw all the elements of the solar system
1878
// We are supposed to be in heliocentric coordinate
1879
void SolarSystem::draw(StelCore* core)
×
1880
{
1881
        // AstroCalcDialog
1882
        drawEphemerisItems(core);
×
1883

1884
        if (!flagShow)
×
1885
                return;
×
1886
        static StelObjectMgr *sObjMgr=GETSTELMODULE(StelObjectMgr);
×
1887

1888
        // Compute each Planet distance to the observer
1889
        const Vec3d obsHelioPos = core->getObserverHeliocentricEclipticPos();
×
1890

1891
        for (const auto& p : std::as_const(systemPlanets))
×
1892
        {
1893
                p->computeDistance(obsHelioPos);
×
1894
        }
1895

1896
        // And sort them from the farthest to the closest. std::sort can split this into parallel threads!
1897
        std::sort(STD_EXECUTION_PAR_COMMA
×
1898
                  systemPlanets.begin(),systemPlanets.end(),biggerDistance());
1899

1900
        if (trailFader.getInterstate()>0.0000001f)
×
1901
        {
1902
                StelPainter sPainter(core->getProjection2d());
×
1903
                const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
×
1904
                allTrails->setOpacity(trailFader.getInterstate());
×
1905
                if (trailsThickness>1 || ppx>1.f)
×
1906
                        sPainter.setLineWidth(trailsThickness*ppx);
×
1907
                allTrails->draw(core, &sPainter);
×
1908
                if (trailsThickness>1 || ppx>1.f)
×
1909
                        sPainter.setLineWidth(1);
×
1910
        }
×
1911

1912
        // Make some voodoo to determine when labels should be displayed
1913
        const float sdLimitMag=static_cast<float>(core->getSkyDrawer()->getLimitMagnitude());
×
1914
        const float maxMagLabel = (sdLimitMag<5.f ? sdLimitMag :
×
1915
                        5.f+(sdLimitMag-5.f)*1.2f) +(static_cast<float>(labelsAmount)-3.f)*1.2f;
×
1916
        const double eclipseFactor=getSolarEclipseFactor(core).first;
×
1917

1918
        // Draw the elements
1919
        for (const auto& p : std::as_const(systemPlanets))
×
1920
        {
1921
                if ( (p != sun) || (/* (p == sun) && */ !(core->getSkyDrawer()->getFlagDrawSunAfterAtmosphere())))
×
1922
                        p->draw(core, maxMagLabel, planetNameFont, eclipseFactor);
×
1923
        }
1924
        if (nbMarkers>0)
×
1925
        {
1926
                StelPainter sPainter(core->getProjection2d());
×
1927
                postDrawAsteroidMarkers(&sPainter);
×
1928
        }
×
1929

1930
        if (sObjMgr->getFlagSelectedObjectPointer() && getFlagPointer())
×
1931
                drawPointer(core);
×
1932
}
1933

1934
// Finalize the drawing of asteroid markers (inspired from StelSkyDrawer)
1935
void SolarSystem::postDrawAsteroidMarkers(StelPainter *sPainter)
×
1936
{
1937
        Q_ASSERT(sPainter);
×
1938

1939
        if (nbMarkers==0)
×
1940
                return;
×
1941

1942
        markerCircleTex->bind();
×
1943
        sPainter->setBlending(true, GL_ONE, GL_ONE);
×
1944

1945
        const QMatrix4x4 qMat=sPainter->getProjector()->getProjectionMatrix().toQMatrix();
×
1946

1947
        vbo->bind();
×
1948
        vbo->write(0, markerArray, nbMarkers*6*sizeof(MarkerVertex));
×
1949
        vbo->write(maxMarkers*6*sizeof(MarkerVertex), textureCoordArray, nbMarkers*6*2);
×
1950
        vbo->release();
×
1951

1952
        markerShaderProgram->bind();
×
1953
        markerShaderProgram->setUniformValue(markerShaderVars.projectionMatrix, qMat);
×
1954

1955
        bindVAO();
×
1956
        glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(nbMarkers)*6);
×
1957
        releaseVAO();
×
1958

1959
        markerShaderProgram->release();
×
1960

1961
        nbMarkers = 0;
×
1962
}
1963

1964
// Draw a point source halo.
1965
bool SolarSystem::drawAsteroidMarker(StelCore* core, StelPainter* sPainter, const float x, const float y, Vec3f &color)
×
1966
{
1967
        const float reducer=markerFader.getInterstate();
×
1968
        if (reducer==0.)
×
1969
                return false;
×
1970

1971
        Q_ASSERT(sPainter);
×
1972
        const float radius = 3.f * static_cast<float>(sPainter->getProjector()->getDevicePixelsPerPixel());
×
1973
        unsigned char markerColor[3] = {
1974
                static_cast<unsigned char>(std::min(static_cast<int>(color[0]*reducer*255+0.5f), 255)),
×
1975
                static_cast<unsigned char>(std::min(static_cast<int>(color[1]*reducer*255+0.5f), 255)),
×
1976
                static_cast<unsigned char>(std::min(static_cast<int>(color[2]*reducer*255+0.5f), 255))};
×
1977
        // Store the drawing instructions in the vertex arrays
1978
        MarkerVertex* vx = &(markerArray[nbMarkers*6]);
×
1979
        vx->pos.set(x-radius,y-radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
1980
        vx->pos.set(x+radius,y-radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
1981
        vx->pos.set(x+radius,y+radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
1982
        vx->pos.set(x-radius,y-radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
1983
        vx->pos.set(x+radius,y+radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
1984
        vx->pos.set(x-radius,y+radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
1985

1986
        ++nbMarkers;
×
1987
        if (nbMarkers>=maxMarkers)
×
1988
        {
1989
                // Flush the buffer (draw all buffered markers)
1990
                postDrawAsteroidMarkers(sPainter);
×
1991
        }
1992
        return true;
×
1993
}
1994

1995
void SolarSystem::drawEphemerisItems(const StelCore* core)
×
1996
{
1997
        if (flagShow || (!flagShow && getFlagEphemerisAlwaysOn()))
×
1998
        {
1999
                if (getFlagEphemerisMarkers())
×
2000
                        drawEphemerisMarkers(core);
×
2001
                if (getFlagEphemerisLine())
×
2002
                        drawEphemerisLine(core);
×
2003
        }
2004
}
×
2005

2006
Vec3f SolarSystem::getEphemerisMarkerColor(int index) const
×
2007
{
2008
        // Sync index with AstroCalcDialog::generateEphemeris(). If required, switch to using a QMap.
2009
        const QVector<Vec3f> colors={
2010
                ephemerisGenericMarkerColor,
2011
                ephemerisSecondaryMarkerColor,
2012
                ephemerisMercuryMarkerColor,
2013
                ephemerisVenusMarkerColor,
2014
                ephemerisMarsMarkerColor,
2015
                ephemerisJupiterMarkerColor,
2016
                ephemerisSaturnMarkerColor};
×
2017
        return colors.value(index, ephemerisGenericMarkerColor);
×
2018
}
×
2019

2020
void SolarSystem::drawEphemerisMarkers(const StelCore *core)
×
2021
{
2022
        const int fsize = AstroCalcDialog::EphemerisList.count();
×
2023
        if (fsize==0) return;
×
2024

2025
        StelProjectorP prj;
×
2026
        if (getFlagEphemerisHorizontalCoordinates())
×
2027
                prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
2028
        else
2029
                prj = core->getProjection(StelCore::FrameJ2000);
×
2030
        StelPainter sPainter(prj);
×
2031

2032
        float size, shift, baseSize = 4.f;
×
2033
        const bool showDates = getFlagEphemerisDates();
×
2034
        const bool showMagnitudes = getFlagEphemerisMagnitudes();
×
2035
        const bool showSkippedData = getFlagEphemerisSkipData();
×
2036
        const bool skipMarkers = getFlagEphemerisSkipMarkers();
×
2037
        const bool isNowVisible = getFlagEphemerisNow();
×
2038
        const int dataStep = getEphemerisDataStep();
×
2039
        const int sizeCoeff = getEphemerisLineThickness() - 1;
×
2040
        QString info = "";
×
2041
        Vec3d win;
×
2042
        Vec3f markerColor;
×
2043

UNCOV
2044
        if (getFlagEphemerisLine() && getFlagEphemerisScaleMarkers())
×
2045
                baseSize = 3.f; // The line lies through center of marker
×
2046

UNCOV
2047
        if (isNowVisible)
×
2048
        {
UNCOV
2049
                const int limit = getEphemerisDataLimit();
×
2050
                const int nsize = static_cast<int>(fsize/limit);
×
2051
                sPainter.setBlending(true, GL_ONE, GL_ONE);
×
2052
                texEphemerisNowMarker->bind();
×
2053
                Vec3d pos;
×
2054
                Vec3f win;
×
2055
                for (int i =0; i < limit; i++)
×
2056
                {
UNCOV
2057
                        long k = static_cast<long>(i)*nsize;
×
2058
                        sPainter.setColor(getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[k].colorIndex));
×
2059
                        if (getFlagEphemerisHorizontalCoordinates())
×
2060
                                pos = AstroCalcDialog::EphemerisList[k].sso->getAltAzPosAuto(core);
×
2061
                        else
UNCOV
2062
                                pos = AstroCalcDialog::EphemerisList[k].sso->getJ2000EquatorialPos(core);
×
2063
                        if (prj->project(pos, win))
×
2064
                                sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), 6.f, 0.f);
×
2065
                }
2066
        }
2067

UNCOV
2068
        for (int i =0; i < fsize; i++)
×
2069
        {
UNCOV
2070
                bool skipFlag = (((i + 1)%dataStep)!=1 && dataStep!=1);
×
2071

2072
                // Check visibility of pointer
UNCOV
2073
                if (!(sPainter.getProjector()->projectCheck(AstroCalcDialog::EphemerisList[i].coord, win)))
×
2074
                        continue;
×
2075

UNCOV
2076
                QString debugStr; // Used temporarily for development
×
2077
                const bool isComet=AstroCalcDialog::EphemerisList[i].isComet;
×
2078
                if (i == AstroCalcDialog::DisplayedPositionIndex)
×
2079
                {
UNCOV
2080
                        markerColor = getEphemerisSelectedMarkerColor();
×
2081
                        size = 6.f;
×
2082
                }
2083
                else
2084
                {
UNCOV
2085
                        markerColor = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i].colorIndex);
×
2086
                        size = baseSize;
×
2087
                }
UNCOV
2088
                if (isComet) size += 16.f;
×
2089
                size += sizeCoeff;
×
2090
                sPainter.setColor(markerColor);
×
2091
                sPainter.setBlending(true, GL_ONE, GL_ONE);
×
2092
                if (isComet)
×
2093
                        texEphemerisCometMarker->bind();
×
2094
                else
UNCOV
2095
                        texEphemerisMarker->bind();
×
2096

UNCOV
2097
                if (skipMarkers && skipFlag)
×
2098
                        continue;
×
2099

UNCOV
2100
                Vec3f win;
×
2101
                if (prj->project(AstroCalcDialog::EphemerisList[i].coord, win))
×
2102
                {
2103
                        float solarAngle=0.f; // Angle to possibly rotate the texture. Degrees.
×
UNCOV
2104
                        if (isComet)
×
2105
                        {
2106
                                // compute solarAngle in screen space.
UNCOV
2107
                                Vec3f sunWin;
×
2108
                                prj->project(AstroCalcDialog::EphemerisList[i].sunCoord, sunWin);
×
2109
                                // TODO: In some projections, we may need to test result and flip/mirror the angle, or deal with wrap-around effects.
2110
                                // E.g., in cylindrical mode, the comet icon will flip as soon as the corresponding sun position wraps around the screen edge.
UNCOV
2111
                                solarAngle=M_180_PIf*(atan2(-(win[1]-sunWin[1]), win[0]-sunWin[0]));
×
2112
                                // This will show projected positions and angles usable in labels.
UNCOV
2113
                                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));
×
2114
                        }
2115
                        //sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 180.f+AstroCalcDialog::EphemerisList[i].solarAngle*M_180_PIf);
UNCOV
2116
                        sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 270.f-solarAngle);
×
2117
                }
2118

UNCOV
2119
                if (showDates || showMagnitudes)
×
2120
                {
UNCOV
2121
                        if (showSkippedData && skipFlag)
×
2122
                                continue;
×
2123

UNCOV
2124
                        shift = 3.f + size/1.6f;
×
2125
                        if (showDates && showMagnitudes)
×
2126
                                info = QString("%1 (%2)").arg(AstroCalcDialog::EphemerisList[i].objDateStr, QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2));
×
2127
                        if (showDates && !showMagnitudes)
×
2128
                                info = AstroCalcDialog::EphemerisList[i].objDateStr;
×
2129
                        if (!showDates && showMagnitudes)
×
2130
                                info = QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2);
×
2131

2132
                        // Activate for debug labels.
2133
                        //info=debugStr;
UNCOV
2134
                        sPainter.drawText(AstroCalcDialog::EphemerisList[i].coord, info, 0, shift, shift, false);
×
2135
                }
UNCOV
2136
        }
×
2137
}
×
2138

UNCOV
2139
void SolarSystem::drawEphemerisLine(const StelCore *core)
×
2140
{
UNCOV
2141
        const int size = AstroCalcDialog::EphemerisList.count();
×
2142
        if (size==0) return;
×
2143

2144
        // The array of data is not empty - good news!
UNCOV
2145
        StelProjectorP prj;
×
2146
        if (getFlagEphemerisHorizontalCoordinates())
×
2147
                prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
2148
        else
UNCOV
2149
                prj = core->getProjection(StelCore::FrameJ2000);
×
2150
        StelPainter sPainter(prj);
×
2151
        const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
×
2152

UNCOV
2153
        const float oldLineThickness=sPainter.getLineWidth();
×
2154
        const float lineThickness = getEphemerisLineThickness()*ppx;
×
2155
        if (!fuzzyEquals(lineThickness, oldLineThickness))
×
2156
                sPainter.setLineWidth(lineThickness);
×
2157

UNCOV
2158
        Vec3f color;
×
2159
        QVector<Vec3d> vertexArray;
×
2160
        QVector<Vec4f> colorArray;
×
2161
        const int limit = getEphemerisDataLimit();
×
2162
        const int nsize = static_cast<int>(size/limit);
×
2163
        vertexArray.resize(nsize);
×
2164
        colorArray.resize(nsize);
×
2165
        for (int j=0; j<limit; j++)
×
2166
        {
UNCOV
2167
                for (int i =0; i < nsize; i++)
×
2168
                {
UNCOV
2169
                        color = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i + j*nsize].colorIndex);
×
2170
                        colorArray[i]=Vec4f(color, 1.0f);
×
2171
                        vertexArray[i]=AstroCalcDialog::EphemerisList[i + j*nsize].coord;
×
2172
                }
UNCOV
2173
                sPainter.drawPath(vertexArray, colorArray);
×
2174
        }
2175

UNCOV
2176
        if (!fuzzyEquals(lineThickness, oldLineThickness))
×
2177
                sPainter.setLineWidth(oldLineThickness); // restore line thickness
×
2178
}
×
2179

UNCOV
2180
void SolarSystem::fillEphemerisDates()
×
2181
{
UNCOV
2182
        const int fsize = AstroCalcDialog::EphemerisList.count();
×
2183
        if (fsize==0) return;
×
2184

UNCOV
2185
        static StelLocaleMgr* localeMgr = &StelApp::getInstance().getLocaleMgr();
×
2186
        static StelCore *core = StelApp::getInstance().getCore();
×
2187
        const bool showSmartDates = getFlagEphemerisSmartDates();
×
2188
        double JD = AstroCalcDialog::EphemerisList.first().objDate;
×
2189
        bool withTime = (fsize>1 && (AstroCalcDialog::EphemerisList[1].objDate-JD<1.0));
×
2190

2191
        int fYear, fMonth, fDay, sYear, sMonth, sDay, h, m, s;
UNCOV
2192
        QString info;
×
2193
        const double shift = core->getUTCOffset(JD)*StelCore::JD_HOUR;
×
2194
        StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
×
2195
        bool sFlag = true;
×
2196
        sYear = fYear;
×
2197
        sMonth = fMonth;
×
2198
        sDay = fDay;
×
2199
        const bool showSkippedData = getFlagEphemerisSkipData();
×
2200
        const int dataStep = getEphemerisDataStep();
×
2201

UNCOV
2202
        for (int i = 0; i < fsize; i++)
×
2203
        {
UNCOV
2204
                const double JD = AstroCalcDialog::EphemerisList[i].objDate;
×
2205
                StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
×
2206

UNCOV
2207
                if (showSkippedData && ((i + 1)%dataStep)!=1 && dataStep!=1)
×
2208
                        continue;
×
2209

UNCOV
2210
                if (showSmartDates)
×
2211
                {
UNCOV
2212
                        if (sFlag)
×
2213
                                info = QString("%1").arg(fYear);
×
2214

UNCOV
2215
                        if (info.isEmpty() && !sFlag && fYear!=sYear)
×
2216
                                info = QString("%1").arg(fYear);
×
2217

UNCOV
2218
                        if (!info.isEmpty())
×
2219
                                info.append(QString("/%1").arg(localeMgr->romanMonthName(fMonth)));
×
2220
                        else if (fMonth!=sMonth)
×
2221
                                info = QString("%1").arg(localeMgr->romanMonthName(fMonth));
×
2222

UNCOV
2223
                        if (!info.isEmpty())
×
2224
                                info.append(QString("/%1").arg(fDay));
×
2225
                        else
UNCOV
2226
                                info = QString("%1").arg(fDay);
×
2227

UNCOV
2228
                        if (withTime) // very short step
×
2229
                        {
UNCOV
2230
                                if (fDay==sDay && !sFlag)
×
2231
                                        info.clear();
×
2232

UNCOV
2233
                                StelUtils::getTimeFromJulianDay(JD+shift, &h, &m, &s);
×
2234
                                QString hours = QString::number(h).rightJustified(2, '0');
×
2235
                                QString minutes = QString::number(m).rightJustified(2, '0');
×
2236
                                if (!info.isEmpty())
×
2237
                                        info.append(QString(" %1:%2").arg(hours, minutes));
×
2238
                                else
UNCOV
2239
                                        info = QString("%1:%2").arg(hours, minutes);
×
2240
                        }
×
2241

UNCOV
2242
                        AstroCalcDialog::EphemerisList[i].objDateStr = info;
×
2243
                        info.clear();
×
2244
                        sYear = fYear;
×
2245
                        sMonth = fMonth;
×
2246
                        sDay = fDay;
×
2247
                        sFlag = false;
×
2248
                }
2249
                else
2250
                {
2251
                        // OK, let's use standard formats for date and time (as defined for whole planetarium)
UNCOV
2252
                        const double utcOffsetHrs = core->getUTCOffset(JD);
×
2253
                        if (withTime)
×
2254
                                AstroCalcDialog::EphemerisList[i].objDateStr = QString("%1 %2").arg(localeMgr->getPrintableDateLocal(JD, utcOffsetHrs), localeMgr->getPrintableTimeLocal(JD, utcOffsetHrs));
×
2255
                        else
UNCOV
2256
                                AstroCalcDialog::EphemerisList[i].objDateStr = localeMgr->getPrintableDateLocal(JD, utcOffsetHrs);
×
2257
                }
2258
        }
UNCOV
2259
}
×
2260

UNCOV
2261
PlanetP SolarSystem::searchByEnglishName(const QString &planetEnglishName) const
×
2262
{
UNCOV
2263
        const QString planetEnglishNameUpper=planetEnglishName.toUpper();
×
2264
        for (const auto& p : systemPlanets)
×
2265
        {
2266
                if (p->getEnglishName().toUpper() == planetEnglishNameUpper)
×
2267
                        return p;
×
2268

2269
                // IAU designation?
2270
                QString iau = p->getIAUDesignation();
×
2271
                if (!iau.isEmpty() && iau.toUpper()==planetEnglishNameUpper)
×
2272
                        return p;
×
2273
        }
×
2274
        for (const auto& p : systemMinorBodies)
×
2275
        {
2276
                QStringList c;
×
2277
                // other comet designations?
2278
                if (p->getPlanetType()==Planet::isComet)
×
2279
                {
2280
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2281
                        c = mp->getExtraDesignations();
×
2282
                } else {
×
2283
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2284
                        c = mp->getExtraDesignations();
×
2285
                }
×
2286
                for (const auto& d : std::as_const(c))
×
2287
                {
2288
                        if (d.toUpper()==planetEnglishNameUpper)
×
2289
                                return p;
×
2290
                }
2291
        }
×
2292
        return PlanetP();
×
UNCOV
2293
}
×
2294

2295
PlanetP SolarSystem::searchMinorPlanetByEnglishName(const QString &planetEnglishName) const
×
2296
{
2297
        const QString planetEnglishNameUpper=planetEnglishName.toUpper();
×
UNCOV
2298
        for (const auto& p : systemMinorBodies)
×
2299
        {
2300
                if (p->getEnglishName().toUpper() == planetEnglishNameUpper)
×
UNCOV
2301
                        return p;
×
2302

2303
                // IAU designation?
2304
                QString iau = p->getIAUDesignation();
×
2305
                if (!iau.isEmpty() && iau.toUpper()==planetEnglishNameUpper)
×
UNCOV
2306
                        return p;
×
2307

UNCOV
2308
                QStringList c;
×
2309
                // other comet designations?
UNCOV
2310
                if (p->getPlanetType()==Planet::isComet)
×
2311
                {
2312
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2313
                        c = mp->getExtraDesignations();
×
UNCOV
2314
                }
×
2315
                else
2316
                {
2317
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2318
                        c = mp->getExtraDesignations();
×
2319
                }
×
UNCOV
2320
                for (const auto& d : std::as_const(c))
×
2321
                {
2322
                        if (d.toUpper()==planetEnglishNameUpper)
×
UNCOV
2323
                                return p;
×
2324
                }
2325
        }
×
UNCOV
2326
        return PlanetP();
×
UNCOV
2327
}
×
2328

2329

UNCOV
2330
StelObjectP SolarSystem::searchByNameI18n(const QString& planetNameI18n) const
×
2331
{
UNCOV
2332
        const QString planetNameI18Upper=planetNameI18n.toUpper();
×
2333
        for (const auto& p : systemPlanets)
×
2334
        {
2335
                QString nativeNameI18nUpper = p->getNameNativeI18n().toUpper();
×
2336
                if (p->getNameI18n().toUpper() == planetNameI18Upper || (!nativeNameI18nUpper.isEmpty() && nativeNameI18nUpper == planetNameI18Upper))
×
2337
                        return qSharedPointerCast<StelObject>(p);
×
UNCOV
2338
        }
×
UNCOV
2339
        return StelObjectP();
×
UNCOV
2340
}
×
2341

2342

2343
StelObjectP SolarSystem::searchByName(const QString& name) const
×
2344
{
2345
        const QString nameUpper=name.toUpper();
×
2346
        for (const auto& p : systemPlanets)
×
2347
        {
UNCOV
2348
                QString nativeName = p->getNameNative().toUpper();
×
UNCOV
2349
                if (p->getEnglishName().toUpper() == nameUpper || (!nativeName.isEmpty() && nativeName == nameUpper))
×
2350
                        return qSharedPointerCast<StelObject>(p);
×
2351

2352
                // IAU designation?
2353
                QString iau = p->getIAUDesignation();
×
2354
                if (!iau.isEmpty() && iau.toUpper()==nameUpper)
×
UNCOV
2355
                        return qSharedPointerCast<StelObject>(p);
×
2356
        }
×
UNCOV
2357
        for (const auto& p : systemMinorBodies)
×
2358
        {
UNCOV
2359
                QStringList c;
×
2360
                // other comet designations?
2361
                if (p->getPlanetType()==Planet::isComet)
×
2362
                {
UNCOV
2363
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
UNCOV
2364
                        c = mp->getExtraDesignations();
×
2365
                }
×
2366
                else
2367
                {
2368
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
UNCOV
2369
                        c = mp->getExtraDesignations();
×
2370
                }
×
2371
                for (const auto& d : std::as_const(c))
×
2372
                {
2373
                        if (d.toUpper()==nameUpper)
×
UNCOV
2374
                                return qSharedPointerCast<StelObject>(p);
×
2375
                }
UNCOV
2376
        }
×
2377

2378
        return StelObjectP();
×
UNCOV
2379
}
×
2380

2381
float SolarSystem::getPlanetVMagnitude(const QString &planetName, bool withExtinction) const
×
2382
{
2383
        StelCore *core=StelApp::getInstance().getCore();
×
2384
        double eclipseFactor=getSolarEclipseFactor(core).first;
×
2385
        PlanetP p = searchByEnglishName(planetName);
×
2386
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2387
                p = searchMinorPlanetByEnglishName(planetName);
×
2388
        float r = p->getVMagnitude(core, eclipseFactor);
×
2389
        if (withExtinction)
×
UNCOV
2390
                r = p->getVMagnitudeWithExtinction(core, r);
×
2391
        return r;
×
UNCOV
2392
}
×
2393

2394
QString SolarSystem::getPlanetType(const QString &planetName) const
×
2395
{
2396
        PlanetP p = searchByEnglishName(planetName);
×
2397
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2398
                p = searchMinorPlanetByEnglishName(planetName);
×
2399
        if (p.isNull())
×
UNCOV
2400
                return QString("UNDEFINED");
×
2401
        return p->getObjectType();
×
UNCOV
2402
}
×
2403

2404
double SolarSystem::getDistanceToPlanet(const QString &planetName) const
×
2405
{
2406
        PlanetP p = searchByEnglishName(planetName);
×
2407
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
UNCOV
2408
                p = searchMinorPlanetByEnglishName(planetName);
×
2409
        return p->getDistance();
×
UNCOV
2410
}
×
2411

2412
double SolarSystem::getElongationForPlanet(const QString &planetName) const
×
2413
{
2414
        PlanetP p = searchByEnglishName(planetName);
×
2415
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
UNCOV
2416
                p = searchMinorPlanetByEnglishName(planetName);
×
2417
        return p->getElongation(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
UNCOV
2418
}
×
2419

2420
double SolarSystem::getPhaseAngleForPlanet(const QString &planetName) const
×
2421
{
2422
        PlanetP p = searchByEnglishName(planetName);
×
2423
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
UNCOV
2424
                p = searchMinorPlanetByEnglishName(planetName);
×
2425
        return p->getPhaseAngle(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
UNCOV
2426
}
×
2427

2428
float SolarSystem::getPhaseForPlanet(const QString &planetName) const
×
2429
{
2430
        PlanetP p = searchByEnglishName(planetName);
×
2431
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
UNCOV
2432
                p = searchMinorPlanetByEnglishName(planetName);
×
2433
        return p->getPhase(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
UNCOV
2434
}
×
2435

2436
QStringList SolarSystem::getObjectsList(QString objType) const
×
2437
{
2438
        QStringList r;
×
UNCOV
2439
        if (objType.toLower()==L1S("all"))
×
2440
        {
UNCOV
2441
                r = listAllObjects(true);
×
2442
                // Remove the Sun
2443
                r.removeOne("Sun");
×
2444
                // Remove special objects
2445
                r.removeOne("Solar System Observer");
×
2446
                r.removeOne("Earth Observer");
×
2447
                r.removeOne("Mars Observer");
×
2448
                r.removeOne("Jupiter Observer");
×
UNCOV
2449
                r.removeOne("Saturn Observer");
×
UNCOV
2450
                r.removeOne("Uranus Observer");
×
2451
                r.removeOne("Neptune Observer");
×
2452
        }
2453
        else
2454
                r = listAllObjectsByType(objType, true);
×
2455

UNCOV
2456
        return r;
×
2457
}
×
2458

2459
// Search if any Planet is close to position given in earth equatorial position and return the distance
2460
StelObjectP SolarSystem::search(Vec3d pos, const StelCore* core) const
×
2461
{
2462
        pos.normalize();
×
UNCOV
2463
        PlanetP closest;
×
2464
        double cos_angle_closest = 0.;
×
UNCOV
2465
        Vec3d equPos;
×
2466

2467
        for (const auto& p : systemPlanets)
×
2468
        {
2469
                equPos = p->getEquinoxEquatorialPos(core);
×
UNCOV
2470
                equPos.normalize();
×
2471
                double cos_ang_dist = equPos*pos;
×
2472
                if (cos_ang_dist>cos_angle_closest)
×
2473
                {
UNCOV
2474
                        closest = p;
×
UNCOV
2475
                        cos_angle_closest = cos_ang_dist;
×
2476
                }
2477
        }
2478

UNCOV
2479
        if (cos_angle_closest>0.999)
×
2480
        {
2481
                return qSharedPointerCast<StelObject>(closest);
×
2482
        }
UNCOV
2483
        else return StelObjectP();
×
2484
}
×
2485

2486
// Return a QList containing the planets located inside the limFov circle around position vv
2487
QList<StelObjectP> SolarSystem::searchAround(const Vec3d& vv, double limitFov, const StelCore* core) const
×
2488
{
UNCOV
2489
        QList<StelObjectP> result;
×
2490
        if (!getFlagPlanets())
×
UNCOV
2491
                return result;
×
2492

2493
        Vec3d v(vv);
×
2494
        
UNCOV
2495
        double cosLimFov = std::cos(limitFov * M_PI/180.);
×
2496
        Vec3d equPos;
×
2497

UNCOV
2498
        const QString weAreHere = core->getCurrentPlanet()->getEnglishName();
×
2499
        for (const auto& p : systemPlanets)
×
2500
        {
UNCOV
2501
                equPos = p->getJ2000EquatorialPos(core);
×
2502
                equPos.normalize();
×
2503

2504
                double cosAngularSize = std::cos(p->getSpheroidAngularRadius(core) * M_PI/180.);
×
2505

2506
                if (equPos*v>=std::min(cosLimFov, cosAngularSize) && p->getEnglishName()!=weAreHere)
×
2507
                {
UNCOV
2508
                        result.append(qSharedPointerCast<StelObject>(p));
×
2509
                }
2510
        }
UNCOV
2511
        return result;
×
UNCOV
2512
}
×
2513

2514
// Update i18 names from english names according to current sky culture translator
2515
void SolarSystem::updateI18n()
×
2516
{
2517
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
2518
        for (const auto& p : std::as_const(systemPlanets))
×
UNCOV
2519
                p->translateName(trans);
×
2520
}
×
2521

2522
QStringList SolarSystem::listMatchingObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
×
2523
{
2524
        QStringList result;
×
2525
        if (getFlagPlanets())
×
2526
                result = StelObjectModule::listMatchingObjects(objPrefix, maxNbItem, useStartOfWords);
×
UNCOV
2527
        return result;
×
2528
}
×
2529

2530
void SolarSystem::setFlagTrails(bool b)
×
2531
{
2532
        if (getFlagTrails() != b)
×
2533
        {
UNCOV
2534
                trailFader = b;
×
2535
                if (b)
×
2536
                {
UNCOV
2537
                        allTrails->reset(maxTrailPoints);
×
2538
                        recreateTrails();
×
2539
                }
UNCOV
2540
                StelApp::immediateSave("astro/flag_object_trails", b);
×
2541
                emit trailsDisplayedChanged(b);
×
2542
        }
2543
}
×
2544

2545
bool SolarSystem::getFlagTrails() const
×
2546
{
UNCOV
2547
        return static_cast<bool>(trailFader);
×
2548
}
2549

2550
void SolarSystem::setMaxTrailPoints(int max)
×
2551
{
2552
        if (maxTrailPoints != max)
×
2553
        {
2554
                maxTrailPoints = max;
×
2555
                allTrails->reset(max);
×
2556
                recreateTrails();
×
UNCOV
2557
                StelApp::immediateSave("viewing/max_trail_points", max);
×
2558
                emit maxTrailPointsChanged(max);
×
2559
        }
2560
}
×
2561

2562
void SolarSystem::setMaxTrailTimeExtent(int max)
×
2563
{
2564
        if (maxTrailTimeExtent != max && maxTrailTimeExtent > 0)
×
2565
        {
2566
                maxTrailTimeExtent = max;
×
2567
                recreateTrails();
×
UNCOV
2568
                StelApp::immediateSave("viewing/max_trail_time_extent", max);
×
2569
                emit maxTrailTimeExtentChanged(max);
×
2570
        }
2571
}
×
2572

2573
void SolarSystem::setTrailsThickness(int v)
×
2574
{
2575
        if (trailsThickness != v)
×
2576
        {
2577
                trailsThickness = v;
×
UNCOV
2578
                StelApp::immediateSave("astro/object_trails_thickness", v);
×
2579
                emit trailsThicknessChanged(v);
×
2580
        }
2581
}
×
2582

2583
void SolarSystem::setFlagHints(bool b)
×
2584
{
2585
        if (getFlagHints() != b)
×
2586
        {
2587
                for (const auto& p : std::as_const(systemPlanets))
×
2588
                        p->setFlagHints(b);
×
UNCOV
2589
                StelApp::immediateSave("astro/flag_planets_hints", b);
×
2590
                emit flagHintsChanged(b);
×
2591
        }
2592
}
×
2593

2594
bool SolarSystem::getFlagHints(void) const
×
2595
{
2596
        for (const auto& p : std::as_const(systemPlanets))
×
2597
        {
UNCOV
2598
                if (p->getFlagHints())
×
2599
                        return true;
×
2600
        }
UNCOV
2601
        return false;
×
2602
}
2603

2604
void SolarSystem::setFlagLabels(bool b)
×
2605
{
2606
        if (getFlagLabels() != b)
×
2607
        {
2608
                for (const auto& p : std::as_const(systemPlanets))
×
2609
                        p->setFlagLabels(b);
×
UNCOV
2610
                StelApp::immediateSave("astro/flag_planets_labels", b);
×
2611
                emit labelsDisplayedChanged(b);
×
2612
        }
2613
}
×
2614

2615
bool SolarSystem::getFlagLabels() const
×
2616
{
2617
        for (const auto& p : std::as_const(systemPlanets))
×
2618
        {
UNCOV
2619
                if (p->getFlagLabels())
×
2620
                        return true;
×
2621
        }
UNCOV
2622
        return false;
×
2623
}
2624

2625
void SolarSystem::setFlagMarkers(bool b)
×
2626
{
2627
        if (getFlagMarkers() != b)
×
2628
        {
2629
                markerFader = b;
×
UNCOV
2630
                StelApp::immediateSave("astro/flag_planets_markers", b);
×
2631
                emit markersDisplayedChanged(b);
×
2632
        }
2633
}
×
2634

2635
bool SolarSystem::getFlagMarkers() const
×
2636
{
UNCOV
2637
        return markerFader;
×
2638
}
2639

2640
void SolarSystem::setFlagLightTravelTime(bool b)
×
2641
{
2642
        if(b!=flagLightTravelTime)
×
2643
        {
2644
                flagLightTravelTime = b;
×
UNCOV
2645
                StelApp::immediateSave("astro/flag_light_travel_time", b);
×
2646
                emit flagLightTravelTimeChanged(b);
×
2647
        }
2648
}
×
2649

2650
void SolarSystem::setFlagShowObjSelfShadows(bool b)
×
2651
{
2652
        if(b!=flagShowObjSelfShadows)
×
2653
        {
2654
                flagShowObjSelfShadows = b;
×
2655
                if(!b)
×
2656
                        Planet::deinitFBO();
×
UNCOV
2657
                StelApp::immediateSave("astro/flag_show_obj_self_shadows", b);
×
2658
                emit flagShowObjSelfShadowsChanged(b);
×
2659
        }
2660
}
×
2661

2662
void SolarSystem::setSelected(PlanetP obj)
×
2663
{
2664
        if (obj && obj->getType() == L1S("Planet"))
×
2665
        {
UNCOV
2666
                selected = obj;
×
UNCOV
2667
                selectedSSO.push_back(obj);
×
2668
        }
2669
        else
2670
                selected.clear();
×
2671
        // Undraw other objects hints, orbit, trails etc..
2672
        setFlagHints(getFlagHints());
×
UNCOV
2673
        reconfigureOrbits();
×
UNCOV
2674
}
×
2675

2676

2677
void SolarSystem::update(double deltaTime)
×
2678
{
UNCOV
2679
        trailFader.update(static_cast<int>(deltaTime*1000));
×
2680
        if (trailFader.getInterstate()>0.f)
×
2681
        {
UNCOV
2682
                allTrails->update();
×
2683
        }
2684

2685
        for (const auto& p : std::as_const(systemPlanets))
×
2686
        {
2687
                p->update(static_cast<int>(deltaTime*1000));
×
2688
        }
UNCOV
2689
        markerFader.update(deltaTime*1000);
×
UNCOV
2690
}
×
2691

2692
// is a lunar eclipse close at hand?
UNCOV
2693
bool SolarSystem::nearLunarEclipse() const
×
2694
{
2695
        // TODO: could replace with simpler test
2696
        // TODO Source?
2697

2698
        const Vec3d sun = getSun()->getAberrationPush();
×
2699
        const Vec3d e = getEarth()->getEclipticPos();
×
UNCOV
2700
        const Vec3d m = getMoon()->getEclipticPos();  // relative to earth
×
UNCOV
2701
        const Vec3d mh = getMoon()->getHeliocentricEclipticPos();  // relative to sun
×
2702

2703
        // shadow location at earth + moon distance along earth vector from (aberrated) sun
2704
        Vec3d en = e-sun;
×
UNCOV
2705
        en.normalize();
×
UNCOV
2706
        Vec3d shadow = en * (e.norm() + m.norm());
×
2707

2708
        // find shadow radii in AU
UNCOV
2709
        double r_penumbra = shadow.norm()*702378.1/AU/e.norm() - SUN_RADIUS/AU;
×
2710

2711
        // modify shadow location for scaled moon
UNCOV
2712
        Vec3d mdist = shadow - mh;
×
2713
        if(mdist.norm() > r_penumbra + 2000./AU) return false;   // not visible so don't bother drawing
×
2714

UNCOV
2715
        return true;
×
2716
}
2717

2718
QStringList SolarSystem::listAllObjects(bool inEnglish) const
×
2719
{
UNCOV
2720
        QStringList result;
×
2721
        if (inEnglish)
×
2722
        {
2723
                for (const auto& p : systemPlanets)
×
2724
                {
2725
                        result << p->getEnglishName();
×
UNCOV
2726
                        if (!p->getIAUDesignation().isEmpty())
×
UNCOV
2727
                                result << p->getIAUDesignation();
×
2728
                }
2729
        }
2730
        else
2731
        {
2732
                for (const auto& p : systemPlanets)
×
2733
                {
2734
                        result << p->getNameI18n();
×
2735
                        if (!p->getNameNativeI18n().isEmpty())
×
2736
                                result << p->getNameNativeI18n() << p->getNameNative();
×
UNCOV
2737
                        if (!p->getIAUDesignation().isEmpty())
×
UNCOV
2738
                                result << p->getIAUDesignation();
×
2739
                }
2740
        }
2741
        for (const auto& p : systemMinorBodies)
×
2742
        {
2743
                QStringList c;
×
2744
                // other comet designations?
2745
                if (p->getPlanetType()==Planet::isComet)
×
2746
                {
2747
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2748
                        c = mp->getExtraDesignations();
×
2749
                } else {
×
2750
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2751
                        c = mp->getExtraDesignations();
×
2752
                }
×
2753
                if (c.count()>0)
×
2754
                        result << c;
×
2755
        }
×
UNCOV
2756
        return result;
×
2757
}
×
2758

2759
QStringList SolarSystem::listAllObjectsByType(const QString &objType, bool inEnglish) const
×
2760
{
UNCOV
2761
        QStringList result;
×
2762
        if (inEnglish)
×
2763
        {
2764
                for (const auto& p : systemPlanets)
×
2765
                {
2766
                        if (p->getObjectType()==objType)
×
2767
                        {
2768
                                result << p->getEnglishName();
×
UNCOV
2769
                                if (!p->getIAUDesignation().isEmpty())
×
UNCOV
2770
                                        result << p->getIAUDesignation();
×
2771
                        }
2772
                }
2773
        }
2774
        else
2775
        {
2776
                for (const auto& p : systemPlanets)
×
2777
                {
2778
                        if (p->getObjectType()==objType)
×
2779
                        {
2780
                                result << p->getNameI18n();
×
UNCOV
2781
                                if (!p->getIAUDesignation().isEmpty())
×
UNCOV
2782
                                        result << p->getIAUDesignation();
×
2783
                        }
2784
                }
2785
        }
2786
        for (const auto& p : systemMinorBodies)
×
2787
        {
2788
                if (p->getObjectType()==objType)
×
2789
                {
2790
                        QStringList c;
×
2791
                        // other comet designations?
2792
                        if (p->getPlanetType()==Planet::isComet)
×
2793
                        {
2794
                                QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2795
                                c = mp->getExtraDesignations();
×
2796
                        } else {
×
2797
                                QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2798
                                c = mp->getExtraDesignations();
×
2799
                        }
×
2800
                        if (c.count()>0)
×
UNCOV
2801
                                result << c;
×
2802
                }
×
2803
        }
UNCOV
2804
        return result;
×
2805
}
×
2806

2807
void SolarSystem::selectedObjectChange(StelModule::StelModuleSelectAction)
×
2808
{
UNCOV
2809
        const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet");
×
2810
        if (!newSelected.empty())
×
2811
        {
2812
                setSelected(qSharedPointerCast<Planet>(newSelected[0]));
×
UNCOV
2813
                if (getFlagIsolatedTrails())
×
UNCOV
2814
                        recreateTrails();
×
2815
        }
2816
        else
UNCOV
2817
                setSelected("");
×
UNCOV
2818
}
×
2819

2820
// Activate/Deactivate planets display
2821
void SolarSystem::setFlagPlanets(bool b)
×
2822
{
2823
        if (b!=flagShow)
×
2824
        {
2825
                flagShow=b;
×
UNCOV
2826
                StelApp::immediateSave("astro/flag_planets", b);
×
2827
                emit flagPlanetsDisplayedChanged(b);
×
2828
        }
2829
}
×
2830

2831
bool SolarSystem::getFlagPlanets(void) const
×
2832
{
UNCOV
2833
        return flagShow;
×
2834
}
2835

2836
void SolarSystem::setFlagEphemerisMarkers(bool b)
×
2837
{
2838
        if (b!=ephemerisMarkersDisplayed)
×
2839
        {
2840
                ephemerisMarkersDisplayed=b;
×
UNCOV
2841
                conf->setValue("astrocalc/flag_ephemeris_markers", b); // Immediate saving of state
×
2842
                emit ephemerisMarkersChanged(b);
×
2843
        }
2844
}
×
2845

2846
bool SolarSystem::getFlagEphemerisMarkers() const
×
2847
{
UNCOV
2848
        return ephemerisMarkersDisplayed;
×
2849
}
2850

2851
void SolarSystem::setFlagEphemerisLine(bool b)
×
2852
{
2853
        if (b!=ephemerisLineDisplayed)
×
2854
        {
2855
                ephemerisLineDisplayed=b;
×
UNCOV
2856
                conf->setValue("astrocalc/flag_ephemeris_line", b); // Immediate saving of state
×
2857
                emit ephemerisLineChanged(b);
×
2858
        }
2859
}
×
2860

2861
bool SolarSystem::getFlagEphemerisLine() const
×
2862
{
UNCOV
2863
        return ephemerisLineDisplayed;
×
2864
}
2865

2866
bool SolarSystem::getFlagEphemerisAlwaysOn() const
×
2867
{
UNCOV
2868
        return ephemerisAlwaysOn;
×
2869
}
2870

2871
void SolarSystem::setFlagEphemerisAlwaysOn(bool b)
×
2872
{
2873
        if (b != ephemerisAlwaysOn)
×
2874
        {
2875
                ephemerisAlwaysOn = b;
×
UNCOV
2876
                conf->setValue("astrocalc/flag_ephemeris_alwayson", b); // Immediate saving of state
×
2877
                emit ephemerisAlwaysOnChanged(b);
×
2878
        }
2879
}
×
2880

2881
bool SolarSystem::getFlagEphemerisNow() const
×
2882
{
UNCOV
2883
        return ephemerisNow;
×
2884
}
2885

2886
void SolarSystem::setFlagEphemerisNow(bool b)
×
2887
{
2888
        if (b != ephemerisNow)
×
2889
        {
2890
                ephemerisNow = b;
×
UNCOV
2891
                conf->setValue("astrocalc/flag_ephemeris_now", b); // Immediate saving of state
×
2892
                emit ephemerisNowChanged(b);
×
2893
        }
2894
}
×
2895

2896
void SolarSystem::setFlagEphemerisHorizontalCoordinates(bool b)
×
2897
{
2898
        if (b!=ephemerisHorizontalCoordinates)
×
2899
        {
2900
                ephemerisHorizontalCoordinates=b;
×
UNCOV
2901
                conf->setValue("astrocalc/flag_ephemeris_horizontal", b); // Immediate saving of state
×
2902
                emit ephemerisHorizontalCoordinatesChanged(b);
×
2903
        }
2904
}
×
2905

2906
bool SolarSystem::getFlagEphemerisHorizontalCoordinates() const
×
2907
{
UNCOV
2908
        return ephemerisHorizontalCoordinates;
×
2909
}
2910

2911
void SolarSystem::setFlagEphemerisDates(bool b)
×
2912
{
2913
        if (b!=ephemerisDatesDisplayed)
×
2914
        {
2915
                ephemerisDatesDisplayed=b;
×
UNCOV
2916
                conf->setValue("astrocalc/flag_ephemeris_dates", b); // Immediate saving of state
×
2917
                emit ephemerisDatesChanged(b);
×
2918
        }
2919
}
×
2920

2921
bool SolarSystem::getFlagEphemerisDates() const
×
2922
{
UNCOV
2923
        return ephemerisDatesDisplayed;
×
2924
}
2925

2926
void SolarSystem::setFlagEphemerisMagnitudes(bool b)
×
2927
{
2928
        if (b!=ephemerisMagnitudesDisplayed)
×
2929
        {
2930
                ephemerisMagnitudesDisplayed=b;
×
UNCOV
2931
                conf->setValue("astrocalc/flag_ephemeris_magnitudes", b); // Immediate saving of state
×
2932
                emit ephemerisMagnitudesChanged(b);
×
2933
        }
2934
}
×
2935

2936
bool SolarSystem::getFlagEphemerisMagnitudes() const
×
2937
{
UNCOV
2938
        return ephemerisMagnitudesDisplayed;
×
2939
}
2940

2941
void SolarSystem::setFlagEphemerisSkipData(bool b)
×
2942
{
2943
        if (b!=ephemerisSkipDataDisplayed)
×
2944
        {
2945
                ephemerisSkipDataDisplayed=b;
×
UNCOV
2946
                conf->setValue("astrocalc/flag_ephemeris_skip_data", b); // Immediate saving of state
×
2947
                emit ephemerisSkipDataChanged(b);
×
2948
        }
2949
}
×
2950

2951
bool SolarSystem::getFlagEphemerisSkipData() const
×
2952
{
UNCOV
2953
        return ephemerisSkipDataDisplayed;
×
2954
}
2955

2956
void SolarSystem::setFlagEphemerisSkipMarkers(bool b)
×
2957
{
2958
        if (b!=ephemerisSkipMarkersDisplayed)
×
2959
        {
2960
                ephemerisSkipMarkersDisplayed=b;
×
UNCOV
2961
                conf->setValue("astrocalc/flag_ephemeris_skip_markers", b); // Immediate saving of state
×
2962
                emit ephemerisSkipMarkersChanged(b);
×
2963
        }
2964
}
×
2965

2966
bool SolarSystem::getFlagEphemerisSkipMarkers() const
×
2967
{
UNCOV
2968
        return ephemerisSkipMarkersDisplayed;
×
2969
}
2970

2971
void SolarSystem::setFlagEphemerisSmartDates(bool b)
×
2972
{
2973
        if (b!=ephemerisSmartDatesDisplayed)
×
2974
        {
2975
                ephemerisSmartDatesDisplayed=b;
×
UNCOV
2976
                conf->setValue("astrocalc/flag_ephemeris_smart_dates", b); // Immediate saving of state
×
2977
                emit ephemerisSmartDatesChanged(b);
×
2978
        }
2979
}
×
2980

2981
bool SolarSystem::getFlagEphemerisSmartDates() const
×
2982
{
UNCOV
2983
        return ephemerisSmartDatesDisplayed;
×
2984
}
2985

2986
void SolarSystem::setFlagEphemerisScaleMarkers(bool b)
×
2987
{
2988
        if (b!=ephemerisScaleMarkersDisplayed)
×
2989
        {
2990
                ephemerisScaleMarkersDisplayed=b;
×
UNCOV
2991
                conf->setValue("astrocalc/flag_ephemeris_scale_markers", b); // Immediate saving of state
×
2992
                emit ephemerisScaleMarkersChanged(b);
×
2993
        }
2994
}
×
2995

2996
bool SolarSystem::getFlagEphemerisScaleMarkers() const
×
2997
{
UNCOV
2998
        return ephemerisScaleMarkersDisplayed;
×
2999
}
3000

3001
void SolarSystem::setEphemerisDataStep(int step)
×
3002
{
3003
        ephemerisDataStep = step;
×
3004
        // automatic saving of the setting
3005
        conf->setValue("astrocalc/ephemeris_data_step", step);
×
UNCOV
3006
        emit ephemerisDataStepChanged(step);
×
3007
}
×
3008

3009
int SolarSystem::getEphemerisDataStep() const
×
3010
{
UNCOV
3011
        return ephemerisDataStep;
×
3012
}
3013

3014
void SolarSystem::setEphemerisDataLimit(int limit)
×
3015
{
3016
        ephemerisDataLimit = limit;
×
UNCOV
3017
        emit ephemerisDataLimitChanged(limit);
×
3018
}
×
3019

3020
int SolarSystem::getEphemerisDataLimit() const
×
3021
{
UNCOV
3022
        return ephemerisDataLimit;
×
3023
}
3024

3025
void SolarSystem::setEphemerisLineThickness(int v)
×
3026
{
3027
        ephemerisLineThickness = v;
×
3028
        // automatic saving of the setting
3029
        conf->setValue("astrocalc/ephemeris_line_thickness", v);
×
UNCOV
3030
        emit ephemerisLineThicknessChanged(v);
×
3031
}
×
3032

3033
int SolarSystem::getEphemerisLineThickness() const
×
3034
{
UNCOV
3035
        return ephemerisLineThickness;
×
3036
}
3037

3038
void SolarSystem::setEphemerisGenericMarkerColor(const Vec3f& color)
×
3039
{
3040
        if (color!=ephemerisGenericMarkerColor)
×
3041
        {
UNCOV
3042
                ephemerisGenericMarkerColor = color;
×
3043
                emit ephemerisGenericMarkerColorChanged(color);
×
3044
        }
3045
}
×
3046

3047
Vec3f SolarSystem::getEphemerisGenericMarkerColor() const
×
3048
{
UNCOV
3049
        return ephemerisGenericMarkerColor;
×
3050
}
3051

3052
void SolarSystem::setEphemerisSecondaryMarkerColor(const Vec3f& color)
×
3053
{
3054
        if (color!=ephemerisSecondaryMarkerColor)
×
3055
        {
UNCOV
3056
                ephemerisSecondaryMarkerColor = color;
×
3057
                emit ephemerisSecondaryMarkerColorChanged(color);
×
3058
        }
3059
}
×
3060

3061
Vec3f SolarSystem::getEphemerisSecondaryMarkerColor() const
×
3062
{
UNCOV
3063
        return ephemerisSecondaryMarkerColor;
×
3064
}
3065

3066
void SolarSystem::setEphemerisSelectedMarkerColor(const Vec3f& color)
×
3067
{
3068
        if (color!=ephemerisSelectedMarkerColor)
×
3069
        {
UNCOV
3070
                ephemerisSelectedMarkerColor = color;
×
3071
                emit ephemerisSelectedMarkerColorChanged(color);
×
3072
        }
3073
}
×
3074

3075
Vec3f SolarSystem::getEphemerisSelectedMarkerColor() const
×
3076
{
UNCOV
3077
        return ephemerisSelectedMarkerColor;
×
3078
}
3079

3080
void SolarSystem::setEphemerisMercuryMarkerColor(const Vec3f& color)
×
3081
{
3082
        if (color!=ephemerisMercuryMarkerColor)
×
3083
        {
UNCOV
3084
                ephemerisMercuryMarkerColor = color;
×
3085
                emit ephemerisMercuryMarkerColorChanged(color);
×
3086
        }
3087
}
×
3088

3089
Vec3f SolarSystem::getEphemerisMercuryMarkerColor() const
×
3090
{
UNCOV
3091
        return ephemerisMercuryMarkerColor;
×
3092
}
3093

3094
void SolarSystem::setEphemerisVenusMarkerColor(const Vec3f& color)
×
3095
{
3096
        if (color!=ephemerisVenusMarkerColor)
×
3097
        {
UNCOV
3098
                ephemerisVenusMarkerColor = color;
×
3099
                emit ephemerisVenusMarkerColorChanged(color);
×
3100
        }
3101
}
×
3102

3103
Vec3f SolarSystem::getEphemerisVenusMarkerColor() const
×
3104
{
UNCOV
3105
        return ephemerisVenusMarkerColor;
×
3106
}
3107

3108
void SolarSystem::setEphemerisMarsMarkerColor(const Vec3f& color)
×
3109
{
3110
        if (color!=ephemerisMarsMarkerColor)
×
3111
        {
UNCOV
3112
                ephemerisMarsMarkerColor = color;
×
3113
                emit ephemerisMarsMarkerColorChanged(color);
×
3114
        }
3115
}
×
3116

3117
Vec3f SolarSystem::getEphemerisMarsMarkerColor() const
×
3118
{
UNCOV
3119
        return ephemerisMarsMarkerColor;
×
3120
}
3121

3122
void SolarSystem::setEphemerisJupiterMarkerColor(const Vec3f& color)
×
3123
{
3124
        if (color!=ephemerisJupiterMarkerColor)
×
3125
        {
UNCOV
3126
                ephemerisJupiterMarkerColor = color;
×
3127
                emit ephemerisJupiterMarkerColorChanged(color);
×
3128
        }
3129
}
×
3130

3131
Vec3f SolarSystem::getEphemerisJupiterMarkerColor() const
×
3132
{
UNCOV
3133
        return ephemerisJupiterMarkerColor;
×
3134
}
3135

3136
void SolarSystem::setEphemerisSaturnMarkerColor(const Vec3f& color)
×
3137
{
3138
        if (color!=ephemerisSaturnMarkerColor)
×
3139
        {
UNCOV
3140
                ephemerisSaturnMarkerColor = color;
×
3141
                emit ephemerisSaturnMarkerColorChanged(color);
×
3142
        }
3143
}
×
3144

3145
Vec3f SolarSystem::getEphemerisSaturnMarkerColor() const
×
3146
{
UNCOV
3147
        return ephemerisSaturnMarkerColor;
×
3148
}
3149

3150
void SolarSystem::setFlagIsolatedTrails(bool b)
×
3151
{
3152
        if(b!=flagIsolatedTrails)
×
3153
        {
UNCOV
3154
                flagIsolatedTrails = b;
×
3155
                recreateTrails();
×
3156
                StelApp::immediateSave("viewing/flag_isolated_trails", b);
×
UNCOV
3157
                emit flagIsolatedTrailsChanged(b);
×
3158
        }
3159
}
×
3160

UNCOV
3161
bool SolarSystem::getFlagIsolatedTrails() const
×
3162
{
UNCOV
3163
        return flagIsolatedTrails;
×
3164
}
3165

3166
int SolarSystem::getNumberIsolatedTrails() const
×
3167
{
UNCOV
3168
        return numberIsolatedTrails;
×
3169
}
3170

3171
void SolarSystem::setNumberIsolatedTrails(int n)
×
3172
{
3173
        // [1..5] - valid range for trails
3174
        numberIsolatedTrails = qBound(1, n, 5);
×
3175

3176
        if (getFlagIsolatedTrails())
×
UNCOV
3177
                recreateTrails();
×
3178

UNCOV
3179
        StelApp::immediateSave("viewing/number_isolated_trails", n);
×
3180
        emit numberIsolatedTrailsChanged(numberIsolatedTrails);
×
UNCOV
3181
}
×
3182

UNCOV
3183
void SolarSystem::setFlagOrbits(bool b)
×
3184
{
3185
        if(b!=getFlagOrbits())
×
3186
        {
3187
                flagOrbits = b;
×
UNCOV
3188
                StelApp::immediateSave("astro/flag_planets_orbits", b);
×
UNCOV
3189
                emit flagOrbitsChanged(b);
×
3190
        }
UNCOV
3191
}
×
3192

3193
// Connect this to all signals when orbit selection or selected object has changed.
3194
// This method goes through all planets and sets orbit drawing as configured by several flags
3195
void SolarSystem::reconfigureOrbits()
×
3196
{
3197
        // State of before 24.3: You could display planet orbits only, selected object's orbit, but not mix selected minor body in relation to all planets.
3198
        // The first
3199
        // we have: flagOrbits O, flagIsolatedOrbits I, flagPlanetsOrbitsOnly P, flagOrbitsWithMoons M, flagPermanentOrbits and a possibly selected planet S
3200
        // permanentOrbits only influences local drawing of a single planet and can be ignored here.
3201
        // O S I P M
3202
        // 0 X X X X  NONE
3203
        // 1 0 1 X X  NONE
3204
        // 1 X 0 0 X  ALL
3205
        // 1 X 0 1 0  all planets only
3206
        // 1 X 0 1 1  all planets with their moons only
3207

3208
        // 1 1 1 0 0  only selected SSO
3209
        // 1 1 1 0 1  only selected SSO and orbits of its moon system
3210
        // 1 1 1 1 0  only selected SSO if it is a major planet
3211
        // 1 1 1 1 1  only selected SSO if it is a major planet, plus its system of moons
3212

UNCOV
3213
        if (!flagOrbits || (flagIsolatedOrbits && (!selected || selected==sun)))
×
3214
        {
UNCOV
3215
                for (const auto& p : std::as_const(systemPlanets))
×
UNCOV
3216
                        p->setFlagOrbits(false);
×
3217
        }
3218
        // from here, flagOrbits is certainly on
UNCOV
3219
        else if (!flagIsolatedOrbits)
×
3220
        {
UNCOV
3221
                for (const auto& p : std::as_const(systemPlanets))
×
UNCOV
3222
                        p->setFlagOrbits(!flagPlanetsOrbitsOnly || (p->getPlanetType()==Planet::isPlanet || (flagOrbitsWithMoons && p->parent && p->parent->getPlanetType()==Planet::isPlanet) ));
×
3223
        }
3224
        else // flagIsolatedOrbits && selected
3225
        {
3226
                // Display only orbit for selected planet and, if requested, its moons.
UNCOV
3227
                for (const auto& p : std::as_const(systemPlanets))
×
UNCOV
3228
                        p->setFlagOrbits(   (p==selected && (  !flagPlanetsOrbitsOnly ||  p->getPlanetType()==Planet::isPlanet ) )
×
UNCOV
3229
                                         || (flagOrbitsWithMoons && p->getPlanetType()==Planet::isMoon && p->parent==selected ) );
×
3230
        }
3231
        // 24.3: With new flag, we can override to see the orbits of major planets together with that of a single selected minor body.
3232
        if (flagOrbits && flagPlanetsOrbits)
×
3233
        {
3234
                for (const auto& p : std::as_const(systemPlanets))
×
3235
                        if ((p->getPlanetType()==Planet::isPlanet) || (flagOrbitsWithMoons && p->getPlanetType()==Planet::isMoon ))
×
UNCOV
3236
                                p->setFlagOrbits(true);
×
3237
        }
3238
}
×
3239

3240
void SolarSystem::setFlagIsolatedOrbits(bool b)
×
3241
{
UNCOV
3242
        if(b!=flagIsolatedOrbits)
×
3243
        {
UNCOV
3244
                flagIsolatedOrbits = b;
×
UNCOV
3245
                StelApp::immediateSave("viewing/flag_isolated_orbits", b);
×
3246
                emit flagIsolatedOrbitsChanged(b);
×
3247
        }
3248
}
×
3249

UNCOV
3250
bool SolarSystem::getFlagIsolatedOrbits() const
×
3251
{
UNCOV
3252
        return flagIsolatedOrbits;
×
3253
}
3254

3255
void SolarSystem::setFlagPlanetsOrbits(bool b)
×
3256
{
3257
        if(b!=flagPlanetsOrbits)
×
3258
        {
3259
                flagPlanetsOrbits = b;
×
UNCOV
3260
                StelApp::immediateSave("viewing/flag_planets_orbits", b);
×
3261
                emit flagPlanetsOrbitsChanged(b);
×
3262
        }
3263
}
×
3264

3265
bool SolarSystem::getFlagPlanetsOrbits() const
×
3266
{
3267
        return flagPlanetsOrbits;
×
3268
}
3269

UNCOV
3270
void SolarSystem::setFlagPlanetsOrbitsOnly(bool b)
×
3271
{
UNCOV
3272
        if(b!=flagPlanetsOrbitsOnly)
×
3273
        {
3274
                flagPlanetsOrbitsOnly = b;
×
UNCOV
3275
                StelApp::immediateSave("viewing/flag_planets_orbits_only", b);
×
3276
                emit flagPlanetsOrbitsOnlyChanged(b);
×
3277
        }
3278
}
×
3279

3280
bool SolarSystem::getFlagPlanetsOrbitsOnly() const
×
3281
{
3282
        return flagPlanetsOrbitsOnly;
×
3283
}
3284

UNCOV
3285
void SolarSystem::setFlagOrbitsWithMoons(bool b)
×
3286
{
UNCOV
3287
        if(b!=flagOrbitsWithMoons)
×
3288
        {
3289
                flagOrbitsWithMoons = b;
×
UNCOV
3290
                StelApp::immediateSave("viewing/flag_orbits_with_moons", b);
×
3291
                emit flagOrbitsWithMoonsChanged(b);
×
3292
        }
3293
}
×
3294

3295
bool SolarSystem::getFlagOrbitsWithMoons() const
×
3296
{
3297
        return flagOrbitsWithMoons;
×
3298
}
3299

3300
// Set/Get planets names color
3301
void SolarSystem::setLabelsColor(const Vec3f& c)
×
3302
{
UNCOV
3303
        if (c!=Planet::getLabelColor())
×
3304
        {
UNCOV
3305
                Planet::setLabelColor(c);
×
3306
                StelApp::immediateSave("color/planet_names_color", c.toStr());
×
UNCOV
3307
                emit labelsColorChanged(c);
×
3308
        }
3309
}
×
3310

UNCOV
3311
Vec3f SolarSystem::getLabelsColor(void) const
×
3312
{
UNCOV
3313
        return Planet::getLabelColor();
×
3314
}
3315

3316
// Set/Get orbits lines color
UNCOV
3317
void SolarSystem::setOrbitsColor(const Vec3f& c)
×
3318
{
UNCOV
3319
        if (c!=Planet::getOrbitColor())
×
3320
        {
UNCOV
3321
                Planet::setOrbitColor(c);
×
3322
                StelApp::immediateSave("color/sso_orbits_color", c.toStr());
×
UNCOV
3323
                emit orbitsColorChanged(c);
×
3324
        }
3325
}
×
3326

UNCOV
3327
Vec3f SolarSystem::getOrbitsColor(void) const
×
3328
{
UNCOV
3329
        return Planet::getOrbitColor();
×
3330
}
3331

3332
void SolarSystem::setMajorPlanetsOrbitsColor(const Vec3f &c)
×
3333
{
UNCOV
3334
        if (c!=Planet::getMajorPlanetOrbitColor())
×
3335
        {
3336
                Planet::setMajorPlanetOrbitColor(c);
×
UNCOV
3337
                StelApp::immediateSave("color/major_planets_orbits_color", c.toStr());
×
3338
                emit majorPlanetsOrbitsColorChanged(c);
×
3339
        }
3340
}
×
3341

3342
Vec3f SolarSystem::getMajorPlanetsOrbitsColor(void) const
×
3343
{
3344
        return Planet::getMajorPlanetOrbitColor();
×
3345
}
3346

UNCOV
3347
void SolarSystem::setMinorPlanetsOrbitsColor(const Vec3f &c)
×
3348
{
UNCOV
3349
        if (c!=Planet::getMinorPlanetOrbitColor())
×
3350
        {
3351
                Planet::setMinorPlanetOrbitColor(c);
×
UNCOV
3352
                StelApp::immediateSave("color/minor_planets_orbits_color", c.toStr());
×
3353
                emit minorPlanetsOrbitsColorChanged(c);
×
3354
        }
3355
}
×
3356

3357
Vec3f SolarSystem::getMinorPlanetsOrbitsColor(void) const
×
3358
{
3359
        return Planet::getMinorPlanetOrbitColor();
×
3360
}
3361

UNCOV
3362
void SolarSystem::setDwarfPlanetsOrbitsColor(const Vec3f &c)
×
3363
{
UNCOV
3364
        if (c!=Planet::getDwarfPlanetOrbitColor())
×
3365
        {
3366
                Planet::setDwarfPlanetOrbitColor(c);
×
UNCOV
3367
                StelApp::immediateSave("color/dwarf_planets_orbits_color", c.toStr());
×
3368
                emit dwarfPlanetsOrbitsColorChanged(c);
×
3369
        }
3370
}
×
3371

3372
Vec3f SolarSystem::getDwarfPlanetsOrbitsColor(void) const
×
3373
{
3374
        return Planet::getDwarfPlanetOrbitColor();
×
3375
}
3376

UNCOV
3377
void SolarSystem::setMoonsOrbitsColor(const Vec3f &c)
×
3378
{
UNCOV
3379
        if (c!=Planet::getMoonOrbitColor())
×
3380
        {
3381
                Planet::setMoonOrbitColor(c);
×
UNCOV
3382
                StelApp::immediateSave("color/moon_orbits_color", c.toStr());
×
3383
                emit moonsOrbitsColorChanged(c);
×
3384
        }
3385
}
×
3386

3387
Vec3f SolarSystem::getMoonsOrbitsColor(void) const
×
3388
{
3389
        return Planet::getMoonOrbitColor();
×
3390
}
3391

UNCOV
3392
void SolarSystem::setCubewanosOrbitsColor(const Vec3f &c)
×
3393
{
UNCOV
3394
        if (c!=Planet::getCubewanoOrbitColor())
×
3395
        {
3396
                Planet::setCubewanoOrbitColor(c);
×
UNCOV
3397
                StelApp::immediateSave("color/cubewano_orbits_color", c.toStr());
×
3398
                emit cubewanosOrbitsColorChanged(c);
×
3399
        }
3400
}
×
3401

3402
Vec3f SolarSystem::getCubewanosOrbitsColor(void) const
×
3403
{
3404
        return Planet::getCubewanoOrbitColor();
×
3405
}
3406

UNCOV
3407
void SolarSystem::setPlutinosOrbitsColor(const Vec3f &c)
×
3408
{
UNCOV
3409
        if (c!=Planet::getPlutinoOrbitColor())
×
3410
        {
3411
                Planet::setPlutinoOrbitColor(c);
×
UNCOV
3412
                StelApp::immediateSave("color/plutino_orbits_color", c.toStr());
×
3413
                emit plutinosOrbitsColorChanged(c);
×
3414
        }
3415
}
×
3416

3417
Vec3f SolarSystem::getPlutinosOrbitsColor(void) const
×
3418
{
3419
        return Planet::getPlutinoOrbitColor();
×
3420
}
3421

UNCOV
3422
void SolarSystem::setScatteredDiskObjectsOrbitsColor(const Vec3f &c)
×
3423
{
UNCOV
3424
        if (c!=Planet::getScatteredDiscObjectOrbitColor())
×
3425
        {
3426
                Planet::setScatteredDiscObjectOrbitColor(c);
×
UNCOV
3427
                StelApp::immediateSave("color/sdo_orbits_color", c.toStr());
×
3428
                emit scatteredDiskObjectsOrbitsColorChanged(c);
×
3429
        }
3430
}
×
3431

3432
Vec3f SolarSystem::getScatteredDiskObjectsOrbitsColor(void) const
×
3433
{
3434
        return Planet::getScatteredDiscObjectOrbitColor();
×
3435
}
3436

UNCOV
3437
void SolarSystem::setOortCloudObjectsOrbitsColor(const Vec3f &c)
×
3438
{
UNCOV
3439
        if (c!=Planet::getOortCloudObjectOrbitColor())
×
3440
        {
3441
                Planet::setOortCloudObjectOrbitColor(c);
×
UNCOV
3442
                StelApp::immediateSave("color/oco_orbits_color", c.toStr());
×
3443
                emit oortCloudObjectsOrbitsColorChanged(c);
×
3444
        }
3445
}
×
3446

3447
Vec3f SolarSystem::getOortCloudObjectsOrbitsColor(void) const
×
3448
{
3449
        return Planet::getOortCloudObjectOrbitColor();
×
3450
}
3451

UNCOV
3452
void SolarSystem::setCometsOrbitsColor(const Vec3f& c)
×
3453
{
UNCOV
3454
        if (c!=Planet::getCometOrbitColor())
×
3455
        {
3456
                Planet::setCometOrbitColor(c);
×
UNCOV
3457
                StelApp::immediateSave("color/comet_orbits_color", c.toStr());
×
3458
                emit cometsOrbitsColorChanged(c);
×
3459
        }
3460
}
×
3461

3462
Vec3f SolarSystem::getCometsOrbitsColor(void) const
×
3463
{
3464
        return Planet::getCometOrbitColor();
×
3465
}
3466

UNCOV
3467
void SolarSystem::setSednoidsOrbitsColor(const Vec3f& c)
×
3468
{
UNCOV
3469
        if (c!=Planet::getSednoidOrbitColor())
×
3470
        {
3471
                Planet::setSednoidOrbitColor(c);
×
UNCOV
3472
                StelApp::immediateSave("color/sednoid_orbits_color", c.toStr());
×
3473
                emit sednoidsOrbitsColorChanged(c);
×
3474
        }
3475
}
×
3476

3477
Vec3f SolarSystem::getSednoidsOrbitsColor(void) const
×
3478
{
3479
        return Planet::getSednoidOrbitColor();
×
3480
}
3481

UNCOV
3482
void SolarSystem::setInterstellarOrbitsColor(const Vec3f& c)
×
3483
{
UNCOV
3484
        if (c!=Planet::getInterstellarOrbitColor())
×
3485
        {
3486
                Planet::setInterstellarOrbitColor(c);
×
UNCOV
3487
                StelApp::immediateSave("color/interstellar_orbits_color", c.toStr());
×
3488
                emit interstellarOrbitsColorChanged(c);
×
3489
        }
3490
}
×
3491

3492
Vec3f SolarSystem::getInterstellarOrbitsColor(void) const
×
3493
{
3494
        return Planet::getInterstellarOrbitColor();
×
3495
}
3496

UNCOV
3497
void SolarSystem::setMercuryOrbitColor(const Vec3f &c)
×
3498
{
UNCOV
3499
        if (c!=Planet::getMercuryOrbitColor())
×
3500
        {
3501
                Planet::setMercuryOrbitColor(c);
×
UNCOV
3502
                StelApp::immediateSave("color/mercury_orbit_color", c.toStr());
×
3503
                emit mercuryOrbitColorChanged(c);
×
3504
        }
3505
}
×
3506

3507
Vec3f SolarSystem::getMercuryOrbitColor(void) const
×
3508
{
3509
        return Planet::getMercuryOrbitColor();
×
3510
}
3511

UNCOV
3512
void SolarSystem::setVenusOrbitColor(const Vec3f &c)
×
3513
{
UNCOV
3514
        if (c!=Planet::getVenusOrbitColor())
×
3515
        {
3516
                Planet::setVenusOrbitColor(c);
×
UNCOV
3517
                StelApp::immediateSave("color/venus_orbit_color", c.toStr());
×
3518
                emit venusOrbitColorChanged(c);
×
3519
        }
3520
}
×
3521

3522
Vec3f SolarSystem::getVenusOrbitColor(void) const
×
3523
{
3524
        return Planet::getVenusOrbitColor();
×
3525
}
3526

UNCOV
3527
void SolarSystem::setEarthOrbitColor(const Vec3f &c)
×
3528
{
UNCOV
3529
        if (c!=Planet::getEarthOrbitColor())
×
3530
        {
3531
                Planet::setEarthOrbitColor(c);
×
UNCOV
3532
                StelApp::immediateSave("color/earth_orbit_color", c.toStr());
×
3533
                emit earthOrbitColorChanged(c);
×
3534
        }
3535
}
×
3536

3537
Vec3f SolarSystem::getEarthOrbitColor(void) const
×
3538
{
3539
        return Planet::getEarthOrbitColor();
×
3540
}
3541

UNCOV
3542
void SolarSystem::setMarsOrbitColor(const Vec3f &c)
×
3543
{
UNCOV
3544
        if (c!=Planet::getMarsOrbitColor())
×
3545
        {
3546
                Planet::setMarsOrbitColor(c);
×
UNCOV
3547
                StelApp::immediateSave("color/mars_orbit_color", c.toStr());
×
3548
                emit marsOrbitColorChanged(c);
×
3549
        }
3550
}
×
3551

3552
Vec3f SolarSystem::getMarsOrbitColor(void) const
×
3553
{
3554
        return Planet::getMarsOrbitColor();
×
3555
}
3556

UNCOV
3557
void SolarSystem::setJupiterOrbitColor(const Vec3f &c)
×
3558
{
UNCOV
3559
        if (c!=Planet::getJupiterOrbitColor())
×
3560
        {
3561
                Planet::setJupiterOrbitColor(c);
×
UNCOV
3562
                StelApp::immediateSave("color/jupiter_orbit_color", c.toStr());
×
3563
                emit jupiterOrbitColorChanged(c);
×
3564
        }
3565
}
×
3566

3567
Vec3f SolarSystem::getJupiterOrbitColor(void) const
×
3568
{
3569
        return Planet::getJupiterOrbitColor();
×
3570
}
3571

UNCOV
3572
void SolarSystem::setSaturnOrbitColor(const Vec3f &c)
×
3573
{
UNCOV
3574
        if (c!=Planet::getSaturnOrbitColor())
×
3575
        {
3576
                Planet::setSaturnOrbitColor(c);
×
UNCOV
3577
                StelApp::immediateSave("color/saturn_orbit_color", c.toStr());
×
3578
                emit saturnOrbitColorChanged(c);
×
3579
        }
3580
}
×
3581

3582
Vec3f SolarSystem::getSaturnOrbitColor(void) const
×
3583
{
3584
        return Planet::getSaturnOrbitColor();
×
3585
}
3586

UNCOV
3587
void SolarSystem::setUranusOrbitColor(const Vec3f &c)
×
3588
{
UNCOV
3589
        if (c!=Planet::getUranusOrbitColor())
×
3590
        {
3591
                Planet::setUranusOrbitColor(c);
×
UNCOV
3592
                StelApp::immediateSave("color/uranus_orbit_color", c.toStr());
×
3593
                emit uranusOrbitColorChanged(c);
×
3594
        }
3595
}
×
3596

3597
Vec3f SolarSystem::getUranusOrbitColor(void) const
×
3598
{
3599
        return Planet::getUranusOrbitColor();
×
3600
}
3601

UNCOV
3602
void SolarSystem::setNeptuneOrbitColor(const Vec3f &c)
×
3603
{
UNCOV
3604
        if (c!=Planet::getNeptuneOrbitColor())
×
3605
        {
3606
                Planet::setNeptuneOrbitColor(c);
×
UNCOV
3607
                StelApp::immediateSave("color/neptune_orbit_color", c.toStr());
×
3608
                emit neptuneOrbitColorChanged(c);
×
3609
        }
3610
}
×
3611

3612
Vec3f SolarSystem::getNeptuneOrbitColor(void) const
×
3613
{
3614
        return Planet::getNeptuneOrbitColor();
×
3615
}
3616

3617
// Set/Get if Moon display is scaled
3618
void SolarSystem::setFlagMoonScale(bool b)
×
3619
{
UNCOV
3620
        if(b!=flagMoonScale)
×
3621
        {
UNCOV
3622
                if (b) getMoon()->setSphereScale(moonScale);
×
3623
                else getMoon()->setSphereScale(1);
×
UNCOV
3624
                flagMoonScale = b;
×
3625
                StelApp::immediateSave("viewing/flag_moon_scaled", b);
×
3626
                emit flagMoonScaleChanged(b);
×
3627
        }
UNCOV
3628
}
×
3629

3630
// Set/Get Moon display scaling factor. This goes directly to the Moon object.
3631
void SolarSystem::setMoonScale(double f)
×
3632
{
3633
        if(!fuzzyEquals(moonScale, f))
×
3634
        {
UNCOV
3635
                moonScale = f;
×
UNCOV
3636
                if (flagMoonScale)
×
3637
                        getMoon()->setSphereScale(moonScale);
×
UNCOV
3638
                StelApp::immediateSave("viewing/moon_scale", f);
×
3639
                emit moonScaleChanged(f);
×
3640
        }
3641
}
×
3642

3643
// Set if minor body display is scaled. This flag will be queried by all Planet objects except for the Moon.
3644
void SolarSystem::setFlagMinorBodyScale(bool b)
×
3645
{
UNCOV
3646
        if(b!=flagMinorBodyScale)
×
3647
        {
UNCOV
3648
                flagMinorBodyScale = b;
×
3649

3650
                double newScale = b ? minorBodyScale : 1.0;
×
3651
                //update the bodies with the new scale
3652
                for (const auto& p : std::as_const(systemPlanets))
×
3653
                {
3654
                        if(p == moon) continue;
×
3655
                        if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
×
3656
                                p->setSphereScale(newScale);
×
3657
                }
3658
                StelApp::immediateSave("viewing/flag_minorbodies_scaled", b);
×
UNCOV
3659
                emit flagMinorBodyScaleChanged(b);
×
3660
        }
UNCOV
3661
}
×
3662

3663
// Set minor body display scaling factor. This will be queried by all Planet objects except for the Moon.
UNCOV
3664
void SolarSystem::setMinorBodyScale(double f)
×
3665
{
UNCOV
3666
        if(!fuzzyEquals(minorBodyScale, f))
×
3667
        {
UNCOV
3668
                minorBodyScale = f;
×
3669
                if(flagMinorBodyScale) //update the bodies with the new scale
×
3670
                {
3671
                        for (const auto& p : std::as_const(systemPlanets))
×
3672
                        {
3673
                                if(p == moon) continue;
×
3674
                                if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
×
3675
                                        p->setSphereScale(minorBodyScale);
×
3676
                        }
3677
                }
3678
                StelApp::immediateSave("viewing/minorbodies_scale", f);
×
UNCOV
3679
                emit minorBodyScaleChanged(f);
×
3680
        }
UNCOV
3681
}
×
3682

3683
// Set if Planet display is scaled
UNCOV
3684
void SolarSystem::setFlagPlanetScale(bool b)
×
3685
{
UNCOV
3686
        if(b!=flagPlanetScale)
×
3687
        {
3688
                double scale=(b ? planetScale : 1.);
×
UNCOV
3689
                for (auto& p : systemPlanets)
×
3690
                {
UNCOV
3691
                        if (p->pType==Planet::isPlanet)
×
3692
                                p->setSphereScale(scale);
×
3693
                }
3694
                flagPlanetScale = b;
×
UNCOV
3695
                StelApp::immediateSave("viewing/flag_planets_scaled", b);
×
UNCOV
3696
                emit flagPlanetScaleChanged(b);
×
3697
        }
3698
}
×
3699

3700
// Set Moon display scaling factor.
UNCOV
3701
void SolarSystem::setPlanetScale(double f)
×
3702
{
3703
        if(!fuzzyEquals(planetScale, f))
×
3704
        {
3705
                planetScale = f;
×
UNCOV
3706
                if (flagPlanetScale)
×
3707
                        for (auto& p : systemPlanets)
×
3708
                        {
UNCOV
3709
                                if (p->pType==Planet::isPlanet)
×
3710
                                        p->setSphereScale(planetScale);
×
3711
                        }
UNCOV
3712
                StelApp::immediateSave("viewing/planets_scale", f);
×
3713
                emit planetScaleChanged(f);
×
3714
        }
3715
}
×
3716

3717
// Set if Sun display is scaled
UNCOV
3718
void SolarSystem::setFlagSunScale(bool b)
×
3719
{
3720
        if(b!=flagSunScale)
×
3721
        {
3722
                if (b) getSun()->setSphereScale(sunScale);
×
UNCOV
3723
                else getSun()->setSphereScale(1);
×
3724
                flagSunScale = b;
×
3725
                StelApp::immediateSave("viewing/flag_sun_scaled", b);
×
3726
                emit flagSunScaleChanged(b);
×
3727
        }
3728
}
×
3729

3730
// Set Sun display scaling factor. This goes directly to the Sun object.
3731
void SolarSystem::setSunScale(double f)
×
3732
{
UNCOV
3733
        if(!fuzzyEquals(sunScale, f))
×
3734
        {
UNCOV
3735
                sunScale = f;
×
UNCOV
3736
                if (flagSunScale)
×
3737
                        getSun()->setSphereScale(sunScale);
×
UNCOV
3738
                StelApp::immediateSave("viewing/sun_scale", f);
×
3739
                emit sunScaleChanged(f);
×
3740
        }
3741
}
×
3742

3743
// Set selected planets by englishName
3744
void SolarSystem::setSelected(const QString& englishName)
×
3745
{
UNCOV
3746
        setSelected(searchByEnglishName(englishName));
×
3747
}
×
3748

3749
// Get the list of all the planet english names
3750
QStringList SolarSystem::getAllPlanetEnglishNames() const
×
3751
{
3752
        QStringList res;
×
UNCOV
3753
        for (const auto& p : systemPlanets)
×
3754
                res.append(p->getEnglishName());
×
3755
        return res;
×
3756
}
×
3757

3758
QStringList SolarSystem::getAllPlanetLocalizedNames() const
×
3759
{
3760
        QStringList res;
×
UNCOV
3761
        for (const auto& p : systemPlanets)
×
UNCOV
3762
                res.append(p->getNameI18n());
×
3763
        return res;
×
UNCOV
3764
}
×
3765

3766
QStringList SolarSystem::getAllMinorPlanetEnglishNames() const
×
3767
{
UNCOV
3768
        QStringList res;
×
3769
        for (const auto& p : systemMinorBodies)
×
UNCOV
3770
                res.append(p->getEnglishName());
×
3771
        return res;
×
3772
}
×
3773

3774
// 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.
3775
void SolarSystem::reloadPlanets()
×
3776
{
3777
        // Save flag states
UNCOV
3778
        const bool flagScaleMoon = getFlagMoonScale();
×
3779
        const double moonScale = getMoonScale();
×
3780
        const bool flagScaleMinorBodies=getFlagMinorBodyScale();
×
3781
        const double minorScale= getMinorBodyScale();
×
3782
        const bool flagPlanets = getFlagPlanets();
×
3783
        const bool flagHints = getFlagHints();
×
UNCOV
3784
        const bool flagLabels = getFlagLabels();
×
3785
        const bool flagOrbits = getFlagOrbits();
×
UNCOV
3786
        bool hasSelection = false;
×
3787

3788
        // Save observer location (fix for LP bug # 969211)
3789
        // TODO: This can probably be done better with a better understanding of StelObserver --BM
3790
        StelCore* core = StelApp::getInstance().getCore();
×
3791
        const StelLocation loc = core->getCurrentLocation();
×
UNCOV
3792
        StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr);
×
3793

3794
        // Whether any planet are selected? Save the current selection...
3795
        const QList<StelObjectP> selectedObject = objMgr->getSelectedObject("Planet");
×
UNCOV
3796
        if (!selectedObject.isEmpty())
×
3797
        {
3798
                // ... unselect current planet.
3799
                hasSelection = true;
×
3800
                objMgr->unSelect();
×
3801
        }
3802
        // Unload all Solar System objects
3803
        selected.clear();//Release the selected one
×
3804

3805
        // GZ TODO in case this methods gets converted to only reload minor bodies: Only delete Orbits which are not referenced by some Planet.
3806
        for (auto* orb : std::as_const(orbits))
×
3807
        {
UNCOV
3808
                delete orb;
×
3809
        }
UNCOV
3810
        orbits.clear();
×
3811

3812
        sun.clear();
×
3813
        moon.clear();
×
UNCOV
3814
        earth.clear();
×
UNCOV
3815
        Planet::texEarthShadow.clear(); //Loaded in loadPlanets()
×
3816

3817
        delete allTrails;
×
UNCOV
3818
        allTrails = Q_NULLPTR;
×
3819

3820
        for (const auto& p : std::as_const(systemPlanets))
×
3821
        {
UNCOV
3822
                p->satellites.clear();
×
3823
        }
3824
        systemPlanets.clear();
×
UNCOV
3825
        systemMinorBodies.clear();
×
3826
        // Memory leak? What's the proper way of cleaning shared pointers?
3827

3828
        // Also delete Comet textures (loaded in loadPlanets()
3829
        Comet::tailTexture.clear();
×
UNCOV
3830
        Comet::comaTexture.clear();
×
3831

3832
        // Re-load the ssystem_major.ini and ssystem_minor.ini file
3833
        loadPlanets();        
×
3834
        computePositions(core, core->getJDE(), getSun());
×
3835
        setSelected("");
×
3836
        recreateTrails();
×
3837
        
3838
        // Restore observer location
3839
        core->moveObserverTo(loc, 0., 0.);
×
3840

3841
        // Restore flag states
UNCOV
3842
        setFlagMoonScale(flagScaleMoon);
×
3843
        setMoonScale(moonScale);
×
UNCOV
3844
        setFlagMinorBodyScale(flagScaleMinorBodies);
×
3845
        setMinorBodyScale(1.0); // force-reset first to really reach the objects in the next call.
×
3846
        setMinorBodyScale(minorScale);
×
UNCOV
3847
        setFlagPlanets(flagPlanets);
×
UNCOV
3848
        setFlagHints(flagHints);
×
UNCOV
3849
        setFlagLabels(flagLabels);
×
3850
        setFlagOrbits(flagOrbits);
×
3851

3852
        // Restore translations
UNCOV
3853
        updateI18n();
×
3854

3855
        if (hasSelection)
×
3856
        {
3857
                // Restore selection...
UNCOV
3858
                StelObjectP obj = selectedObject[0];
×
UNCOV
3859
                objMgr->findAndSelect(obj->getEnglishName(), obj->getType());
×
3860
        }
×
3861

UNCOV
3862
        emit solarSystemDataReloaded();
×
3863
}
×
3864

3865
// Set the algorithm for computation of apparent magnitudes for planets in case  observer on the Earth
3866
void SolarSystem::setApparentMagnitudeAlgorithmOnEarth(const QString &algorithm)
×
3867
{
3868
        Planet::ApparentMagnitudeAlgorithm id=vMagAlgorithmMap.key(algorithm);
×
3869
        Planet::setApparentMagnitudeAlgorithm(id);
×
3870
        StelApp::immediateSave("astro/apparent_magnitude_algorithm", algorithm);
×
3871
        emit apparentMagnitudeAlgorithmOnEarthChanged(algorithm);
×
3872
}
×
3873
// overloaded for GUI efficiency
UNCOV
3874
void SolarSystem::setApparentMagnitudeAlgorithmOnEarth(const Planet::ApparentMagnitudeAlgorithm id)
×
3875
{
UNCOV
3876
        QString name =vMagAlgorithmMap.value(id);
×
3877
        Planet::setApparentMagnitudeAlgorithm(id);
×
UNCOV
3878
        StelApp::immediateSave("astro/apparent_magnitude_algorithm", name);
×
UNCOV
3879
        emit apparentMagnitudeAlgorithmOnEarthChanged(name);
×
3880
}
×
3881

3882
// Get the algorithm used for computation of apparent magnitudes for planets in case  observer on the Earth
UNCOV
3883
QString SolarSystem::getApparentMagnitudeAlgorithmOnEarth() const
×
3884
{
3885
        return vMagAlgorithmMap.value(Planet::getApparentMagnitudeAlgorithm());
×
3886
}
3887

3888
void SolarSystem::setFlagDrawMoonHalo(bool b)
×
3889
{
3890
        Planet::drawMoonHalo=b;
×
3891
        StelApp::immediateSave("viewing/flag_draw_moon_halo", b);
×
3892
        emit flagDrawMoonHaloChanged(b);
×
3893
}
×
3894

UNCOV
3895
bool SolarSystem::getFlagDrawMoonHalo() const
×
3896
{
UNCOV
3897
        return Planet::drawMoonHalo;
×
3898
}
3899

3900
void SolarSystem::setFlagDrawSunHalo(bool b)
×
3901
{
3902
        Planet::drawSunHalo=b;
×
UNCOV
3903
        StelApp::immediateSave("viewing/flag_draw_sun_halo", b);
×
UNCOV
3904
        emit flagDrawSunHaloChanged(b);
×
3905
}
×
3906

3907
bool SolarSystem::getFlagDrawSunHalo() const
×
3908
{
UNCOV
3909
        return Planet::drawSunHalo;
×
3910
}
3911

3912
void SolarSystem::setFlagPermanentOrbits(bool b)
×
3913
{
3914
        if (Planet::permanentDrawingOrbits!=b)
×
3915
        {
UNCOV
3916
                Planet::permanentDrawingOrbits=b;
×
3917
                StelApp::immediateSave("astro/flag_permanent_orbits", b);
×
UNCOV
3918
                emit flagPermanentOrbitsChanged(b);
×
3919
        }
UNCOV
3920
}
×
3921

3922
bool SolarSystem::getFlagPermanentOrbits() const
×
3923
{
3924
        return Planet::permanentDrawingOrbits;
×
3925
}
3926

3927
void SolarSystem::setOrbitsThickness(int v)
×
3928
{
3929
        if (v!=Planet::orbitsThickness)
×
3930
        {
3931
                Planet::orbitsThickness=v;
×
UNCOV
3932
                StelApp::immediateSave("astro/object_orbits_thickness", v);
×
UNCOV
3933
                emit orbitsThicknessChanged(v);
×
3934
        }
UNCOV
3935
}
×
3936

UNCOV
3937
int SolarSystem::getOrbitsThickness() const
×
3938
{
3939
        return Planet::orbitsThickness;
×
3940
}
3941

3942
void SolarSystem::setGrsLongitude(int longitude)
×
3943
{
3944
        RotationElements::grsLongitude = longitude;
×
3945
        // automatic saving of the setting
3946
        conf->setValue("astro/grs_longitude", longitude);
×
UNCOV
3947
        emit grsLongitudeChanged(longitude);
×
UNCOV
3948
}
×
3949

UNCOV
3950
int SolarSystem::getGrsLongitude() const
×
3951
{
UNCOV
3952
        return static_cast<int>(RotationElements::grsLongitude);
×
3953
}
3954

3955
void SolarSystem::setGrsDrift(double drift)
×
3956
{
3957
        RotationElements::grsDrift = drift;
×
3958
        // automatic saving of the setting
3959
        conf->setValue("astro/grs_drift", drift);
×
UNCOV
3960
        emit grsDriftChanged(drift);
×
3961
}
×
3962

UNCOV
3963
double SolarSystem::getGrsDrift() const
×
3964
{
UNCOV
3965
        return RotationElements::grsDrift;
×
3966
}
3967

3968
void SolarSystem::setGrsJD(double JD)
×
3969
{
3970
        RotationElements::grsJD = JD;
×
3971
        // automatic saving of the setting
3972
        conf->setValue("astro/grs_jd", JD);
×
UNCOV
3973
        emit grsJDChanged(JD);
×
3974
}
×
3975

UNCOV
3976
double SolarSystem::getGrsJD()
×
3977
{
UNCOV
3978
        return RotationElements::grsJD;
×
3979
}
3980

3981
void SolarSystem::setFlagEarthShadowEnlargementDanjon(bool b)
×
3982
{
3983
        earthShadowEnlargementDanjon=b;
×
UNCOV
3984
        StelApp::immediateSave("astro/shadow_enlargement_danjon", b);
×
3985
        emit earthShadowEnlargementDanjonChanged(b);
×
UNCOV
3986
}
×
3987

UNCOV
3988
bool SolarSystem::getFlagEarthShadowEnlargementDanjon() const
×
3989
{
3990
        return earthShadowEnlargementDanjon;
×
3991
}
3992

UNCOV
3993
void SolarSystem::setOrbitColorStyle(const QString &style)
×
3994
{
3995
        static const QMap<QString, Planet::PlanetOrbitColorStyle>map={
3996
                { QString("groups"),                    Planet::ocsGroups},
×
UNCOV
3997
                { QString("major_planets"),             Planet::ocsMajorPlanets},
×
3998
                { QString("major_planets_minor_types"), Planet::ocsMajorPlanetsMinorTypes}
×
UNCOV
3999
        };
×
4000
        Planet::PlanetOrbitColorStyle st=map.value(style.toLower(), Planet::ocsOneColor);
×
UNCOV
4001
        Planet::orbitColorStyle = st;
×
UNCOV
4002
        StelApp::immediateSave("astro/planets_orbits_color_style", style);
×
4003
        emit orbitColorStyleChanged(style);
×
UNCOV
4004
}
×
4005

4006
QString SolarSystem::getOrbitColorStyle() const
×
4007
{
4008
        static const QMap<Planet::PlanetOrbitColorStyle, QString>map={
UNCOV
4009
                { Planet::ocsOneColor,               "one_color"},
×
4010
                { Planet::ocsGroups,                 "groups"},
×
UNCOV
4011
                { Planet::ocsMajorPlanets,           "major_planets"},
×
4012
                { Planet::ocsMajorPlanetsMinorTypes, "major_planets_minor_types"},
×
UNCOV
4013
        };
×
UNCOV
4014
        return map.value(Planet::orbitColorStyle, "one_color");
×
4015
}
×
4016

4017
// TODO: To make the code better understandable, get rid of planet->computeModelMatrix(trans, true) here.
4018
QPair<double, PlanetP> SolarSystem::getSolarEclipseFactor(const StelCore* core) const
×
4019
{
4020
        PlanetP p;
×
4021
        const Vec3d Lp = sun->getEclipticPos() + sun->getAberrationPush();
×
4022
        const Vec3d P3 = core->getObserverHeliocentricEclipticPos();
×
4023
        const double RS = sun->getEquatorialRadius();
×
4024

4025
        double final_illumination = 1.0;
×
4026

UNCOV
4027
        for (const auto& planet : systemPlanets)
×
4028
        {
UNCOV
4029
                if(planet == sun || planet == core->getCurrentPlanet())
×
UNCOV
4030
                        continue;
×
4031

4032
                // Seen from Earth, only Moon, Venus or Mercury are relevant. The rest can be thrown away. There is no asteroid to go in front of the sun...
4033
                static const QStringList fromEarth({"Moon", "Mercury", "Venus"});
×
4034
                if ((core->getCurrentPlanet() == earth) && !fromEarth.contains(planet->englishName))
×
4035
                        continue;
×
4036

4037
                Mat4d trans;
×
UNCOV
4038
                planet->computeModelMatrix(trans, true);
×
4039

4040
                const Vec3d C = trans * Vec3d(0., 0., 0.);
×
UNCOV
4041
                const double radius = planet->getEquatorialRadius();
×
4042

4043
                Vec3d v1 = Lp - P3;
×
4044
                Vec3d v2 = C - P3;
×
4045
                const double L = v1.norm();
×
UNCOV
4046
                const double l = v2.norm();
×
4047
                v1 /= L;
×
UNCOV
4048
                v2 /= l;
×
4049

UNCOV
4050
                const double R = RS / L;
×
4051
                const double r = radius / l;
×
4052
                const double d = ( v1 - v2 ).norm();
×
4053
                double illumination;
4054

4055
                if(d >= R + r) // distance too far
×
4056
                {
4057
                        illumination = 1.0;
×
4058
                }
4059
                else if(d <= r - R) // umbra
×
4060
                {
UNCOV
4061
                        illumination = 0.0;
×
4062
                }
4063
                else if(d <= R - r) // penumbra completely inside
×
4064
                {
4065
                        illumination = 1.0 - r * r / (R * R);
×
4066
                }
4067
                else // penumbra partially inside
4068
                {
4069
                        const double x = (R * R + d * d - r * r) / (2.0 * d);
×
4070

UNCOV
4071
                        const double alpha = std::acos(x / R);
×
4072
                        const double beta = std::acos((d - x) / r);
×
4073

4074
                        const double AR = R * R * (alpha - 0.5 * std::sin(2.0 * alpha));
×
UNCOV
4075
                        const double Ar = r * r * (beta - 0.5 * std::sin(2.0 * beta));
×
UNCOV
4076
                        const double AS = R * R * 2.0 * std::asin(1.0);
×
4077

UNCOV
4078
                        illumination = 1.0 - (AR + Ar) / AS;
×
4079
                }
4080

4081
                if(illumination < final_illumination)
×
4082
                {
4083
                        final_illumination = illumination;
×
UNCOV
4084
                        p = planet;
×
4085
                }
4086
        }
4087

UNCOV
4088
        return QPair<double, PlanetP>(final_illumination, p);
×
UNCOV
4089
}
×
4090

4091
// Opening angle of the bright Solar crescent, radians
4092
// From: J. Meeus, Morsels IV, ch.15
4093
// lunarSize: apparent Lunar radius or diameter, angular units of your preference
4094
// solarSize: apparent Solar radius or diameter, resp., same angular units
4095
// eclipseMagnitude: covered fraction of the Solar diameter.
4096
double SolarSystem::getEclipseCrescentAngle(const double lunarSize, const double solarSize, const double eclipseMagnitude)
×
4097
{
4098
        const double R = lunarSize/solarSize;
×
UNCOV
4099
        const double cosAhalf = 2.*eclipseMagnitude * (R-eclipseMagnitude)/(1.+R-2.*eclipseMagnitude) - 1.;
×
4100
        return (std::fabs(cosAhalf) <= 1. ? 2.*acos(cosAhalf) : 0.);
×
4101
}
4102

4103
// Retrieve Radius of Umbra and Penumbra at the distance of the Moon.
4104
// Returns a pair (umbra, penumbra) in (geocentric_arcseconds, AU, geometric_AU).
4105
// * sizes in arcseconds are the usual result found as Bessel element in eclipse literature.
4106
//   It includes scaling for effects of atmosphere either after Chauvenet (2%) or after Danjon. (see Espenak: 5000 Years Canon of Lunar Eclipses.)
4107
// * sizes in AU are the same, converted back to AU in Lunar distance.
4108
// * sizes in geometric_AU derived from pure geometrical evaluations without scalings applied.
UNCOV
4109
QPair<Vec3d,Vec3d> SolarSystem::getEarthShadowRadiiAtLunarDistance() const
×
4110
{
4111
        // Note: The application of this shadow enlargement is not according to the books, but looks close enough for now.
UNCOV
4112
        static const double sun2earth=sun->getEquatorialRadius() / earth->getEquatorialRadius();
×
UNCOV
4113
        PlanetP sun=getSun();
×
UNCOV
4114
        PlanetP moon=getMoon();
×
UNCOV
4115
        PlanetP earth=getEarth();
×
UNCOV
4116
        const double lunarDistance=moon->getEclipticPos().norm(); // Lunar distance [AU]
×
UNCOV
4117
        const double earthDistance=earth->getHeliocentricEclipticPos().norm(); // Earth distance [AU]
×
4118
        const double sunHP =asin(earth->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec.
×
UNCOV
4119
        const double moonHP=asin(earth->getEquatorialRadius()/lunarDistance) * M_180_PI*3600.; // arcsec.
×
4120
        const double sunSD  =atan(sun->getEquatorialRadius()/earthDistance)  * M_180_PI*3600.; // arcsec.
×
4121

4122
        // Compute umbra radius at lunar distance.
UNCOV
4123
        const double lUmbra=earthDistance/(sun2earth-1.); // length of earth umbra [AU]
×
UNCOV
4124
        const double rUmbraAU=earth->getEquatorialRadius()*(lUmbra-lunarDistance)/lUmbra; // radius of earth shadow at lunar distance [AU]
×
4125
        // Penumbra:
UNCOV
4126
        const double lPenumbra=earthDistance/(sun2earth + 1.); // distance between earth and point between sun and earth where penumbral border rays intersect
×
UNCOV
4127
        const double rPenumbraAU=earth->getEquatorialRadius()*(lPenumbra+lunarDistance)/lPenumbra; // radius of penumbra at Lunar distance [AU]
×
4128

4129
        //Classical Bessel elements instead
4130
        double f1, f2;
4131
        if (earthShadowEnlargementDanjon)
×
4132
        {
4133
                static const double danjonScale=1+1./85.-1./594.; // ~1.01, shadow magnification factor (see Espenak 5000 years Canon)
4134
                f1=danjonScale*moonHP + sunHP + sunSD; // penumbra radius, arcsec
×
4135
                f2=danjonScale*moonHP + sunHP - sunSD; // umbra radius, arcsec
×
4136
        }
4137
        else
4138
        {
4139
                const double mHP1=0.998340*moonHP;
×
4140
                f1=1.02*(mHP1 + sunHP + sunSD); // penumbra radius, arcsec
×
4141
                f2=1.02*(mHP1 + sunHP - sunSD); // umbra radius, arcsec
×
4142
        }
UNCOV
4143
        const double f1_AU=tan(f1/3600.*M_PI_180)*lunarDistance;
×
UNCOV
4144
        const double f2_AU=tan(f2/3600.*M_PI_180)*lunarDistance;
×
4145
        return QPair<Vec3d,Vec3d>(Vec3d(f2, f2_AU, rUmbraAU), Vec3d(f1, f1_AU, rPenumbraAU));
×
4146
}
×
4147

4148
bool SolarSystem::removeMinorPlanet(const QString &name)
×
4149
{
UNCOV
4150
        PlanetP candidate = searchMinorPlanetByEnglishName(name);
×
UNCOV
4151
        if (!candidate)
×
4152
        {
4153
                qWarning() << "Cannot remove planet " << name << ": Not found.";
×
UNCOV
4154
                return false;
×
4155
        }
4156

4157
        Orbit* orbPtr=static_cast<Orbit*>(candidate->orbitPtr);
×
UNCOV
4158
        if (orbPtr)
×
UNCOV
4159
                orbits.removeOne(orbPtr);
×
UNCOV
4160
        systemPlanets.removeOne(candidate);
×
4161
        systemMinorBodies.removeOne(candidate);
×
4162
        candidate.clear();
×
4163
        return true;
×
UNCOV
4164
}
×
4165

4166
void SolarSystem::onNewSurvey(HipsSurveyP survey)
×
4167
{
4168
        if (!survey->isPlanetarySurvey()) return;
×
4169

4170
        const auto type = survey->getType();
×
UNCOV
4171
        const bool isPlanetColor = type == "planet";
×
4172
        const bool isPlanetNormal = type == "planet-normal";
×
4173
        const bool isPlanetHorizon = type == "planet-horizon";
×
UNCOV
4174
        if (!isPlanetColor && !isPlanetNormal && !isPlanetHorizon)
×
4175
                return;
×
4176

UNCOV
4177
        QString planetName = survey->getFrame();
×
UNCOV
4178
        PlanetP pl = searchByEnglishName(planetName);
×
4179
        if (!pl) return;
×
4180
        if (isPlanetColor)
×
4181
        {
4182
                if (pl->survey) return;
×
4183
                pl->survey = survey;
×
4184
        }
4185
        else if (isPlanetNormal)
×
4186
        {
UNCOV
4187
                if (pl->surveyForNormals) return;
×
4188
                pl->surveyForNormals = survey;
×
4189
        }
4190
        else if (isPlanetHorizon)
×
4191
        {
4192
                if (pl->surveyForHorizons) return;
×
4193
                pl->surveyForHorizons = survey;
×
4194
        }
4195
        survey->setProperty("planet", pl->getEnglishName());
×
4196
        // Not visible by default for the moment.
4197
        survey->setProperty("visible", false);
×
4198
}
×
4199

4200
void SolarSystem::setExtraThreads(int n)
×
4201
{
4202
        extraThreads=qBound(0,n,QThreadPool::globalInstance()->maxThreadCount()-1);
×
4203
        StelApp::immediateSave("astro/solar_system_threads", extraThreads);
×
UNCOV
4204
        emit extraThreadsChanged(extraThreads);
×
4205
}
×
4206

4207
void SolarSystem::setMarkerMagThreshold(double m)
×
4208
{
UNCOV
4209
        markerMagThreshold=qBound(-5.,m,37.); // sync with GUI & WUI!
×
4210
        StelApp::immediateSave("astro/planet_markers_mag_threshold", markerMagThreshold);
×
UNCOV
4211
        emit markerMagThresholdChanged(markerMagThreshold);
×
4212
}
×
4213

4214
const QMap<Planet::ApparentMagnitudeAlgorithm, QString> SolarSystem::vMagAlgorithmMap =
4215
{
4216
        {Planet::MallamaHilton_2018,                "Mallama2018"},
4217
        {Planet::ExplanatorySupplement_2013,        "ExpSup2013"},
4218
        {Planet::ExplanatorySupplement_1992,        "ExpSup1992"},
4219
        {Planet::Mueller_1893,                        "Mueller1893"},
4220
        {Planet::AstronomicalAlmanac_1984,        "AstrAlm1984"},
4221
        {Planet::Generic,                        "Generic"},
4222
        {Planet::UndefinedAlgorithm,                ""}
4223
};
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