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

Stellarium / stellarium / 4105865515

pending completion
4105865515

push

github

Georg Zotti
Allow "goto" action to observers

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

14669 of 124375 relevant lines covered (11.79%)

26392.59 hits per line

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

0.51
/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

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

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

57
// Init static transfo matrices
58
// See vsop87.doc:
59
const Mat4d StelCore::matJ2000ToVsop87(Mat4d::xrotation(-23.4392803055555555556*M_PI_180) * Mat4d::zrotation(0.0000275*M_PI_180));
60
const Mat4d StelCore::matVsop87ToJ2000(matJ2000ToVsop87.transpose());
61
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);
62
const Mat4d StelCore::matGalacticToJ2000(matJ2000ToGalactic.transpose());
63
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);
64
const Mat4d StelCore::matSupergalacticToJ2000(matJ2000ToSupergalactic.transpose());
65
Mat4d StelCore::matJ2000ToJ1875; // gets to be initialized in constructor.
66

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

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

112
        toneReproducer = new StelToneReproducer();
×
113
        milliSecondsOfLastJDUpdate = QDateTime::currentMSecsSinceEpoch();
×
114

115
        QSettings* conf = StelApp::getInstance().getSettings();
×
116
        // Create and initialize the default projector params
117
        QString tmpstr = conf->value("projection/viewport").toString();
×
118
        currentProjectorParams.maskType = StelProjector::stringToMaskType(tmpstr);
×
119
        const int viewport_width = conf->value("projection/viewport_width", currentProjectorParams.viewportXywh[2]).toInt();
×
120
        const int viewport_height = conf->value("projection/viewport_height", currentProjectorParams.viewportXywh[3]).toInt();
×
121
        const int viewport_x = conf->value("projection/viewport_x", 0).toInt();
×
122
        const int viewport_y = conf->value("projection/viewport_y", 0).toInt();
×
123
        currentProjectorParams.viewportXywh.set(viewport_x,viewport_y,viewport_width,viewport_height);
×
124

125
        const qreal viewportCenterX = conf->value("projection/viewport_center_x",0.5*viewport_width).toDouble();
×
126
        const qreal viewportCenterY = conf->value("projection/viewport_center_y",0.5*viewport_height).toDouble();
×
127
        currentProjectorParams.viewportCenter.set(viewportCenterX, viewportCenterY);
×
128
        const qreal viewportCenterOffsetX = conf->value("projection/viewport_center_offset_x",0.).toDouble();
×
129
        const qreal viewportCenterOffsetY = conf->value("projection/viewport_center_offset_y",0.).toDouble();
×
130
        currentProjectorParams.viewportCenterOffset.set(viewportCenterOffsetX, viewportCenterOffsetY);
×
131

132
        currentProjectorParams.viewportFovDiameter = conf->value("projection/viewport_fov_diameter", qMin(viewport_width,viewport_height)).toDouble();
×
133
        currentProjectorParams.flipHorz = conf->value("projection/flip_horz",false).toBool();
×
134
        currentProjectorParams.flipVert = conf->value("projection/flip_vert",false).toBool();
×
135

136
        currentProjectorParams.gravityLabels = conf->value("viewing/flag_gravity_labels").toBool();
×
137
        
138
        currentProjectorParams.devicePixelsPerPixel = StelApp::getInstance().getDevicePixelsPerPixel();
×
139

140
        flagUseNutation=conf->value("astro/flag_nutation", true).toBool();
×
141
        flagUseAberration=conf->value("astro/flag_aberration", true).toBool();
×
142
        aberrationFactor=conf->value("astro/aberration_factor", 1.0).toDouble();
×
143
        flagUseTopocentricCoordinates=conf->value("astro/flag_topocentric_coordinates", true).toBool();
×
144
        flagUseDST=conf->value("localization/flag_dst", true).toBool();
×
145

146
        // Initialize matJ2000ToJ1875 matrix
147
        double eps1875, chi1875, omega1875, psi1875;
148
        const double jdB1875 = StelUtils::getJDFromBesselianEpoch(1875.0);
×
149
        getPrecessionAnglesVondrak(jdB1875, &eps1875, &chi1875, &omega1875, &psi1875);
×
150
        matJ2000ToJ1875 = Mat4d::xrotation(84381.406*1./3600.*M_PI/180.) * Mat4d::zrotation(-psi1875) * Mat4d::xrotation(-omega1875) * Mat4d::zrotation(chi1875);
×
151
        matJ2000ToJ1875 = matJ2000ToJ1875.transpose();
×
152
}
×
153

154

155
StelCore::~StelCore()
×
156
{
157
        delete toneReproducer; toneReproducer=Q_NULLPTR;
×
158
        delete geodesicGrid; geodesicGrid=Q_NULLPTR;
×
159
        delete skyDrawer; skyDrawer=Q_NULLPTR;
×
160
        delete position; position=Q_NULLPTR;
×
161
}
×
162

163
DitheringMode StelCore::parseDitheringMode(const QString& str)
×
164
{
165
        const auto s=str.trimmed().toLower();
×
166
        if(s=="disabled"   ) return DitheringMode::Disabled;
×
167
        if(s=="color565"   ) return DitheringMode::Color565;
×
168
        if(s=="color666"   ) return DitheringMode::Color666;
×
169
        if(s=="color888"   ) return DitheringMode::Color888;
×
170
        if(s=="color101010") return DitheringMode::Color101010;
×
171
        return DitheringMode::Disabled;
×
172
}
×
173

174
/*************************************************************************
175
 Load core data and initialize with default values
176
*************************************************************************/
177
void StelCore::init()
×
178
{
179
        QSettings* conf = StelApp::getInstance().getSettings();
×
180

181
        const char ditheringModeKey[] = "video/dithering_mode";
×
182
        QVariant selectedDitherFormat = conf->value(ditheringModeKey);
×
183
        if(!selectedDitherFormat.isValid())
×
184
        {
185
                constexpr char defaultValue[] = "color888";
×
186
                selectedDitherFormat = defaultValue;
×
187
                conf->setValue(ditheringModeKey, defaultValue);
×
188
        }
189
        ditheringMode = parseDitheringMode(selectedDitherFormat.toString());
×
190

191
        if (conf->childGroups().contains("location_run_once"))
×
192
                defaultLocationID = "stellarium_cli";
×
193
        else
194
                defaultLocationID = conf->value("init_location/location", "auto").toString();
×
195
        bool ok;
196
        StelLocationMgr* locationMgr = &StelApp::getInstance().getLocationMgr();
×
197
        StelLocation location=locationMgr->getLastResortLocation(); // first location: Paris. Required if no IP connection on first launch!
×
198
        if (defaultLocationID == "auto")
×
199
        {
200
                locationMgr->locationFromIP();
×
201
        }
202
        else if (defaultLocationID == "stellarium_cli")
×
203
        {
204
                location = locationMgr->locationFromCLI();
×
205
        }
206
        else if (defaultLocationID.startsWith("GPS", Qt::CaseInsensitive))
×
207
        {
208
                // The location is obtained already from init_location/last_resort_location
209
                location.name = conf->value("init_location/location").toString();
×
210
        }
211
        else
212
        {
213
                location = locationMgr->locationForString(defaultLocationID);
×
214
        }
215

216
        if (!location.isValid())
×
217
        {
218
                qWarning() << "Warning: location" << defaultLocationID << "is unknown.";
×
219
                location = locationMgr->getLastResortLocation();
×
220
        }
221
        position = new StelObserver(location);
×
222

223
        QString ctz = conf->value("localization/time_zone", "").toString();
×
224
        if (!ctz.isEmpty())
×
225
                setUseCustomTimeZone(true);
×
226
        else
227
                ctz = getCurrentLocation().ianaTimeZone;
×
228
        setCurrentTimeZone(ctz);
×
229

230
        // Delta-T stuff
231
        // Define default algorithm for time correction (Delta T)
232
        QString tmpDT = conf->value("navigation/time_correction_algorithm", "EspenakMeeusModified").toString();
×
233
        setCurrentDeltaTAlgorithmKey(tmpDT);
×
234

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

241
        // Time stuff
242
        setTimeNow();
×
243

244
        // We want to be able to handle the old style preset time, recorded as a double
245
        // jday, or as a more human readable string...
246
        QString presetTimeStr = conf->value("navigation/preset_sky_time",2451545.).toString();
×
247
        presetSkyTime = presetTimeStr.toDouble(&ok);
×
248
        if (ok)
×
249
        {
250
                qDebug() << "navigation/preset_sky_time is a double - treating as jday:" << QString::number(presetSkyTime, 'f', 5);
×
251
        }
252
        else
253
        {
254
                qDebug() << "navigation/preset_sky_time was not a double, treating as string date:" << presetTimeStr;
×
255
                presetSkyTime = StelUtils::qDateTimeToJd(QDateTime::fromString(presetTimeStr));
×
256
        }
257
        setInitTodayTime(QTime::fromString(conf->value("navigation/today_time", "22:00").toString()));
×
258
        startupTimeMode = conf->value("navigation/startup_time_mode", "actual").toString().toLower();
×
259
        if (startupTimeMode=="preset")        
×
260
                setJD(presetSkyTime - static_cast<double>(getUTCOffset(presetSkyTime)) * JD_HOUR);
×
261
        else if (startupTimeMode=="today")
×
262
                setTodayTime(getInitTodayTime());
×
263

264
        // Compute transform matrices between coordinates systems
265
        updateTransformMatrices();
×
266
        updateFixedEquatorialTransformMatrices();
×
267
        connect(this, SIGNAL(locationChanged(const StelLocation&)), this, SLOT(updateFixedEquatorialTransformMatrices()));
×
268

269
        movementMgr = new StelMovementMgr(this);
×
270
        movementMgr->init();
×
271
        currentProjectorParams.fov = static_cast<float>(movementMgr->getInitFov());
×
272
        StelApp::getInstance().getModuleMgr().registerModule(movementMgr);
×
273

274
        skyDrawer = new StelSkyDrawer(this);
×
275
        skyDrawer->init();
×
276

277
        propMgr = StelApp::getInstance().getStelPropertyManager();
×
278
        propMgr->registerObject(skyDrawer);
×
279
        propMgr->registerObject(this);
×
280
        propMgr->registerObject(toneReproducer);
×
281

282
        setCurrentProjectionTypeKey(getDefaultProjectionTypeKey());
×
283
        updateMaximumFov();
×
284

285
        // activate DE430/431
286
        initEphemeridesFunctions();
×
287

288
        // Register all the core actions.
289
        QString timeGroup = N_("Date and Time");
×
290
        QString movementGroup = N_("Movement and Selection");
×
291
        QString displayGroup = N_("Display Options");
×
292
        StelActionMgr* actionsMgr = StelApp::getInstance().getStelActionManager();
×
293
        actionsMgr->addAction("actionIncrease_Time_Speed", timeGroup, N_("Increase time speed"), this, "increaseTimeSpeed()", "L");
×
294
        actionsMgr->addAction("actionDecrease_Time_Speed", timeGroup, N_("Decrease time speed"), this, "decreaseTimeSpeed()", "J");
×
295
        actionsMgr->addAction("actionIncrease_Time_Speed_Less", timeGroup, N_("Increase time speed (a little)"), this, "increaseTimeSpeedLess()", "Shift+L");
×
296
        actionsMgr->addAction("actionDecrease_Time_Speed_Less", timeGroup, N_("Decrease time speed (a little)"), this, "decreaseTimeSpeedLess()", "Shift+J");
×
297
        actionsMgr->addAction("actionSet_Real_Time_Speed", timeGroup, N_("Set normal time rate"), this, "toggleRealTimeSpeed()", "K");
×
298
        actionsMgr->addAction("actionSet_Time_Rate_Zero", timeGroup, N_("Set time rate to zero"), this, "setZeroTimeSpeed()", "7");
×
299
        actionsMgr->addAction("actionSet_Time_Reverse", timeGroup, N_("Set reverse time direction"), this, "revertTimeDirection()", "0");
×
300
        actionsMgr->addAction("actionReturn_To_Current_Time", timeGroup, N_("Set time to now"), this, "setTimeNow()", "8");
×
301
        actionsMgr->addAction("actionAdd_Solar_Minute", timeGroup, N_("Add 1 solar minute"), this, "addMinute()");
×
302
        actionsMgr->addAction("actionAdd_Solar_Hour", timeGroup, N_("Add 1 solar hour"), this, "addHour()", "Ctrl+=");
×
303
        actionsMgr->addAction("actionAdd_Solar_Day", timeGroup, N_("Add 1 solar day"), this, "addDay()", "=");
×
304
        actionsMgr->addAction("actionAdd_Solar_Week", timeGroup, N_("Add 7 solar days"), this, "addWeek()", "]");
×
305
        actionsMgr->addAction("actionSubtract_Solar_Minute", timeGroup, N_("Subtract 1 solar minute"), this, "subtractMinute()");
×
306
        actionsMgr->addAction("actionSubtract_Solar_Hour", timeGroup, N_("Subtract 1 solar hour"), this, "subtractHour()", "Ctrl+-");
×
307
        actionsMgr->addAction("actionSubtract_Solar_Day", timeGroup, N_("Subtract 1 solar day"), this, "subtractDay()", "-");
×
308
        actionsMgr->addAction("actionSubtract_Solar_Week", timeGroup, N_("Subtract 7 solar days"), this, "subtractWeek()", "[");
×
309
        actionsMgr->addAction("actionAdd_Sidereal_Day", timeGroup, N_("Add 1 sidereal day"), this, "addSiderealDay()", "Alt+=");
×
310
        actionsMgr->addAction("actionAdd_Sidereal_Week", timeGroup, N_("Add 7 sidereal days"), this, "addSiderealWeek()");
×
311
        actionsMgr->addAction("actionAdd_Sidereal_Year", timeGroup, N_("Add 1 sidereal year"), this, "addSiderealYear()", "Ctrl+Alt+Shift+]");
×
312
        actionsMgr->addAction("actionAdd_Sidereal_Century", timeGroup, N_("Add 100 sidereal years"), this, "addSiderealYears()");
×
313
        actionsMgr->addAction("actionAdd_Synodic_Month", timeGroup, N_("Add 1 synodic month"), this, "addSynodicMonth()");
×
314
        actionsMgr->addAction("actionAdd_Saros", timeGroup, N_("Add 1 saros"), this, "addSaros()");
×
315
        actionsMgr->addAction("actionAdd_Draconic_Month", timeGroup, N_("Add 1 draconic month"), this, "addDraconicMonth()");
×
316
        actionsMgr->addAction("actionAdd_Draconic_Year", timeGroup, N_("Add 1 draconic year"), this, "addDraconicYear()");
×
317
        actionsMgr->addAction("actionAdd_Anomalistic_Month", timeGroup, N_("Add 1 anomalistic month"), this, "addAnomalisticMonth()");
×
318
        actionsMgr->addAction("actionAdd_Anomalistic_Year", timeGroup, N_("Add 1 anomalistic year"), this, "addAnomalisticYear()");
×
319
        actionsMgr->addAction("actionAdd_Anomalistic_Century", timeGroup, N_("Add 100 anomalistic years"), this, "addAnomalisticYears()");
×
320
        actionsMgr->addAction("actionAdd_Mean_Tropical_Month", timeGroup, N_("Add 1 mean tropical month"), this, "addMeanTropicalMonth()");
×
321
        actionsMgr->addAction("actionAdd_Mean_Tropical_Year", timeGroup, N_("Add 1 mean tropical year"), this, "addMeanTropicalYear()");
×
322
        actionsMgr->addAction("actionAdd_Mean_Tropical_Century", timeGroup, N_("Add 100 mean tropical years"), this, "addMeanTropicalYears()");
×
323
        actionsMgr->addAction("actionAdd_Tropical_Year", timeGroup, N_("Add 1 tropical year"), this, "addTropicalYear()");
×
324
        actionsMgr->addAction("actionAdd_Julian_Year", timeGroup, N_("Add 1 Julian year"), this, "addJulianYear()");
×
325
        actionsMgr->addAction("actionAdd_Julian_Century", timeGroup, N_("Add 1 Julian century"), this, "addJulianYears()");
×
326
        actionsMgr->addAction("actionAdd_Gaussian_Year", timeGroup, N_("Add 1 Gaussian year"), this, "addGaussianYear()");
×
327
        actionsMgr->addAction("actionAdd_Calendric_Month", timeGroup, N_("Add 1 calendric month"), this, "addCalendricMonth()");
×
328
        actionsMgr->addAction("actionSubtract_Sidereal_Day", timeGroup, N_("Subtract 1 sidereal day"), this, "subtractSiderealDay()", "Alt+-");
×
329
        actionsMgr->addAction("actionSubtract_Sidereal_Week", timeGroup, N_("Subtract 7 sidereal days"), this, "subtractSiderealWeek()");
×
330
        actionsMgr->addAction("actionSubtract_Sidereal_Year", timeGroup, N_("Subtract 1 sidereal year"), this, "subtractSiderealYear()", "Ctrl+Alt+Shift+[");
×
331
        actionsMgr->addAction("actionSubtract_Sidereal_Century", timeGroup, N_("Subtract 100 sidereal years"), this, "subtractSiderealYears()");
×
332
        actionsMgr->addAction("actionSubtract_Synodic_Month", timeGroup, N_("Subtract 1 synodic month"), this, "subtractSynodicMonth()");
×
333
        actionsMgr->addAction("actionSubtract_Saros", timeGroup, N_("Subtract 1 saros"), this, "subtractSaros()");
×
334
        actionsMgr->addAction("actionSubtract_Draconic_Month", timeGroup, N_("Subtract 1 draconic month"), this, "subtractDraconicMonth()");
×
335
        actionsMgr->addAction("actionSubtract_Draconic_Year", timeGroup, N_("Subtract 1 draconic year"), this, "subtractDraconicYear()");
×
336
        actionsMgr->addAction("actionSubtract_Anomalistic_Month", timeGroup, N_("Subtract 1 anomalistic month"), this, "subtractAnomalisticMonth()");
×
337
        actionsMgr->addAction("actionSubtract_Anomalistic_Year", timeGroup, N_("Subtract 1 anomalistic year"), this, "subtractAnomalisticYear()");
×
338
        actionsMgr->addAction("actionSubtract_Anomalistic_Century", timeGroup, N_("Subtract 100 anomalistic years"), this, "subtractAnomalisticYears()");
×
339
        actionsMgr->addAction("actionSubtract_Mean_Tropical_Month", timeGroup, N_("Subtract 1 mean tropical month"), this, "subtractMeanTropicalMonth()");
×
340
        actionsMgr->addAction("actionSubtract_Mean_Tropical_Year", timeGroup, N_("Subtract 1 mean tropical year"), this, "subtractMeanTropicalYear()");
×
341
        actionsMgr->addAction("actionSubtract_Mean_Tropical_Century", timeGroup, N_("Subtract 100 mean tropical years"), this, "subtractMeanTropicalYears()");
×
342
        actionsMgr->addAction("actionSubtract_Tropical_Year", timeGroup, N_("Subtract 1 tropical year"), this, "subtractTropicalYear()");
×
343
        actionsMgr->addAction("actionSubtract_Julian_Year", timeGroup, N_("Subtract 1 Julian year"), this, "subtractJulianYear()");
×
344
        actionsMgr->addAction("actionSubtract_Julian_Century", timeGroup, N_("Subtract 1 Julian century"), this, "subtractJulianYears()");
×
345
        actionsMgr->addAction("actionSubtract_Gaussian_Year", timeGroup, N_("Subtract 1 Gaussian year"), this, "subtractGaussianYear()");
×
346
        actionsMgr->addAction("actionSubtract_Calendric_Month", timeGroup, N_("Subtract 1 calendric month"), this, "subtractCalendricMonth()");
×
347

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

351
        actionsMgr->addAction("actionHorizontal_Flip", displayGroup, N_("Flip scene horizontally"), this, "flipHorz", "Ctrl+Shift+H", "", true);
×
352
        actionsMgr->addAction("actionVertical_Flip", displayGroup, N_("Flip scene vertically"), this, "flipVert", "Ctrl+Shift+V", "", true);
×
353
}
×
354

