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

Stellarium / stellarium / 13280109945

12 Feb 2025 07:19AM UTC coverage: 12.129% (+0.03%) from 12.099%
13280109945

Pull #3751

github

10110111
Regenerate the SC .pot file
Pull Request #3751: Switch skycultures to the new format

14613 of 120480 relevant lines covered (12.13%)

18988.36 hits per line

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

0.48
/src/core/StelCore.cpp
1
/*
2
 * Copyright (C) 2003 Fabien Chereau
3
 * Copyright (C) 2012 Matthew Gates
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18
 */
19

20
#include "StelCore.hpp"
21

22
#include "StelProjector.hpp"
23
#include "StelProjectorClasses.hpp"
24
#include "StelToneReproducer.hpp"
25
#include "StelApp.hpp"
26
#include "StelUtils.hpp"
27
#include "StelGeodesicGrid.hpp"
28
#include "StelMovementMgr.hpp"
29
#include "StelModuleMgr.hpp"
30
#include "StelPainter.hpp"
31
#include "StelLocationMgr.hpp"
32
#include "StelObserver.hpp"
33
#include "StelObjectMgr.hpp"
34
#include "Planet.hpp"
35
#include "SolarSystem.hpp"
36
#include "LandscapeMgr.hpp"
37
#include "StelTranslator.hpp"
38
#include "StelActionMgr.hpp"
39
#include "StelFileMgr.hpp"
40
#include "StelMainView.hpp"
41
#include "EphemWrapper.hpp"
42
#include "NomenclatureItem.hpp"
43
#include "precession.h"
44
#include "Star.hpp"
45

46
#include <QSettings>
47
#include <QDebug>
48
#include <QMetaEnum>
49
#include <QTimeZone>
50
#include <QFile>
51
#include <QDir>
52
#include <QRegularExpression>
53
#include <QOpenGLShaderProgram>
54

55
#include <iostream>
56
#include <fstream>
57

58
// Init static transfo matrices
59
// See vsop87.doc:
60
const Mat4d StelCore::matJ2000ToVsop87(Mat4d::xrotation(-23.4392803055555555556*M_PI_180) * Mat4d::zrotation(0.0000275*M_PI_180));
61
const Mat4d StelCore::matVsop87ToJ2000(matJ2000ToVsop87.transpose());
62
const Mat4d StelCore::matJ2000ToGalactic(-0.054875539726, 0.494109453312, -0.867666135858, 0, -0.873437108010, -0.444829589425, -0.198076386122, 0, -0.483834985808, 0.746982251810, 0.455983795705, 0, 0, 0, 0, 1);
63
const Mat4d StelCore::matGalacticToJ2000(matJ2000ToGalactic.transpose());
64
const Mat4d StelCore::matJ2000ToSupergalactic(0.37501548, -0.89832046, 0.22887497, 0, 0.34135896, -0.09572714, -0.93504565, 0, 0.86188018, 0.42878511, 0.27075058, 0, 0, 0, 0, 1);
65
const Mat4d StelCore::matSupergalacticToJ2000(matJ2000ToSupergalactic.transpose());
66
Mat4d StelCore::matJ2000ToJ1875; // gets to be initialized in constructor.
67

68
const double StelCore::JD_SECOND = 0.000011574074074074074074;        // 1/(24*60*60)=1/86400
69
const double StelCore::JD_MINUTE = 0.00069444444444444444444;        // 1/(24*60)   =1/1440
70
const double StelCore::JD_HOUR   = 0.041666666666666666666;        // 1/24
71
const double StelCore::JD_DAY    = 1.;
72
const double StelCore::ONE_OVER_JD_SECOND = 86400;                // 86400
73
const double StelCore::TZ_ERA_BEGINNING = 2395996.5;                // December 1, 1847
74

75
Vec3d StelCore::cachedParallaxDiff = Vec3d(0.,0.,0.);
76
double StelCore::cachedParallaxJD = 0.0;
77
PlanetP StelCore::cachedParallaxPlanet;
78
Vec3d StelCore::cachedAberrationVec = Vec3d(0.,0.,0.);
79
double StelCore::cachedAberrationJD = 0.0;
80
PlanetP StelCore::cachedAberrationPlanet = Q_NULLPTR;
81

82
StelCore::StelCore()
×
83
        : skyDrawer(Q_NULLPTR)
×
84
        , movementMgr(Q_NULLPTR)
×
85
        , propMgr(Q_NULLPTR)
×
86
        , geodesicGrid(Q_NULLPTR)
×
87
        , currentProjectionType(ProjectionStereographic)
×
88
        , currentDeltaTAlgorithm(EspenakMeeus)
×
89
        , position(Q_NULLPTR)
×
90
        , flagUseNutation(true)
×
91
        , flagUseAberration(true)
×
92
        , aberrationFactor(1.0)
×
93
        , flagUseParallax(true)
×
94
        , parallaxFactor(1.0)
×
95
        , flagUseTopocentricCoordinates(true)
×
96
        , timeSpeed(JD_SECOND)
×
97
        , JD(0.,0.)
×
98
        , presetSkyTime(0.)
×
99
        , milliSecondsOfLastJDUpdate(0)
×
100
        , jdOfLastJDUpdate(0.)
×
101
        , flagUseDST(true)
×
102
        , flagUseCTZ(false)
×
103
        , startupTimeStop(false)
×
104
        , deltaTCustomNDot(-26.0)
×
105
        , deltaTCustomYear(1820.0)
×
106
        , deltaTnDot(-26.0)
×
107
        , deltaTdontUseMoon(false)
×
108
        , deltaTfunc(StelUtils::getDeltaTByEspenakMeeus)
×
109
        , deltaTstart(-1999)
×
110
        , deltaTfinish(3000)
×
111
        , de430Available(false)
×
112
        , de431Available(false)
×
113
        , de430Active(false)
×
114
        , de431Active(false)
×
115
        , de440Available(false)
×
116
        , de441Available(false)
×
117
        , de440Active(false)
×
118
        , de441Active(false)
×
119
{
120
        setObjectName("StelCore");
×
121
        registerMathMetaTypes();
×
122

123
        toneReproducer = new StelToneReproducer();
×
124
        milliSecondsOfLastJDUpdate = QDateTime::currentMSecsSinceEpoch();
×
125

126
        QSettings* conf = StelApp::getInstance().getSettings();
×
127
        // Create and initialize the default projector params
128
        QString tmpstr = conf->value("projection/viewport").toString();
×
129
        currentProjectorParams.maskType = StelProjector::stringToMaskType(tmpstr);
×
130
        const int viewport_width = conf->value("projection/viewport_width", currentProjectorParams.viewportXywh[2]).toInt();
×
131
        const int viewport_height = conf->value("projection/viewport_height", currentProjectorParams.viewportXywh[3]).toInt();
×
132
        const int viewport_x = conf->value("projection/viewport_x", 0).toInt();
×
133
        const int viewport_y = conf->value("projection/viewport_y", 0).toInt();
×
134
        currentProjectorParams.viewportXywh.set(viewport_x,viewport_y,viewport_width,viewport_height);
×
135

136
        const qreal viewportCenterX = conf->value("projection/viewport_center_x",0.5*viewport_width).toDouble();
×
137
        const qreal viewportCenterY = conf->value("projection/viewport_center_y",0.5*viewport_height).toDouble();
×
138
        currentProjectorParams.viewportCenter.set(viewportCenterX, viewportCenterY);
×
139
        const qreal viewportCenterOffsetX = conf->value("projection/viewport_center_offset_x",0.).toDouble();
×
140
        const qreal viewportCenterOffsetY = conf->value("projection/viewport_center_offset_y",0.).toDouble();
×
141
        currentProjectorParams.viewportCenterOffset.set(viewportCenterOffsetX/100., viewportCenterOffsetY/100.);
×
142

143
        currentProjectorParams.viewportFovDiameter = conf->value("projection/viewport_fov_diameter", qMin(viewport_width,viewport_height)).toDouble();
×
144
        currentProjectorParams.flipHorz = conf->value("projection/flip_horz",false).toBool();
×
145
        currentProjectorParams.flipVert = conf->value("projection/flip_vert",false).toBool();
×
146

147
        currentProjectorParams.gravityLabels = conf->value("viewing/flag_gravity_labels").toBool();
×
148
        
149
        currentProjectorParams.devicePixelsPerPixel = StelApp::getInstance().getDevicePixelsPerPixel();
×
150

151
        flagUseNutation=conf->value("astro/flag_nutation", true).toBool();
×
152
        flagUseAberration=conf->value("astro/flag_aberration", true).toBool();
×
153
        aberrationFactor=conf->value("astro/aberration_factor", 1.0).toDouble();
×
154
        flagUseParallax=conf->value("astro/flag_parallax", true).toBool();
×
155
        parallaxFactor=conf->value("astro/parallax_factor", 1.0).toDouble();
×
156
        flagUseTopocentricCoordinates=conf->value("astro/flag_topocentric_coordinates", true).toBool();
×
157
        flagUseDST=conf->value("localization/flag_dst", true).toBool();
×
158

159
        // Initialize matJ2000ToJ1875 matrix
160
        double eps1875, chi1875, omega1875, psi1875;
161
        const double jdB1875 = StelUtils::getJDFromBesselianEpoch(1875.0);
×
162
        getPrecessionAnglesVondrak(jdB1875, &eps1875, &chi1875, &omega1875, &psi1875);
×
163
        matJ2000ToJ1875 = Mat4d::xrotation(84381.406*1./3600.*M_PI/180.) * Mat4d::zrotation(-psi1875) * Mat4d::xrotation(-omega1875) * Mat4d::zrotation(chi1875);
×
164
        matJ2000ToJ1875 = matJ2000ToJ1875.transpose();
×
165
}
×
166

167

168
StelCore::~StelCore()
×
169
{
170
        delete toneReproducer; toneReproducer=Q_NULLPTR;
×
171
        delete geodesicGrid; geodesicGrid=Q_NULLPTR;
×
172
        delete skyDrawer; skyDrawer=Q_NULLPTR;
×
173
        delete position; position=Q_NULLPTR;
×
174
        cachedParallaxPlanet=Q_NULLPTR;
×
175
        cachedAberrationPlanet=Q_NULLPTR;
×
176
}
×
177

178
const QMap<QString, DitheringMode>StelCore::ditheringMap={
179
        {"disabled"   , DitheringMode::Disabled},
180
        {"color565"   , DitheringMode::Color565},
181
        {"color666"   , DitheringMode::Color666},
182
        {"color888"   , DitheringMode::Color888},
183
        {"color101010", DitheringMode::Color101010}};
184

185
DitheringMode StelCore::parseDitheringMode(const QString& str)
×
186
{
187
        const auto s=str.trimmed().toLower();
×
188
        return ditheringMap.value(s, DitheringMode::Disabled);
×
189
}
×
190

191
/*************************************************************************
192
 Load core data and initialize with default values
193
*************************************************************************/
194
void StelCore::init()
×
195
{
196
        QSettings* conf = StelApp::getInstance().getSettings();
×
197

198
        const char ditheringModeKey[] = "video/dithering_mode";
×
199
        QVariant selectedDitherFormat = conf->value(ditheringModeKey);
×
200
        if(!selectedDitherFormat.isValid())
×
201
        {
202
                constexpr char defaultValue[] = "color888";
×
203
                selectedDitherFormat = defaultValue;
×
204
                conf->setValue(ditheringModeKey, defaultValue);
×
205
        }
206
        ditheringMode = parseDitheringMode(selectedDitherFormat.toString());
×
207

208
        if (conf->childGroups().contains("location_run_once"))
×
209
                defaultLocationID = "stellarium_cli";
×
210
        else
211
                defaultLocationID = conf->value("init_location/location", "auto").toString();
×
212
        bool ok;
213
        StelLocationMgr* locationMgr = &StelApp::getInstance().getLocationMgr();
×
214
        StelLocation location=locationMgr->getLastResortLocation(); // first location: Paris. Required if no IP connection on first launch!
×
215
        if (defaultLocationID == "auto")
×
216
        {
217
                locationMgr->locationFromIP();
×
218
        }
219
        else if (defaultLocationID == "stellarium_cli")
×
220
        {
221
                location = locationMgr->locationFromCLI();
×
222
        }
223
        else if (defaultLocationID.startsWith("GPS", Qt::CaseInsensitive))
×
224
        {
225
                // The location is obtained already from init_location/last_resort_location
226
                location.name = conf->value("init_location/location").toString();
×
227
        }
228
        else
229
        {
230
                location = locationMgr->locationForString(defaultLocationID);
×
231
        }
232

233
        if (!location.isValid())
×
234
        {
235
                qWarning() << "Warning: location" << defaultLocationID << "is unknown.";
×
236
                location = locationMgr->getLastResortLocation();
×
237
        }
238
        position = new StelObserver(location);
×
239

240
        QString ctz = conf->value("localization/time_zone", "").toString();
×
241
        if (!ctz.isEmpty())
×
242
                setUseCustomTimeZone(true);
×
243
        else
244
                ctz = getCurrentLocation().ianaTimeZone;
×
245
        setCurrentTimeZone(ctz);
×
246

247
        // Delta-T stuff
248
        // Define default algorithm for time correction (Delta T)
249
        QString tmpDT = conf->value("navigation/time_correction_algorithm", "EspenakMeeusModified").toString();
×
250
        setCurrentDeltaTAlgorithmKey(tmpDT);
×
251

252
        // Define variables of custom equation for calculation of Delta T
253
        // Default: ndot = -26.0 "/cy/cy; year = 1820; DeltaT = -20 + 32*u^2, where u = (currentYear-1820)/100
254
        setDeltaTCustomYear(conf->value("custom_time_correction/year", 1820.0).toDouble());
×
255
        setDeltaTCustomNDot(conf->value("custom_time_correction/ndot", -26.0).toDouble());
×
256
        setDeltaTCustomEquationCoefficients(Vec3d(conf->value("custom_time_correction/coefficients", "-20,0,32").toString()));
×
257

258
        // Time stuff
259
        setTimeNow();
×
260

261
        // We want to be able to handle the old style preset time, recorded as a double
262
        // jday, or as a more human readable string...
263
        QString presetTimeStr = conf->value("navigation/preset_sky_time",2451545.).toString();
×
264
        presetSkyTime = presetTimeStr.toDouble(&ok);
×
265
        if (ok)
×
266
        {
267
                qDebug().noquote() << "navigation/preset_sky_time is a double - treating as jday:" << QString::number(presetSkyTime, 'f', 5);
×
268
        }
269
        else
270
        {
271
                qDebug().noquote() << "navigation/preset_sky_time was not a double, treating as string date:" << presetTimeStr;
×
272
                presetSkyTime = StelUtils::qDateTimeToJd(QDateTime::fromString(presetTimeStr));
×
273
        }
274
        setInitTodayTime(QTime::fromString(conf->value("navigation/today_time", "22:00").toString()));
×
275
        startupTimeMode = conf->value("navigation/startup_time_mode", "actual").toString().toLower();
×
276
        if (startupTimeMode=="preset")        
×
277
                setJD(presetSkyTime - static_cast<double>(getUTCOffset(presetSkyTime)) * JD_HOUR);
×
278
        else if (startupTimeMode=="today")
×
279
                setTodayTime(getInitTodayTime());
×
280
        startupTimeStop = conf->value("navigation/startup_time_stop", false).toBool();
×
281
        if (startupTimeStop)
×
282
                setZeroTimeSpeed();
×
283

284
        // Compute transform matrices between coordinates systems
285
        updateTransformMatrices();
×
286
        updateFixedEquatorialTransformMatrices();
×
287
        connect(this, SIGNAL(locationChanged(const StelLocation&)), this, SLOT(updateFixedEquatorialTransformMatrices()));
×
288

289
        movementMgr = new StelMovementMgr(this);
×
290
        movementMgr->init();
×
291
        currentProjectorParams.fov = static_cast<float>(movementMgr->getInitFov());
×
292
        StelApp::getInstance().getModuleMgr().registerModule(movementMgr);
×
293

294
        skyDrawer = new StelSkyDrawer(this);
×
295
        skyDrawer->init();
×
296

297
        propMgr = StelApp::getInstance().getStelPropertyManager();
×
298
        propMgr->registerObject(skyDrawer);
×
299
        propMgr->registerObject(this);
×
300
        propMgr->registerObject(toneReproducer);
×
301

302
        setCurrentProjectionTypeKey(getDefaultProjectionTypeKey());
×
303
        updateMaximumFov();
×
304

305
        // activate DE430/431
306
        initEphemeridesFunctions();
×
307

308
        // Register all the core actions.
309
        QString timeGroup = N_("Date and Time");
×
310
        QString movementGroup = N_("Movement and Selection");
×
311
        QString displayGroup = N_("Display Options");
×
312
        StelActionMgr* actionsMgr = StelApp::getInstance().getStelActionManager();
×
313
        actionsMgr->addAction("actionIncrease_Time_Speed", timeGroup, N_("Increase time speed"), this, "increaseTimeSpeed()", "L");
×
314
        actionsMgr->addAction("actionDecrease_Time_Speed", timeGroup, N_("Decrease time speed"), this, "decreaseTimeSpeed()", "J");
×
315
        actionsMgr->addAction("actionIncrease_Time_Speed_Less", timeGroup, N_("Increase time speed (a little)"), this, "increaseTimeSpeedLess()", "Shift+L");
×
316
        actionsMgr->addAction("actionDecrease_Time_Speed_Less", timeGroup, N_("Decrease time speed (a little)"), this, "decreaseTimeSpeedLess()", "Shift+J");
×
317
        actionsMgr->addAction("actionSet_Real_Time_Speed", timeGroup, N_("Set normal time rate"), this, "toggleRealTimeSpeed()", "K");
×
318
        actionsMgr->addAction("actionSet_Time_Rate_Zero", timeGroup, N_("Set time rate to zero"), this, "setZeroTimeSpeed()", "7");
×
319
        actionsMgr->addAction("actionSet_Time_Reverse", timeGroup, N_("Set reverse time direction"), this, "revertTimeDirection()", "0");
×
320
        actionsMgr->addAction("actionReturn_To_Current_Time", timeGroup, N_("Set time to now"), this, "setTimeNow()", "8");
×
321
        actionsMgr->addAction("actionAdd_Solar_Minute", timeGroup, N_("Add 1 solar minute"), this, "addMinute()");
×
322
        actionsMgr->addAction("actionAdd_Solar_Hour", timeGroup, N_("Add 1 solar hour"), this, "addHour()", "Ctrl+=");
×
323
        actionsMgr->addAction("actionAdd_Solar_Day", timeGroup, N_("Add 1 solar day"), this, "addDay()", "=");
×
324
        actionsMgr->addAction("actionAdd_Solar_Week", timeGroup, N_("Add 7 solar days"), this, "addWeek()", "]");
×
325
        actionsMgr->addAction("actionSubtract_Solar_Minute", timeGroup, N_("Subtract 1 solar minute"), this, "subtractMinute()");
×
326
        actionsMgr->addAction("actionSubtract_Solar_Hour", timeGroup, N_("Subtract 1 solar hour"), this, "subtractHour()", "Ctrl+-");
×
327
        actionsMgr->addAction("actionSubtract_Solar_Day", timeGroup, N_("Subtract 1 solar day"), this, "subtractDay()", "-");
×
328
        actionsMgr->addAction("actionSubtract_Solar_Week", timeGroup, N_("Subtract 7 solar days"), this, "subtractWeek()", "[");
×
329
        actionsMgr->addAction("actionAdd_Sidereal_Day", timeGroup, N_("Add 1 sidereal day"), this, "addSiderealDay()", "Alt+=");
×
330
        actionsMgr->addAction("actionAdd_Sidereal_Week", timeGroup, N_("Add 7 sidereal days"), this, "addSiderealWeek()");
×
331
        actionsMgr->addAction("actionAdd_Sidereal_Year", timeGroup, N_("Add 1 sidereal year"), this, "addSiderealYear()", "Ctrl+Alt+Shift+]");
×
332
        actionsMgr->addAction("actionAdd_Sidereal_Century", timeGroup, N_("Add 100 sidereal years"), this, "addSiderealYears()");
×
333
        actionsMgr->addAction("actionAdd_Synodic_Month", timeGroup, N_("Add 1 synodic month"), this, "addSynodicMonth()");
×
334
        actionsMgr->addAction("actionAdd_Saros", timeGroup, N_("Add 1 saros"), this, "addSaros()");
×
335
        actionsMgr->addAction("actionAdd_Draconic_Month", timeGroup, N_("Add 1 draconic month"), this, "addDraconicMonth()");
×
336
        actionsMgr->addAction("actionAdd_Draconic_Year", timeGroup, N_("Add 1 draconic year"), this, "addDraconicYear()");
×
337
        actionsMgr->addAction("actionAdd_Anomalistic_Month", timeGroup, N_("Add 1 anomalistic month"), this, "addAnomalisticMonth()");
×
338
        actionsMgr->addAction("actionAdd_Anomalistic_Year", timeGroup, N_("Add 1 anomalistic year"), this, "addAnomalisticYear()");
×
339
        actionsMgr->addAction("actionAdd_Anomalistic_Century", timeGroup, N_("Add 100 anomalistic years"), this, "addAnomalisticYears()");
×
340
        actionsMgr->addAction("actionAdd_Mean_Tropical_Month", timeGroup, N_("Add 1 mean tropical month"), this, "addMeanTropicalMonth()");
×
341
        actionsMgr->addAction("actionAdd_Mean_Tropical_Year", timeGroup, N_("Add 1 mean tropical year"), this, "addMeanTropicalYear()");
×
342
        actionsMgr->addAction("actionAdd_Mean_Tropical_Century", timeGroup, N_("Add 100 mean tropical years"), this, "addMeanTropicalYears()");
×
343
        actionsMgr->addAction("actionAdd_Tropical_Year", timeGroup, N_("Add 1 tropical year"), this, "addTropicalYear()");
×
344
        actionsMgr->addAction("actionAdd_Julian_Year", timeGroup, N_("Add 1 Julian year"), this, "addJulianYear()");
×
345
        actionsMgr->addAction("actionAdd_Julian_Century", timeGroup, N_("Add 1 Julian century"), this, "addJulianYears()");
×
346
        actionsMgr->addAction("actionAdd_Gaussian_Year", timeGroup, N_("Add 1 Gaussian year"), this, "addGaussianYear()");
×
347
        actionsMgr->addAction("actionAdd_Calendar_Month", timeGroup, N_("Add 1 calendar month"), this, "addCalendarMonth()");
×
348
        actionsMgr->addAction("actionAdd_Calendar_Year", timeGroup, N_("Add 1 calendar year"), this, "addCalendarYear()");
×
349
        actionsMgr->addAction("actionAdd_Calendar_Decade", timeGroup, N_("Add 10 calendar years"), this, "addCalendarDecade()");
×
350
        actionsMgr->addAction("actionAdd_Calendar_Century", timeGroup, N_("Add 100 calendar years"), this, "addCalendarCentury()");
×
351
        actionsMgr->addAction("actionAdd_Great_Year", timeGroup, N_("Add 1 Great year"), this, "addGreatYear()");
×
352
        actionsMgr->addAction("actionSubtract_Sidereal_Day", timeGroup, N_("Subtract 1 sidereal day"), this, "subtractSiderealDay()", "Alt+-");
×
353
        actionsMgr->addAction("actionSubtract_Sidereal_Week", timeGroup, N_("Subtract 7 sidereal days"), this, "subtractSiderealWeek()");
×
354
        actionsMgr->addAction("actionSubtract_Sidereal_Year", timeGroup, N_("Subtract 1 sidereal year"), this, "subtractSiderealYear()", "Ctrl+Alt+Shift+[");
×
355
        actionsMgr->addAction("actionSubtract_Sidereal_Century", timeGroup, N_("Subtract 100 sidereal years"), this, "subtractSiderealYears()");
×
356
        actionsMgr->addAction("actionSubtract_Synodic_Month", timeGroup, N_("Subtract 1 synodic month"), this, "subtractSynodicMonth()");
×
357
        actionsMgr->addAction("actionSubtract_Saros", timeGroup, N_("Subtract 1 saros"), this, "subtractSaros()");
×
358
        actionsMgr->addAction("actionSubtract_Draconic_Month", timeGroup, N_("Subtract 1 draconic month"), this, "subtractDraconicMonth()");
×
359
        actionsMgr->addAction("actionSubtract_Draconic_Year", timeGroup, N_("Subtract 1 draconic year"), this, "subtractDraconicYear()");
×
360
        actionsMgr->addAction("actionSubtract_Anomalistic_Month", timeGroup, N_("Subtract 1 anomalistic month"), this, "subtractAnomalisticMonth()");
×
361
        actionsMgr->addAction("actionSubtract_Anomalistic_Year", timeGroup, N_("Subtract 1 anomalistic year"), this, "subtractAnomalisticYear()");
×
362
        actionsMgr->addAction("actionSubtract_Anomalistic_Century", timeGroup, N_("Subtract 100 anomalistic years"), this, "subtractAnomalisticYears()");
×
363
        actionsMgr->addAction("actionSubtract_Mean_Tropical_Month", timeGroup, N_("Subtract 1 mean tropical month"), this, "subtractMeanTropicalMonth()");
×
364
        actionsMgr->addAction("actionSubtract_Mean_Tropical_Year", timeGroup, N_("Subtract 1 mean tropical year"), this, "subtractMeanTropicalYear()");
×
365
        actionsMgr->addAction("actionSubtract_Mean_Tropical_Century", timeGroup, N_("Subtract 100 mean tropical years"), this, "subtractMeanTropicalYears()");
×
366
        actionsMgr->addAction("actionSubtract_Tropical_Year", timeGroup, N_("Subtract 1 tropical year"), this, "subtractTropicalYear()");
×
367
        actionsMgr->addAction("actionSubtract_Julian_Year", timeGroup, N_("Subtract 1 Julian year"), this, "subtractJulianYear()");
×
368
        actionsMgr->addAction("actionSubtract_Julian_Century", timeGroup, N_("Subtract 1 Julian century"), this, "subtractJulianYears()");
×
369
        actionsMgr->addAction("actionSubtract_Gaussian_Year", timeGroup, N_("Subtract 1 Gaussian year"), this, "subtractGaussianYear()");
×
370
        actionsMgr->addAction("actionSubtract_Calendar_Month", timeGroup, N_("Subtract 1 calendar month"), this, "subtractCalendarMonth()");
×
371
        actionsMgr->addAction("actionSubtract_Calendar_Year", timeGroup, N_("Subtract 1 calendar year"), this, "subtractCalendarYear()");
×
372
        actionsMgr->addAction("actionSubtract_Calendar_Decade", timeGroup, N_("Subtract 10 calendar years"), this, "subtractCalendarDecade()");
×
373
        actionsMgr->addAction("actionSubtract_Calendar_Century", timeGroup, N_("Subtract 100 calendar years"), this, "subtractCalendarCentury()");
×
374
        actionsMgr->addAction("actionSubtract_Great_Year", timeGroup, N_("Subtract 1 Great year"), this, "subtractGreatYear()");
×
375

376
        actionsMgr->addAction("actionSet_Home_Planet_To_Selected", movementGroup, N_("Set home planet to selected planet"), this, "moveObserverToSelected()", "Ctrl+G");
×
377
        actionsMgr->addAction("actionGo_Home_Global", movementGroup, N_("Go to home"), this, "returnToHome()", "Ctrl+H");
×
378

379
        actionsMgr->addAction("actionHorizontal_Flip", displayGroup, N_("Flip scene horizontally"), this, "flipHorz", "Ctrl+Shift+H", "", true);
×
380
        actionsMgr->addAction("actionVertical_Flip", displayGroup, N_("Flip scene vertically"), this, "flipVert", "Ctrl+Shift+V", "", true);
×
381
}
×
382

