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

Stellarium / stellarium / 13149582607

03 Feb 2025 11:24AM UTC coverage: 12.101% (-0.04%) from 12.141%
13149582607

push

github

web-flow
Translate po/stellarium/stellarium.pot in zh_CN

100% translated source file: 'po/stellarium/stellarium.pot'
on 'zh_CN'.

14603 of 120671 relevant lines covered (12.1%)

18593.62 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
        , flagNativePlanetNames(false)
×
92
        , flagIsolatedTrails(true)
×
93
        , numberIsolatedTrails(0)
×
94
        , maxTrailPoints(5000)
×
95
        , maxTrailTimeExtent(1)
×
96
        , trailsThickness(1)
×
97
        , flagIsolatedOrbits(true)
×
98
        , flagPlanetsOrbits(false)
×
99
        , flagPlanetsOrbitsOnly(false)
×
100
        , flagOrbitsWithMoons(false)
×
101
        , ephemerisMarkersDisplayed(true)
×
102
        , ephemerisDatesDisplayed(false)
×
103
        , ephemerisMagnitudesDisplayed(false)
×
104
        , ephemerisHorizontalCoordinates(false)
×
105
        , ephemerisLineDisplayed(false)
×
106
        , ephemerisAlwaysOn(false)
×
107
        , ephemerisNow(false)
×
108
        , ephemerisLineThickness(1)
×
109
        , ephemerisSkipDataDisplayed(false)
×
110
        , ephemerisSkipMarkersDisplayed(false)
×
111
        , ephemerisDataStep(1)
×
112
        , ephemerisDataLimit(1)
×
113
        , ephemerisSmartDatesDisplayed(true)
×
114
        , ephemerisScaleMarkersDisplayed(false)
×
115
        , ephemerisGenericMarkerColor(Vec3f(1.0f, 1.0f, 0.0f))
×
116
        , ephemerisSecondaryMarkerColor(Vec3f(0.7f, 0.7f, 1.0f))
×
117
        , ephemerisSelectedMarkerColor(Vec3f(1.0f, 0.7f, 0.0f))
×
118
        , ephemerisMercuryMarkerColor(Vec3f(1.0f, 1.0f, 0.0f))
×
119
        , ephemerisVenusMarkerColor(Vec3f(1.0f, 1.0f, 1.0f))
×
120
        , ephemerisMarsMarkerColor(Vec3f(1.0f, 0.0f, 0.0f))
×
121
        , ephemerisJupiterMarkerColor(Vec3f(0.3f, 1.0f, 1.0f))
×
122
        , ephemerisSaturnMarkerColor(Vec3f(0.0f, 1.0f, 0.0f))
×
123
        , allTrails(Q_NULLPTR)
×
124
        , conf(StelApp::getInstance().getSettings())
×
125
        , extraThreads(0)
×
126
        , nbMarkers(0)
×
127
        , vao(new QOpenGLVertexArrayObject)
×
128
        , vbo(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer))
×
129
        , markerMagThreshold(15.)
×
130
        , computePositionsAlgorithm(conf->value("devel/compute_positions_algorithm", 2).toInt())
×
131
{
132
        planetNameFont.setPixelSize(StelApp::getInstance().getScreenFontSize());
×
133
        connect(&StelApp::getInstance(), SIGNAL(screenFontSizeChanged(int)), this, SLOT(setFontSize(int)));
×
134
        setObjectName("SolarSystem");
×
135
        connect(this, SIGNAL(flagOrbitsChanged(bool)),            this, SLOT(reconfigureOrbits()));
×
136
        connect(this, SIGNAL(flagPlanetsOrbitsChanged(bool)),     this, SLOT(reconfigureOrbits()));
×
137
        connect(this, SIGNAL(flagPlanetsOrbitsOnlyChanged(bool)), this, SLOT(reconfigureOrbits()));
×
138
        connect(this, SIGNAL(flagIsolatedOrbitsChanged(bool)),    this, SLOT(reconfigureOrbits()));
×
139
        connect(this, SIGNAL(flagOrbitsWithMoonsChanged(bool)),   this, SLOT(reconfigureOrbits()));
×
140

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

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

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

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

179

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

185
        delete allTrails;
×
186
        allTrails = Q_NULLPTR;
×
187

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

363
        connect(StelApp::getInstance().getModule("HipsMgr"), SIGNAL(gotNewSurvey(HipsSurveyP)),
×
364
                        this, SLOT(onNewSurvey(HipsSurveyP)));
365

366
        // Fill ephemeris dates
367
        connect(this, SIGNAL(requestEphemerisVisualization()), this, SLOT(fillEphemerisDates()));
×
368
        connect(this, SIGNAL(ephemerisDataStepChanged(int)), this, SLOT(fillEphemerisDates()));
×
369
        connect(this, SIGNAL(ephemerisSkipDataChanged(bool)), this, SLOT(fillEphemerisDates()));
×
370
        connect(this, SIGNAL(ephemerisSkipMarkersChanged(bool)), this, SLOT(fillEphemerisDates()));
×
371
        connect(this, SIGNAL(ephemerisSmartDatesChanged(bool)), this, SLOT(fillEphemerisDates()));
×
372

373

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

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

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

414
        vbo->create();
×
415
        vbo->bind();
×
416
        vbo->setUsagePattern(QOpenGLBuffer::StreamDraw);
×
417
        vbo->allocate(maxMarkers*6*sizeof(MarkerVertex) + maxMarkers*6*2);
×
418

419
        if(vao->create())
×
420
        {
421
                vao->bind();
×
422
                setupCurrentVAO();
×
423
                vao->release();
×
424
        }
425

426
        vbo->release();
×
427
}
×
428

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

441
void SolarSystem::bindVAO()
×
442
{
443
        if(vao->isCreated())
×
444
                vao->bind();
×
445
        else
446
                setupCurrentVAO();
×
447
}
×
448

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

463
void SolarSystem::deinit()
×
464
{
465
        Planet::deinitShader();
×
466
        Planet::deinitFBO();
×
467
}
×
468

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

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

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

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

534

535
void SolarSystem::updateSkyCulture(const QString& skyCultureDir)
×
536
{
537
        planetNativeNamesMap.clear();
×
538
        planetNativeNamesMeaningMap.clear();
×
539

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

542
        if (namesFile.isEmpty())
×
543
        {
544
                for (const auto& p : std::as_const(systemPlanets))
×
545
                {
546
                        if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
×
547
                        {
548
                                p->setNativeName("");
×
549
                                p->setNativeNameMeaning("");
×
550
                        }
551
                }
552
                updateI18n();
×
553
                return;
×
554
        }
555

556
        // Open file
557
        QFile planetNamesFile(namesFile);
×
558
        if (!planetNamesFile.open(QIODevice::ReadOnly | QIODevice::Text))
×
559
        {
560
                qDebug() << " Cannot open file" << QDir::toNativeSeparators(namesFile);
×
561
                return;
×
562
        }
563

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

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

572
        QString record, planetId, nativeName, nativeNameMeaning;
×
573

574
        // keep track of how many records we processed.
575
        int totalRecords=0;
×
576
        int readOk=0;
×
577
        int lineNumber=0;
×
578
        while (!planetNamesFile.atEnd())
×
579
        {
580
                record = QString::fromUtf8(planetNamesFile.readLine());
×
581
                lineNumber++;
×
582

583
                // Skip comments
584
                if (commentRx.match(record).hasMatch())
×
585
                        continue;
×
586

587
                totalRecords++;
×
588

589
                QRegularExpressionMatch match=recRx.match(record);
×
590
                if (!match.hasMatch())
×
591
                {
592
                        qWarning() << "ERROR - cannot parse record at line" << lineNumber << "in planet names file" << QDir::toNativeSeparators(namesFile);
×
593
                }
594
                else
595
                {
596
                        planetId          = match.captured(1).trimmed();
×
597
                        nativeName        = match.captured(2).trimmed();
×
598
                        nativeNameMeaning = match.captured(3).trimmed();
×
599
                        planetNativeNamesMap[planetId] = nativeName;
×
600
                        planetNativeNamesMeaningMap[planetId] = nativeNameMeaning;
×
601
                        readOk++;
×
602
                }
603
        }
×
604
        planetNamesFile.close();
×
605
        qDebug() << "Loaded" << readOk << "/" << totalRecords << "native names of planets";
×
606

607
        for (const auto& p : std::as_const(systemPlanets))
×
608
        {
609
                if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
×
610
                {
611
                        p->setNativeName(planetNativeNamesMap[p->getEnglishName()]);
×
612
                        p->setNativeNameMeaning(planetNativeNamesMeaningMap[p->getEnglishName()]);
×
613
                }
614
        }
615

616
        updateI18n();
×
617
}
×
618

619
void SolarSystem::reloadShaders()
×
620
{
621
        Planet::deinitShader();
×
622
        Planet::initShader();
×
623
}
×
624

625
void SolarSystem::drawPointer(const StelCore* core)
×
626
{
627
        const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
628
        static StelObjectMgr *sObjMgr=GETSTELMODULE(StelObjectMgr);
×
629

630
        const QList<StelObjectP> newSelected = sObjMgr->getSelectedObject("Planet");
×
631
        if (!newSelected.empty())
×
632
        {
633
                const StelObjectP obj = newSelected[0];
×
634
                Vec3d pos=obj->getJ2000EquatorialPos(core);
×
635

636
                Vec3f screenpos;
×
637
                // Compute 2D pos and return if outside screen
638
                if (!prj->project(pos, screenpos))
×
639
                        return;
×
640

641
                StelPainter sPainter(prj);
×
642
                sPainter.setColor(getPointerColor());
×
643

644
                float screenSize = static_cast<float>(obj->getAngularRadius(core))*prj->getPixelPerRadAtCenter()*M_PI_180f*2.f;
×
645
                
646
                const float scale = static_cast<float>(prj->getDevicePixelsPerPixel());
×
647
                screenSize+= scale * (45.f + 10.f*std::sin(2.f * static_cast<float>(StelApp::getInstance().getAnimationTime())));
×
648

649
                texPointer->bind();
×
650

651
                sPainter.setBlending(true);
×
652

653
                screenSize*=0.5f;
×
654
                const float angleBase = static_cast<float>(StelApp::getInstance().getAnimationTime()) * 10;
×
655
                // We draw 4 instances of the sprite at the corners of the pointer
656
                for (int i = 0; i < 4; ++i)
×
657
                {
658
                        const float angle = angleBase + i * 90;
×
659
                        const float x = screenpos[0] + screenSize * cos(angle * M_PI_180f);
×
660
                        const float y = screenpos[1] + screenSize * sin(angle * M_PI_180f);
×
661
                        sPainter.drawSprite2dMode(x, y, 10, angle);
×
662
                }
663
        }
×
664
}
×
665

666
void keplerOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
×
667
{
668
        static_cast<KeplerOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
×
669
        static_cast<KeplerOrbit*>(orbitPtr)->getVelocity(xyzdot);
×
670
}
×
671

672
void gimbalOrbitPosFunc(double jd,double xyz[3], double xyzdot[3], void* orbitPtr)
×
673
{
674
        static_cast<GimbalOrbit*>(orbitPtr)->positionAtTimevInVSOP87Coordinates(jd, xyz);
×
675
        static_cast<GimbalOrbit*>(orbitPtr)->getVelocity(xyzdot);
×
676
}
×
677

678
// Init and load the solar system data (2 files)
679
void SolarSystem::loadPlanets()
×
680
{
681
        minorBodies.clear();
×
682
        systemMinorBodies.clear();
×
683
        qDebug() << "Loading Solar System data (1: planets and moons) ...";
×
684
        QString solarSystemFile = StelFileMgr::findFile("data/ssystem_major.ini");
×
685
        if (solarSystemFile.isEmpty())
×
686
        {
687
                qWarning() << "ERROR while loading ssystem_major.ini (unable to find data/ssystem_major.ini):" << StelUtils::getEndLineChar();
×
688
                return;
×
689
        }
690

691
        if (!loadPlanets(solarSystemFile))
×
692
        {
693
                qWarning() << "ERROR while loading ssystem_major.ini:" << StelUtils::getEndLineChar();
×
694
                return;
×
695
        }
696

697
        qDebug() << "Loading Solar System data (2: minor bodies) ...";
×
698
        QStringList solarSystemFiles = StelFileMgr::findFileInAllPaths("data/ssystem_minor.ini");
×
699
        if (solarSystemFiles.isEmpty())
×
700
        {
701
                qWarning() << "ERROR while loading ssystem_minor.ini (unable to find data/ssystem_minor.ini):" << StelUtils::getEndLineChar();
×
702
                return;
×
703
        }
704

705
        for (const auto& solarSystemFile : std::as_const(solarSystemFiles))
×
706
        {
707
                if (loadPlanets(solarSystemFile))
×
708
                {
709
                        qDebug() << "File ssystem_minor.ini is loaded successfully...";
×
710
                        break;
×
711
                }
712
                else
713
                {
714
//                        sun.clear();
715
//                        moon.clear();
716
//                        earth.clear();
717
                        //qCritical() << "We should not be here!";
718

719
                        qDebug() << "Removing minor bodies";
×
720
                        for (const auto& p : std::as_const(systemPlanets))
×
721
                        {
722
                                // We can only delete minor objects now!
723
                                if (p->pType >= Planet::isAsteroid)
×
724
                                {
725
                                        p->satellites.clear();
×
726
                                }
727
                        }                        
728
                        systemPlanets.clear();                        
×
729
                        //Memory leak? What's the proper way of cleaning shared pointers?
730

731
                        // TODO: 0.16pre what about the orbits list?
732

733
                        //If the file is in the user data directory, rename it:
734
                        if (solarSystemFile.contains(StelFileMgr::getUserDir()))
×
735
                        {
736
                                QString newName = QString("%1/data/ssystem_minor-%2.ini").arg(StelFileMgr::getUserDir(), QDateTime::currentDateTime().toString("yyyyMMddThhmmss"));
×
737
                                if (QFile::rename(solarSystemFile, newName))
×
738
                                        qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "has been renamed to" << QDir::toNativeSeparators(newName);
×
739
                                else
740
                                {
741
                                        qWarning() << "Invalid Solar System file" << QDir::toNativeSeparators(solarSystemFile) << "cannot be removed!";
×
742
                                        qWarning() << "Please either delete it, rename it or move it elsewhere.";
×
743
                                }
744
                        }
×
745
                }
746
        }
747

748
        shadowPlanetCount = 0;
×
749

750
        for (const auto& planet : std::as_const(systemPlanets))
×
751
                if(planet->parent != sun || !planet->satellites.isEmpty())
×
752
                        shadowPlanetCount++;
×
753
}
×
754

755
unsigned char SolarSystem::BvToColorIndex(double bV)
×
756
{
757
        const double dBV = qBound(-500., static_cast<double>(bV)*1000.0, 3499.);
×
758
        return static_cast<unsigned char>(std::floor(0.5+127.0*((500.0+dBV)/4000.0)));
×
759
}
760