355
QString StelCore::getDefaultProjectionTypeKey() const
×
356
{
357
        QSettings* conf = StelApp::getInstance().getSettings();
×
358
        return conf->value("projection/type", "ProjectionStereographic").toString();
×
359
}
360

361
// Get the shared instance of StelGeodesicGrid.
362
// The returned instance is guaranteed to allow for at least maxLevel levels
363
const StelGeodesicGrid* StelCore::getGeodesicGrid(int maxLevel) const
×
364
{
365
        if (geodesicGrid==Q_NULLPTR)
×
366
        {
367
                geodesicGrid = new StelGeodesicGrid(maxLevel);
×
368
        }
369
        else if (maxLevel>geodesicGrid->getMaxLevel())
×
370
        {
371
                delete geodesicGrid;
×
372
                geodesicGrid = new StelGeodesicGrid(maxLevel);
×
373
        }
374
        return geodesicGrid;
×
375
}
376

377
StelProjectorP StelCore::getProjection2d() const
×
378
{
379
        StelProjectorP prj(new StelProjector2d());
×
380
        prj->init(currentProjectorParams);
×
381
        return prj;
×
382
}
×
383

384
StelProjectorP StelCore::getProjection(StelProjector::ModelViewTranformP modelViewTransform, ProjectionType projType) const
×
385
{
386
        if (projType==static_cast<ProjectionType>(1000))
×
387
                projType = currentProjectionType;
×
388

389
        StelProjectorP prj;
×
390
        switch (projType)
×
391
        {
392
                case ProjectionPerspective:
×
393
                        prj = StelProjectorP(new StelProjectorPerspective(modelViewTransform));
×
394
                        break;
×
395
                case ProjectionEqualArea:
×
396
                        prj = StelProjectorP(new StelProjectorEqualArea(modelViewTransform));
×
397
                        break;
×
398
                case ProjectionStereographic:
×
399
                        prj = StelProjectorP(new StelProjectorStereographic(modelViewTransform));
×
400
                        break;
×
401
                case ProjectionFisheye:
×
402
                        prj = StelProjectorP(new StelProjectorFisheye(modelViewTransform));
×
403
                        break;
×
404
                case ProjectionHammer:
×
405
                        prj = StelProjectorP(new StelProjectorHammer(modelViewTransform));
×
406
                        break;
×
407
                case ProjectionCylinder:
×
408
                        prj = StelProjectorP(new StelProjectorCylinder(modelViewTransform));
×
409
                        break;
×
410
                case ProjectionCylinderFill:
×
411
                        prj = StelProjectorP(new StelProjectorCylinderFill(modelViewTransform));
×
412
                        break;
×
413
                case ProjectionMercator:
×
414
                        prj = StelProjectorP(new StelProjectorMercator(modelViewTransform));
×
415
                        break;
×
416
                case ProjectionOrthographic:
×
417
                        prj = StelProjectorP(new StelProjectorOrthographic(modelViewTransform));
×
418
                        break;
×
419
                case ProjectionSinusoidal:
×
420
                        prj = StelProjectorP(new StelProjectorSinusoidal(modelViewTransform));
×
421
                        break;
×
422
                case ProjectionMiller:
×
423
                        prj = StelProjectorP(new StelProjectorMiller(modelViewTransform));
×
424
                        break;
×
425
                default:
×
426
                        qWarning() << "Unknown projection type: " << static_cast<int>(projType) << "using ProjectionStereographic instead";
×
427
                        prj = StelProjectorP(new StelProjectorStereographic(modelViewTransform));
×
428
                        Q_ASSERT(0);
×
429
        }
430
        prj->init(currentProjectorParams);
×
431
        return prj;
×
432
}
×
433

434
// Get an instance of projector using the current display parameters from Navigation, StelMovementMgr
435
StelProjectorP StelCore::getProjection(FrameType frameType, RefractionMode refractionMode) const
×
436
{
437
        switch (frameType)
×
438
        {
439
                case FrameAltAz:
×
440
                        return getProjection(getAltAzModelViewTransform(refractionMode));
×
441
                case FrameHeliocentricEclipticJ2000:
×
442
                        return getProjection(getHeliocentricEclipticModelViewTransform(refractionMode));
×
443
                case FrameObservercentricEclipticJ2000:
×
444
                        return getProjection(getObservercentricEclipticJ2000ModelViewTransform(refractionMode));
×
445
                case FrameObservercentricEclipticOfDate:
×
446
                        return getProjection(getObservercentricEclipticOfDateModelViewTransform(refractionMode));
×
447
                case FrameEquinoxEqu:
×
448
                        return getProjection(getEquinoxEquModelViewTransform(refractionMode));
×
449
                case FrameFixedEquatorial:
×
450
                        return getProjection(getFixedEquatorialModelViewTransform(refractionMode));
×
451
                case FrameJ2000:
×
452
                        return getProjection(getJ2000ModelViewTransform(refractionMode));
×
453
                case FrameGalactic:
×
454
                        return getProjection(getGalacticModelViewTransform(refractionMode));
×
455
                case FrameSupergalactic:
×
456
                        return getProjection(getSupergalacticModelViewTransform(refractionMode));
×
457
                default:
×
458
                        qDebug() << "Unknown reference frame type: " << static_cast<int>(frameType) << ".";
×
459
        }
460
        Q_ASSERT(0);
×
461
        return getProjection2d();
462
}
463

464
SphericalCap StelCore::getVisibleSkyArea() const
×
465
{
466
        const LandscapeMgr* landscapeMgr = GETSTELMODULE(LandscapeMgr);
×
467
        Vec3d up(0, 0, 1);
×
468
        up = altAzToJ2000(up, RefractionOff);
×
469
        
470
        // Limit star drawing to above landscape's minimal altitude (was const=-0.035, Bug lp:1469407)
471
        if (landscapeMgr->getIsLandscapeFullyVisible())
×
472
        {
473
                return SphericalCap(up, landscapeMgr->getLandscapeSinMinAltitudeLimit());
×
474
        }
475
        return SphericalCap(up, -1.);
×
476
}
477

478
// Handle the resizing of the window
479
void StelCore::windowHasBeenResized(qreal x, qreal y, qreal width, qreal height)
×
480
{
481
        // Maximize display when resized since it invalidates previous options anyway
482
        currentProjectorParams.viewportXywh.set(qRound(x), qRound(y), qRound(width), qRound(height));
×
483
        currentProjectorParams.viewportCenter.set(x+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*width, y+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*height);
×
484
        currentProjectorParams.viewportFovDiameter = qMin(width,height);
×
485

486
        if (currentProjectionType==ProjectionType::ProjectionCylinderFill)
×
487
        {
488
                currentProjectorParams.widthStretch=0.5*width/height;
×
489
                currentProjectorParams.viewportFovDiameter = height;
×
490
        }
491
}
×
492

493
/*************************************************************************
494
 Update all the objects in function of the time
495
*************************************************************************/
496
void StelCore::update(double deltaTime)
×
497
{
498
        // Update the position of observation and time and recompute planet positions etc...
499
        updateTime(deltaTime);
×
500

501
        // Transform matrices between coordinates systems
502
        updateTransformMatrices();
×
503

504
        // Update direction of vision/Zoom level
505
        movementMgr->updateMotion(deltaTime);
×
506

507
        currentProjectorParams.fov = static_cast<float>(movementMgr->getCurrentFov());
×
508

509
        skyDrawer->update(deltaTime);
×
510
}
×
511

512

513
/*************************************************************************
514
 Execute all the pre-drawing functions
515
*************************************************************************/
516
void StelCore::preDraw()
×
517
{
518
        // Init openGL viewing with fov, screen size and clip planes
519
        currentProjectorParams.zNear = 0.000001;
×
520
        currentProjectorParams.zFar = 500.;
×
521

522
        // Clear the render buffer.
523
        // Here we can set a sky background color if really wanted (art
524
        // applications. Astronomical sky should be 0/0/0/0)
525
        Vec3f backColor = StelMainView::getInstance().getSkyBackgroundColor();
×
526
        QOpenGLFunctions* gl = QOpenGLContext::currentContext()->functions();
×
527
        gl->glClearColor(backColor[0], backColor[1], backColor[2], 0.f);
×
528
        gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
×
529

530
        skyDrawer->preDraw();
×
531
}
×
532

533

534
/*************************************************************************
535
 Update core state after drawing modules
536
*************************************************************************/
537
void StelCore::postDraw()
×
538
{
539
        StelPainter sPainter(getProjection(StelCore::FrameJ2000));
×
540
        sPainter.drawViewportShape();
×
541
}
×
542

543
void StelCore::updateMaximumFov()
×
544
{
545
        const float savedFov = currentProjectorParams.fov;
×
546
        currentProjectorParams.fov = 0.0001f;        // Avoid crash
×
547
        const float newMaxFov = getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())))->getMaxFov();
×
548
        movementMgr->setMaxFov(static_cast<double>(newMaxFov));
×
549
        currentProjectorParams.fov = qMin(newMaxFov, savedFov);
×
550
}
×
551

552
void StelCore::setCurrentProjectionType(ProjectionType type)
×
553
{
554
        if(type!=currentProjectionType)
×
555
        {
556
                QSettings* conf = StelApp::getInstance().getSettings();
×
557

558
                currentProjectionType=type;
×
559
                updateMaximumFov();
×
560
                if (currentProjectionType==ProjectionType::ProjectionCylinderFill)
×
561
                {
562
                        // 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.
563
                        // (To configure a stretch at startup, use startup.ssc script.)
564
                        conf->setValue("projection/width_stretch", currentProjectorParams.widthStretch);
×
565
                        currentProjectorParams.fov=180.f;
×
566
                        currentProjectorParams.widthStretch=0.5*currentProjectorParams.viewportXywh[2]/currentProjectorParams.viewportXywh[3];
×
567
                        currentProjectorParams.viewportFovDiameter = currentProjectorParams.viewportXywh[3];
×
568
                        Q_ASSERT(movementMgr);
×
569
                        movementMgr->setViewportVerticalOffsetTarget(0.);
×
570
                        movementMgr->zoomTo(180., 0.5);
×
571
                }
572
                else
573
                {
574
                        // reset to what is stored in config.ini
575
                        currentProjectorParams.widthStretch=conf->value("projection/width_stretch", 1.0).toDouble();
×
576
                }
577

578
                emit currentProjectionTypeChanged(type);
×
579
                emit currentProjectionTypeKeyChanged(getCurrentProjectionTypeKey());
×
580
                emit currentProjectionNameI18nChanged(getCurrentProjectionNameI18n());
×
581
        }
582
}
×
583

584
StelCore::ProjectionType StelCore::getCurrentProjectionType() const
×
585
{
586
        return currentProjectionType;
×
587
}
588

589
//! Set the current projection type to use
590
void StelCore::setCurrentProjectionTypeKey(QString key)
×
591
{
592
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
593
        ProjectionType newType = static_cast<ProjectionType>(en.keyToValue(key.toLatin1().data()));
×
594
        if (newType<0)
×
595
        {
596
                qWarning() << "Unknown projection type: " << key << "setting \"ProjectionStereographic\" instead";
×
597
                newType = ProjectionStereographic;
×
598
        }
599
        setCurrentProjectionType(newType);
×
600
}
×
601

602
//! Get the current Mapping used by the Projection
603
QString StelCore::getCurrentProjectionTypeKey(void) const
×
604
{
605
        return metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType")).key(currentProjectionType);
×
606
}
607

608
QString StelCore::getCurrentProjectionNameI18n() const
×
609
{
610
        return projectionTypeKeyToNameI18n(getCurrentProjectionTypeKey());
×
611
}
612

613
//! Get the list of all the available projections
614
QStringList StelCore::getAllProjectionTypeKeys() const
×
615
{
616
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
617
        QStringList l;
×
618
        for (int i=0;i<en.keyCount();++i)
×
619
                l << en.key(i);
×
620
        return l;
×
621
}
×
622

623
void StelCore::setMaskType(StelProjector::StelProjectorMaskType m)
×
624
{
625
        currentProjectorParams.maskType = m;
×
626
}
×
627

628
void StelCore::setFlagGravityLabels(bool gravity)
×
629
{
630
        currentProjectorParams.gravityLabels = gravity;
×
631
        emit flagGravityLabelsChanged(gravity);
×
632
}
×
633

634
bool StelCore::getFlagGravityLabels() const
×
635
{
636
        return currentProjectorParams.gravityLabels;
×
637
}
638

639
void StelCore::setDefaultAngleForGravityText(float a)
×
640
{
641
        currentProjectorParams.defaultAngleForGravityText = a;
×
642
}
×
643

644
void StelCore::setFlipHorz(bool flip)
×
645
{
646
        if (currentProjectorParams.flipHorz != flip)
×
647
        {
648
                currentProjectorParams.flipHorz = flip;
×
649
                emit flipHorzChanged(flip);
×
650
        }
651
}
×
652

653
void StelCore::setFlipVert(bool flip)
×
654
{
655
        if (currentProjectorParams.flipVert != flip)
×
656
        {
657
                currentProjectorParams.flipVert = flip;
×
658
                emit flipVertChanged(flip);
×
659
        }
660
}
×
661

662
bool StelCore::getFlipHorz(void) const
×
663
{
664
        return currentProjectorParams.flipHorz;
×
665
}
666

667
bool StelCore::getFlipVert(void) const
×
668
{
669
        return currentProjectorParams.flipVert;
×
670
}
671

672
// Get current value for horizontal viewport offset [-50...50]
673
double StelCore::getViewportHorizontalOffset(void) const
×
674
{
675
        return (currentProjectorParams.viewportCenterOffset[0] * 100.0);
×
676
}
677
// Set horizontal viewport offset. Argument will be clamped to be inside [-50...50]
678
void StelCore::setViewportHorizontalOffset(double newOffsetPct)
×
679
{
680
        currentProjectorParams.viewportCenterOffset[0]=0.01* qBound(-50., newOffsetPct, 50.);
×
681
        currentProjectorParams.viewportCenter.set(currentProjectorParams.viewportXywh[0]+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*currentProjectorParams.viewportXywh[2],
×
682
                                                currentProjectorParams.viewportXywh[1]+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*currentProjectorParams.viewportXywh[3]);
×
683
}
×
684

685
// Get current value for vertical viewport offset [-50...50]
686
double StelCore::getViewportVerticalOffset(void) const
×
687
{
688
        return (currentProjectorParams.viewportCenterOffset[1] * 100.0);
×
689
}
690
// Set vertical viewport offset. Argument will be clamped to be inside [-50...50]
691
void StelCore::setViewportVerticalOffset(double newOffsetPct)
×
692
{
693
        currentProjectorParams.viewportCenterOffset[1]=0.01* qBound(-50., newOffsetPct, 50.);
×
694
        currentProjectorParams.viewportCenter.set(currentProjectorParams.viewportXywh[0]+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*currentProjectorParams.viewportXywh[2],
×
695
                                                currentProjectorParams.viewportXywh[1]+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*currentProjectorParams.viewportXywh[3]);
×
696
}
×
697