383
QString StelCore::getDefaultProjectionTypeKey() const
×
384
{
385
        QSettings* conf = StelApp::getInstance().getSettings();
×
386
        return conf->value("projection/type", "ProjectionStereographic").toString();
×
387
}
388

389
// Get the shared instance of StelGeodesicGrid.
390
// The returned instance is guaranteed to allow for at least maxLevel levels
391
const StelGeodesicGrid* StelCore::getGeodesicGrid(int maxLevel) const
×
392
{
393
        if (geodesicGrid==Q_NULLPTR)
×
394
        {
395
                geodesicGrid = new StelGeodesicGrid(maxLevel);
×
396
        }
397
        else if (maxLevel>geodesicGrid->getMaxLevel())
×
398
        {
399
                delete geodesicGrid;
×
400
                geodesicGrid = new StelGeodesicGrid(maxLevel);
×
401
        }
402
        return geodesicGrid;
×
403
}
404

405
StelProjectorP StelCore::getProjection2d() const
×
406
{
407
        StelProjectorP prj(new StelProjector2d());
×
408
        prj->init(currentProjectorParams);
×
409
        return prj;
×
410
}
×
411

412
StelProjectorP StelCore::getProjection(StelProjector::ModelViewTranformP modelViewTransform, ProjectionType projType) const
×
413
{
414
        if (projType==static_cast<ProjectionType>(1000))
×
415
                projType = currentProjectionType;
×
416

417
        StelProjectorP prj;
×
418
        switch (projType)
×
419
        {
420
                case ProjectionPerspective:
×
421
                        prj = StelProjectorP(new StelProjectorPerspective(modelViewTransform));
×
422
                        break;
×
423
                case ProjectionEqualArea:
×
424
                        prj = StelProjectorP(new StelProjectorEqualArea(modelViewTransform));
×
425
                        break;
×
426
                case ProjectionStereographic:
×
427
                        prj = StelProjectorP(new StelProjectorStereographic(modelViewTransform));
×
428
                        break;
×
429
                case ProjectionFisheye:
×
430
                        prj = StelProjectorP(new StelProjectorFisheye(modelViewTransform));
×
431
                        break;
×
432
                case ProjectionHammer:
×
433
                        prj = StelProjectorP(new StelProjectorHammer(modelViewTransform));
×
434
                        break;
×
435
                case ProjectionCylinder:
×
436
                        prj = StelProjectorP(new StelProjectorCylinder(modelViewTransform));
×
437
                        break;
×
438
                case ProjectionCylinderFill:
×
439
                        prj = StelProjectorP(new StelProjectorCylinderFill(modelViewTransform));
×
440
                        break;
×
441
                case ProjectionMercator:
×
442
                        prj = StelProjectorP(new StelProjectorMercator(modelViewTransform));
×
443
                        break;
×
444
                case ProjectionOrthographic:
×
445
                        prj = StelProjectorP(new StelProjectorOrthographic(modelViewTransform));
×
446
                        break;
×
447
                case ProjectionSinusoidal:
×
448
                        prj = StelProjectorP(new StelProjectorSinusoidal(modelViewTransform));
×
449
                        break;
×
450
                case ProjectionMiller:
×
451
                        prj = StelProjectorP(new StelProjectorMiller(modelViewTransform));
×
452
                        break;
×
453
                default:
×
454
                        qWarning() << "Unknown projection type: " << static_cast<int>(projType) << "using ProjectionStereographic instead";
×
455
                        prj = StelProjectorP(new StelProjectorStereographic(modelViewTransform));
×
456
                        Q_ASSERT(0);
×
457
        }
458
        prj->init(currentProjectorParams);
×
459
        return prj;
×
460
}
×
461

462
// Get an instance of projector using the current display parameters from Navigation, StelMovementMgr
463
StelProjectorP StelCore::getProjection(FrameType frameType, RefractionMode refractionMode) const
×
464
{
465
        switch (frameType)
×
466
        {
467
                case FrameAltAz:
×
468
                        return getProjection(getAltAzModelViewTransform(refractionMode));
×
469
                case FrameHeliocentricEclipticJ2000:
×
470
                        return getProjection(getHeliocentricEclipticModelViewTransform(refractionMode));
×
471
                case FrameObservercentricEclipticJ2000:
×
472
                        return getProjection(getObservercentricEclipticJ2000ModelViewTransform(refractionMode));
×
473
                case FrameObservercentricEclipticOfDate:
×
474
                        return getProjection(getObservercentricEclipticOfDateModelViewTransform(refractionMode));
×
475
                case FrameEquinoxEqu:
×
476
                        return getProjection(getEquinoxEquModelViewTransform(refractionMode));
×
477
                case FrameFixedEquatorial:
×
478
                        return getProjection(getFixedEquatorialModelViewTransform(refractionMode));
×
479
                case FrameJ2000:
×
480
                        return getProjection(getJ2000ModelViewTransform(refractionMode));
×
481
                case FrameGalactic:
×
482
                        return getProjection(getGalacticModelViewTransform(refractionMode));
×
483
                case FrameSupergalactic:
×
484
                        return getProjection(getSupergalacticModelViewTransform(refractionMode));
×
485
                default:
×
486
                        qDebug() << "Unknown reference frame type: " << static_cast<int>(frameType) << ".";
×
487
        }
488
        Q_ASSERT(0);
×
489
        return getProjection2d();
490
}
491

492
SphericalCap StelCore::getVisibleSkyArea() const
×
493
{
494
        const LandscapeMgr* landscapeMgr = GETSTELMODULE(LandscapeMgr);
×
495
        Vec3d up(0, 0, 1);
×
496
        up = altAzToJ2000(up, RefractionOff);
×
497
        
498
        // Limit star drawing to above landscape's minimal altitude (was const=-0.035, Bug lp:1469407)
499
        if (landscapeMgr->getIsLandscapeFullyVisible())
×
500
        {
501
                return SphericalCap(up, landscapeMgr->getLandscapeSinMinAltitudeLimit());
×
502
        }
503
        return SphericalCap(up, -1.);
×
504
}
505

506
// Handle the resizing of the window
507
void StelCore::windowHasBeenResized(qreal x, qreal y, qreal width, qreal height)
×
508
{
509
        // Maximize display when resized since it invalidates previous options anyway
510
        currentProjectorParams.viewportXywh.set(qRound(x), qRound(y), qRound(width), qRound(height));
×
511
        currentProjectorParams.viewportCenter.set(x+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*width, y+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*height);
×
512
        currentProjectorParams.viewportFovDiameter = qMin(width,height);
×
513

514
        if (currentProjectionType==ProjectionType::ProjectionCylinderFill)
×
515
        {
516
                currentProjectorParams.widthStretch=0.5*width/height;
×
517
                currentProjectorParams.viewportFovDiameter = height;
×
518
        }
519
}
×
520

521
/*************************************************************************
522
 Update all the objects in function of the time
523
*************************************************************************/
524
void StelCore::update(double deltaTime)
×
525
{
526
        // Update the position of observation and time and recompute planet positions etc...
527
        updateTime(deltaTime);
×
528

529
        // Transform matrices between coordinates systems
530
        updateTransformMatrices();
×
531

532
        // Update direction of vision/Zoom level
533
        movementMgr->updateMotion(deltaTime);
×
534

535
        currentProjectorParams.fov = static_cast<float>(movementMgr->getCurrentFov());
×
536

537
        skyDrawer->update(deltaTime);
×
538
}
×
539

540

541
/*************************************************************************
542
 Execute all the pre-drawing functions
543
*************************************************************************/
544
void StelCore::preDraw()
×
545
{
546
        // Init openGL viewing with fov, screen size and clip planes
547
        currentProjectorParams.zNear = 0.000001;
×
548
        currentProjectorParams.zFar = 500.;
×
549

550
        // Clear the render buffer.
551
        // Here we can set a sky background color if really wanted (art
552
        // applications. Astronomical sky should be 0/0/0/0)
553
        Vec3f backColor = StelMainView::getInstance().getSkyBackgroundColor();
×
554
        QOpenGLFunctions* gl = QOpenGLContext::currentContext()->functions();
×
555
        gl->glClearColor(backColor[0], backColor[1], backColor[2], 0.f);
×
556
        gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
×
557

558
        skyDrawer->preDraw();
×
559
}
×
560

561

562
/*************************************************************************
563
 Update core state after drawing modules
564
*************************************************************************/
565
void StelCore::postDraw()
×
566
{
567
        StelPainter sPainter(getProjection(StelCore::FrameJ2000));
×
568
        sPainter.drawViewportShape();
×
569
}
×
570

571
void StelCore::updateMaximumFov()
×
572
{
573
        const float savedFov = currentProjectorParams.fov;
×
574
        currentProjectorParams.fov = 0.0001f;        // Avoid crash
×
575
        const float newMaxFov = getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())))->getMaxFov();
×
576
        movementMgr->setMaxFov(static_cast<double>(newMaxFov));
×
577
        currentProjectorParams.fov = qMin(newMaxFov, savedFov);
×
578
}
×
579

580
void StelCore::setCurrentProjectionType(ProjectionType type)
×
581
{
582
        if(type!=currentProjectionType)
×
583
        {
584
                QSettings* conf = StelApp::getInstance().getSettings();
×
585

586
                currentProjectionType=type;
×
587
                updateMaximumFov();
×
588
                if (currentProjectionType==ProjectionType::ProjectionCylinderFill)
×
589
                {
590
                        // Save whatever stretch is present into config.ini. This value is saved just temporarily until switching back to another projection and will not be loaded on startup.
591
                        // (To configure a stretch at startup, use startup.ssc script.)
592
                        conf->setValue("projection/width_stretch", currentProjectorParams.widthStretch);
×
593
                        currentProjectorParams.fov=180.f;
×
594
                        currentProjectorParams.widthStretch=0.5*currentProjectorParams.viewportXywh[2]/currentProjectorParams.viewportXywh[3];
×
595
                        currentProjectorParams.viewportFovDiameter = currentProjectorParams.viewportXywh[3];
×
596
                        Q_ASSERT(movementMgr);
×
597
                        movementMgr->setViewportVerticalOffsetTarget(0.);
×
598
                        movementMgr->zoomTo(180., 0.5);
×
599
                }
600
                else
601
                {
602
                        // reset to what is stored in config.ini
603
                        currentProjectorParams.widthStretch=conf->value("projection/width_stretch", 1.0).toDouble();
×
604
                }
605

606
                emit currentProjectionTypeChanged(type);
×
607
                emit currentProjectionTypeKeyChanged(getCurrentProjectionTypeKey());
×
608
                emit currentProjectionNameI18nChanged(getCurrentProjectionNameI18n());
×
609
        }
610
}
×
611

612
StelCore::ProjectionType StelCore::getCurrentProjectionType() const
×
613
{
614
        return currentProjectionType;
×
615
}
616

617
//! Set the current projection type to use
618
void StelCore::setCurrentProjectionTypeKey(QString key)
×
619
{
620
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
621
        ProjectionType newType = static_cast<ProjectionType>(en.keyToValue(key.toLatin1().data()));
×
622
        if (newType<0)
×
623
        {
624
                qWarning() << "Unknown projection type: " << key << "setting \"ProjectionStereographic\" instead";
×
625
                key="ProjectionStereographic";
×
626
                newType = ProjectionStereographic;
×
627
        }
628
        StelApp::immediateSave("projection/type", key);
×
629
        setCurrentProjectionType(newType);
×
630
}
×
631

632
//! Get the current Mapping used by the Projection
633
QString StelCore::getCurrentProjectionTypeKey(void) const
×
634
{
635
        return metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType")).key(currentProjectionType);
×
636
}
637

638
QString StelCore::getCurrentProjectionNameI18n() const
×
639
{
640
        return projectionTypeKeyToNameI18n(getCurrentProjectionTypeKey());
×
641
}
642

643
//! Get the list of all the available projections
644
QStringList StelCore::getAllProjectionTypeKeys() const
×
645
{
646
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
647
        QStringList l;
×
648
        for (int i=0;i<en.keyCount();++i)
×
649
                l << en.key(i);
×
650
        return l;
×
651
}
×
652

653
void StelCore::setMaskType(StelProjector::StelProjectorMaskType m)
×
654
{
655
        currentProjectorParams.maskType = m;
×
656
}
×
657

658
void StelCore::setFlagGravityLabels(bool gravity)
×
659
{
660
        currentProjectorParams.gravityLabels = gravity;
×
661
        StelApp::immediateSave("viewing/flag_gravity_labels", gravity);
×
662
        emit flagGravityLabelsChanged(gravity);
×
663
}
×
664

665
bool StelCore::getFlagGravityLabels() const
×
666
{
667
        return currentProjectorParams.gravityLabels;
×
668
}
669

670
void StelCore::setDefaultAngleForGravityText(float a)
×
671
{
672
        currentProjectorParams.defaultAngleForGravityText = a;
×
673
}
×
674

675
void StelCore::setFlipHorz(bool flip)
×
676
{
677
        if (currentProjectorParams.flipHorz != flip)
×
678
        {
679
                currentProjectorParams.flipHorz = flip;
×
680
                StelApp::immediateSave("projection/flip_horz", flip);
×
681
                emit flipHorzChanged(flip);
×
682
        }
683
}
×
684

685
void StelCore::setFlipVert(bool flip)
×
686
{
687
        if (currentProjectorParams.flipVert != flip)
×
688
        {
689
                currentProjectorParams.flipVert = flip;
×
690
                StelApp::immediateSave("projection/flip_vert", flip);
×
691
                emit flipVertChanged(flip);
×
692
        }
693
}
×
694

695
bool StelCore::getFlipHorz(void) const
×
696
{
697
        return currentProjectorParams.flipHorz;
×
698
}
699

700
bool StelCore::getFlipVert(void) const
×
701
{
702
        return currentProjectorParams.flipVert;
×
703
}
704

705
// Get current value for horizontal viewport offset [-50...50]
706
double StelCore::getViewportHorizontalOffset(void) const
×
707
{
708
        return (currentProjectorParams.viewportCenterOffset[0] * 100.0);
×
709
}
710
// Set horizontal viewport offset. Argument will be clamped to be inside [-50...50]
711
void StelCore::setViewportHorizontalOffset(double newOffsetPct)
×
712
{
713
        currentProjectorParams.viewportCenterOffset[0]=0.01* qBound(-50., newOffsetPct, 50.);
×
714
        currentProjectorParams.viewportCenter.set(currentProjectorParams.viewportXywh[0]+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*currentProjectorParams.viewportXywh[2],
×
715
                                                currentProjectorParams.viewportXywh[1]+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*currentProjectorParams.viewportXywh[3]);
×
716
}
×
717