761
bool SolarSystem::loadPlanets(const QString& filePath)
×
762
{
763
        StelSkyDrawer* skyDrawer = StelApp::getInstance().getCore()->getSkyDrawer();
×
764
        qDebug().noquote() << "Loading from:"  << filePath;
×
765
        QSettings pd(filePath, StelIniFormat);
×
766
        if (pd.status() != QSettings::NoError)
×
767
        {
768
                qWarning().noquote() << "ERROR while parsing" << QDir::toNativeSeparators(filePath);
×
769
                return false;
×
770
        }
771

772
        // QSettings does not allow us to say that the sections of the file
773
        // will be listed in the same order  as in the file like the old
774
        // InitParser used to so we can no longer assume that.
775
        //
776
        // This means we must first decide what order to read the sections
777
        // of the file in (each section contains one planet/moon/asteroid/comet/...) to avoid setting
778
        // the parent Planet* to one which has not yet been created.
779
        //
780
        // Stage 1: Make a map of body names back to the section names
781
        // which they come from. Also make a map of body name to parent body
782
        // name. These two maps can be made in a single pass through the
783
        // sections of the file.
784
        //
785
        // Stage 2: Make an ordered list of section names such that each
786
        // item is only ever dependent on items which appear earlier in the
787
        // list.
788
        // 2a: Make a QMultiMap relating the number of levels of dependency
789
        //     to the body name, i.e.
790
        //     0 -> Sun
791
        //     1 -> Mercury
792
        //     1 -> Venus
793
        //     1 -> Earth
794
        //     2 -> Moon
795
        //     etc.
796
        // 2b: Populate an ordered list of section names by iterating over
797
        //     the QMultiMap.  This type of container is always sorted on the
798
        //     key in ascending order, so it's easy.
799
        //     i.e. [sun, earth, moon] is fine, but not [sun, moon, earth]
800
        //
801
        // Stage 3: iterate over the ordered sections decided in stage 2,
802
        // creating the planet objects from the QSettings data.
803

804
        // Stage 1 (as described above).
805
        QMap<QString, QString> secNameMap;
×
806
        QMap<QString, QString> parentMap;
×
807
        QStringList sections = pd.childGroups();
×
808
        // qDebug() << "Stage 1: load ini file with" << sections.size() << "entries: "<< sections;
809
        for (int i=0; i<sections.size(); ++i)
×
810
        {
811
                const QString secname = sections.at(i);
×
812
                const QString englishName = pd.value(secname+"/name", pd.value(secname+"/iau_designation")).toString();
×
813
                if (englishName.isEmpty())
×
814
                        qWarning().noquote() << "SSO without proper name found in" << QDir::toNativeSeparators(filePath) << "section" << secname;
×
815
                const QString strParent = pd.value(secname+"/parent", "Sun").toString();
×
816
                // 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.
817
                QString obName=englishName;
×
818
                const bool isMinor=QStringList({"asteroid", "plutino", "comet", "dwarf planet", "cubewano", "scattered disc object", "oco", "sednoid", "interstellar object"}).contains(pd.value(secname+"/type").toString());
×
819
                if (isMinor && englishName!=L1S("Pluto"))
×
820
                {
821
                        const QString designation = pd.value(secname+"/iau_designation", pd.value(secname+"/minor_planet_number")).toString();
×
822
                        if (designation.isEmpty() && pd.value(secname+"/type") != L1S("comet"))
×
823
                                qWarning().noquote() << "Minor body " << englishName << "has incomplete data (missing iau_designation or minor_planet_number) in" << QDir::toNativeSeparators(filePath) << "section" << secname;
×
824
                        obName=(QString("%1 (%2)").arg(designation, englishName));
×
825
                }
×
826
                if (secNameMap.contains(obName))
×
827
                        qWarning() << "secNameMap already contains " << obName << ". Overwriting data.";
×
828
                secNameMap[obName] = secname;
×
829
                if (strParent!=L1S("none") && !strParent.isEmpty() && !englishName.isEmpty())
×
830
                {
831
                        parentMap[obName] = strParent;
×
832
                        // qDebug() << "parentmap[" << obName << "] = " << strParent;
833
                }
834
        }
×
835

836
        // Stage 2a (as described above).
837
        QMultiMap<int, QString> depLevelMap;
×
838
        for (int i=0; i<sections.size(); ++i)
×
839
        {
840
                const QString secname = sections.at(i);
×
841
                const QString englishName = pd.value(secname+"/name", pd.value(secname+"/iau_designation")).toString();
×
842
                QString obName=englishName;
×
843
                const bool isMinor=QStringList({"asteroid", "plutino", "comet", "dwarf planet", "cubewano", "scattered disc object", "oco", "sednoid", "interstellar object"}).contains(pd.value(secname+"/type").toString());
×
844
                if (isMinor && englishName!=L1S("Pluto"))
×
845
                {
846
                        const QString designation = pd.value(secname+"/iau_designation", pd.value(secname+"/minor_planet_number")).toString();
×
847
                        obName=(QString("%1 (%2)").arg(designation, englishName));
×
848
                }
×
849
                // follow dependencies, incrementing level when we have one till we run out.
850
                QString p=obName;
×
851
                int level = 0;
×
852
                while(parentMap.contains(p) && parentMap[p]!=L1S("none"))
×
853
                {
854
                        level++;
×
855
                        p = parentMap[p];
×
856
                }
857

858
                depLevelMap.insert(level, secNameMap[obName]);
×
859
                // qDebug() << "2a: Level" << level << "secNameMap[" << obName << "]="<< secNameMap[obName];
860
        }
×
861

862
        // Stage 2b (as described above).
863
        // qDebug() << "Stage 2b:";
864
        QStringList orderedSections;
×
865
#if (QT_VERSION>=QT_VERSION_CHECK(6,0,0))
866
        QMultiMapIterator<int, QString> levelMapIt(depLevelMap);
×
867
#else
868
        QMapIterator<int, QString> levelMapIt(depLevelMap);
869
#endif
870
        while(levelMapIt.hasNext())
×
871
        {
872
                levelMapIt.next();
×
873
                orderedSections << levelMapIt.value();
×
874
        }
875
        // qDebug() << orderedSections;
876

877
        // Stage 3 (as described above).
878
        int readOk=0;
×
879
        //int totalPlanets=0;
880

881
        // qDebug() << "Adding " << orderedSections.size() << "objects...";
882
        for (int i = 0;i<orderedSections.size();++i)
×
883
        {
884
                // qDebug() << "Processing entry" << orderedSections.at(i);
885

886
                //totalPlanets++;
887
                const QString secname = orderedSections.at(i);
×
888
                const QString type = pd.value(secname+"/type").toString();
×
889
                QString englishName = pd.value(secname+"/name").toString().simplified();
×
890
                // englishName alone may be a combination of several elements...
891
                if (type==L1S("comet") || type == L1S("interstellar object"))
×
892
                {
893
                        static const QRegularExpression periodicRe("^([1-9][0-9]*[PD](-\\w+)?)"); // No "/" at end, there are nameless numbered comets! (e.g. 362P, 396P)
×
894
                        QRegularExpressionMatch periodMatch=periodicRe.match(englishName);
×
895

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

899
                        // Our name rules for the final englishName, which must contain one element in brackets unless it starts with "A/".
900
                        // Numbered periodic comets: "1P/Halley (1986)"
901
                        // Reclassified Asteroid like "A/2022 B3"
902
                        // All others: C-AX/2023 A2 (discoverer)". (with optional fragment code -AX)
903
                        const QString iauDesignation = pd.value(secname+"/iau_designation").toString();
×
904
                        const QString dateCode =      pd.value(secname+"/date_code").toString();
×
905
                        const QString perihelCode =   pd.value(secname+"/perihelion_code").toString();
×
906
                        const QString discoveryCode = pd.value(secname+"/discovery_code").toString();
×
907
                        if (iauDesignation.isEmpty() && perihelCode.isEmpty() && discoveryCode.isEmpty() && !periodMatch.hasMatch() && !iauDesignationMatch.hasMatch())
×
908
                        {
909
                                qWarning() << "Comet " << englishName << "has no IAU designation, no perihelion code, no discovery code and seems not a numbered comet in section " << secname;
×
910
                        }
911
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
912

913
                        // 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!
914
                        if (iauDesignation.isEmpty() && !englishName.contains("(") && (!discoveryCode.isEmpty()))
×
915
                        {
916
                                        englishName.append(QString(" (%1)").arg(discoveryCode));
×
917
                        }
918
                        else if (iauDesignation.isEmpty() && !englishName.contains("("))
×
919
                        {
920
                                // Prepare perihel year to attach to the name when loading an old ssystem_minor.ini where this name component is missing
921
                                QString periStr;
×
922
                                double periJD=pd.value(secname+"/orbit_TimeAtPericenter").toDouble();
×
923
                                if (periJD)
×
924
                                {
925
                                        int day, month, year;
926
                                        StelUtils::getDateFromJulianDay(periJD, &year, &month, &day);
×
927
                                        periStr=QString::number(year);
×
928
                                }
929
                                if (!periStr.isEmpty())
×
930
                                        englishName.append(QString(" (%1)").arg(periStr));
×
931
                                else
932
                                        qWarning() << "orbit_TimeAtPericenter may be invalid for object" << englishName << "in section" << secname;
×
933
                        }
×
934
                        else if (!iauDesignation.isEmpty() && !englishName.contains("(") && !englishName.contains("/") && !englishName.startsWith("A/"))
×
935
                                englishName=QString("%1 (%2)").arg(iauDesignation, englishName); // recombine name and iau_designation if name is only the discoverer name.
×
936

937
                        if (!englishName.contains("(") && !englishName.startsWith("A/"))
×
938
                        {
939
                                QString name;
×
940
                                if (!iauDesignation.isEmpty())
×
941
                                {
942
                                        name=iauDesignation;
×
943
                                        if (!englishName.isEmpty())
×
944
                                                name.append(QString(" (%1)").arg(englishName));
×
945
                                }
946
                                else if (!dateCode.isEmpty())
×
947
                                {
948
                                        name=dateCode;
×
949
                                        if (!englishName.isEmpty())
×
950
                                                name.append(QString(" (%1)").arg(englishName));
×
951
                                }
952
                                else if (!discoveryCode.isEmpty())
×
953
                                {
954
                                        name=discoveryCode;
×
955
                                        if (!englishName.isEmpty())
×
956
                                                name.append(QString(" (%1)").arg(englishName));
×
957
                                }
958
                                else if (!perihelCode.isEmpty())
×
959
                                {
960
                                        name.append(QString("C/%1").arg(perihelCode)); // This is not classic, but a final fallback before warning
×
961
                                        if (!englishName.isEmpty())
×
962
                                                name.append(QString(" (%1)").arg(englishName));
×
963
                                }
964

965
                                if (name.contains("("))
×
966
                                        englishName=name;
×
967
                                else
968
                                        qWarning() << "Comet " << englishName << "has no proper name elements in section " << secname;
×
969
                        }
×
970
                }
×
971
                else if (QStringList({"asteroid", "dwarf planet", "cubewano", "sednoid", "plutino", "scattered disc object", "Oort cloud object"}).contains(type) && !englishName.contains("Pluto"))
×
972
                {
973
                        const int minorPlanetNumber= pd.value(secname+"/minor_planet_number").toInt();
×
974
                        const QString iauDesignation = pd.value(secname+"/iau_designation", "").toString();
×
975
                        if (iauDesignation.isEmpty() && minorPlanetNumber==0)
×
976
                                qWarning() << "minor body " << englishName << "has no IAU code in section " << secname;
×
977
                        const QString discoveryCode = pd.value(secname+"/discovery_code").toString();
×
978

979
                        // 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
980
                        if (englishName.isEmpty())
×
981
                        {
982
                                //if (minorPlanetNumber>0)
983
                                //        englishName=QString("(%1) ").arg(minorPlanetNumber);
984
                                if (!iauDesignation.isEmpty())
×
985
                                {
986
                                        englishName.append(iauDesignation);
×
987
                                }
988
                                else if (!discoveryCode.isEmpty())
×
989
                                {
990
                                        englishName.append(discoveryCode);
×
991
                                }
992
                                else
993
                                        qWarning() << "Minor body in section" << secname << "has no proper name elements";
×
994
                        }
995
                }
×
996

997
                const double bV = pd.value(secname+"/color_index_bv", 99.).toDouble();
×
998
                const QString strParent = pd.value(secname+"/parent", "Sun").toString(); // Obvious default, keep file entries simple.
×
999
                PlanetP parent;
×
1000
                if (strParent!=L1S("none"))
×
1001
                {
1002
                        // Look in the other planets the one named with strParent
1003
                        for (const auto& p : std::as_const(systemPlanets))
×
1004
                        {
1005
                                if (p->getCommonEnglishName()==strParent)
×
1006
                                {
1007
                                        parent = p;
×
1008
                                        break;
×
1009
                                }
1010
                        }
1011
                        if (parent.isNull())
×
1012
                        {
1013
                                qWarning().noquote().nospace() << "ERROR: can't find parent solar system body for " << englishName << ". Skipping.";
×
1014
                                //abort();
1015
                                continue;
×
1016
                        }
1017
                }
1018
                Q_ASSERT(parent || englishName==L1S("Sun"));
×
1019

1020
                const QString coordFuncName = pd.value(secname+"/coord_func", "kepler_orbit").toString(); // 0.20: new default for all non *_special.
×
1021
                // qDebug() << "englishName:" << englishName << ", parent:" << strParent <<  ", coord_func:" << coordFuncName;
1022
                posFuncType posfunc=Q_NULLPTR;
×
1023
                Orbit* orbitPtr=Q_NULLPTR;
×
1024
                OsculatingFunctType *osculatingFunc = Q_NULLPTR;
×
1025
                bool closeOrbit = true;
×
1026
                double semi_major_axis=0; // used again below.
×
1027

1028

1029
#ifdef USE_GIMBAL_ORBIT
1030
                // undefine the flag in Orbit.h to disable and use the old, static observer solution (on an infinitely slow KeplerOrbit)
1031
                // Note that for now we ignore any orbit-related config values except orbit_SemiMajorAxis from the ini file.
1032
                if (type==L1S("observer"))
×
1033
                {
1034
                        double unit = 1; // AU
×
1035
                        double defaultSemiMajorAxis = 1;
×
1036
                        if (strParent!=L1S("Sun"))
×
1037
                        {
1038
                                unit /= AU;  // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
×
1039
                                defaultSemiMajorAxis *= AU;
×
1040
                        }
1041
                        semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis", defaultSemiMajorAxis).toDouble() * unit;
×
1042
                        // Create a pseudo orbit that allows interaction with keyboard
1043
                        GimbalOrbit *orb = new GimbalOrbit(semi_major_axis, 0.*M_PI_180, 45.*M_PI_180); // [Over mid-north latitude]
×
1044
                        orb->setMinDistance(parent->getEquatorialRadius()*1.5);
×
1045
                        orbits.push_back(orb);
×
1046

1047
                        orbitPtr = orb;
×
1048
                        posfunc = &gimbalOrbitPosFunc;
×
1049
                }
1050
                else
1051
#endif
1052
                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!
×
1053
                {
1054
                        if (coordFuncName!=L1S("kepler_orbit"))
×
1055
                                qDebug() << "Old-fashioned entry" << coordFuncName << "found. Please delete line from " << filePath << "section" << secname;
×
1056
                        // 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.
1057
                        // Read the orbital elements                        
1058
                        const double eccentricity = pd.value(secname+"/orbit_Eccentricity", 0.0).toDouble();
×
1059
                        if (eccentricity >= 1.0) closeOrbit = false;
×
1060
                        double pericenterDistance = pd.value(secname+"/orbit_PericenterDistance",-1e100).toDouble(); // AU, or km for Moons (those where parent!=sun)!
×
1061
                        if (pericenterDistance <= 0.0) {
×
1062
                                semi_major_axis = pd.value(secname+"/orbit_SemiMajorAxis",-1e100).toDouble();
×
1063
                                if (semi_major_axis <= -1e100) {
×
1064
                                        qDebug() << "ERROR loading " << englishName << "from section" << secname
×
1065
                                                 << ": you must provide orbit_PericenterDistance or orbit_SemiMajorAxis. Skipping " << englishName;
×
1066
                                        continue;
×
1067
                                } else {
1068
                                        Q_ASSERT(eccentricity != 1.0); // parabolic orbits have no semi_major_axis
×
1069
                                        pericenterDistance = semi_major_axis * (1.0-eccentricity);
×
1070
                                }
1071
                        } else {
1072
                                semi_major_axis = (eccentricity == 1.0)
×
1073
                                                                ? 0.0 // parabolic orbits have no semi_major_axis
×
1074
                                                                : pericenterDistance / (1.0-eccentricity);
×
1075
                        }
1076
                        if (strParent!=L1S("Sun"))
×
1077
                                pericenterDistance /= AU;  // Planet moons have distances given in km in the .ini file! But all further computation done in AU.
×
1078

1079
                        double meanMotion = pd.value(secname+"/orbit_MeanMotion",-1e100).toDouble(); // degrees/day
×
1080
                        if (meanMotion <= -1e100) {
×
1081
                                const double period = pd.value(secname+"/orbit_Period",-1e100).toDouble();
×
1082
                                if (period <= -1e100) {
×
1083
                                        if (parent->getParent()) {
×
1084
                                                qWarning().noquote() << "ERROR: " << englishName
×
1085
                                                           << ": when the parent body is not the sun, you must provide "
×
1086
                                                           << "either orbit_MeanMotion or orbit_Period";
×
1087
                                        } else {
1088
                                                // in case of parent=sun: use Gaussian gravitational constant for calculating meanMotion:
1089
                                                meanMotion = (eccentricity == 1.0)
×
1090
                                                                        ? 0.01720209895 * (1.5/pericenterDistance) * std::sqrt(0.5/pericenterDistance)  // Heafner: Fund.Eph.Comp. W / dt
×
1091
                                                                        : 0.01720209895 / (fabs(semi_major_axis)*std::sqrt(fabs(semi_major_axis)));
×
1092
                                        }
1093
                                } else {
1094
                                        meanMotion = 2.0*M_PI/period;
×
1095
                                }
1096
                        } else {
1097
                                meanMotion *= (M_PI/180.0);
×
1098
                        }
1099

1100
                        const double ascending_node = pd.value(secname+"/orbit_AscendingNode", 0.0).toDouble()*(M_PI/180.0);
×
1101
                        double arg_of_pericenter = pd.value(secname+"/orbit_ArgOfPericenter",-1e100).toDouble();
×
1102
                        double long_of_pericenter;
1103
                        if (arg_of_pericenter <= -1e100) {
×
1104
                                long_of_pericenter = pd.value(secname+"/orbit_LongOfPericenter", 0.0).toDouble()*(M_PI/180.0);
×
1105
                                arg_of_pericenter = long_of_pericenter - ascending_node;
×
1106
                        } else {
1107
                                arg_of_pericenter *= (M_PI/180.0);
×
1108
                                long_of_pericenter = arg_of_pericenter + ascending_node;
×
1109
                        }
1110

1111
                        double time_at_pericenter = pd.value(secname+"/orbit_TimeAtPericenter",-1e100).toDouble();
×
1112
                        // 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.
1113
                        // However, the distinction is relevant to discern element sets for various valid ranges.
1114
                        // Comet orbits epoch should default to T while planets or moons default to J2000.
1115
                        const double epoch = pd.value(secname+"/orbit_Epoch", type==L1S("comet") ? time_at_pericenter : Planet::J2000).toDouble();
×
1116
                        if (time_at_pericenter <= -1e100) {
×
1117
                                double mean_anomaly = pd.value(secname+"/orbit_MeanAnomaly",-1e100).toDouble()*(M_PI/180.0);
×
1118
                                if (mean_anomaly <= -1e10) {
×
1119
                                        double mean_longitude = pd.value(secname+"/orbit_MeanLongitude",-1e100).toDouble()*(M_PI/180.0);
×
1120
                                        if (mean_longitude <= -1e10) {
×
1121
                                                qWarning().noquote() << "ERROR: " << englishName
×
1122
                                                           << ": when you do not provide orbit_TimeAtPericenter, you must provide orbit_Epoch"
×
1123
                                                           << "and either one of orbit_MeanAnomaly or orbit_MeanLongitude. Skipping this object.";
×
1124
                                                //abort();
1125
                                                continue;
×
1126
                                        } else {
1127
                                                mean_anomaly = mean_longitude - long_of_pericenter;
×
1128
                                        }
1129
                                }
1130
                                time_at_pericenter = epoch - mean_anomaly / meanMotion;
×
1131
                        }
1132

1133
                        static const QMap<QString, double>massMap={ // masses from DE430/431
1134
                                { "Sun",            1.0},
×
1135
                                { "Mercury",  6023682.155592},
×
1136
                                { "Venus",     408523.718658},
×
1137
                                { "Earth",     332946.048834},
×
1138
                                { "Mars",     3098703.590291},
×
1139
                                { "Jupiter",     1047.348625},
×
1140
                                { "Saturn",      3497.901768},
×
1141
                                { "Uranus",     22902.981613},
×
1142
                                { "Neptune",    19412.259776},
×
1143
                                { "Pluto",  135836683.768617}};
×
1144

1145
                        // Construct orbital elements relative to the parent body. This will construct orbits for J2000 only.
1146
                        // Some planet axes move very slowly, this effect could be modelled by replicating these lines
1147
                        // after recomputing obliquity and node (below) in Planet::computeTransMatrix().
1148
                        // The effect is negligible for several millennia, though.
1149
                        // When the parent is the sun use ecliptic rather than sun equator:
1150
                        const double parentRotObliquity  = parent->getParent() ? parent->getRotObliquity(Planet::J2000) : 0.0;
×
1151
                        const double parent_rot_asc_node = parent->getParent() ? parent->getRotAscendingNode()  : 0.0;
×
1152
                        double parent_rot_j2000_longitude = 0.0;
×
1153
                        if (parent->getParent()) {
×
1154
                                const double c_obl = cos(parentRotObliquity);
×
1155
                                const double s_obl = sin(parentRotObliquity);
×
1156
                                const double c_nod = cos(parent_rot_asc_node);
×
1157
                                const double s_nod = sin(parent_rot_asc_node);
×
1158
                                const Vec3d OrbitAxis0( c_nod,       s_nod,        0.0);
×
1159
                                const Vec3d OrbitAxis1(-s_nod*c_obl, c_nod*c_obl,s_obl);
×
1160
                                const Vec3d OrbitPole(  s_nod*s_obl,-c_nod*s_obl,c_obl);
×
1161
                                const Vec3d J2000Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(Vec3d(0,0,1)));
×
1162
                                Vec3d J2000NodeOrigin(J2000Pole^OrbitPole);
×
1163
                                J2000NodeOrigin.normalize();
×
1164
                                parent_rot_j2000_longitude = atan2(J2000NodeOrigin*OrbitAxis1,J2000NodeOrigin*OrbitAxis0);
×
1165
                        }
1166

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

1170
                        // Create a Keplerian orbit. This has been called CometOrbit before 0.20.
1171
                        //qDebug() << "Creating KeplerOrbit for" << parent->englishName << "---" << englishName;
1172
                        KeplerOrbit *orb = new KeplerOrbit(epoch,                  // JDE
1173
                                                           pericenterDistance,     // [AU]
1174
                                                           eccentricity,           // 0..>1 (>>1 for Interstellar objects)
1175
                                                           inclination,            // [radians]
1176
                                                           ascending_node,         // [radians]
1177
                                                           arg_of_pericenter,      // [radians]
1178
                                                           time_at_pericenter,     // JDE
1179
                                                           orbitGoodDays,          // orbitGoodDays. 0=always good, -1=compute_half_orbit_duration
1180
                                                           meanMotion,             // [radians/day]
1181
                                                           parentRotObliquity,     // [radians]
1182
                                                           parent_rot_asc_node,    // [radians]
1183
                                                           parent_rot_j2000_longitude, // [radians]
1184
                                                           1./massMap.value(parent->englishName, 1.)); // central mass [solar masses]
×
1185
                        orbits.push_back(orb);
×
1186

1187
                        orbitPtr = orb;
×
1188
                        posfunc = &keplerOrbitPosFunc;
×
1189
                }
1190
                else
1191
                {
1192
                        static const QMap<QString, posFuncType>posfuncMap={
1193
                                { "sun_special",       &get_sun_barycentric_coordsv},
×
1194
                                { "mercury_special",   &get_mercury_helio_coordsv},
×
1195
                                { "venus_special",     &get_venus_helio_coordsv},
×
1196
                                { "earth_special",     &get_earth_helio_coordsv},
×
1197
                                { "lunar_special",     &get_lunar_parent_coordsv},
×
1198
                                { "mars_special",      &get_mars_helio_coordsv},
×
1199
                                { "phobos_special",    &get_phobos_parent_coordsv},
×
1200
                                { "deimos_special",    &get_deimos_parent_coordsv},
×
1201
                                { "jupiter_special",   &get_jupiter_helio_coordsv},
×
1202
                                { "io_special",        &get_io_parent_coordsv},
×
1203
                                { "europa_special",    &get_europa_parent_coordsv},
×
1204
                                { "ganymede_special",  &get_ganymede_parent_coordsv},
×
1205
                                { "calisto_special",   &get_callisto_parent_coordsv},
×
1206
                                { "callisto_special",  &get_callisto_parent_coordsv},
×
1207
                                { "saturn_special",    &get_saturn_helio_coordsv},
×
1208
                                { "mimas_special",     &get_mimas_parent_coordsv},
×
1209
                                { "enceladus_special", &get_enceladus_parent_coordsv},
×
1210
                                { "tethys_special",    &get_tethys_parent_coordsv},
×
1211
                                { "dione_special",     &get_dione_parent_coordsv},
×
1212
                                { "rhea_special",      &get_rhea_parent_coordsv},
×
1213
                                { "titan_special",     &get_titan_parent_coordsv},
×
1214
                                { "hyperion_special",  &get_hyperion_parent_coordsv},
×
1215
                                { "iapetus_special",   &get_iapetus_parent_coordsv},
×
1216
                                { "helene_special",    &get_helene_parent_coordsv},
×
1217
                                { "telesto_special",   &get_telesto_parent_coordsv},
×
1218
                                { "calypso_special",   &get_calypso_parent_coordsv},
×
1219
                                { "uranus_special",    &get_uranus_helio_coordsv},
×
1220
                                { "miranda_special",   &get_miranda_parent_coordsv},
×
1221
                                { "ariel_special",     &get_ariel_parent_coordsv},
×
1222
                                { "umbriel_special",   &get_umbriel_parent_coordsv},
×
1223
                                { "titania_special",   &get_titania_parent_coordsv},
×
1224
                                { "oberon_special",    &get_oberon_parent_coordsv},
×
1225
                                { "neptune_special",   &get_neptune_helio_coordsv},
×
1226
                                { "pluto_special",     &get_pluto_helio_coordsv}};
×
1227
                        static const QMap<QString, OsculatingFunctType*>osculatingMap={
1228
                                { "mercury_special",   &get_mercury_helio_osculating_coords},
×
1229
                                { "venus_special",     &get_venus_helio_osculating_coords},
×
1230
                                { "earth_special",     &get_earth_helio_osculating_coords},
×
1231
                                { "mars_special",      &get_mars_helio_osculating_coords},
×
1232
                                { "jupiter_special",   &get_jupiter_helio_osculating_coords},
×
1233
                                { "saturn_special",    &get_saturn_helio_osculating_coords},
×
1234
                                { "uranus_special",    &get_uranus_helio_osculating_coords},
×
1235
                                { "neptune_special",   &get_neptune_helio_osculating_coords}};
×
1236
                        posfunc=posfuncMap.value(coordFuncName, Q_NULLPTR);
×
1237
                        osculatingFunc=osculatingMap.value(coordFuncName, Q_NULLPTR);
×
1238
                }
1239
                if (posfunc==Q_NULLPTR)
×
1240
                {
1241
                        qCritical() << "ERROR in section " << secname << ": can't find posfunc " << coordFuncName << " for " << englishName;
×
1242
                        exit(-1);
×
1243
                }
1244

1245
                // Create the Solar System body and add it to the list
1246
                //TODO: Refactor the subclass selection to reduce duplicate code mess here,
1247
                // by at least using this base class pointer and using setXXX functions instead of mega-constructors
1248
                // that have to pass most of it on to the Planet class
1249
                PlanetP newP;
×
1250

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

1258
                        Vec3f color = Vec3f(1.f, 1.f, 1.f);
×
1259
                        if (bV<99.)
×
1260
                                color = skyDrawer->indexToColor(BvToColorIndex(bV))*0.75f; // see ZoneArray.cpp:L490
×
1261
                        else
1262
                                color = Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString());