698
// Set both viewport offsets. Arguments will be clamped to be inside [-50...50]. I (GZ) hope this will avoid some of the shaking.
699
void StelCore::setViewportOffset(double newHorizontalOffsetPct, double newVerticalOffsetPct)
×
700
{
701
        currentProjectorParams.viewportCenterOffset[0]=0.01* qBound(-50., newHorizontalOffsetPct, 50.);
×
702
        currentProjectorParams.viewportCenterOffset[1]=0.01* qBound(-50., newVerticalOffsetPct,   50.);
×
703
        currentProjectorParams.viewportCenter.set(currentProjectorParams.viewportXywh[0]+(0.5+currentProjectorParams.viewportCenterOffset.v[0])*currentProjectorParams.viewportXywh[2],
×
704
                                                currentProjectorParams.viewportXywh[1]+(0.5+currentProjectorParams.viewportCenterOffset.v[1])*currentProjectorParams.viewportXywh[3]);
×
705
}
×
706

707
void StelCore::setViewportStretch(float stretch)
×
708
{
709
        currentProjectorParams.widthStretch=static_cast<qreal>(qMax(0.001f, stretch));
×
710
}
×
711

712
QString StelCore::getDefaultLocationID() const
×
713
{
714
        return defaultLocationID;
×
715
}
716

717
QString StelCore::projectionTypeKeyToNameI18n(const QString& key) const
×
718
{
719
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
720
        QString s(getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())), static_cast<ProjectionType>(en.keyToValue(key.toLatin1())))->getNameI18());
×
721
        return s;
×
722
}
723

724
QString StelCore::projectionNameI18nToTypeKey(const QString& nameI18n) const
×
725
{
726
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("ProjectionType"));
×
727
        for (int i=0;i<en.keyCount();++i)
×
728
        {
729
                if (getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())), static_cast<ProjectionType>(i))->getNameI18()==nameI18n)
×
730
                        return en.valueToKey(i);
×
731
        }
732
        // Unknown translated name
733
        Q_ASSERT(0);
×
734
        return en.valueToKey(ProjectionStereographic);
735
}
736

737
StelProjector::StelProjectorParams StelCore::getCurrentStelProjectorParams() const
×
738
{
739
        return currentProjectorParams;
×
740
}
741

742
void StelCore::setCurrentStelProjectorParams(const StelProjector::StelProjectorParams& newParams)
×
743
{
744
        currentProjectorParams=newParams;
×
745
}
×
746

747
void StelCore::lookAtJ2000(const Vec3d& pos, const Vec3d& aup)
×
748
{
749
        Vec3d f(j2000ToAltAz(pos, RefractionOff));
×
750
        Vec3d up(j2000ToAltAz(aup, RefractionOff));
×
751
        f.normalize();
×
752
        up.normalize();
×
753

754
        // Update the model view matrix
755
        Vec3d s(f^up);        // y vector
×
756
        s.normalize();
×
757
        Vec3d u(s^f);        // Up vector in AltAz coordinates
×
758
        u.normalize();
×
759
        matAltAzModelView.set(s[0],u[0],-f[0],0.,
×
760
                              s[1],u[1],-f[1],0.,
×
761
                              s[2],u[2],-f[2],0.,
×
762
                              0.,0.,0.,1.);
763
        invertMatAltAzModelView = matAltAzModelView.inverse();
×
764
}
×
765

766
void StelCore::setMatAltAzModelView(const Mat4d& mat)
×
767
{
768
        matAltAzModelView = mat;
×
769
        invertMatAltAzModelView = matAltAzModelView.inverse();
×
770
}
×
771

772
Vec3d StelCore::altAzToEquinoxEqu(const Vec3d& v, RefractionMode refMode) const
×
773
{
774
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
775
                return matAltAzToEquinoxEqu*v;
×
776
        Vec3d r(v);
×
777
        skyDrawer->getRefraction().backward(r);
×
778
        r.transfo4d(matAltAzToEquinoxEqu);
×
779
        return r;
×
780
}
781

782
Vec3d StelCore::equinoxEquToAltAz(const Vec3d& v, RefractionMode refMode) const
×
783
{
784
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
785
                return matEquinoxEquToAltAz*v;
×
786
        Vec3d r(v);
×
787
        r.transfo4d(matEquinoxEquToAltAz);
×
788
        skyDrawer->getRefraction().forward(r);
×
789
        return r;
×
790
}
791

792
Vec3d StelCore::altAzToJ2000(const Vec3d& v, RefractionMode refMode) const
×
793
{
794
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
795
                return matEquinoxEquDateToJ2000*matAltAzToEquinoxEqu*v;
×
796
        Vec3d r(v);
×
797
        skyDrawer->getRefraction().backward(r);
×
798
        r.transfo4d(matEquinoxEquDateToJ2000*matAltAzToEquinoxEqu);
×
799
        return r;
×
800
}
801

802
Vec3d StelCore::j2000ToAltAz(const Vec3d& v, RefractionMode refMode) const
×
803
{
804
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
805
                return matJ2000ToAltAz*v;
×
806
        Vec3d r(v);
×
807
        r.transfo4d(matJ2000ToAltAz);
×
808
        skyDrawer->getRefraction().forward(r);
×
809
        return r;
×
810
}
811

812
Vec3d StelCore::galacticToJ2000(const Vec3d& v) const
×
813
{
814
        return matGalacticToJ2000*v;
×
815
}
816

817
Vec3d StelCore::supergalacticToJ2000(const Vec3d& v) const
×
818
{
819
        return matSupergalacticToJ2000*v;
×
820
}
821

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

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

844
Vec3d StelCore::j2000ToJ1875(const Vec3d& v) const
×
845
{
846
        return matJ2000ToJ1875*v;
×
847
}
848

849
Vec3d StelCore::j2000ToGalactic(const Vec3d& v) const
×
850
{
851
        return matJ2000ToGalactic*v;
×
852
}
853

854
Vec3d StelCore::j2000ToSupergalactic(const Vec3d& v) const
×
855
{
856
        return matJ2000ToSupergalactic*v;
×
857
}
858

859
//! Transform vector from heliocentric ecliptic coordinate to altazimuthal
860
Vec3d StelCore::heliocentricEclipticToAltAz(const Vec3d& v, RefractionMode refMode) const
×
861
{
862
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
863
                return matHeliocentricEclipticJ2000ToAltAz*v;
×
864
        Vec3d r(v);
×
865
        r.transfo4d(matHeliocentricEclipticJ2000ToAltAz);
×
866
        skyDrawer->getRefraction().forward(r);
×
867
        return r;
×
868
}
869

870
//! Transform from heliocentric coordinate to equatorial at current equinox (for the planet where the observer stands)
871
Vec3d StelCore::heliocentricEclipticToEquinoxEqu(const Vec3d& v) const
×
872
{
873
        return matHeliocentricEclipticToEquinoxEqu*v;
×
874
}
875

876
/*
877
//! Transform vector from heliocentric coordinate to false equatorial : equatorial
878
//! coordinate but centered on the observer position (useful for objects close to earth)
879
//! Unused as of V0.13
880
Vec3d StelCore::heliocentricEclipticToEarthPosEquinoxEqu(const Vec3d& v) const
881
{
882
        return matAltAzToEquinoxEqu*matHeliocentricEclipticToAltAz*v;
883
}
884
*/
885

886
StelProjector::ModelViewTranformP StelCore::getHeliocentricEclipticModelViewTransform(RefractionMode refMode) const
×
887
{
888
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
889
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matHeliocentricEclipticJ2000ToAltAz));
×
890
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
891
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
892
        refr->setPreTransfoMat(matHeliocentricEclipticJ2000ToAltAz);
×
893
        refr->setPostTransfoMat(matAltAzModelView);
×
894
        return StelProjector::ModelViewTranformP(refr);
×
895
}
896

897
//! Get the modelview matrix for observer-centric ecliptic J2000 (Vsop87A) drawing
898
StelProjector::ModelViewTranformP StelCore::getObservercentricEclipticJ2000ModelViewTransform(RefractionMode refMode) const
×
899
{
900
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
901
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matJ2000ToAltAz*matVsop87ToJ2000));
×
902
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
903
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
904
        refr->setPreTransfoMat(matJ2000ToAltAz*matVsop87ToJ2000);
×
905
        refr->setPostTransfoMat(matAltAzModelView);
×
906
        return StelProjector::ModelViewTranformP(refr);
×
907
}
908

909
//! Get the modelview matrix for observer-centric ecliptic-of-date drawing
910
StelProjector::ModelViewTranformP StelCore::getObservercentricEclipticOfDateModelViewTransform(RefractionMode refMode) const
×
911
{
912
        double eps_A=getPrecessionAngleVondrakCurrentEpsilonA();
×
913
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
914
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz* Mat4d::xrotation(eps_A)));
×
915
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
916
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
917
        refr->setPreTransfoMat(matEquinoxEquToAltAz* Mat4d::xrotation(eps_A));
×
918
        refr->setPostTransfoMat(matAltAzModelView);
×
919
        return StelProjector::ModelViewTranformP(refr);
×
920
}
921

922
//! Get the modelview matrix for observer-centric equatorial at equinox drawing
923
StelProjector::ModelViewTranformP StelCore::getEquinoxEquModelViewTransform(RefractionMode refMode) const
×
924
{
925
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
926
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz));
×
927
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
928
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
929
        refr->setPreTransfoMat(matEquinoxEquToAltAz);
×
930
        refr->setPostTransfoMat(matAltAzModelView);
×
931
        return StelProjector::ModelViewTranformP(refr);
×
932
}
933

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

946
//! Get the modelview matrix for observer-centric altazimuthal drawing
947
StelProjector::ModelViewTranformP StelCore::getAltAzModelViewTransform(RefractionMode refMode) const
×
948
{
949
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
950
        {
951
                // Catch problem with improperly initialized matAltAzModelView
952
                Q_ASSERT(matAltAzModelView[0]==matAltAzModelView[0]);
×
953
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,Mat4d::identity()));
×
954
        }
955
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
956
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
957
        refr->setPostTransfoMat(matAltAzModelView);
×
958
        return StelProjector::ModelViewTranformP(refr);
×
959
}
960

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

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

985
//! Get the modelview matrix for observer-centric Supergalactic equatorial drawing
986
StelProjector::ModelViewTranformP StelCore::getSupergalacticModelViewTransform(RefractionMode refMode) const
×
987
{
988
        if (refMode==RefractionOff || skyDrawer==Q_NULLPTR || (refMode==RefractionAuto && skyDrawer->getFlagHasAtmosphere()==false))
×
989
                return StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(matAltAzModelView,matEquinoxEquToAltAz*matJ2000ToEquinoxEqu*matSupergalacticToJ2000));
×
990
        Refraction* refr = new Refraction(skyDrawer->getRefraction());
×
991
        // The pretransform matrix will convert from input coordinates to AltAz needed by the refraction function.
992
        refr->setPreTransfoMat(matEquinoxEquToAltAz*matJ2000ToEquinoxEqu*matSupergalacticToJ2000);
×
993
        refr->setPostTransfoMat(matAltAzModelView);
×
994
        return StelProjector::ModelViewTranformP(refr);
×
995
}
996

997
// GZ: One of the most important functions, totally void of doc. :-(
998
// called in update() (for every frame)
999
void StelCore::updateTransformMatrices()
×
1000
{
1001
        matAltAzToEquinoxEqu = position->getRotAltAzToEquatorial(getJD(), getJDE());
×
1002
        matEquinoxEquToAltAz = matAltAzToEquinoxEqu.transpose();
×
1003

1004
        // multiply static J2000 earth axis tilt (eclipticalJ2000<->equatorialJ2000)
1005
        // in effect, this matrix transforms from VSOP87 ecliptical J2000 to planet-based equatorial coordinates.
1006
        // For earth, matJ2000ToEquinoxEqu is the precession matrix.        
1007
        matEquinoxEquDateToJ2000 = matVsop87ToJ2000 * position->getRotEquatorialToVsop87();
×
1008
        matJ2000ToEquinoxEqu = matEquinoxEquDateToJ2000.transpose();
×
1009
        matJ2000ToAltAz = matEquinoxEquToAltAz*matJ2000ToEquinoxEqu;
×
1010
        matAltAzToJ2000 = matJ2000ToAltAz.transpose();
×
1011

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

1014
        // These two next have to take into account the position of the observer on the earth/planet of observation.        
1015
        Mat4d matAltAzToVsop87 = matJ2000ToVsop87 * matEquinoxEquDateToJ2000 * matAltAzToEquinoxEqu;
×
1016
        //Mat4d tmp1 = matJ2000ToVsop87 * matEquinoxEquDateToJ2000;
1017

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

1028
                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * matAltAzToVsop87 *
×
1029
                                Mat4d::translation(Vec3d(rho*sin(sigma), 0., rho*cos(sigma) ));
×
1030

1031
                matHeliocentricEclipticJ2000ToAltAz =
1032
                                Mat4d::translation(Vec3d(-rho*sin(sigma), 0., -rho*cos(sigma))) * matAltAzToVsop87.transpose() *
×
1033
                                Mat4d::translation(-position->getCenterVsop87Pos());
×
1034

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

1039
//                matHeliocentricEclipticJ2000ToAltAz =
1040
//                                matEquinoxEquToAltAz *
1041
//                                Mat4d::translation(Vec3d(-rho*sin(sigma), 0., -rho*cos(sigma))) * tmp1.transpose() *
1042
//                                Mat4d::translation(-position->getCenterVsop87Pos());
1043

1044

1045
//                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * tmp *
1046
//                                Mat4d::translation(Vec3d(0.,0., position->getDistanceFromCenter()));
1047

1048
//                matHeliocentricEclipticJ2000ToAltAz =  Mat4d::translation(Vec3d(0.,0.,-position->getDistanceFromCenter())) * tmp.transpose() *
1049
//                                Mat4d::translation(-position->getCenterVsop87Pos());
1050
        }
1051
        else
1052
        {
1053
                matAltAzToHeliocentricEclipticJ2000 =  Mat4d::translation(position->getCenterVsop87Pos()) * matAltAzToVsop87;
×
1054
                matHeliocentricEclipticJ2000ToAltAz =  matAltAzToVsop87.transpose() * Mat4d::translation(-position->getCenterVsop87Pos());
×
1055
        }
1056
}
×
1057

1058
// This avoids calling a costly operation every frame.
1059
void StelCore::updateFixedEquatorialTransformMatrices()
×
1060
{
1061
        matAltAzToFixedEquatorial = Mat4d::yrotation(M_PI_2-static_cast<double>(getCurrentLocation().getLatitude())*M_PI_180);
×
1062
        matFixedEquatorialToAltAz = matAltAzToFixedEquatorial.transpose();
×
1063
}
×
1064
// Return the observer heliocentric position
1065
Vec3d StelCore::getObserverHeliocentricEclipticPos() const
×
1066
{
1067
        return Vec3d(matAltAzToHeliocentricEclipticJ2000[12], matAltAzToHeliocentricEclipticJ2000[13], matAltAzToHeliocentricEclipticJ2000[14]);
×
1068
}
1069

1070
// Set the location to use by default at startup
1071
void StelCore::setDefaultLocationID(const QString& id)
×
1072
{
1073
        StelLocation location = StelApp::getInstance().getLocationMgr().locationForString(id);
×
1074
        if (!location.isValid())
×
1075
        {
1076
                qWarning() << "Trying to set an invalid location" << id;
×
1077
                return;
×
1078
        }
1079
        defaultLocationID = id;
×
1080
        QSettings* conf = StelApp::getInstance().getSettings();
×
1081
        Q_ASSERT(conf);
×
1082
        conf->setValue("init_location/location", id);
×
1083
}
×
1084

1085
void StelCore::returnToDefaultLocation()
×
1086
{
1087
        StelLocationMgr& locationMgr = StelApp::getInstance().getLocationMgr();
×
1088
        StelLocation loc = locationMgr.locationForString(defaultLocationID);
×
1089
        if (loc.isValid())
×
1090
                moveObserverTo(loc, 0.);
×
1091
}
×
1092

1093
void StelCore::returnToHome()
×
1094
{
1095
        // Using returnToDefaultLocation() and getCurrentLocation() introduce issue, because for flying
1096
        // between planets using SpaceShip and second method give does not exist data
1097
        StelLocationMgr& locationMgr = StelApp::getInstance().getLocationMgr();
×
1098
        StelLocation loc;
×
1099
        if (defaultLocationID == "auto")
×
1100
        {
1101
                locationMgr.locationFromIP();
×
1102
                loc = locationMgr.getLastResortLocation();
×
1103
        }
1104
        else
1105
                loc = locationMgr.locationForString(defaultLocationID);
×
1106

1107
        if (loc.isValid())
×
1108
                moveObserverTo(loc, 0.);
×
1109

1110
        PlanetP p = GETSTELMODULE(SolarSystem)->searchByEnglishName(loc.planetName);
×
1111
        QSettings* conf = StelApp::getInstance().getSettings();
×
1112

1113
        LandscapeMgr* landscapeMgr = GETSTELMODULE(LandscapeMgr);
×
1114
        landscapeMgr->setCurrentLandscapeID(landscapeMgr->getDefaultLandscapeID());
×
1115
        landscapeMgr->setFlagAtmosphere(p->hasAtmosphere() && conf->value("landscape/flag_atmosphere", true).toBool());
×
1116
        landscapeMgr->setFlagFog(p->hasAtmosphere() && conf->value("landscape/flag_fog", true).toBool());
×
1117
        landscapeMgr->setFlagLandscape(!p->getEnglishName().contains("observer", Qt::CaseInsensitive) && conf->value("landscape/flag_landscape", true).toBool());
×
1118

1119
        GETSTELMODULE(StelObjectMgr)->unSelect();
×
1120

1121
        StelMovementMgr* smmgr = getMovementMgr();
×
1122
        smmgr->setViewDirectionJ2000(altAzToJ2000(smmgr->getInitViewingDirection(), StelCore::RefractionOff));
×
1123
        smmgr->zoomTo(smmgr->getInitFov(), 1.);
×
1124
}
×
1125