718
// Get current value for vertical viewport offset [-50...50]
719
double StelCore::getViewportVerticalOffset(void) const
×
720
{
721
        return (currentProjectorParams.viewportCenterOffset[1] * 100.0);
×
722
}
723
// Set vertical viewport offset. Argument will be clamped to be inside [-50...50]
724
void StelCore::setViewportVerticalOffset(double newOffsetPct)
×
725
{
726
        currentProjectorParams.viewportCenterOffset[1]=0.01* qBound(-50., newOffsetPct, 50.);
×
727
        currentProjectorParams.viewportCenter.set(currentProjectorParams.viewportXywh[0]+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*currentProjectorParams.viewportXywh[2],
×
728
                                                currentProjectorParams.viewportXywh[1]+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*currentProjectorParams.viewportXywh[3]);
×
729
}
×
730

731
// Set both viewport offsets. Arguments will be clamped to be inside [-50...50]. I (GZ) hope this will avoid some of the shaking.
732
void StelCore::setViewportOffset(double newHorizontalOffsetPct, double newVerticalOffsetPct)
×
733
{
734
        currentProjectorParams.viewportCenterOffset[0]=0.01* qBound(-50., newHorizontalOffsetPct, 50.);
×
735
        currentProjectorParams.viewportCenterOffset[1]=0.01* qBound(-50., newVerticalOffsetPct,   50.);
×
736
        currentProjectorParams.viewportCenter.set(currentProjectorParams.viewportXywh[0]+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*currentProjectorParams.viewportXywh[2],
×
737
                                                currentProjectorParams.viewportXywh[1]+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*currentProjectorParams.viewportXywh[3]);
×
738
}
×
739

740
void StelCore::setViewportStretch(float stretch)
×
741
{
742
        currentProjectorParams.widthStretch=static_cast<qreal>(qMax(0.001f, stretch));
×
743
}
×
744

745
QString StelCore::getDefaultLocationID() const
×
746
{
747
        return defaultLocationID;
×
748
}
749

750
QString StelCore::projectionTypeKeyToNameI18n(const QString& key) const
×
751
{
752
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
753
        QString s(getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())), static_cast<ProjectionType>(en.keyToValue(key.toLatin1())))->getNameI18());
×
754
        return s;
×
755
}
756

757
QString StelCore::projectionNameI18nToTypeKey(const QString& nameI18n) const
×
758
{
759
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
760
        for (int i=0;i<en.keyCount();++i)
×
761
        {
762
                if (getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())), static_cast<ProjectionType>(i))->getNameI18()==nameI18n)
×
763
                        return en.valueToKey(i);
×
764
        }
765
        // Unknown translated name
766
        Q_ASSERT(0);
×
767
        return en.valueToKey(ProjectionStereographic);
768
}
769

770
StelProjector::StelProjectorParams StelCore::getCurrentStelProjectorParams() const
×
771
{
772
        return currentProjectorParams;
×
773
}
774

775
void StelCore::setCurrentStelProjectorParams(const StelProjector::StelProjectorParams& newParams)
×
776
{
777
        currentProjectorParams=newParams;
×
778
}
×
779

780
void StelCore::lookAtJ2000(const Vec3d& pos, const Vec3d& aup)
×
781
{
782
        Vec3d f(j2000ToAltAz(pos, RefractionOff));
×
783
        Vec3d up(j2000ToAltAz(aup, RefractionOff));
×
784
        f.normalize();
×
785
        up.normalize();
×
786

787
        // Update the model view matrix
788
        Vec3d s(f^up);        // y vector
×
789
        s.normalize();
×
790
        Vec3d u(s^f);        // Up vector in AltAz coordinates
×
791
        u.normalize();
×
792
        matAltAzModelView.set(s[0],u[0],-f[0],0.,
×
793
                              s[1],u[1],-f[1],0.,
×
794
                              s[2],u[2],-f[2],0.,
×
795
                              0.,0.,0.,1.);
796
        invertMatAltAzModelView = matAltAzModelView.inverse();
×
797
}
×
798

799
//void StelCore::setMatAltAzModelView(const Mat4d& mat)
800
//{
801
//        matAltAzModelView = mat;
802
//        invertMatAltAzModelView = matAltAzModelView.inverse();
803
//}
804

805
Vec3d StelCore::altAzToEquinoxEqu(const Vec3d& v, RefractionMode refMode) const
×
806
{
807
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
808
                return matAltAzToEquinoxEqu*v;
×
809
        Vec3d r(v);
×
810
        skyDrawer->getRefraction().backward(r);
×
811
        r.transfo4d(matAltAzToEquinoxEqu);
×
812
        return r;
×
813
}
814

815
Vec3d StelCore::equinoxEquToAltAz(const Vec3d& v, RefractionMode refMode) const
×
816
{
817
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
818
                return matEquinoxEquToAltAz*v;
×
819
        Vec3d r(v);
×
820
        r.transfo4d(matEquinoxEquToAltAz);
×
821
        skyDrawer->getRefraction().forward(r);
×
822
        return r;
×
823
}
824

825
Vec3d StelCore::altAzToJ2000(const Vec3d& v, RefractionMode refMode) const
×
826
{
827
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
828
                return matEquinoxEquDateToJ2000*matAltAzToEquinoxEqu*v;
×
829
        Vec3d r(v);
×
830
        skyDrawer->getRefraction().backward(r);
×
831
        r.transfo4d(matEquinoxEquDateToJ2000*matAltAzToEquinoxEqu);
×
832
        return r;
×
833
}
834

835
Vec3d StelCore::j2000ToAltAz(const Vec3d& v, RefractionMode refMode) const
×
836
{
837
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
838
                return matJ2000ToAltAz*v;
×
839
        Vec3d r(v);
×
840
        r.transfo4d(matJ2000ToAltAz);
×
841
        skyDrawer->getRefraction().forward(r);
×
842
        return r;
×
843
}
844

845
Vec3d StelCore::galacticToJ2000(const Vec3d& v) const
×
846
{
847
        return matGalacticToJ2000*v;
×
848
}
849

850
Vec3d StelCore::supergalacticToJ2000(const Vec3d& v) const
×
851
{
852
        return matSupergalacticToJ2000*v;
×
853
}
854

855
Vec3d StelCore::equinoxEquToJ2000(const Vec3d& v, RefractionMode refMode) const
×
856
{
857
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
858
                return matEquinoxEquDateToJ2000*v;
×
859
        Vec3d r(v);
×
860
        r.transfo4d(matEquinoxEquToAltAz);
×
861
        skyDrawer->getRefraction().backward(r);
×
862
        r.transfo4d(matAltAzToJ2000);
×
863
        return r;
×
864
}
865

866
Vec3d StelCore::j2000ToEquinoxEqu(const Vec3d& v, RefractionMode refMode) const
×
867
{
868
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
869
                return matJ2000ToEquinoxEqu*v;
×
870
        Vec3d r(v);
×
871
        r.transfo4d(matJ2000ToAltAz);
×
872
        skyDrawer->getRefraction().forward(r);
×
873
        r.transfo4d(matAltAzToEquinoxEqu);
×
874
        return r;
×
875
}
876

877
Vec3d StelCore::j2000ToJ1875(const Vec3d& v) const
×
878
{
879
        return matJ2000ToJ1875*v;
×
880
}
881

882
Vec3d StelCore::j1875ToJ2000(const Vec3d& v) const
×
883
{
884
        return matJ2000ToJ1875.transpose()*v;
×
885
}
886

887
Vec3d StelCore::j2000ToGalactic(const Vec3d& v) const
×
888
{
889
        return matJ2000ToGalactic*v;
×
890
}
891

892
Vec3d StelCore::j2000ToSupergalactic(const Vec3d& v) const
×
893
{
894
        return matJ2000ToSupergalactic*v;
×
895
}
896

897
//! Transform vector from heliocentric ecliptic coordinate to altazimuthal
898
Vec3d StelCore::heliocentricEclipticToAltAz(const Vec3d& v, RefractionMode refMode) const
×
899
{
900
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
901
                return matHeliocentricEclipticJ2000ToAltAz*v;
×
902
        Vec3d r(v);
×
903
        r.transfo4d(matHeliocentricEclipticJ2000ToAltAz);
×
904
        skyDrawer->getRefraction().forward(r);
×
905
        return r;
×
906
}
907

908
//! Transform from heliocentric coordinate to equatorial at current equinox (for the planet where the observer stands)
909
Vec3d StelCore::heliocentricEclipticToEquinoxEqu(const Vec3d& v) const
×
910
{
911
        return matHeliocentricEclipticToEquinoxEqu*v;
×
912
}
913

914
/*
915
//! Transform vector from heliocentric coordinate to false equatorial : equatorial
916
//! coordinate but centered on the observer position (useful for objects close to earth)
917
//! Unused as of V0.13
918
Vec3d StelCore::heliocentricEclipticToEarthPosEquinoxEqu(const Vec3d& v) const
919
{
920
        return matAltAzToEquinoxEqu*matHeliocentricEclipticToAltAz*v;
921
}
922
*/
923

924
StelProjector::ModelViewTranformP StelCore::getHeliocentricEclipticModelViewTransform(RefractionMode refMode) const
×
925
{
926
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
927
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matHeliocentricEclipticJ2000ToAltAz));
×
928
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
929
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
930
        refr->setPreTransfoMat(matHeliocentricEclipticJ2000ToAltAz);
×
931
        refr->setPostTransfoMat(matAltAzModelView);
×
932
        return StelProjector::ModelViewTranformP(refr);
×
933
}
934

935
//! Get the modelview matrix for observer-centric ecliptic J2000 (Vsop87A) drawing
936
StelProjector::ModelViewTranformP StelCore::getObservercentricEclipticJ2000ModelViewTransform(RefractionMode refMode) const
×
937
{
938
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
939
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matJ2000ToAltAz*matVsop87ToJ2000));
×
940
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
941
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
942
        refr->setPreTransfoMat(matJ2000ToAltAz*matVsop87ToJ2000);
×
943
        refr->setPostTransfoMat(matAltAzModelView);
×
944
        return StelProjector::ModelViewTranformP(refr);
×
945
}
946

947
//! Get the modelview matrix for observer-centric ecliptic-of-date drawing
948
StelProjector::ModelViewTranformP StelCore::getObservercentricEclipticOfDateModelViewTransform(RefractionMode refMode) const
×
949
{
950
        double eps_A=getPrecessionAngleVondrakCurrentEpsilonA();
×
951
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
952
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz* Mat4d::xrotation(eps_A)));
×
953
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
954
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
955
        refr->setPreTransfoMat(matEquinoxEquToAltAz* Mat4d::xrotation(eps_A));
×
956
        refr->setPostTransfoMat(matAltAzModelView);
×
957
        return StelProjector::ModelViewTranformP(refr);
×
958
}
959

960
//! Get the modelview matrix for observer-centric equatorial at equinox drawing
961
StelProjector::ModelViewTranformP StelCore::getEquinoxEquModelViewTransform(RefractionMode refMode) const
×
962
{
963
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
964
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz));
×
965
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
966
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
967
        refr->setPreTransfoMat(matEquinoxEquToAltAz);
×
968
        refr->setPostTransfoMat(matAltAzModelView);
×
969
        return StelProjector::ModelViewTranformP(refr);
×
970
}
971

972
//! Get the modelview matrix for observer-centric fixed equatorial drawing
973
StelProjector::ModelViewTranformP StelCore::getFixedEquatorialModelViewTransform(RefractionMode refMode) const
×
974
{
975
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
976
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matFixedEquatorialToAltAz));
×
977
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
978
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
979
        refr->setPreTransfoMat(matFixedEquatorialToAltAz);
×
980
        refr->setPostTransfoMat(matAltAzModelView);
×
981
        return StelProjector::ModelViewTranformP(refr);
×
982
}
983

984
//! Get the modelview matrix for observer-centric altazimuthal drawing
985
StelProjector::ModelViewTranformP StelCore::getAltAzModelViewTransform(RefractionMode refMode) const
×
986
{
987
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
988
        {
989
                // Catch problem with improperly initialized matAltAzModelView
990
                Q_ASSERT(matAltAzModelView[0]==matAltAzModelView[0]);
×
991
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,Mat4d::identity()));
×
992
        }
993
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
994
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
995
        refr->setPostTransfoMat(matAltAzModelView);
×
996
        return StelProjector::ModelViewTranformP(refr);
×
997
}
998

999
//! Get the modelview matrix for observer-centric J2000 equatorial drawing
1000
StelProjector::ModelViewTranformP StelCore::getJ2000ModelViewTransform(RefractionMode refMode) const
×
1001
{
1002
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
1003
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz*matJ2000ToEquinoxEqu));
×
1004
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
1005
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
1006
        refr->setPreTransfoMat(matEquinoxEquToAltAz*matJ2000ToEquinoxEqu);
×
1007
        refr->setPostTransfoMat(matAltAzModelView);
×
1008
        return StelProjector::ModelViewTranformP(refr);
×
1009
}
1010

1011
//! Get the modelview matrix for observer-centric Galactic equatorial drawing
1012
StelProjector::ModelViewTranformP StelCore::getGalacticModelViewTransform(RefractionMode refMode) const
×
1013
{
1014
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
1015
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz*matJ2000ToEquinoxEqu*matGalacticToJ2000));
×
1016
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
1017
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
1018
        refr->setPreTransfoMat(matEquinoxEquToAltAz*matJ2000ToEquinoxEqu*matGalacticToJ2000);
×
1019
        refr->setPostTransfoMat(matAltAzModelView);
×
1020
        return StelProjector::ModelViewTranformP(refr);
×
1021
}
1022

1023
//! Get the modelview matrix for observer-centric Supergalactic equatorial drawing
1024
StelProjector::ModelViewTranformP StelCore::getSupergalacticModelViewTransform(RefractionMode refMode) const
×
1025
{
1026
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
1027
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz*matJ2000ToEquinoxEqu*matSupergalacticToJ2000));
×
1028
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
1029
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
1030
        refr->setPreTransfoMat(matEquinoxEquToAltAz*matJ2000ToEquinoxEqu*matSupergalacticToJ2000);
×
1031
        refr->setPostTransfoMat(matAltAzModelView);
×
1032
        return StelProjector::ModelViewTranformP(refr);
×
1033
}
1034

1035
// GZ: One of the most important functions, totally void of doc. :-(
1036
// called in update() (for every frame)
1037
void StelCore::updateTransformMatrices()
×
1038
{
1039
        matAltAzToEquinoxEqu = position->getRotAltAzToEquatorial(getJD(), getJDE());
×
1040
        matEquinoxEquToAltAz = matAltAzToEquinoxEqu.transpose();
×
1041

1042
        // multiply static J2000 earth axis tilt (eclipticalJ2000<->equatorialJ2000)
1043
        // in effect, this matrix transforms from VSOP87 ecliptical J2000 to planet-based equatorial coordinates.
1044
        // For earth, matJ2000ToEquinoxEqu is the precession matrix.        
1045
        matEquinoxEquDateToJ2000 = matVsop87ToJ2000 * position->getRotEquatorialToVsop87();
×
1046
        matJ2000ToEquinoxEqu = matEquinoxEquDateToJ2000.transpose();
×
1047
        matJ2000ToAltAz = matEquinoxEquToAltAz*matJ2000ToEquinoxEqu;
×
1048
        matAltAzToJ2000 = matJ2000ToAltAz.transpose();
×
1049

1050
        matHeliocentricEclipticToEquinoxEqu = matJ2000ToEquinoxEqu * matVsop87ToJ2000 * Mat4d::translation(-position->getCenterVsop87Pos());
×
1051

1052
        // These two next have to take into account the position of the observer on the earth/planet of observation.        
1053
        Mat4d matAltAzToVsop87 = matJ2000ToVsop87 * matEquinoxEquDateToJ2000 * matAltAzToEquinoxEqu;
×
1054
        //Mat4d tmp1 = matJ2000ToVsop87 * matEquinoxEquDateToJ2000;
1055

1056
        // Before 0.14 getDistanceFromCenter assumed spherical planets. Now uses rectangular coordinates for observer!
1057
        // In series 0.14 and 0.15, this was erroneous: offset by distance rho, but in the wrong direction.
1058
        // Attempt to fix LP:1275092. This improves the situation, but is still not perfect.
1059
        // Please keep the commented stuff until situation is really solved.
1060
        if (flagUseTopocentricCoordinates)
×
1061
        {
1062
                const Vec4d offset=position->getTopographicOffsetFromCenter(); // [rho cosPhi', rho sinPhi', phi'_rad, rho]
×
1063
                const double sigma=static_cast<double>(position->getCurrentLocation().getLatitude())*M_PI/180.0 - offset.v[2];
×
1064
                const double rho=offset.v[3];
×
1065

1066
                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * matAltAzToVsop87 *
×
1067
                                Mat4d::translation(Vec3d(rho*sin(sigma), 0., rho*cos(sigma) ));
×
1068

1069
                matHeliocentricEclipticJ2000ToAltAz =
1070
                                Mat4d::translation(Vec3d(-rho*sin(sigma), 0., -rho*cos(sigma))) * matAltAzToVsop87.transpose() *
×
1071
                                Mat4d::translation(-position->getCenterVsop87Pos());
×
1072

1073
                // Here I tried to split tmp matrix. This does not work:
1074
//                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * tmp1 *
1075
//                                Mat4d::translation(Vec3d(rho*sin(sigma), 0., rho*cos(sigma) )) * matAltAzToEquinoxEqu;
1076

1077
//                matHeliocentricEclipticJ2000ToAltAz =
1078
//                                matEquinoxEquToAltAz *
1079
//                                Mat4d::translation(Vec3d(-rho*sin(sigma), 0., -rho*cos(sigma))) * tmp1.transpose() *
1080
//                                Mat4d::translation(-position->getCenterVsop87Pos());
1081

1082

1083
//                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * tmp *
1084
//                                Mat4d::translation(Vec3d(0.,0., position->getDistanceFromCenter()));
1085

1086
//                matHeliocentricEclipticJ2000ToAltAz =  Mat4d::translation(Vec3d(0.,0.,-position->getDistanceFromCenter())) * tmp.transpose() *
1087
//                                Mat4d::translation(-position->getCenterVsop87Pos());
1088
        }
1089
        else
1090
        {
1091
                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * matAltAzToVsop87;
×
1092
                matHeliocentricEclipticJ2000ToAltAz =  matAltAzToVsop87.transpose() * Mat4d::translation(-position->getCenterVsop87Pos());
×
1093
        }
1094
}
×
1095

1096
// This avoids calling a costly operation every frame.
1097
void StelCore::updateFixedEquatorialTransformMatrices()
×
1098
{
1099
        matAltAzToFixedEquatorial = Mat4d::yrotation(M_PI_2-static_cast<double>(getCurrentLocation().getLatitude())*M_PI_180);
×
1100
        matFixedEquatorialToAltAz = matAltAzToFixedEquatorial.transpose();
×
1101
}
×
1102
// Return the observer heliocentric position
1103
Vec3d StelCore::getObserverHeliocentricEclipticPos() const
×
1104
{
1105
        return Vec3d(matAltAzToHeliocentricEclipticJ2000[12], matAltAzToHeliocentricEclipticJ2000[13], matAltAzToHeliocentricEclipticJ2000[14]);
×
1106
}
1107

1108
Vec3d StelCore::getObserverHeliocentricEclipticVelocity() const
×
1109
{
1110
        if (!position) return Vec3d(0,0,0);
×
1111

1112
        const auto& planet = *position->getHomePlanet();
×
1113
        const Vec3d planetVelocity = planet.getHeliocentricEclipticVelocity();
×
1114
        if (!flagUseTopocentricCoordinates)
×
1115
                return planetVelocity;
×
1116

1117
        const auto off = position->getTopographicOffsetFromCenter();
×
1118
        const auto rotRadius = off.v[0];
×
1119
        const auto rotPeriod = planet.getSiderealDay();
×
1120
        const auto linearSpeed = 2 * M_PI * rotRadius / rotPeriod; // AU/day
×
1121
        const auto toJ2000 = matAltAzToHeliocentricEclipticJ2000.upper3x3();
×
1122
        const auto eastwardVelocity = Vec3d(0,linearSpeed,0);
×
1123
        const auto velocity = toJ2000 * eastwardVelocity;
×
1124
        return planetVelocity + velocity;
×
1125
}
1126

1127
// Set the location to use by default at startup
1128
void StelCore::setDefaultLocationID(const QString& id)
×
1129
{
1130
        StelLocation location = StelApp::getInstance().getLocationMgr().locationForString(id);
×
1131
        if (!location.isValid())
×
1132
        {
1133
                qWarning() << "Trying to set an invalid location" << id;
×
1134
                return;
×
1135
        }
1136
        defaultLocationID = id;
×
1137
        QSettings* conf = StelApp::getInstance().getSettings();
×
1138
        Q_ASSERT(conf);
×
1139
        conf->setValue("init_location/location", id);
×
1140
}
×
1141