×
1263

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

1268
                        newP = PlanetP(new MinorPlanet(englishName,
×
1269
                                                    pd.value(secname+"/radius", 0.0).toDouble()/AU,
×
1270
                                                    pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1271
                                                    color, // halo color
1272
                                                    pd.value(secname+"/albedo", 0.0f).toFloat(),
×
1273
                                                    pd.value(secname+"/roughness",0.9f).toFloat(),
×
1274
                                                    pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1275
                                                    pd.value(secname+"/normals_map", normalMapName).toString(),
×
1276
                                                    pd.value(secname+"/horizon_map", horizonMapName).toString(),
×
1277
                                                    pd.value(secname+"/model").toString(),
×
1278
                                                    posfunc,
1279
                                                    static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object created previously
1280
                                                    osculatingFunc, // should be Q_NULLPTR
1281
                                                    closeOrbit,
1282
                                                    hidden,
1283
                                                    type));
×
1284
                        QSharedPointer<MinorPlanet> mp =  newP.dynamicCast<MinorPlanet>();
×
1285
                        //Number, IAU provisional designation
1286
                        mp->setMinorPlanetNumber(pd.value(secname+"/minor_planet_number", 0).toInt());
×
1287
                        mp->setIAUDesignation(pd.value(secname+"/iau_designation", "").toString());
×
1288

1289
                        //H-G magnitude system
1290
                        const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1291
                        const float slope = pd.value(secname+"/slope_parameter", 0.15f).toFloat();
×
1292
                        if (magnitude > -99.f)
×
1293
                        {
1294
                                mp->setAbsoluteMagnitudeAndSlope(magnitude, qBound(0.0f, slope, 1.0f));
×
1295
                                mp->updateEquatorialRadius();
×
1296
                        }
1297

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

1301
                        // Discovery circumstances
1302
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1303
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1304
                        if (!discoveryDate.isEmpty())
×
1305
                                mp->setDiscoveryData(discoveryDate, discovererName);
×
1306

1307
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
1308
                        QStringList codes = { pd.value(secname+"/date_code", "").toString(),
×
1309
                                              pd.value(secname+"/perihelion_code", "").toString(),
×
1310
                                              pd.value(secname+"/discovery_code", "").toString() };
×
1311
                        codes.removeAll("");
×
1312
                        if (codes.count()>0)
×
1313
                                mp->setExtraDesignations(codes);
×
1314

1315
                        if (semi_major_axis>0)
×
1316
                                mp->deltaJDE = 2.0*semi_major_axis*StelCore::JD_SECOND;
×
1317
                         else if (semi_major_axis<=0.0 && type!=L1S("interstellar object"))
×
1318
                                qWarning().noquote() << "WARNING: Minor body" << englishName << "has no semimajor axis!";
×
1319

1320
                        systemMinorBodies.push_back(newP);
×
1321
                }
×
1322
                else if (type == L1S("comet"))
×
1323
                {
1324
                        minorBodies << englishName;
×
1325
                        newP = PlanetP(new Comet(englishName,
×
1326
                                              pd.value(secname+"/radius", 5.0).toDouble()/AU,
×
1327
                                              pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1328
                                              Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
×
1329
                                              pd.value(secname+"/albedo", 0.075f).toFloat(), // assume very dark surface
×
1330
                                              pd.value(secname+"/roughness",0.9f).toFloat(),
×
1331
                                              pd.value(secname+"/outgas_intensity",0.1f).toFloat(),
×
1332
                                              pd.value(secname+"/outgas_falloff", 0.1f).toFloat(),
×
1333
                                              pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1334
                                              pd.value(secname+"/model").toString(),
×
1335
                                              posfunc,
1336
                                              static_cast<KeplerOrbit*>(orbitPtr), // the KeplerOrbit object
1337
                                              osculatingFunc, // ALWAYS NULL for comets.
1338
                                              closeOrbit,
1339
                                              pd.value(secname+"/hidden", false).toBool(),
×
1340
                                              type,
1341
                                              pd.value(secname+"/dust_widthfactor", 1.5f).toFloat(),
×
1342
                                              pd.value(secname+"/dust_lengthfactor", 0.4f).toFloat(),
×
1343
                                              pd.value(secname+"/dust_brightnessfactor", 1.5f).toFloat()
×
1344
                                              ));
×
1345
                        QSharedPointer<Comet> comet = newP.dynamicCast<Comet>();
×
1346

1347
                        //g,k magnitude system
1348
                        const float magnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1349
                        const float slope = qBound(-5.0f, pd.value(secname+"/slope_parameter", 4.0f).toFloat(), 30.0f);
×
1350
                        if (magnitude > -99.f)
×
1351
                                        comet->setAbsoluteMagnitudeAndSlope(magnitude, slope);
×
1352

1353
                        QString iauDesignation = pd.value(secname+"/iau_designation", "").toString();
×
1354
                        if (!iauDesignation.isEmpty())
×
1355
                                comet->setIAUDesignation(iauDesignation);
×
1356
                        // order of codes: date_code [P/1982 U1] - perihelion_code [1986 III] - discovery_code [1982i]
1357
                        QStringList codes = { pd.value(secname+"/date_code", "").toString(),
×
1358
                                              pd.value(secname+"/perihelion_code", "").toString(),
×
1359
                                              pd.value(secname+"/discovery_code", "").toString() };
×
1360
                        codes.removeAll("");
×
1361
                        if (codes.count()>0)
×
1362
                                comet->setExtraDesignations(codes);
×
1363

1364
                        // Discovery circumstances
1365
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1366
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1367
                        if (!discoveryDate.isEmpty())
×
1368
                                comet->setDiscoveryData(discoveryDate, discovererName);
×
1369

1370
                        systemMinorBodies.push_back(newP);
×
1371
                }
×
1372
                else // type==star|planet|moon|dwarf planet|observer|artificial
1373
                {
1374
                        //qDebug() << type;
1375
                        Q_ASSERT(type==L1S("star") || type==L1S("planet") || type==L1S("moon") || type==L1S("artificial") || type==L1S("observer") || type==L1S("dwarf planet")); // TBD: remove Pluto...
×
1376
                        // Set possible default name of the normal map for avoiding yin-yang shaped moon
1377
                        // phase when normal map key not exists. Example: moon_normals.png
1378
                        // Details: https://bugs.launchpad.net/stellarium/+bug/1335609                        
1379
                        newP = PlanetP(new Planet(englishName,
×
1380
                                               pd.value(secname+"/radius", 1.0).toDouble()/AU,
×
1381
                                               pd.value(secname+"/oblateness", 0.0).toDouble(),
×
1382
                                               Vec3f(pd.value(secname+"/color", "1.0,1.0,1.0").toString()), // halo color
×
1383
                                               pd.value(secname+"/albedo", 0.25f).toFloat(),
×
1384
                                               pd.value(secname+"/roughness",0.9f).toFloat(),
×
1385
                                               pd.value(secname+"/tex_map", "nomap.png").toString(),
×
1386
                                               pd.value(secname+"/normals_map", englishName.toLower().append("_normals.png")).toString(),
×
1387
                                               pd.value(secname+"/horizon_map", englishName.toLower().append("_horizon.png")).toString(),
×
1388
                                               pd.value(secname+"/model").toString(),
×
1389
                                               posfunc,
1390
                                               static_cast<KeplerOrbit*>(orbitPtr), // This remains Q_NULLPTR for the major planets, or has a KeplerOrbit for planet moons.
1391
                                               osculatingFunc,
1392
                                               closeOrbit,
1393
                                               pd.value(secname+"/hidden", false).toBool(),
×
1394
                                               pd.value(secname+"/atmosphere", false).toBool(),
×
1395
                                               pd.value(secname+"/halo", true).toBool(),
×
1396
                                               type));
×
1397
                        newP->absoluteMagnitude = pd.value(secname+"/absolute_magnitude", -99.f).toFloat();
×
1398
                        newP->massKg = pd.value(secname+"/mass_kg", 0.).toDouble();
×
1399

1400
                        // Moon designation (planet index + IAU moon number)
1401
                        QString moonDesignation = pd.value(secname+"/iau_moon_number", "").toString();
×
1402
                        if (!moonDesignation.isEmpty())
×
1403
                                newP->setIAUMoonNumber(moonDesignation);
×
1404
                        newP->setColorIndexBV(static_cast<float>(bV));
×
1405
                        // Discovery circumstances
1406
                        QString discovererName = pd.value(secname+"/discoverer", "").toString();
×
1407
                        QString discoveryDate = pd.value(secname+"/discovery", "").toString();
×
1408
                        if (!discoveryDate.isEmpty())
×
1409
                                newP->setDiscoveryData(discoveryDate, discovererName);
×
1410
                }
×
1411

1412
                if (!parent.isNull())
×
1413
                {
1414
                        parent->satellites.append(newP);
×
1415
                        newP->parent = parent;
×
1416
                }
1417
                if (secname==L1S("earth")) earth = newP;
×
1418
                if (secname==L1S("sun")) sun = newP;
×
1419
                if (secname==L1S("moon")) moon = newP;
×
1420

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

1424
                // There are two ways of defining the axis orientation:
1425
                // obliquity and ascending node, which was used by Stellarium already before 2010 (based on Celestia?).
1426
                double rotObliquity = pd.value(secname+"/rot_obliquity",0.).toDouble()*(M_PI_180);
×
1427
                double rotAscNode = pd.value(secname+"/rot_equator_ascending_node",0.).toDouble()*(M_PI_180);
×
1428
                // rot_periode given in hours (from which rotPeriod in days),
1429
                // The default is useful for many moons in bound rotation
1430
                double rotPeriod=pd.value(secname+"/rot_periode", pd.value(secname+"/orbit_Period", 1.).toDouble()*24.).toDouble()/24.;
×
1431
                double rotOffset=pd.value(secname+"/rot_rotation_offset",0.).toDouble();
×
1432

1433
                // 0.21+: Use WGCCRE planet North pole data if available
1434
                // NB: N pole for J2000 epoch as defined by IAU (NOT right hand rotation rule)
1435
                // Define only basic motion. Use special functions for more complicated axes.
1436
                const double J2000NPoleRA  = pd.value(secname+"/rot_pole_ra",  0.).toDouble()*M_PI_180;
×
1437
                const double J2000NPoleRA1 = pd.value(secname+"/rot_pole_ra1", 0.).toDouble()*M_PI_180;
×
1438
                const double J2000NPoleDE  = pd.value(secname+"/rot_pole_de",  0.).toDouble()*M_PI_180;
×
1439
                const double J2000NPoleDE1 = pd.value(secname+"/rot_pole_de1", 0.).toDouble()*M_PI_180;
×
1440
                const double J2000NPoleW0  = pd.value(secname+"/rot_pole_w0",  0.).toDouble(); // [degrees]   Basically the same idea as rot_rotation_offset, but W!=rotAngle
×
1441
                const double J2000NPoleW1  = pd.value(secname+"/rot_pole_w1",  0.).toDouble(); // [degrees/d] Basically the same idea as 360/rot_periode
×
1442
                if (fabs(J2000NPoleW1) > 0.0) // Patch possibly old period value with a more modern value.
×
1443
                {
1444
                        // this is just another expression for rotational speed.
1445
                        rotPeriod=360.0/J2000NPoleW1;
×
1446
                }
1447

1448
                // IMPORTANT: For the planet moons with orbits relative to planets' equator plane,
1449
                // re-compute the important bits from the updated axis elements.
1450
                // Reactivated to re-establish Pluto/Charon lock #153
1451
                if((J2000NPoleRA!=0.) || (J2000NPoleDE!=0.))
×
1452
                {
1453
                        // If available, recompute obliquity and AscNode from the new data.
1454
                        // Solution since 0.16: Make this once for J2000.
1455
                        // Optional (future?): Repeat this block in Planet::computeTransMatrix() for planets with moving axes and update all Moons' KeplerOrbit if required.
1456
                        Vec3d J2000NPole;
×
1457
                        StelUtils::spheToRect(J2000NPoleRA,J2000NPoleDE,J2000NPole);
×
1458

1459
                        Vec3d vsop87Pole(StelCore::matJ2000ToVsop87.multiplyWithoutTranslation(J2000NPole));
×
1460

1461
                        double lon, lat;
1462
                        StelUtils::rectToSphe(&lon, &lat, vsop87Pole);
×
1463

1464
                        rotObliquity = (M_PI_2 - lat);
×
1465
                        rotAscNode = (lon + M_PI_2);
×
1466

1467
                        //qDebug() << englishName << ": Compare these values to the older data in ssystem_major";
1468
                        //qDebug() << "\tCalculated rotational obliquity: " << rotObliquity*180./M_PI;
1469
                        //qDebug() << "\tCalculated rotational ascending node: " << rotAscNode*180./M_PI;
1470

1471
                        if (J2000NPoleW0 >0)
×
1472
                        {
1473
                                // W0 is counted from the ascending node with ICRF, but rotOffset from orbital plane.
1474
                                // Try this assumption by just counting Offset=W0+90+RA0.
1475
                                rotOffset=J2000NPoleW0 + lon*M_180_PI;
×
1476
                                //qDebug() << "\tCalculated rotational period (days // hours): " << rotPeriod << "//" << rotPeriod*24.;
1477
                                //qDebug() << "\tRotational offset (degrees): " << rotOffset;
1478
                        }
1479
                }
1480
                newP->setRotationElements(
×
1481
                        englishName,
1482
                        rotPeriod,
1483
                        rotOffset,
1484
                        pd.value(secname+"/rot_epoch", Planet::J2000).toDouble(),
×
1485
                        rotObliquity,
1486
                        rotAscNode,
1487
                        J2000NPoleRA,
1488
                        J2000NPoleRA1,
1489
                        J2000NPoleDE,
1490
                        J2000NPoleDE1,
1491
                        J2000NPoleW0,
1492
                        J2000NPoleW1);
1493
                // orbit_Period given in days.
1494
                // Elliptical Kepler orbits (ecc<0.9) will replace whatever is given by a value computed on the fly. Parabolic objects show 0.
1495
                newP->setSiderealPeriod(fabs(pd.value(secname+"/orbit_Period", 0.).toDouble()));
×
1496

1497
                if (pd.contains(secname+"/tex_ring")) {
×
1498
                        const float rMin = pd.value(secname+"/ring_inner_size").toFloat()/AUf;
×
1499
                        const float rMax = pd.value(secname+"/ring_outer_size").toFloat()/AUf;
×
1500
                        Ring *r = new Ring(rMin,rMax,pd.value(secname+"/tex_ring").toString());
×
1501
                        newP->setRings(r);
×
1502
                }
1503

1504
                systemPlanets.push_back(newP);
×
1505
                readOk++;
×
1506
        }
×
1507

1508
        // special case: load earth shadow texture
1509
        if (!Planet::texEarthShadow)
×
1510
                Planet::texEarthShadow = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/earth-shadow.png");
×
1511

1512
        // Also comets just have static textures.
1513
        if (!Comet::comaTexture)
×
1514
                Comet::comaTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometComa.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
×
1515
        //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.
1516
        if (!Comet::tailTexture)
×
1517
                Comet::tailTexture = StelApp::getInstance().getTextureManager().createTextureThread(StelFileMgr::getInstallationDir()+"/textures/cometTail.png", StelTexture::StelTextureParams(true, GL_LINEAR, GL_CLAMP_TO_EDGE));
×
1518

1519
        if (readOk==0)
×
1520
                qWarning().noquote() << "No Solar System objects loaded from" << QDir::toNativeSeparators(filePath);
×
1521
        else
1522
                qDebug() << "Loaded" << readOk << "Solar System bodies from " << filePath;
×
1523
        qDebug() << "Solar System now has" << systemPlanets.count() << "entries.";
×
1524
        return readOk>0;
×
1525
}
×
1526