1126
double StelCore::getJDOfLastJDUpdate() const
×
1127
{
1128
        return jdOfLastJDUpdate;
×
1129
}
1130

1131
void StelCore::setMilliSecondsOfLastJDUpdate(qint64 millis)
×
1132
{
1133
        milliSecondsOfLastJDUpdate = millis;
×
1134
}
×
1135

1136
qint64 StelCore::getMilliSecondsOfLastJDUpdate() const
×
1137
{
1138
        return milliSecondsOfLastJDUpdate;
×
1139
}
1140

1141
void StelCore::setJD(double newJD)
×
1142
{
1143
        JD.first=newJD;
×
1144
        JD.second=computeDeltaT(newJD);        
×
1145
        resetSync();
×
1146
}
×
1147

1148
double StelCore::getJD() const
×
1149
{
1150
        return JD.first;
×
1151
}
1152

1153
void StelCore::setJDE(double newJDE)
×
1154
{
1155
        // nitpickerish this is not exact, but as good as it gets...
1156
        JD.second=computeDeltaT(newJDE);
×
1157
        JD.first=newJDE-JD.second/86400.0;
×
1158
        resetSync();
×
1159
}
×
1160

1161
double StelCore::getJDE() const
×
1162
{
1163
        return JD.first+JD.second/86400.0;
×
1164
}
1165

1166

1167
void StelCore::setMJDay(double MJD)
×
1168
{
1169
        setJD(MJD+2400000.5);
×
1170
}
×
1171

1172
double StelCore::getMJDay() const
×
1173
{
1174
        return JD.first-2400000.5;
×
1175
}
1176

1177
double StelCore::getPresetSkyTime() const
×
1178
{
1179
        return presetSkyTime;
×
1180
}
1181

1182
void StelCore::setPresetSkyTime(double d)
×
1183
{
1184
        presetSkyTime=d;
×
1185
}
×
1186

1187
void StelCore::setTimeRate(double ts)
×
1188
{
1189
        timeSpeed=ts;
×
1190
        resetSync();
×
1191
        emit timeRateChanged(timeSpeed);
×
1192
}
×
1193

1194
double StelCore::getTimeRate() const
×
1195
{
1196
        return timeSpeed;
×
1197
}
1198

1199
void StelCore::revertTimeDirection(void)
×
1200
{
1201
        setTimeRate(-1*getTimeRate());
×
1202
}
×
1203

1204
void StelCore::moveObserverToSelected()
×
1205
{
1206
        StelObjectMgr* objmgr = GETSTELMODULE(StelObjectMgr);
×
1207
        Q_ASSERT(objmgr);
×
1208
        if (objmgr->getWasSelected())
×
1209
        {
1210
                Planet* pl = dynamic_cast<Planet*>(objmgr->getSelectedObject()[0].data());
×
1211
                if (pl)
×
1212
                {
1213
                        // We need to move to the selected planet. Try to generate a location from the current one
1214
                        StelLocation loc = getCurrentLocation();
×
1215
                        if (loc.planetName != pl->getEnglishName())
×
1216
                        {
1217
                                loc.planetName = pl->getEnglishName();                                
×
1218
                                loc.name = "landing site";
×
1219
                                loc.state = "";
×
1220
                                if (pl->getPlanetType()==Planet::isObserver)
×
1221
                                        loc.role=QChar('o');
×
1222
                                else
1223
                                        loc.role=QChar('X');
×
1224

1225
                                // Let's try guess name of location...
1226
                                LocationMap results = StelApp::getInstance().getLocationMgr().pickLocationsNearby(loc.planetName, loc.getLongitude(), loc.getLatitude(), 1.0f);
×
1227
                                if (results.size()>0)
×
1228
                                        loc = results.value(results.firstKey()); // ...and use it!
×
1229

1230
                                moveObserverTo(loc);
×
1231
                        }
×
1232
                }
×
1233
                else
1234
                {
1235
                        NomenclatureItem* ni = dynamic_cast<NomenclatureItem*>(objmgr->getSelectedObject()[0].data());
×
1236
                        if (ni)
×
1237
                        {
1238
                                // We need to move to the nomenclature item's host planet.
1239
                                StelLocation loc; //  = getCurrentLocation();
×
1240
                                loc.planetName = ni->getPlanet()->getEnglishName();
×
1241
                                loc.name=ni->getEnglishName();
×
1242
                                loc.state = "";
×
1243
                                loc.setLongitude(ni->getLongitude());
×
1244
                                loc.setLatitude(ni->getLatitude());
×
1245
                                loc.lightPollutionLuminance = 0;
×
1246

1247
                                moveObserverTo(loc);
×
1248
                                objmgr->unSelect(); // no use to keep it: Marker will flicker around the screen.
×
1249
                        }
×
1250
                }
1251
        }
1252
        StelMovementMgr* mmgr = GETSTELMODULE(StelMovementMgr);
×
1253
        Q_ASSERT(mmgr);
×
1254
        mmgr->setFlagTracking(false);
×
1255
}
×
1256

1257
// Get the information on the current location
1258
const StelLocation& StelCore::getCurrentLocation() const
×
1259
{
1260
        return position->getCurrentLocation();
×
1261
}
1262

1263
const QSharedPointer<Planet> StelCore::getCurrentPlanet() const
×
1264
{
1265
        return position->getHomePlanet();
×
1266
}
1267

1268
const StelObserver *StelCore::getCurrentObserver() const
×
1269
{
1270
        return position;
×
1271
}
1272

1273
void StelCore::setObserver(StelObserver *obs)
×
1274
{
1275
        delete position;
×
1276
        position = obs;
×
1277
        if (!getUseCustomTimeZone() && obs->getCurrentLocation().ianaTimeZone.length()>0)
×
1278
                setCurrentTimeZone(obs->getCurrentLocation().ianaTimeZone);
×
1279
}
×
1280

1281
// Smoothly move the observer to the given location
1282
void StelCore::moveObserverTo(const StelLocation& target, double duration, double durationIfPlanetChange, const QString &landscapeID)
×
1283
{
1284
        double d = (getCurrentLocation().planetName==target.planetName) ? duration : durationIfPlanetChange;
×
1285
        if (d>0.)
×
1286
        {
1287
                StelLocation curLoc = getCurrentLocation();
×
1288
                if (position->isTraveling())
×
1289
                {
1290
                        // Avoid using a temporary location name to create another temporary one (otherwise it looks like loc1 -> loc2 -> loc3 etc..)
1291
                        curLoc.name = ".";
×
1292
                }
1293
                SpaceShipObserver* newObs = new SpaceShipObserver(curLoc, target, d);                
×
1294
                setObserver(newObs);
×
1295
                newObs->update(0);
×
1296
        }
×
1297
        else
1298
        {
1299
                setObserver(new StelObserver(target));
×
1300
        }
1301

1302
        // Auto-select observed planet for observer locations
1303
        if (target.role==QChar('o'))
×
1304
        {
1305
                // If we change to an Observer "planet", auto-select and focus on the observed object.
1306
                SolarSystem *ss=GETSTELMODULE(SolarSystem);
×
1307
                PlanetP planet=nullptr;
×
1308
                if (ss)
×
1309
                        planet=GETSTELMODULE(SolarSystem)->searchByEnglishName(target.planetName);
×
1310
                if (planet && planet->getPlanetType()==Planet::isObserver)
×
1311
                {
1312
                        StelObjectMgr *soMgr=GETSTELMODULE(StelObjectMgr);
×
1313
                        if (soMgr)
×
1314
                        {
1315
                                soMgr->findAndSelect(planet->getParent()->getEnglishName());
×
1316
                                GETSTELMODULE(StelMovementMgr)->setFlagTracking(true);
×
1317
                        }
1318
                }
1319
        }
×
1320
        emit targetLocationChanged(target, landscapeID);
×
1321
        emit locationChanged(getCurrentLocation());
×
1322
}
×
1323

1324
double StelCore::getUTCOffset(const double JD) const
×
1325
{
1326
        int year, month, day, hour, minute, second;
1327
        StelUtils::getDateTimeFromJulianDay(JD, &year, &month, &day, &hour, &minute, &second);
×
1328
        // as analogous to second statement in getJDFromDate, nkerr
1329
        if ( year <= 0 )
×
1330
        {
1331
                year = year - 1;
×
1332
        }
1333
        //getTime/DateFromJulianDay returns UTC time, not local time
1334
        QDateTime universal(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC);
×
1335
        if (!universal.isValid())
×
1336
        {
1337
                //qWarning() << "JD " << QString("%1").arg(JD) << " out of bounds of QT help with GMT shift, using current datetime";
1338
                // Assumes the GMT shift was always the same before year -4710
1339
                // NOTE: QDateTime has no year 0, and therefore likely different leap year rules.
1340
                // Under which circumstances do we get invalid universal?
1341
                universal = QDateTime(QDate(-4710, month, day), QTime(hour, minute, second), Qt::UTC);
×
1342
        }
1343

1344
#if defined(Q_OS_WIN)
1345
        if (abs(year)<3)
1346
        {
1347
                // Mitigate a QTBUG on Windows (GH #594).
1348
                // This bug causes offset to be MIN_INT in January to March, 1AD.
1349
                // We assume a constant offset in this remote history,
1350
                // so we construct yet another date to get a valid offset.
1351
                // Application of the named time zones is inappropriate in any case.
1352
                universal = QDateTime(QDate(3, month, day), QTime(hour, minute, second), Qt::UTC);
1353
        }
1354
#endif
1355
        StelLocation loc = getCurrentLocation();
×
1356
        QString tzName = getCurrentTimeZone();
×
1357
        QTimeZone tz(tzName.toUtf8());
×
1358
        // 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.
1359
        // We must use an intermediate Boolean which we set to false where needed.
1360
        bool tzValid=tz.isValid();
×
1361
        if (QString("LMST LTST system_default").contains(tzName))
×
1362
                tzValid=false;
×
1363
        if (!tzValid && !QString("LMST LTST system_default").contains(tzName))
×
1364
        {
1365
                qWarning() << "Invalid timezone: " << tzName;
×
1366
        }
1367

1368
        qint64 shiftInSeconds = 0;
×
1369
        if (tzName=="system_default" || (loc.planetName=="Earth" && !tzValid && !QString("LMST LTST").contains(tzName)))
×
1370
        {
1371
                QDateTime local = universal.toLocalTime();
×
1372
                //Both timezones should be interpreted as UTC because secsTo() converts both
1373
                //times to UTC if their zones have different daylight saving time rules.
1374
                local.setTimeSpec(Qt::UTC);
×
1375
                shiftInSeconds = universal.secsTo(local);
×
1376
                if (abs(shiftInSeconds)>50000 || shiftInSeconds==INT_MIN)
×
1377
                {
1378
                        qDebug() << "TZ system_default or invalid, At JD" << QString::number(JD, 'g', 11) << ", shift:" << shiftInSeconds;
×
1379
                }
1380
        }
×
1381
        else
1382
        {
1383
                // The first adoption of a standard time was on December 1, 1847 in Great Britain
1384
                if (tzValid && loc.planetName=="Earth" && (JD>=StelCore::TZ_ERA_BEGINNING || getUseCustomTimeZone()))
×
1385
                {
1386
                        if (getUseDST())
×
1387
                                shiftInSeconds = tz.offsetFromUtc(universal);
×
1388
                        else
1389
                                shiftInSeconds = tz.standardTimeOffset(universal);
×
1390
                        if (abs(shiftInSeconds)>500000 || shiftInSeconds==INT_MIN)
×
1391
                        {
1392
                                // Something very strange has happened. The Windows-only clause above already mitigated GH #594.
1393
                                // Trigger this with a named custom TZ like Europe/Stockholm.
1394
                                // Then try to wheel back some date in January-March from year 10 to 0. Instead of year 1, it jumps to 70,
1395
                                // an offset of INT_MIN
1396
                                qWarning() << "ERROR TRAPPED! --- Please submit a bug report with this logfile attached.";
×
1397
                                qWarning() << "TZ" << tz << "valid, but at JD" << QString::number(JD, 'g', 11) << ", shift:" << shiftInSeconds;
×
1398
                                qWarning() << "Universal reference date: " << universal.toString();
×
1399
                        }
1400
                }
1401
                else
1402
                {
1403
                        shiftInSeconds = qRound((loc.getLongitude()/15.f)*3600.f); // Local Mean Solar Time
×
1404
                }
1405
                if (tzName=="LTST")
×
1406
                        shiftInSeconds += qRound(getSolutionEquationOfTime()*60);
×
1407
        }
1408
        //qDebug() << "ShiftInSeconds:" << shiftInSeconds;
1409
        #ifdef Q_OS_WIN
1410
        // A dirty hack for report: https://github.com/Stellarium/stellarium/issues/686
1411
        // TODO: switch to IANA TZ on all operating systems
1412
        if (tzName=="Europe/Volgograd")
1413
                shiftInSeconds = 4*3600; // UTC+04:00
1414
        #endif
1415

1416
        // Extraterrestrial: Either use the configured Terrestrial timezone, or even a pseudo-LMST based on planet's rotation speed?
1417
        if (loc.planetName!="Earth")
×
1418
        {
1419
                if (tzValid && (JD>=StelCore::TZ_ERA_BEGINNING || getUseCustomTimeZone()))
×
1420
                {
1421
                        if (getUseDST())
×
1422
                                shiftInSeconds = tz.offsetFromUtc(universal);
×
1423
                        else
1424
                                shiftInSeconds = tz.standardTimeOffset(universal);
×
1425
                        if (shiftInSeconds==INT_MIN) // triggered error
×
1426
                        {
1427
                                // Something very strange has happened. The Windows-only clause above already mitigated GH #594.
1428
                                // Trigger this with a named custom TZ like Europe/Stockholm.
1429
                                // Then try to wheel back some date in January-March from year 10 to 0. Instead of year 1, it jumps to 70,
1430
                                // an offset of INT_MIN
1431
                                qWarning() << "ERROR TRAPPED! --- Please submit a bug report with this logfile attached.";
×
1432
                                qWarning() << "TZ" << tz << "valid, but at JD" << QString::number(JD, 'g', 11) << ", shift:" << shiftInSeconds;
×
1433
                                qWarning() << "Universal reference date: " << universal.toString();
×
1434
                        }
1435
                }
1436
                else
1437
                {
1438
                        // TODO: This should give "mean solar time" for any planet.
1439
                        // Combine rotation and orbit, or (for moons) rotation and orbit of parent planet.
1440
                        // LTST is even worse, needs equation of time for other planets.
1441
                        shiftInSeconds = 0; // For now, give UT
×
1442
                }
1443
        }
1444

1445
        return shiftInSeconds / 3600.0;
×
1446
}
×
1447

1448
QString StelCore::getCurrentTimeZone() const
×
1449
{
1450
        return currentTimeZone;
×
1451
}
1452

1453
void StelCore::setCurrentTimeZone(const QString& tz)
×
1454
{
1455
        if (StelApp::getInstance().getLocationMgr().getAllTimezoneNames().contains(tz))
×
1456
        {
1457
                currentTimeZone = tz;
×
1458
                emit currentTimeZoneChanged(tz);
×
1459
        }
1460
        else
1461
        {
1462
                qWarning() << "StelCore: Invalid timezone name:" << tz << " -- not setting timezone.";
×
1463
        }
1464
}
×
1465

1466
bool StelCore::getUseDST() const
×
1467
{
1468
        return flagUseDST;
×
1469
}
1470

1471
void StelCore::setUseDST(const bool b)
×
1472
{
1473
        flagUseDST = b;
×
1474
        StelApp::getInstance().getSettings()->setValue("localization/flag_dst", b);
×
1475
        emit flagUseDSTChanged(b);
×
1476
}
×
1477

1478
void StelCore::setDitheringMode(const DitheringMode newMode)
×
1479
{
1480
        if(newMode == ditheringMode)
×
1481
                return;
×
1482

1483
        ditheringMode = newMode;
×
1484
        emit ditheringModeChanged(newMode);
×
1485
}
1486

1487
void StelCore::setDitheringMode(const QString& modeName)
×
1488
{
1489
        const auto mode = parseDitheringMode(modeName);
×
1490
        setDitheringMode(mode);
×
1491
}
×
1492

1493
bool StelCore::getUseCustomTimeZone() const
×
1494
{
1495
        return flagUseCTZ;
×
1496
}
1497

1498
void StelCore::setUseCustomTimeZone(const bool b)
×
1499
{
1500
        flagUseCTZ = b;
×
1501
        emit useCustomTimeZoneChanged(b);
×
1502
}
×
1503

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

1508
        const double T=(JDE-2451545.0)/36525.;
×
1509
        const double tau = T*0.1;
×
1510
        const double epsRad=getPrecessionAngleVondrakEpsilon(JDE);
×
1511
        const double e = (-0.0000001267*T-0.000042037)*T+0.016708634;
×
1512
        const double M = ((-0.0001537*T+35999.05029)*T+357.52911)*M_PI_180;
×
1513
        double Lo = StelUtils::fmodpos(280.4664567 + tau*(360007.6982779 + tau*(0.03032028 + tau*(1./49931. + tau*(-1./15300. - tau/2000000.)))), 360.);
×
1514
        Lo *= M_PI_180;