1142
void StelCore::returnToDefaultLocation()
×
1143
{
1144
        StelLocationMgr& locationMgr = StelApp::getInstance().getLocationMgr();
×
1145
        StelLocation loc = locationMgr.locationForString(defaultLocationID);
×
1146
        if (loc.isValid())
×
1147
                moveObserverTo(loc, 1., 2.);
×
1148
        else
1149
                qDebug() << "StelCore::returnToDefaultLocation: Location " << loc.serializeToLine().replace('\t', '|') << "is invalid. Store an entry from the locations list as default location.";
×
1150
}
×
1151

1152
void StelCore::returnToHome()
×
1153
{
1154
        // Using returnToDefaultLocation() and getCurrentLocation() introduce issue, because for flying
1155
        // between planets using SpaceShip and second method give does not exist data
1156
        StelLocationMgr& locationMgr = StelApp::getInstance().getLocationMgr();
×
1157
        StelLocation loc;
×
1158
        QSettings* conf = StelApp::getInstance().getSettings();
×
1159
        if (defaultLocationID == "auto")
×
1160
        {
1161
                locationMgr.locationFromIP();
×
1162
                loc = locationMgr.getLastResortLocation();
×
1163
        }
1164
        else
1165
                loc = locationMgr.locationForString(defaultLocationID);
×
1166

1167
        if (loc.isValid())
×
1168
                moveObserverTo(loc, conf->value("navigation/return_home_duration", 0.).toDouble()); // ability set a duration of movement (for a demo)
×
1169

1170
        PlanetP p = GETSTELMODULE(SolarSystem)->searchByEnglishName(loc.planetName);
×
1171

1172
        LandscapeMgr* landscapeMgr = GETSTELMODULE(LandscapeMgr);
×
1173
        landscapeMgr->setCurrentLandscapeID(landscapeMgr->getDefaultLandscapeID());
×
1174
        landscapeMgr->setFlagAtmosphere(p->hasAtmosphere() && conf->value("landscape/flag_atmosphere", true).toBool());
×
1175
        landscapeMgr->setFlagFog(p->hasAtmosphere() && conf->value("landscape/flag_fog", true).toBool());
×
1176
        landscapeMgr->setFlagLandscape(!p->getEnglishName().contains("observer", Qt::CaseInsensitive) && conf->value("landscape/flag_landscape", true).toBool());
×
1177

1178
        GETSTELMODULE(StelObjectMgr)->unSelect();
×
1179

1180
        StelMovementMgr* smmgr = getMovementMgr();
×
1181
        smmgr->setViewDirectionJ2000(altAzToJ2000(smmgr->getInitViewingDirection(), StelCore::RefractionOff));
×
1182
        smmgr->zoomTo(smmgr->getInitFov(), conf->value("navigation/return_fov_duration", 1.).toDouble()); // ability set a duration of zooming (for a demo)
×
1183
}
×
1184

1185
double StelCore::getJDOfLastJDUpdate() const
×
1186
{
1187
        return jdOfLastJDUpdate;
×
1188
}
1189

1190
void StelCore::setMilliSecondsOfLastJDUpdate(qint64 millis)
×
1191
{
1192
        milliSecondsOfLastJDUpdate = millis;
×
1193
}
×
1194

1195
qint64 StelCore::getMilliSecondsOfLastJDUpdate() const
×
1196
{
1197
        return milliSecondsOfLastJDUpdate;
×
1198
}
1199

1200
void StelCore::setJD(double newJD)
×
1201
{
1202
        JD.first=newJD;
×
1203
        JD.second=computeDeltaT(newJD);        
×
1204
        resetSync();
×
1205
}
×
1206

1207
double StelCore::getJD() const
×
1208
{
1209
        return JD.first;
×
1210
}
1211

1212
void StelCore::setJDE(double newJDE)
×
1213
{
1214
        // nitpickerish this is not exact, but as good as it gets...
1215
        JD.second=computeDeltaT(newJDE);
×
1216
        JD.first=newJDE-JD.second/86400.0;
×
1217
        resetSync();
×
1218
}
×
1219

1220
double StelCore::getJDE() const
×
1221
{
1222
        return JD.first+JD.second/86400.0;
×
1223
}
1224

1225

1226
void StelCore::setMJDay(double MJD)
×
1227
{
1228
        setJD(MJD+2400000.5);
×
1229
}
×
1230

1231
double StelCore::getMJDay() const
×
1232
{
1233
        return JD.first-2400000.5;
×
1234
}
1235

1236
double StelCore::getPresetSkyTime() const
×
1237
{
1238
        return presetSkyTime;
×
1239
}
1240

1241
void StelCore::setPresetSkyTime(double d)
×
1242
{
1243
        StelApp::immediateSave("navigation/preset_sky_time", d);
×
1244
        presetSkyTime=d;
×
1245
}
×
1246

1247
void StelCore::setTimeRate(double ts)
×
1248
{
1249
        timeSpeed=ts;
×
1250
        resetSync();
×
1251
        emit timeRateChanged(timeSpeed);
×
1252
}
×
1253

1254
double StelCore::getTimeRate() const
×
1255
{
1256
        return timeSpeed;
×
1257
}
1258

1259
void StelCore::revertTimeDirection(void)
×
1260
{
1261
        setTimeRate(-1*getTimeRate());
×
1262
}
×
1263

1264
void StelCore::moveObserverToSelected()
×
1265
{
1266
        StelObjectMgr* objmgr = GETSTELMODULE(StelObjectMgr);
×
1267
        Q_ASSERT(objmgr);
×
1268
        if (objmgr->getWasSelected())
×
1269
        {
1270
                Planet* pl = dynamic_cast<Planet*>(objmgr->getSelectedObject()[0].data());
×
1271
                if (pl)
×
1272
                {
1273
                        // We need to move to the selected planet. Try to generate a location from the current one
1274
                        StelLocation loc = getCurrentLocation();
×
1275
                        if (loc.planetName != pl->getEnglishName())
×
1276
                        {
1277
                                loc.planetName = pl->getEnglishName();                                
×
1278
                                loc.name = "landing site";
×
1279
                                loc.state = "";
×
1280
                                if (pl->getPlanetType()==Planet::isObserver)
×
1281
                                        loc.role=QChar('o');
×
1282
                                else
1283
                                        loc.role=QChar('X');
×
1284

1285
                                // Let's try guess name of location...
1286
                                LocationMap results = StelApp::getInstance().getLocationMgr().pickLocationsNearby(loc.planetName, loc.getLongitude(), loc.getLatitude(), 1.0f);
×
1287
                                if (!results.isEmpty())
×
1288
                                        loc = results.value(results.firstKey()); // ...and use it!
×
1289

1290
                                moveObserverTo(loc, 1, 1, pl->getEnglishName());
×
1291
                        }
×
1292
                }
×
1293
                else
1294
                {
1295
                        NomenclatureItem* ni = dynamic_cast<NomenclatureItem*>(objmgr->getSelectedObject()[0].data());
×
1296
                        if (ni)
×
1297
                        {
1298
                                // We need to move to the nomenclature item's host planet.
1299
                                StelLocation loc(ni->getEnglishName(), "", "", ni->getPlanet()->getEnglishName(), ni->getLongitude(), ni->getLatitude(), 0, 0, getCurrentTimeZone(), 1, 'X', ni->getPlanet()->getEnglishName());
×
1300
                                loc.lightPollutionLuminance = 0; // be dead sure it's zero!
×
1301

1302
                                moveObserverTo(loc, 1, 1, ni->getPlanet()->getEnglishName());
×
1303
                                objmgr->unSelect(); // no use to keep it: Marker will flicker around the screen.
×
1304
                        }
×
1305
                }
1306
        }
1307
        StelMovementMgr* mmgr = GETSTELMODULE(StelMovementMgr);
×
1308
        Q_ASSERT(mmgr);
×
1309
        mmgr->setFlagTracking(false);
×
1310
}
×
1311

1312
// Get the information on the current location
1313
const StelLocation& StelCore::getCurrentLocation() const
×
1314
{
1315
        return position->getCurrentLocation();
×
1316
}
1317

1318
const QSharedPointer<Planet> StelCore::getCurrentPlanet() const
×
1319
{
1320
        return position->getHomePlanet();
×
1321
}
1322

1323
const StelObserver *StelCore::getCurrentObserver() const
×
1324
{
1325
        return position;
×
1326
}
1327

1328
void StelCore::setObserver(StelObserver *obs)
×
1329
{
1330
        delete position;
×
1331
        position = obs;
×
1332
        if (!getUseCustomTimeZone() && !obs->getCurrentLocation().ianaTimeZone.isEmpty())
×
1333
                setCurrentTimeZone(obs->getCurrentLocation().ianaTimeZone);
×
1334
}
×
1335

1336
// Smoothly move the observer to the given location
1337
void StelCore::moveObserverTo(const StelLocation& target, double duration, double durationIfPlanetChange, const QString &landscapeID)
×
1338
{
1339
        const double d = (getCurrentLocation().planetName==target.planetName) ? duration : durationIfPlanetChange;
×
1340
        //qDebug() << "StelCore::moveObserverTo" << target.name << "in" << d << "seconds with Landscape" << landscapeID ;
1341
        if (d>0.)
×
1342
        {
1343
                StelLocation curLoc = getCurrentLocation();
×
1344
                if (position->isTraveling())
×
1345
                {
1346
                        // Avoid using a temporary location name to create another temporary one (otherwise it looks like loc1 -> loc2 -> loc3 etc..)
1347
                        curLoc.name = ".";
×
1348
                }
1349
                SpaceShipObserver* newObs = new SpaceShipObserver(curLoc, target, d);                
×
1350
                setObserver(newObs);
×
1351
                newObs->update(0);
×
1352
        }
×
1353
        else
1354
        {
1355
                setObserver(new StelObserver(target));
×
1356
        }
1357

1358
        // Auto-select observed planet for observer locations
1359
        if (target.role==QChar('o'))
×
1360
        {
1361
                // If we change to an Observer "planet", auto-select and focus on the observed object.
1362
                SolarSystem *ss=GETSTELMODULE(SolarSystem);
×
1363
                PlanetP planet=nullptr;
×
1364
                if (ss)
×
1365
                        planet=GETSTELMODULE(SolarSystem)->searchByEnglishName(target.planetName);
×
1366
                if (planet && planet->getPlanetType()==Planet::isObserver)
×
1367
                {
1368
                        StelObjectMgr *soMgr=GETSTELMODULE(StelObjectMgr);
×
1369
                        if (soMgr)
×
1370
                        {
1371
                                soMgr->findAndSelect(planet->getParent()->getEnglishName());
×
1372
                                GETSTELMODULE(StelMovementMgr)->setFlagTracking(true);
×
1373
                        }
1374
                }
1375
        }
×
1376
        emit targetLocationChanged(target, landscapeID); // inform others about our next location. E.g., let LandscapeMgr load a new landscape.
×
1377
        emit locationChanged(getCurrentLocation());
×
1378
}
×
1379

1380
double StelCore::getUTCOffset(const double JD) const
×
1381
{
1382
        int year, month, day, hour, minute, second;
1383
        StelUtils::getDateTimeFromJulianDay(JD, &year, &month, &day, &hour, &minute, &second);
×
1384
        // as analogous to second statement in getJDFromDate, nkerr
1385
        if ( year <= 0 )
×
1386
        {
1387
                year = year - 1;
×
1388
        }
1389
        //getTime/DateFromJulianDay returns UTC time, not local time
1390
        QDateTime universal(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC);
×
1391
        if (!universal.isValid())
×
1392
        {
1393
                //qWarning() << "JD " << QString("%1").arg(JD) << " out of bounds of QT help with GMT shift, using current datetime";
1394
                // Assumes the GMT shift was always the same before year -4710
1395
                // NOTE: QDateTime has no year 0, and therefore likely different leap year rules.
1396
                // Under which circumstances do we get invalid universal?
1397
                universal = QDateTime(QDate(-4710, month, day), QTime(hour, minute, second), Qt::UTC);
×
1398
        }
1399

1400
#if defined(Q_OS_WIN)
1401
        if (abs(year)<3)
1402
        {
1403
                // Mitigate a QTBUG on Windows (GH #594).
1404
                // This bug causes offset to be MIN_INT in January to March, 1AD.
1405
                // We assume a constant offset in this remote history,
1406
                // so we construct yet another date to get a valid offset.
1407
                // Application of the named time zones is inappropriate in any case.
1408
                universal = QDateTime(QDate(3, month, day), QTime(hour, minute, second), Qt::UTC);
1409
        }
1410
#endif
1411
        StelLocation loc = getCurrentLocation();
×
1412
        QString tzName = getCurrentTimeZone();
×
1413
        bool tzSpecial = QString("LMST LTST system_default").contains(tzName);
×
1414
        QTimeZone tz(tzName.toUtf8());
×
1415
        // We must fight a bug in Qt6.2 on Linux. For some reason tz.isValid() is true even for our self-named zones LMST,LTST,system_default.
1416
        // We must use an intermediate Boolean which we set to false where needed.
1417
        bool tzValid = tzSpecial ? false : tz.isValid();
×
1418

1419
        if (!tzValid && !tzSpecial)
×
1420
                qWarning().noquote() << "Invalid timezone: " << tzName;
×
1421

1422
        qint64 shiftInSeconds = 0;
×
1423
        if (tzName=="system_default" || (loc.planetName=="Earth" && !tzValid && !QString("LMST LTST").contains(tzName)))
×
1424
        {
1425
                QDateTime local = universal.toLocalTime();
×
1426
                //Both timezones should be interpreted as UTC because secsTo() converts both
1427
                //times to UTC if their zones have different daylight saving time rules.
1428
                local.setTimeSpec(Qt::UTC);
×
1429
                shiftInSeconds = universal.secsTo(local);
×
1430
                if (abs(shiftInSeconds)>50000 || shiftInSeconds==INT_MIN)
×
1431
                {
1432
                        qDebug() << "TZ system_default or invalid, At JD" << QString::number(JD, 'g', 11) << ", shift:" << shiftInSeconds;
×
1433
                }
1434
        }
×
1435
        else
1436
        {
1437
                // The first adoption of a standard time was on December 1, 1847 in Great Britain
1438
                if (tzValid && loc.planetName=="Earth" && (JD>=StelCore::TZ_ERA_BEGINNING || getUseCustomTimeZone()))
×
1439
                {
1440
                        if (getUseDST())
×
1441
                                shiftInSeconds = tz.offsetFromUtc(universal);
×
1442
                        else
1443
                                shiftInSeconds = tz.standardTimeOffset(universal);
×
1444
                        if (abs(shiftInSeconds)>500000 || shiftInSeconds==INT_MIN)
×
1445
                        {
1446
                                // Something very strange has happened. The Windows-only clause above already mitigated GH #594.
1447
                                // Trigger this with a named custom TZ like Europe/Stockholm.
1448
                                // Then try to wheel back some date in January-March from year 10 to 0. Instead of year 1, it jumps to 70,
1449
                                // an offset of INT_MIN
1450
                                qWarning() << "ERROR TRAPPED! --- Please submit a bug report with this logfile attached.";
×
1451
                                qWarning() << "TZ" << tz << "valid, but at JD" << QString::number(JD, 'g', 11) << ", shift:" << shiftInSeconds;
×
1452
                                qWarning() << "Universal reference date: " << universal.toString();
×
1453
                        }
1454
                }
1455
                else
1456
                {
1457
                        shiftInSeconds = qRound((loc.getLongitude()/15.f)*3600.f); // Local Mean Solar Time
×
1458
                }
1459
                if (tzName=="LTST")
×
1460
                        shiftInSeconds += qRound(getSolutionEquationOfTime()*60);
×
1461
        }
1462
        //qDebug() << "ShiftInSeconds:" << shiftInSeconds;
1463

1464
        // Extraterrestrial: Either use the configured Terrestrial timezone, or even a pseudo-LMST based on planet's rotation speed?
1465
        if (loc.planetName!="Earth")
×
1466
        {
1467
                if (tzValid && (JD>=StelCore::TZ_ERA_BEGINNING || getUseCustomTimeZone()))
×
1468
                {
1469
                        if (getUseDST())
×
1470
                                shiftInSeconds = tz.offsetFromUtc(universal);
×
1471
                        else
1472
                                shiftInSeconds = tz.standardTimeOffset(universal);
×
1473
                        if (shiftInSeconds==INT_MIN) // triggered error
×
1474
                        {
1475
                                // Something very strange has happened. The Windows-only clause above already mitigated GH #594.
1476
                                // Trigger this with a named custom TZ like Europe/Stockholm.
1477
                                // Then try to wheel back some date in January-March from year 10 to 0. Instead of year 1, it jumps to 70,
1478
                                // an offset of INT_MIN
1479
                                qWarning() << "ERROR TRAPPED! --- Please submit a bug report with this logfile attached.";
×
1480
                                qWarning() << "TZ" << tz << "valid, but at JD" << QString::number(JD, 'g', 11) << ", shift:" << shiftInSeconds;
×
1481
                                qWarning() << "Universal reference date: " << universal.toString();
×
1482
                        }
1483
                }
1484
                else
1485
                {
1486
                        // TODO: This should give "mean solar time" for any planet.
1487
                        // Combine rotation and orbit, or (for moons) rotation and orbit of parent planet.
1488
                        // LTST is even worse, needs equation of time for other planets.
1489
                        shiftInSeconds = 0; // For now, give UT
×
1490
                }
1491
        }
1492

1493
        return shiftInSeconds / 3600.0;
×
1494
}
×
1495

1496
QString StelCore::getCurrentTimeZone() const
×
1497
{
1498
        return currentTimeZone;
×
1499
}
1500

1501
void StelCore::setCurrentTimeZone(const QString& tz)
×
1502
{
1503
        if (StelApp::getInstance().getLocationMgr().getAllTimezoneNames().contains(tz))
×
1504
        {
1505
                currentTimeZone = tz;
×
1506
                emit currentTimeZoneChanged(tz);
×
1507
        }
1508
        else
1509
        {
1510
                qWarning() << "StelCore: Invalid timezone name:" << tz << " -- not setting timezone.";
×
1511
        }
1512
}
×
1513

1514
bool StelCore::getUseDST() const
×
1515
{
1516
        return flagUseDST;
×
1517
}
1518

1519
void StelCore::setUseDST(const bool b)
×
1520
{
1521
        flagUseDST = b;
×
1522
        StelApp::getInstance().getSettings()->setValue("localization/flag_dst", b);
×
1523
        emit flagUseDSTChanged(b);
×
1524
}
×
1525

1526
void StelCore::setDitheringMode(const DitheringMode newMode)
×
1527
{
1528
        if(newMode == ditheringMode)
×
1529
                return;
×
1530

1531
        ditheringMode = newMode;
×
1532
        StelApp::immediateSave("video/dithering_mode", ditheringMap.key(newMode, "disabled"));
×
1533
        emit ditheringModeChanged(newMode);
×
1534
}
1535

1536
void StelCore::setDitheringMode(const QString& modeName)
×
1537
{
1538
        const auto mode = parseDitheringMode(modeName);
×
1539
        setDitheringMode(mode);
×
1540
}
×
1541

1542
bool StelCore::getUseCustomTimeZone() const
×
1543
{
1544
        return flagUseCTZ;
×
1545
}
1546

1547
void StelCore::setUseCustomTimeZone(const bool b)
×
1548
{
1549
        flagUseCTZ = b;
×
1550
        emit useCustomTimeZoneChanged(b);
×
1551
}
×
1552

1553
bool StelCore::getStartupTimeStop() const
×
1554
{
1555
        return startupTimeStop;
×
1556
}
1557

1558
void StelCore::setStartupTimeStop(const bool b)
×
1559
{
1560
        startupTimeStop = b;
×
1561
        StelApp::immediateSave("navigation/startup_time_stop", b);
×
1562
        emit startupTimeStopChanged(b);
×
1563
}
×
1564

1565
double StelCore::getSolutionEquationOfTime(const double JDE) const
×
1566
{
1567
        // The full solution to the equation of time requires lots of computation. We go the fast way from Meeus, AA2, 28.3.
1568

1569
        const double T=(JDE-2451545.0)/36525.;
×
1570
        const double tau = T*0.1;
×
1571
        const double epsRad=getPrecessionAngleVondrakEpsilon(JDE);
×
1572
        const double e = (-0.0000001267*T-0.000042037)*T+0.016708634;
×
1573
        const double M = ((-0.0001537*T+35999.05029)*T+357.52911)*M_PI_180;
×
1574
        double Lo = StelUtils::fmodpos(280.4664567 + tau*(360007.6982779 + tau*(0.03032028 + tau*(1./49931. + tau*(-1./15300. - tau/2000000.)))), 360.);
×
1575
        Lo *= M_PI_180;
×
1576
        double y=tan(epsRad*0.5); y*=y;
×
1577

1578
        double E=y*sin(2.*Lo)+2.*e*sin(M)*(2.*y*cos(2.*Lo)-1.)-0.5*y*y*sin(4.*Lo)-1.25*e*e*sin(2.*M);
×
1579
        return E*M_180_PI*4.;
×
1580
}
1581