1527
// Compute the position for every elements of the solar system.
1528
// The order is not important since the position is computed relatively to the mother body
1529
void SolarSystem::computePositions(StelCore *core, double dateJDE, PlanetP observerPlanet)
×
1530
{
1531
        const StelObserver *obs=core->getCurrentObserver();
×
1532
        const bool withAberration=core->getUseAberration();
×
1533
        // 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.
1534
        // 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.)
1535
        static bool threadMessage=true;
1536
        if (threadMessage)
×
1537
        {
1538
                qDebug() << "SolarSystem: We have configured" << extraThreads << "threads (plus main thread) for computePositions().";
×
1539
                if (extraThreads > QThreadPool::globalInstance()->maxThreadCount()-1)
×
1540
                {
1541
                        qDebug() << "This is more than the maximum additional thread count (" << QThreadPool::globalInstance()->maxThreadCount()-1 << ").";
×
1542
                        qDebug() << "Consider reducing this number to avoid oversubscription.";
×
1543
                }
1544
                threadMessage=false;
×
1545
        }
1546

1547
        if (flagLightTravelTime) // switching off light time correction implies no aberration for the planets.
×
1548
        {
1549
                const StelObserver *obs=core->getCurrentObserver();
×
1550
                const bool observerPlanetIsEarth = observerPlanet==getEarth();
×
1551
                //static StelObjectMgr* omgr=GETSTELMODULE(StelObjectMgr);
1552
                //omgr->removeExtraInfoStrings(StelObject::DebugAid);
1553

1554
                switch (computePositionsAlgorithm)
×
1555
                {
1556
                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.
×
1557
                {
1558
                        // Position of this planet will be used in the subsequent computations
1559
                        observerPlanet->computePosition(obs, dateJDE, Vec3d(0.));
×
1560
                        const bool observerIsEarth = observerPlanet->englishName==L1S("Earth");
×
1561
                        const Vec3d obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1562
                        const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1563
                        const double dateJD = dateJDE - (core->computeDeltaT(dateJDE))/86400.0;
×
1564

1565
                        const auto processPlanet = [this,dateJD,dateJDE,observerIsEarth,withAberration,observerPlanet,
×
1566
                                                   obsPosJDE,aberrationPushSpeed,obs](const PlanetP& p, const Vec3d& observerPosFinal)
1567
                        {
1568
                                // 1. First approximation.
1569
                                p->computePosition(obs, dateJDE, Vec3d(0.));
×
1570

1571
                                // For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1572
                                // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1573
                                // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1574
                                // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1575
                                // used ephemerides already provide aberration-corrected positions for the Moon?
1576
                                Vec3d planetPos = p->getHeliocentricEclipticPos();
×
1577
                                double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1578
                                const bool needToApplyAberration = withAberration && (!observerIsEarth || p != getMoon());
×
1579
                                Vec3d aberrationPush(0.);
×
1580
                                if(needToApplyAberration)
×
1581
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1582
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1583

1584
                                // Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1585
                                planetPos = p->getHeliocentricEclipticPos();
×
1586
                                lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1587
                                if(needToApplyAberration)
×
1588
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1589
                                // The next call may already do nothing if the time difference to the previous round is not large enough.
1590
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1591

1592
                                const auto update = &RotationElements::updatePlanetCorrections;
×
1593
                                if      (p->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1594
                                else if (p->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1595
                                else if (p->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1596
                                else if (p->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1597
                                else if (p->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1598
                                else if (p->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1599

1600
                                if(p != observerPlanet)
×
1601
                                {
1602
                                        const double light_speed_correction = (AU / (SPEED_OF_LIGHT * 86400)) *
1603
                                                                              (p->getHeliocentricEclipticPos()-obsPosJDE).norm();
×
1604
                                        p->computeTransMatrix(dateJD-light_speed_correction, dateJDE-light_speed_correction);
×
1605
                                }
1606
                        };
×
1607

1608
                        // This will be used for computation of transformation matrices
1609
                        processPlanet(observerPlanet, Vec3d(0.));
×
1610
                        observerPlanet->computeTransMatrix(dateJD, dateJDE);
×
1611
                        const Vec3d observerPosFinal = observerPlanet->getHeliocentricEclipticPos();
×
1612

1613
                        // Threadable loop function for self-set number of additional worker threads
1614
                        const auto loop = [&planets=std::as_const(systemPlanets),processPlanet,
×
1615
                                          observerPosFinal](const int indexMin, const int indexMax)
1616
                        {
1617
                                for(int i = indexMin; i <= indexMax; ++i)
×
1618
                                        processPlanet(planets[i], observerPosFinal);
×
1619
                        };
×
1620

1621
                        QList<QFuture<void>> futures;
×
1622
                        const int totalThreads = extraThreads+1;
×
1623
                        const auto blockSize = systemPlanets.size() / totalThreads;
×
1624
                        for(int threadN=0; threadN<totalThreads-1; ++threadN)
×
1625
                        {
1626
                                const int indexMin = blockSize*threadN;
×
1627
                                const int indexMax = blockSize*(threadN+1)-1;
×
1628
                                futures.append(QtConcurrent::run(loop, indexMin,indexMax));
×
1629
                        }
1630
                        // and the last thread is the current one
1631
                        loop(blockSize*(totalThreads-1), systemPlanets.size()-1);
×
1632
                        for(auto& f : futures)
×
1633

1634
                                f.waitForFinished();
×
1635
                }
×
1636
                break;
×
1637
                case 2:
×
1638
                {
1639
                        // Better 3-loop solution. This is still following the original solution:
1640
                        // First, compute approximate positions at JDE.
1641
                        // Then for each object, compute light time and repeat light-time corrected.
1642
                        // Third, check new light time, and recompute once more if needed.
1643

1644
                        // 1. First approximation.
1645
                        QList<QFuture<void>> futures;
×
1646
                        // This defines a function to be thrown onto a pool thread that computes every 'incr'th element.
1647
                        auto plCompLoopZero = [=](int offset){
×
1648
                                for (auto it=systemPlanets.cbegin()+offset, end=systemPlanets.cend(); it<end; it+=(extraThreads+1))
×
1649
                                {
1650
                                        it->data()->computePosition(obs, dateJDE, Vec3d(0.));
×
1651
                                }
1652
                        };
×
1653

1654
                        // Move to external threads, but also run a part in the main thread. The index 'availableThreads' is just the last group of objects.
1655
                        for (int stride=0; stride<extraThreads; stride++)
×
1656
                        {
1657
                                auto future=QtConcurrent::run(plCompLoopZero, stride);
×
1658
                                futures.append(future);
×
1659
                        }
×
1660
                        plCompLoopZero(extraThreads);
×
1661

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
                        const Vec3d &obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1668

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

1676
                        auto plCompLoopOne = [=](int offset){
×
1677
                                for (auto it=systemPlanets.cbegin()+offset, end=systemPlanets.cend(); it<end; it+=extraThreads+1)
×
1678
                                {
1679
                                        const auto planetPos = it->data()->getHeliocentricEclipticPos();
×
1680
                                        const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1681
                                        Vec3d aberrationPush(0.);
×
1682
                                        if (withAberration && (!observerPlanetIsEarth || it->data() != getMoon()))
×
1683
                                                aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1684
                                        it->data()->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1685
                                }
1686
                        };
×
1687
                        for (int stride=0; stride<extraThreads; stride++)
×
1688
                        {
1689
                                auto future=QtConcurrent::run(plCompLoopOne, stride);
×
1690
                                futures.append(future);
×
1691
                        }
×
1692
                        plCompLoopOne(extraThreads); // main thread's share of the computation task
×
1693
                        // Now the list is being computed by other threads. we can just wait sequentially for completion.
1694
                        for(auto f: futures)
×
1695
                                f.waitForFinished();
×
1696
                        futures.clear();
×
1697

1698
                        // 3. Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1699
                        auto plCompLoopTwo = [=](int offset){
×
1700
                                for (auto it=systemPlanets.cbegin()+offset, end=systemPlanets.cend(); it<end; it+=extraThreads+1)
×
1701
                                {
1702
                                        const auto planetPos = it->data()->getHeliocentricEclipticPos();
×
1703
                                        const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1704
                                        Vec3d aberrationPush(0.);
×
1705
                                        if (withAberration && (!observerPlanetIsEarth || it->data() != getMoon()))
×
1706
                                                aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1707
                                        // The next call may already do nothing if the time difference to the previous round is not large enough.
1708
                                        it->data()->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1709
                                        //it->data()->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1710
                                        //                                                        .arg(QString::number(lightTimeDays, 'f', 3))
1711
                                        //                                                        .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1712
                                        //                                                        .arg(QString::number(aberrationPushSpeed[1], 'f', 3))
1713
                                        //                                                        .arg(QString::number(aberrationPushSpeed[2], 'f', 3)));
1714

1715
                                        const auto update = &RotationElements::updatePlanetCorrections;
×
1716
                                        if      (it->data()->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1717
                                        else if (it->data()->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1718
                                        else if (it->data()->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1719
                                        else if (it->data()->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1720
                                        else if (it->data()->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1721
                                        else if (it->data()->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1722
                                }
1723
                        };
×
1724
                        for (int stride=0; stride<extraThreads; stride++)
×
1725
                        {
1726
                                auto future=QtConcurrent::run(plCompLoopTwo, stride);
×
1727
                                futures.append(future);
×
1728
                        }
×
1729
                        // At this point all available threads from the global ThreadPool should be active:
1730
                        //omgr->addToExtraInfoString(StelObject::DebugAid, QString("Threads: Ideal: %1, Pool max %2/active %3, SolarSystem using %4<br/>").
1731
                        //                           arg(QString::number(QThread::idealThreadCount()),
1732
                        //                               QString::number(QThreadPool::globalInstance()->maxThreadCount()),
1733
                        //                               QString::number(QThreadPool::globalInstance()->activeThreadCount()),
1734
                        //                               QString::number(extraThreads)));
1735
                        // and we still run the last stride in the main thread.
1736
                        plCompLoopTwo(extraThreads);
×
1737
                        // Now the list is being computed by other threads. we can just wait sequentially for completion.
1738
                        for(auto f: futures)
×
1739
                                f.waitForFinished();
×
1740
                        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1741
                }
×
1742
                break;
×
1743
                case 1: // Simple multithreading with QtConcurrent::blockingMap(). 3-loop solution. This is closely following the original solution:
×
1744
                {
1745
                        // First, compute approximate positions at JDE.
1746
                        // Then for each object, compute light time and repeat light-time corrected.
1747
                        // Third, check new light time, and recompute if needed.
1748

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

1753
                        const Vec3d &obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1754

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

1762
                        auto plCompPosJDEOne = [=](QSharedPointer<Planet> &p){
×
1763
                                const Vec3d planetPos = p->getHeliocentricEclipticPos();
×
1764
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1765
                                Vec3d aberrationPush(0.);
×
1766
                                if (withAberration && (!observerPlanetIsEarth || p != getMoon() ))
×
1767
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1768
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1769
                        };
×
1770
                        QtConcurrent::blockingMap(systemPlanets, plCompPosJDEOne);
×
1771

1772
                        // 3. Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1773
                        auto plCompPosJDETwo = [=](QSharedPointer<Planet> &p){
×
1774
                                const Vec3d planetPos = p->getHeliocentricEclipticPos();
×
1775
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1776
                                Vec3d aberrationPush(0.);
×
1777
                                if (withAberration && (!observerPlanetIsEarth || p != getMoon() ))
×
1778
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1779
                                // The next call may already do nothing if the time difference to the previous round is not large enough.
1780
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1781
                                //p->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1782
                                //                                              .arg(QString::number(lightTimeDays, 'f', 3))
1783
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1784
                                //                                              .arg(QString::number(aberrationPushSpeed[1], 'f', 3))
1785
                                //                                              .arg(QString::number(aberrationPushSpeed[2], 'f', 3)));
1786

1787
                                const auto update = &RotationElements::updatePlanetCorrections;
×
1788
                                if      (p->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1789
                                else if (p->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1790
                                else if (p->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1791
                                else if (p->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1792
                                else if (p->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1793
                                else if (p->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1794
                        };
×
1795
                        QtConcurrent::blockingMap(systemPlanets, plCompPosJDETwo);
×
1796
                        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1797
                }
1798
                break;
×
1799
                case 0:
×
1800
                default: // Original single-threaded.
1801
                {
1802
                        // First, compute approximate positions at JDE.
1803
                        // Then for each object, compute light time and repeat light-time corrected.
1804
                        // Third, check new light time, and recompute if needed.
1805

1806
                        for (const auto& p : std::as_const(systemPlanets))
×
1807
                        {
1808
                                p->computePosition(obs, dateJDE, Vec3d(0.));
×
1809
                        }
1810
                        const Vec3d obsPosJDE=observerPlanet->getHeliocentricEclipticPos();
×
1811

1812
                        // For higher accuracy, we now make two iterations of light time and aberration correction. In the final
1813
                        // round, we also compute rotation data.  May fix sub-arcsecond inaccuracies, and optionally apply
1814
                        // aberration in the way described in Explanatory Supplement (2013), 7.55.  For reasons unknown (See
1815
                        // discussion in GH:#1626) we do not add anything for the Moon when observed from Earth!  Presumably the
1816
                        // used ephemerides already provide aberration-corrected positions for the Moon?
1817
                        const Vec3d aberrationPushSpeed=observerPlanet->getHeliocentricEclipticVelocity() * core->getAberrationFactor();
×
1818
                        for (const auto& p : std::as_const(systemPlanets))
×
1819
                        {
1820
                                //p->setExtraInfoString(StelObject::DebugAid, "");
1821
                                const auto planetPos = p->getHeliocentricEclipticPos();
×
1822
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1823
                                Vec3d aberrationPush(0.);
×
1824
                                if (withAberration && (observerPlanet->englishName!=L1S("Earth") || p->englishName!=L1S("Moon")))
×
1825
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1826
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1827
                        }
1828
                        // Extra accuracy with another round. Not sure if useful. Maybe hide behind a new property flag?
1829
                        for (const auto& p : std::as_const(systemPlanets))
×
1830
                        {
1831
                                //p->setExtraInfoString(StelObject::DebugAid, "");
1832
                                const auto planetPos = p->getHeliocentricEclipticPos();
×
1833
                                const double lightTimeDays = (planetPos-obsPosJDE).norm() * (AU / (SPEED_OF_LIGHT * 86400.));
×
1834
                                Vec3d aberrationPush(0.);
×
1835
                                if (withAberration && (observerPlanet->englishName!=L1S("Earth") || p->englishName!=L1S("Moon")))
×
1836
                                        aberrationPush=lightTimeDays*aberrationPushSpeed;
×
1837
                                // The next call may already do nothing if the time difference to the previous round is not large enough.
1838
                                p->computePosition(obs, dateJDE-lightTimeDays, aberrationPush);
×
1839
                                //p->setExtraInfoString(StelObject::DebugAid, QString("LightTime %1d; obsSpeed %2/%3/%4 AU/d")
1840
                                //                                              .arg(QString::number(lightTimeDays, 'f', 3))
1841
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1842
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3))
1843
                                //                                              .arg(QString::number(aberrationPushSpeed[0], 'f', 3)));
1844

1845
                                const auto update = &RotationElements::updatePlanetCorrections;
×
1846
                                if      (p->englishName==L1S("Moon"))    update(dateJDE-lightTimeDays, RotationElements::EarthMoon);
×
1847
                                else if (p->englishName==L1S("Mars"))    update(dateJDE-lightTimeDays, RotationElements::Mars);
×
1848
                                else if (p->englishName==L1S("Jupiter")) update(dateJDE-lightTimeDays, RotationElements::Jupiter);
×
1849
                                else if (p->englishName==L1S("Saturn"))  update(dateJDE-lightTimeDays, RotationElements::Saturn);
×
1850
                                else if (p->englishName==L1S("Uranus"))  update(dateJDE-lightTimeDays, RotationElements::Uranus);
×
1851
                                else if (p->englishName==L1S("Neptune")) update(dateJDE-lightTimeDays, RotationElements::Neptune);
×
1852
                        }
1853
                        computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1854
                } // end of default (original single-threaded) solution
1855

1856
                }
1857
        }
1858
        else
1859
        {
1860
                for (const auto& p : std::as_const(systemPlanets))
×
1861
                {
1862
                        //p->setExtraInfoString(StelObject::DebugAid, "");
1863
                        p->computePosition(obs, dateJDE, Vec3d(0.));
×
1864
                        const auto update = &RotationElements::updatePlanetCorrections;
×
1865
                        if      (p->englishName==L1S("Moon"))    update(dateJDE, RotationElements::EarthMoon);
×
1866
                        else if (p->englishName==L1S("Mars"))    update(dateJDE, RotationElements::Mars);
×
1867
                        else if (p->englishName==L1S("Jupiter")) update(dateJDE, RotationElements::Jupiter);
×
1868
                        else if (p->englishName==L1S("Saturn"))  update(dateJDE, RotationElements::Saturn);
×
1869
                        else if (p->englishName==L1S("Uranus"))  update(dateJDE, RotationElements::Uranus);
×
1870
                        else if (p->englishName==L1S("Neptune")) update(dateJDE, RotationElements::Neptune);
×
1871
                }
1872
                computeTransMatrices(dateJDE, observerPlanet->getHeliocentricEclipticPos());
×
1873
        }
1874
}
×
1875

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

1882
        if (flagLightTravelTime)
×
1883
        {
1884
                for (const auto& p : std::as_const(systemPlanets))
×
1885
                {
1886
                        const double light_speed_correction = (p->getHeliocentricEclipticPos()-observerPos).norm() * (AU / (SPEED_OF_LIGHT * 86400));
×
1887
                        p->computeTransMatrix(dateJD-light_speed_correction, dateJDE-light_speed_correction);
×
1888
                }
1889
        }
1890
        else
1891
        {
1892
                for (const auto& p : std::as_const(systemPlanets))
×
1893
                {
1894
                        p->computeTransMatrix(dateJD, dateJDE);
×
1895
                }
1896
        }
1897
}
×
1898

1899
// And sort them from the furthest to the closest to the observer
1900
// NOTE: std::binary_function is deprecated in C++11 and removed in C++17
1901
struct biggerDistance : public StelUtils::binary_function<PlanetP, PlanetP, bool>
1902
{
1903
        bool operator()(PlanetP p1, PlanetP p2)
×
1904
        {
1905
                return p1->getDistance() > p2->getDistance();
×
1906
        }
1907
};
1908

1909
// Draw all the elements of the solar system
1910
// We are supposed to be in heliocentric coordinate
1911
void SolarSystem::draw(StelCore* core)
×
1912
{
1913
        // AstroCalcDialog
1914
        drawEphemerisItems(core);
×
1915

1916
        if (!flagShow)
×
1917
                return;
×
1918
        static StelObjectMgr *sObjMgr=GETSTELMODULE(StelObjectMgr);
×
1919

1920
        // Compute each Planet distance to the observer
1921
        const Vec3d obsHelioPos = core->getObserverHeliocentricEclipticPos();
×
1922

1923
        for (const auto& p : std::as_const(systemPlanets))
×
1924
        {
1925
                p->computeDistance(obsHelioPos);
×
1926
        }
1927

1928
        // And sort them from the farthest to the closest. std::sort can split this into parallel threads!
1929
        std::sort(STD_EXECUTION_PAR_COMMA
×
1930
                  systemPlanets.begin(),systemPlanets.end(),biggerDistance());
1931

1932
        if (trailFader.getInterstate()>0.0000001f)
×
1933
        {
1934
                StelPainter sPainter(core->getProjection2d());
×
1935
                const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
×
1936
                allTrails->setOpacity(trailFader.getInterstate());
×
1937
                if (trailsThickness>1 || ppx>1.f)
×
1938
                        sPainter.setLineWidth(trailsThickness*ppx);
×
1939
                allTrails->draw(core, &sPainter);
×
1940
                if (trailsThickness>1 || ppx>1.f)
×
1941
                        sPainter.setLineWidth(1);
×
1942
        }
×
1943

1944
        // Make some voodoo to determine when labels should be displayed
1945
        const float sdLimitMag=static_cast<float>(core->getSkyDrawer()->getLimitMagnitude());
×
1946
        const float maxMagLabel = (sdLimitMag<5.f ? sdLimitMag :
×
1947
                        5.f+(sdLimitMag-5.f)*1.2f) +(static_cast<float>(labelsAmount)-3.f)*1.2f;
×
1948
        const double eclipseFactor=getSolarEclipseFactor(core).first;
×
1949

1950
        // Draw the elements
1951
        for (const auto& p : std::as_const(systemPlanets))
×
1952
        {
1953
                if ( (p != sun) || (/* (p == sun) && */ !(core->getSkyDrawer()->getFlagDrawSunAfterAtmosphere())))
×
1954
                        p->draw(core, maxMagLabel, planetNameFont, eclipseFactor);
×
1955
        }
1956
        if (nbMarkers>0)
×
1957
        {
1958
                StelPainter sPainter(core->getProjection2d());
×
1959
                postDrawAsteroidMarkers(&sPainter);
×
1960
        }
×
1961

1962
        if (sObjMgr->getFlagSelectedObjectPointer() && getFlagPointer())
×
1963
                drawPointer(core);
×
1964
}
1965

1966
// Finalize the drawing of asteroid markers (inspired from StelSkyDrawer)
1967
void SolarSystem::postDrawAsteroidMarkers(StelPainter *sPainter)
×
1968
{
1969
        Q_ASSERT(sPainter);
×
1970

1971
        if (nbMarkers==0)
×
1972
                return;
×
1973

1974
        markerCircleTex->bind();
×
1975
        sPainter->setBlending(true, GL_ONE, GL_ONE);
×
1976

1977
        const QMatrix4x4 qMat=sPainter->getProjector()->getProjectionMatrix().toQMatrix();
×
1978

1979
        vbo->bind();
×
1980
        vbo->write(0, markerArray, nbMarkers*6*sizeof(MarkerVertex));
×
1981
        vbo->write(maxMarkers*6*sizeof(MarkerVertex), textureCoordArray, nbMarkers*6*2);
×
1982
        vbo->release();
×
1983

1984
        markerShaderProgram->bind();
×
1985
        markerShaderProgram->setUniformValue(markerShaderVars.projectionMatrix, qMat);
×
1986

1987
        bindVAO();
×
1988
        glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(nbMarkers)*6);
×
1989
        releaseVAO();
×
1990

1991
        markerShaderProgram->release();
×
1992

1993
        nbMarkers = 0;
×
1994
}
1995

1996
// Draw a point source halo.
1997
bool SolarSystem::drawAsteroidMarker(StelCore* core, StelPainter* sPainter, const float x, const float y, Vec3f &color)
×
1998
{
1999
        const float reducer=markerFader.getInterstate();
×
2000
        if (reducer==0.)
×
2001
                return false;
×
2002

2003
        Q_ASSERT(sPainter);
×
2004
        const float radius = 3.f * static_cast<float>(sPainter->getProjector()->getDevicePixelsPerPixel());
×
2005
        unsigned char markerColor[3] = {
2006
                static_cast<unsigned char>(std::min(static_cast<int>(color[0]*reducer*255+0.5f), 255)),
×
2007
                static_cast<unsigned char>(std::min(static_cast<int>(color[1]*reducer*255+0.5f), 255)),
×
2008
                static_cast<unsigned char>(std::min(static_cast<int>(color[2]*reducer*255+0.5f), 255))};
×
2009
        // Store the drawing instructions in the vertex arrays
2010
        MarkerVertex* vx = &(markerArray[nbMarkers*6]);
×
2011
        vx->pos.set(x-radius,y-radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
2012
        vx->pos.set(x+radius,y-radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
2013
        vx->pos.set(x+radius,y+radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
2014
        vx->pos.set(x-radius,y-radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
2015
        vx->pos.set(x+radius,y+radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
2016
        vx->pos.set(x-radius,y+radius); std::memcpy(vx->color, markerColor, 3); ++vx;
×
2017

2018
        ++nbMarkers;
×
2019
        if (nbMarkers>=maxMarkers)
×
2020
        {
2021
                // Flush the buffer (draw all buffered markers)
2022
                postDrawAsteroidMarkers(sPainter);
×
2023
        }
2024
        return true;
×
2025
}
2026

2027
void SolarSystem::drawEphemerisItems(const StelCore* core)
×
2028
{
2029
        if (flagShow || (!flagShow && getFlagEphemerisAlwaysOn()))
×
2030
        {
2031
                if (getFlagEphemerisMarkers())
×
2032
                        drawEphemerisMarkers(core);
×
2033
                if (getFlagEphemerisLine())
×
2034
                        drawEphemerisLine(core);
×
2035
        }
2036
}
×
2037

2038
Vec3f SolarSystem::getEphemerisMarkerColor(int index) const
×
2039
{
2040
        // Sync index with AstroCalcDialog::generateEphemeris(). If required, switch to using a QMap.
2041
        const QVector<Vec3f> colors={
2042
                ephemerisGenericMarkerColor,
2043
                ephemerisSecondaryMarkerColor,
2044
                ephemerisMercuryMarkerColor,
2045
                ephemerisVenusMarkerColor,
2046
                ephemerisMarsMarkerColor,
2047
                ephemerisJupiterMarkerColor,
2048
                ephemerisSaturnMarkerColor};
×
2049
        return colors.value(index, ephemerisGenericMarkerColor);
×
2050
}
×
2051

2052
void SolarSystem::drawEphemerisMarkers(const StelCore *core)
×
2053
{
2054
        const int fsize = AstroCalcDialog::EphemerisList.count();
×
2055
        if (fsize==0) return;
×
2056

2057
        StelProjectorP prj;
×
2058
        if (getFlagEphemerisHorizontalCoordinates())
×
2059
                prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
2060
        else
2061
                prj = core->getProjection(StelCore::FrameJ2000);
×
2062
        StelPainter sPainter(prj);
×
2063

2064
        float size, shift, baseSize = 4.f;
×
2065
        const bool showDates = getFlagEphemerisDates();
×
2066
        const bool showMagnitudes = getFlagEphemerisMagnitudes();
×
2067
        const bool showSkippedData = getFlagEphemerisSkipData();
×
2068
        const bool skipMarkers = getFlagEphemerisSkipMarkers();
×
2069
        const bool isNowVisible = getFlagEphemerisNow();
×
2070
        const int dataStep = getEphemerisDataStep();
×
2071
        const int sizeCoeff = getEphemerisLineThickness() - 1;
×
2072
        QString info = "";
×
2073
        Vec3d win;
×
2074
        Vec3f markerColor;
×
2075
        bool skipFlag = false;
×
2076

2077
        if (getFlagEphemerisLine() && getFlagEphemerisScaleMarkers())
×
2078
                baseSize = 3.f; // The line lies through center of marker
×
2079

2080
        if (isNowVisible)
×
2081
        {
2082
                const int limit = getEphemerisDataLimit();
×
2083
                const int nsize = static_cast<int>(fsize/limit);
×
2084
                sPainter.setBlending(true, GL_ONE, GL_ONE);
×
2085
                texEphemerisNowMarker->bind();
×
2086
                Vec3d pos;
×
2087
                Vec3f win;
×
2088
                for (int i =0; i < limit; i++)
×
2089
                {
2090
                        long k = static_cast<long>(i)*nsize;
×
2091
                        sPainter.setColor(getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[k].colorIndex));
×
2092
                        if (getFlagEphemerisHorizontalCoordinates())
×
2093
                                pos = AstroCalcDialog::EphemerisList[k].sso->getAltAzPosAuto(core);
×
2094
                        else
2095
                                pos = AstroCalcDialog::EphemerisList[k].sso->getJ2000EquatorialPos(core);
×
2096
                        if (prj->project(pos, win))
×
2097
                                sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), 6.f, 0.f);
×
2098
                }
2099
        }
2100

2101
        for (int i =0; i < fsize; i++)
×
2102
        {
2103
                skipFlag = (((i + 1)%dataStep)!=1 && dataStep!=1);
×
2104

2105
                // Check visibility of pointer
2106
                if (!(sPainter.getProjector()->projectCheck(AstroCalcDialog::EphemerisList[i].coord, win)))
×
2107
                        continue;
×
2108

2109
                QString debugStr; // Used temporarily for development
×
2110
                const bool isComet=AstroCalcDialog::EphemerisList[i].isComet;
×
2111
                if (i == AstroCalcDialog::DisplayedPositionIndex)
×
2112
                {
2113
                        markerColor = getEphemerisSelectedMarkerColor();
×
2114
                        size = 6.f;
×
2115
                }
2116
                else
2117
                {
2118
                        markerColor = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i].colorIndex);
×
2119
                        size = baseSize;
×
2120
                }
2121
                if (isComet) size += 16.f;
×
2122
                size += sizeCoeff;
×
2123
                sPainter.setColor(markerColor);
×
2124
                sPainter.setBlending(true, GL_ONE, GL_ONE);
×
2125
                if (isComet)
×
2126
                        texEphemerisCometMarker->bind();
×
2127
                else
2128
                        texEphemerisMarker->bind();
×
2129

2130
                if (skipMarkers && skipFlag)
×
2131
                        continue;
×
2132

2133
                Vec3f win;
×
2134
                float solarAngle=0.f; // Angle to possibly rotate the texture. Degrees.
×
2135
                if (prj->project(AstroCalcDialog::EphemerisList[i].coord, win))
×
2136
                {
2137
                        if (isComet)
×
2138
                        {
2139
                                // compute solarAngle in screen space.
2140
                                Vec3f sunWin;
×
2141
                                prj->project(AstroCalcDialog::EphemerisList[i].sunCoord, sunWin);
×
2142
                                // TODO: In some projections, we may need to test result and flip/mirror the angle, or deal with wrap-around effects.
2143
                                // E.g., in cylindrical mode, the comet icon will flip as soon as the corresponding sun position wraps around the screen edge.
2144
                                solarAngle=M_180_PIf*(atan2(-(win[1]-sunWin[1]), win[0]-sunWin[0]));
×
2145
                                // This will show projected positions and angles usable in labels.
2146
                                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));
×
2147
                        }
2148
                        //sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 180.f+AstroCalcDialog::EphemerisList[i].solarAngle*M_180_PIf);
2149
                        sPainter.drawSprite2dMode(static_cast<float>(win[0]), static_cast<float>(win[1]), size, 270.f-solarAngle);
×
2150
                }
2151

2152
                if (showDates || showMagnitudes)
×
2153
                {
2154
                        if (showSkippedData && skipFlag)
×
2155
                                continue;
×
2156

2157
                        shift = 3.f + size/1.6f;
×
2158
                        if (showDates && showMagnitudes)
×
2159
                                info = QString("%1 (%2)").arg(AstroCalcDialog::EphemerisList[i].objDateStr, QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2));
×
2160
                        if (showDates && !showMagnitudes)
×
2161
                                info = AstroCalcDialog::EphemerisList[i].objDateStr;
×
2162
                        if (!showDates && showMagnitudes)
×
2163
                                info = QString::number(AstroCalcDialog::EphemerisList[i].magnitude, 'f', 2);
×
2164

2165
                        // Activate for debug labels.
2166
                        //info=debugStr;
2167
                        sPainter.drawText(AstroCalcDialog::EphemerisList[i].coord, info, 0, shift, shift, false);
×
2168
                }
2169
        }
×
2170
}
×
2171

2172
void SolarSystem::drawEphemerisLine(const StelCore *core)
×
2173
{
2174
        const int size = AstroCalcDialog::EphemerisList.count();
×
2175
        if (size==0) return;
×
2176

2177
        // The array of data is not empty - good news!
2178
        StelProjectorP prj;
×
2179
        if (getFlagEphemerisHorizontalCoordinates())
×
2180
                prj = core->getProjection(StelCore::FrameAltAz, StelCore::RefractionOff);
×
2181
        else
2182
                prj = core->getProjection(StelCore::FrameJ2000);
×
2183
        StelPainter sPainter(prj);
×
2184
        const float ppx = static_cast<float>(sPainter.getProjector()->getDevicePixelsPerPixel());
×
2185

2186
        const float oldLineThickness=sPainter.getLineWidth();
×
2187
        const float lineThickness = getEphemerisLineThickness()*ppx;
×
2188
        if (!fuzzyEquals(lineThickness, oldLineThickness))
×
2189
                sPainter.setLineWidth(lineThickness);
×
2190

2191
        Vec3f color;
×
2192
        QVector<Vec3d> vertexArray;
×
2193
        QVector<Vec4f> colorArray;
×
2194
        const int limit = getEphemerisDataLimit();
×
2195
        const int nsize = static_cast<int>(size/limit);
×
2196
        vertexArray.resize(nsize);
×
2197
        colorArray.resize(nsize);
×
2198
        for (int j=0; j<limit; j++)
×
2199
        {
2200
                for (int i =0; i < nsize; i++)
×
2201
                {
2202
                        color = getEphemerisMarkerColor(AstroCalcDialog::EphemerisList[i + j*nsize].colorIndex);
×
2203
                        colorArray[i]=Vec4f(color, 1.0f);
×
2204
                        vertexArray[i]=AstroCalcDialog::EphemerisList[i + j*nsize].coord;
×
2205
                }
2206
                sPainter.drawPath(vertexArray, colorArray);
×
2207
        }
2208

2209
        if (!fuzzyEquals(lineThickness, oldLineThickness))
×
2210
                sPainter.setLineWidth(oldLineThickness); // restore line thickness
×
2211
}
×
2212

2213
void SolarSystem::fillEphemerisDates()
×
2214
{
2215
        const int fsize = AstroCalcDialog::EphemerisList.count();
×
2216
        if (fsize==0) return;
×
2217

2218
        static StelLocaleMgr* localeMgr = &StelApp::getInstance().getLocaleMgr();
×
2219
        static StelCore *core = StelApp::getInstance().getCore();
×
2220
        const bool showSmartDates = getFlagEphemerisSmartDates();
×
2221
        double JD = AstroCalcDialog::EphemerisList.first().objDate;
×
2222
        bool withTime = (fsize>1 && (AstroCalcDialog::EphemerisList[1].objDate-JD<1.0));
×
2223

2224
        int fYear, fMonth, fDay, sYear, sMonth, sDay, h, m, s;
2225
        QString info;
×
2226
        const double shift = core->getUTCOffset(JD)*StelCore::JD_HOUR;
×
2227
        StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
×
2228
        bool sFlag = true;
×
2229
        sYear = fYear;
×
2230
        sMonth = fMonth;
×
2231
        sDay = fDay;
×
2232
        const bool showSkippedData = getFlagEphemerisSkipData();
×
2233
        const int dataStep = getEphemerisDataStep();
×
2234

2235
        for (int i = 0; i < fsize; i++)
×
2236
        {
2237
                const double JD = AstroCalcDialog::EphemerisList[i].objDate;
×
2238
                StelUtils::getDateFromJulianDay(JD+shift, &fYear, &fMonth, &fDay);
×
2239

2240
                if (showSkippedData && ((i + 1)%dataStep)!=1 && dataStep!=1)
×
2241
                        continue;
×
2242

2243
                if (showSmartDates)
×
2244
                {
2245
                        if (sFlag)
×
2246
                                info = QString("%1").arg(fYear);
×
2247

2248
                        if (info.isEmpty() && !sFlag && fYear!=sYear)
×
2249
                                info = QString("%1").arg(fYear);
×
2250

2251
                        if (!info.isEmpty())
×
2252
                                info.append(QString("/%1").arg(localeMgr->romanMonthName(fMonth)));
×
2253
                        else if (fMonth!=sMonth)
×
2254
                                info = QString("%1").arg(localeMgr->romanMonthName(fMonth));
×
2255

2256
                        if (!info.isEmpty())
×
2257
                                info.append(QString("/%1").arg(fDay));
×
2258
                        else
2259
                                info = QString("%1").arg(fDay);
×
2260

2261
                        if (withTime) // very short step
×
2262
                        {
2263
                                if (fDay==sDay && !sFlag)
×
2264
                                        info.clear();
×
2265

2266
                                StelUtils::getTimeFromJulianDay(JD+shift, &h, &m, &s);
×
2267
                                QString hours = QString::number(h).rightJustified(2, '0');
×
2268
                                QString minutes = QString::number(m).rightJustified(2, '0');
×
2269
                                if (!info.isEmpty())
×
2270
                                        info.append(QString(" %1:%2").arg(hours, minutes));
×
2271
                                else
2272
                                        info = QString("%1:%2").arg(hours, minutes);
×
2273
                        }
×
2274

2275
                        AstroCalcDialog::EphemerisList[i].objDateStr = info;
×
2276
                        info.clear();
×
2277
                        sYear = fYear;
×
2278
                        sMonth = fMonth;
×
2279
                        sDay = fDay;
×
2280
                        sFlag = false;
×
2281
                }
2282
                else
2283
                {
2284
                        // OK, let's use standard formats for date and time (as defined for whole planetarium)
2285
                        const double utcOffsetHrs = core->getUTCOffset(JD);
×
2286
                        if (withTime)
×
2287
                                AstroCalcDialog::EphemerisList[i].objDateStr = QString("%1 %2").arg(localeMgr->getPrintableDateLocal(JD, utcOffsetHrs), localeMgr->getPrintableTimeLocal(JD, utcOffsetHrs));
×
2288
                        else
2289
                                AstroCalcDialog::EphemerisList[i].objDateStr = localeMgr->getPrintableDateLocal(JD, utcOffsetHrs);
×
2290
                }
2291
        }
2292
}
×
2293

2294
PlanetP SolarSystem::searchByEnglishName(const QString &planetEnglishName) const
×
2295
{
2296
        for (const auto& p : systemPlanets)
×
2297
        {
2298
                if (p->getEnglishName().toUpper() == planetEnglishName.toUpper() || p->getCommonEnglishName().toUpper() == planetEnglishName.toUpper())
×
2299
                        return p;
×
2300

2301
                // IAU designation?
2302
                QString iau = p->getIAUDesignation();
×
2303
                if (!iau.isEmpty() && iau.toUpper()==planetEnglishName.toUpper())
×
2304
                        return p;
×
2305
        }
×
2306
        for (const auto& p : systemMinorBodies)
×
2307
        {
2308
                QStringList c;
×
2309
                // other comet designations?
2310
                if (p->getPlanetType()==Planet::isComet)
×
2311
                {
2312
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2313
                        c = mp->getExtraDesignations();
×
2314
                } else {
×
2315
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2316
                        c = mp->getExtraDesignations();
×
2317
                }
×
2318
                for (const auto& d : c)
×
2319
                {
2320
                        if (d.toUpper()==planetEnglishName.toUpper())
×
2321
                                return p;
×
2322
                }
2323
        }
×
2324
        return PlanetP();
×
2325
}
2326

2327
PlanetP SolarSystem::searchMinorPlanetByEnglishName(const QString &planetEnglishName) const
×
2328
{
2329
        for (const auto& p : systemMinorBodies)
×
2330
        {
2331
                if (p->getCommonEnglishName().toUpper() == planetEnglishName.toUpper() || p->getEnglishName().toUpper() == planetEnglishName.toUpper())
×
2332
                        return p;
×
2333

2334
                // IAU designation?
2335
                QString iau = p->getIAUDesignation();
×
2336
                if (!iau.isEmpty() && iau.toUpper()==planetEnglishName.toUpper())
×
2337
                        return p;
×
2338

2339
                QStringList c;
×
2340
                // other comet designations?
2341
                if (p->getPlanetType()==Planet::isComet)
×
2342
                {
2343
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2344
                        c = mp->getExtraDesignations();
×
2345
                }
×
2346
                else
2347
                {
2348
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2349
                        c = mp->getExtraDesignations();
×
2350
                }
×
2351
                for (const auto& d : c)
×
2352
                {
2353
                        if (d.toUpper()==planetEnglishName.toUpper())
×
2354
                                return p;
×
2355
                }
2356
        }
×
2357
        return PlanetP();
×
2358
}
2359

2360

2361
StelObjectP SolarSystem::searchByNameI18n(const QString& planetNameI18) const
×
2362
{
2363
        for (const auto& p : systemPlanets)
×
2364
        {
2365
                QString nativeName = p->getNativeNameI18n().toUpper();
×
2366
                if (p->getNameI18n().toUpper() == planetNameI18.toUpper() || (!nativeName.isEmpty() && nativeName == planetNameI18.toUpper()))
×
2367
                        return qSharedPointerCast<StelObject>(p);
×
2368
        }
×
2369
        return StelObjectP();
×
2370
}
2371

2372

2373
StelObjectP SolarSystem::searchByName(const QString& name) const
×
2374
{
2375
        for (const auto& p : systemPlanets)
×
2376
        {
2377
                QString nativeName = p->getNativeName().toUpper();
×
2378
                if (p->getEnglishName().toUpper() == name.toUpper() || (!nativeName.isEmpty() && nativeName == name.toUpper()))
×
2379
                        return qSharedPointerCast<StelObject>(p);
×
2380

2381
                // IAU designation?
2382
                QString iau = p->getIAUDesignation();
×
2383
                if (!iau.isEmpty() && iau.toUpper()==name.toUpper())
×
2384
                        return qSharedPointerCast<StelObject>(p);
×
2385
        }
×
2386
        for (const auto& p : systemMinorBodies)
×
2387
        {
2388
                QStringList c;
×
2389
                // other comet designations?
2390
                if (p->getPlanetType()==Planet::isComet)
×
2391
                {
2392
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2393
                        c = mp->getExtraDesignations();
×
2394
                }
×
2395
                else
2396
                {
2397
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2398
                        c = mp->getExtraDesignations();
×
2399
                }
×
2400
                for (const auto& d : c)
×
2401
                {
2402
                        if (d.toUpper()==name.toUpper())
×
2403
                                return qSharedPointerCast<StelObject>(p);
×
2404
                }
2405
        }
×
2406

2407
        return StelObjectP();
×
2408
}
2409

2410
float SolarSystem::getPlanetVMagnitude(const QString &planetName, bool withExtinction) const
×
2411
{
2412
        StelCore *core=StelApp::getInstance().getCore();
×
2413
        double eclipseFactor=getSolarEclipseFactor(core).first;
×
2414
        PlanetP p = searchByEnglishName(planetName);
×
2415
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2416
                p = searchMinorPlanetByEnglishName(planetName);
×
2417
        float r = p->getVMagnitude(core, eclipseFactor);
×
2418
        if (withExtinction)
×
2419
                r = p->getVMagnitudeWithExtinction(core, r);
×
2420
        return r;
×
2421
}
×
2422

2423
QString SolarSystem::getPlanetType(const QString &planetName) const
×
2424
{
2425
        PlanetP p = searchByEnglishName(planetName);
×
2426
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2427
                p = searchMinorPlanetByEnglishName(planetName);
×
2428
        if (p.isNull())
×
2429
                return QString("UNDEFINED");
×
2430
        return p->getObjectType();
×
2431
}
×
2432

2433
double SolarSystem::getDistanceToPlanet(const QString &planetName) const
×
2434
{
2435
        PlanetP p = searchByEnglishName(planetName);
×
2436
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2437
                p = searchMinorPlanetByEnglishName(planetName);
×
2438
        return p->getDistance();
×
2439
}
×
2440

2441
double SolarSystem::getElongationForPlanet(const QString &planetName) const
×
2442
{
2443
        PlanetP p = searchByEnglishName(planetName);
×
2444
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2445
                p = searchMinorPlanetByEnglishName(planetName);
×
2446
        return p->getElongation(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
2447
}
×
2448

2449
double SolarSystem::getPhaseAngleForPlanet(const QString &planetName) const
×
2450
{
2451
        PlanetP p = searchByEnglishName(planetName);
×
2452
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2453
                p = searchMinorPlanetByEnglishName(planetName);
×
2454
        return p->getPhaseAngle(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
2455
}
×
2456

2457
float SolarSystem::getPhaseForPlanet(const QString &planetName) const
×
2458
{
2459
        PlanetP p = searchByEnglishName(planetName);
×
2460
        if (p.isNull()) // Possible was asked the common name of minor planet?
×
2461
                p = searchMinorPlanetByEnglishName(planetName);
×
2462
        return p->getPhase(StelApp::getInstance().getCore()->getObserverHeliocentricEclipticPos());
×
2463
}
×
2464

2465
QStringList SolarSystem::getObjectsList(QString objType) const
×
2466
{
2467
        QStringList r;
×
2468
        if (objType.toLower()==L1S("all"))
×
2469
        {
2470
                r = listAllObjects(true);
×
2471
                // Remove the Sun
2472
                r.removeOne("Sun");
×
2473
                // Remove special objects
2474
                r.removeOne("Solar System Observer");
×
2475
                r.removeOne("Earth Observer");
×
2476
                r.removeOne("Mars Observer");
×
2477
                r.removeOne("Jupiter Observer");
×
2478
                r.removeOne("Saturn Observer");
×
2479
                r.removeOne("Uranus Observer");
×
2480
                r.removeOne("Neptune Observer");
×
2481
        }
2482
        else
2483
                r = listAllObjectsByType(objType, true);
×
2484

2485
        return r;
×
2486
}
×
2487

2488
// Search if any Planet is close to position given in earth equatorial position and return the distance
2489
StelObjectP SolarSystem::search(Vec3d pos, const StelCore* core) const
×
2490
{
2491
        pos.normalize();
×
2492
        PlanetP closest;
×
2493
        double cos_angle_closest = 0.;
×
2494
        Vec3d equPos;
×
2495

2496
        for (const auto& p : systemPlanets)
×
2497
        {
2498
                equPos = p->getEquinoxEquatorialPos(core);
×
2499
                equPos.normalize();
×
2500
                double cos_ang_dist = equPos*pos;
×
2501
                if (cos_ang_dist>cos_angle_closest)
×
2502
                {
2503
                        closest = p;
×
2504
                        cos_angle_closest = cos_ang_dist;
×
2505
                }
2506
        }
2507

2508
        if (cos_angle_closest>0.999)
×
2509
        {
2510
                return qSharedPointerCast<StelObject>(closest);
×
2511
        }
2512
        else return StelObjectP();
×
2513
}
×
2514

2515
// Return a QList containing the planets located inside the limFov circle around position vv
2516
QList<StelObjectP> SolarSystem::searchAround(const Vec3d& vv, double limitFov, const StelCore* core) const
×
2517
{
2518
        QList<StelObjectP> result;
×
2519
        if (!getFlagPlanets())
×
2520
                return result;
×
2521

2522
        Vec3d v(vv);
×
2523
        
2524
        double cosLimFov = std::cos(limitFov * M_PI/180.);
×
2525
        Vec3d equPos;
×
2526
        double cosAngularSize;
2527

2528
        const QString weAreHere = core->getCurrentPlanet()->getEnglishName();
×
2529
        for (const auto& p : systemPlanets)
×
2530
        {
2531
                equPos = p->getJ2000EquatorialPos(core);
×
2532
                equPos.normalize();
×
2533

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

2536
                if (equPos*v>=std::min(cosLimFov, cosAngularSize) && p->getEnglishName()!=weAreHere)
×
2537
                {
2538
                        result.append(qSharedPointerCast<StelObject>(p));
×
2539
                }
2540
        }
2541
        return result;
×
2542
}
×
2543

2544
// Update i18 names from english names according to current sky culture translator
2545
void SolarSystem::updateI18n()
×
2546
{
2547
        const StelTranslator& trans = StelApp::getInstance().getLocaleMgr().getSkyTranslator();
×
2548
        for (const auto& p : std::as_const(systemPlanets))
×
2549
                p->translateName(trans);
×
2550
}
×
2551

2552
QStringList SolarSystem::listMatchingObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
×
2553
{
2554
        QStringList result;
×
2555
        if (getFlagPlanets())
×
2556
                result = StelObjectModule::listMatchingObjects(objPrefix, maxNbItem, useStartOfWords);
×
2557
        return result;
×
2558
}
×
2559

2560
void SolarSystem::setFlagTrails(bool b)
×
2561
{
2562
        if (getFlagTrails() != b)
×
2563
        {
2564
                trailFader = b;
×
2565
                if (b)
×
2566
                {
2567
                        allTrails->reset(maxTrailPoints);
×
2568
                        recreateTrails();
×
2569
                }
2570
                StelApp::immediateSave("astro/flag_object_trails", b);
×
2571
                emit trailsDisplayedChanged(b);
×
2572
        }
2573
}
×
2574

2575
bool SolarSystem::getFlagTrails() const
×
2576
{
2577
        return static_cast<bool>(trailFader);
×
2578
}
2579

2580
void SolarSystem::setMaxTrailPoints(int max)
×
2581
{
2582
        if (maxTrailPoints != max)
×
2583
        {
2584
                maxTrailPoints = max;
×
2585
                allTrails->reset(max);
×
2586
                recreateTrails();
×
2587
                StelApp::immediateSave("viewing/max_trail_points", max);
×
2588
                emit maxTrailPointsChanged(max);
×
2589
        }
2590
}
×
2591

2592
void SolarSystem::setMaxTrailTimeExtent(int max)
×
2593
{
2594
        if (maxTrailTimeExtent != max && maxTrailTimeExtent > 0)
×
2595
        {
2596
                maxTrailTimeExtent = max;
×
2597
                recreateTrails();
×
2598
                StelApp::immediateSave("viewing/max_trail_time_extent", max);
×
2599
                emit maxTrailTimeExtentChanged(max);
×
2600
        }
2601
}
×
2602

2603
void SolarSystem::setTrailsThickness(int v)
×
2604
{
2605
        if (trailsThickness != v)
×
2606
        {
2607
                trailsThickness = v;
×
2608
                StelApp::immediateSave("astro/object_trails_thickness", v);
×
2609
                emit trailsThicknessChanged(v);
×
2610
        }
2611
}
×
2612

2613
void SolarSystem::setFlagHints(bool b)
×
2614
{
2615
        if (getFlagHints() != b)
×
2616
        {
2617
                for (const auto& p : std::as_const(systemPlanets))
×
2618
                        p->setFlagHints(b);
×
2619
                StelApp::immediateSave("astro/flag_planets_hints", b);
×
2620
                emit flagHintsChanged(b);
×
2621
        }
2622
}
×
2623

2624
bool SolarSystem::getFlagHints(void) const
×
2625
{
2626
        for (const auto& p : std::as_const(systemPlanets))
×
2627
        {
2628
                if (p->getFlagHints())
×
2629
                        return true;
×
2630
        }
2631
        return false;
×
2632
}
2633

2634
void SolarSystem::setFlagLabels(bool b)
×
2635
{
2636
        if (getFlagLabels() != b)
×
2637
        {
2638
                for (const auto& p : std::as_const(systemPlanets))
×
2639
                        p->setFlagLabels(b);
×
2640
                StelApp::immediateSave("astro/flag_planets_labels", b);
×
2641
                emit labelsDisplayedChanged(b);
×
2642
        }
2643
}
×
2644

2645
bool SolarSystem::getFlagLabels() const
×
2646
{
2647
        for (const auto& p : std::as_const(systemPlanets))
×
2648
        {
2649
                if (p->getFlagLabels())
×
2650
                        return true;
×
2651
        }
2652
        return false;
×
2653
}
2654

2655
void SolarSystem::setFlagMarkers(bool b)
×
2656
{
2657
        if (getFlagMarkers() != b)
×
2658
        {
2659
                markerFader = b;
×
2660
                StelApp::immediateSave("astro/flag_planets_markers", b);
×
2661
                emit markersDisplayedChanged(b);
×
2662
        }
2663
}
×
2664

2665
bool SolarSystem::getFlagMarkers() const
×
2666
{
2667
        return markerFader;
×
2668
}
2669

2670
void SolarSystem::setFlagLightTravelTime(bool b)
×
2671
{
2672
        if(b!=flagLightTravelTime)
×
2673
        {
2674
                flagLightTravelTime = b;
×
2675
                StelApp::immediateSave("astro/flag_light_travel_time", b);
×
2676
                emit flagLightTravelTimeChanged(b);
×
2677
        }
2678
}
×
2679

2680
void SolarSystem::setFlagShowObjSelfShadows(bool b)
×
2681
{
2682
        if(b!=flagShowObjSelfShadows)
×
2683
        {
2684
                flagShowObjSelfShadows = b;
×
2685
                if(!b)
×
2686
                        Planet::deinitFBO();
×
2687
                StelApp::immediateSave("astro/flag_show_obj_self_shadows", b);
×
2688
                emit flagShowObjSelfShadowsChanged(b);
×
2689
        }
2690
}
×
2691

2692
void SolarSystem::setSelected(PlanetP obj)
×
2693
{
2694
        if (obj && obj->getType() == L1S("Planet"))
×
2695
        {
2696
                selected = obj;
×
2697
                selectedSSO.push_back(obj);
×
2698
        }
2699
        else
2700
                selected.clear();
×
2701
        // Undraw other objects hints, orbit, trails etc..
2702
        setFlagHints(getFlagHints());
×
2703
        reconfigureOrbits();
×
2704
}
×
2705

2706

2707
void SolarSystem::update(double deltaTime)
×
2708
{
2709
        trailFader.update(static_cast<int>(deltaTime*1000));
×
2710
        if (trailFader.getInterstate()>0.f)
×
2711
        {
2712
                allTrails->update();
×
2713
        }
2714

2715
        for (const auto& p : std::as_const(systemPlanets))
×
2716
        {
2717
                p->update(static_cast<int>(deltaTime*1000));
×
2718
        }
2719
        markerFader.update(deltaTime*1000);
×
2720
}
×
2721

2722
// is a lunar eclipse close at hand?
2723
bool SolarSystem::nearLunarEclipse() const
×
2724
{
2725
        // TODO: could replace with simpler test
2726
        // TODO Source?
2727

2728
        const Vec3d sun = getSun()->getAberrationPush();
×
2729
        const Vec3d e = getEarth()->getEclipticPos();
×
2730
        const Vec3d m = getMoon()->getEclipticPos();  // relative to earth
×
2731
        const Vec3d mh = getMoon()->getHeliocentricEclipticPos();  // relative to sun
×
2732

2733
        // shadow location at earth + moon distance along earth vector from (aberrated) sun
2734
        Vec3d en = e-sun;
×
2735
        en.normalize();
×
2736
        Vec3d shadow = en * (e.norm() + m.norm());
×
2737

2738
        // find shadow radii in AU
2739
        double r_penumbra = shadow.norm()*702378.1/AU/e.norm() - SUN_RADIUS/AU;
×
2740

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

2745
        return true;
×
2746
}
2747

2748
QStringList SolarSystem::listAllObjects(bool inEnglish) const
×
2749
{
2750
        QStringList result;
×
2751
        if (inEnglish)
×
2752
        {
2753
                for (const auto& p : systemPlanets)
×
2754
                {
2755
                        result << p->getEnglishName();
×
2756
                        if (!p->getIAUDesignation().isEmpty())
×
2757
                                result << p->getIAUDesignation();
×
2758
                }
2759
        }
2760
        else
2761
        {
2762
                for (const auto& p : systemPlanets)
×
2763
                {
2764
                        result << p->getNameI18n();
×
2765
                        if (!p->getNativeNameI18n().isEmpty())
×
2766
                                result << p->getNativeNameI18n() << p->getNativeName();
×
2767
                        if (!p->getIAUDesignation().isEmpty())
×
2768
                                result << p->getIAUDesignation();
×
2769
                }
2770
        }
2771
        for (const auto& p : systemMinorBodies)
×
2772
        {
2773
                QStringList c;
×
2774
                // other comet designations?
2775
                if (p->getPlanetType()==Planet::isComet)
×
2776
                {
2777
                        QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2778
                        c = mp->getExtraDesignations();
×
2779
                } else {
×
2780
                        QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2781
                        c = mp->getExtraDesignations();
×
2782
                }
×
2783
                if (c.count()>0)
×
2784
                        result << c;
×
2785
        }
×
2786
        return result;
×
2787
}
×
2788

2789
QStringList SolarSystem::listAllObjectsByType(const QString &objType, bool inEnglish) const
×
2790
{
2791
        QStringList result;
×
2792
        if (inEnglish)
×
2793
        {
2794
                for (const auto& p : systemPlanets)
×
2795
                {
2796
                        if (p->getObjectType()==objType)
×
2797
                        {
2798
                                result << p->getEnglishName();
×
2799
                                if (!p->getIAUDesignation().isEmpty())
×
2800
                                        result << p->getIAUDesignation();
×
2801
                        }
2802
                }
2803
        }
2804
        else
2805
        {
2806
                for (const auto& p : systemPlanets)
×
2807
                {
2808
                        if (p->getObjectType()==objType)
×
2809
                        {
2810
                                result << p->getNameI18n();
×
2811
                                if (!p->getIAUDesignation().isEmpty())
×
2812
                                        result << p->getIAUDesignation();
×
2813
                        }
2814
                }
2815
        }
2816
        for (const auto& p : systemMinorBodies)
×
2817
        {
2818
                if (p->getObjectType()==objType)
×
2819
                {
2820
                        QStringList c;
×
2821
                        // other comet designations?
2822
                        if (p->getPlanetType()==Planet::isComet)
×
2823
                        {
2824
                                QSharedPointer<Comet> mp = p.dynamicCast<Comet>();
×
2825
                                c = mp->getExtraDesignations();
×
2826
                        } else {
×
2827
                                QSharedPointer<MinorPlanet> mp = p.dynamicCast<MinorPlanet>();
×
2828
                                c = mp->getExtraDesignations();
×
2829
                        }
×
2830
                        if (c.count()>0)
×
2831
                                result << c;
×
2832
                }
×
2833
        }
2834
        return result;
×
2835
}
×
2836

2837
void SolarSystem::selectedObjectChange(StelModule::StelModuleSelectAction)
×
2838
{
2839
        const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Planet");
×
2840
        if (!newSelected.empty())
×
2841
        {
2842
                setSelected(qSharedPointerCast<Planet>(newSelected[0]));
×
2843
                if (getFlagIsolatedTrails())
×
2844
                        recreateTrails();
×
2845
        }
2846
        else
2847
                setSelected("");
×
2848
}
×
2849

2850
// Activate/Deactivate planets display
2851
void SolarSystem::setFlagPlanets(bool b)
×
2852
{
2853
        if (b!=flagShow)
×
2854
        {
2855
                flagShow=b;
×
2856
                StelApp::immediateSave("astro/flag_planets", b);
×
2857
                emit flagPlanetsDisplayedChanged(b);
×
2858
        }
2859
}
×
2860

2861
bool SolarSystem::getFlagPlanets(void) const
×
2862
{
2863
        return flagShow;
×
2864
}
2865

2866
void SolarSystem::setFlagEphemerisMarkers(bool b)
×
2867
{
2868
        if (b!=ephemerisMarkersDisplayed)
×
2869
        {
2870
                ephemerisMarkersDisplayed=b;
×
2871
                conf->setValue("astrocalc/flag_ephemeris_markers", b); // Immediate saving of state
×
2872
                emit ephemerisMarkersChanged(b);
×
2873
        }
2874
}
×
2875

2876
bool SolarSystem::getFlagEphemerisMarkers() const
×
2877
{
2878
        return ephemerisMarkersDisplayed;
×
2879
}
2880

2881
void SolarSystem::setFlagEphemerisLine(bool b)
×
2882
{
2883
        if (b!=ephemerisLineDisplayed)
×
2884
        {
2885
                ephemerisLineDisplayed=b;
×
2886
                conf->setValue("astrocalc/flag_ephemeris_line", b); // Immediate saving of state
×
2887
                emit ephemerisLineChanged(b);
×
2888
        }
2889
}
×
2890

2891
bool SolarSystem::getFlagEphemerisLine() const
×
2892
{
2893
        return ephemerisLineDisplayed;
×
2894
}
2895

2896
bool SolarSystem::getFlagEphemerisAlwaysOn() const
×
2897
{
2898
        return ephemerisAlwaysOn;
×
2899
}
2900

2901
void SolarSystem::setFlagEphemerisAlwaysOn(bool b)
×
2902
{
2903
        if (b != ephemerisAlwaysOn)
×
2904
        {
2905
                ephemerisAlwaysOn = b;
×
2906
                conf->setValue("astrocalc/flag_ephemeris_alwayson", b); // Immediate saving of state
×
2907
                emit ephemerisAlwaysOnChanged(b);
×
2908
        }
2909
}
×
2910

2911
bool SolarSystem::getFlagEphemerisNow() const
×
2912
{
2913
        return ephemerisNow;
×
2914
}
2915

2916
void SolarSystem::setFlagEphemerisNow(bool b)
×
2917
{
2918
        if (b != ephemerisNow)
×
2919
        {
2920
                ephemerisNow = b;
×
2921
                conf->setValue("astrocalc/flag_ephemeris_now", b); // Immediate saving of state
×
2922
                emit ephemerisNowChanged(b);
×
2923
        }
2924
}
×
2925

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

2936
bool SolarSystem::getFlagEphemerisHorizontalCoordinates() const
×
2937
{
2938
        return ephemerisHorizontalCoordinates;
×
2939
}
2940

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

2951
bool SolarSystem::getFlagEphemerisDates() const
×
2952
{
2953
        return ephemerisDatesDisplayed;
×
2954
}
2955

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

2966
bool SolarSystem::getFlagEphemerisMagnitudes() const
×
2967
{
2968
        return ephemerisMagnitudesDisplayed;
×
2969
}
2970

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

2981
bool SolarSystem::getFlagEphemerisSkipData() const
×
2982
{
2983
        return ephemerisSkipDataDisplayed;
×
2984
}
2985

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

2996
bool SolarSystem::getFlagEphemerisSkipMarkers() const
×
2997
{
2998
        return ephemerisSkipMarkersDisplayed;
×
2999
}
3000

3001
void SolarSystem::setFlagEphemerisSmartDates(bool b)
×
3002
{
3003
        if (b!=ephemerisSmartDatesDisplayed)
×
3004
        {
3005
                ephemerisSmartDatesDisplayed=b;
×
3006
                conf->setValue("astrocalc/flag_ephemeris_smart_dates", b); // Immediate saving of state
×
3007
                emit ephemerisSmartDatesChanged(b);
×
3008
        }
3009
}
×
3010

3011
bool SolarSystem::getFlagEphemerisSmartDates() const
×
3012
{
3013
        return ephemerisSmartDatesDisplayed;
×
3014
}
3015

3016
void SolarSystem::setFlagEphemerisScaleMarkers(bool b)
×
3017
{
3018
        if (b!=ephemerisScaleMarkersDisplayed)
×
3019
        {
3020
                ephemerisScaleMarkersDisplayed=b;
×
3021
                conf->setValue("astrocalc/flag_ephemeris_scale_markers", b); // Immediate saving of state
×
3022
                emit ephemerisScaleMarkersChanged(b);
×
3023
        }
3024
}
×
3025

3026
bool SolarSystem::getFlagEphemerisScaleMarkers() const
×
3027
{
3028
        return ephemerisScaleMarkersDisplayed;
×
3029
}
3030

3031
void SolarSystem::setEphemerisDataStep(int step)
×
3032
{
3033
        ephemerisDataStep = step;
×
3034
        // automatic saving of the setting
3035
        conf->setValue("astrocalc/ephemeris_data_step", step);
×
3036
        emit ephemerisDataStepChanged(step);
×
3037
}
×
3038

3039
int SolarSystem::getEphemerisDataStep() const
×
3040
{
3041
        return ephemerisDataStep;
×
3042
}
3043

3044
void SolarSystem::setEphemerisDataLimit(int limit)
×
3045
{
3046
        ephemerisDataLimit = limit;
×
3047
        emit ephemerisDataLimitChanged(limit);
×
3048
}
×
3049

3050
int SolarSystem::getEphemerisDataLimit() const
×
3051
{
3052
        return ephemerisDataLimit;
×
3053
}
3054

3055
void SolarSystem::setEphemerisLineThickness(int v)
×
3056
{
3057
        ephemerisLineThickness = v;
×
3058
        // automatic saving of the setting
3059
        conf->setValue("astrocalc/ephemeris_line_thickness", v);
×
3060
        emit ephemerisLineThicknessChanged(v);
×
3061
}
×
3062

3063
int SolarSystem::getEphemerisLineThickness() const
×
3064
{
3065
        return ephemerisLineThickness;
×
3066
}
3067

3068
void SolarSystem::setEphemerisGenericMarkerColor(const Vec3f& color)
×
3069
{
3070
        if (color!=ephemerisGenericMarkerColor)
×
3071
        {
3072
                ephemerisGenericMarkerColor = color;
×
3073
                emit ephemerisGenericMarkerColorChanged(color);
×
3074
        }
3075
}
×
3076

3077
Vec3f SolarSystem::getEphemerisGenericMarkerColor() const
×
3078
{
3079
        return ephemerisGenericMarkerColor;
×
3080
}
3081

3082
void SolarSystem::setEphemerisSecondaryMarkerColor(const Vec3f& color)
×
3083
{
3084
        if (color!=ephemerisSecondaryMarkerColor)
×
3085
        {
3086
                ephemerisSecondaryMarkerColor = color;
×
3087
                emit ephemerisSecondaryMarkerColorChanged(color);
×
3088
        }
3089
}
×
3090

3091
Vec3f SolarSystem::getEphemerisSecondaryMarkerColor() const
×
3092
{
3093
        return ephemerisSecondaryMarkerColor;
×
3094
}
3095

3096
void SolarSystem::setEphemerisSelectedMarkerColor(const Vec3f& color)
×
3097
{
3098
        if (color!=ephemerisSelectedMarkerColor)
×
3099
        {
3100
                ephemerisSelectedMarkerColor = color;
×
3101
                emit ephemerisSelectedMarkerColorChanged(color);
×
3102
        }
3103
}
×
3104

3105
Vec3f SolarSystem::getEphemerisSelectedMarkerColor() const
×
3106
{
3107
        return ephemerisSelectedMarkerColor;
×
3108
}
3109

3110
void SolarSystem::setEphemerisMercuryMarkerColor(const Vec3f& color)
×
3111
{
3112
        if (color!=ephemerisMercuryMarkerColor)
×
3113
        {
3114
                ephemerisMercuryMarkerColor = color;
×
3115
                emit ephemerisMercuryMarkerColorChanged(color);
×
3116
        }
3117
}
×
3118

3119
Vec3f SolarSystem::getEphemerisMercuryMarkerColor() const
×
3120
{
3121
        return ephemerisMercuryMarkerColor;
×
3122
}
3123

3124
void SolarSystem::setEphemerisVenusMarkerColor(const Vec3f& color)
×
3125
{
3126
        if (color!=ephemerisVenusMarkerColor)
×
3127
        {
3128
                ephemerisVenusMarkerColor = color;
×
3129
                emit ephemerisVenusMarkerColorChanged(color);
×
3130
        }
3131
}
×
3132

3133
Vec3f SolarSystem::getEphemerisVenusMarkerColor() const
×
3134
{
3135
        return ephemerisVenusMarkerColor;
×
3136
}
3137

3138
void SolarSystem::setEphemerisMarsMarkerColor(const Vec3f& color)
×
3139
{
3140
        if (color!=ephemerisMarsMarkerColor)
×
3141
        {
3142
                ephemerisMarsMarkerColor = color;
×
3143
                emit ephemerisMarsMarkerColorChanged(color);
×
3144
        }
3145
}
×
3146

3147
Vec3f SolarSystem::getEphemerisMarsMarkerColor() const
×
3148
{
3149
        return ephemerisMarsMarkerColor;
×
3150
}
3151

3152
void SolarSystem::setEphemerisJupiterMarkerColor(const Vec3f& color)
×
3153
{
3154
        if (color!=ephemerisJupiterMarkerColor)
×
3155
        {
3156
                ephemerisJupiterMarkerColor = color;
×
3157
                emit ephemerisJupiterMarkerColorChanged(color);
×
3158
        }
3159
}
×
3160

3161
Vec3f SolarSystem::getEphemerisJupiterMarkerColor() const
×
3162
{
3163
        return ephemerisJupiterMarkerColor;
×
3164
}
3165

3166
void SolarSystem::setEphemerisSaturnMarkerColor(const Vec3f& color)
×
3167
{
3168
        if (color!=ephemerisSaturnMarkerColor)
×
3169
        {
3170
                ephemerisSaturnMarkerColor = color;
×
3171
                emit ephemerisSaturnMarkerColorChanged(color);
×
3172
        }
3173
}
×
3174

3175
Vec3f SolarSystem::getEphemerisSaturnMarkerColor() const
×
3176
{
3177
        return ephemerisSaturnMarkerColor;
×
3178
}
3179

3180
void SolarSystem::setFlagNativePlanetNames(bool b)
×
3181
{
3182
        if (b!=flagNativePlanetNames)
×
3183
        {
3184
                flagNativePlanetNames=b;
×
3185
                for (const auto& p : std::as_const(systemPlanets))
×
3186
                {
3187
                        if (p->getPlanetType()==Planet::isPlanet || p->getPlanetType()==Planet::isMoon || p->getPlanetType()==Planet::isStar)
×
3188
                                p->setFlagNativeName(flagNativePlanetNames);
×
3189
                }
3190
                updateI18n();
×
3191
                StelApp::immediateSave("viewing/flag_planets_native_names", b);
×
3192
                emit flagNativePlanetNamesChanged(b);
×
3193
        }
3194
}
×
3195

3196
bool SolarSystem::getFlagNativePlanetNames() const
×
3197
{
3198
        return flagNativePlanetNames;
×
3199
}
3200

3201
void SolarSystem::setFlagIsolatedTrails(bool b)
×
3202
{
3203
        if(b!=flagIsolatedTrails)
×
3204
        {
3205
                flagIsolatedTrails = b;
×
3206
                recreateTrails();
×
3207
                StelApp::immediateSave("viewing/flag_isolated_trails", b);
×
3208
                emit flagIsolatedTrailsChanged(b);
×
3209
        }
3210
}
×
3211

3212
bool SolarSystem::getFlagIsolatedTrails() const
×
3213
{
3214
        return flagIsolatedTrails;
×
3215
}
3216

3217
int SolarSystem::getNumberIsolatedTrails() const
×
3218
{
3219
        return numberIsolatedTrails;
×
3220
}
3221

3222
void SolarSystem::setNumberIsolatedTrails(int n)
×
3223
{
3224
        // [1..5] - valid range for trails
3225
        numberIsolatedTrails = qBound(1, n, 5);
×
3226

3227
        if (getFlagIsolatedTrails())
×
3228
                recreateTrails();
×
3229

3230
        StelApp::immediateSave("viewing/number_isolated_trails", n);
×
3231
        emit numberIsolatedTrailsChanged(numberIsolatedTrails);
×
3232
}
×
3233

3234
void SolarSystem::setFlagOrbits(bool b)
×
3235
{
3236
        if(b!=getFlagOrbits())
×
3237
        {
3238
                flagOrbits = b;
×
3239
                StelApp::immediateSave("astro/flag_planets_orbits", b);
×
3240
                emit flagOrbitsChanged(b);
×
3241
        }
3242
}
×
3243

3244
// Connect this to all signals when orbit selection or selected object has changed.
3245
// This method goes through all planets and sets orbit drawing as configured by several flags
3246
void SolarSystem::reconfigureOrbits()
×
3247
{
3248
        // 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.
3249
        // The first
3250
        // we have: flagOrbits O, flagIsolatedOrbits I, flagPlanetsOrbitsOnly P, flagOrbitsWithMoons M, flagPermanentOrbits and a possibly selected planet S
3251
        // permanentOrbits only influences local drawing of a single planet and can be ignored here.
3252
        // O S I P M
3253
        // 0 X X X X  NONE
3254
        // 1 0 1 X X  NONE
3255
        // 1 X 0 0 X  ALL
3256
        // 1 X 0 1 0  all planets only
3257
        // 1 X 0 1 1  all planets with their moons only
3258

3259
        // 1 1 1 0 0  only selected SSO
3260
        // 1 1 1 0 1  only selected SSO and orbits of its moon system
3261
        // 1 1 1 1 0  only selected SSO if it is a major planet
3262
        // 1 1 1 1 1  only selected SSO if it is a major planet, plus its system of moons
3263

3264
        if (!flagOrbits || (flagIsolatedOrbits && (!selected || selected==sun)))
×
3265
        {
3266
                for (const auto& p : std::as_const(systemPlanets))
×
3267
                        p->setFlagOrbits(false);
×
3268
        }
3269
        // from here, flagOrbits is certainly on
3270
        else if (!flagIsolatedOrbits)
×
3271
        {
3272
                for (const auto& p : std::as_const(systemPlanets))
×
3273
                        p->setFlagOrbits(!flagPlanetsOrbitsOnly || (p->getPlanetType()==Planet::isPlanet || (flagOrbitsWithMoons && p->parent && p->parent->getPlanetType()==Planet::isPlanet) ));
×
3274
        }
3275
        else // flagIsolatedOrbits && selected
3276
        {
3277
                // Display only orbit for selected planet and, if requested, its moons.
3278
                for (const auto& p : std::as_const(systemPlanets))
×
3279
                        p->setFlagOrbits(   (p==selected && (  !flagPlanetsOrbitsOnly ||  p->getPlanetType()==Planet::isPlanet ) )
×
3280
                                         || (flagOrbitsWithMoons && p->getPlanetType()==Planet::isMoon && p->parent==selected ) );
×
3281
        }
3282
        // 24.3: With new flag, we can override to see the orbits of major planets together with that of a single selected minor body.
3283
        if (flagOrbits && flagPlanetsOrbits)
×
3284
        {
3285
                for (const auto& p : std::as_const(systemPlanets))
×
3286
                        if ((p->getPlanetType()==Planet::isPlanet) || (flagOrbitsWithMoons && p->getPlanetType()==Planet::isMoon ))
×
3287
                                p->setFlagOrbits(true);
×
3288
        }
3289
}
×
3290

3291
void SolarSystem::setFlagIsolatedOrbits(bool b)
×
3292
{
3293
        if(b!=flagIsolatedOrbits)
×
3294
        {
3295
                flagIsolatedOrbits = b;
×
3296
                StelApp::immediateSave("viewing/flag_isolated_orbits", b);
×
3297
                emit flagIsolatedOrbitsChanged(b);
×
3298
        }
3299
}
×
3300

3301
bool SolarSystem::getFlagIsolatedOrbits() const
×
3302
{
3303
        return flagIsolatedOrbits;
×
3304
}
3305

3306
void SolarSystem::setFlagPlanetsOrbits(bool b)
×
3307
{
3308
        if(b!=flagPlanetsOrbits)
×
3309
        {
3310
                flagPlanetsOrbits = b;
×
3311
                StelApp::immediateSave("viewing/flag_planets_orbits", b);
×
3312
                emit flagPlanetsOrbitsChanged(b);
×
3313
        }
3314
}
×
3315

3316
bool SolarSystem::getFlagPlanetsOrbits() const
×
3317
{
3318
        return flagPlanetsOrbits;
×
3319
}
3320

3321
void SolarSystem::setFlagPlanetsOrbitsOnly(bool b)
×
3322
{
3323
        if(b!=flagPlanetsOrbitsOnly)
×
3324
        {
3325
                flagPlanetsOrbitsOnly = b;
×
3326
                StelApp::immediateSave("viewing/flag_planets_orbits_only", b);
×
3327
                emit flagPlanetsOrbitsOnlyChanged(b);
×
3328
        }
3329
}
×
3330

3331
bool SolarSystem::getFlagPlanetsOrbitsOnly() const
×
3332
{
3333
        return flagPlanetsOrbitsOnly;
×
3334
}
3335

3336
void SolarSystem::setFlagOrbitsWithMoons(bool b)
×
3337
{
3338
        if(b!=flagOrbitsWithMoons)
×
3339
        {
3340
                flagOrbitsWithMoons = b;
×
3341
                StelApp::immediateSave("viewing/flag_orbits_with_moons", b);
×
3342
                emit flagOrbitsWithMoonsChanged(b);
×
3343
        }
3344
}
×
3345

3346
bool SolarSystem::getFlagOrbitsWithMoons() const
×
3347
{
3348
        return flagOrbitsWithMoons;
×
3349
}
3350

3351
// Set/Get planets names color
3352
void SolarSystem::setLabelsColor(const Vec3f& c)
×
3353
{
3354
        if (c!=Planet::getLabelColor())
×
3355
        {
3356
                Planet::setLabelColor(c);
×
3357
                emit labelsColorChanged(c);
×
3358
        }
3359
}
×
3360

3361
Vec3f SolarSystem::getLabelsColor(void) const
×
3362
{
3363
        return Planet::getLabelColor();
×
3364
}
3365

3366
// Set/Get orbits lines color
3367
void SolarSystem::setOrbitsColor(const Vec3f& c)
×
3368
{
3369
        if (c!=Planet::getOrbitColor())
×
3370
        {
3371
                Planet::setOrbitColor(c);
×
3372
                emit orbitsColorChanged(c);
×
3373
        }
3374
}
×
3375

3376
Vec3f SolarSystem::getOrbitsColor(void) const
×
3377
{
3378
        return Planet::getOrbitColor();
×
3379
}
3380

3381
void SolarSystem::setMajorPlanetsOrbitsColor(const Vec3f &c)
×
3382
{
3383
        if (c!=Planet::getMajorPlanetOrbitColor())
×
3384
        {
3385
                Planet::setMajorPlanetOrbitColor(c);
×
3386
                emit majorPlanetsOrbitsColorChanged(c);
×
3387
        }
3388
}
×
3389

3390
Vec3f SolarSystem::getMajorPlanetsOrbitsColor(void) const
×
3391
{
3392
        return Planet::getMajorPlanetOrbitColor();
×
3393
}
3394

3395
void SolarSystem::setMinorPlanetsOrbitsColor(const Vec3f &c)
×
3396
{
3397
        if (c!=Planet::getMinorPlanetOrbitColor())
×
3398
        {
3399
                Planet::setMinorPlanetOrbitColor(c);
×
3400
                emit minorPlanetsOrbitsColorChanged(c);
×
3401
        }
3402
}
×
3403

3404
Vec3f SolarSystem::getMinorPlanetsOrbitsColor(void) const
×
3405
{
3406
        return Planet::getMinorPlanetOrbitColor();
×
3407
}
3408

3409
void SolarSystem::setDwarfPlanetsOrbitsColor(const Vec3f &c)
×
3410
{
3411
        if (c!=Planet::getDwarfPlanetOrbitColor())
×
3412
        {
3413
                Planet::setDwarfPlanetOrbitColor(c);
×
3414
                emit dwarfPlanetsOrbitsColorChanged(c);
×
3415
        }
3416
}
×
3417

3418
Vec3f SolarSystem::getDwarfPlanetsOrbitsColor(void) const
×
3419
{
3420
        return Planet::getDwarfPlanetOrbitColor();
×
3421
}
3422

3423
void SolarSystem::setMoonsOrbitsColor(const Vec3f &c)
×
3424
{
3425
        if (c!=Planet::getMoonOrbitColor())
×
3426
        {
3427
                Planet::setMoonOrbitColor(c);
×
3428
                emit moonsOrbitsColorChanged(c);
×
3429
        }
3430
}
×
3431

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

3437
void SolarSystem::setCubewanosOrbitsColor(const Vec3f &c)
×
3438
{
3439
        if (c!=Planet::getCubewanoOrbitColor())
×
3440
        {
3441
                Planet::setCubewanoOrbitColor(c);
×
3442
                emit cubewanosOrbitsColorChanged(c);
×
3443
        }
3444
}
×
3445

3446
Vec3f SolarSystem::getCubewanosOrbitsColor(void) const
×
3447
{
3448
        return Planet::getCubewanoOrbitColor();
×
3449
}
3450

3451
void SolarSystem::setPlutinosOrbitsColor(const Vec3f &c)
×
3452
{
3453
        if (c!=Planet::getPlutinoOrbitColor())
×
3454
        {
3455
                Planet::setPlutinoOrbitColor(c);
×
3456
                emit plutinosOrbitsColorChanged(c);
×
3457
        }
3458
}
×
3459

3460
Vec3f SolarSystem::getPlutinosOrbitsColor(void) const
×
3461
{
3462
        return Planet::getPlutinoOrbitColor();
×
3463
}
3464

3465
void SolarSystem::setScatteredDiskObjectsOrbitsColor(const Vec3f &c)
×
3466
{
3467
        if (c!=Planet::getScatteredDiscObjectOrbitColor())
×
3468
        {
3469
                Planet::setScatteredDiscObjectOrbitColor(c);
×
3470
                emit scatteredDiskObjectsOrbitsColorChanged(c);
×
3471
        }
3472
}
×
3473

3474
Vec3f SolarSystem::getScatteredDiskObjectsOrbitsColor(void) const
×
3475
{
3476
        return Planet::getScatteredDiscObjectOrbitColor();
×
3477
}
3478

3479
void SolarSystem::setOortCloudObjectsOrbitsColor(const Vec3f &c)
×
3480
{
3481
        if (c!=Planet::getOortCloudObjectOrbitColor())
×
3482
        {
3483
                Planet::setOortCloudObjectOrbitColor(c);
×
3484
                emit oortCloudObjectsOrbitsColorChanged(c);
×
3485
        }
3486
}
×
3487

3488
Vec3f SolarSystem::getOortCloudObjectsOrbitsColor(void) const
×
3489
{
3490
        return Planet::getOortCloudObjectOrbitColor();
×
3491
}
3492

3493
void SolarSystem::setCometsOrbitsColor(const Vec3f& c)
×
3494
{
3495
        if (c!=Planet::getCometOrbitColor())
×
3496
        {
3497
                Planet::setCometOrbitColor(c);
×
3498
                emit cometsOrbitsColorChanged(c);
×
3499
        }
3500
}
×
3501

3502
Vec3f SolarSystem::getCometsOrbitsColor(void) const
×
3503
{
3504
        return Planet::getCometOrbitColor();
×
3505
}
3506

3507
void SolarSystem::setSednoidsOrbitsColor(const Vec3f& c)
×
3508
{
3509
        if (c!=Planet::getSednoidOrbitColor())
×
3510
        {
3511
                Planet::setSednoidOrbitColor(c);
×
3512
                emit sednoidsOrbitsColorChanged(c);
×
3513
        }
3514
}
×
3515

3516
Vec3f SolarSystem::getSednoidsOrbitsColor(void) const
×
3517
{
3518
        return Planet::getSednoidOrbitColor();
×
3519
}
3520

3521
void SolarSystem::setInterstellarOrbitsColor(const Vec3f& c)
×
3522
{
3523
        if (c!=Planet::getInterstellarOrbitColor())
×
3524
        {
3525
                Planet::setInterstellarOrbitColor(c);
×
3526
                emit interstellarOrbitsColorChanged(c);
×
3527
        }
3528
}
×
3529

3530
Vec3f SolarSystem::getInterstellarOrbitsColor(void) const
×
3531
{
3532
        return Planet::getInterstellarOrbitColor();
×
3533
}
3534

3535
void SolarSystem::setMercuryOrbitColor(const Vec3f &c)
×
3536
{
3537
        if (c!=Planet::getMercuryOrbitColor())
×
3538
        {
3539
                Planet::setMercuryOrbitColor(c);
×
3540
                emit mercuryOrbitColorChanged(c);
×
3541
        }
3542
}
×
3543

3544
Vec3f SolarSystem::getMercuryOrbitColor(void) const
×
3545
{
3546
        return Planet::getMercuryOrbitColor();
×
3547
}
3548

3549
void SolarSystem::setVenusOrbitColor(const Vec3f &c)
×
3550
{
3551
        if (c!=Planet::getVenusOrbitColor())
×
3552
        {
3553
                Planet::setVenusOrbitColor(c);
×
3554
                emit venusOrbitColorChanged(c);
×
3555
        }
3556
}
×
3557

3558
Vec3f SolarSystem::getVenusOrbitColor(void) const
×
3559
{
3560
        return Planet::getVenusOrbitColor();
×
3561
}
3562

3563
void SolarSystem::setEarthOrbitColor(const Vec3f &c)
×
3564
{
3565
        if (c!=Planet::getEarthOrbitColor())
×
3566
        {
3567
                Planet::setEarthOrbitColor(c);
×
3568
                emit earthOrbitColorChanged(c);
×
3569
        }
3570
}
×
3571

3572
Vec3f SolarSystem::getEarthOrbitColor(void) const
×
3573
{
3574
        return Planet::getEarthOrbitColor();
×
3575
}
3576

3577
void SolarSystem::setMarsOrbitColor(const Vec3f &c)
×
3578
{
3579
        if (c!=Planet::getMarsOrbitColor())
×
3580
        {
3581
                Planet::setMarsOrbitColor(c);
×
3582
                emit marsOrbitColorChanged(c);
×
3583
        }
3584
}
×
3585

3586
Vec3f SolarSystem::getMarsOrbitColor(void) const
×
3587
{
3588
        return Planet::getMarsOrbitColor();
×
3589
}
3590

3591
void SolarSystem::setJupiterOrbitColor(const Vec3f &c)
×
3592
{
3593
        if (c!=Planet::getJupiterOrbitColor())
×
3594
        {
3595
                Planet::setJupiterOrbitColor(c);
×
3596
                emit jupiterOrbitColorChanged(c);
×
3597
        }
3598
}
×
3599

3600
Vec3f SolarSystem::getJupiterOrbitColor(void) const
×
3601
{
3602
        return Planet::getJupiterOrbitColor();
×
3603
}
3604

3605
void SolarSystem::setSaturnOrbitColor(const Vec3f &c)
×
3606
{
3607
        if (c!=Planet::getSaturnOrbitColor())
×
3608
        {
3609
                Planet::setSaturnOrbitColor(c);
×
3610
                emit saturnOrbitColorChanged(c);
×
3611
        }
3612
}
×
3613

3614
Vec3f SolarSystem::getSaturnOrbitColor(void) const
×
3615
{
3616
        return Planet::getSaturnOrbitColor();
×
3617
}
3618

3619
void SolarSystem::setUranusOrbitColor(const Vec3f &c)
×
3620
{
3621
        if (c!=Planet::getUranusOrbitColor())
×
3622
        {
3623
                Planet::setUranusOrbitColor(c);
×
3624
                emit uranusOrbitColorChanged(c);
×
3625
        }
3626
}
×
3627

3628
Vec3f SolarSystem::getUranusOrbitColor(void) const
×
3629
{
3630
        return Planet::getUranusOrbitColor();
×
3631
}
3632

3633
void SolarSystem::setNeptuneOrbitColor(const Vec3f &c)
×
3634
{
3635
        if (c!=Planet::getNeptuneOrbitColor())
×
3636
        {
3637
                Planet::setNeptuneOrbitColor(c);
×
3638
                emit neptuneOrbitColorChanged(c);
×
3639
        }
3640
}
×
3641

3642
Vec3f SolarSystem::getNeptuneOrbitColor(void) const
×
3643
{
3644
        return Planet::getNeptuneOrbitColor();
×
3645
}
3646

3647
// Set/Get if Moon display is scaled
3648
void SolarSystem::setFlagMoonScale(bool b)
×
3649
{
3650
        if(b!=flagMoonScale)
×
3651
        {
3652
                if (b) getMoon()->setSphereScale(moonScale);
×
3653
                else getMoon()->setSphereScale(1);
×
3654
                flagMoonScale = b;
×
3655
                StelApp::immediateSave("viewing/flag_moon_scaled", b);
×
3656
                emit flagMoonScaleChanged(b);
×
3657
        }
3658
}
×
3659

3660
// Set/Get Moon display scaling factor. This goes directly to the Moon object.
3661
void SolarSystem::setMoonScale(double f)
×
3662
{
3663
        if(!fuzzyEquals(moonScale, f))
×
3664
        {
3665
                moonScale = f;
×
3666
                if (flagMoonScale)
×
3667
                        getMoon()->setSphereScale(moonScale);
×
3668
                StelApp::immediateSave("viewing/moon_scale", f);
×
3669
                emit moonScaleChanged(f);
×
3670
        }
3671
}
×
3672

3673
// Set if minor body display is scaled. This flag will be queried by all Planet objects except for the Moon.
3674
void SolarSystem::setFlagMinorBodyScale(bool b)
×
3675
{
3676
        if(b!=flagMinorBodyScale)
×
3677
        {
3678
                flagMinorBodyScale = b;
×
3679

3680
                double newScale = b ? minorBodyScale : 1.0;
×
3681
                //update the bodies with the new scale
3682
                for (const auto& p : std::as_const(systemPlanets))
×
3683
                {
3684
                        if(p == moon) continue;
×
3685
                        if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
×
3686
                                p->setSphereScale(newScale);
×
3687
                }
3688
                StelApp::immediateSave("viewing/flag_minorbodies_scaled", b);
×
3689
                emit flagMinorBodyScaleChanged(b);
×
3690
        }
3691
}
×
3692

3693
// Set minor body display scaling factor. This will be queried by all Planet objects except for the Moon.
3694
void SolarSystem::setMinorBodyScale(double f)
×
3695
{
3696
        if(!fuzzyEquals(minorBodyScale, f))
×
3697
        {
3698
                minorBodyScale = f;
×
3699
                if(flagMinorBodyScale) //update the bodies with the new scale
×
3700
                {
3701
                        for (const auto& p : std::as_const(systemPlanets))
×
3702
                        {
3703
                                if(p == moon) continue;
×
3704
                                if (p->getPlanetType()!=Planet::isPlanet && p->getPlanetType()!=Planet::isStar)
×
3705
                                        p->setSphereScale(minorBodyScale);
×
3706
                        }
3707
                }
3708
                StelApp::immediateSave("viewing/minorbodies_scale", f);
×
3709
                emit minorBodyScaleChanged(f);
×
3710
        }
3711
}
×
3712

3713
// Set if Planet display is scaled
3714
void SolarSystem::setFlagPlanetScale(bool b)
×
3715
{
3716
        if(b!=flagPlanetScale)
×
3717
        {
3718
                double scale=(b ? planetScale : 1.);
×
3719
                for (auto& p : systemPlanets)
×
3720
                {
3721
                        if (p->pType==Planet::isPlanet)
×
3722
                                p->setSphereScale(scale);
×
3723
                }
3724
                flagPlanetScale = b;
×
3725
                StelApp::immediateSave("viewing/flag_planets_scaled", b);
×
3726
                emit flagPlanetScaleChanged(b);
×
3727
        }
3728
}
×
3729

3730
// Set Moon display scaling factor.
3731
void SolarSystem::setPlanetScale(double f)
×
3732
{
3733
        if(!fuzzyEquals(planetScale, f))
×
3734
        {
3735
                planetScale = f;
×
3736
                if (flagPlanetScale)
×
3737
                        for (auto& p : systemPlanets)
×
3738
                        {
3739
                                if (p->pType==Planet::isPlanet)
×
3740
                                        p->setSphereScale(planetScale);
×
3741
                        }
3742
                StelApp::immediateSave("viewing/planets_scale", f);
×
3743
                emit planetScaleChanged(f);
×
3744
        }
3745
}
×
3746

3747
// Set if Sun display is scaled
3748
void SolarSystem::setFlagSunScale(bool b)
×
3749
{
3750
        if(b!=flagSunScale)
×
3751
        {
3752
                if (b) getSun()->setSphereScale(sunScale);
×
3753
                else getSun()->setSphereScale(1);
×
3754
                flagSunScale = b;
×
3755
                StelApp::immediateSave("viewing/flag_sun_scaled", b);
×
3756
                emit flagSunScaleChanged(b);
×
3757
        }
3758
}
×
3759

3760
// Set Sun display scaling factor. This goes directly to the Sun object.
3761
void SolarSystem::setSunScale(double f)
×
3762
{
3763
        if(!fuzzyEquals(sunScale, f))
×
3764
        {
3765
                sunScale = f;
×
3766
                if (flagSunScale)
×
3767
                        getSun()->setSphereScale(sunScale);
×
3768
                StelApp::immediateSave("viewing/sun_scale", f);
×
3769
                emit sunScaleChanged(f);
×
3770
        }
3771
}
×
3772

3773
// Set selected planets by englishName
3774
void SolarSystem::setSelected(const QString& englishName)
×
3775
{
3776
        setSelected(searchByEnglishName(englishName));
×
3777
}
×
3778

3779
// Get the list of all the planet english names
3780
QStringList SolarSystem::getAllPlanetEnglishNames() const
×
3781
{
3782
        QStringList res;
×
3783
        for (const auto& p : systemPlanets)
×
3784
                res.append(p->getEnglishName());
×
3785
        return res;
×
3786
}
×
3787

3788
QStringList SolarSystem::getAllPlanetLocalizedNames() const
×
3789
{
3790
        QStringList res;
×
3791
        for (const auto& p : systemPlanets)
×
3792
                res.append(p->getNameI18n());
×
3793
        return res;
×
3794
}
×
3795

3796
QStringList SolarSystem::getAllMinorPlanetCommonEnglishNames() const
×
3797
{
3798
        QStringList res;
×
3799
        for (const auto& p : systemMinorBodies)
×
3800
                res.append(p->getCommonEnglishName());
×
3801
        return res;
×
3802
}
×
3803

3804

3805
// 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.
3806
void SolarSystem::reloadPlanets()
×
3807
{
3808
        // Save flag states
3809
        const bool flagScaleMoon = getFlagMoonScale();
×
3810
        const double moonScale = getMoonScale();
×
3811
        const bool flagScaleMinorBodies=getFlagMinorBodyScale();
×
3812
        const double minorScale= getMinorBodyScale();
×
3813
        const bool flagPlanets = getFlagPlanets();
×
3814
        const bool flagHints = getFlagHints();
×
3815
        const bool flagLabels = getFlagLabels();
×
3816
        const bool flagOrbits = getFlagOrbits();
×
3817
        const bool flagNative = getFlagNativePlanetNames();
×
3818
        bool hasSelection = false;
×
3819

3820
        // Save observer location (fix for LP bug # 969211)
3821
        // TODO: This can probably be done better with a better understanding of StelObserver --BM
3822
        StelCore* core = StelApp::getInstance().getCore();
×
3823
        const StelLocation loc = core->getCurrentLocation();
×
3824
        StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr);
×
3825

3826
        // Whether any planet are selected? Save the current selection...
3827
        const QList<StelObjectP> selectedObject = objMgr->getSelectedObject("Planet");
×
3828
        if (!selectedObject.isEmpty())
×
3829
        {
3830
                // ... unselect current planet.
3831
                hasSelection = true;
×
3832
                objMgr->unSelect();
×
3833
        }
3834
        // Unload all Solar System objects
3835
        selected.clear();//Release the selected one
×
3836

3837
        // GZ TODO in case this methods gets converted to only reload minor bodies: Only delete Orbits which are not referenced by some Planet.
3838
        for (auto* orb : std::as_const(orbits))
×
3839
        {
3840
                delete orb;
×
3841
        }
3842
        orbits.clear();
×
3843

3844
        sun.clear();
×
3845
        moon.clear();
×
3846
        earth.clear();
×
3847
        Planet::texEarthShadow.clear(); //Loaded in loadPlanets()
×
3848

3849
        delete allTrails;
×
3850
        allTrails = Q_NULLPTR;
×
3851

3852
        for (const auto& p : std::as_const(systemPlanets))
×
3853
        {
3854
                p->satellites.clear();
×
3855
        }
3856
        systemPlanets.clear();
×
3857
        systemMinorBodies.clear();
×
3858
        // Memory leak? What's the proper way of cleaning shared pointers?
3859

3860
        // Also delete Comet textures (loaded in loadPlanets()
3861
        Comet::tailTexture.clear();
×
3862
        Comet::comaTexture.clear();
×
3863

3864
        // Re-load the ssystem_major.ini and ssystem_minor.ini file
3865
        loadPlanets();        
×
3866
        computePositions(core, core->getJDE(), getSun());
×
3867
        setSelected("");
×
3868
        recreateTrails();
×
3869
        
3870
        // Restore observer location
3871
        core->moveObserverTo(loc, 0., 0.);
×
3872

3873
        // Restore flag states
3874
        setFlagMoonScale(flagScaleMoon);
×
3875
        setMoonScale(moonScale);
×
3876
        setFlagMinorBodyScale(flagScaleMinorBodies);
×
3877
        setMinorBodyScale(1.0); // force-reset first to really reach the objects in the next call.
×
3878
        setMinorBodyScale(minorScale);
×
3879
        setFlagPlanets(flagPlanets);
×
3880
        setFlagHints(flagHints);
×
3881
        setFlagLabels(flagLabels);
×
3882
        setFlagOrbits(flagOrbits);
×
3883
        setFlagNativePlanetNames(flagNative);
×
3884

3885
        // Restore translations
3886
        updateI18n();
×
3887

3888
        if (hasSelection)
×
3889
        {
3890
                // Restore selection...
3891
                StelObjectP obj = selectedObject[0];
×
3892
                objMgr->findAndSelect(obj->getEnglishName(), obj->getType());
×
3893
        }
×
3894

3895
        emit solarSystemDataReloaded();
×
3896
}
×
3897

3898
// Set the algorithm for computation of apparent magnitudes for planets in case  observer on the Earth
3899
void SolarSystem::setApparentMagnitudeAlgorithmOnEarth(const QString &algorithm)
×
3900
{
3901
        Planet::ApparentMagnitudeAlgorithm id=vMagAlgorithmMap.key(algorithm);
×
3902
        Planet::setApparentMagnitudeAlgorithm(id);
×
3903
        StelApp::immediateSave("astro/apparent_magnitude_algorithm", algorithm);
×
3904
        emit apparentMagnitudeAlgorithmOnEarthChanged(algorithm);
×
3905
}
×
3906
// overloaded for GUI efficiency
3907
void SolarSystem::setApparentMagnitudeAlgorithmOnEarth(const Planet::ApparentMagnitudeAlgorithm id)
×
3908
{
3909
        QString name =vMagAlgorithmMap.value(id);
×
3910
        Planet::setApparentMagnitudeAlgorithm(id);
×
3911
        StelApp::immediateSave("astro/apparent_magnitude_algorithm", name);
×
3912
        emit apparentMagnitudeAlgorithmOnEarthChanged(name);
×
3913
}
×
3914

3915
// Get the algorithm used for computation of apparent magnitudes for planets in case  observer on the Earth
3916
QString SolarSystem::getApparentMagnitudeAlgorithmOnEarth() const
×
3917
{
3918
        return vMagAlgorithmMap.value(Planet::getApparentMagnitudeAlgorithm());
×
3919
}
3920

3921
void SolarSystem::setFlagDrawMoonHalo(bool b)
×
3922
{
3923
        Planet::drawMoonHalo=b;
×
3924
        StelApp::immediateSave("viewing/flag_draw_moon_halo", b);
×
3925
        emit flagDrawMoonHaloChanged(b);
×
3926
}
×
3927

3928
bool SolarSystem::getFlagDrawMoonHalo() const
×
3929
{
3930
        return Planet::drawMoonHalo;
×
3931
}
3932

3933
void SolarSystem::setFlagDrawSunHalo(bool b)
×
3934
{
3935
        Planet::drawSunHalo=b;
×
3936
        StelApp::immediateSave("viewing/flag_draw_sun_halo", b);
×
3937
        emit flagDrawSunHaloChanged(b);
×
3938
}
×
3939

3940
bool SolarSystem::getFlagDrawSunHalo() const
×
3941
{
3942
        return Planet::drawSunHalo;
×
3943
}
3944

3945
void SolarSystem::setFlagPermanentOrbits(bool b)
×
3946
{
3947
        if (Planet::permanentDrawingOrbits!=b)
×
3948
        {
3949
                Planet::permanentDrawingOrbits=b;
×
3950
                StelApp::immediateSave("astro/flag_permanent_orbits", b);
×
3951
                emit flagPermanentOrbitsChanged(b);
×
3952
        }
3953
}
×
3954

3955
bool SolarSystem::getFlagPermanentOrbits() const
×
3956
{
3957
        return Planet::permanentDrawingOrbits;
×
3958
}
3959

3960
void SolarSystem::setOrbitsThickness(int v)
×
3961
{
3962
        if (v!=Planet::orbitsThickness)
×
3963
        {
3964
                Planet::orbitsThickness=v;
×
3965
                StelApp::immediateSave("astro/object_orbits_thickness", v);
×
3966
                emit orbitsThicknessChanged(v);
×
3967
        }
3968
}
×
3969

3970
int SolarSystem::getOrbitsThickness() const
×
3971
{
3972
        return Planet::orbitsThickness;
×
3973
}
3974

3975
void SolarSystem::setGrsLongitude(int longitude)
×
3976
{
3977
        RotationElements::grsLongitude = longitude;
×
3978
        // automatic saving of the setting
3979
        conf->setValue("astro/grs_longitude", longitude);
×
3980
        emit grsLongitudeChanged(longitude);
×
3981
}
×
3982

3983
int SolarSystem::getGrsLongitude() const
×
3984
{
3985
        return static_cast<int>(RotationElements::grsLongitude);
×
3986
}
3987

3988
void SolarSystem::setGrsDrift(double drift)
×
3989
{
3990
        RotationElements::grsDrift = drift;
×
3991
        // automatic saving of the setting
3992
        conf->setValue("astro/grs_drift", drift);
×
3993
        emit grsDriftChanged(drift);
×
3994
}
×
3995

3996
double SolarSystem::getGrsDrift() const
×
3997
{
3998
        return RotationElements::grsDrift;
×
3999
}
4000

4001
void SolarSystem::setGrsJD(double JD)
×
4002
{
4003
        RotationElements::grsJD = JD;
×
4004
        // automatic saving of the setting
4005
        conf->setValue("astro/grs_jd", JD);
×
4006
        emit grsJDChanged(JD);
×
4007
}
×
4008

4009
double SolarSystem::getGrsJD()
×
4010
{
4011
        return RotationElements::grsJD;
×
4012
}
4013

4014
void SolarSystem::setFlagEarthShadowEnlargementDanjon(bool b)
×
4015
{
4016
        earthShadowEnlargementDanjon=b;
×
4017
        StelApp::immediateSave("astro/shadow_enlargement_danjon", b);
×
4018
        emit earthShadowEnlargementDanjonChanged(b);
×
4019
}
×
4020

4021
bool SolarSystem::getFlagEarthShadowEnlargementDanjon() const
×
4022
{
4023
        return earthShadowEnlargementDanjon;
×
4024
}
4025

4026
void SolarSystem::setOrbitColorStyle(const QString &style)
×
4027
{
4028
        static const QMap<QString, Planet::PlanetOrbitColorStyle>map={
4029
                { QString("groups"),                    Planet::ocsGroups},
×
4030
                { QString("major_planets"),             Planet::ocsMajorPlanets},
×
4031
                { QString("major_planets_minor_types"), Planet::ocsMajorPlanetsMinorTypes}
×
4032
        };
×
4033
        Planet::PlanetOrbitColorStyle st=map.value(style.toLower(), Planet::ocsOneColor);
×
4034
        Planet::orbitColorStyle = st;
×
4035
        StelApp::immediateSave("astro/planets_orbits_color_style", style);
×
4036
        emit orbitColorStyleChanged(style);
×
4037
}
×
4038

4039
QString SolarSystem::getOrbitColorStyle() const
×
4040
{
4041
        static const QMap<Planet::PlanetOrbitColorStyle, QString>map={
4042
                { Planet::ocsOneColor,               "one_color"},
×
4043
                { Planet::ocsGroups,                 "groups"},
×
4044
                { Planet::ocsMajorPlanets,           "major_planets"},
×
4045
                { Planet::ocsMajorPlanetsMinorTypes, "major_planets_minor_types"},
×
4046
        };
×
4047
        return map.value(Planet::orbitColorStyle, "one_color");
×
4048
}
×
4049

4050
// TODO: To make the code better understandable, get rid of planet->computeModelMatrix(trans, true) here.
4051
QPair<double, PlanetP> SolarSystem::getSolarEclipseFactor(const StelCore* core) const
×
4052
{
4053
        PlanetP p;
×
4054
        const Vec3d Lp = sun->getEclipticPos() + sun->getAberrationPush();
×
4055
        const Vec3d P3 = core->getObserverHeliocentricEclipticPos();
×
4056
        const double RS = sun->getEquatorialRadius();
×
4057

4058
        double final_illumination = 1.0;
×
4059

4060
        for (const auto& planet : systemPlanets)
×
4061
        {
4062
                if(planet == sun || planet == core->getCurrentPlanet())
×
4063
                        continue;
×
4064

4065
                // 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...
4066
                static const QStringList fromEarth({"Moon", "Mercury", "Venus"});
×
4067
                if ((core->getCurrentPlanet() == earth) && !fromEarth.contains(planet->englishName))
×
4068
                        continue;
×
4069

4070
                Mat4d trans;
×
4071
                planet->computeModelMatrix(trans, true);
×
4072

4073
                const Vec3d C = trans * Vec3d(0., 0., 0.);
×
4074
                const double radius = planet->getEquatorialRadius();
×
4075

4076
                Vec3d v1 = Lp - P3;
×
4077
                Vec3d v2 = C - P3;
×
4078
                const double L = v1.norm();
×
4079
                const double l = v2.norm();
×
4080
                v1 /= L;
×
4081
                v2 /= l;
×
4082

4083
                const double R = RS / L;
×
4084
                const double r = radius / l;
×
4085
                const double d = ( v1 - v2 ).norm();
×
4086
                double illumination;
4087

4088
                if(d >= R + r) // distance too far
×
4089
                {
4090
                        illumination = 1.0;
×
4091
                }
4092
                else if(d <= r - R) // umbra
×
4093
                {
4094
                        illumination = 0.0;
×
4095
                }
4096
                else if(d <= R - r) // penumbra completely inside
×
4097
                {
4098
                        illumination = 1.0 - r * r / (R * R);
×
4099
                }
4100
                else // penumbra partially inside
4101
                {
4102
                        const double x = (R * R + d * d - r * r) / (2.0 * d);
×
4103

4104
                        const double alpha = std::acos(x / R);
×
4105
                        const double beta = std::acos((d - x) / r);
×
4106

4107
                        const double AR = R * R * (alpha - 0.5 * std::sin(2.0 * alpha));
×
4108
                        const double Ar = r * r * (beta - 0.5 * std::sin(2.0 * beta));
×
4109
                        const double AS = R * R * 2.0 * std::asin(1.0);
×
4110

4111
                        illumination = 1.0 - (AR + Ar) / AS;
×
4112
                }
4113

4114
                if(illumination < final_illumination)
×
4115
                {
4116
                        final_illumination = illumination;
×
4117
                        p = planet;
×
4118
                }
4119
        }
4120

4121
        return QPair<double, PlanetP>(final_illumination, p);
×
4122
}
×
4123

4124
// Opening angle of the bright Solar crescent, radians
4125
// From: J. Meeus, Morsels IV, ch.15
4126
// lunarSize: apparent Lunar radius or diameter, angular units of your preference
4127
// solarSize: apparent Solar radius or diameter, resp., same angular units
4128
// eclipseMagnitude: covered fraction of the Solar diameter.
4129
double SolarSystem::getEclipseCrescentAngle(const double lunarSize, const double solarSize, const double eclipseMagnitude)
×
4130
{
4131
        const double R = lunarSize/solarSize;
×
4132
        const double cosAhalf = 2.*eclipseMagnitude * (R-eclipseMagnitude)/(1.+R-2.*eclipseMagnitude) - 1.;
×
4133
        return (std::fabs(cosAhalf) <= 1. ? 2.*acos(cosAhalf) : 0.);
×
4134
}
4135

4136
// Retrieve Radius of Umbra and Penumbra at the distance of the Moon.
4137
// Returns a pair (umbra, penumbra) in (geocentric_arcseconds, AU, geometric_AU).
4138
// * sizes in arcseconds are the usual result found as Bessel element in eclipse literature.
4139
//   It includes scaling for effects of atmosphere either after Chauvenet (2%) or after Danjon. (see Espenak: 5000 Years Canon of Lunar Eclipses.)
4140
// * sizes in AU are the same, converted back to AU in Lunar distance.
4141
// * sizes in geometric_AU derived from pure geometrical evaluations without scalings applied.
4142
QPair<Vec3d,Vec3d> SolarSystem::getEarthShadowRadiiAtLunarDistance() const
×
4143
{
4144
        // Note: The application of this shadow enlargement is not according to the books, but looks close enough for now.
4145
        static const double sun2earth=sun->getEquatorialRadius() / earth->getEquatorialRadius();
×
4146
        PlanetP sun=getSun();
×
4147
        PlanetP moon=getMoon();
×
4148
        PlanetP earth=getEarth();
×
4149
        const double lunarDistance=moon->getEclipticPos().norm(); // Lunar distance [AU]
×
4150
        const double earthDistance=earth->getHeliocentricEclipticPos().norm(); // Earth distance [AU]
×
4151
        const double sunHP =asin(earth->getEquatorialRadius()/earthDistance) * M_180_PI*3600.; // arcsec.
×
4152
        const double moonHP=asin(earth->getEquatorialRadius()/lunarDistance) * M_180_PI*3600.; // arcsec.
×
4153
        const double sunSD  =atan(sun->getEquatorialRadius()/earthDistance)  * M_180_PI*3600.; // arcsec.
×
4154

4155
        // Compute umbra radius at lunar distance.
4156
        const double lUmbra=earthDistance/(sun2earth-1.); // length of earth umbra [AU]
×
4157
        const double rUmbraAU=earth->getEquatorialRadius()*(lUmbra-lunarDistance)/lUmbra; // radius of earth shadow at lunar distance [AU]
×
4158
        // Penumbra:
4159
        const double lPenumbra=earthDistance/(sun2earth + 1.); // distance between earth and point between sun and earth where penumbral border rays intersect
×
4160
        const double rPenumbraAU=earth->getEquatorialRadius()*(lPenumbra+lunarDistance)/lPenumbra; // radius of penumbra at Lunar distance [AU]
×
4161

4162
        //Classical Bessel elements instead
4163
        double f1, f2;
4164
        if (earthShadowEnlargementDanjon)
×
4165
        {
4166
                static const double danjonScale=1+1./85.-1./594.; // ~1.01, shadow magnification factor (see Espenak 5000 years Canon)
4167
                f1=danjonScale*moonHP + sunHP + sunSD; // penumbra radius, arcsec
×
4168
                f2=danjonScale*moonHP + sunHP - sunSD; // umbra radius, arcsec
×
4169
        }
4170
        else
4171
        {
4172
                const double mHP1=0.998340*moonHP;
×
4173
                f1=1.02*(mHP1 + sunHP + sunSD); // penumbra radius, arcsec
×
4174
                f2=1.02*(mHP1 + sunHP - sunSD); // umbra radius, arcsec
×
4175
        }
4176
        const double f1_AU=tan(f1/3600.*M_PI_180)*lunarDistance;
×
4177
        const double f2_AU=tan(f2/3600.*M_PI_180)*lunarDistance;
×
4178
        return QPair<Vec3d,Vec3d>(Vec3d(f2, f2_AU, rUmbraAU), Vec3d(f1, f1_AU, rPenumbraAU));
×
4179
}
×
4180

4181
bool SolarSystem::removeMinorPlanet(const QString &name)
×
4182
{
4183
        PlanetP candidate = searchMinorPlanetByEnglishName(name);
×
4184
        if (!candidate)
×
4185
        {
4186
                qWarning() << "Cannot remove planet " << name << ": Not found.";
×
4187
                return false;
×
4188
        }
4189

4190
        Orbit* orbPtr=static_cast<Orbit*>(candidate->orbitPtr);
×
4191
        if (orbPtr)
×
4192
                orbits.removeOne(orbPtr);
×
4193
        systemPlanets.removeOne(candidate);
×
4194
        systemMinorBodies.removeOne(candidate);
×
4195
        candidate.clear();
×
4196
        return true;
×
4197
}
×
4198

4199
void SolarSystem::onNewSurvey(HipsSurveyP survey)
×
4200
{
4201
        // For the moment we only consider the survey url to decide if we
4202
        // assign it to a planet.  It would be better to use some property
4203
        // for that.
4204
        QString planetName = QUrl(survey->getUrl()).fileName();
×
4205
        PlanetP pl = searchByEnglishName(planetName);
×
4206
        if (!pl || pl->survey)
×
4207
                return;
×
4208
        pl->survey = survey;
×
4209
        survey->setProperty("planet", pl->getCommonEnglishName());
×
4210
        // Not visible by default for the moment.
4211
        survey->setProperty("visible", false);
×
4212
}
×
4213

4214
void SolarSystem::setExtraThreads(int n)
×
4215
{
4216
        extraThreads=qBound(0,n,QThreadPool::globalInstance()->maxThreadCount()-1);
×
4217
        StelApp::immediateSave("astro/solar_system_threads", extraThreads);
×
4218
        emit extraThreadsChanged(extraThreads);
×
4219
}
×
4220

4221
void SolarSystem::setMarkerMagThreshold(double m)
×
4222
{
4223
        markerMagThreshold=qBound(-5.,m,37.); // sync with GUI & WUI!
×
4224
        StelApp::immediateSave("astro/planet_markers_mag_threshold", markerMagThreshold);
×
4225
        emit markerMagThresholdChanged(markerMagThreshold);
×
4226
}
×
4227

4228
const QMap<Planet::ApparentMagnitudeAlgorithm, QString> SolarSystem::vMagAlgorithmMap =
4229
{
4230
        {Planet::MallamaHilton_2018,                "Mallama2018"},
4231
        {Planet::ExplanatorySupplement_2013,        "ExpSup2013"},
4232
        {Planet::ExplanatorySupplement_1992,        "ExpSup1992"},
4233
        {Planet::Mueller_1893,                        "Mueller1893"},
4234
        {Planet::AstronomicalAlmanac_1984,        "AstrAlm1984"},
4235
        {Planet::Generic,                        "Generic"},
4236
        {Planet::UndefinedAlgorithm,                ""}
4237
};
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