×
1515
        double y=tan(epsRad*0.5); y*=y;
×
1516

1517
        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);
×
1518
        return E*M_180_PI*4.;
×
1519
}
1520

1521
double StelCore::getSolutionEquationOfTime() const
×
1522
{
1523
        const double tau = (getJDE() - 2451545.0)/365250.0;
×
1524
        const double sunMeanLongitude = StelUtils::fmodpos(280.4664567 + tau*(360007.6982779 + tau*(0.03032028 + tau*(1./49931. + tau*(-1./15300. - tau/2000000.)))), 360.);
×
1525

1526
        Vec3d pos = GETSTELMODULE(StelObjectMgr)->searchByName("Sun")->getEquinoxEquatorialPos(this);
×
1527
        double ra, dec;
1528
        StelUtils::rectToSphe(&ra, &dec, pos);
×
1529

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

1533
        double deltaPsi, deltaEps;
1534
        getNutationAngles(getJDE(), &deltaPsi, &deltaEps); // these are radians!
×
1535
        double equation = 4*(sunMeanLongitude - 0.0057183 - alpha + deltaPsi*M_180_PI*cos(getPrecessionAngleVondrakEpsilon(getJDE())));
×
1536
        // The equation of time is always smaller 20 minutes in absolute value
1537
        if (qAbs(equation)>20)
×
1538
        {
1539
                // 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
1540
                if (equation>0.)
×
1541
                        equation -= 1440.;
×
1542
                else
1543
                        equation += 1440.;
×
1544
        }
1545

1546
        return equation;
×
1547
}
1548

1549
//! Set stellarium time to current real world time
1550
void StelCore::setTimeNow()
×
1551
{
1552
        setJD(StelUtils::getJDFromSystem());
×
1553
        // Force emit dateChanged
1554
        emit dateChanged();
×
1555
}
×
1556

1557
void StelCore::setTodayTime(const QTime& target)
×
1558
{
1559
        QDateTime dt = QDateTime::currentDateTime();
×
1560
        if (target.isValid())
×
1561
        {
1562
                dt.setTime(target);
×
1563
                // don't forget to adjust for timezone / daylight savings.
1564
                double JD = StelUtils::qDateTimeToJd(dt)-(static_cast<double>(getUTCOffset(StelUtils::getJDFromSystem())) * JD_HOUR);
×
1565
                setJD(JD);
×
1566
        }
1567
        else
1568
        {
1569
                qWarning() << "WARNING - time passed to StelCore::setTodayTime is not valid. The system time will be used." << target;
×
1570
                setTimeNow();
×
1571
        }
1572
}
×
1573

1574
//! Get whether the current stellarium time is the real world time
1575
bool StelCore::getIsTimeNow(void) const
×
1576
{
1577
        // cache last time to prevent to much slow system call
1578
        static double lastJD = getJD();
×
1579
        static bool previousResult = (fabs(getJD()-(StelUtils::getJDFromSystem()))<JD_SECOND);
×
1580
        if (fabs(lastJD-getJD())>JD_SECOND/4)
×
1581
        {
1582
                lastJD = getJD();
×
1583
                previousResult = (fabs(getJD()-(StelUtils::getJDFromSystem()))<JD_SECOND);
×
1584
        }
1585
        return previousResult;
×
1586
}
1587

1588
QTime StelCore::getInitTodayTime(void) const
×
1589
{
1590
        return initTodayTime;
×
1591
}
1592

1593
void StelCore::setInitTodayTime(const QTime& time)
×
1594
{
1595
        initTodayTime=time;
×
1596
}
×
1597

1598
void StelCore::setPresetSkyTime(QDateTime dateTime)
×
1599
{
1600
        setPresetSkyTime(StelUtils::qDateTimeToJd(dateTime));
×
1601
}
×
1602

1603
void StelCore::addMinute()
×
1604
{
1605
        addSolarDays(JD_MINUTE);
×
1606
}
×
1607

1608
void StelCore::addHour()
×
1609
{
1610
        addSolarDays(JD_HOUR);
×
1611
}
×
1612

1613
void StelCore::addDay()
×
1614
{
1615
        addSolarDays(1.0);
×
1616
}
×
1617

1618
void StelCore::addWeek()
×
1619
{
1620
        addSolarDays(7.0);
×
1621
}
×
1622

1623
void StelCore::addSiderealDay()
×
1624
{
1625
        addSiderealDays(1.0);
×
1626
}
×
1627

1628
void StelCore::addSiderealWeek()
×
1629
{
1630
        addSiderealDays(7.0);
×
1631
}
×
1632

1633
void StelCore::addSiderealYear()
×
1634
{
1635
        addSiderealYears(1.);
×
1636
}
×
1637

1638
void StelCore::addSiderealYears(double n)
×
1639
{
1640
        double days = 365.256363004;
×
1641
        double sidereal = getLocalSiderealYearLength();
×
1642
        Planet::PlanetType ptype = getCurrentPlanet()->getPlanetType();
×
1643
        if (ptype!=Planet::isObserver && ptype!=Planet::isArtificial && sidereal>0.)
×
1644
                days = sidereal;
×
1645

1646
        addSolarDays(days*n);
×
1647
}
×
1648

1649
void StelCore::addSynodicMonth()
×
1650
{
1651
        addSolarDays(29.530588853);
×
1652
}
×
1653

1654
void StelCore::addSaros()
×
1655
{
1656
        // 223 synodic months
1657
        addSolarDays(223*29.530588853);
×
1658
}
×
1659

1660
void StelCore::addDraconicMonth()
×
1661
{
1662
        addSolarDays(27.212220817);
×
1663
}
×
1664

1665
void StelCore::addMeanTropicalMonth()
×
1666
{
1667
        addSolarDays(27.321582241);
×
1668
}
×
1669

1670
void StelCore::addCalendricMonth()
×
1671
{
1672
        double cjd = getJD();
×
1673
        int year, month, day, hour, minute, second;
1674
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1675
        month++;
×
1676
        if (month>12)
×
1677
        {
1678
                month = 1;
×
1679
                year++;
×
1680
        }
1681
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1682
        setJD(cjd);
×
1683
}
×
1684

1685
void StelCore::addAnomalisticMonth()
×
1686
{
1687
        addSolarDays(27.554549878);
×
1688
}
×
1689

1690
void StelCore::addAnomalisticYear()
×
1691
{
1692
        addAnomalisticYears(1.);
×
1693
}
×
1694

1695
void StelCore::addAnomalisticYears(double n)
×
1696
{
1697
        addSolarDays(365.259636*n);
×
1698
}
×
1699

1700
void StelCore::addDraconicYear()
×
1701
{
1702
        addSolarDays(346.620075883);
×
1703
}
×
1704

1705
void StelCore::addMeanTropicalYear()
×
1706
{
1707
        addMeanTropicalYears(1.0);
×
1708
}
×
1709

1710
void StelCore::addTropicalYear()
×
1711
{
1712
        // Source: J. Meeus. More Mathematical Astronomy Morsels. 2002, p. 358.
1713
        // Meeus, J. & Savoie, D. The history of the tropical year. Journal of the British Astronomical Association, vol.102, no.1, p.40-42
1714
        // http://articles.adsabs.harvard.edu//full/1992JBAA..102...40M
1715
        const double T = (getJD()-2451545.0)/365250.0;
×
1716
        addSolarDays(365.242189623 - T*(0.000061522 - T*(0.0000000609 + T*0.00000026525)));
×
1717
}
×
1718

1719
void StelCore::addMeanTropicalYears(double n)
×
1720
{        
1721
        // Source: https://en.wikipedia.org/wiki/Tropical_year#Mean_tropical_year_current_value
1722
        addSolarDays(365.2421897*n); // The mean tropical year on January 1, 2000
×
1723
}
×
1724

1725
void StelCore::addJulianYear()
×
1726
{
1727
        addJulianYears(1.);
×
1728
}
×
1729

1730
void StelCore::addGaussianYear()
×
1731
{
1732
        addSolarDays(365.2568983);
×
1733
}
×
1734

1735
void StelCore::addJulianYears(double n)
×
1736
{
1737
        addSolarDays(365.25*n);
×
1738
}
×
1739

1740
void StelCore::subtractMinute()
×
1741
{
1742
        addSolarDays(-JD_MINUTE);
×
1743
}
×
1744

1745
void StelCore::subtractHour()
×
1746
{
1747
        addSolarDays(-JD_HOUR);
×
1748
}
×
1749

1750
void StelCore::subtractDay()
×
1751
{
1752
        addSolarDays(-1.0);
×
1753
}
×
1754

1755
void StelCore::subtractWeek()
×
1756
{
1757
        addSolarDays(-7.0);
×
1758
}
×
1759

1760
void StelCore::subtractSiderealDay()
×
1761
{
1762
        addSiderealDays(-1.0);
×
1763
}
×
1764

1765
void StelCore::subtractSiderealWeek()
×
1766
{
1767
        addSiderealDays(-7.0);
×
1768
}
×
1769

1770
void StelCore::subtractSiderealYear()
×
1771
{
1772
        addSiderealYears(-1.);
×
1773
}
×
1774

1775
void StelCore::subtractSiderealYears(double n)
×
1776
{
1777
        addSiderealYears(-n);
×
1778
}
×
1779

1780
void StelCore::subtractSynodicMonth()
×
1781
{
1782
        addSolarDays(-29.530588853);
×
1783
}
×
1784

1785
void StelCore::subtractSaros()
×
1786
{
1787
        // 223 synodic months
1788
        addSolarDays(-223*29.530588853);
×
1789
}
×
1790

1791
void StelCore::subtractDraconicMonth()
×
1792
{
1793
        addSolarDays(-27.212220817);
×
1794
}
×
1795

1796
void StelCore::subtractMeanTropicalMonth()
×
1797
{
1798
        addSolarDays(-27.321582241);
×
1799
}
×
1800

1801
void StelCore::subtractCalendricMonth()
×
1802
{
1803
        double cjd = getJD();
×
1804
        int year, month, day, hour, minute, second;
1805
        StelUtils::getDateTimeFromJulianDay(cjd, &year, &month, &day, &hour, &minute, &second);
×
1806
        month--;
×
1807
        if (month<1)
×
1808
        {
1809
                month = 12;
×
1810
                year--;
×
1811
        }
1812
        StelUtils::getJDFromDate(&cjd, year, month, day, hour, minute, static_cast<float>(second));
×
1813
        setJD(cjd);
×
1814
}
×
1815

1816
void StelCore::subtractAnomalisticMonth()
×
1817
{
1818
        addSolarDays(-27.554549878);
×
1819
}
×
1820

1821
void StelCore::subtractAnomalisticYear()
×
1822
{
1823
        subtractAnomalisticYears(1.);
×
1824
}
×
1825

1826
void StelCore::subtractAnomalisticYears(double n)
×
1827
{
1828
        addSolarDays(-365.259636*n);
×
1829
}
×
1830

1831
void StelCore::subtractDraconicYear()
×
1832
{
1833
        addSolarDays(-346.620075883);
×
1834
}
×
1835

1836
void StelCore::subtractTropicalYear()
×
1837
{
1838
        // Source: J. Meeus. More Mathematical Astronomy Morsels. 2002, p. 358.
1839
        double T = (getJD()-2451545.0)/365250.0;
×
1840
        addSolarDays(-(365.242189623 - T*(0.000061522 - T*(0.0000000609 + T*0.00000026525))));
×
1841
}
×
1842

1843
void StelCore::subtractMeanTropicalYear()
×
1844
{
1845
        addMeanTropicalYears(-1.0);
×
1846
}
×
1847

1848
void StelCore::subtractMeanTropicalYears(double n)
×
1849
{
1850
        addMeanTropicalYears(-1.0*n);
×
1851
}
×
1852

1853
void StelCore::subtractJulianYear()
×
1854
{
1855
        addSolarDays(-365.25);
×
1856
}
×
1857

1858
void StelCore::subtractGaussianYear()
×
1859
{
1860
        addSolarDays(-365.2568983);
×
1861
}
×
1862

1863
void StelCore::subtractJulianYears(double n)
×
1864
{
1865
        addSolarDays(-365.25*n);
×
1866
}
×
1867

1868
void StelCore::addSolarDays(double d)
×
1869
{
1870
        const PlanetP& home = getCurrentPlanet();
×
1871
        Planet::PlanetType ptype = home->getPlanetType();
×
1872
        if (ptype!=Planet::isArtificial && ptype!=Planet::isObserver)
×
1873
                d *= home->getMeanSolarDay();
×
1874

1875
        setJD(getJD() + d);
×
1876

1877
        if (qAbs(d)>0.99) // WTF: qAbs(d)>=1.0 not working here!
×
1878
                emit dateChanged();
×
1879
}
×
1880

1881
void StelCore::addSiderealDays(double d)
×
1882
{
1883
        const PlanetP& home = getCurrentPlanet();
×
1884
        Planet::PlanetType ptype = home->getPlanetType();
×
1885
        if (ptype!=Planet::isArtificial && ptype!=Planet::isObserver)
×
1886
                d *= home->getSiderealDay();
×
1887

1888
        setJD(getJD() + d);
×
1889
}
×
1890

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

1898
//! Get the duration of a sidereal day for the current observer in day.
1899
double StelCore::getLocalSiderealDayLength() const
×
1900
{
1901
        return getCurrentPlanet()->getSiderealDay();
×
1902
}
1903

1904
//! Get the duration of a sidereal year for the current observer in days.
1905
double StelCore::getLocalSiderealYearLength() const
×
1906
{
1907
        return getCurrentPlanet()->getSiderealPeriod();
×
1908
}
1909

1910
QString StelCore::getStartupTimeMode() const
×
1911
{
1912
        return startupTimeMode;
×
1913
}
1914

1915
//! Increase the time speed
1916
void StelCore::increaseTimeSpeed()
×
1917
{
1918
        double s = getTimeRate();
×
1919
        if (s>=JD_SECOND) s*=10.;
×
1920
        else if (s<-JD_SECOND) s/=10.;
×
1921
        else if (s>=0.) s=JD_SECOND;
×
1922
        else s=0.;
×
1923
        setTimeRate(s);
×
1924
}
×
1925

1926
//! Decrease the time speed
1927
void StelCore::decreaseTimeSpeed()
×
1928
{
1929
        double s = getTimeRate();
×
1930
        if (s>JD_SECOND) s/=10.;
×
1931
        else if (s<=-JD_SECOND) s*=10.;
×
1932
        else if (s<=0.) s=-JD_SECOND;
×
1933
        else s=0.;
×
1934
        setTimeRate(s);
×
1935
}
×
1936

1937
void StelCore::increaseTimeSpeedLess()
×
1938
{
1939
        double s = getTimeRate();
×
1940
        if (s>=JD_SECOND) s*=2.;
×
1941
        else if (s<-JD_SECOND) s/=2.;
×
1942
        else if (s>=0.) s=JD_SECOND;
×
1943
        else s=0.;
×
1944
        setTimeRate(s);
×
1945
}
×
1946

1947
void StelCore::decreaseTimeSpeedLess()
×
1948
{
1949
        double s = getTimeRate();
×
1950
        if (s>JD_SECOND) s/=2.;
×
1951
        else if (s<=-JD_SECOND) s*=2.;
×
1952
        else if (s<=0.) s=-JD_SECOND;
×
1953
        else s=0.;
×
1954
        setTimeRate(s);
×
1955
}
×
1956

1957
void StelCore::setZeroTimeSpeed()
×
1958
{
1959
        setTimeRate(0);
×
1960
}
×
1961

1962
void StelCore::setRealTimeSpeed()
×
1963
{
1964
        setTimeRate(JD_SECOND);
×
1965
}
×
1966

1967
void StelCore::toggleRealTimeSpeed()
×
1968
{
1969
        (!getRealTimeSpeed()) ? setRealTimeSpeed() : setZeroTimeSpeed();
×
1970
}
×
1971

1972
bool StelCore::getRealTimeSpeed() const
×
1973
{
1974
        return (fabs(timeSpeed-JD_SECOND)<0.0000001);
×
1975
}
1976

1977
////////////////////////////////////////////////////////////////////////////////
1978
// Increment time
1979
void StelCore::updateTime(double deltaTime)
×
1980
{
1981
        if (getRealTimeSpeed())
×
1982
        {
1983
                JD.first = jdOfLastJDUpdate + (QDateTime::currentMSecsSinceEpoch() - milliSecondsOfLastJDUpdate) / 1000.0 * JD_SECOND;
×
1984
        }
1985
        else
1986
        {
1987
                JD.first = jdOfLastJDUpdate + (QDateTime::currentMSecsSinceEpoch() - milliSecondsOfLastJDUpdate) / 1000.0 * timeSpeed;
×
1988
        }
1989

1990
        // Fix time limits to -100000 to +100000 to prevent bugs
1991
        if (JD.first>38245309.499988) JD.first = 38245309.499988;
×
1992
        if (JD.first<-34803211.500012) JD.first = -34803211.500012;
×
1993
        JD.second=computeDeltaT(JD.first);
×
1994

1995
        if (position->isObserverLifeOver())
×
1996
        {
1997
                // Unselect if the new home planet is the previously selected object
1998
                StelObjectMgr* objmgr = GETSTELMODULE(StelObjectMgr);
×
1999
                Q_ASSERT(objmgr);
×
2000
                if (objmgr->getWasSelected() && objmgr->getSelectedObject()[0].data()==getCurrentPlanet())
×
2001
                {
2002
                        objmgr->unSelect();
×
2003
                }
2004
                StelObserver* newObs = position->getNextObserver();
×
2005
                delete position;
×
2006
                position = newObs;
×
2007
        }
2008
        if (position->update(deltaTime))
×
2009
                emit locationChanged(getCurrentLocation());
×
2010

2011
        // Position of sun and all the satellites (ie planets)
2012
        // GZ maybe setting this static can speedup a bit?
2013
        static SolarSystem* solsystem = static_cast<SolarSystem*>(StelApp::getInstance().getModuleMgr().getModule("SolarSystem"));
×
2014
        // Likely the most important location where we need JDE:
2015
        solsystem->computePositions(getJDE(), getCurrentPlanet());
×
2016
}
×
2017