1582
double StelCore::getSolutionEquationOfTime() const
×
1583
{
1584
        const double tau = (getJDE() - 2451545.0)/365250.0;
×
1585
        const double sunMeanLongitude = StelUtils::fmodpos(280.4664567 + tau*(360007.6982779 + tau*(0.03032028 + tau*(1./49931. + tau*(-1./15300. - tau/2000000.)))), 360.);
×
1586

1587
        Vec3d pos = GETSTELMODULE(StelObjectMgr)->searchByName("Sun")->getEquinoxEquatorialPos(this);
×
1588
        double ra, dec;
1589
        StelUtils::rectToSphe(&ra, &dec, pos);
×
1590

1591
        // convert radians to degrees and reduce the angle, so that 0 <= angle < 360
1592
        const double alpha = StelUtils::fmodpos(ra*M_180_PI, 360.);
×
1593

1594
        double deltaPsi, deltaEps;
1595
        getNutationAngles(getJDE(), &deltaPsi, &deltaEps); // these are radians!
×
1596
        double equation = 4*(sunMeanLongitude - 0.0057183 - alpha + deltaPsi*M_180_PI*cos(getPrecessionAngleVondrakEpsilon(getJDE())));
×
1597
        // The equation of time is always smaller 20 minutes in absolute value
1598
        if (qAbs(equation)>20)
×
1599
        {
1600
                // If absolute value of the equation of time appears to be too large, add 24 hours (1440 minutes) to or subtract it from our result
1601
                if (equation>0.)
×
1602
                        equation -= 1440.;
×
1603
                else
1604
                        equation += 1440.;
×
1605
        }
1606

1607
        return equation;
×
1608
}
1609

1610
//! Set stellarium time to current real world time
1611
void StelCore::setTimeNow()
×
1612
{
1613
        setJD(StelUtils::getJDFromSystem());
×
1614
        // Force emit dateChanged
1615
        emit dateChanged();
×
1616
}
×
1617

1618
void StelCore::setTodayTime(const QTime& target)
×
1619
{
1620
        QDateTime dt = QDateTime::currentDateTime();
×
1621
        if (target.isValid())
×
1622
        {
1623
                dt.setTime(target);
×
1624
                // don't forget to adjust for timezone / daylight savings.
1625
                double JD = StelUtils::qDateTimeToJd(dt)-(static_cast<double>(getUTCOffset(StelUtils::getJDFromSystem())) * JD_HOUR);
×
1626
                setJD(JD);
×
1627
        }
1628
        else
1629
        {
1630
                qWarning() << "WARNING - time passed to StelCore::setTodayTime is not valid. The system time will be used." << target;
×
1631
                setTimeNow();
×
1632
        }
1633
}
×
1634

1635
//! Get whether the current stellarium time is the real world time
1636
bool StelCore::getIsTimeNow(void) const
×
1637
{
1638
        // cache last time to prevent to much slow system call
1639
        static double lastJD = getJD();
×
1640
        static bool previousResult = (fabs(getJD()-(StelUtils::getJDFromSystem()))<JD_SECOND);
×
1641
        if (fabs(lastJD-getJD())>JD_SECOND/4)
×
1642
        {
1643
                lastJD = getJD();
×
1644
                previousResult = (fabs(getJD()-(StelUtils::getJDFromSystem()))<JD_SECOND);
×
1645
        }
1646
        return previousResult;
×
1647
}
1648

1649
QTime StelCore::getInitTodayTime(void) const
×
1650
{
1651
        return initTodayTime;
×
1652
}
1653

1654
void StelCore::setInitTodayTime(const QTime& time)
×
1655
{
1656
        StelApp::immediateSave("navigation/today_time", time);
×
1657
        initTodayTime=time;
×
1658
}
×
1659

1660
void StelCore::setPresetSkyTime(QDateTime dateTime)
×
1661
{
1662
        setPresetSkyTime(StelUtils::qDateTimeToJd(dateTime));
×
1663
}
×
1664

1665
void StelCore::addMinute()
×
1666
{
1667
        addSolarDays(JD_MINUTE);
×
1668
}
×
1669

1670
void StelCore::addHour()
×
1671
{
1672
        addSolarDays(JD_HOUR);
×
1673
}
×
1674

1675
void StelCore::addDay()
×
1676
{
1677
        addSolarDays(1.0);
×
1678
}
×
1679

1680
void StelCore::addWeek()
×
1681
{
1682
        addSolarDays(7.0);
×
1683
}
×
1684

1685
void StelCore::addSiderealDay()
×
1686
{
1687
        addSiderealDays(1.0);
×
1688
}
×
1689

1690
void StelCore::addSiderealWeek()
×
1691
{
1692
        addSiderealDays(7.0);
×
1693
}
×
1694

1695
void StelCore::addSiderealYear()
×
1696
{
1697
        addSiderealYears(1.);
×
1698
}
×
1699

1700
void StelCore::addSiderealYears(double n)
×
1701
{
1702
        double days = 365.256363004;
×
1703
        double sidereal = getLocalSiderealYearLength();
×
1704
        Planet::PlanetType ptype = getCurrentPlanet()->getPlanetType();
×
1705
        if (ptype!=Planet::isObserver && ptype!=Planet::isArtificial && sidereal>0.)
×
1706
                days = sidereal;
×
1707

1708
        addSolarDays(days*n);
×
1709
}
×
1710

1711
void StelCore::addSynodicMonth()
×
1712
{
1713
        addSolarDays(29.530588853);
×
1714
}
×
1715

1716
void StelCore::addSaros()
×
1717
{
1718
        // 223 synodic months
1719
        addSolarDays(223*29.530588853);
×
1720
}
×
1721

1722
void StelCore::addDraconicMonth()
×
1723
{
1724
        addSolarDays(27.212220817);
×
1725
}
×
1726

1727
void StelCore::addMeanTropicalMonth()
×
1728
{
1729
        addSolarDays(27.321582241);
×
1730
}
×
1731

1732
void StelCore::addCalendarMonth()
×
1733
{
1734
        double cjd = getJD();
×
1735
        int year, month, day, hour, minute, second;
1736
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1737
        month++;
×
1738
        if (month>12)
×
1739
        {
1740
                month = 1;
×
1741
                year++;
×
1742
        }
1743
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1744
        setJD(cjd);
×
1745
}
×
1746

1747
void StelCore::addCalendarYear()
×
1748
{
1749
        double cjd = getJD();
×
1750
        int year, month, day, hour, minute, second;
1751
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1752
        year++;
×
1753
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1754
        setJD(cjd);
×
1755
}
×
1756

1757
void StelCore::addCalendarDecade()
×
1758
{
1759
        double cjd = getJD();
×
1760
        int year, month, day, hour, minute, second;
1761
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1762
        year+=10;
×
1763
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1764
        setJD(cjd);
×
1765
}
×
1766

1767
void StelCore::addCalendarCentury()
×
1768
{
1769
        double cjd = getJD();
×
1770
        int year, month, day, hour, minute, second;
1771
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1772
        year+=100;
×
1773
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1774
        setJD(cjd);
×
1775
}
×
1776

1777
void StelCore::addAnomalisticMonth()
×
1778
{
1779
        addSolarDays(27.554549878);
×
1780
}
×
1781

1782
void StelCore::addAnomalisticYear()
×
1783
{
1784
        addAnomalisticYears(1.);
×
1785
}
×
1786

1787
void StelCore::addAnomalisticYears(double n)
×
1788
{
1789
        addSolarDays(365.259636*n);
×
1790
}
×
1791

1792
void StelCore::addDraconicYear()
×
1793
{
1794
        addSolarDays(346.620075883);
×
1795
}
×
1796

1797
void StelCore::addMeanTropicalYear()
×
1798
{
1799
        addMeanTropicalYears(1.0);
×
1800
}
×
1801

1802
void StelCore::addTropicalYear()
×
1803
{
1804
        // Source: J. Meeus. More Mathematical Astronomy Morsels. 2002, p. 358.
1805
        // Meeus, J. & Savoie, D. The history of the tropical year. Journal of the British Astronomical Association, vol.102, no.1, p.40-42
1806
        // http://articles.adsabs.harvard.edu//full/1992JBAA..102...40M
1807
        const double T = (getJD()-2451545.0)/365250.0;
×
1808
        addSolarDays(365.242189623 - T*(0.000061522 - T*(0.0000000609 + T*0.00000026525)));
×
1809
}
×
1810

1811
void StelCore::addMeanTropicalYears(double n)
×
1812
{        
1813
        // Source: https://en.wikipedia.org/wiki/Tropical_year#Mean_tropical_year_current_value
1814
        addSolarDays(365.2421897*n); // The mean tropical year on January 1, 2000
×
1815
}
×
1816

1817
void StelCore::addJulianYear()
×
1818
{
1819
        addJulianYears(1.);
×
1820
}
×
1821

1822
void StelCore::addGaussianYear()
×
1823
{
1824
        addSolarDays(365.2568983);
×
1825
}
×
1826

1827
void StelCore::addJulianYears(double n)
×
1828
{
1829
        addSolarDays(365.25*n);
×
1830
}
×
1831

1832
void StelCore::addGreatYear()
×
1833
{
1834
        addSiderealYears(25800);
×
1835
}
×
1836

1837
void StelCore::subtractMinute()
×
1838
{
1839
        addSolarDays(-JD_MINUTE);
×
1840
}
×
1841

1842
void StelCore::subtractHour()
×
1843
{
1844
        addSolarDays(-JD_HOUR);
×
1845
}
×
1846

1847
void StelCore::subtractDay()
×
1848
{
1849
        addSolarDays(-1.0);
×
1850
}
×
1851

1852
void StelCore::subtractWeek()
×
1853
{
1854
        addSolarDays(-7.0);
×
1855
}
×
1856

1857
void StelCore::subtractSiderealDay()
×
1858
{
1859
        addSiderealDays(-1.0);
×
1860
}
×
1861

1862
void StelCore::subtractSiderealWeek()
×
1863
{
1864
        addSiderealDays(-7.0);
×
1865
}
×
1866

1867
void StelCore::subtractSiderealYear()
×
1868
{
1869
        addSiderealYears(-1.);
×
1870
}
×
1871

1872
void StelCore::subtractSiderealYears(double n)
×
1873
{
1874
        addSiderealYears(-n);
×
1875
}
×
1876

1877
void StelCore::subtractSynodicMonth()
×
1878
{
1879
        addSolarDays(-29.530588853);
×
1880
}
×
1881

1882
void StelCore::subtractSaros()
×
1883
{
1884
        // 223 synodic months
1885
        addSolarDays(-223*29.530588853);
×
1886
}
×
1887

1888
void StelCore::subtractDraconicMonth()
×
1889
{
1890
        addSolarDays(-27.212220817);
×
1891
}
×
1892

1893
void StelCore::subtractMeanTropicalMonth()
×
1894
{
1895
        addSolarDays(-27.321582241);
×
1896
}
×
1897

1898
void StelCore::subtractCalendarMonth()
×
1899
{
1900
        double cjd = getJD();
×
1901
        int year, month, day, hour, minute, second;
1902
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1903
        month--;
×
1904
        if (month<1)
×
1905
        {
1906
                month = 12;
×
1907
                year--;
×
1908
        }
1909
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1910
        setJD(cjd);
×
1911
}
×
1912

1913
void StelCore::subtractCalendarYear()
×
1914
{
1915
        double cjd = getJD();
×
1916
        int year, month, day, hour, minute, second;
1917
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1918
        year--;
×
1919
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1920
        setJD(cjd);
×
1921
}
×
1922

1923
void StelCore::subtractCalendarDecade()
×
1924
{
1925
        double cjd = getJD();
×
1926
        int year, month, day, hour, minute, second;
1927
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1928
        year-=10;
×
1929
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1930
        setJD(cjd);
×
1931
}
×
1932

1933
void StelCore::subtractCalendarCentury()
×
1934
{
1935
        double cjd = getJD();
×
1936
        int year, month, day, hour, minute, second;
1937
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1938
        year-=100;
×
1939
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1940
        setJD(cjd);
×
1941
}
×
1942

1943
void StelCore::subtractGreatYear()
×
1944
{
1945
        subtractSiderealYears(25800);
×
1946
}
×
1947

1948
void StelCore::subtractAnomalisticMonth()
×
1949
{
1950
        addSolarDays(-27.554549878);
×
1951
}
×
1952

1953
void StelCore::subtractAnomalisticYear()
×
1954
{
1955
        subtractAnomalisticYears(1.);
×
1956
}
×
1957

1958
void StelCore::subtractAnomalisticYears(double n)
×
1959
{
1960
        addSolarDays(-365.259636*n);
×
1961
}
×
1962

1963
void StelCore::subtractDraconicYear()
×
1964
{
1965
        addSolarDays(-346.620075883);
×
1966
}
×
1967

1968
void StelCore::subtractTropicalYear()
×
1969
{
1970
        // Source: J. Meeus. More Mathematical Astronomy Morsels. 2002, p. 358.
1971
        double T = (getJD()-2451545.0)/365250.0;
×
1972
        addSolarDays(-(365.242189623 - T*(0.000061522 - T*(0.0000000609 + T*0.00000026525))));
×
1973
}
×
1974

1975
void StelCore::subtractMeanTropicalYear()
×
1976
{
1977
        addMeanTropicalYears(-1.0);
×
1978
}
×
1979

1980
void StelCore::subtractMeanTropicalYears(double n)
×
1981
{
1982
        addMeanTropicalYears(-1.0*n);
×
1983
}
×
1984

1985
void StelCore::subtractJulianYear()
×
1986
{
1987
        addSolarDays(-365.25);
×
1988
}
×
1989

1990
void StelCore::subtractGaussianYear()
×
1991
{
1992
        addSolarDays(-365.2568983);
×
1993
}
×
1994

1995
void StelCore::subtractJulianYears(double n)
×
1996
{
1997
        addSolarDays(-365.25*n);
×
1998
}
×
1999

2000
void StelCore::addSolarDays(double d)
×
2001
{
2002
        const PlanetP& home = getCurrentPlanet();
×
2003
        Planet::PlanetType ptype = home->getPlanetType();
×
2004
        if (ptype!=Planet::isArtificial && ptype!=Planet::isObserver)
×
2005
                d *= home->getMeanSolarDay();
×
2006

2007
        setJD(getJD() + d);
×
2008

2009
        if (qAbs(d)>0.99) // WTF: qAbs(d)>=1.0 not working here!
×
2010
                emit dateChanged();
×
2011
}
×
2012

2013
void StelCore::addSiderealDays(double d)
×
2014
{
2015
        const PlanetP& home = getCurrentPlanet();
×
2016
        Planet::PlanetType ptype = home->getPlanetType();
×
2017
        if (ptype!=Planet::isArtificial && ptype!=Planet::isObserver)
×
2018
                d *= home->getSiderealDay();
×
2019

2020
        setJD(getJD() + d);
×
2021
}
×
2022

2023
// Get the sidereal time of the prime meridian (i.e. Rotation Angle) shifted by the observer longitude
2024
double StelCore::getLocalSiderealTime() const
×
2025
{
2026
        // On Earth, this requires UT deliberately with all its faults, on other planets we use the more regular TT.
2027
        return (getCurrentPlanet()->getSiderealTime(getJD(), getJDE())+static_cast<double>(position->getCurrentLocation().getLongitude()))*M_PI/180.;
×
2028
}
2029

2030
//! Get the duration of a sidereal day for the current observer in day.
2031
double StelCore::getLocalSiderealDayLength() const
×
2032
{
2033
        return getCurrentPlanet()->getSiderealDay();
×
2034
}
2035

2036
//! Get the duration of a sidereal year for the current observer in days.
2037
double StelCore::getLocalSiderealYearLength() const
×
2038
{
2039
        return getCurrentPlanet()->getSiderealPeriod();
×
2040
}
2041

2042
QString StelCore::getStartupTimeMode() const
×
2043
{
2044
        return startupTimeMode;
×
2045
}
2046

2047
//! Increase the time speed
2048
void StelCore::increaseTimeSpeed()
×
2049
{
2050
        double s = getTimeRate();
×
2051
        if (s>=JD_SECOND) s*=10.;
×
2052
        else if (s<-JD_SECOND) s/=10.;
×
2053
        else if (s>=0.) s=JD_SECOND;
×
2054
        else s=0.;
×
2055
        setTimeRate(s);
×
2056
}
×
2057

2058
//! Decrease the time speed
2059
void StelCore::decreaseTimeSpeed()
×
2060
{
2061
        double s = getTimeRate();
×
2062
        if (s>JD_SECOND) s/=10.;
×
2063
        else if (s<=-JD_SECOND) s*=10.;
×
2064
        else if (s<=0.) s=-JD_SECOND;
×
2065
        else s=0.;
×
2066
        setTimeRate(s);
×
2067
}
×
2068

2069
void StelCore::increaseTimeSpeedLess()
×
2070
{
2071
        double s = getTimeRate();
×
2072
        if (s>=JD_SECOND) s*=2.;
×
2073
        else if (s<-JD_SECOND) s/=2.;
×
2074
        else if (s>=0.) s=JD_SECOND;
×
2075
        else s=0.;
×
2076
        setTimeRate(s);
×
2077
}
×
2078

2079
void StelCore::decreaseTimeSpeedLess()
×
2080
{
2081
        double s = getTimeRate();
×
2082
        if (s>JD_SECOND) s/=2.;
×
2083
        else if (s<=-JD_SECOND) s*=2.;
×
2084
        else if (s<=0.) s=-JD_SECOND;
×
2085
        else s=0.;
×
2086
        setTimeRate(s);
×
2087
}
×
2088

2089
void StelCore::setZeroTimeSpeed()
×
2090
{
2091
        setTimeRate(0);
×
2092
}
×
2093

2094
void StelCore::setRealTimeSpeed()
×
2095
{
2096
        setTimeRate(JD_SECOND);
×
2097
}
×
2098

2099
void StelCore::toggleRealTimeSpeed()
×
2100
{
2101
        (!getRealTimeSpeed()) ? setRealTimeSpeed() : setZeroTimeSpeed();
×
2102
}
×
2103

2104
bool StelCore::getRealTimeSpeed() const
×
2105
{
2106
        return (fabs(timeSpeed-JD_SECOND)<0.0000001);
×
2107
}
2108

2109
////////////////////////////////////////////////////////////////////////////////
2110
// Increment time
2111
void StelCore::updateTime(double deltaTime)
×
2112
{
2113
        if (getRealTimeSpeed())
×
2114
        {
2115
                JD.first = jdOfLastJDUpdate + (QDateTime::currentMSecsSinceEpoch() - milliSecondsOfLastJDUpdate) / 1000.0 * JD_SECOND;
×
2116
        }
2117
        else
2118
        {
2119
                JD.first = jdOfLastJDUpdate + (QDateTime::currentMSecsSinceEpoch() - milliSecondsOfLastJDUpdate) / 1000.0 * timeSpeed;
×
2120
        }
2121

2122
        // Fix time limits to -100000 to +100000 to prevent bugs
2123
        if (JD.first>38245309.499988) JD.first = 38245309.499988;
×
2124
        if (JD.first<-34803211.500012) JD.first = -34803211.500012;
×
2125
        JD.second=computeDeltaT(JD.first);
×
2126

2127
        if (position->isObserverLifeOver())
×
2128
        {
2129
                // Unselect if the new home planet is the previously selected object
2130
                StelObjectMgr* objmgr = GETSTELMODULE(StelObjectMgr);
×
2131
                Q_ASSERT(objmgr);
×
2132
                if (objmgr->getWasSelected() && objmgr->getSelectedObject()[0].data()==getCurrentPlanet())
×
2133
                {
2134
                        objmgr->unSelect();
×
2135
                }
2136
                StelObserver* newObs = position->getNextObserver();
×
2137
                delete position;
×
2138
                position = newObs;
×
2139
        }
2140
        if (position && position->update(deltaTime))
×
2141
        {
2142
                emit locationChanged(getCurrentLocation());
×
2143
        }
2144

2145
        // Position of sun and all the satellites (ie planets)
2146
        // GZ maybe setting this static can speedup a bit?
2147
        static SolarSystem* solsystem = static_cast<SolarSystem*>(StelApp::getInstance().getModuleMgr().getModule("SolarSystem"));
×
2148
        // Likely the most important location where we need JDE:
2149
        solsystem->computePositions(this, getJDE(), getCurrentPlanet());
×
2150
}
×
2151

2152
void StelCore::resetSync()
×
2153
{
2154
        jdOfLastJDUpdate = getJD();
×
2155
        //use currentMsecsSinceEpoch directly instead of StelApp::getTotalRuntime,
2156
        //because the StelApp::startMSecs gets subtracted anyways in update()
2157
        //also changed to qint64 to increase precision
2158
        milliSecondsOfLastJDUpdate = QDateTime::currentMSecsSinceEpoch();
×
2159
        emit timeSyncOccurred(jdOfLastJDUpdate);
×
2160
}
×
2161