2018
void StelCore::resetSync()
×
2019
{
2020
        jdOfLastJDUpdate = getJD();
×
2021
        //use currentMsecsSinceEpoch directly instead of StelApp::getTotalRuntime,
2022
        //because the StelApp::startMSecs gets subtracted anyways in update()
2023
        //also changed to qint64 to increase precision
2024
        milliSecondsOfLastJDUpdate = QDateTime::currentMSecsSinceEpoch();
×
2025
        emit timeSyncOccurred(jdOfLastJDUpdate);
×
2026
}
×
2027

2028
void StelCore::registerMathMetaTypes()
×
2029
{
2030
        //enables use of these types in QVariant, StelProperty, signals and slots
2031
        qRegisterMetaType<Vec2d>();
×
2032
        qRegisterMetaType<Vec2f>();
×
2033
        qRegisterMetaType<Vec2i>();
×
2034
        qRegisterMetaType<Vec3d>();
×
2035
        qRegisterMetaType<Vec3f>();
×
2036
        qRegisterMetaType<Vec3i>();
×
2037
        qRegisterMetaType<Vec4d>();
×
2038
        qRegisterMetaType<Vec4f>();
×
2039
        qRegisterMetaType<Vec4i>();
×
2040
        qRegisterMetaType<Mat4d>();
×
2041
        qRegisterMetaType<Mat4f>();
×
2042
        qRegisterMetaType<Mat3d>();
×
2043
        qRegisterMetaType<Mat3f>();
×
2044

2045
#if (QT_VERSION<QT_VERSION_CHECK(6,0,0))
2046
        //registers the QDataStream operators, so that QVariants with these types can be saved
2047
        qRegisterMetaTypeStreamOperators<Vec2d>();
×
2048
        qRegisterMetaTypeStreamOperators<Vec2f>();
×
2049
        qRegisterMetaTypeStreamOperators<Vec2i>();
×
2050
        qRegisterMetaTypeStreamOperators<Vec3d>();
×
2051
        qRegisterMetaTypeStreamOperators<Vec3f>();
×
2052
        qRegisterMetaTypeStreamOperators<Vec3i>();
×
2053
        qRegisterMetaTypeStreamOperators<Vec4d>();
×
2054
        qRegisterMetaTypeStreamOperators<Vec4f>();
×
2055
        qRegisterMetaTypeStreamOperators<Vec4i>();
×
2056
        qRegisterMetaTypeStreamOperators<Mat4d>();
×
2057
        qRegisterMetaTypeStreamOperators<Mat4f>();
×
2058
        qRegisterMetaTypeStreamOperators<Mat3d>();
×
2059
        qRegisterMetaTypeStreamOperators<Mat3f>();
×
2060
#endif
2061
        //for debugging QVariants with these types, it helps if we register the string converters
2062
        // This is also required for QJSEngine.
2063
        QMetaType::registerConverter(&Vec2d::toString);
×
2064
        QMetaType::registerConverter(&Vec2f::toString);
×
2065
        QMetaType::registerConverter(&Vec2i::toString);
×
2066
        QMetaType::registerConverter(&Vec3d::toString);
×
2067
        QMetaType::registerConverter(&Vec3f::toString);
×
2068
        QMetaType::registerConverter(&Vec3i::toString);
×
2069
        QMetaType::registerConverter(&Vec4d::toString);
×
2070
        QMetaType::registerConverter(&Vec4f::toString);
×
2071
        QMetaType::registerConverter(&Vec4i::toString);
×
2072

2073
        //Hopefully this works to convert types in scripts when given as String "[...]"
2074
        // Maybe even make brackets optional!
2075
        // Nope, does not work for QJSEngine.
2076
//        QMetaType::registerConverter<QString, Vec2d>(&Vec2d::fromBracketedString);
2077
//        QMetaType::registerConverter<QString, Vec2f>(&Vec2f::fromBracketedString);
2078
//        QMetaType::registerConverter<QString, Vec2i>(&Vec2i::fromBracketedString);
2079
//        QMetaType::registerConverter<QString, Vec3d>(&Vec3d::fromBracketedString);
2080
//        QMetaType::registerConverter<QString, Vec3f>(&Vec3f::fromBracketedString);
2081
//        QMetaType::registerConverter<QString, Vec3i>(&Vec3i::fromBracketedString);
2082
//        QMetaType::registerConverter<QString, Vec4d>(&Vec4d::fromBracketedString);
2083
//        QMetaType::registerConverter<QString, Vec4f>(&Vec4f::fromBracketedString);
2084
//        QMetaType::registerConverter<QString, Vec4i>(&Vec4i::fromBracketedString);
2085
}
×
2086

2087
void StelCore::setStartupTimeMode(const QString& s)
×
2088
{
2089
        startupTimeMode = s;
×
2090
}
×
2091

2092
// return precomputed DeltaT in seconds. Public.
2093
double StelCore::getDeltaT() const
×
2094
{
2095
        return JD.second;
×
2096
}
2097

2098

2099
// compute and return DeltaT in seconds. Try not to call it directly, current DeltaT, JD, and JDE are available.
2100
double StelCore::computeDeltaT(const double JD)
×
2101
{
2102
        double DeltaT = 0.;
×
2103
        if (currentDeltaTAlgorithm==Custom)
×
2104
        {
2105
                // User defined coefficients for quadratic equation for DeltaT may change frequently.
2106
                deltaTnDot = deltaTCustomNDot; // n.dot = custom value "/cy/cy
×
2107
                int year, month, day;
2108
                StelUtils::getDateFromJulianDay(JD, &year, &month, &day);
×
2109
                double u = (StelUtils::yearFraction(year,month,day)-getDeltaTCustomYear())/100.;
×
2110
                DeltaT = deltaTCustomEquationCoeff[0] + u*(deltaTCustomEquationCoeff[1] + u*deltaTCustomEquationCoeff[2]);
×
2111
        }
2112

2113
        else
2114
        {
2115
                Q_ASSERT(deltaTfunc);
×
2116
                DeltaT=deltaTfunc(JD);
×
2117
        }
2118

2119
        if (!deltaTdontUseMoon)
×
2120
                DeltaT += StelUtils::getMoonSecularAcceleration(JD, deltaTnDot, ((de440Active&&EphemWrapper::jd_fits_de440(JD)) ||
×
2121
                                                                                 (de441Active&&EphemWrapper::jd_fits_de441(JD)) ||
×
2122
                                                                                 (de430Active&&EphemWrapper::jd_fits_de430(JD)) ||
×
2123
                                                                                 (de431Active&&EphemWrapper::jd_fits_de431(JD))));
×
2124

2125
        return DeltaT;
×
2126
}
2127

2128
// set a function pointer here. This should make the actual computation simpler by just calling the function.
2129
void StelCore::setCurrentDeltaTAlgorithm(DeltaTAlgorithm algorithm)
×
2130
{
2131
        currentDeltaTAlgorithm=algorithm;
×
2132
        deltaTdontUseMoon = false; // most algorithms will use it!
×
2133
        switch (currentDeltaTAlgorithm)
×
2134
        {
2135
                case WithoutCorrection:
×
2136
                        // Without correction, DeltaT is disabled
2137
                        deltaTfunc = StelUtils::getDeltaTwithoutCorrection;
×
2138
                        deltaTnDot = -26.; // n.dot = -26.0"/cy/cy OR WHAT SHALL WE DO HERE?
×
2139
                        deltaTdontUseMoon = true;
×
2140
                        deltaTstart        = INT_MIN;
×
2141
                        deltaTfinish        = INT_MAX;
×
2142
                        break;
×
2143
                case Schoch:
×
2144
                        // Schoch (1931) algorithm for DeltaT
2145
                        deltaTnDot = -29.68; // n.dot = -29.68"/cy/cy
×
2146
                        deltaTfunc = StelUtils::getDeltaTBySchoch;
×
2147
                        deltaTstart        = -300;
×
2148
                        deltaTfinish        = 1980;
×
2149
                        break;
×
2150
                case Clemence:
×
2151
                        // Clemence (1948) algorithm for DeltaT
2152
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy
×
2153
                        deltaTfunc = StelUtils::getDeltaTByClemence;
×
2154
                        deltaTstart        = 1681;
×
2155
                        deltaTfinish        = 1900;
×
2156
                        break;
×
2157
                case IAU:
×
2158
                        // IAU (1952) algorithm for DeltaT, based on observations by Spencer Jones (1939)
2159
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy
×
2160
                        deltaTfunc = StelUtils::getDeltaTByIAU;
×
2161
                        deltaTstart        = 1681;
×
2162
                        deltaTfinish        = 1936; // Details in http://adsabs.harvard.edu/abs/1939MNRAS..99..541S
×
2163
                        break;
×
2164
                case AstronomicalEphemeris:
×
2165
                        // Astronomical Ephemeris (1960) algorithm for DeltaT
2166
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy
×
2167
                        deltaTfunc = StelUtils::getDeltaTByAstronomicalEphemeris;
×
2168
                        // GZ: What is the source of "1681..1900"? Expl.Suppl.AE 1961-p87 says "...over periods extending back to ancient times"
2169
                        // I changed to what I estimate.
2170
                        deltaTstart        = -500; // 1681;
×
2171
                        deltaTfinish        =  2000; // 1900;
×
2172
                        break;
×
2173
                case TuckermanGoldstine:
×
2174
                        // Tuckerman (1962, 1964) & Goldstine (1973) algorithm for DeltaT
2175
                        //FIXME: n.dot
2176
                        deltaTnDot = -22.44; // n.dot = -22.44 "/cy/cy ???
×
2177
                        deltaTfunc = StelUtils::getDeltaTByTuckermanGoldstine;
×
2178
                        deltaTstart        = -600;
×
2179
                        deltaTfinish        = 1649;
×
2180
                        break;
×
2181
                case MullerStephenson:
×
2182
                        // Muller & Stephenson (1975) algorithm for DeltaT
2183
                        deltaTnDot = -37.5; // n.dot = -37.5 "/cy/cy
×
2184
                        deltaTfunc = StelUtils::getDeltaTByMullerStephenson;
×
2185
                        deltaTstart        = -1375;
×
2186
                        deltaTfinish        = 1975;
×
2187
                        break;
×
2188
                case Stephenson1978:
×
2189
                        // Stephenson (1978) algorithm for DeltaT
2190
                        deltaTnDot = -30.0; // n.dot = -30.0 "/cy/cy
×
2191
                        deltaTfunc = StelUtils::getDeltaTByStephenson1978;
×
2192
                        deltaTstart        = INT_MIN; // Range unknown!
×
2193
                        deltaTfinish        = INT_MAX;
×
2194
                        break;
×
2195
                case SchmadelZech1979:
×
2196
                        // Schmadel & Zech (1979) algorithm for DeltaT
2197
                        deltaTnDot = -23.8946; // n.dot = -23.8946 "/cy/cy
×
2198
                        deltaTfunc = StelUtils::getDeltaTBySchmadelZech1979;
×
2199
                        deltaTstart        = 1800;
×
2200
                        deltaTfinish        = 1975;
×
2201
                        break;
×
2202
                case MorrisonStephenson1982:
×
2203
                        // Morrison & Stephenson (1982) algorithm for DeltaT (used by RedShift)
2204
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2205
                        deltaTfunc = StelUtils::getDeltaTByMorrisonStephenson1982;
×
2206
                        // FIXME: Is it valid range?
2207
                        deltaTstart        = -4000;
×
2208
                        deltaTfinish        = 2800;
×
2209
                        break;
×
2210
                case StephensonMorrison1984:
×
2211
                        // Stephenson & Morrison (1984) algorithm for DeltaT
2212
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2213
                        deltaTfunc = StelUtils::getDeltaTByStephensonMorrison1984;
×
2214
                        deltaTstart        = -391;
×
2215
                        deltaTfinish        = 1600; // TODO: 1630..1980 are tabulated values
×
2216
                        break;
×
2217
                case StephensonHoulden:
×
2218
                        // Stephenson & Houlden (1986) algorithm for DeltaT.
2219
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2220
                        deltaTfunc = StelUtils::getDeltaTByStephensonHoulden;
×
2221
                        deltaTstart        = -1500;
×
2222
                        deltaTfinish        = 1600; // TODO: 1630..1980 are tabulated values from Stephenson & Morrison (1984)
×
2223
                        break;
×
2224
                case Espenak:
×
2225
                        // Espenak (1987, 1989) algorithm for DeltaT
2226
                        //FIXME: n.dot
2227
                        deltaTnDot = -23.8946; // n.dot = -23.8946 "/cy/cy ???
×
2228
                        deltaTfunc = StelUtils::getDeltaTByEspenak;
×
2229
                        deltaTstart        = 1950;
×
2230
                        deltaTfinish        = 2100;
×
2231
                        break;
×
2232
                case Borkowski:
×
2233
                        // Borkowski (1988) algorithm for DeltaT, relates to ELP2000-85!
2234
                        deltaTnDot = -23.895; // GZ: I see -23.895 in the paper, not -23.859; (?) // n.dot = -23.859 "/cy/cy
×
2235
                        deltaTfunc = StelUtils::getDeltaTByBorkowski;
×
2236
                        deltaTstart        = -2136;
×
2237
                        deltaTfinish        = 1715;
×
2238
                        break;
×
2239
                case SchmadelZech1988:
×
2240
                        // Schmadel & Zech (1988) algorithm for DeltaT
2241
                        //FIXME: n.dot
2242
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy ???
×
2243
                        deltaTfunc = StelUtils::getDeltaTBySchmadelZech1988;
×
2244
                        deltaTstart        = 1800;
×
2245
                        deltaTfinish        = 1988;
×
2246
                        break;
×
2247
                case ChaprontTouze:
×
2248
                        // Chapront-Touzé & Chapront (1991) algorithm for DeltaT
2249
                        deltaTnDot = -23.8946; // n.dot = -23.8946 "/cy/cy
×
2250
                        deltaTfunc = StelUtils::getDeltaTByChaprontTouze;
×
2251
                        // FIXME: Is it valid range?
2252
                        deltaTstart        = -4000;
×
2253
                        deltaTfinish        = 8000;
×
2254
                        break;
×
2255
                case StephensonMorrison1995:
×
2256
                        // Stephenson & Morrison (1995) algorithm for DeltaT
2257
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2258
                        deltaTfunc = StelUtils::getDeltaTByStephensonMorrison1995;
×
2259
                        deltaTstart        = -700;
×
2260
                        deltaTfinish        = 1600;
×
2261
                        break;
×
2262
                case Stephenson1997:
×
2263
                        // Stephenson (1997) algorithm for DeltaT
2264
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2265
                        deltaTfunc = StelUtils::getDeltaTByStephenson1997;
×
2266
                        deltaTstart        = -500;
×
2267
                        deltaTfinish        = 1600;
×
2268
                        break;
×
2269
                case ChaprontMeeus:
×
2270
                        // Chapront, Chapront-Touze & Francou (1997) & Meeus (1998) algorithm for DeltaT
2271
                        deltaTnDot = -25.7376; // n.dot = -25.7376 "/cy/cy
×
2272
                        deltaTfunc = StelUtils::getDeltaTByChaprontMeeus;
×
2273
                        deltaTstart        = -400; // 1800; // not explicitly given, but guess based on his using ChaprontFrancou which is cited elsewhere in a similar term with -391.
×
2274
                        deltaTfinish        =  2150; // 1997;
×
2275
                        break;
×
2276
                case JPLHorizons:
×
2277
                        // JPL Horizons algorithm for DeltaT
2278
                        deltaTnDot = -25.7376; // n.dot = -25.7376 "/cy/cy
×
2279
                        deltaTfunc = StelUtils::getDeltaTByJPLHorizons;
×
2280
                        deltaTstart        = -2999;
×
2281
                        deltaTfinish        = 1620;
×
2282
                        break;
×
2283
                case MeeusSimons:
×
2284
                        // Meeus & Simons (2000) algorithm for DeltaT
2285
                        deltaTnDot = -25.7376; // n.dot = -25.7376 "/cy/cy
×
2286
                        deltaTfunc = StelUtils::getDeltaTByMeeusSimons;
×
2287
                        deltaTstart        = 1620;
×
2288
                        deltaTfinish        = 2000;
×
2289
                        break;
×
2290
                case ReingoldDershowitz:
×
2291
                        // Reingold & Dershowitz (2002, 2007, 2018) algorithm for DeltaT
2292
                        // FIXME: n.dot
2293
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy ???
×
2294
                        deltaTfunc = StelUtils::getDeltaTByReingoldDershowitz;
×
2295
                        // GZ: while not original work, it's based on Meeus and therefore the full implementation covers likewise approximately:
2296
                        // AW: limits from 4th edition:
2297
                        deltaTstart        = -500; //1620;
×
2298
                        deltaTfinish        = 2150; //2019;
×
2299
                        break;
×
2300
                case MontenbruckPfleger:
×
2301
                        // Montenbruck & Pfleger (2000) algorithm for DeltaT
2302
                        // NOTE: book does not contain n.dot value
2303
                        // FIXME: n.dot
2304
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy ???
×
2305
                        deltaTfunc = StelUtils::getDeltaTByMontenbruckPfleger;
×
2306
                        deltaTstart        = 1825;
×
2307
                        deltaTfinish        = 2005;
×
2308
                        break;
×
2309
                case MorrisonStephenson2004:
×
2310
                        // Morrison & Stephenson (2004, 2005) algorithm for DeltaT
2311
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2312
                        deltaTfunc = StelUtils::getDeltaTByMorrisonStephenson2004;
×
2313
                        deltaTstart        = -1000;
×
2314
                        deltaTfinish        = 2000;
×
2315
                        break;
×
2316
                case Reijs:
×
2317
                        // Reijs (2006) algorithm for DeltaT
2318
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2319
                        deltaTfunc = StelUtils::getDeltaTByReijs;
×
2320
                        deltaTstart        = -1500; // -500; // GZ: It models long-term variability, so we should reflect this. Not sure on the begin, though.
×
2321
                        deltaTfinish        = 1100; // not 1620; // GZ: Not applicable for telescopic era, and better not after 1100 (pers.comm.)
×
2322
                        break;
×
2323
                case EspenakMeeus:
×
2324
                        // Espenak & Meeus (2006) algorithm for DeltaT
2325
                        deltaTnDot = -25.858; // n.dot = -25.858 "/cy/cy
×
2326
                        deltaTfunc = StelUtils::getDeltaTByEspenakMeeus;
×
2327
                        deltaTstart        = -1999;
×
2328
                        deltaTfinish        = 3000;
×
2329
                        break;
×
2330
                case EspenakMeeusModified:
×
2331
                        // Espenak & Meeus (2006) algorithm (with modified formulae) for DeltaT
2332
                        deltaTnDot = -25.858; // n.dot = -25.858 "/cy/cy
×
2333
                        deltaTfunc = StelUtils::getDeltaTByEspenakMeeusModified;
×
2334
                        deltaTstart        = -1999;
×
2335
                        deltaTfinish        = 3000;
×
2336
                        break;
×
2337
                case EspenakMeeusZeroMoonAccel:
×
2338
                        // This is a trying area. Something is wrong with DeltaT, maybe ndot is still not applied correctly.
2339
                        // Espenak & Meeus (2006) algorithm for DeltaT
2340
                        deltaTnDot = -25.858; // n.dot = -25.858 "/cy/cy
×
2341
                        deltaTdontUseMoon = true;
×
2342
                        deltaTfunc = StelUtils::getDeltaTByEspenakMeeus;
×
2343
                        deltaTstart        = -1999;
×
2344
                        deltaTfinish        = 3000;
×
2345
                        break;
×
2346
                case Banjevic:
×
2347
                        // Banjevic (2006) algorithm for DeltaT
2348
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2349
                        deltaTfunc = StelUtils::getDeltaTByBanjevic;
×
2350
                        deltaTstart        = -2020;
×
2351
                        deltaTfinish        = 1620;
×
2352
                        break;
×
2353
                case IslamSadiqQureshi:
×
2354
                        // Islam, Sadiq & Qureshi (2008 + revisited 2013) algorithm for DeltaT (6 polynomials)
2355
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2356
                        deltaTfunc = StelUtils::getDeltaTByIslamSadiqQureshi;
×
2357
                        deltaTdontUseMoon = true; // Seems this solutions doesn't use value of secular acceleration of the Moon
×
2358
                        deltaTstart        = 1620;
×
2359
                        deltaTfinish        = 2007;
×
2360
                        break;
×
2361
                case KhalidSultanaZaidi:
×
2362
                        // M. Khalid, Mariam Sultana and Faheem Zaidi polinomial approximation of time period 1620-2013 (2014)
2363
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2364
                        deltaTfunc = StelUtils::getDeltaTByKhalidSultanaZaidi;
×
2365
                        deltaTdontUseMoon = true; // Seems this solutions doesn't use value of secular acceleration of the Moon
×
2366
                        deltaTstart        = 1620;
×
2367
                        deltaTfinish        = 2013;
×
2368
                        break;
×
2369
                case StephensonMorrisonHohenkerk2016:
×
2370
                        deltaTnDot = -25.82; // n.dot = -25.82 "/cy/cy
×
2371
                        deltaTfunc=StelUtils::getDeltaTByStephensonMorrisonHohenkerk2016;
×
2372
                        deltaTstart        = -720;
×
2373
                        deltaTfinish        = 2019;
×
2374
                        break;
×
2375
                case Henriksson2017:
×
2376
                        // Henriksson solution (2017) for Schoch formula for DeltaT (1931)
2377
                        // Source: The Acceleration of the Moon and the Universe – the Mass of the Graviton.
2378
                        // Henriksson, G.
2379
                        // Advances in Astrophysics, Vol. 2, No. 3, August 2017
2380
                        // https://doi.org/10.22606/adap.2017.23004
2381
                        deltaTnDot = -30.128; // n.dot = -30.128"/cy/cy
×
2382
                        deltaTfunc = StelUtils::getDeltaTBySchoch;
×
2383
                        deltaTstart        = -4000;
×
2384
                        deltaTfinish        = 2000;
×
2385
                        break;
×
2386
                case Custom:
×
2387
                        // User defined coefficients for quadratic equation for DeltaT. These can change, and we don't use the function pointer here.
2388
                        deltaTnDot = deltaTCustomNDot; // n.dot = custom value "/cy/cy
×
2389
                        deltaTfunc=Q_NULLPTR;
×
2390
                        deltaTstart        = INT_MIN; // Range unknown!
×
2391
                        deltaTfinish        = INT_MAX;
×
2392
                        break;
×
2393
                default:
×
2394
                        deltaTnDot = -26.0; // n.dot = -26.0 "/cy/cy
×
2395
                        deltaTfunc=Q_NULLPTR;
×
2396
                        deltaTstart        = INT_MIN; // Range unknown!
×
2397
                        deltaTfinish        = INT_MAX;
×
2398
                        qCritical() << "StelCore: unknown DeltaT algorithm selected (" << currentDeltaTAlgorithm << ")! (setting nDot=-26., but no function!!)";
×
2399
        }
2400
        Q_ASSERT((currentDeltaTAlgorithm==Custom) || (deltaTfunc!=Q_NULLPTR));
×
2401
}
×
2402

2403
//! Set the current algorithm for time correction to use
2404
void StelCore::setCurrentDeltaTAlgorithmKey(QString key)
×
2405
{
2406
        const QMetaEnum& en = metaObject()->enumerator(metaObject()->indexOfEnumerator("DeltaTAlgorithm"));
×
2407
        DeltaTAlgorithm algo = static_cast<DeltaTAlgorithm>(en.keyToValue(key.toLatin1().data()));
×
2408
        if (algo<0)
×
2409
        {
2410
                qWarning() << "Unknown DeltaT algorithm: " << key << "setting \"WithoutCorrection\" instead";
×
2411
                algo = WithoutCorrection;
×
2412
        }
2413
        setCurrentDeltaTAlgorithm(algo);
×
2414
}
×
2415

2416
//! Get the current algorithm used by the DeltaT
2417
QString StelCore::getCurrentDeltaTAlgorithmKey(void) const
×
2418
{
2419
        return metaObject()->enumerator(metaObject()->indexOfEnumerator("DeltaTAlgorithm")).key(currentDeltaTAlgorithm);
×
2420
}
2421

2422
//! Get description of the current algorithm for time correction
2423
QString StelCore::getCurrentDeltaTAlgorithmDescription(void) const
×
2424
{
2425
        // 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.
2426
        QString description;
×
2427
        double jd = 0;
×
2428
        QString marker;
×
2429
        switch (getCurrentDeltaTAlgorithm())
×
2430
        {
2431
                case WithoutCorrection:
×
2432
                        description = q_("Correction is disabled. Use only if you know what you are doing!");
×
2433
                        break;
×
2434
                case Schoch: // historical value.
×
2435
                        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));
×
2436
                        break;
×
2437
                case Clemence: // historical value.
×
2438
                        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));
×
2439
                        break;
×
2440
                case IAU: // historical value.
×
2441
                        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));
×
2442
                        // find year of publication of AFFC
2443
                        break;
×
2444
                case AstronomicalEphemeris: // historical value.
×
2445
                        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));
×
2446
                        // TODO: expand the sentence: ... adopted ... from 19xx-19yy?
2447
                        break;
×
2448
                case TuckermanGoldstine: // historical value.
×
2449
                        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));
×
2450
                        // TODO: These tables are sometimes found cited, but I have no details. Maybe add "based on ... " ?
2451
                        break;
×
2452
                case MullerStephenson:
×
2453
                        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));
×
2454
                        break;
×
2455
                case Stephenson1978:
×
2456
                        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));
×
2457
                        break;
×
2458
                case SchmadelZech1979: // outdated data fit, historical value?
×
2459
                        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));
×
2460
                        break;
×
2461
                case MorrisonStephenson1982:
×
2462
                        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));
×
2463
                        break;
×
2464
                case StephensonMorrison1984: // PRIMARY SOURCE
×
2465
                        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));
×
2466
                        break;
×
2467
                case StephensonHoulden:
×
2468
                        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));
×
2469
                        break;
×
2470
                case Espenak: // limited range, but wide availability?
×
2471
                        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));
×
2472
                        break;
×
2473
                case Borkowski: // Linked to ELP2000-85, so it's important...
×
2474
                        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));
×
2475
                        break;
×
2476
                case SchmadelZech1988: // data fit through Stephenson&Morrison1984, which itself is important. Unclear who uses this version?
×
2477
                        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));
×
2478
                        break;
×
2479
                case ChaprontTouze:
×
2480
                        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));
×
2481
                        break;
×
2482
                case StephensonMorrison1995:
×
2483
                        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));
×
2484
                        break;
×
2485
                case Stephenson1997:
×
2486
                        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));
×
2487
                        break;
×
2488
                case ChaprontMeeus:
×
2489
                        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));
×
2490
                        break;
×
2491
                case JPLHorizons:
×
2492
                        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));
×
2493
                        break;
×
2494
                case MeeusSimons:
×
2495
                        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));
×
2496
                        break;
×
2497
                case MontenbruckPfleger: // uninspired
×
2498
                        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));
×
2499
                        break;
×
2500
                case ReingoldDershowitz: //
×
2501
                        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));
×
2502
                        break;
×
2503
                case MorrisonStephenson2004: // PRIMARY SOURCE
×
2504
                        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));
×
2505
                        break;
×
2506
                case Reijs:
×
2507
                        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));
×
2508
                        break;
×
2509
                case EspenakMeeus: // GENERAL SOLUTION
×
2510
                        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 and in their <em>Five Millennium Canon of Solar Eclipses: -1900 to +3000</em> (2006). 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));
×
2511
                        break;
×
2512
                case EspenakMeeusModified: // MODIFIED SOLUTION
×
2513
                        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. Formula for 2005-2050 is modified to match observed values and near-term predictions.").append(getCurrentDeltaTAlgorithmValidRangeDescription(jd, &marker)).append(" <em>").append(q_("Used by default.")).append("</em>");
×
2514
                        break;
×
2515
                case EspenakMeeusZeroMoonAccel: // PATCHED SOLUTION. Experimental, it may not make sense to keep it in V1.0.
×
2516
                        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));
×
2517
                        break;
×
2518
                case Banjevic:
×
2519
                        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));
×
2520
                        break;
×
2521
                case IslamSadiqQureshi:
×
2522
                        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));
×
2523
                        break;
×
2524
                case KhalidSultanaZaidi:
×
2525
                        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));
×
2526
                        break;
×
2527
                case StephensonMorrisonHohenkerk2016: // PRIMARY SOURCE, SEEMS VERY IMPORTANT
×
2528
                        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));
×
2529
                        break;
×
2530
                case Henriksson2017:
×
2531
                        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));
×
2532
                        break;
×
2533
                case Custom:
×
2534
                        description = q_("This is a quadratic formula for calculation of %1T with coefficients defined by the user.").arg(QChar(0x0394));
×
2535
                        break;
×
2536
                default:
×
2537
                        description = q_("Error");
×
2538
        }
2539

2540
        // Put n-dot value info
2541
        if (getCurrentDeltaTAlgorithm()!=WithoutCorrection)
×
2542
        {
2543
                QString accel = QString("%1\"/cy<sup>2</sup>").arg(QString::number(getDeltaTnDot(), 'f', 4));
×
2544
                QString ndot  = QString("&#x1E45;");
×
2545
                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));
×
2546
        }
×
2547

2548
        return description;
×
2549
}
×
2550

2551
QString StelCore::getCurrentDeltaTAlgorithmValidRangeDescription(const double JD, QString *marker) const
×
2552
{
2553
        QString validRange = "";
×
2554
        QString validRangeAppendix = "";
×
2555
        *marker = "";
×
2556
        int year, month, day;
2557

2558
        StelUtils::getDateFromJulianDay(JD, &year, &month, &day);
×
2559
        switch (currentDeltaTAlgorithm)
×
2560
        {
2561
                // These models provide extrapolated values outside their specified/recommended range.
2562
                case WithoutCorrection:      // and
×
2563
                case Schoch:                 // and
2564
                case Clemence:               // and
2565
                case IAU:                    // and
2566
                case AstronomicalEphemeris:  // and
2567
                case TuckermanGoldstine:     // and
2568
                case StephensonHoulden:      // and
2569
                case MullerStephenson:       // and
2570
                case Stephenson1978:         // and
2571
                case MorrisonStephenson1982: // and
2572
                case StephensonMorrison1984: // and
2573
                case Espenak:                // and
2574
                case Borkowski:              // and
2575
                case StephensonMorrison1995: // and
2576
                case Stephenson1997:         // and
2577
                case ChaprontMeeus:          // and
2578
                case ReingoldDershowitz:     // and
2579
                case MorrisonStephenson2004: // and
2580
                case Reijs:                  // and
2581
                case EspenakMeeus:           // range stated in the Canon, p. 14.  ... and
2582
                case EspenakMeeusModified:   // the default, range stated in the Canon, p. 14.  ... and
2583
                case EspenakMeeusZeroMoonAccel: // and
2584
                case StephensonMorrisonHohenkerk2016: // and
2585
                case Henriksson2017:
2586
                        break;
×
2587
                case JPLHorizons: // and
×
2588
                case MeeusSimons:
2589
                        validRangeAppendix = q_("with zero values outside this range");
×
2590
                        break;
×
2591
                case MontenbruckPfleger:
×
2592
                        validRangeAppendix = q_("with a typical 1-second accuracy and zero values outside this range");
×
2593
                        break;
×
2594
                case SchmadelZech1988:
×
2595
                        validRangeAppendix = q_("with a mean error of less than one second, max. error 1.9s, and values for the limit years outside this range");
×
2596
                        break;
×
2597
                case SchmadelZech1979:  // and
×
2598
                case ChaprontTouze:     // and
2599
                case Banjevic:          // and
2600
                case IslamSadiqQureshi: // and
2601
                case KhalidSultanaZaidi:
2602
                        validRangeAppendix = q_("with values for the limit years outside this range");
×
2603
                        break;
×
2604
                case Custom:
×
2605
                        // Valid range unknown
2606
                        break;
×
2607
        }
2608

2609
        if (deltaTstart > INT_MIN) // limits declared?
×
2610
        {
2611
                if (validRangeAppendix!="")
×
2612
                        validRange = q_("Valid range of usage: between years %1 and %2, %3.").arg(deltaTstart).arg(deltaTfinish).arg(validRangeAppendix);
×
2613
                else
2614
                        validRange = q_("Valid range of usage: between years %1 and %2.").arg(deltaTstart).arg(deltaTfinish);
×
2615
                if ((year < deltaTstart) || (deltaTfinish < year))
×
2616
                        *marker = "*"; // mark "outside designed range, possibly wrong"
×
2617
        }
2618
        else
2619
                *marker = "?"; // mark "no range given"
×
2620

2621
        return QString(" %1").arg(validRange);
×
2622
}
×
2623

2624
// return if sky plus atmosphere is bright enough from sunlight so that e.g. screen labels should be rendered dark.
2625
// DONE: Simply ask the atmosphere for its surrounding brightness
2626
// TODO2: This could be moved to the SkyDrawer or even some GUI class, as it is used to decide a GUI thing.
2627
bool StelCore::isBrightDaylight() const
×
2628
{
2629
        if (propMgr->getStelPropertyValue("Oculars.ocularDisplayed", true).toBool())
×
2630
                return false;
×
2631
        SolarSystem* ssys = GETSTELMODULE(SolarSystem);
×
2632
        if (!ssys->getFlagPlanets())
×
2633
                return false;
×
2634
        if (!getSkyDrawer()->getFlagHasAtmosphere())
×
2635
                return false;
×
2636
        if (ssys->getSolarEclipseFactor(this).first<=0.01) // Total solar eclipse
×
2637
                return false;
×
2638

2639
        // immediately decide upon sky background brightness...
2640
        return (GETSTELMODULE(LandscapeMgr)->getAtmosphereAverageLuminance() > static_cast<float>(getSkyDrawer()->getDaylightLabelThreshold()));
×
2641
}
2642

2643
double StelCore::getCurrentEpoch() const
×
2644
{
2645
        return 2000.0 + (getJD() - 2451545.0)/365.25;
×
2646
}
2647

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

2652
bool StelCore::de430IsAvailable()
×
2653
{
2654
        return de430Available;
×
2655
}
2656

2657
bool StelCore::de431IsAvailable()
×
2658
{
2659
        return de431Available;
×
2660
}
2661

2662
bool StelCore::de430IsActive()
×
2663
{
2664
        return de430Active;
×
2665
}
2666