2162
void StelCore::registerMathMetaTypes()
×
2163
{
2164
        //enables use of these types in QVariant, StelProperty, signals and slots
2165
        qRegisterMetaType<Vec2d>();
×
2166
        qRegisterMetaType<Vec2f>();
×
2167
        qRegisterMetaType<Vec2i>();
×
2168
        qRegisterMetaType<Vec3d>();
×
2169
        qRegisterMetaType<Vec3f>();
×
2170
        qRegisterMetaType<Vec3i>();
×
2171
        qRegisterMetaType<Vec4d>();
×
2172
        qRegisterMetaType<Vec4f>();
×
2173
        qRegisterMetaType<Vec4i>();
×
2174
        qRegisterMetaType<Mat4d>();
×
2175
        qRegisterMetaType<Mat4f>();
×
2176
        qRegisterMetaType<Mat3d>();
×
2177
        qRegisterMetaType<Mat3f>();
×
2178
        qRegisterMetaType<DitheringMode>();
×
2179

2180
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
2181
        //registers the QDataStream operators, so that QVariants with these types can be saved
2182
        qRegisterMetaTypeStreamOperators<Vec2d>();
2183
        qRegisterMetaTypeStreamOperators<Vec2f>();
2184
        qRegisterMetaTypeStreamOperators<Vec2i>();
2185
        qRegisterMetaTypeStreamOperators<Vec3d>();
2186
        qRegisterMetaTypeStreamOperators<Vec3f>();
2187
        qRegisterMetaTypeStreamOperators<Vec3i>();
2188
        qRegisterMetaTypeStreamOperators<Vec4d>();
2189
        qRegisterMetaTypeStreamOperators<Vec4f>();
2190
        qRegisterMetaTypeStreamOperators<Vec4i>();
2191
        qRegisterMetaTypeStreamOperators<Mat4d>();
2192
        qRegisterMetaTypeStreamOperators<Mat4f>();
2193
        qRegisterMetaTypeStreamOperators<Mat3d>();
2194
        qRegisterMetaTypeStreamOperators<Mat3f>();
2195
        qRegisterMetaTypeStreamOperators<DitheringMode>();
2196
#endif
2197
        //for debugging QVariants with these types, it helps if we register the string converters
2198
        // This is also required for QJSEngine.
2199
        QMetaType::registerConverter(&Vec2d::toString);
×
2200
        QMetaType::registerConverter(&Vec2f::toString);
×
2201
        QMetaType::registerConverter(&Vec2i::toString);
×
2202
        QMetaType::registerConverter(&Vec3d::toString);
×
2203
        QMetaType::registerConverter(&Vec3f::toString);
×
2204
        QMetaType::registerConverter(&Vec3i::toString);
×
2205
        QMetaType::registerConverter(&Vec4d::toString);
×
2206
        QMetaType::registerConverter(&Vec4f::toString);
×
2207
        QMetaType::registerConverter(&Vec4i::toString);
×
2208

2209
        //Hopefully this works to convert types in scripts when given as String "[...]"
2210
        // Maybe even make brackets optional!
2211
        // Nope, does not work for QJSEngine.
2212
//        QMetaType::registerConverter<QString, Vec2d>(&Vec2d::fromBracketedString);
2213
//        QMetaType::registerConverter<QString, Vec2f>(&Vec2f::fromBracketedString);
2214
//        QMetaType::registerConverter<QString, Vec2i>(&Vec2i::fromBracketedString);
2215
//        QMetaType::registerConverter<QString, Vec3d>(&Vec3d::fromBracketedString);
2216
//        QMetaType::registerConverter<QString, Vec3f>(&Vec3f::fromBracketedString);
2217
//        QMetaType::registerConverter<QString, Vec3i>(&Vec3i::fromBracketedString);
2218
//        QMetaType::registerConverter<QString, Vec4d>(&Vec4d::fromBracketedString);
2219
//        QMetaType::registerConverter<QString, Vec4f>(&Vec4f::fromBracketedString);
2220
//        QMetaType::registerConverter<QString, Vec4i>(&Vec4i::fromBracketedString);
2221
}
×
2222

2223
void StelCore::setStartupTimeMode(const QString& s)
×
2224
{
2225
        StelApp::immediateSave("navigation/startup_time_mode", s);
×
2226
        startupTimeMode = s;
×
2227
}
×
2228

2229
// return precomputed DeltaT in seconds. Public.
2230
double StelCore::getDeltaT() const
×
2231
{
2232
        return JD.second;
×
2233
}
2234

2235

2236
// compute and return DeltaT in seconds. Try not to call it directly, current DeltaT, JD, and JDE are available.
2237
double StelCore::computeDeltaT(const double JD)
×
2238
{
2239
        double DeltaT = 0.;
×
2240
        if (currentDeltaTAlgorithm==Custom)
×
2241
        {
2242
                // User defined coefficients for quadratic equation for DeltaT may change frequently.
2243
                deltaTnDot = deltaTCustomNDot; // n.dot = custom value "/cy/cy
×
2244
                int year, month, day;
2245
                StelUtils::getDateFromJulianDay(JD, &year, &month, &day);
×
2246
                double u = (StelUtils::yearFraction(year,month,day)-getDeltaTCustomYear())/100.;
×
2247
                DeltaT = deltaTCustomEquationCoeff[0] + u*(deltaTCustomEquationCoeff[1] + u*deltaTCustomEquationCoeff[2]);
×
2248
        }
2249

2250
        else
2251
        {
2252
                Q_ASSERT(deltaTfunc);
×
2253
                DeltaT=deltaTfunc(JD);
×
2254
        }
2255

2256
        if (!deltaTdontUseMoon)
×
2257
                DeltaT += StelUtils::getMoonSecularAcceleration(JD, deltaTnDot, ((de440Active&&EphemWrapper::jd_fits_de440(JD)) ||
×
2258
                                                                                 (de441Active&&EphemWrapper::jd_fits_de441(JD)) ||
×
2259
                                                                                 (de430Active&&EphemWrapper::jd_fits_de430(JD)) ||
×
2260
                                                                                 (de431Active&&EphemWrapper::jd_fits_de431(JD))));
×
2261

2262
        return DeltaT;
×
2263
}
2264

2265
// set a function pointer here. This should make the actual computation simpler by just calling the function.
2266
void StelCore::setCurrentDeltaTAlgorithm(DeltaTAlgorithm algorithm)
×
2267
{
2268
        currentDeltaTAlgorithm=algorithm;
×
2269
        deltaTdontUseMoon = false; // most algorithms will use it!
×
2270
        switch (currentDeltaTAlgorithm)
×
2271
        {
2272
                case WithoutCorrection:
×
2273
                        // Without correction, DeltaT is disabled
2274
                        deltaTfunc = StelUtils::getDeltaTwithoutCorrection;
×
2275
                        deltaTnDot = -26.; // n.dot = -26.0"/cy/cy OR WHAT SHALL WE DO HERE?
×
2276
                        deltaTdontUseMoon = true;
×
2277
                        deltaTstart        = INT_MIN;
×
2278
                        deltaTfinish        = INT_MAX;
×
2279
                        break;
×
2280
                case Schoch:
×
2281
                        // Schoch (1931) algorithm for DeltaT
2282
                        deltaTnDot = -29.68; // n.dot = -29.68"/cy/cy
×
2283
                        deltaTfunc = StelUtils::getDeltaTBySchoch;
×
2284
                        deltaTstart        = -300;
×
2285
                        deltaTfinish        = 1980;
×
2286
                        break;
×
2287
                case Clemence:
×
2288
                        // Clemence (1948) algorithm for DeltaT
2289
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy
×
2290
                        deltaTfunc = StelUtils::getDeltaTByClemence;
×
2291
                        deltaTstart        = 1681;
×
2292
                        deltaTfinish        = 1900;
×
2293
                        break;
×
2294
                case IAU:
×
2295
                        // IAU (1952) algorithm for DeltaT, based on observations by Spencer Jones (1939)
2296
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy
×
2297
                        deltaTfunc = StelUtils::getDeltaTByIAU;
×
2298
                        deltaTstart        = 1681;
×
2299
                        deltaTfinish        = 1936; // Details in http://adsabs.harvard.edu/abs/1939MNRAS..99..541S
×
2300
                        break;
×
2301
                case AstronomicalEphemeris:
×
2302
                        // Astronomical Ephemeris (1960) algorithm for DeltaT
2303
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy
×
2304
                        deltaTfunc = StelUtils::getDeltaTByAstronomicalEphemeris;
×
2305
                        // GZ: What is the source of "1681..1900"? Expl.Suppl.AE 1961-p87 says "...over periods extending back to ancient times"
2306
                        // I changed to what I estimate.
2307
                        deltaTstart        = -500; // 1681;
×
2308
                        deltaTfinish        =  2000; // 1900;
×
2309
                        break;
×
2310
                case TuckermanGoldstine:
×
2311
                        // Tuckerman (1962, 1964) & Goldstine (1973) algorithm for DeltaT
2312
                        //FIXME: n.dot
2313
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy ???
×
2314
                        deltaTfunc = StelUtils::getDeltaTByTuckermanGoldstine;
×
2315
                        deltaTstart        = -600;
×
2316
                        deltaTfinish        = 1649;
×
2317
                        break;
×
2318
                case MullerStephenson:
×
2319
                        // Muller & Stephenson (1975) algorithm for DeltaT
2320
                        deltaTnDot = -37.5; // n.dot = -37.5 "/cy/cy
×
2321
                        deltaTfunc = StelUtils::getDeltaTByMullerStephenson;
×
2322
                        deltaTstart        = -1375;
×
2323
                        deltaTfinish        = 1975;
×
2324
                        break;
×
2325
                case Stephenson1978:
×
2326
                        // Stephenson (1978) algorithm for DeltaT
2327
                        deltaTnDot = -30.0; // n.dot = -30.0 "/cy/cy
×
2328
                        deltaTfunc = StelUtils::getDeltaTByStephenson1978;
×
2329
                        deltaTstart        = INT_MIN; // Range unknown!
×
2330
                        deltaTfinish        = INT_MAX;
×
2331
                        break;
×
2332
                case SchmadelZech1979:
×
2333
                        // Schmadel & Zech (1979) algorithm for DeltaT
2334
                        deltaTnDot = -23.8946; // n.dot = -23.8946 "/cy/cy
×
2335
                        deltaTfunc = StelUtils::getDeltaTBySchmadelZech1979;
×
2336
                        deltaTstart        = 1800;
×
2337
                        deltaTfinish        = 1975;
×
2338
                        break;
×
2339
                case MorrisonStephenson1982:
×
2340
                        // Morrison & Stephenson (1982) algorithm for DeltaT (used by RedShift)
2341
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2342
                        deltaTfunc = StelUtils::getDeltaTByMorrisonStephenson1982;
×
2343
                        // FIXME: Is it valid range?
2344
                        deltaTstart        = -4000;
×
2345
                        deltaTfinish        = 2800;
×
2346
                        break;
×
2347
                case StephensonMorrison1984:
×
2348
                        // Stephenson & Morrison (1984) algorithm for DeltaT
2349
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2350
                        deltaTfunc = StelUtils::getDeltaTByStephensonMorrison1984;
×
2351
                        deltaTstart        = -391;
×
2352
                        deltaTfinish        = 1600; // TODO: 1630..1980 are tabulated values
×
2353
                        break;
×
2354
                case StephensonHoulden:
×
2355
                        // Stephenson & Houlden (1986) algorithm for DeltaT.
2356
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2357
                        deltaTfunc = StelUtils::getDeltaTByStephensonHoulden;
×
2358
                        deltaTstart        = -1500;
×
2359
                        deltaTfinish        = 1600; // TODO: 1630..1980 are tabulated values from Stephenson & Morrison (1984)
×
2360
                        break;
×
2361
                case Espenak:
×
2362
                        // Espenak (1987, 1989) algorithm for DeltaT
2363
                        //FIXME: n.dot
2364
                        deltaTnDot = -23.8946; // n.dot = -23.8946 "/cy/cy ???
×
2365
                        deltaTfunc = StelUtils::getDeltaTByEspenak;
×
2366
                        deltaTstart        = 1950;
×
2367
                        deltaTfinish        = 2100;
×
2368
                        break;
×
2369
                case Borkowski:
×
2370
                        // Borkowski (1988) algorithm for DeltaT, relates to ELP2000-85!
2371
                        deltaTnDot = -23.895; // GZ: I see -23.895 in the paper, not -23.859; (?) // n.dot = -23.859 "/cy/cy
×
2372
                        deltaTfunc = StelUtils::getDeltaTByBorkowski;
×
2373
                        deltaTstart        = -2136;
×
2374
                        deltaTfinish        = 1715;
×
2375
                        break;
×
2376
                case SchmadelZech1988:
×
2377
                        // Schmadel & Zech (1988) algorithm for DeltaT
2378
                        //FIXME: n.dot
2379
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy ???
×
2380
                        deltaTfunc = StelUtils::getDeltaTBySchmadelZech1988;
×
2381
                        deltaTstart        = 1800;
×
2382
                        deltaTfinish        = 1988;
×
2383
                        break;
×
2384
                case ChaprontTouze:
×
2385
                        // Chapront-Touzé & Chapront (1991) algorithm for DeltaT
2386
                        deltaTnDot = -23.8946; // n.dot = -23.8946 "/cy/cy
×
2387
                        deltaTfunc = StelUtils::getDeltaTByChaprontTouze;
×
2388
                        // FIXME: Is it valid range?
2389
                        deltaTstart        = -4000;
×
2390
                        deltaTfinish        = 8000;
×
2391
                        break;
×
2392
                case StephensonMorrison1995:
×
2393
                        // Stephenson & Morrison (1995) algorithm for DeltaT
2394
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2395
                        deltaTfunc = StelUtils::getDeltaTByStephensonMorrison1995;
×
2396
                        deltaTstart        = -700;
×
2397
                        deltaTfinish        = 1600;
×
2398
                        break;
×
2399
                case Stephenson1997:
×
2400
                        // Stephenson (1997) algorithm for DeltaT
2401
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2402
                        deltaTfunc = StelUtils::getDeltaTByStephenson1997;
×
2403
                        deltaTstart        = -500;
×
2404
                        deltaTfinish        = 1600;
×
2405
                        break;
×
2406
                case ChaprontMeeus:
×
2407
                        // Chapront, Chapront-Touze & Francou (1997) & Meeus (1998) algorithm for DeltaT
2408
                        deltaTnDot = -25.7376; // n.dot = -25.7376 "/cy/cy
×
2409
                        deltaTfunc = StelUtils::getDeltaTByChaprontMeeus;
×
2410
                        deltaTstart        = -400; // 1800; // not explicitly given, but guess based on his using ChaprontFrancou which is cited elsewhere in a similar term with -391.
×
2411
                        deltaTfinish        =  2150; // 1997;
×
2412
                        break;
×
2413
                case JPLHorizons:
×
2414
                        // JPL Horizons algorithm for DeltaT
2415
                        deltaTnDot = -25.7376; // n.dot = -25.7376 "/cy/cy
×
2416
                        deltaTfunc = StelUtils::getDeltaTByJPLHorizons;
×
2417
                        deltaTstart        = -2999;
×
2418
                        deltaTfinish        = 1620;
×
2419
                        break;
×
2420
                case MeeusSimons:
×
2421
                        // Meeus & Simons (2000) algorithm for DeltaT
2422
                        deltaTnDot = -25.7376; // n.dot = -25.7376 "/cy/cy
×
2423
                        deltaTfunc = StelUtils::getDeltaTByMeeusSimons;
×
2424
                        deltaTstart        = 1620;
×
2425
                        deltaTfinish        = 2000;
×
2426
                        break;
×
2427
                case ReingoldDershowitz:
×
2428
                        // Reingold & Dershowitz (2002, 2007, 2018) algorithm for DeltaT
2429
                        // FIXME: n.dot
2430
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy ???
×
2431
                        deltaTfunc = StelUtils::getDeltaTByReingoldDershowitz;
×
2432
                        // GZ: while not original work, it's based on Meeus and therefore the full implementation covers likewise approximately:
2433
                        // AW: limits from 4th edition:
2434
                        deltaTstart        = -500; //1620;
×
2435
                        deltaTfinish        = 2150; //2019;
×
2436
                        break;
×
2437
                case MontenbruckPfleger:
×
2438
                        // Montenbruck & Pfleger (2000) algorithm for DeltaT
2439
                        // NOTE: book does not contain n.dot value
2440
                        // FIXME: n.dot
2441
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy ???
×
2442
                        deltaTfunc = StelUtils::getDeltaTByMontenbruckPfleger;
×
2443
                        deltaTstart        = 1825;
×
2444
                        deltaTfinish        = 2005;
×
2445
                        break;
×
2446
                case MorrisonStephenson2004:
×
2447
                        // Morrison & Stephenson (2004, 2005) algorithm for DeltaT
2448
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2449
                        deltaTfunc = StelUtils::getDeltaTByMorrisonStephenson2004;
×
2450
                        deltaTstart        = -1000;
×
2451
                        deltaTfinish        = 2000;
×
2452
                        break;
×
2453
                case Reijs:
×
2454
                        // Reijs (2006) algorithm for DeltaT
2455
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2456
                        deltaTfunc = StelUtils::getDeltaTByReijs;
×
2457
                        deltaTstart        = -1500; // -500; // GZ: It models long-term variability, so we should reflect this. Not sure on the begin, though.
×
2458
                        deltaTfinish        = 1100; // not 1620; // GZ: Not applicable for telescopic era, and better not after 1100 (pers.comm.)
×
2459
                        break;
×
2460
                case EspenakMeeus:
×
2461
                        // Espenak & Meeus (2006, 2014) algorithm for DeltaT
2462
                        deltaTnDot = -25.858; // n.dot = -25.858 "/cy/cy
×
2463
                        deltaTfunc = StelUtils::getDeltaTByEspenakMeeus;
×
2464
                        deltaTstart        = -1999;
×
2465
                        deltaTfinish        = 3000;
×
2466
                        break;
×
2467
                case EspenakMeeusModified:
×
2468
                        // Espenak & Meeus (2006, 2014) algorithm (with modified formulae) for DeltaT
2469
                        deltaTnDot = -25.858; // n.dot = -25.858 "/cy/cy
×
2470
                        deltaTfunc = StelUtils::getDeltaTByEspenakMeeusModified;
×
2471
                        deltaTstart        = -1999;
×
2472
                        deltaTfinish        = 3000;
×
2473
                        break;
×
2474
                case EspenakMeeusZeroMoonAccel:
×
2475
                        // This is a trying area. Something is wrong with DeltaT, maybe ndot is still not applied correctly.
2476
                        // Espenak & Meeus (2006, 2014) algorithm for DeltaT
2477
                        deltaTnDot = -25.858; // n.dot = -25.858 "/cy/cy
×
2478
                        deltaTdontUseMoon = true;
×
2479
                        deltaTfunc = StelUtils::getDeltaTByEspenakMeeus;
×
2480
                        deltaTstart        = -1999;
×
2481
                        deltaTfinish        = 3000;
×
2482
                        break;
×
2483
                case Banjevic:
×
2484
                        // Banjevic (2006) algorithm for DeltaT
2485
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2486
                        deltaTfunc = StelUtils::getDeltaTByBanjevic;
×
2487
                        deltaTstart        = -2020;
×
2488
                        deltaTfinish        = 1620;
×
2489
                        break;
×
2490
                case IslamSadiqQureshi:
×
2491
                        // Islam, Sadiq & Qureshi (2008 + revisited 2013) algorithm for DeltaT (6 polynomials)
2492
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2493
                        deltaTfunc = StelUtils::getDeltaTByIslamSadiqQureshi;
×
2494
                        deltaTdontUseMoon = true; // Seems this solutions doesn't use value of secular acceleration of the Moon
×
2495
                        deltaTstart        = 1620;
×
2496
                        deltaTfinish        = 2007;
×
2497
                        break;
×
2498
                case KhalidSultanaZaidi:
×
2499
                        // M. Khalid, Mariam Sultana and Faheem Zaidi polynomial approximation of time period 1620-2013 (2014)
2500
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2501
                        deltaTfunc = StelUtils::getDeltaTByKhalidSultanaZaidi;
×
2502
                        deltaTdontUseMoon = true; // Seems this solutions doesn't use value of secular acceleration of the Moon
×
2503
                        deltaTstart        = 1620;
×
2504
                        deltaTfinish        = 2013;
×
2505
                        break;
×
2506
                case StephensonMorrisonHohenkerk2016:
×
2507
                        deltaTnDot = -25.82; // n.dot = -25.82 "/cy/cy
×
2508
                        deltaTfunc=StelUtils::getDeltaTByStephensonMorrisonHohenkerk2016;
×
2509
                        deltaTstart        = -720;
×
2510
                        deltaTfinish        = 2019;
×
2511
                        break;
×
2512
                case Henriksson2017:
×
2513
                        // Henriksson solution (2017) for Schoch formula for DeltaT (1931)
2514
                        // Source: The Acceleration of the Moon and the Universe – the Mass of the Graviton.
2515
                        // Henriksson, G.
2516
                        // Advances in Astrophysics, Vol. 2, No. 3, August 2017
2517
                        // https://doi.org/10.22606/adap.2017.23004
2518
                        deltaTnDot = -30.128; // n.dot = -30.128"/cy/cy
×
2519
                        deltaTfunc = StelUtils::getDeltaTBySchoch;
×
2520
                        deltaTstart        = -4000;
×
2521
                        deltaTfinish        = 2000;
×
2522
                        break;
×
2523
                case Custom:
×
2524
                        // User defined coefficients for quadratic equation for DeltaT. These can change, and we don't use the function pointer here.
2525
                        deltaTnDot = deltaTCustomNDot; // n.dot = custom value "/cy/cy
×
2526
                        deltaTfunc=Q_NULLPTR;
×
2527
                        deltaTstart        = INT_MIN; // Range unknown!
×
2528
                        deltaTfinish        = INT_MAX;
×
2529
                        break;
×
2530
                default:
×
2531
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2532
                        deltaTfunc=Q_NULLPTR;
×
2533
                        deltaTstart        = INT_MIN; // Range unknown!
×
2534
                        deltaTfinish        = INT_MAX;
×
2535
                        qCritical() << "StelCore: unknown DeltaT algorithm selected (" << currentDeltaTAlgorithm << ")! (setting nDot=-26., but no function!!)";
×
2536
        }
2537
        Q_ASSERT((currentDeltaTAlgorithm==Custom) || (deltaTfunc!=Q_NULLPTR));
×
2538
}
×
2539