2667
bool StelCore::de431IsActive()
×
2668
{
2669
        return de431Active;
×
2670
}
2671

2672
void StelCore::setDe430Active(bool status)
×
2673
{
2674
        de430Active = de430Available && status;
×
2675
}
×
2676

2677
void StelCore::setDe431Active(bool status)
×
2678
{
2679
        de431Active = de431Available && status;
×
2680
}
×
2681

2682

2683
bool StelCore::de440IsAvailable()
×
2684
{
2685
        return de440Available;
×
2686
}
2687

2688
bool StelCore::de441IsAvailable()
×
2689
{
2690
        return de441Available;
×
2691
}
2692

2693
bool StelCore::de440IsActive()
×
2694
{
2695
        return de440Active;
×
2696
}
2697

2698
bool StelCore::de441IsActive()
×
2699
{
2700
        return de441Active;
×
2701
}
2702

2703
void StelCore::setDe440Active(bool status)
×
2704
{
2705
        de440Active = de440Available && status;
×
2706
}
×
2707

2708
void StelCore::setDe441Active(bool status)
×
2709
{
2710
        de441Active = de441Available && status;
×
2711
}
×
2712

2713
void StelCore::initEphemeridesFunctions()
×
2714
{
2715
        QSettings* conf = StelApp::getInstance().getSettings();
×
2716

2717
        QString de430ConfigPath = conf->value("astro/de430_path").toString();
×
2718
        QString de431ConfigPath = conf->value("astro/de431_path").toString();
×
2719
        QString de440ConfigPath = conf->value("astro/de440_path").toString();
×
2720
        QString de441ConfigPath = conf->value("astro/de441_path").toString();
×
2721

2722
        QString de430FilePath;
×
2723
        QString de431FilePath;
×
2724
        QString de440FilePath;
×
2725
        QString de441FilePath;
×
2726

2727
        //<-- DE430 -->
2728
        if(de430ConfigPath.remove(QChar('"')).isEmpty())
×
2729
                de430FilePath = StelFileMgr::findFile("ephem/" + QString(DE430_FILENAME), StelFileMgr::File);
×
2730
        else
2731
                de430FilePath = StelFileMgr::findFile(de430ConfigPath, StelFileMgr::File);
×
2732

2733
        de430Available=!de430FilePath.isEmpty();
×
2734
        if(de430Available)
×
2735
        {
2736
                qDebug() << "DE430 at: " << de430FilePath;
×
2737
                EphemWrapper::init_de430(de430FilePath.toStdString().c_str());
×
2738
        }
2739
        setDe430Active(de430Available && conf->value("astro/flag_use_de430", false).toBool());
×
2740

2741
        //<-- DE431 -->
2742
        if(de431ConfigPath.remove(QChar('"')).isEmpty())
×
2743
                de431FilePath = StelFileMgr::findFile("ephem/" + QString(DE431_FILENAME), StelFileMgr::File);
×
2744
        else
2745
                de431FilePath = StelFileMgr::findFile(de431ConfigPath, StelFileMgr::File);
×
2746

2747
        de431Available=!de431FilePath.isEmpty();
×
2748
        if(de431Available)
×
2749
        {
2750
                qDebug() << "DE431 at: " << de431FilePath;
×
2751
                EphemWrapper::init_de431(de431FilePath.toStdString().c_str());
×
2752
        }
2753
        setDe431Active(de431Available && conf->value("astro/flag_use_de431", false).toBool());
×
2754

2755
        //<-- DE440 -->
2756
        if(de440ConfigPath.remove(QChar('"')).isEmpty())
×
2757
                de440FilePath = StelFileMgr::findFile("ephem/" + QString(DE440_FILENAME), StelFileMgr::File);
×
2758
        else
2759
                de440FilePath = StelFileMgr::findFile(de440ConfigPath, StelFileMgr::File);
×
2760

2761
        de440Available=!de440FilePath.isEmpty();
×
2762
        if(de440Available)
×
2763
        {
2764
                qDebug() << "DE440 at: " << de440FilePath;
×
2765
                EphemWrapper::init_de440(de440FilePath.toStdString().c_str());
×
2766
        }
2767
        setDe440Active(de440Available && conf->value("astro/flag_use_de440", false).toBool());
×
2768

2769
        //<-- DE441 -->
2770
        if(de441ConfigPath.remove(QChar('"')).isEmpty())
×
2771
                de441FilePath = StelFileMgr::findFile("ephem/" + QString(DE441_FILENAME), StelFileMgr::File);
×
2772
        else
2773
                de441FilePath = StelFileMgr::findFile(de441ConfigPath, StelFileMgr::File);
×
2774

2775
        de441Available=!de441FilePath.isEmpty();
×
2776
        if(de441Available)
×
2777
        {
2778
                qDebug() << "DE441 at: " << de441FilePath;
×
2779
                EphemWrapper::init_de441(de441FilePath.toStdString().c_str());
×
2780
        }
2781
        setDe441Active(de441Available && conf->value("astro/flag_use_de441", false).toBool());
×
2782
}
×
2783

2784
// Methods for finding constellation from J2000 position.
2785
typedef struct iau_constline{
2786
        double RAlow;  // low value of 1875.0 right ascension segment, HH.dddd
2787
        double RAhigh; // high value of 1875.0 right ascension segment, HH.dddd
2788
        double decLow; // declination 1875.0 of southern border, DD.dddd
2789
        QString constellation; // 3-letter code of constellation
2790
} iau_constelspan;
2791

2792
static QVector<iau_constelspan> iau_constlineVec;
2793
static bool iau_constlineVecInitialized=false;
2794

2795
// File iau_constellations_spans.dat is converted from file data.dat from ADC catalog VI/42.
2796
// We converted back to HH:MM:SS format to avoid the inherent rounding errors present in that file (Bug LP:#1690615).
2797
QString StelCore::getIAUConstellation(const Vec3d &positionEqJnow) const
×
2798
{
2799
        // Precess positionJ2000 to 1875.0
2800
        const Vec3d pos1875=j2000ToJ1875(equinoxEquToJ2000(positionEqJnow, RefractionOff));
×
2801
        double RA1875;
2802
        double dec1875;
2803
        StelUtils::rectToSphe(&RA1875, &dec1875, pos1875);
×
2804
        RA1875 *= 12./M_PI; // hours
×
2805
        if (RA1875 <0.) RA1875+=24.;
×
2806
        dec1875 *= M_180_PI; // degrees
×
2807
        Q_ASSERT(RA1875>=0.0);
×
2808
        Q_ASSERT(RA1875<=24.0);
×
2809
        Q_ASSERT(dec1875<=90.0);
×
2810
        Q_ASSERT(dec1875>=-90.0);
×
2811

2812
        // read file into structure.
2813
        if (!iau_constlineVecInitialized)
×
2814
        {
2815
                //struct iau_constline line;
2816
                QFile file(StelFileMgr::findFile("data/constellations_spans.dat"));
×
2817

2818
                if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
×
2819
                {
2820
                        qWarning() << "IAU constellation line data file data/constellations_spans.dat not found.";
×
2821
                        return "err";
×
2822
                }
2823
                iau_constelspan span;
×
2824
                static const QRegularExpression emptyLine("^\\s*$");
×
2825
                static const QRegularExpression spaceRe("\\s+");
×
2826
                QTextStream in(&file);
×
2827
                while (!in.atEnd())
×
2828
                {
2829
                        // Build list of entries. The checks can certainly become more robust. Actually the file must have 4-part lines.
2830
                        QString line = in.readLine();
×
2831
                        if (line.length()==0) continue;
×
2832
                        if (emptyLine.match(line).hasMatch()) continue;
×
2833
                        if (line.at(0)=='#') continue; // skip comment lines.
×
2834
                        //QStringList list = line.split(QRegularExpression("\\b\\s+\\b"));
2835
                        QStringList list = line.trimmed().split(spaceRe);
×
2836
                        if (list.count() != 4)
×
2837
                        {
2838
                                qWarning() << "IAU constellation file constellations_spans.dat has bad line:" << line << "with" << list.count() << "elements";
×
2839
                                continue;
×
2840
                        }
2841
                        //qDebug() << "Creating span for decl=" << list.at(2) << " from RA=" << list.at(0) << "to" << list.at(1) << ": " << list.at(3);
2842
                        QStringList numList=list.at(0).split(QString(":"));
×
2843
                        span.RAlow= atof(numList.at(0).toLatin1()) + atof(numList.at(1).toLatin1())/60. + atof(numList.at(2).toLatin1())/3600.;
×
2844
                        numList=list.at(1).split(QString(":"));
×
2845
                        span.RAhigh=atof(numList.at(0).toLatin1()) + atof(numList.at(1).toLatin1())/60. + atof(numList.at(2).toLatin1())/3600.;
×
2846
                        numList=list.at(2).split(QString(":"));
×
2847
                        span.decLow=atof(numList.at(0).toLatin1());
×
2848
                        if (span.decLow<0.0)
×
2849
                                span.decLow -= atof(numList.at(1).toLatin1())/60.;
×
2850
                        else
2851
                                span.decLow += atof(numList.at(1).toLatin1())/60.;
×
2852
                        span.constellation=list.at(3);
×
2853
                        iau_constlineVec.append(span);
×
2854
                }
×
2855
                file.close();
×
2856
                iau_constlineVecInitialized=true;
×
2857
        }
×
2858

2859
        // iterate through vector, find entry where declination is lower.
2860
        int entry=0;
×
2861
        while (iau_constlineVec.at(entry).decLow > dec1875)
×
2862
                entry++;
×
2863
        while (entry<iau_constlineVec.size())
×
2864
        {
2865
                while (iau_constlineVec.at(entry).RAhigh <= RA1875)
×
2866
                        entry++;
×
2867
                while (iau_constlineVec.at(entry).RAlow >= RA1875)
×
2868
                        entry++;
×
2869
                if (iau_constlineVec.at(entry).RAhigh > RA1875)
×
2870
                        return iau_constlineVec.at(entry).constellation;
×
2871
                else
2872
                        entry++;
×
2873
        }
2874
        qDebug() << "getIAUconstellation error: Cannot determine, algorithm failed.";
×
2875
        return "(?)";
×
2876
}
2877

2878
// NELM = naked-eye limiting magnitude
2879
int StelCore::nelmToBortleScaleIndex(const float nelm)
×
2880
{
2881
        // Ref: Bortle, John E. (February 2001). "Gauging Light Pollution: The Bortle Dark-Sky Scale".
2882
        //  Sky & Telescope. Sky Publishing Corporation.
2883
        // https://skyandtelescope.org/astronomy-resources/light-pollution-and-astronomy-the-bortle-dark-sky-scale/
2884
        if(nelm < 4.0) return 9;
×
2885
        if(nelm < 4.5) return 8;
×
2886
        if(nelm < 5.0) return 7;
×
2887
        if(nelm < 5.5) return 6;
×
2888
        if(nelm < 6.0) return 5;
×
2889
        if(nelm < 6.5) return 4;
×
2890
        if(nelm < 7.0) return 3;
×
2891
        if(nelm < 7.5) return 2;
×
2892
        return 1;
×
2893
}
2894

2895
float StelCore::bortleScaleIndexToNELM(const int index)
182✔
2896
{
2897
        // This is kind of inverse of nelmToBortleScaleIndex(), where the "representative NELM" is chosen to be
2898
        // the middle of the interval of the NELM values for the inner indices (2-8), and the same distance from
2899
        // the boundary for outer indices (1 and 9).
2900
        switch(index)
182✔
2901
        {
2902
        case 1: return 7.75;
×
2903
        case 2: return 7.25;
14✔
2904
        case 3: return 6.75;
×
2905
        case 4: return 6.25;
×
2906
        case 5: return 5.75;
×
2907
        case 6: return 5.25;
28✔
2908
        case 7: return 4.75;
70✔
2909
        case 8: return 4.25;
×
2910
        case 9: return 3.75;
70✔
2911
        default:
×
2912
                        qWarning().nospace() << "Bortle scale index " << index << " out of range";
×
2913
                        return 0; // Let the problem be visible
×
2914
        }
2915
}
2916

2917
float StelCore::luminanceToNELM(const float luminance)
×
2918
{
2919
        // Ref: Schaefer, B. E.. "Telescopic limiting magnitudes". Astronomical Society of the Pacific,
2920
        //  Publications (ISSN 0004-6280), vol. 102, Feb. 1990, p. 212-229.
2921
        // http://adsbit.harvard.edu/cgi-bin/nph-iarticle_query?bibcode=1990PASP..102..212S
2922
        //
2923
        // Using formula (18), assuming observer's acuity Fₛ=1 (as suggested in the text as "typical observer"),
2924
        // absorption term kᵥ=0.3 (as suggested for "typical weather"), coefficient for Bₛ is adjusted to take
2925
        // the value in cd/m².
2926
        //
2927
        return 8.32f - 2.17147240951626f*std::log(1 + 88.5588612190873f*std::sqrt(luminance));
×
2928
}
2929

2930
float StelCore::nelmToLuminance(const float nelm)
182✔
2931
{
2932
        // This is just the inverse of luminanceToNELM()
2933
        const auto toSquare = std::exp(3.8315015947420905f-0.46051701859880895f*nelm) - 1;
182✔
2934
        return toSquare*toSquare*0.0001275075653676456f;
182✔
2935
}
2936

2937
Vec3d StelCore::getMouseJ2000Pos() const
×
2938
{
2939
        const StelProjectorP prj = getProjection(StelCore::FrameJ2000, StelCore::RefractionAuto);
×
2940
        float ppx = static_cast<float>(getCurrentStelProjectorParams().devicePixelsPerPixel);
×
2941

2942
        QPoint p = StelMainView::getInstance().getMousePos(); // get screen coordinates of mouse cursor
×
2943
        Vec3d mousePosition;
×
2944
        const float wh = prj->getViewportWidth()*0.5f; // get half of width of the screen
×
2945
        const float hh = prj->getViewportHeight()*0.5f; // get half of height of the screen
×
2946
        const float mx = p.x()*ppx-wh; // point 0 in center of the screen, axis X directed to right
×
2947
        const float my = p.y()*ppx-hh; // point 0 in center of the screen, axis Y directed to bottom
×
2948
        // calculate position of mouse cursor via position of center of the screen (and invert axis Y)
2949
        // If coordinates are invalid, don't draw them.
2950
        bool coordsValid = prj->unProject(static_cast<double>(prj->getViewportPosX()+wh+mx), static_cast<double>(prj->getViewportPosY()+hh+1-my), mousePosition);
×
2951
        if (coordsValid)
×
2952
        { // Nick Fedoseev patch
2953
                Vec3d win;
×
2954
                prj->project(mousePosition,win);
×
2955
                float dx = prj->getViewportPosX()+wh+mx - static_cast<float>(win.v[0]);
×
2956
                float dy = prj->getViewportPosY()+hh+1-my - static_cast<float>(win.v[1]);
×
2957
                prj->unProject(static_cast<double>(prj->getViewportPosX()+wh+mx+dx), static_cast<double>(prj->getViewportPosY()+hh+1-my+dy), mousePosition);
×
2958
        }
2959
//        if (getUseAberration() && getCurrentPlanet())
2960
//        {
2961
//                Vec3d vel=getCurrentPlanet()->getHeliocentricEclipticVelocity();
2962
//                vel=StelCore::matVsop87ToJ2000*vel * getAberrationFactor()*(AU/(86400.0*SPEED_OF_LIGHT));
2963
//                mousePosition-=vel;
2964
//                mousePosition.normalize();
2965
//        }
2966
        return mousePosition;
×
2967
}
×
2968

2969
QByteArray StelCore::getAberrationShader() const
×
2970
{
2971
        return 1+R"(
×
2972
uniform vec3 STELCORE_currentPlanetHeliocentricEclipticVelocity;
2973
// objectDir points to the object as viewed from its comoving frame.
2974
// Return value represents the apparent direction to this object from a frame
2975
// that moves with respect to the object at slightly relativistic speeds (v<0.1c).
2976
// Relative error in aberration angle is about 0.5v/c.
2977
vec3 applyAberrationToObject(vec3 objectDir)
2978
{
2979
        vec3 velocity = STELCORE_currentPlanetHeliocentricEclipticVelocity;
2980
        return normalize(objectDir + velocity);
2981
}
2982
// viewDir is the direction where the object appears to be when viewed from a
2983
// frame that moves with respect to it at slightly relativistic speeds (v<0.1c).
2984
// Return value represents the direction to the object as viewed from its comoving frame.
2985
// Relative error in aberration angle is about 0.5v/c.
2986
vec3 applyAberrationToViewDir(vec3 viewDir)
2987
{
2988
        vec3 velocity = STELCORE_currentPlanetHeliocentricEclipticVelocity;
2989
        return normalize(viewDir - velocity);
2990
}
2991
)";
2992
}
2993

2994
void StelCore::setAberrationUniforms(QOpenGLShaderProgram& program) const
×
2995
{
2996
        Vec3d velocity;
×
2997
        if(getUseAberration())
×
2998
        {
2999
                const auto p = getCurrentPlanet();
×
3000
                const auto hev = p->getHeliocentricEclipticVelocity();
×
3001
                velocity = StelCore::matVsop87ToJ2000 * hev;
×
3002
                velocity *= getAberrationFactor() * (AU/(86400.0*SPEED_OF_LIGHT));
×
3003
        }
×
3004
        else
3005
        {
3006
                velocity = Vec3d(0,0,0);
×
3007
        }
3008
        program.setUniformValue("STELCORE_currentPlanetHeliocentricEclipticVelocity", velocity.toQVector());
×
3009
}
×
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