2540
//! Set the current algorithm for time correction to use
2541
void StelCore::setCurrentDeltaTAlgorithmKey(QString key)
×
2542
{
2543
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("DeltaTAlgorithm"));
×
2544
        DeltaTAlgorithm algo = static_cast<DeltaTAlgorithm>(en.keyToValue(key.toLatin1().data()));
×
2545
        if (algo<0)
×
2546
        {
2547
                qWarning() << "Unknown DeltaT algorithm: " << key << "setting \"WithoutCorrection\" instead";
×
2548
                algo = WithoutCorrection;
×
2549
        }
2550
        StelApp::immediateSave("navigation/time_correction_algorithm", key);
×
2551
        setCurrentDeltaTAlgorithm(algo);
×
2552
}
×
2553

2554
//! Get the current algorithm used by the DeltaT
2555
QString StelCore::getCurrentDeltaTAlgorithmKey(void) const
×
2556
{
2557
        return metaObject()->enumerator(metaObject()->indexOfEnumerator("DeltaTAlgorithm")).key(currentDeltaTAlgorithm);
×
2558
}
2559

2560
//! Get description of the current algorithm for time correction
2561
QString StelCore::getCurrentDeltaTAlgorithmDescription(void) const
×
2562
{
2563
        // GZ remarked where more info would be desirable. Generally, a full citation and the math. term would be nice to have displayed if it's just one formula, and the range of valid dates.
2564
        QString description;
×
2565
        double jd = 0;
×
2566
        QString marker;
×
2567
        switch (getCurrentDeltaTAlgorithm())
×
2568
        {
2569
                case WithoutCorrection:
×
2570
                        description = q_("Correction is disabled. Use only if you know what you are doing!");
×
2571
                        break;
×
2572
                case Schoch: // historical value.
×
2573
                        description = q_("This historical formula was obtained by C. Schoch in 1931 and was used by G. Henriksson in his article <em>Einstein's Theory of Relativity Confirmed by Ancient Solar Eclipses</em> (%1). See for more info %2here%3.").arg("2009", "<a href='http://journalofcosmology.com/AncientAstronomy123.html'>", "</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2574
                        break;
×
2575
                case Clemence: // historical value.
×
2576
                        description = q_("This empirical equation was published by G. M. Clemence in the article <em>On the system of astronomical constants</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/1948AJ.....53..169C'>1948</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2577
                        break;
×
2578
                case IAU: // historical value.
×
2579
                        description = q_("This formula is based on a study of post-1650 observations of the Sun, the Moon and the planets by Spencer Jones (%1) and used by Jean Meeus in his <em>Astronomical Formulae for Calculators</em>. It was also adopted in the PC program SunTracker Pro.").arg("<a href='http://adsabs.harvard.edu/abs/1939MNRAS..99..541S'>1939</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2580
                        // find year of publication of AFFC
2581
                        break;
×
2582
                case AstronomicalEphemeris: // historical value.
×
2583
                        description = q_("This is a slightly modified version of the IAU (1952) formula which was adopted in the <em>Astronomical Ephemeris</em> and in the <em>Canon of Solar Eclipses</em> by Mucke & Meeus (1983).").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2584
                        // TODO: expand the sentence: ... adopted ... from 19xx-19yy?
2585
                        break;
×
2586
                case TuckermanGoldstine: // historical value.
×
2587
                        description = q_("The tables of Tuckerman (1962, 1964) list the positions of the Sun, the Moon and the planets at 5- and 10-day intervals from 601 BCE to 1649 CE. The same relation was also implicitly adopted in the syzygy tables of Goldstine (1973).").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2588
                        // TODO: These tables are sometimes found cited, but I have no details. Maybe add "based on ... " ?
2589
                        break;
×
2590
                case MullerStephenson:
×
2591
                        description = q_("This equation was published by P. M. Muller and F. R. Stephenson in the article <em>The accelerations of the earth and moon from early astronomical observations</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/1975grhe.conf..459M'>1975</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2592
                        break;
×
2593
                case Stephenson1978:
×
2594
                        description = q_("This equation was published by F. R. Stephenson in the article <em>Pre-Telescopic Astronomical Observations</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/1978tfer.conf....5S'>1978</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2595
                        break;
×
2596
                case SchmadelZech1979: // outdated data fit, historical value?
×
2597
                        description = q_("This 12th-order polynomial equation (outdated and superseded by Schmadel & Zech (1988)) was published by L. D. Schmadel and G. Zech in the article <em>Polynomial approximations for the correction delta T E.T.-U.T. in the period 1800-1975</em> (%1) as fit through data published by Brouwer (1952).").arg("<a href='http://adsabs.harvard.edu/abs/1979AcA....29..101S'>1979</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2598
                        break;
×
2599
                case MorrisonStephenson1982:
×
2600
                        description = q_("This algorithm was adopted in P. Bretagnon & L. Simon's <em>Planetary Programs and Tables from -4000 to +2800</em> (1986) and in the PC planetarium program RedShift.").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2601
                        break;
×
2602
                case StephensonMorrison1984: // PRIMARY SOURCE
×
2603
                        description = q_("This formula was published by F. R. Stephenson and L. V. Morrison in the article <em>Long-term changes in the rotation of the earth - 700 B.C. to A.D. 1980</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/1984RSPTA.313...47S'>1984</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2604
                        break;
×
2605
                case StephensonHoulden:
×
2606
                        description = q_("This algorithm was published by F. R. Stephenson and M. A. Houlden in the book <em>Atlas of Historical Eclipse Maps</em> (%1). This algorithm is used in the PC planetarium program Guide 7.").arg("<a href='https://assets.cambridge.org/97805212/67236/frontmatter/9780521267236_frontmatter.pdf'>1986</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2607
                        break;
×
2608
                case Espenak: // limited range, but wide availability?
×
2609
                        description = q_("This algorithm was given by F. Espenak in his <em>Fifty Year Canon of Solar Eclipses: 1986-2035</em> (1987) and in his <em>Fifty Year Canon of Lunar Eclipses: 1986-2035</em> (1989).").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2610
                        break;
×
2611
                case Borkowski: // Linked to ELP2000-85, so it's important...
×
2612
                        description = q_("This formula was obtained by K.M. Borkowski (%1) from an analysis of 31 solar eclipse records dating between 2137 BCE and 1715 CE.").arg("<a href='http://adsabs.harvard.edu/abs/1988A&A...205L...8B'>1988</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2613
                        break;
×
2614
                case SchmadelZech1988: // data fit through Stephenson&Morrison1984, which itself is important. Unclear who uses this version?
×
2615
                        description = q_("This 12th-order polynomial equation was published by L. D. Schmadel and G. Zech in the article <em>Empirical Transformations from U.T. to E.T. for the Period 1800-1988</em> (%1) as data fit through values given by Stephenson & Morrison (1984).").arg("<a href='http://adsabs.harvard.edu/abs/1988AN....309..219S'>1988</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2616
                        break;
×
2617
                case ChaprontTouze:
×
2618
                        description = q_("This formula was adopted by M. Chapront-Touze & J. Chapront in the shortened version of the ELP 2000-85 lunar theory in their <em>Lunar Tables and Programs from 4000 B.C. to A.D. 8000</em> (1991).").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2619
                        break;
×
2620
                case StephensonMorrison1995:
×
2621
                        description = q_("This equation was published by F. R. Stephenson and L. V. Morrison in the article <em>Long-Term Fluctuations in the Earth's Rotation: 700 BC to AD 1990</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/1995RSPTA.351..165S'>1995</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2622
                        break;
×
2623
                case Stephenson1997:
×
2624
                        description = q_("F. R. Stephenson published this formula in his book <em>Historical Eclipses and Earth's Rotation</em> (%1).").arg("<a href='http://ebooks.cambridge.org/ebook.jsf?bid=CBO9780511525186'>1997</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2625
                        break;
×
2626
                case ChaprontMeeus:
×
2627
                        description = q_("From J. Meeus, <em>Astronomical Algorithms</em> (2nd ed., 1998), and widely used. Table for 1620..2000, and includes a variant of Chapront, Chapront-Touze & Francou (1997) for dates outside 1620..2000.").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2628
                        break;
×
2629
                case JPLHorizons:
×
2630
                        description = q_("The JPL Solar System Dynamics Group of the NASA Jet Propulsion Laboratory use this formula in their interactive website %1JPL Horizons%2.").arg("<a href='http://ssd.jpl.nasa.gov/?horizons'>", "</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2631
                        break;
×
2632
                case MeeusSimons:
×
2633
                        description = q_("This polynome was published by J. Meeus and L. Simons in article <em>Polynomial approximations to Delta T, 1620-2000 AD</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/2000JBAA..110..323M'>2000</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2634
                        break;
×
2635
                case MontenbruckPfleger: // uninspired
×
2636
                        description = q_("The fourth edition of O. Montenbruck & T. Pfleger's <em>Astronomy on the Personal Computer</em> (2000) provides simple 3rd-order polynomial data fits for the recent past.").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2637
                        break;
×
2638
                case ReingoldDershowitz: //
×
2639
                        description = q_("E. M. Reingold & N. Dershowitz present this polynomial data fit in <em>Calendrical Calculations</em> (4th ed. 2018) and in their <em>Calendrical Tabulations</em> (2002). It is based on Jean Meeus' <em>Astronomical Algorithms</em> (1991).").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2640
                        break;
×
2641
                case MorrisonStephenson2004: // PRIMARY SOURCE
×
2642
                        description = q_("This important solution was published by L. V. Morrison and F. R. Stephenson in article <em>Historical values of the Earth's clock error %1T and the calculation of eclipses</em> (%2) with addendum in (%3).").arg(QChar(0x0394)).arg("<a href='http://adsabs.harvard.edu/abs/2004JHA....35..327M'>2004</a>", "<a href='http://adsabs.harvard.edu/abs/2005JHA....36..339M'>2005</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2643
                        break;
×
2644
                case Reijs:
×
2645
                        description = q_("From the Length of Day (LOD; as determined by Stephenson & Morrison (%2)), Victor Reijs derived a %1T formula by using a Simplex optimisation with a cosine and square function. This is based on a possible periodicy described by Stephenson (%2). See for more info %3here%4.").arg(QChar(0x0394)).arg("<a href='http://adsabs.harvard.edu/abs/2004JHA....35..327M'>2004</a>", "<a href='http://www.iol.ie/~geniet/eng/DeltaTeval.htm'>", "</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2646
                        break;
×
2647
                case EspenakMeeus: // GENERAL SOLUTION
×
2648
                        description = q_("This solution by F. Espenak and J. Meeus, based on Morrison & Stephenson (2004) and a polynomial fit through tabulated values for 1600-2000, is used for the %1NASA Eclipse Web Site%2, in their <em>Five Millennium Canon of Solar Eclipses: -1900 to +3000</em> (2006) and <em>Thousand Year Canon of Solar Eclipses 1501 to 2500</em> (2014). This formula is also used in the solar, lunar and planetary ephemeris program SOLEX.").arg("<a href='http://eclipse.gsfc.nasa.gov/eclipse.html'>", "</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2649
                        break;
×
2650
                case EspenakMeeusModified: // MODIFIED SOLUTION
×
2651
                        description = q_("This solution is modified from F. Espenak and J. Meeus, based on Morrison & Stephenson (2004) and a polynomial fit through tabulated values for 1600-2000. Values for 2015-2033 are interpolated from observations and predictions by IERS Rapid Service/Prediction Center.").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker)).append(" <em>").append(q_("Used by default.")).append("</em>");
×
2652
                        break;
×
2653
                case EspenakMeeusZeroMoonAccel: // PATCHED SOLUTION. Experimental, it may not make sense to keep it in V1.0.
×
2654
                        description = QString("%1 %2").arg(q_("PATCHED VERSION WITHOUT ADDITIONAL LUNAR ACCELERATION."), q_("This solution by F. Espenak and J. Meeus, based on Morrison & Stephenson (2004) and a polynomial fit through tabulated values for 1600-2000.")).append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2655
                        break;
×
2656
                case Banjevic:
×
2657
                        description = q_("This solution by B. Banjevic, based on Stephenson & Morrison (1984), was published in article <em>Ancient eclipses and dating the fall of Babylon</em> (%1).").arg("<a href='http://adsabs.harvard.edu/abs/2006POBeo..80..251B'>2006</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2658
                        break;
×
2659
                case IslamSadiqQureshi:
×
2660
                        description = q_("This solution by S. Islam, M. Sadiq and M. S. Qureshi, based on Meeus & Simons (2000), was published in article <em>Error Minimization of Polynomial Approximation of DeltaT</em> (%1) and revisited by Sana Islam in 2013.").arg("<a href='http://www.ias.ac.in/article/fulltext/joaa/029/03-04/0363-0366'>2008</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2661
                        break;
×
2662
                case KhalidSultanaZaidi:
×
2663
                        description = q_("This polynomial approximation with 0.6 seconds of accuracy by M. Khalid, Mariam Sultana and Faheem Zaidi was published in <em>Delta T: Polynomial Approximation of Time Period 1620-2013</em> (%1).").arg("<a href='https://doi.org/10.1155/2014/480964'>2014</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2664
                        break;
×
2665
                case StephensonMorrisonHohenkerk2016: // PRIMARY SOURCE, SEEMS VERY IMPORTANT
×
2666
                        description = q_("This solution by F. R. Stephenson, L. V. Morrison and C. Y. Hohenkerk (2016) was published in <em>Measurement of the Earth’s rotation: 720 BC to AD 2015</em> (%1) and updated in <em>Addendum 2020 to 'Measurement of the Earth's Rotation: 720 BC to AD 2015'</em> (Morrison, L. V., Stephenson, F.R., Hohenkerk, C.Y. and Zawilski, M.; %2). Outside of the named range (modelled with a spline fit) it provides values from an approximate parabola.").arg("<a href='https://doi.org/10.1098/rspa.2016.0404'>2016</a>", "<a href='https://doi.org/10.1098/rspa.2020.0776'>2021</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2667
                        break;
×
2668
                case Henriksson2017:
×
2669
                        description = q_("This solution by G. Henriksson was published in the article <em>The Acceleration of the Moon and the Universe - the Mass of the Graviton</em> (%1) and based on C. Schoch's formula (1931).").arg("<a href='https://doi.org/10.22606/adap.2017.23004'>2017</a>").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker));
×
2670
                        break;
×
2671
                case Custom:
×
2672
                        description = q_("This is a quadratic formula for calculation of %1T with coefficients defined by the user.").arg(QChar(0x0394));
×
2673
                        break;
×
2674
                default:
×
2675
                        description = q_("Error");
×
2676
        }
2677

2678
        // Put n-dot value info
2679
        if (getCurrentDeltaTAlgorithm()!=WithoutCorrection)
×
2680
        {
2681
                QString accel = QString("%1\"/cy<sup>2</sup>").arg(QString::number(getDeltaTnDot(), 'f', 4));
×
2682
                QString ndot  = QString("&#x1E45;");
×
2683
                description.append(" " + q_("The solution's value of %1 for %2 (secular acceleration of the Moon) requires an adaptation, see Guide for details.").arg(accel, ndot));
×
2684
        }
×
2685

2686
        return description;
×
2687
}
×
2688

2689
QString StelCore::getCurrentDeltaTAlgorithmValidRangeDescription(const double JD, QString *marker) const
×
2690
{
2691
        QString validRange = "";
×
2692
        QString validRangeAppendix = "";
×
2693
        *marker = "";
×
2694
        int year, month, day;
2695

2696
        StelUtils::getDateFromJulianDay(JD, &year, &month, &day);
×
2697
        switch (currentDeltaTAlgorithm)
×
2698
        {
2699
                // These models provide extrapolated values outside their specified/recommended range.
2700
                case WithoutCorrection:      // and
×
2701
                case Schoch:                 // and
2702
                case Clemence:               // and
2703
                case IAU:                    // and
2704
                case AstronomicalEphemeris:  // and
2705
                case TuckermanGoldstine:     // and
2706
                case StephensonHoulden:      // and
2707
                case MullerStephenson:       // and
2708
                case Stephenson1978:         // and
2709
                case MorrisonStephenson1982: // and
2710
                case StephensonMorrison1984: // and
2711
                case Espenak:                // and
2712
                case Borkowski:              // and
2713
                case StephensonMorrison1995: // and
2714
                case Stephenson1997:         // and
2715
                case ChaprontMeeus:          // and
2716
                case ReingoldDershowitz:     // and
2717
                case MorrisonStephenson2004: // and
2718
                case Reijs:                  // and
2719
                case EspenakMeeus:           // range stated in the Canon, p. 14.  ... and
2720
                case EspenakMeeusModified:   // the default, range stated in the Canon, p. 14.  ... and
2721
                case EspenakMeeusZeroMoonAccel: // and
2722
                case StephensonMorrisonHohenkerk2016: // and
2723
                case Henriksson2017:
2724
                        break;
×
2725
                case JPLHorizons: // and
×
2726
                case MeeusSimons:
2727
                        validRangeAppendix = q_("with zero values outside this range");
×
2728
                        break;
×
2729
                case MontenbruckPfleger:
×
2730
                        validRangeAppendix = q_("with a typical 1-second accuracy and zero values outside this range");
×
2731
                        break;
×
2732
                case SchmadelZech1988:
×
2733
                        validRangeAppendix = q_("with a mean error of less than one second, max. error 1.9s, and values for the limit years outside this range");
×
2734
                        break;
×
2735
                case SchmadelZech1979:  // and
×
2736
                case ChaprontTouze:     // and
2737
                case Banjevic:          // and
2738
                case IslamSadiqQureshi: // and
2739
                case KhalidSultanaZaidi:
2740
                        validRangeAppendix = q_("with values for the limit years outside this range");
×
2741
                        break;
×
2742
                case Custom:
×
2743
                        // Valid range unknown
2744
                        break;
×
2745
        }
2746

2747
        if (deltaTstart > INT_MIN) // limits declared?
×
2748
        {
2749
                if (validRangeAppendix!="")
×
2750
                        validRange = q_("Valid range of usage: between years %1 and %2, %3.").arg(deltaTstart).arg(deltaTfinish).arg(validRangeAppendix);
×
2751
                else
2752
                        validRange = q_("Valid range of usage: between years %1 and %2.").arg(deltaTstart).arg(deltaTfinish);
×
2753
                if ((year < deltaTstart) || (deltaTfinish < year))
×
2754
                        *marker = "*"; // mark "outside designed range, possibly wrong"
×
2755
        }
2756
        else
2757
                *marker = "?"; // mark "no range given"
×
2758

2759
        return QString(" %1").arg(validRange);
×
2760
}
×
2761

2762
// return if sky plus atmosphere is bright enough from sunlight so that e.g. screen labels should be rendered dark.
2763
// DONE: Simply ask the atmosphere for its surrounding brightness
2764
// TODO2: This could be moved to the SkyDrawer or even some GUI class, as it is used to decide a GUI thing.
2765
bool StelCore::isBrightDaylight() const
×
2766
{
2767
        if (propMgr->getStelPropertyValue("Oculars.ocularDisplayed", true).toBool())
×
2768
                return false;
×
2769
        SolarSystem* ssys = GETSTELMODULE(SolarSystem);
×
2770
        if (!ssys->getFlagPlanets())
×
2771
                return false;
×
2772
        if (!getSkyDrawer()->getFlagHasAtmosphere())
×
2773
                return false;
×
2774
        if (ssys->getSolarEclipseFactor(this).first<=0.01) // Total solar eclipse
×
2775
                return false;
×
2776

2777
        // immediately decide upon sky background brightness...
2778
        return (GETSTELMODULE(LandscapeMgr)->getAtmosphereAverageLuminance() > static_cast<float>(getSkyDrawer()->getDaylightLabelThreshold()));
×
2779
}
2780

2781
double StelCore::getCurrentEpoch() const
×
2782
{
2783
        return 2000.0 + (getJD() - 2451545.0)/365.25;
×
2784
}
2785

2786
// DE430/DE431 handling.
2787
// NOTE: When DE431 is not available, DE430 installed, but date outside, de430IsActive() may be true but computations still go back to VSOP!
2788
// To test whether DE43x is really currently in use, test (EphemWrapper::use_de430(jd) || EphemWrapper::use_de431(jd))
2789

2790
bool StelCore::de430IsAvailable()
×
2791
{
2792
        return de430Available;
×
2793
}
2794

2795
bool StelCore::de431IsAvailable()
×
2796
{
2797
        return de431Available;
×
2798
}
2799

2800
bool StelCore::de430IsActive()
×
2801
{
2802
        return de430Active;
×
2803
}
2804

2805
bool StelCore::de431IsActive()
×
2806
{
2807
        return de431Active;
×
2808
}
2809

2810
void StelCore::setDe430Active(bool status)
×
2811
{
2812
        de430Active = de430Available && status;
×
2813
}
×
2814

2815
void StelCore::setDe431Active(bool status)
×
2816
{
2817
        de431Active = de431Available && status;
×
2818
}
×
2819

2820

2821
bool StelCore::de440IsAvailable()
×
2822
{
2823
        return de440Available;
×
2824
}
2825

2826
bool StelCore::de441IsAvailable()
×
2827
{
2828
        return de441Available;
×
2829
}
2830

2831
bool StelCore::de440IsActive()
×
2832
{
2833
        return de440Active;
×
2834
}
2835

2836
bool StelCore::de441IsActive()
×
2837
{
2838
        return de441Active;
×
2839
}
2840

2841
void StelCore::setDe440Active(bool status)
×
2842
{
2843
        de440Active = de440Available && status;
×
2844
}
×
2845

2846
void StelCore::setDe441Active(bool status)
×
2847
{
2848
        de441Active = de441Available && status;
×
2849
}
×
2850

2851
void StelCore::initEphemeridesFunctions()
×
2852
{
2853
        QSettings* conf = StelApp::getInstance().getSettings();
×
2854

2855
        QString de430ConfigPath = conf->value("astro/de430_path").toString();
×
2856
        QString de431ConfigPath = conf->value("astro/de431_path").toString();
×
2857
        QString de440ConfigPath = conf->value("astro/de440_path").toString();
×
2858
        QString de441ConfigPath = conf->value("astro/de441_path").toString();
×
2859

2860
        QString de430FilePath;
×
2861
        QString de431FilePath;
×
2862
        QString de440FilePath;
×
2863
        QString de441FilePath;
×
2864

2865
        //<-- DE430 -->
2866
        if(de430ConfigPath.remove(QChar('"')).isEmpty())
×
2867
                de430FilePath = StelFileMgr::findFile("ephem/" + QString(DE430_FILENAME), StelFileMgr::File);
×
2868
        else
2869
                de430FilePath = StelFileMgr::findFile(de430ConfigPath, StelFileMgr::File);
×
2870

2871
        de430Available=!de430FilePath.isEmpty();
×
2872
        if(de430Available)
×
2873
        {
2874
                qDebug().noquote() << "DE430 at:" << de430FilePath;
×
2875
                EphemWrapper::init_de430(de430FilePath.toStdString().c_str());
×
2876
        }
2877
        setDe430Active(de430Available && conf->value("astro/flag_use_de430", false).toBool());
×
2878

2879
        //<-- DE431 -->
2880
        if(de431ConfigPath.remove(QChar('"')).isEmpty())
×
2881
                de431FilePath = StelFileMgr::findFile("ephem/" + QString(DE431_FILENAME), StelFileMgr::File);
×
2882
        else
2883
                de431FilePath = StelFileMgr::findFile(de431ConfigPath, StelFileMgr::File);
×
2884

2885
        de431Available=!de431FilePath.isEmpty();
×
2886
        if(de431Available)
×
2887
        {
2888
                qDebug().noquote() << "DE431 at:" << de431FilePath;
×
2889
                EphemWrapper::init_de431(de431FilePath.toStdString().c_str());
×
2890
        }
2891
        setDe431Active(de431Available && conf->value("astro/flag_use_de431", false).toBool());
×
2892

2893
        //<-- DE440 -->
2894
        if(de440ConfigPath.remove(QChar('"')).isEmpty())
×
2895
                de440FilePath = StelFileMgr::findFile("ephem/" + QString(DE440_FILENAME), StelFileMgr::File);
×
2896
        else
2897
                de440FilePath = StelFileMgr::findFile(de440ConfigPath, StelFileMgr::File);
×
2898

2899
        de440Available=!de440FilePath.isEmpty();
×
2900
        if(de440Available)
×
2901
        {
2902
                qDebug().noquote() << "DE440 at:" << de440FilePath;
×
2903
                EphemWrapper::init_de440(de440FilePath.toStdString().c_str());
×
2904
        }
2905
        setDe440Active(de440Available && conf->value("astro/flag_use_de440", false).toBool());
×
2906

2907
        //<-- DE441 -->
2908
        if(de441ConfigPath.remove(QChar('"')).isEmpty())
×
2909
                de441FilePath = StelFileMgr::findFile("ephem/" + QString(DE441_FILENAME), StelFileMgr::File);
×
2910
        else
2911
                de441FilePath = StelFileMgr::findFile(de441ConfigPath, StelFileMgr::File);
×
2912

2913
        de441Available=!de441FilePath.isEmpty();
×
2914
        if(de441Available)
×
2915
        {
2916
                qDebug().noquote() << "DE441 at:" << de441FilePath;
×
2917
                EphemWrapper::init_de441(de441FilePath.toStdString().c_str());
×
2918
        }
2919
        setDe441Active(de441Available && conf->value("astro/flag_use_de441", false).toBool());
×
2920

2921
        minMaxEphemRange = qMakePair(-4000, 8000); // VSOP87
×
2922
        if (de430Active || de440Active)
×
2923
                minMaxEphemRange = qMakePair(1550, 2650);
×
2924
        if (de431Active || de441Active)
×
2925
                minMaxEphemRange = qMakePair(-13000, 17000);
×
2926
}
×
2927

2928
// Methods for finding constellation from J2000 position.
2929
typedef struct iau_constline{
2930
        double RAlow;  // low value of 1875.0 right ascension segment, HH.dddd
2931
        double RAhigh; // high value of 1875.0 right ascension segment, HH.dddd
2932
        double decLow; // declination 1875.0 of southern border, DD.dddd
2933
        QString constellation; // 3-letter code of constellation
2934
} iau_constelspan;
2935

2936
static QVector<iau_constelspan> iau_constlineVec;
2937
static bool iau_constlineVecInitialized=false;
2938

2939
// File iau_constellations_spans.dat is converted from file data.dat from ADC catalog VI/42.
2940
// We converted back to HH:MM:SS format to avoid the inherent rounding errors present in that file (Bug LP:#1690615).
2941
QString StelCore::getIAUConstellation(const Vec3d &positionEqJnow) const
×
2942
{
2943
        // Precess positionJ2000 to 1875.0
2944
        const Vec3d pos1875=j2000ToJ1875(equinoxEquToJ2000(positionEqJnow, RefractionOff));
×
2945
        double RA1875;
2946
        double dec1875;
2947
        StelUtils::rectToSphe(&RA1875, &dec1875, pos1875);
×
2948
        RA1875 *= 12./M_PI; // hours
×
2949
        if (RA1875 <0.) RA1875+=24.;
×
2950
        dec1875 *= M_180_PI; // degrees
×
2951
        Q_ASSERT(RA1875>=0.0);
×
2952
        Q_ASSERT(RA1875<=24.0);
×
2953
        Q_ASSERT(dec1875<=90.0);
×
2954
        Q_ASSERT(dec1875>=-90.0);
×
2955

2956
        // read file into structure.
2957
        if (!iau_constlineVecInitialized)
×
2958
        {
2959
                //struct iau_constline line;
2960
                QFile file(StelFileMgr::findFile("data/constellations_spans.dat"));
×
2961

2962
                if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
×
2963
                {
2964
                        qWarning() << "IAU constellation line data file data/constellations_spans.dat not found.";
×
2965
                        return "err";
×
2966
                }
2967
                iau_constelspan span;
×
2968
                static const QRegularExpression emptyLine("^\\s*$");
×
2969
                static const QRegularExpression spaceRe("\\s+");
×
2970
                QTextStream in(&file);
×
2971
                while (!in.atEnd())
×
2972
                {
2973
                        // Build list of entries. The checks can certainly become more robust. Actually the file must have 4-part lines.
2974
                        QString line = in.readLine();
×
2975
                        if (line.length()==0) continue;
×
2976
                        if (emptyLine.match(line).hasMatch()) continue;
×
2977
                        if (line.at(0)=='#') continue; // skip comment lines.
×
2978
                        //QStringList list = line.split(QRegularExpression("\\b\\s+\\b"));
2979
                        QStringList list = line.trimmed().split(spaceRe);
×
2980
                        if (list.count() != 4)
×
2981
                        {
2982
                                qWarning() << "IAU constellation file constellations_spans.dat has bad line:" << line << "with" << list.count() << "elements";
×
2983
                                continue;
×
2984
                        }
2985
                        //qDebug() << "Creating span for decl=" << list.at(2) << " from RA=" << list.at(0) << "to" << list.at(1) << ": " << list.at(3);
2986
                        QStringList numList=list.at(0).split(QString(":"));
×
2987
                        span.RAlow= atof(numList.at(0).toLatin1()) + atof(numList.at(1).toLatin1())/60. + atof(numList.at(2).toLatin1())/3600.;
×
2988
                        numList=list.at(1).split(QString(":"));
×
2989
                        span.RAhigh=atof(numList.at(0).toLatin1()) + atof(numList.at(1).toLatin1())/60. + atof(numList.at(2).toLatin1())/3600.;
×
2990
                        numList=list.at(2).split(QString(":"));
×
2991
                        span.decLow=atof(numList.at(0).toLatin1());
×
2992
                        if (span.decLow<0.0)
×
2993
                                span.decLow -= atof(numList.at(1).toLatin1())/60.;
×
2994
                        else
2995
                                span.decLow += atof(numList.at(1).toLatin1())/60.;
×
2996
                        span.constellation=list.at(3);
×
2997
                        iau_constlineVec.append(span);
×
2998
                }
×
2999
                file.close();
×
3000
                iau_constlineVecInitialized=true;
×
3001
        }
×
3002

3003
        // iterate through vector, find entry where declination is lower.
3004
        int entry=0;
×
3005
        while (iau_constlineVec.at(entry).decLow > dec1875)
×
3006
                entry++;
×
3007
        while (entry<iau_constlineVec.size())
×
3008
        {
3009
                while (iau_constlineVec.at(entry).RAhigh <= RA1875)
×
3010
                        entry++;
×
3011
                while (iau_constlineVec.at(entry).RAlow >= RA1875)
×
3012
                        entry++;
×
3013
                if (iau_constlineVec.at(entry).RAhigh > RA1875)
×
3014
                        return iau_constlineVec.at(entry).constellation;
×
3015
                else
3016
                        entry++;
×
3017
        }
3018
        qDebug() << "getIAUconstellation error: Cannot determine, algorithm failed.";
×
3019
        return "(?)";
×
3020
}
3021

3022
// NELM = naked-eye limiting magnitude
3023
int StelCore::nelmToBortleScaleIndex(const float nelm)
×
3024
{
3025
        // Ref: Bortle, John E. (February 2001). "Gauging Light Pollution: The Bortle Dark-Sky Scale".
3026
        //  Sky & Telescope. Sky Publishing Corporation.
3027
        // https://skyandtelescope.org/astronomy-resources/light-pollution-and-astronomy-the-bortle-dark-sky-scale/
3028
        if(nelm < 4.0) return 9;
×
3029
        if(nelm < 4.5) return 8;
×
3030
        if(nelm < 5.0) return 7;
×
3031
        if(nelm < 5.5) return 6;
×
3032
        if(nelm < 6.0) return 5;
×
3033
        if(nelm < 6.5) return 4;
×
3034
        if(nelm < 7.0) return 3;
×
3035
        if(nelm < 7.5) return 2;
×
3036
        return 1;
×
3037
}
3038

3039
float StelCore::bortleScaleIndexToNELM(const int index)
247✔
3040
{
3041
        // This is kind of inverse of nelmToBortleScaleIndex(), where the "representative NELM" is chosen to be
3042
        // the middle of the interval of the NELM values for the inner indices (2-8), and the same distance from
3043
        // the boundary for outer indices (1 and 9).
3044
        switch(index)
247✔
3045
        {
3046
        case 1: return 7.75;
×
3047
        case 2: return 7.25;
19✔
3048
        case 3: return 6.75;
×
3049
        case 4: return 6.25;
×
3050
        case 5: return 5.75;
×
3051
        case 6: return 5.25;
38✔
3052
        case 7: return 4.75;
95✔
3053
        case 8: return 4.25;
×
3054
        case 9: return 3.75;
95✔
3055
        default:
×
3056
                        qWarning().nospace() << "Bortle scale index " << index << " out of range";
×
3057
                        return 0; // Let the problem be visible
×
3058
        }
3059
}
3060

3061
float StelCore::luminanceToNELM(const float luminance)
×
3062
{
3063
        // Ref: Schaefer, B. E.. "Telescopic limiting magnitudes". Astronomical Society of the Pacific,
3064
        //  Publications (ISSN 0004-6280), vol. 102, Feb. 1990, p. 212-229.
3065
        // http://adsbit.harvard.edu/cgi-bin/nph-iarticle_query?bibcode=1990PASP..102..212S
3066
        //
3067
        // Using formula (18), assuming observer's acuity Fₛ=1 (as suggested in the text as "typical observer"),
3068
        // absorption term kᵥ=0.3 (as suggested for "typical weather"), coefficient for Bₛ is adjusted to take
3069
        // the value in cd/m².
3070
        //
3071
        return 8.32f - 2.17147240951626f*std::log(1 + 88.5588612190873f*std::sqrt(luminance));
×
3072
}
3073

3074
float StelCore::nelmToLuminance(const float nelm)
247✔
3075
{
3076
        // This is just the inverse of luminanceToNELM()
3077
        const auto toSquare = std::exp(3.8315015947420905f-0.46051701859880895f*nelm) - 1;
247✔
3078
        return toSquare*toSquare*0.0001275075653676456f;
247✔
3079
}
3080

3081
Vec3d StelCore::getMouseJ2000Pos() const
×
3082
{
3083
        const StelProjectorP prj = getProjection(StelCore::FrameJ2000, StelCore::RefractionAuto);
×
3084
        float ppx = static_cast<float>(getCurrentStelProjectorParams().devicePixelsPerPixel);
×
3085

3086
        QPoint p = StelMainView::getInstance().getMousePos(); // get screen coordinates of mouse cursor
×
3087
        Vec3d mousePosition;
×
3088
        const float wh = prj->getViewportWidth()*0.5f; // get half of width of the screen
×
3089
        const float hh = prj->getViewportHeight()*0.5f; // get half of height of the screen
×
3090
        const float mx = p.x()*ppx-wh; // point 0 in center of the screen, axis X directed to right
×
3091
        const float my = p.y()*ppx-hh; // point 0 in center of the screen, axis Y directed to bottom
×
3092
        // calculate position of mouse cursor via position of center of the screen (and invert axis Y)
3093
        // If coordinates are invalid, don't draw them.
3094
        bool coordsValid = prj->unProject(static_cast<double>(prj->getViewportPosX()+wh+mx), static_cast<double>(prj->getViewportPosY()+hh+1-my), mousePosition);
×
3095
        if (coordsValid)
×
3096
        { // Nick Fedoseev patch
3097
                Vec3d win;
×
3098
                prj->project(mousePosition,win);
×
3099
                float dx = prj->getViewportPosX()+wh+mx - static_cast<float>(win.v[0]);
×
3100
                float dy = prj->getViewportPosY()+hh+1-my - static_cast<float>(win.v[1]);
×
3101
                prj->unProject(static_cast<double>(prj->getViewportPosX()+wh+mx+dx), static_cast<double>(prj->getViewportPosY()+hh+1-my+dy), mousePosition);
×
3102
        }
3103
//        if (getUseAberration() && getCurrentPlanet())
3104
//        {
3105
//                Vec3d vel=getCurrentPlanet()->getHeliocentricEclipticVelocity();
3106
//                vel=StelCore::matVsop87ToJ2000*vel * getAberrationFactor()*(AU/(86400.0*SPEED_OF_LIGHT));
3107
//                mousePosition-=vel;
3108
//                mousePosition.normalize();
3109
//        }
3110
        return mousePosition;
×
3111
}
×
3112

3113
Vec3d StelCore::calculateParallaxDiff(double JD) const {
×
3114
        // ICRS coordinates are barycentric (Gaia gives barycentric RA/DEC coordinates)
3115
        // diff between solar system bayrcentric location at STAR_CATALOG_JDEPOCH and current solar system bayrcentric location
3116
        Vec3d PosNow = getCurrentPlanet()->getBarycentricEclipticPos(JD);
×
3117
        // Transform from heliocentric ecliptic to equatorial coordinates
3118
        PosNow = matVsop87ToJ2000.upper3x3() * -1. * PosNow;  // need to times -1 because technically it is doing (0,0,0) - PosNow
×
3119
        return PosNow;
×
3120
}
3121

3122
Vec3d StelCore::getParallaxDiff(double JD) const {
×
3123
        // if isArtificial meaning transitioning between planets, use cache and don't recalculate because it will crash
3124
        if ((fuzzyEquals(JD, cachedParallaxJD, JD_SECOND) && (getCurrentPlanet() == cachedParallaxPlanet)) || (getCurrentPlanet()->getPlanetType() == Planet::isArtificial))
×
3125
        {
3126
                return cachedParallaxDiff;
×
3127
        }
3128
        cachedParallaxDiff = calculateParallaxDiff(JD); // set the cache to the new value
×
3129
        cachedParallaxJD = JD; // set the cache to the new value
×
3130
        cachedParallaxPlanet = getCurrentPlanet(); 
×
3131
    return cachedParallaxDiff;
×
3132
}
3133

3134
Vec3d StelCore::calculateAberrationVec(double JD) const {
×
3135
        // Solar system barycentric velocity
3136
        Q_UNUSED(JD);
3137
        Vec3d vel = getCurrentPlanet()->getBarycentricEclipticVelocity(JD);
×
3138
        vel = StelCore::matVsop87ToJ2000 * vel * (AU/(86400.0*SPEED_OF_LIGHT));
×
3139
        return vel;
×
3140
}
3141

3142
Vec3d StelCore::getAberrationVec(double JD) const {
×
3143
        // need to recompute the aberration vector if the JD has changed or the planet has changed
3144
        if (fuzzyEquals(JD, cachedAberrationJD, JD_SECOND) && (getCurrentPlanet() == cachedAberrationPlanet))
×
3145
        {
3146
                return getAberrationFactor() * cachedAberrationVec;
×
3147
        }
3148
        cachedAberrationVec = StelCore::calculateAberrationVec(JD); // set the cache to the new value
×
3149
        cachedAberrationJD = JD; // set the cache to the new value
×
3150
        cachedAberrationPlanet = getCurrentPlanet();
×
3151
        return getAberrationFactor() * cachedAberrationVec;
×
3152
}
3153

3154
QByteArray StelCore::getAberrationShader() const
×
3155
{
3156
        return 1+R"(
×
3157
uniform vec3 STELCORE_currentPlanetBarycentricEclipticVelocity;
3158
// objectDir points to the object as viewed from its comoving frame.
3159
// Return value represents the apparent direction to this object from a frame
3160
// that moves with respect to the object at slightly relativistic speeds (v<0.1c).
3161
// Relative error in aberration angle is about 0.5v/c.
3162
vec3 applyAberrationToObject(vec3 objectDir)
3163
{
3164
        vec3 velocity = STELCORE_currentPlanetBarycentricEclipticVelocity;
3165
        return normalize(objectDir + velocity);
3166
}
3167
// viewDir is the direction where the object appears to be when viewed from a
3168
// frame that moves with respect to it at slightly relativistic speeds (v<0.1c).
3169
// Return value represents the direction to the object as viewed from its comoving frame.
3170
// Relative error in aberration angle is about 0.5v/c.
3171
vec3 applyAberrationToViewDir(vec3 viewDir)
3172
{
3173
        vec3 velocity = STELCORE_currentPlanetBarycentricEclipticVelocity;
3174
        return normalize(viewDir - velocity);
3175
}
3176
)";
3177
}
3178

3179
void StelCore::setAberrationUniforms(QOpenGLShaderProgram& program) const
×
3180
{
3181
        Vec3d velocity;
×
3182
        if(getUseAberration())
×
3183
        {
3184
                velocity = cachedAberrationVec;
×
3185
        }
3186
        else
3187
        {
3188
                velocity = Vec3d(0,0,0);
×
3189
        }
3190
        program.setUniformValue("STELCORE_currentPlanetBarycentricEclipticVelocity", velocity.toQVector());
×
3191
}
×
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