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

Stellarium / stellarium / 15670918640

16 Jun 2025 02:08AM UTC coverage: 11.775% (-0.2%) from 11.931%
15670918640

push

github

alex-w
Updated data

14700 of 124846 relevant lines covered (11.77%)

18324.52 hits per line

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

62.73
/src/core/StelUtils.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2002 Fabien Chereau
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 "StelUtils.hpp"
21
#include "VecMath.hpp"
22
#include "StelLocaleMgr.hpp"
23
#include <QBuffer>
24
#include <QString>
25
#include <QStringList>
26
#include <QTextStream>
27
#include <QFile>
28
#include <QDebug>
29
#include <QLocale>
30
#include <QRegularExpression>
31
#include <QProcess>
32
#include <QSysInfo>
33
#include <QJsonValue>
34
#include <cmath> // std::fmod
35
#include <limits>
36
#include <zlib.h>
37

38
#ifdef CYGWIN
39
  #include <malloc.h>
40
#endif
41

42
#if defined Q_OS_FREEBSD || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HAIKU || defined Q_OS_SOLARIS
43
  #include <sys/utsname.h>
44
#endif
45

46
namespace StelUtils
47
{
48
//! Return the full name of stellarium, e.g. "Stellarium 23.1"
49
QString getApplicationName()
1✔
50
{
51
        return QString("Stellarium %1").arg(STELLARIUM_BUIDING_VERSION); // see lines 158-188 in CMakeLists.txt
1✔
52
}
53

54
//! Return the version of stellarium, e.g. "23.1.0"
55
QString getApplicationVersion()
1✔
56
{
57
#ifdef GIT_REVISION
58
        return QString("%1-%2 [%3]").arg(PACKAGE_VERSION, GIT_REVISION, GIT_BRANCH);
1✔
59
#else
60
        return QString(PACKAGE_VERSION);
61
#endif
62
}
63

64
//! Return the public version of stellarium, e.g. "23.1"
65
QString getApplicationPublicVersion()
2✔
66
{
67
        return QString(STELLARIUM_PUBLIC_VERSION);
2✔
68
}
69

70
//! Return the series of stellarium, e.g. "23.0"
71
QString getApplicationSeries()
1✔
72
{
73
        return QString(STELLARIUM_SERIES);
1✔
74
}
75

76
QString getUserAgentString()
1✔
77
{
78
        // Set user agent as "Stellarium/$version$ ($operating system$; $CPU architecture$)"
79
        return QString("Stellarium/%1 (%2; %3)").arg(StelUtils::getApplicationPublicVersion(), StelUtils::getOperatingSystemInfo(), QSysInfo::currentCpuArchitecture());
1✔
80
}
81

82
QString getOperatingSystemInfo()
2✔
83
{
84
        QString OS = QSysInfo::prettyProductName();
2✔
85

86
        #if defined Q_OS_FREEBSD || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_SOLARIS
87
        struct utsname buff;
88
        if (uname(&buff) != -1)
89
                OS = QString("%1 %2").arg(buff.sysname, buff.release);
90
        #endif
91

92
        #ifdef Q_OS_HAIKU
93
        struct utsname buff;
94
        if (uname(&buff) != -1)
95
        {
96
                QString revision = QString("%1").arg(buff.version).split(" ").first();
97
                OS = QString("%1 R%2 (%3)").arg(buff.sysname, buff.release, revision);
98
        }
99
        #endif
100

101
        if (OS.isEmpty() || OS==QStringLiteral("unknown"))
4✔
102
                OS = "Unknown operating system";
×
103

104
        return OS;
2✔
105
}
×
106

107
double hmsStrToHours(const QString& s)
15✔
108
{
109
        static const QRegularExpression reg("(\\d+)h(\\d+)m(\\d+)s");
15✔
110
        QRegularExpressionMatch match=reg.match(s);
15✔
111
        if (!match.hasMatch())
15✔
112
                return 0.;
1✔
113
        uint hrs = match.captured(1).toUInt();
14✔
114
        uint min = match.captured(2).toUInt();
14✔
115
        int sec  = match.captured(3).toInt();
14✔
116

117
        return hmsToHours(hrs, min, sec);
14✔
118
}
15✔
119

120
/*************************************************************************
121
 Convert a real duration in days to DHMS formatted string
122
*************************************************************************/
123
QString daysFloatToDHMS(float days)
×
124
{
125
        float remain = days;
×
126

127
        int d = static_cast<int> (remain); remain -= d;
×
128
        remain *= 24.0f;
×
129
        int h = static_cast<int> (remain); remain -= h;
×
130
        remain *= 60.0f;
×
131
        int m = static_cast<int> (remain); remain -= m; 
×
132
        remain *= 60.0f;
×
133

134
        auto r = QString("%1%2 %3%4 %5%6 %7%8")
×
135
        .arg(d)                .arg(qc_("d", "duration"))
×
136
        .arg(h)                .arg(qc_("h", "duration"))
×
137
        .arg(m)                .arg(qc_("m", "duration"))
×
138
        .arg(remain)        .arg(qc_("s", "duration"));
×
139

140
        return r;
×
141
}
142

143

144
/*************************************************************************
145
 Convert an angle in radian to hms
146
*************************************************************************/
147
void radToHms(double angle, unsigned int& h, unsigned int& m, double& s)
15✔
148
{
149
        angle = std::fmod(angle,2.0*M_PI);
15✔
150
        if (angle < 0.0) angle += 2.0*M_PI; // range: [0..2.0*M_PI)
15✔
151

152
        angle *= 12./M_PI;
15✔
153

154
        h = static_cast<unsigned int>(angle);
15✔
155
        m = static_cast<unsigned int>((angle-h)*60);
15✔
156
        s = qAbs((angle-h)*3600.-60.*m);
15✔
157
}
15✔
158

159
/*************************************************************************
160
 Convert an angle in radian to dms
161
*************************************************************************/
162
void radToDms(double angle, bool& sign, unsigned int& d, unsigned int& m, double& s)
218✔
163
{
164
        angle = std::fmod(angle,2.0*M_PI);
218✔
165
        sign=true;
218✔
166
        if (angle<0)
218✔
167
        {
168
                angle *= -1;
56✔
169
                sign = false;
56✔
170
        }
171
        angle *= M_180_PI;
218✔
172

173
        d = static_cast<unsigned int>(angle);
218✔
174
        m = static_cast<unsigned int>((angle - d)*60);
218✔
175
        s = (angle-d)*3600-60*m;
218✔
176
        // workaround for rounding numbers        
177
        if (s>59.9)
218✔
178
        {
179
                s = 0.;
33✔
180
                m += 1;
33✔
181
        }
182
        if (m==60)
218✔
183
        {
184
                m = 0;
33✔
185
                d += 1;
33✔
186
        }        
187
}
218✔
188

189
QString radToDecDegStr(const double angle, const int precision, const bool useD, const bool positive)
13✔
190
{
191
        const QChar degsign = (useD ? 'd' : QChar(0x00B0));
13✔
192
        double deg = (positive ? fmodpos(angle, 2.0*M_PI) : std::fmod(angle, 2.0*M_PI)) * M_180_PI;
13✔
193

194
        return QString("%1%2").arg(QString::number(deg, 'f', precision), degsign);
13✔
195
}
196

197
/*************************************************************************
198
 Convert an angle in radian to a hms formatted string
199
 If the minute and second part are null are too small, don't print them
200
*************************************************************************/
201
QString radToHmsStrAdapt(const double angle)
4✔
202
{
203
        unsigned int h,m;
204
        double s;
205
        QString buf;
4✔
206
        QTextStream ts(&buf);
4✔
207
        StelUtils::radToHms(angle+0.005*M_PI/12/(60*60), h, m, s);
4✔
208
        ts << h << 'h';
4✔
209
        if (std::fabs(s*100-static_cast<int>(s)*100)>=1)
4✔
210
        {
211
                ts << m << 'm';
×
212
                ts.setRealNumberNotation(QTextStream::FixedNotation);
×
213
                ts.setPadChar('0');
×
214
                ts.setFieldWidth(4);
×
215
                ts.setRealNumberPrecision(1);
×
216
                ts << s;
×
217
                ts.reset();
×
218
                ts << 's';
×
219
        }
220
        else if (static_cast<int>(s)!=0)
4✔
221
        {
222
                ts << m << 'm' << static_cast<int>(s) << 's';
×
223
        }
224
        else if (m!=0)
4✔
225
        {
226
                ts << m << 'm';
3✔
227
        }
228
        return buf;
8✔
229
}
4✔
230

231
/*************************************************************************
232
 Convert an angle in radian to a hms formatted string
233
 If decimal is true,  output should be like this: "  16h29m55.3s"
234
 If decimal is true,  output should be like this: "  16h20m00.4s"
235
 If decimal is false, output should be like this: "   0h26m5s"
236
*************************************************************************/
237
QString radToHmsStr(const double angle, const bool decimal)
7✔
238
{
239
        unsigned int h,m;
240
        double s;
241
        StelUtils::radToHms(angle, h, m, s);
7✔
242
        int width, precision;
243
        QString carry;
7✔
244
        if (decimal)
7✔
245
        {
246
                width=5;
3✔
247
                precision=2;
3✔
248
                carry="60.00";
3✔
249
        }
250
        else
251
        {
252
                width=4;
4✔
253
                precision=1;
4✔
254
                carry="60.0";
4✔
255
        }
256

257
        // handle carry case (when seconds are rounded up)
258
        if (QString("%1").arg(s, 0, 'f', precision) == carry)
7✔
259
        {
260
                s=0.;
2✔
261
                m+=1;
2✔
262
        }
263
        if (m==60)
7✔
264
        {
265
                m=0;
×
266
                h+=1;
×
267
        }
268
        if (h==24 && m==0 && s==0.)
7✔
269
                h=0;
×
270

271
        return QString("%1h%2m%3s").arg(h, width).arg(m, 2, 10, QChar('0')).arg(s, 3+precision, 'f', precision, QChar('0'));
14✔
272
}
7✔
273

274
/*************************************************************************
275
 Convert an angle in radian to a dms formatted string
276
 If the minute and second part are null are too small, don't print them
277
*************************************************************************/
278
QString radToDmsStrAdapt(const double angle, const bool useD)
38✔
279
{
280
        const QChar degsign = (useD ? 'd' : QChar(0x00B0));
38✔
281
        bool sign;
282
        unsigned int d,m;
283
        double s;
284
        StelUtils::radToDms(angle, sign, d, m, s);
38✔
285
        QString str;
38✔
286
        QTextStream os(&str);
38✔
287

288
        os << (sign?'+':'-') << d << degsign;
38✔
289
        if (std::fabs(s*100-static_cast<int>(s)*100)>=1)
38✔
290
        {
291
#if (QT_VERSION>=QT_VERSION_CHECK(5, 14, 0))
292
                os << m << '\'' << Qt::fixed << qSetRealNumberPrecision(2) << qSetFieldWidth(5) << qSetPadChar('0') << s << qSetFieldWidth(0) << '\"';
4✔
293
#else
294
                os << m << '\'' << fixed << qSetRealNumberPrecision(2) << qSetFieldWidth(5) << qSetPadChar('0') << s << qSetFieldWidth(0) << '\"';
295
#endif
296
        }
297
        else if (static_cast<int>(s)!=0)
34✔
298
        {
299
                os << m << '\'' << static_cast<int>(s) << '\"';
4✔
300
        }
301
        else if (m!=0)
30✔
302
        {
303
                os << m << '\'';
8✔
304
        }
305
        //qDebug() << "radToDmsStrAdapt(" << angle << ", " << useD << ") = " << str;
306
        return str;
76✔
307
}
38✔
308

309

310
/*************************************************************************
311
 Convert an angle in radian to a dms formatted string
312
*************************************************************************/
313
QString radToDmsStr(const double angle, const bool decimal, const bool useD)
76✔
314
{
315
        const int precision = decimal ? 1 : 0;
76✔
316
        return StelUtils::radToDmsPStr(angle, precision, useD);
76✔
317
}
318

319
/*************************************************************************
320
 Convert an angle in radian to a dms formatted string
321
*************************************************************************/
322
QString radToDmsPStr(const double angle, const int precision, const bool useD)
152✔
323
{
324
        const QChar degsign = (useD ? 'd' : QChar(0x00B0));
152✔
325
        bool sign;
326
        unsigned int d,m;
327
        double s;
328
        StelUtils::radToDms(angle, sign, d, m, s);
152✔
329
        QString str;
152✔
330
        QTextStream os(&str);
152✔
331
        os << (sign?'+':'-') << d << degsign;
152✔
332

333
        os << qSetFieldWidth(2) << qSetPadChar('0') << m << qSetFieldWidth(0) << '\'';
152✔
334
        int width = 2;
152✔
335
        if (precision>0)
152✔
336
                width = 3 + precision;
114✔
337
#if (QT_VERSION>=QT_VERSION_CHECK(5, 14, 0))
338
        os << qSetRealNumberPrecision(precision) << Qt::fixed << qSetFieldWidth(width) << qSetPadChar('0') << s << qSetFieldWidth(0) << '\"';
152✔
339
#else
340
        os << qSetRealNumberPrecision(precision) << fixed << qSetFieldWidth(width) << qSetPadChar('0') << s << qSetFieldWidth(0) << '\"';
341
#endif
342
        return str;
304✔
343
}
152✔
344

345
void decDegToDms(double angle, bool &sign, unsigned int &d, unsigned int &m, double &s)
70✔
346
{
347
        sign = true;
70✔
348
        if (angle<0.)
70✔
349
        {
350
                sign = false;
36✔
351
                angle *= -1;
36✔
352
        }
353

354
        d = static_cast<unsigned int>(angle);
70✔
355
        m = static_cast<unsigned int>((angle-d)*60);
70✔
356
        s = (angle-d)*3600.-60.*m;
70✔
357

358
        if (s>59.9)
70✔
359
        {
360
                s = 0.;
16✔
361
                m += 1;
16✔
362
        }
363
        if (m==60)
70✔
364
        {
365
                m = 0;
1✔
366
                d += 1;
1✔
367
        }
368
}
70✔
369

370
// Convert an angle in decimal degrees to a dms formatted string
371
QString decDegToDmsStr(const double angle)
6✔
372
{
373
        bool sign;
374
        double s;
375
        unsigned int d, m;
376
        decDegToDms(angle, sign, d, m, s);
6✔
377
        return QString("%1%2%3%4\'%5\"").arg(sign?'+':'-').arg(d).arg(QChar(0x00B0)).arg(m,2,10,QLatin1Char('0')).arg(static_cast<unsigned int>(s),2,10,QLatin1Char('0'));
6✔
378
}
379

380
// Convert latitude in decimal degrees to a dms formatted string.
381
QString decDegToLatitudeStr(const double latitude, bool dms)
12✔
382
{
383
        bool sign;
384
        double s;
385
        unsigned int d, m;
386
        decDegToDms(latitude, sign, d, m, s);
12✔
387
        // Important note: we use untranslatable designations for North and South directions,
388
        //                 because on some languages (e.g. Russian) the name of direction is
389
        //                 followed the value of latitude.
390
        // Example: N50.036 = 50.036 с.ш. (Russian; "с.ш." = "n.l." (northern latitude))
391
        if (dms)
12✔
392
                return QString("%1%2%3%4\'%5\"").arg(sign ? 'N' : 'S').arg(d).arg(QChar(0x00B0)).arg(m,2,10,QLatin1Char('0')).arg(static_cast<unsigned int>(s),2,10,QLatin1Char('0'));
6✔
393
        else
394
                return QString("%1%2%3").arg(sign ? 'N' : 'S').arg(QString::number(fabs(latitude), 'f', 4), QChar(0x00B0));
6✔
395
}
396

397
// default values as for Earth
398
QString decDegToLongitudeStr(const double longitude, bool eastPositive, bool semiSphere, bool dms)
40✔
399
{
400
        bool sign;
401
        double s, longMod = longitude;
40✔
402
        unsigned int d, m;
403
        QString positive, negative;
40✔
404
        if (eastPositive)
40✔
405
        {
406
                positive = "E";
26✔
407
                negative = "W";
26✔
408
        }
409
        else
410
        {
411
                longMod = fmodpos(360.-longitude, 360.); // avoid 360.0 for the poles!
14✔
412
                positive = "W";
14✔
413
                negative = "E";
14✔
414
        }
415
        if (semiSphere)
40✔
416
                longMod = longitude > 180. ? longitude-360. : longitude;
28✔
417
        decDegToDms(longMod, sign, d, m, s);
40✔
418
        // Important note: we use untranslatable designations for East and West directions,
419
        //                 because on some languages (e.g. Russian) the name of direction is
420
        //                 followed the value of longitude.
421
        // Example: E82.136 = 82.136 в.д. (Russian; "в.д." = "e.l." (eastern longitude))
422
        if (dms)
40✔
423
                return QString("%1%2%3%4\'%5\"").arg(sign ? positive : negative).arg(d).arg(QChar(0x00B0)).arg(m,2,10,QLatin1Char('0')).arg(static_cast<unsigned int>(s),2,10,QLatin1Char('0'));
20✔
424
        else
425
                return QString("%1%2%3").arg(sign ? positive : negative).arg(QString::number(fabs(longMod), 'f', 4), QChar(0x00B0));
20✔
426
}
40✔
427

428
// Convert a dms formatted string to an angle in radian
429
double dmsStrToRad(const QString& s)
22✔
430
{
431
        static const QRegularExpression reg("([\\+\\-])(\\d+)d(\\d+)'(\\d+)\"");
22✔
432
        QRegularExpressionMatch match=reg.match(s);
22✔
433
        if (!match.hasMatch())
22✔
434
                return 0;
2✔
435
        bool sign = (match.captured(1) == "-");
20✔
436
        int deg   = match.captured(2).toInt();
20✔
437
        uint min  = match.captured(3).toUInt();
20✔
438
        int sec   = match.captured(4).toInt();
20✔
439

440
        double rad = dmsToRad(qAbs(deg), min, sec);
20✔
441
        if (sign)
20✔
442
                rad *= -1;
5✔
443

444
        return rad;
20✔
445
}
22✔
446

447
double getDecAngle(const QString& str)
69✔
448
{
449
        static const QString reStr("([-+]?)\\s*"                         // [sign]  (1)
450
                                   "(?:"                                 // either
451
                                   "(\\d+(?:\\.\\d+)?)\\s*"              //  fract  (2)
452
                                   "([dhms°º]?)"                         //  [dhms] (3) \u00B0\u00BA
453
                                   "|"                                   // or
454
                                   "(?:(\\d+)\\s*([hHdD°º])\\s*)?"       //  [int degs]   (4) (5)
455
                                   "(?:"                                 //  either
456
                                   "(?:(\\d+)\\s*['mM]\\s*)?"            //   [int mins]  (6)
457
                                   "(\\d+(?:\\.\\d+)?)\\s*[\"sS]"        //   fract secs  (7)
458
                                   "|"                                   //  or
459
                                   "(\\d+(?:\\.\\d+)?)\\s*['mM]"         //   fract mins  (8)
460
                                   ")"                                   //  end
461
                                   ")"                                   // end
462
                                   "\\s*([NSEW]?)"                       // [point] (9)
463
                                  );
69✔
464

465
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
466
        QRegularExpression rex(QRegularExpression::anchoredPattern(reStr), QRegularExpression::CaseInsensitiveOption);
69✔
467
        QRegularExpressionMatch match=rex.match(str);
69✔
468
        if( match.hasMatch() )
69✔
469
        {
470
                QStringList caps = match.capturedTexts();
61✔
471
#else
472
        QRegExp rex(reStr, Qt::CaseInsensitive);
473
        if( rex.exactMatch(str) )
474
        {
475
                QStringList caps = rex.capturedTexts();
476
#endif
477
#if 0
478
                qDebug() << "reg exp: ";
479
                for( int i = 1; i <= rex.captureCount() ; ++i ){
480
                        qDebug() << i << "=\"" << caps.at(i) << "\" ";
481
                }
482
#endif
483
                double d = 0;
61✔
484
                double m = 0;
61✔
485
                double s = 0;
61✔
486
                ushort hd = caps.at(5).isEmpty() ? 'd' : caps.at(5).toLower().at(0).unicode();
61✔
487
                QString pointStr = caps.at(9).toUpper() + " ";
61✔
488
                if( caps.at(7) != "" )
61✔
489
                {
490
                        // [dh, degs], [m] and s entries at 4, 5, 6, 7
491
                        d = caps.at(4).toDouble();
37✔
492
                        m = caps.at(6).toDouble();
37✔
493
                        s = caps.at(7).toDouble();
37✔
494
                }
495
                else if( caps.at(8) != "" )
24✔
496
                {
497
                        // [dh, degs] and m entries at 4, 5, 8
498
                        d = caps.at(4).toDouble();
11✔
499
                        m = caps.at(8).toDouble();
11✔
500
                }
501
                else if( caps.at(2) != "" )
13✔
502
                {
503
                        // some value at 2, dh|m|s at 3
504
                        double x = caps.at(2).toDouble();
13✔
505
                        QString sS = caps.at(3) + caps.at(9);
13✔
506
                        switch( sS.length() )
13✔
507
                        {
508
                                case 0:
×
509
                                        // degrees, no point
510
                                        hd = 'd';
×
511
                                        break;
×
512
                                case 1:
8✔
513
                                        // NnSEeWw is point for degrees, "dhms°..." distinguish dhms
514
                                        if( QString("NnSEeWw").contains(sS.at(0)) )
8✔
515
                                        {
516
                                                pointStr = sS.toUpper();
4✔
517
                                                hd = 'd';
4✔
518
                                        }
519
                                        else
520
                                                hd = sS.toLower().at(0).unicode();
4✔
521
                                        break;
8✔
522
                                case 2:
5✔
523
                                        // hdms selected by 1st char, NSEW by 2nd
524
                                        hd = sS.at(0).toLower().unicode();
5✔
525
                                        pointStr = sS.right(1).toUpper();
5✔
526
                                        break;
5✔
527
                        }
528
                        switch( hd )
13✔
529
                        {
530
                                case 'h':
9✔
531
                                case 'd':
532
                                case 0x00B0:
533
                                case 0x00BA:
534
                                        d = x;
9✔
535
                                        break;
9✔
536
                                case 'm':
1✔
537
                                case '\'':
538
                                        m = x;
1✔
539
                                        break;
1✔
540
                                case 's':
3✔
541
                                case '"':
542
                                        s = x;
3✔
543
                                        break;
3✔
544
                                default:
×
545
                                        qDebug() << "internal error, hd = " << hd;
×
546
                        }
547
                }
13✔
548
                else
549
                {
550
                        qDebug() << "getDecAngle failed to parse angle string: " << str;
×
551
                        return -0.0;
×
552
                }
553

554
                // General sign handling: group 1 or overruled by point
555
                int sgn = caps.at(1) == "-" ? -1 : 1;
61✔
556
                bool isNS = false;
61✔
557
                switch( pointStr.at(0).unicode() )
61✔
558
                {
559
                        case 'N':
5✔
560
                                sgn = 1;
5✔
561
                                isNS = 1;
5✔
562
                                break;
5✔
563
                        case 'S':
7✔
564
                                sgn = -1;
7✔
565
                                isNS = 1;
7✔
566
                                break;
7✔
567
                        case 'E':
3✔
568
                                sgn = 1;
3✔
569
                                break;
3✔
570
                        case 'W':
4✔
571
                                sgn = -1;
4✔
572
                                break;
4✔
573
                        default:  // OK, there is no NSEW.
42✔
574
                                break;
42✔
575
                }
576

577
                int h2d = 1;
61✔
578
                if( hd == 'h' )
61✔
579
                {
580
                        // Sanity check - h and N/S not accepted together
581
                        if( isNS  )
8✔
582
                        {
583
                                qDebug() << "getDecAngle does not accept ...H...N/S: " << str;
1✔
584
                                return -0.0;
1✔
585
                        }
586
                        h2d = 15;
7✔
587
                }
588
                double deg = (d + (m/60) + (s/3600))*h2d*sgn;
60✔
589
                return deg * 2 * M_PI / 360.;
60✔
590
        }
61✔
591

592
        qDebug() << "getDecAngle failed to parse angle string: " << str;
8✔
593
        return -0.0;
8✔
594
}
69✔
595

596
int getBiggerPowerOfTwo(int value)
17✔
597
{
598
        int p=1;
17✔
599
        while (p<value)
66✔
600
                p<<=1;
49✔
601
        return p;
17✔
602
}
603

604
// Return the first power of two smaller than or equal to the given value
605
int getSmallerPowerOfTwo(const int value)
×
606
{
607
        if (value==0) return 1;
×
608
        const auto bigger = getBiggerPowerOfTwo(value);
×
609
        // Leave exact power of two unchanged
610
        if (bigger == value) return value;
×
611

612
        return bigger >> 1;
×
613
}
614

615
/*************************************************************************
616
 Convert a Qt QDateTime class to Julian Day
617
*************************************************************************/
618

619
QDateTime jdToQDateTime(const double& jd, const Qt::TimeSpec timeSpec)
6✔
620
{
621
        Q_ASSERT((timeSpec==Qt::UTC) || (timeSpec==Qt::LocalTime));
6✔
622
        int year, month, day, hour, minute, second, millis;
623
        getDateTimeFromJulianDay(jd, &year, &month, &day, &hour, &minute, &second, &millis);
6✔
624
        QDateTime result(QDate(year, month, day), QTime(hour, minute, second, millis), timeSpec);
6✔
625
        if (!result.isValid())
6✔
626
                qCritical() << "StelUtils::jdToQDateTime(): Invalid QDateTime:" << result;
×
627
        Q_ASSERT(result.isValid());
6✔
628
        return result;
12✔
629
}
×
630

631
void getDateFromJulianDay(const double jd, int *yy, int *mm, int *dd)
8,756,634✔
632
{
633
        /*
634
         * This algorithm is taken from
635
         * "Numerical Recipes in C, 2nd Ed." (1992), pp. 14-15
636
         * and converted to integer math.
637
         * The electronic version of the book is freely available
638
         * at http://www.nr.com/ , under "Obsolete Versions - Older
639
         * book and code versions".
640
         */
641

642
        static const long JD_GREG_CAL = 2299161;
643
        static const int JB_MAX_WITHOUT_OVERFLOW = 107374182;
644
        const long julian = static_cast<long>(std::floor(jd + 0.5));
8,756,634✔
645

646
        long ta, tc;
647

648
        if (julian >= JD_GREG_CAL)
8,756,634✔
649
        {
650
                long jalpha = (4*(julian - 1867216) - 1) / 146097;
8,741,951✔
651
                ta = julian + 1 + jalpha - jalpha / 4;
8,741,951✔
652
        }
653
        else if (julian < 0)
14,683✔
654
        {
655
                ta = julian + 36525 * (1 - julian / 36525);
9,032✔
656
        }
657
        else
658
        {
659
                ta = julian;
5,651✔
660
        }
661

662
        long tb = ta + 1524;
8,756,634✔
663
        if (tb <= JB_MAX_WITHOUT_OVERFLOW)
8,756,634✔
664
        {
665
                tc = (tb*20 - 2442) / 7305;
8,754,632✔
666
        }
667
        else
668
        {
669
                tc = static_cast<long>((static_cast<unsigned long long>(tb)*20 - 2442) / 7305);
2,002✔
670
        }
671
        long td = 365 * tc + tc/4;
8,756,634✔
672
        long te = ((tb - td) * 10000)/306001;
8,756,634✔
673

674
        *dd = tb - td - (306001 * te) / 10000;
8,756,634✔
675

676
        *mm = te - 1;
8,756,634✔
677
        if (*mm > 12)
8,756,634✔
678
        {
679
                *mm -= 12;
1,421,748✔
680
        }
681
        *yy = tc - 4715;
8,756,634✔
682
        if (*mm > 2)
8,756,634✔
683
        {
684
                --(*yy);
7,334,886✔
685
        }
686
        if (julian < 0)
8,756,634✔
687
        {
688
                *yy -= 100 * (1 - julian / 36525);
9,032✔
689
        }
690
}
8,756,634✔
691

692
void getTimeFromJulianDay(const double julianDay, int *hour, int *minute, int *second, int *millis, bool *wrapDay)
52✔
693
{
694
        double frac = julianDay - (std::floor(julianDay));
52✔
695
        double secs = frac * 24.0 * 60.0 * 60.0 + 0.0001; // add constant to fix floating-point truncation error
52✔
696
        int s = int(std::floor(secs));
52✔
697

698
        *hour = ((s / (60 * 60))+12);
52✔
699
        if (*hour>=24)
52✔
700
        {
701
                *hour-=24;
4✔
702
                if (*hour>=24)
4✔
703
                        qCritical() << "This is wrapping more than a day!";
×
704
                Q_ASSERT(*hour < 24);
4✔
705
                if (wrapDay) *wrapDay=true;
4✔
706
        }
707
        else
708
                if (wrapDay) *wrapDay=false;
48✔
709
        *minute = (s/(60))%60;
52✔
710
        *second = s % 60;
52✔
711
        if(millis)
52✔
712
        {
713
                *millis = int(std::floor((secs - std::floor(secs)) * 1000.0));
13✔
714
        }
715
        //qDebug() << "getTimeFromJulianDay:" << QString::number(frac, 'f', 18) << QString::number(secs, 'f', 5) << "~" << s << *hour << *minute << *second;
716
}
52✔
717

718
void getDateTimeFromJulianDay(const double julianDay, int *year, int *month, int *day, int *hour, int *minute, int *second, int *millis)
46✔
719
{
720
        bool wrapDay;
721
        getTimeFromJulianDay(julianDay, hour, minute, second, millis, &wrapDay);
46✔
722
        if (wrapDay)
46✔
723
                getDateFromJulianDay(julianDay+0.1, year, month, day);
3✔
724
        else
725
                getDateFromJulianDay(julianDay, year, month, day);
43✔
726
}
46✔
727

728
double getHoursFromJulianDay(const double julianDay)
6✔
729
{
730
        int hr, min, sec, millis;
731
        getTimeFromJulianDay(julianDay, &hr, &min, &sec, &millis);
6✔
732
        return static_cast<double>(hr)+static_cast<double>(min)/60.+static_cast<double>(sec + millis/1000.)/3600.;
6✔
733
}
734

735

736
QString julianDayToISO8601String(const double jd, bool addMS)
40✔
737
{
738
        int year, month, day, hour, minute, second, millis=0;
40✔
739
        getDateTimeFromJulianDay(jd, &year, &month, &day, &hour, &minute, &second, addMS ? &millis : Q_NULLPTR );
40✔
740

741
        QString res = QString("%1-%2-%3T%4:%5:%6")
40✔
742
                                 .arg((year >= 0 ? year : -1* year),4,10,QLatin1Char('0'))
80✔
743
                                 .arg(month,2,10,QLatin1Char('0'))
80✔
744
                                 .arg(day,2,10,QLatin1Char('0'))
80✔
745
                                 .arg(hour,2,10,QLatin1Char('0'))
80✔
746
                                 .arg(minute,2,10,QLatin1Char('0'))
80✔
747
                                 .arg(second,2,10,QLatin1Char('0'));
40✔
748

749
        if(addMS)
40✔
750
        {
751
                res.append(QString(".%1").arg(millis,3,10,QLatin1Char('0')));
1✔
752
        }
753
        if (year < 0)
40✔
754
        {
755
                res.prepend("-");
25✔
756
        }
757
        return res;
80✔
758
}
×
759

760
// Format the date per the fmt.
761
QString localeDateString(const int year, const int month, const int day, const int dayOfWeek, const QString &fmt)
6✔
762
{
763
        /* we have to handle the year zero, and the years before qdatetime can represent. */
764
        const QLatin1Char quote('\'');
6✔
765
        QString out;
6✔
766
        int quotestartedat = -1;
6✔
767

768
        for (int i = 0; i < fmt.length(); i++)
36✔
769
        {
770
                if (fmt.at(i) == quote)
30✔
771
                {
772
                        if (quotestartedat >= 0)
×
773
                        {
774
                                if ((quotestartedat+1) == i)
×
775
                                {
776
                                        out += quote;
×
777
                                        quotestartedat = -1;
×
778
                                }
779
                                else
780
                                {
781
                                        quotestartedat = -1;
×
782
                                }
783
                        }
784
                        else
785
                        {
786
                                quotestartedat = i;
×
787
                        }
788
                }
789
                else if (quotestartedat > 0)
30✔
790
                {
791
                        out += fmt.at(i);
×
792
                }
793
                else if (fmt.at(i) == QLatin1Char('d') ||
54✔
794
                                 fmt.at(i) == QLatin1Char('M') ||
54✔
795
                                 fmt.at(i) == QLatin1Char('y'))
48✔
796
                {
797
                        int j = i+1;
18✔
798
                        while ((j < fmt.length()) && (fmt.at(j) == fmt.at(i)) && (4 >= (j-i+1)))
36✔
799
                        {
800
                                j++;
18✔
801
                        }
802

803
                        QString frag = fmt.mid(i,(j-i));
18✔
804

805
                        if (frag == "d")
18✔
806
                        {
807
                                out += QString("%1").arg(day);
×
808
                        }
809
                        else if (frag == "dd")
18✔
810
                        {
811
                                out += QString("%1").arg(day, 2, 10, QLatin1Char('0'));
6✔
812
                        }
813
                        else if (frag == "ddd")
12✔
814
                        {
815
                                out += StelLocaleMgr::shortDayName(dayOfWeek+1);
×
816
                        }
817
                        else if (frag == "dddd")
12✔
818
                        {
819
                                out += StelLocaleMgr::longDayName(dayOfWeek+1);
×
820
                        }
821
                        else if (frag == "M")
12✔
822
                        {
823
                                out += QString("%1").arg(month);
×
824
                        }
825
                        else if (frag == "MM")
12✔
826
                        {
827
                                out += QString("%1").arg(month, 2, 10, QLatin1Char('0'));
6✔
828
                        }
829
                        else if (frag == "MMM")
6✔
830
                        {
831
                                out += StelLocaleMgr::shortMonthName(month);
×
832
                        }
833
                        else if (frag == "MMMM")
6✔
834
                        {
835
                                out += StelLocaleMgr::longMonthName(month);
×
836
                        }
837
                        else if (frag == "y")
6✔
838
                        {
839
                                out += frag;
×
840
                        }
841
                        else if (frag == "yy")
6✔
842
                        {
843
                                int dispyear = year % 100;
6✔
844
                                out += QString("%1").arg(dispyear,2,10,QLatin1Char('0'));
6✔
845
                        }
846
                        else if (frag == "yyy")
×
847
                        {
848
                                // assume greedy: understand yy before y.
849
                                int dispyear = year % 100;
×
850
                                out += QString("%1").arg(dispyear,2,10,QLatin1Char('0'));
×
851
                                out += QLatin1Char('y');
×
852
                        }
853
                        else if (frag == "yyyy")
×
854
                        {
855
                                int dispyear = abs(year);
×
856
                                if (year <  0)
×
857
                                {
858
                                        out += QLatin1Char('-');
×
859
                                }
860
                                out += QString("%1").arg(dispyear,4,10,QLatin1Char('0'));
×
861
                        }
862

863
                        i = j-1;
18✔
864
                }
18✔
865
                else
866
                {
867
                        out += fmt.at(i);
12✔
868
                }
869
        }
870

871
        return out;
12✔
872
}
×
873

874
//! try to get a reasonable locale date string from the system, trying to work around
875
//! limitations of qdatetime for large dates in the past.  see QDateTime::toString().
876
QString localeDateString(const int year, const int month, const int day, const int dayOfWeek)
10✔
877
{
878
        // try the QDateTime first
879
        QDate test(year, month, day);
10✔
880

881
        // try to avoid QDate's non-astronomical time here, don't do BCE or year 0.
882
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
883
        if (year > 0 && test.isValid() && !test.toString(QLocale().dateFormat(QLocale::ShortFormat)).isEmpty())
10✔
884
        {
885
                return test.toString(QLocale().dateFormat(QLocale::ShortFormat));
8✔
886
        }
887
#else
888
        if (year > 0 && test.isValid() && !test.toString(Qt::DefaultLocaleShortDate).isEmpty())
889
        {
890
                return test.toString(Qt::DefaultLocaleShortDate);
891
        }
892
#endif
893
        else
894
        {
895
                return localeDateString(year,month,day,dayOfWeek,QLocale().dateFormat(QLocale::ShortFormat));
6✔
896
        }
897
}
898

899
QString localeDiscoveryDateString(const QString& discovery)
×
900
{
901
        QString ddate = discovery; // YYYY
×
902
        QStringList date = discovery.split("-");
×
903
        if (date.count()==3) // YYYY-MM-DD
×
904
                ddate = QString("%1 %2 %3").arg(QString::number(date.at(2).toInt()), StelLocaleMgr::longGenitiveMonthName(date.at(1).toInt()), date.at(0));
×
905
        if (date.count()==2) // YYYY-MM
×
906
                ddate = QString("%1 %2").arg(StelLocaleMgr::longMonthName(date.at(1).toInt()), date.at(0));
×
907

908
        return ddate;
×
909
}
×
910

911
int getDayOfWeek(int year, int month, int day)
6✔
912
{
913
        double JD;
914
        getJDFromDate(&JD, year, month, day, 0, 0, 0);
6✔
915
        return getDayOfWeek(JD);
12✔
916
}
917

918
//! use QDateTime to get a Julian Date from the system's current time.
919
//! this is an acceptable use of QDateTime because the system's current
920
//! time is more than likely always going to be expressible by QDateTime.
921
double getJDFromSystem()
×
922
{
923
        return qDateTimeToJd(QDateTime::currentDateTimeUtc());
×
924
}
925

926
double getJDFromBesselianEpoch(const double epoch)
7✔
927
{
928
        return 2400000.5 + (15019.81352 + (epoch - 1900.0) * 365.242198781);
7✔
929
}
930

931
double getJDFromJulianEpoch(const double epoch)
×
932
{
933
        return 2451545.0 + (epoch - 2000.0) * 365.25;
×
934
}
935

936

937
double qTimeToJDFraction(const QTime& time)
×
938
{
939
        return static_cast<double>(1./(24*60*60*1000)*QTime(0, 0, 0, 0).msecsTo(time))-0.5;
×
940
}
941

942
QTime jdFractionToQTime(const double jd)
×
943
{
944
        double decHours = std::fmod(jd+0.5, 1.0) * 24.;
×
945
        int hours =int(std::floor(decHours));
×
946
        double decMins = (decHours-hours)*60.;
×
947
        int mins = int(std::floor(decMins));
×
948
        double decSec = (decMins-mins)*60.;
×
949
        int sec = int(std::floor(decSec));
×
950
        double decMsec = (decSec-sec)*1000.;
×
951
        int ms=int(std::round(decMsec));
×
952

953
        if (ms>=1000){
×
954
                ms-=1000;
×
955
                sec+=1;
×
956
        }
957
        if (sec>=60){
×
958
                sec-=60;
×
959
                mins+=1;
×
960
        }
961
        if (mins>=60){
×
962
                mins-=60;
×
963
                hours+=1;
×
964
        }
965
        if (hours >= 24)
×
966
                qWarning() << "Hours exceed a full day!" << hours;
×
967
        hours %= 24;
×
968

969
        QTime tm=QTime(hours, mins, sec, ms);
×
970
        if (!tm.isValid())
×
971
                qWarning() << "Invalid QTime:" << hours << "/" << mins << "/" << sec << "/" << ms << "-->" << tm;
×
972
        Q_ASSERT(tm.isValid());
×
973
        return tm;
×
974
}
975

976
// UTC !
977
bool getJDFromDate(double* newjd, const int y, const int m, const int d, const int h, const int min, const float s)
2,114,157✔
978
{
979
        static const long IGREG2 = 15+31L*(10+12L*1582);
980
        double deltaTime = (h / 24.0) + (min / (24.0*60.0)) + (static_cast<double>(s) / (24.0 * 60.0 * 60.0)) - 0.5;
2,114,157✔
981
        QDate test((y <= 0 ? y-1 : y), m, d);
2,114,157✔
982
        // if QDate will oblige, do so.
983
        // added hook for Julian calendar, because it has been removed from Qt5 --AW
984
        if ( test.isValid() && y>1582)
2,114,157✔
985
        {
986
                double qdjd = static_cast<double>(test.toJulianDay());
2,099,639✔
987
                qdjd += deltaTime;
2,099,639✔
988
                *newjd = qdjd;
2,099,639✔
989
                return true;
2,099,639✔
990
        }
991
        else
992
        {
993
                /*
994
                 * Algorithm taken from "Numerical Recipes in C, 2nd Ed." (1992), pp. 11-12
995
                 */
996
                long jy, jm;
997

998
                jy = y;
14,518✔
999
                if (m > 2)
14,518✔
1000
                {
1001
                        jm = m + 1;
11,908✔
1002
                }
1003
                else
1004
                {
1005
                        --jy;
2,610✔
1006
                        jm = m + 13;
2,610✔
1007
                }
1008

1009
                long laa = 1461 * jy / 4;
14,518✔
1010
                if (jy < 0 && jy % 4)
14,518✔
1011
                {
1012
                        --laa;
10,259✔
1013
                }
1014
                long lbb = 306001 * jm / 10000;
14,518✔
1015
                long ljul = laa + lbb + d + 1720995L;
14,518✔
1016

1017
                if (d + 31L*(m + 12L * y) >= IGREG2)
14,518✔
1018
                {
1019
                        long lcc = jy/100;
41✔
1020
                        if (jy < 0 && jy % 100)
41✔
1021
                        {
1022
                                --lcc;
×
1023
                        }
1024
                        long lee = lcc/4;
41✔
1025
                        if (lcc < 0 && lcc % 4)
41✔
1026
                        {
1027
                                --lee;
×
1028
                        }
1029
                        ljul += 2 - lcc + lee;
41✔
1030
                }
1031
                double jd = static_cast<double>(ljul);
14,518✔
1032
                jd += deltaTime;
14,518✔
1033
                *newjd = jd;
14,518✔
1034
                return true;
14,518✔
1035
        }
1036
}
1037

1038
double getJDFromDate_alg2(const int y, const int m, const int d, const int h, const int min, const int s)
×
1039
{
1040
        double extra = (100.0* y) + m - 190002.5;
×
1041
        double rjd = 367.0 * y;
×
1042
        rjd -= std::floor(7.0*(y+std::floor((m+9.0)/12.0))/4.0);
×
1043
        rjd += std::floor(275.0*m/9.0) ;
×
1044
        rjd += d;
×
1045
        rjd += (h + (min + s/60.0)/60.)/24.0;
×
1046
        rjd += 1721013.5;
×
1047
        rjd -= 0.5*extra/std::fabs(extra);
×
1048
        rjd += 0.5;
×
1049
        return rjd;
×
1050
}
1051

1052
int numberOfDaysInMonthInYear(const int month, const int year)
16,262✔
1053
{
1054
        switch(month)
16,262✔
1055
        {
1056
                case 1:
9,633✔
1057
                case 3:
1058
                case 5:
1059
                case 7:
1060
                case 8:
1061
                case 10:
1062
                case 12:
1063
                        return 31;
9,633✔
1064
                case 4:
5,347✔
1065
                case 6:
1066
                case 9:
1067
                case 11:
1068
                        return 30;
5,347✔
1069
                case 2:
1,277✔
1070
                        if ( year > 1582 )
1,277✔
1071
                        {
1072
                                if ( year % 4 == 0 )
151✔
1073
                                {
1074
                                        if ( year % 100 == 0 )
35✔
1075
                                        {
1076
                                                return ( year % 400 == 0 ? 29 : 28 );
2✔
1077
                                        }
1078
                                        else
1079
                                        {
1080
                                                return 29;
33✔
1081
                                        }
1082
                                }
1083
                                else
1084
                                {
1085
                                        return 28;
116✔
1086
                                }
1087
                        }
1088
                        else
1089
                        {
1090
                                return ( year % 4 == 0 ? 29 : 28 );
1,126✔
1091
                        }
1092
                case 0:
2✔
1093
                        return numberOfDaysInMonthInYear(12, year-1);
2✔
1094
                case 13:
3✔
1095
                        return numberOfDaysInMonthInYear(1, year+1);
3✔
1096
                default:
×
1097
                        break;
×
1098
        }
1099

1100
        return 0;
×
1101
}
1102

1103
// return true if year is a leap year. Observes 1582 switch from Julian to Gregorian Calendar.
1104
bool isLeapYear(const int year)
811✔
1105
{
1106
        if (year>1582)
811✔
1107
        {
1108
                if (year % 100 == 0)
522✔
1109
                        return (year % 400 == 0);
56✔
1110
                else
1111
                        return (year % 4 == 0);
466✔
1112
        }
1113
        else
1114
                return (year % 4 == 0); // astronomical year counting: strictly every 4th year.
289✔
1115
}
1116

1117
// Find day number for date in year.
1118
// Meeus, AA 2nd, 1998, ch.7 p.65
1119
int dayInYear(const int year, const int month, const int day)
402✔
1120
{
1121
        const int k=(isLeapYear(year) ? 1:2);
402✔
1122
        return static_cast<int>(275*month/9) - k*static_cast<int>((month+9)/12) + day -30;
402✔
1123
}
1124

1125
// Find date from day number within year and the year.
1126
// Meeus, AA 2nd, 1998, ch.7 p.66
1127
Vec3i dateFromDayYear(const int day, const int year)
4✔
1128
{
1129
        const int k=(isLeapYear(year) ? 1:2);
4✔
1130
        int month = day<32 ? 1 : static_cast<int>(9.f*(k+day)/275.f+0.98f);
4✔
1131

1132
        int monthDay = day - static_cast<int>(275.f*month/9.f) + k*static_cast<int>((month+9)/12.f) + 30;
4✔
1133
        return {year, month, monthDay};
4✔
1134
}
1135

1136
// Return a fractional year like YYYY.ddddd. For negative years, the year number is of course decrease. E.g. -500.5 occurs in -501.
1137
double yearFraction(const int year, const int month, const double day)
392✔
1138
{
1139
        double d=dayInYear(year, month, 0)+day;
392✔
1140
        double daysInYear=( isLeapYear(year) ? 366.0 : 365.0);
392✔
1141
        return year+d/daysInYear;
392✔
1142
}
1143

1144
//! given the submitted year/month/day hour:minute:second, try to
1145
//! normalize into an actual year/month/day.  values can be positive, 0,
1146
//! or negative.  start assessing from seconds to larger increments.
1147
bool changeDateTimeForRollover(int oy, int om, int od, int oh, int omin, int os,
5✔
1148
                               int* ry, int* rm, int* rd, int* rh, int* rmin, int* rs)
1149
{
1150
        bool change = false;
5✔
1151

1152
        while ( os > 59 ) {
6✔
1153
                os -= 60;
1✔
1154
                omin += 1;
1✔
1155
                change = true;
1✔
1156
        }
1157
        while ( os < 0 ) {
6✔
1158
                os += 60;
1✔
1159
                omin -= 1;
1✔
1160
                change = true;
1✔
1161
        }
1162

1163
        while (omin > 59 ) {
6✔
1164
                omin -= 60;
1✔
1165
                oh += 1;
1✔
1166
                change = true;
1✔
1167
        }
1168
        while (omin < 0 ) {
6✔
1169
                omin += 60;
1✔
1170
                oh -= 1;
1✔
1171
                change = true;
1✔
1172
        }
1173

1174
        while ( oh > 23 ) {
6✔
1175
                oh -= 24;
1✔
1176
                od += 1;
1✔
1177
                change = true;
1✔
1178
        }
1179
        while ( oh < 0 ) {
6✔
1180
                oh += 24;
1✔
1181
                od -= 1;
1✔
1182
                change = true;
1✔
1183
        }
1184

1185
        while ( od > numberOfDaysInMonthInYear(om, oy) ) {
9✔
1186
                od -= numberOfDaysInMonthInYear(om, oy);
4✔
1187
                om++;
4✔
1188
                if ( om > 12 ) {
4✔
1189
                om -= 12;
2✔
1190
                oy += 1;
2✔
1191
                }
1192
                change = true;
4✔
1193
        }
1194
        while ( od < 1 ) {
6✔
1195
                od += numberOfDaysInMonthInYear(om-1,oy);
1✔
1196
                om--;
1✔
1197
                if ( om < 1 ) {
1✔
1198
                om += 12;
1✔
1199
                oy -= 1;
1✔
1200
                }
1201
                change = true;
1✔
1202
        }
1203

1204
        while ( om > 12 ) {
5✔
1205
                om -= 12;
×
1206
                oy += 1;
×
1207
                change = true;
×
1208
        }
1209
        while ( om < 1 ) {
5✔
1210
                om += 12;
×
1211
                oy -= 1;
×
1212
                change = true;
×
1213
        }
1214

1215
        // and the julian-gregorian epoch hole: round up to the 15th
1216
        if ( oy == 1582 && om == 10 && ( od > 4 && od < 15 ) ) {
5✔
1217
                od = 15;
×
1218
                change = true;
×
1219
        }
1220

1221
        if ( change ) {
5✔
1222
                *ry = oy;
5✔
1223
                *rm = om;
5✔
1224
                *rd = od;
5✔
1225
                *rh = oh;
5✔
1226
                *rmin = omin;
5✔
1227
                *rs = os;
5✔
1228
        }
1229
        return change;
5✔
1230
}
1231

1232
void debugQVariantMap(const QVariant& m, const QString& indent, const QString& key)
×
1233
{
1234
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1235
        QMetaType t = m.metaType();
×
1236
        if (t == QMetaType(QMetaType::QVariantMap))
×
1237
#else
1238
        QVariant::Type t = m.type();
1239
        if (t == QVariant::Map)
1240
#endif
1241
        {
1242
                qDebug() << indent + key + "(map):";
×
1243
                QList<QString> keys = m.toMap().keys();
×
1244
                std::sort(keys.begin(), keys.end());
×
1245
                for (auto &k : keys)
×
1246
                {
1247
                        debugQVariantMap(m.toMap()[k], indent + "    ", k);
×
1248
                }
1249
        }
×
1250
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1251
        else if (t == QMetaType(QMetaType::QVariantList))
×
1252
#else
1253
        else if (t == QVariant::List)
1254
#endif
1255
        {
1256
                qDebug() << indent + key + "(list):";
×
1257
                const QList<QVariant> mList=m.toList();
×
1258
                for (const auto& item : mList)
×
1259
                {
1260
                        debugQVariantMap(item, indent + "    ");
×
1261
                }
1262
        }
×
1263
        else
1264
                qDebug() << indent + key + " => " + m.toString();
×
1265
}
×
1266

1267
double getJulianDayFromISO8601String(const QString& iso8601Date, bool* ok)
40✔
1268
{
1269
        int y, m, d, h, min;
1270
        float s;
1271
        *ok = getDateTimeFromISO8601String(iso8601Date, &y, &m, &d, &h, &min, &s);        
40✔
1272
        if (*ok)
40✔
1273
        {
1274
                double jd;
1275
                if (!StelUtils::getJDFromDate(&jd, y, m, d, h, min, s))
39✔
1276
                {
1277
                        *ok = false;
×
1278
                        return 0.0;
×
1279
                }
1280
                return jd;
39✔
1281
        }
1282
        return 0.0;
1✔
1283
}
1284

1285
bool getDateTimeFromISO8601String(const QString& iso8601Date, int* y, int* m, int* d, int* h, int* min, float* s)
40✔
1286
{
1287
        // Represents an ISO8601 complete date string.
1288
        static const QRegularExpression finalRe("^([+\\-]?\\d+)[:\\-](\\d\\d)[:\\-](\\d\\d)T(\\d?\\d):(\\d\\d):(\\d\\d(?:\\.\\d*)?)$");
40✔
1289
        QRegularExpressionMatch match=finalRe.match(iso8601Date);
40✔
1290
        if (match.hasMatch() && finalRe.captureCount()==6)
40✔
1291
        {
1292
                bool error = false;
39✔
1293
                bool ok;
1294
                *y = match.captured(1).toInt(&ok);
39✔
1295
                error = error || !ok;
39✔
1296
                *m = match.captured(2).toInt(&ok);
39✔
1297
                error = error || !ok;
39✔
1298
                *d = match.captured(3).toInt(&ok);
39✔
1299
                error = error || !ok;
39✔
1300
                *h = match.captured(4).toInt(&ok);
39✔
1301
                error = error || !ok;
39✔
1302
                *min = match.captured(5).toInt(&ok);
39✔
1303
                error = error || !ok;
39✔
1304
                *s = match.captured(6).toFloat(&ok);
39✔
1305
                error = error || !ok;
39✔
1306
                if (!error)
39✔
1307
                        return true;
39✔
1308
        }
1309
        return false;
1✔
1310
}
40✔
1311

1312
QString getHoursMinutesFromJulianDay(const double julianDay)
×
1313
{
1314
        int hr, min, sec, millis;
1315
        getTimeFromJulianDay(julianDay, &hr, &min, &sec, &millis);
×
1316
        int m = qRound(min + sec/60.);
×
1317
        if (m==60)
×
1318
        {
1319
                hr += 1;
×
1320
                m = 0;
×
1321
        }
1322
        if (hr>=24)
×
1323
        {
1324
                hr -= 24;
×
1325
        }
1326
        return QString("%1:%2").arg(hr, 2, 10, QChar('0')).arg(m, 2, 10, QChar('0'));
×
1327
}
1328

1329
QString hoursToHmsStr(const double hours, const bool minutesOnly, const bool colonFormat)
104✔
1330
{
1331
        int h = static_cast<int>(hours);
104✔
1332
        double minutes = (qAbs(hours)-qAbs(double(h)))*60.;
104✔
1333
        if (minutesOnly)
104✔
1334
        {
1335
                int m = qRound(minutes);
22✔
1336
                if (m==60)
22✔
1337
                {
1338
                        h += 1;
6✔
1339
                        m = 0;
6✔
1340
                }
1341
                QString format=colonFormat ? "%1:%2" : "%1h%2m";
22✔
1342
                return QString(format).arg(h).arg(m, 2, 10, QChar('0'));
22✔
1343
        }
22✔
1344
        else
1345
        {
1346
                int m = static_cast<int>(minutes);
82✔
1347
                float s = static_cast<float>((((qAbs(hours)-qAbs(double(h)))*60.)-m)*60.);
82✔
1348
                if (s>59.9f)
82✔
1349
                {
1350
                        m += 1;
1✔
1351
                        s = 0.f;
1✔
1352
                }
1353
                if (m==60)
82✔
1354
                {
1355
                        h += 1;
×
1356
                        m = 0;
×
1357
                }
1358
                QString format=colonFormat ? "%1:%2:%3" : "%1h%2m%3s";
82✔
1359
                return QString(format).arg(h).arg(m, 2, 10, QChar('0')).arg(s, 4, 'f', 1, QChar('0'));
82✔
1360
        }
82✔
1361
}
1362

1363
QString hoursToHmsStr(const float hours, const bool minutesOnly, const bool colonFormat)
11✔
1364
{
1365
        return hoursToHmsStr(static_cast<double>(hours), minutesOnly, colonFormat);
11✔
1366
}
1367

1368
//! The method to splitting the text by substrings by some limit of string length
1369
QString wrapText(const QString& s, const int limit)
×
1370
{
1371
        QString result = "";
×
1372
        if (s.length()<=limit)
×
1373
                result = s;
×
1374
        else
1375
        {
1376
                QString prepare = "";
×
1377
                QStringList data = s.split(" ");
×
1378
                for (int i = 0; i<data.size(); i++)
×
1379
                {
1380
                        prepare.append(QString(" %1").arg(data.at(i)));
×
1381
                        if (prepare.length() >= limit)
×
1382
                        {
1383
                                result.append(QString("<br />%1").arg(data.at(i)));
×
1384
                                prepare = "";
×
1385
                        }
1386
                        else
1387
                                result.append(QString(" %1").arg(data.at(i)));
×
1388
                }
1389
        }
×
1390

1391
        return result;
×
1392
}
×
1393

1394

1395
/* /////////////////// DELTA T VARIANTS
1396
// For the standard epochs for many formulae, we use
1397
// J2000.0=2000-jan-1.5=2451545.0,
1398
//  1900.0=1900-jan-0.5=2415020.0
1399
//  1820.0=1820-jan-0.5=2385800.0
1400
//  1810.0=1810-jan-0.5=2382148.0
1401
//  1800.0=1800-jan-0.5=2378496.0
1402
//  1735.0=1735-jan-0.5=2354756.0
1403
//  1625.0=1625-jan-0.5=2314579.0
1404
//
1405
// Up to V0.15.1, if the requested year was outside validity range, we returned zero or some useless value.
1406
// Starting with V0.15.2 the value from the edge of the range is returned instead.
1407
*/
1408

1409
double getDeltaTwithoutCorrection(const double jDay)
×
1410
{
1411
        Q_UNUSED(jDay)
1412
        return 0.;
×
1413
}
1414

1415
// Implementation of algorithm by Espenak & Meeus (2006) and Espenak (2014) for DeltaT computation
1416
double getDeltaTByEspenakMeeus(const double jDay)
86✔
1417
{
1418
        int year, month, day;        
1419
        getDateFromJulianDay(jDay, &year, &month, &day);
86✔
1420

1421
        // Note: the method here is adapted from
1422
        // "Five Millennium Canon of Solar Eclipses" [Espenak and Meeus, 2006]
1423
        // A summary is described here:
1424
        // https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html
1425
        // And updated version:
1426
        // "Thousand Year Canon of Solar Eclipses 1501 to 2500" [Espenak, 2014]
1427
        // https://eclipsewise.com/help/deltatpoly2014.html
1428

1429
        double y = yearFraction(year, month, day);
86✔
1430

1431
        // set the default value for Delta T
1432
        double u = (y-1820)/100.;
86✔
1433
        double r = (-20 + 32 * u * u);
86✔
1434

1435
        if (y < -500)
86✔
1436
        {
1437
                // values are equal to defaults!
1438
                // u = (y-1820)/100.;
1439
                // r = (-20 + 32 * u * u);
1440
        }
1441
        else if (y < 500)
86✔
1442
        {
1443
                u = y/100;
10✔
1444
                //r = (10583.6 - 1014.41 * u + 33.78311 * std::pow(u,2) - 5.952053 * std::pow(u,3)
1445
                //       - 0.1798452 * std::pow(u,4) + 0.022174192 * std::pow(u,5) + 0.0090316521 * std::pow(u,6));
1446
                r = (((((0.0090316521*u + 0.022174192)*u - 0.1798452)*u - 5.952053)*u + 33.78311)*u -1014.41)*u +10583.6;
10✔
1447
        }
1448
        else if (y < 1600)
76✔
1449
        {
1450
                u = (y-1000)/100;
11✔
1451
                //r = (1574.2 - 556.01 * u + 71.23472 * std::pow(u,2) + 0.319781 * std::pow(u,3)
1452
                //       - 0.8503463 * std::pow(u,4) - 0.005050998 * std::pow(u,5) + 0.0083572073 * std::pow(u,6));
1453
                r = (((((0.0083572073*u - 0.005050998)*u -0.8503463)*u +0.319781)*u + 71.23472)*u -556.01)*u + 1574.2;
11✔
1454
        }
1455
        else if (y < 1700)
65✔
1456
        {
1457
                double t = y - 1600;
1✔
1458
                //r = (120 - 0.9808 * t - 0.01532 * std::pow(t,2) + std::pow(t,3) / 7129);
1459
                r = ((t/7129.0 - 0.01532)*t - 0.9808)*t +120.0;
1✔
1460
        }
1461
        else if (y < 1800)
64✔
1462
        {
1463
                double t = y - 1700;
2✔
1464
                //r = (8.83 + 0.1603 * t - 0.0059285 * std::pow(t,2) + 0.00013336 * std::pow(t,3) - std::pow(t,4) / 1174000);
1465
                r = (((-t/1174000.0 + 0.00013336)*t - 0.0059285)*t + 0.1603)*t +8.83;
2✔
1466
        }
1467
        else if (y < 1860)
62✔
1468
        {
1469
                double t = y - 1800;
2✔
1470
                //r = (13.72 - 0.332447 * t + 0.0068612 * std::pow(t,2) + 0.0041116 * std::pow(t,3) - 0.00037436 * std::pow(t,4)
1471
                //       + 0.0000121272 * std::pow(t,5) - 0.0000001699 * std::pow(t,6) + 0.000000000875 * std::pow(t,7));
1472
                r = ((((((.000000000875*t -.0000001699)*t + 0.0000121272)*t - 0.00037436)*t + 0.0041116)*t + 0.0068612)*t - 0.332447)*t +13.72;
2✔
1473
        }
1474
        else if (y < 1900)
60✔
1475
        {
1476
                double t = y - 1860;
1✔
1477
                //r = (7.62 + 0.5737 * t - 0.251754 * std::pow(t,2) + 0.01680668 * std::pow(t,3)
1478
                //        -0.0004473624 * std::pow(t,4) + std::pow(t,5) / 233174);
1479
                r = ((((t/233174.0 -0.0004473624)*t + 0.01680668)*t - 0.251754)*t + 0.5737)*t + 7.62;
1✔
1480
        }
1481
        else if (y < 1920)
59✔
1482
        {
1483
                double t = y - 1900;
2✔
1484
                //r = (-2.79 + 1.494119 * t - 0.0598939 * std::pow(t,2) + 0.0061966 * std::pow(t,3) - 0.000197 * std::pow(t,4));
1485
                r = (((-0.000197*t + 0.0061966)*t - 0.0598939)*t + 1.494119)*t -2.79;
2✔
1486
        }
1487
        else if (y < 1941)
57✔
1488
        {
1489
                double t = y - 1920;
1✔
1490
                //r = (21.20 + 0.84493*t - 0.076100 * std::pow(t,2) + 0.0020936 * std::pow(t,3));
1491
                r = ((0.0020936*t - 0.076100)*t+ 0.84493)*t +21.20;
1✔
1492
        }
1493
        else if (y < 1961)
56✔
1494
        {
1495
                double t = y - 1950;
16✔
1496
                //r = (29.07 + 0.407*t - std::pow(t,2)/233 + std::pow(t,3) / 2547);
1497
                r = ((t/2547.0 -1.0/233.0)*t + 0.407)*t +29.07;
16✔
1498
        }
1499
        else if (y < 1986)
40✔
1500
        {
1501
                double t = y - 1975;
5✔
1502
                //r = (45.45 + 1.067*t - std::pow(t,2)/260 - std::pow(t,3) / 718);
1503
                r = ((-t/718.0 -1/260.0)*t + 1.067)*t +45.45;
5✔
1504
        }
1505
        else if (y < 2005)
35✔
1506
        {
1507
                double t = y - 2000;
15✔
1508
                //r = (63.86 + 0.3345 * t - 0.060374 * std::pow(t,2) + 0.0017275 * std::pow(t,3) + 0.000651814 * std::pow(t,4) + 0.00002373599 * std::pow(t,5));
1509
                r = ((((0.00002373599*t + 0.000651814)*t + 0.0017275)*t - 0.060374)*t + 0.3345)*t +63.86;
15✔
1510
        }
1511
        else if (y < 2015)
20✔
1512
        {
1513
                double t = y - 2005;
2✔
1514
                r = 0.2930*t +64.69;
2✔
1515
        }
1516
        else if (y < 3000)
18✔
1517
        {
1518
                double t = y - 2015;
18✔
1519
                r = (0.0039755*t + 0.3645)*t +67.62;
18✔
1520
                // r = 4283.78 at year 3000
1521
        }
1522
        else if (y < 3100)
×
1523
        {
1524
                // Default value for Delta T gives r = 4435.68 at year 3000
1525
                // and r = 5222.88 at year 3100
1526
                // We introduce a simple method to patch the discontinuity
1527
                r = 4283.78+(y-3000)*9.391;
×
1528
        }
1529

1530
        return r;
86✔
1531
}
1532

1533
// Values in second for interpolation table 2015..2033.
1534
static const double IERSDeltaTTable[] = { 67.64, 68.10, 68.59, 68.97, 69.22, 69.36, 69.36, 69.29, 69.20, // observed values for 2015-2023
1535
 69.11, 69.04, 69.05, 69.14, 69.34, 69.63, 69.97, 70.32, 70.62, 70.98}; // predicted values for 2024-2033
1536
// Implementation of algorithm by Espenak & Meeus (2006, 2014) with interpolation and modified formula for 2015-2050
1537
double getDeltaTByEspenakMeeusModified(const double jDay)
×
1538
{
1539
        int year, month, day;        
1540
        getDateFromJulianDay(jDay, &year, &month, &day);
×
1541

1542
        // Note: the method here is adapted from
1543
        // "Five Millennium Canon of Solar Eclipses" [Espenak and Meeus, 2006]
1544
        // A summary is described here:
1545
        // https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html
1546
        // And updated version:
1547
        // "Thousand Year Canon of Solar Eclipses 1501 to 2500" [Espenak, 2014]
1548
        // https://eclipsewise.com/help/deltatpoly2014.html
1549

1550
        double y = yearFraction(year, month, day);
×
1551

1552
        // set the default value for Delta T
1553
        double u = (y-1820)/100.;
×
1554
        double r = (-20 + 32 * u * u);
×
1555

1556
        if (y < -500)
×
1557
        {
1558
                // values are equal to defaults!
1559
        }
1560
        else if (y < 500)
×
1561
        {
1562
                u = y/100;
×
1563
                r = (((((0.0090316521*u + 0.022174192)*u - 0.1798452)*u - 5.952053)*u + 33.78311)*u -1014.41)*u +10583.6;
×
1564
        }
1565
        else if (y < 1600)
×
1566
        {
1567
                u = (y-1000)/100;
×
1568
                r = (((((0.0083572073*u - 0.005050998)*u -0.8503463)*u +0.319781)*u + 71.23472)*u -556.01)*u + 1574.2;
×
1569
        }
1570
        else if (y < 1700)
×
1571
        {
1572
                double t = y - 1600;
×
1573
                r = ((t/7129.0 - 0.01532)*t - 0.9808)*t +120.0;
×
1574
        }
1575
        else if (y < 1800)
×
1576
        {
1577
                double t = y - 1700;
×
1578
                r = (((-t/1174000.0 + 0.00013336)*t - 0.0059285)*t + 0.1603)*t +8.83;
×
1579
        }
1580
        else if (y < 1860)
×
1581
        {
1582
                double t = y - 1800;
×
1583
                r = ((((((.000000000875*t -.0000001699)*t + 0.0000121272)*t - 0.00037436)*t + 0.0041116)*t + 0.0068612)*t - 0.332447)*t +13.72;
×
1584
        }
1585
        else if (y < 1900)
×
1586
        {
1587
                double t = y - 1860;
×
1588
                r = ((((t/233174.0 -0.0004473624)*t + 0.01680668)*t - 0.251754)*t + 0.5737)*t + 7.62;
×
1589
        }
1590
        else if (y < 1920)
×
1591
        {
1592
                double t = y - 1900;
×
1593
                r = (((-0.000197*t + 0.0061966)*t - 0.0598939)*t + 1.494119)*t -2.79;
×
1594
        }
1595
        else if (y < 1941)
×
1596
        {
1597
                double t = y - 1920;
×
1598
                r = ((0.0020936*t - 0.076100)*t+ 0.84493)*t +21.20;
×
1599
        }
1600
        else if (y < 1961)
×
1601
        {
1602
                double t = y - 1950;
×
1603
                r = ((t/2547.0 -1.0/233.0)*t + 0.407)*t +29.07;
×
1604
        }
1605
        else if (y < 1986)
×
1606
        {
1607
                double t = y - 1975;
×
1608
                r = ((-t/718.0 -1/260.0)*t + 1.067)*t +45.45;
×
1609
        }
1610
        else if (y < 2005)
×
1611
        {
1612
                double t = y - 2000;
×
1613
                r = ((((0.00002373599*t + 0.000651814)*t + 0.0017275)*t - 0.060374)*t + 0.3345)*t +63.86;
×
1614
        }
1615
        else if (y < 2015)
×
1616
        {
1617
                double t = y - 2005;
×
1618
                r = 0.2930*t +64.69;
×
1619
        }
1620
        // WB: Interpolation from IERS's DeltaT values between 2015-2023, including predicted values between 2024-2033
1621
        // Data: https://maia.usno.navy.mil/ser7/deltat.data & https://maia.usno.navy.mil/ser7/deltat.preds
1622
        else if (y < 2033)
×
1623
        {
1624
                double yeardec = yearFraction(year, month, day);
×
1625
                int pos = (year-2015);
×
1626
                r = IERSDeltaTTable[pos]+(yeardec-(pos+2015))*(IERSDeltaTTable[pos+1]-IERSDeltaTTable[pos]);
×
1627
        }
1628
        // WB: Formula to connect final predicted year and 2050
1629
        // 85 is the predicted deltaT for 2050 (Espenak)
1630
        // It looks more likely that this value is too high
1631
        // But we will follow it for now until we have a better model
1632
        // Last updated: 2023 Sep 9
1633
        else if (y < 2050)
×
1634
        {
1635
                double finalPredictedYear = 2033.0;
×
1636
                double finalPredictedDeltaT = 70.98;
×
1637
                double t = y - finalPredictedYear;
×
1638
                r = finalPredictedDeltaT + (85.-finalPredictedDeltaT) * t/(2050.-finalPredictedYear);
×
1639
        }
1640
        else if (y < 3000)
×
1641
        {
1642
                double t = y - 2015;
×
1643
                r = (0.0039755*t + 0.3645)*t +67.62;
×
1644
                // r = 4283.78 at year 3000
1645
        }
1646
        else if (y < 3100)
×
1647
        {
1648
                // Default value for Delta T gives r = 4435.68 at year 3000
1649
                // and r = 5222.88 at year 3100
1650
                // We introduce a simple method to patch the discontinuity
1651
                r = 4283.78+(y-3000)*9.391;
×
1652
        }
1653
        return r;
×
1654
}
1655

1656
// Implementation of algorithm by Schoch (1931) for DeltaT computation
1657
double getDeltaTBySchoch(const double jDay)
×
1658
{
1659
        double u=(jDay-2378496.0)/36525.0; // (1800-jan-0.5)
×
1660
        return -36.28 + 36.28*u*u;
×
1661
}
1662

1663
// Implementation of algorithm by Clemence (1948) for DeltaT computation
1664
double getDeltaTByClemence(const double jDay)
×
1665
{
1666
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
×
1667
        return +8.72 + 26.75*u + 11.22*u*u;
×
1668
}
1669

1670
// Implementation of algorithm by IAU (1952) for DeltaT computation
1671
double getDeltaTByIAU(const double jDay)
50✔
1672
{
1673
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)        
50✔
1674
        return (29.950*u +72.318)*u +24.349 + 1.82144*getMoonFluctuation(jDay)  ;
50✔
1675
}
1676

1677
// Implementation of algorithm by Astronomical Ephemeris (1960) for DeltaT computation, also used by Mucke&Meeus, Canon of Solar Eclipses, Vienna 1983
1678
double getDeltaTByAstronomicalEphemeris(const double jDay)
11✔
1679
{
1680
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
11✔
1681
        // TODO: Calculate Moon's longitude fluctuation
1682
        // Note: also Mucke&Meeus 1983 ignore b
1683
        return (29.949*u +72.3165)*u +24.349 /* + 1.821*b*/ ;
11✔
1684
}
1685

1686
// Implementation of algorithm by Tuckerman (1962, 1964) & Goldstine (1973) for DeltaT computation
1687
double getDeltaTByTuckermanGoldstine(const double jDay)
11✔
1688
{
1689
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
11✔
1690
        return (36.79*u +35.06)*u + 4.87;
11✔
1691
}
1692

1693
// Implementation of algorithm by Muller & Stephenson (1975) for DeltaT computation
1694
double getDeltaTByMullerStephenson(const double jDay)
×
1695
{
1696
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
×
1697
        return (45.78*u +120.38)*u +66.0;
×
1698
}
1699

1700
// Implementation of algorithm by Stephenson (1978) for DeltaT computation
1701
double getDeltaTByStephenson1978(const double jDay)
×
1702
{
1703
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
×
1704
        return (38.30*u +114.0)*u +20.0;
×
1705
}
1706

1707
// Implementation of algorithm by Stephenson (1997) for DeltaT computation
1708
double getDeltaTByStephenson1997(const double jDay)
8✔
1709
{
1710
        double u=(jDay-2354756.0)/36525.0; // (1735-jan-0.5)
8✔
1711
        return -20.0 + 35.0*u*u;
8✔
1712
}
1713

1714
// Implementation of algorithm by Schmadel & Zech (1979) for DeltaT computation. STRICTLY 1800...1975 ONLY!! Now delivers values for the edges.
1715
double getDeltaTBySchmadelZech1979(const double jDay)
×
1716
{
1717
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
×
1718
        u=qBound(-1.0, u, 0.76);  // Limit range to 1800...1975. Else we have crazy values which cause strange artefacts.
×
1719
        double deltaT=(((((((((((-0.089491*u -0.117389)*u + 0.185489)*u + 0.247433)*u - 0.159732)*u - 0.200097)*u + 0.075456)*u
×
1720
                        + 0.076929)*u - 0.020446)*u - 0.013867)*u + 0.003081)*u + 0.001233)*u -0.000029;
×
1721
        return deltaT * 86400.0;
×
1722
}
1723

1724
// Implementation of algorithm by Morrison & Stephenson (1982) for DeltaT computation
1725
double getDeltaTByMorrisonStephenson1982(const double jDay)
30✔
1726
{
1727
        double u=(jDay-2382148.0)/36525.0; // (1810-jan-0.5)
30✔
1728
        return -15.0+32.50*u*u;
30✔
1729
}
1730

1731
// Implementation of algorithm by Stephenson & Morrison (1984) for DeltaT computation
1732
double getDeltaTByStephensonMorrison1984(const double jDay)
17✔
1733
{
1734
        int year, month, day;        
1735
        double deltaT = 0.;
17✔
1736
        getDateFromJulianDay(jDay, &year, &month, &day);
17✔
1737

1738
        // Limited years!
1739
        year=qBound(-391, year, 1600);
17✔
1740

1741
        double u = (yearFraction(year, month, day)-1800)/100;
17✔
1742

1743
        if (-391 < year && year <= 948)
17✔
1744
                deltaT = (44.3*u +320.0)*u +1360.0;
10✔
1745
        if (948 < year && year <= 1600)
17✔
1746
                deltaT = 25.5*u*u;
7✔
1747

1748
        return deltaT;
17✔
1749
}
1750

1751
// Implementation of algorithm by Stephenson & Morrison (1995) for DeltaT computation
1752
double getDeltaTByStephensonMorrison1995(const double jDay)
24✔
1753
{
1754
        double u=(jDay-2385800.0)/36525.0; // (1820-jan-0.5)
24✔
1755
        return -20.0 + 31.0*u*u;
24✔
1756
}
1757

1758
// Implementation of algorithm by Stephenson & Houlden (1986) for DeltaT computation
1759
double getDeltaTByStephensonHoulden(const double jDay)
37✔
1760
{
1761
        int year, month, day;
1762
        double u, deltaT = 0.;
37✔
1763
        getDateFromJulianDay(jDay, &year, &month, &day);
37✔
1764

1765
        if (year <= 948)
37✔
1766
        {
1767
                //u = (year-948)/100;
1768
                u = (yearFraction(year, month, day)-948)/100;
30✔
1769
                deltaT = (46.5*u -405.0)*u +1830.0;
30✔
1770
        }
1771
        if (948 < year && year <= 1600)
37✔
1772
        {
1773
                //u = (year-1850)/100;
1774
                u = (yearFraction(year, month, day)-1850)/100;
7✔
1775
                deltaT = 22.5*u*u;
7✔
1776
        }
1777

1778
        return deltaT;
37✔
1779
        // This formula found in the cited book, page (ii), formula (1).
1780
        //double T=(jDay-2415020.0)/36525; // centuries from J1900.0
1781
        //return (36.79*T+35.06)*T+4.87;
1782
}
1783

1784
// Implementation of algorithm by Espenak (1987, 1989) for DeltaT computation
1785
double getDeltaTByEspenak(const double jDay)
×
1786
{
1787
        double u=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
×
1788
        return (64.3*u +61.0)*u +67.0;
×
1789
}
1790

1791
// Implementation of algorithm by Borkowski (1988) for DeltaT computation
1792
// This is explicitly compatible with ELP2000-85.
1793
double getDeltaTByBorkowski(const double jDay)
11✔
1794
{
1795
        double u=(jDay-2451545.0)/36525.0 + 3.75; // (2000-jan-1.5), deviation from 1625 as given in the paper.
11✔
1796
        return 40.0 + 35.0*u*u;
11✔
1797
}
1798

1799
// Implementation of algorithm by Schmadel & Zech (1988) for DeltaT computation. STRICTLY 1800...1988 ONLY!! Now delivers values for the edges.
1800
double getDeltaTBySchmadelZech1988(const double jDay)
×
1801
{
1802
        double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
×
1803
        u=qBound(-1.0, u, 0.89);  // Limit range to 1800...1988. Else we have crazy values which cause strange artefacts.
×
1804
        double deltaT = (((((((((((-0.058091*u -0.067471)*u +.145932)*u +.161416)*u -.149279)*u -.146960)*u +.079441)*u +.062971)*u -.022542)*u -.012462)*u +.003357)*u +.001148)*u-.000014;
×
1805
        return deltaT * 86400.0;
×
1806
}
1807

1808
// Implementation of algorithm by Chapront-Touzé & Chapront (1991) for DeltaT computation
1809
double getDeltaTByChaprontTouze(const double jDay)
2✔
1810
{
1811
        int year, month, day;        
1812
        double deltaT = 0.;
2✔
1813
        getDateFromJulianDay(jDay, &year, &month, &day);
2✔
1814

1815
        // Limited years!
1816
        if (year < -391 || year > 1600)
2✔
1817
                return deltaT;
2✔
1818
        //year=qBound(-391, year, 1600);
1819

1820
        double u=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
×
1821

1822
        if (-391 < year && year <= 948)
×
1823
                deltaT = (42.4*u +495.0)*u + 2177.0;
×
1824
        if (948 < year) // && year <= 1600)
×
1825
                deltaT = (23.6*u +100.0)*u + 102.0;
×
1826

1827
        return deltaT;
×
1828
}
1829

1830
// Implementation of algorithm by JPL Horizons for DeltaT computation
1831
double getDeltaTByJPLHorizons(const double jDay)
11✔
1832
{ // FIXME: It does not make sense to have zeros after 1620 in a JPL Horizons compatible implementation!
1833
        int year, month, day;
1834
        double u;
1835
        double deltaT = 0.;
11✔
1836
        getDateFromJulianDay(jDay, &year, &month, &day);
11✔
1837

1838
        // Limited years!
1839
        year=qBound(-2999, year, 1620);
11✔
1840

1841
        if (-2999 < year && year < 948)
11✔
1842
        {
1843
                u=(jDay-2385800.0)/36525.0; // (1820-jan-1.5)
5✔
1844
                deltaT = 31.0*u*u;
5✔
1845
        }
1846
        if (948 < year && year <= 1620)
11✔
1847
        {
1848
                u=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
6✔
1849
                deltaT = (22.5*u +67.5)*u + 50.6;
6✔
1850
        }
1851

1852
        return deltaT;
11✔
1853
}
1854

1855
// Implementation of algorithm by Morrison & Stephenson (2004, 2005) for DeltaT computation
1856
double getDeltaTByMorrisonStephenson2004(const double jDay)
12✔
1857
{
1858
        double u=(jDay-2385800.0)/36525.0; // (1820-jan-0.5)
12✔
1859
        return -20.0 + 32.0 * u*u;
12✔
1860
}
1861

1862
// Implementation of algorithm by Reijs (2006) for DeltaT computation
1863
double getDeltaTByReijs(const double jDay)
×
1864
{
1865
        double OffSetYear = (2385800.0 - jDay)/365.25;
×
1866

1867
        return ((1.8 * OffSetYear*OffSetYear/200 + 1443*3.76/(2*M_PI)*(std::cos(2*M_PI*OffSetYear/1443)-1))*365.25)/1000;
×
1868
}
1869

1870
// Implementation of algorithm by Chapront, Chapront-Touze & Francou (1997) & Meeus (1998) for DeltaT computation
1871
// 191 values in tenths of second for interpolation table 1620..2000, every 2nd year.
1872
static const int MeeusDeltaTTable[] = { 1210, 1120, 1030, 950, 880, 820, 770, 720, 680, 630, 600, 560, 530, 510, 480,
1873
                                        460, 440, 420, 400, 380, 350, 330, 310, 290, 260, 240, 220, 200, 180, 160, 140, 120, 110, 100,  90,  80,  70,  70,  70,  70, // before 1700
1874
                                        70,  70,  80,  80,  90,  90,  90,  90,  90, 100, 100, 100, 100, 100, 100, 100, 100, 110, 110, 110, 110, 110, 120, 120, 120, // before 1750
1875
                                        120, 130, 130, 130, 140, 140, 140, 140, 150, 150, 150, 150, 150, 160, 160, 160, 160, 160, 160, 160, 160, 150, 150, 140, 130, // before 1800
1876
                                        131, 125, 122, 120, 120, 120, 120, 120, 120, 119, 116, 110, 102,  92,  82,  71,  62,  56,  54,  53,  54,  56,  59,  62,  65, // before 1850
1877
                                        68,  71,  73,  75,  76,  77,  73,  62,  52,  27,  14, -12, -28, -38, -48, -55, -53, -56, -57, -59, -60, -63, -65, -62, -47, // before 1900
1878
                                        -28,  -1,  26,  53,  77, 104, 133, 160, 182, 202, 211, 224, 235, 238, 243, 240, 239, 239, 237, 240, 243, 253, 262, 273, 282, // before 1950
1879
                                        291, 300, 307, 314, 322, 331, 340, 350, 365, 383, 402, 422, 445, 465, 485, 505, 522, 538, 549, 558, 569, 583, 600, 616, 630, 650}; //closing: 2000
1880
double getDeltaTByChaprontMeeus(const double jDay)
73✔
1881
{
1882
        int year, month, day;
1883
        double deltaT = 0.;
73✔
1884
        getDateFromJulianDay(jDay, &year, &month, &day);
73✔
1885

1886
        //const double u19=(jDay-2415020.0)/36525.0; // (1900-jan-0.5) Only for approx form.
1887
        const double u20=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
73✔
1888

1889
        if (year<948)
73✔
1890
                deltaT=(44.1*u20 +497.0)*u20+2177.0;
10✔
1891
        else if (year<1620)
63✔
1892
                deltaT=(25.3*u20 + 102.0)*u20+102.0;
7✔
1893
        // The next terms are the short approximative formulae. But Meeus gives exact values, table, etc. for 1620..2000.
1894
        //else if (year<1900)
1895
        //        deltaT= ((((((((( 123563.95*u19 + 727058.63)*u19 + 1818961.41)*u19 + 2513807.78)*u19 + 2087298.89)*u19 + 1061660.75)*u19 +
1896
        //                     324011.78)*u19 + 56282.84)*u19 + 5218.61)*u19 + 228.95)*u19 - 2.50;
1897
        //else if (year<1997)
1898
        //        deltaT= (((((((( 58353.42*u19 -232424.66)*u19 +372919.88)*u19 - 303191.19)*u19 + 124906.15)*u19 - 18756.33)*u19 - 2637.80)*u19 + 815.20)*u19 + 87.24)*u19 - 2.44;
1899
        else if (year <2000)
56✔
1900
        {
1901
                double yeardec=yearFraction(year, month, day);
46✔
1902
                int pos=(year-1620)/2; // this is a deliberate integer division! 2->1, 3->1, 4->2, 5->2 etc.
46✔
1903
                deltaT= MeeusDeltaTTable[pos]+ (yeardec-(2*pos+1620))*0.5  *(MeeusDeltaTTable[pos+1]-MeeusDeltaTTable[pos]);
46✔
1904
                deltaT /= 10.0;
46✔
1905
        }
1906
        else if (year<2100)
10✔
1907
                deltaT=(25.3*u20 + 102.0)*u20+102.0 + 0.37*(year-2100);
1✔
1908
        else // year > 2100
1909
                deltaT=(25.3*u20 + 102.0)*u20+102.0;
9✔
1910
        return deltaT;
73✔
1911
}
1912

1913
// Implementation of algorithm by Montenbruck & Pfleger (2000) for DeltaT computation
1914
// Their implementation explicitly returns 0 for out-of-range data, so must ours!
1915
// Note: the polynomes do not form a well-behaved continuous line.
1916
// The source of their data is likely the data table from Meeus, Astr. Alg. 1991.
1917
double getDeltaTByMontenbruckPfleger(const double jDay)
22✔
1918
{
1919
        double deltaT = 0.;
22✔
1920
        const double T=(jDay-2451545.)/36525.;
22✔
1921
        double t;
1922
        if (jDay<2387627.5 || jDay >=2453736.5) // ...1825-01-01 0:00 or 2006-01-01 0:00...
22✔
1923
                deltaT=0.0;
2✔
1924
        else if (jDay < 2396758.5) // 1850-01-01 0:00
20✔
1925
        {
1926
                t=T+1.75;
×
1927
                deltaT=(( -572.3*t+413.9)*t  -80.8)*t +10.4;
×
1928
        }
1929
        else if (jDay < 2405889.5) // 1875-01-01 0:00
20✔
1930
        {
1931
                t=T+1.50;
×
1932
                deltaT=((   18.8*t-358.4)*t  +46.3)*t + 6.6;
×
1933
        }
1934
        else if (jDay < 2415020.5) // 1900-01-01 0:00
20✔
1935
        {
1936
                t=T+1.25;
×
1937
                deltaT=((  867.4*t-166.2)*t  -10.8)*t - 3.9;
×
1938
        }
1939
        else if (jDay < 2424151.5) // 1925-01-01 0:00
20✔
1940
        {
1941
                t=T+1.00;
5✔
1942
                deltaT=((-1467.4*t+327.5)*t +114.1)*t - 2.6;
5✔
1943
        }
1944
        else if (jDay < 2433282.5) // 1950-01-01 0:00
15✔
1945
        {
1946
                t=T+0.75;
5✔
1947
                deltaT=((  483.4*t - 8.2)*t  - 6.3)*t +24.2;
5✔
1948
        }
1949
        else if (jDay < 2442413.5) // 1975-01-01 0:00
10✔
1950
        {
1951
                t=T+0.50;
5✔
1952
                deltaT=((  550.7*t - 3.8)*t  +32.5)*t +29.3;
5✔
1953
        }
1954
        else if (jDay < 2451545.5) // 2000-01-01 0:00
5✔
1955
        {
1956
                t=T+0.25;
5✔
1957
                deltaT=(( 1516.7*t-570.5)*t +130.5)*t +45.3;
5✔
1958
        }
1959
        else if (jDay < 2453736.5) // 2006-01-01 0:00 [extrapolation from 2000]
×
1960
        {
1961
                t=T+0.5;
×
1962
                deltaT=(( 1516.7*t-570.5)*t +130.5)*t +45.3;
×
1963
        }
1964

1965
        return deltaT;
22✔
1966
}
1967

1968
// Implementation of algorithm by Meeus & Simons (2000) for DeltaT computation
1969
// Zero outside defined range 1620..2000!
1970
double getDeltaTByMeeusSimons(const double jDay)
27✔
1971
{
1972
        int year, month, day;
1973
        double u;        
1974
        double deltaT = 0.0;
27✔
1975
        getDateFromJulianDay(jDay, &year, &month, &day);
27✔
1976
        const double ub=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
27✔
1977

1978
        if (year<1620)
27✔
1979
                deltaT = 0.0;
1✔
1980
        else if (year < 1690)
26✔
1981
        {
1982
                u = 3.45 + ub;
×
1983
                deltaT = (((1244.0*u -454.0)*u + 50.0)*u -107.0)*u +40.3;
×
1984
        }
1985
        else if (year < 1770)
26✔
1986
        {
1987
                u = 2.70 + ub;
×
1988
                deltaT = (((70.0*u -16.0)*u -1.0)*u +11.3)*u +10.2;
×
1989
        }
1990
        else if (year < 1820)
26✔
1991
        {
1992
                u = 2.05 + ub;
×
1993
                deltaT = (((6.0*u +173.0)*u -22.0)*u -18.8)*u +14.7;
×
1994
        }
1995
        else if (year < 1870)
26✔
1996
        {
1997
                u = 1.55 + ub;
×
1998
                deltaT = (((-1654.0*u -534.0)*u +111)*u +12.7)*u +5.7;
×
1999
        }
2000
        else if (year < 1900)
26✔
2001
        {
2002
                u = 1.15 + ub;
×
2003
                deltaT = (((8234.0*u +101.0)*u +27.0)*u - 14.6)*u -5.8;
×
2004
        }
2005
        else if (year < 1940)
26✔
2006
        {
2007
                u = 0.80 + ub;
×
2008
                deltaT = (((4441.0*u + 19.0)*u -443.0)*u +67.0)*u +21.4;
×
2009
        }
2010
        else if (year < 1990)
26✔
2011
        {
2012
                u = 0.35 + ub;
16✔
2013
                deltaT = (((-1883.0*u -140.0)*u +189.0)*u +74.0)*u +36.2;
16✔
2014
        }
2015
        else if (year <= 2000)
10✔
2016
        {
2017
                u = 0.05 + ub;
9✔
2018
                deltaT = ((-5034.0*u -188.0)*u +82.0)*u +60.8;
9✔
2019
        }
2020

2021
        return deltaT;
27✔
2022
}
2023

2024
// Implementation of algorithm by Reingold & Dershowitz (Cal. Calc. 1997, 2001, 2007, 2018, Cal. Tab. 2002) for DeltaT computation.
2025
// Created as yet another multi-segment polynomial fit through the table in Meeus: Astronomical Algorithms (1991).
2026
// Note that only the Third edition (2007) adds the 1700-1799 term.
2027
// Note that only the ultimate edition (2018) adds the -500..1699 and 2006..2150 terms.
2028
// More efficient reimplementation with stricter adherence to the source.
2029
double getDeltaTByReingoldDershowitz(const double jDay)
27✔
2030
{
2031
        int year, month, day;        
2032
        getDateFromJulianDay(jDay, &year, &month, &day);
27✔
2033
        // R&D don't use a float-fraction year, but explicitly only the integer year! And R&D use a proleptic Gregorian year before 1582.
2034
        // We cannot do that, but the difference is negligible.
2035
        double deltaT=0.0; // If it returns 0, there is a bug!
27✔
2036

2037
        if ((year>= 2051) && (year <= 2150))
27✔
2038
        {
2039
                // [2051..2150]
2040
                const double x = (year-1820)/100.;
3✔
2041
                deltaT = -20 + 32*x*x + 0.5628*(2150-year);
3✔
2042
        }
3✔
2043
        else if ((year >= 1987) && (year <= 2050))
24✔
2044
        {
2045
                const int y2000 = year-2000;
6✔
2046
                if (year>=2006) // [2006..2050]
6✔
2047
                {
2048
                        deltaT = ((0.005589*y2000 + 0.32217)*y2000 + 62.92);
3✔
2049
                }
2050
                else  // [1987..2005]
2051
                {
2052
                        deltaT = (((((0.00002373599*y2000 + 0.000651814)*y2000 + 0.0017275)*y2000 - 0.060374)*y2000 + 0.3345)*y2000 + 63.86);
3✔
2053
                }
2054
        }
6✔
2055
        else if ((year >= 1800) && (year <= 1986))
18✔
2056
        {
2057
                const double c = (getFixedFromGregorian(year, 7, 1)-getFixedFromGregorian(1900, 1, 1))/36525.;
4✔
2058
                if (year >= 1900) // [1900..1986]
4✔
2059
                {
2060
                        deltaT = ((((((-0.212591*c + 0.677066)*c - 0.861938)*c + 0.553040)*c - 0.181133)*c + 0.025184)*c + 0.000297)*c - 0.00002;
1✔
2061
                }
2062
                else    // [1800..1899]
2063
                {
2064
                        deltaT = (((((((((2.043794*c + 11.636204)*c + 28.316289)*c + 38.291999)*c + 31.332267)*c + 15.845535)*c + 4.867575)*c + 0.865736)*c + 0.083563)*c + 0.003844)*c - 0.000009;
3✔
2065
                }
2066
                deltaT *= 86400.; // convert to seconds
4✔
2067
        }
4✔
2068
        else if ((year>=1700) && (year<=1799))
14✔
2069
        {
2070
                // [1700..1799]
2071
                const int y1700 = year-1700;
2✔
2072
                deltaT = (((-0.0000266484*y1700 + 0.003336121)*y1700 - 0.005092142)*y1700 + 8.118780842);
2✔
2073
        }
2✔
2074
        else if ((year>=1600) && (year<=1699))
12✔
2075
        {
2076
                // [1600..1699]
2077
                const int y1600 = year-1600;
2✔
2078
                deltaT = (((0.000140272128*y1600 - 0.01532)*y1600 - 0.9808)*y1600 + 120.);
2✔
2079
        }
2✔
2080
        else if ((year>=500) && (year<=1599))
10✔
2081
        {
2082
                // [500..1599]
2083
                const double y1000 = (year-1000)/100.;
4✔
2084
                deltaT = ((((((0.0083572073*y1000 - 0.005050998)*y1000 - 0.8503463)*y1000 + 0.319781)*y1000 + 71.23472)*y1000 - 556.01)*y1000 + 1574.2);
4✔
2085
        }
4✔
2086
        else if ((year>-500) && (year<500))
6✔
2087
        {
2088
                // (-500..500)
2089
                const double y0 = year/100.;
3✔
2090
                deltaT = ((((((0.0090316521*y0 + 0.022174192)*y0 - 0.1798452)*y0 - 5.952053)*y0 + 33.78311)*y0 - 1014.41)*y0 + 10583.6);
3✔
2091
        }
3✔
2092
        else
2093
        {
2094
                // otherwise
2095
                const double x = (year-1820)/100.;
3✔
2096
                deltaT = (-20 + 32*x*x);
3✔
2097
        }
2098

2099
        return deltaT;
27✔
2100
}
2101

2102
// Implementation of algorithm by Banjevic (2006) for DeltaT computation.
2103
double getDeltaTByBanjevic(const double jDay)
×
2104
{
2105
        int year, month, day;
2106
        getDateFromJulianDay(jDay, &year, &month, &day);
×
2107
        double u, c;
2108

2109
        // Limited years!
2110
        year=qBound(-2020, year, 1620);
×
2111

2112
        if (year<=-700)
×
2113
        {
2114
                u = (jDay-2378496.0)/36525.0; // 1800.0=1800-jan-0.5=2378496.0
×
2115
                c = 30.86;
×
2116
        }
2117
        else //  if (year>-700 && year<=1620)
2118
        {
2119
                u = (jDay-2385800.0)/36525.0; // 1820.0=1820-jan-0.5=2385800.0
×
2120
                c = 31;
×
2121
        }
2122

2123
        return c*u*u;
×
2124
}
2125

2126
// Implementation of algorithm by Islam, Sadiq & Qureshi (2008 + revisited 2013) for DeltaT computation.
2127
double getDeltaTByIslamSadiqQureshi(const double jDay)
×
2128
{
2129
        int year, month, day;
2130
        getDateFromJulianDay(jDay, &year, &month, &day);
×
2131
        double deltaT; // Return deltaT for the edge year outside valid range.
2132
        double u, ub;
2133

2134
        // Limited years: Apply border values!
2135
        //year=qBound(1620, year, 2007);
2136
        if (year<1620)
×
2137
        {
2138
                const double j1620=qDateTimeToJd(QDateTime(QDate(1620, 1, 1), QTime(0, 0, 0), Qt::UTC));
×
2139
                ub=(j1620-2454101.0)/36525.0;
×
2140
        }
2141
        else if (year>2007)
×
2142
        {
2143
                const double j2008=qDateTimeToJd(QDateTime(QDate(2008, 1, 1), QTime(0, 0, 0), Qt::UTC));
×
2144
                ub=(j2008-2454101.0)/36525.0;
×
2145
        }
2146
        else
2147
                ub=(jDay-2454101.0)/36525.0; // (2007-jan-0.5)
×
2148

2149

2150
        if (year <= 1698)
×
2151
        {
2152
                u = 3.48 + ub;
×
2153
                deltaT = (((1162.805 * u - 273.116) * u + 14.523) * u - 105.262) * u + 38.067;
×
2154
        }
2155
        else if (year <= 1806)
×
2156
        {
2157
                u = 2.545 + ub;
×
2158
                deltaT = (((-71.724 * u - 39.048) * u + 7.591) * u + 13.893) * u + 13.759;
×
2159
        }
2160
        else if (year <= 1872)
×
2161
        {
2162
                u = 1.675 + ub;
×
2163
                deltaT = (((-1612.55 * u - 157.977) * u + 161.524) * u - 3.654) * u + 5.859;
×
2164
        }
2165
        else if (year <= 1906)
×
2166
        {
2167
                u = 1.175 + ub;
×
2168
                deltaT = (((6250.501 * u + 1006.463) * u + 139.921) * u - 2.732) * u - 6.203;
×
2169
        }
2170
        else if (year <= 1953)
×
2171
        {
2172
                // revised 2013 per email
2173
                u = 0.77 + ub;
×
2174
                deltaT = (((-390.785 * u + 901.514) * u - 88.044) * u + 8.997) * u + 24.006;
×
2175
        }
2176
        else //if (year <= 2007)
2177
        {
2178
                // revised 2013 per email
2179
                u = 0.265 + ub;
×
2180
                deltaT = (((1314.759 * u - 296.018) * u - 101.898) * u + 88.659) * u + 49.997;
×
2181
        }
2182

2183
        return deltaT;
×
2184
}
2185

2186
// Implementation of polynomial approximation of time period 1620-2013 for DeltaT by M. Khalid, Mariam Sultana and Faheem Zaidi (2014).
2187
double getDeltaTByKhalidSultanaZaidi(const double jDay)
18✔
2188
{
2189
        int year, month, day;
2190
        getDateFromJulianDay(jDay, &year, &month, &day);
18✔
2191
        //double a0, a1, a2, a3, a4;
2192
        const double k[9] ={     3.670,    3.120,    2.495,     1.925,     1.525,    1.220,     0.880,     0.455,      0.115};
18✔
2193
        const double a0[9]={    76.541,   10.872,   13.480,    12.584,     6.364,   -5.058,    13.392,    30.782,     55.281};
18✔
2194
        const double a1[9]={  -253.532,  -40.744,   13.075,     1.929,    11.004,   -1.701,   128.592,    34.348,     91.248};
18✔
2195
        const double a2[9]={   695.901,  236.890,    8.635,    60.896,   407.776,  -46.403,  -279.165,    46.452,     87.202};
18✔
2196
        const double a3[9]={ -1256.982, -351.537,   -3.307, -1432.216, -4168.394, -866.171, -1282.050,  1295.550,  -3092.565};
18✔
2197
        const double a4[9]={   627.152,   36.612, -128.294,  3129.071,  7561.686, 5917.585,  4039.490, -3210.913,   8255.422};
18✔
2198
        int i;
2199
        // Limited years! Deliver border values.
2200
        year=qBound(1620, year, 2013);
18✔
2201

2202
        if (year<=1672)
18✔
2203
                i=0;
2✔
2204
        else if (year<=1729)
16✔
2205
                i=1;
2✔
2206
        else if (year<=1797)
14✔
2207
                i=2;
2✔
2208
        else if (year<=1843)
12✔
2209
                i=3;
2✔
2210
        else if (year<=1877)
10✔
2211
                i=4;
2✔
2212
        else if (year<=1904)
8✔
2213
                i=5;
2✔
2214
        else if (year<=1945)
6✔
2215
                i=6;
2✔
2216
        else if (year<=1989)
4✔
2217
                i=7;
2✔
2218
        else // if (year<=2013)
2219
                i=8;
2✔
2220

2221
        double u = k[i] + (year - 2000.)/100.; // Avoid possible wrong calculations!
18✔
2222

2223
        return (((a4[i]*u + a3[i])*u + a2[i])*u + a1[i])*u + a0[i];
18✔
2224
}
2225

2226
static const double StephensonMorrisonHohenkerk2016DeltaTtableS15[58][6]={
2227
// Table S15: The Polynomial Coefficients for DT -720.0 to 2019.0   v. 2020
2228
// Source: http://astro.ukho.gov.uk/nao/lvm/Table-S15.2020.txt
2229
//        Row         Years                  Polynomial Coefficients
2230
//          i      K_i     K_{i+1}        a_0         a_1         a_2         a_3
2231
//        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2232
/*       1 */  { -720.0,    -100.0,   20371.848,   -9999.586,     776.247,     409.160 },
2233
/*          2 */  { -100.0,     400.0,   11557.668,   -5822.270,    1303.151,    -503.433 },
2234
/*         3 */  {  400.0,    1000.0,    6535.116,   -5671.519,    -298.291,    1085.087 },
2235
/*         4 */  { 1000.0,    1150.0,    1650.393,    -753.210,     184.811,     -25.346 },
2236
/*         5 */  { 1150.0,    1300.0,    1056.647,    -459.628,     108.771,     -24.641 },
2237
/*         6 */  { 1300.0,    1500.0,     681.149,    -421.345,      61.953,     -29.414 },
2238
/*         7 */  { 1500.0,    1600.0,     292.343,    -192.841,      -6.572,      16.197 },
2239
/*         8 */  { 1600.0,    1650.0,     109.127,     -78.697,      10.505,       3.018 },
2240
/*         9 */  { 1650.0,    1720.0,      43.952,     -68.089,      38.333,      -2.127 },
2241
/*        10 */  { 1720.0,    1800.0,      12.068,       2.507,      41.731,     -37.939 },
2242
/*        11 */  { 1800.0,    1810.0,      18.367,      -3.481,      -1.126,       1.918 },
2243
/*        12 */  { 1810.0,    1820.0,      15.678,       0.021,       4.629,      -3.812 },
2244
/*        13 */  { 1820.0,    1830.0,      16.516,      -2.157,      -6.806,       3.250 },
2245
/*        14 */  { 1830.0,    1840.0,      10.804,      -6.018,       2.944,      -0.096 },
2246
/*        15 */  { 1840.0,    1850.0,       7.634,      -0.416,       2.658,      -0.539 },
2247
/*        16 */  { 1850.0,    1855.0,       9.338,       1.642,       0.261,      -0.883 },
2248
/*        17 */  { 1855.0,    1860.0,      10.357,      -0.486,      -2.389,       1.558 },
2249
/*        18 */  { 1860.0,    1865.0,       9.040,      -0.591,       2.284,      -2.477 },
2250
/*        19 */  { 1865.0,    1870.0,       8.255,      -3.456,      -5.148,       2.720 },
2251
/*        20 */  { 1870.0,    1875.0,       2.371,      -5.593,       3.011,      -0.914 },
2252
/*        21 */  { 1875.0,    1880.0,      -1.126,      -2.314,       0.269,      -0.039 },
2253
/*        22 */  { 1880.0,    1885.0,      -3.210,      -1.893,       0.152,       0.563 },
2254
/*        23 */  { 1885.0,    1890.0,      -4.388,       0.101,       1.842,      -1.438 },
2255
/*        24 */  { 1890.0,    1895.0,      -3.884,      -0.531,      -2.474,       1.871 },
2256
/*        25 */  { 1895.0,    1900.0,      -5.017,       0.134,       3.138,      -0.232 },
2257
/*        26 */  { 1900.0,    1905.0,      -1.977,       5.715,       2.443,      -1.257 },
2258
/*        27 */  { 1905.0,    1910.0,       4.923,       6.828,      -1.329,       0.720 },
2259
/*        28 */  { 1910.0,    1915.0,      11.142,       6.330,       0.831,      -0.825 },
2260
/*        29 */  { 1915.0,    1920.0,      17.479,       5.518,      -1.643,       0.262 },
2261
/*        30 */  { 1920.0,    1925.0,      21.617,       3.020,      -0.856,       0.008 },
2262
/*        31 */  { 1925.0,    1930.0,      23.789,       1.333,      -0.831,       0.127 },
2263
/*        32 */  { 1930.0,    1935.0,      24.418,       0.052,      -0.449,       0.142 },
2264
/*        33 */  { 1935.0,    1940.0,      24.164,      -0.419,      -0.022,       0.702 },
2265
/*        34 */  { 1940.0,    1945.0,      24.426,       1.645,       2.086,      -1.106 },
2266
/*        35 */  { 1945.0,    1950.0,      27.050,       2.499,      -1.232,       0.614 },
2267
/*        36 */  { 1950.0,    1953.0,      28.932,       1.127,       0.220,      -0.277 },
2268
/*        37 */  { 1953.0,    1956.0,      30.002,       0.737,      -0.610,       0.631 },
2269
/*        38 */  { 1956.0,    1959.0,      30.760,       1.409,       1.282,      -0.799 },
2270
/*        39 */  { 1959.0,    1962.0,      32.652,       1.577,      -1.115,       0.507 },
2271
/*        40 */  { 1962.0,    1965.0,      33.621,       0.868,       0.406,       0.199 },
2272
/*        41 */  { 1965.0,    1968.0,      35.093,       2.275,       1.002,      -0.414 },
2273
/*        42 */  { 1968.0,    1971.0,      37.956,       3.035,      -0.242,       0.202 },
2274
/*        43 */  { 1971.0,    1974.0,      40.951,       3.157,       0.364,      -0.229 },
2275
/*        44 */  { 1974.0,    1977.0,      44.244,       3.199,      -0.323,       0.172 },
2276
/*        45 */  { 1977.0,    1980.0,      47.291,       3.069,       0.193,      -0.192 },
2277
/*        46 */  { 1980.0,    1983.0,      50.361,       2.878,      -0.384,       0.081 },
2278
/*        47 */  { 1983.0,    1986.0,      52.936,       2.354,      -0.140,      -0.165 },
2279
/*        48 */  { 1986.0,    1989.0,      54.984,       1.577,      -0.637,       0.448 },
2280
/*        49 */  { 1989.0,    1992.0,      56.373,       1.648,       0.708,      -0.276 },
2281
/*        50 */  { 1992.0,    1995.0,      58.453,       2.235,      -0.121,       0.110 },
2282
/*        51 */  { 1995.0,    1998.0,      60.678,       2.324,       0.210,      -0.313 },
2283
/*        52 */  { 1998.0,    2001.0,      62.898,       1.804,      -0.729,       0.109 },
2284
/*        53 */  { 2001.0,    2004.0,      64.083,       0.674,      -0.402,       0.199 },
2285
/*        54 */  { 2004.0,    2007.0,      64.553,       0.466,       0.194,      -0.017 },
2286
/*        55 */  { 2007.0,    2010.0,      65.197,       0.804,       0.144,      -0.084 },
2287
/*        56 */  { 2010.0,    2013.0,      66.061,       0.839,      -0.109,       0.128 },
2288
/*        57 */  { 2013.0,    2016.0,      66.920,       1.007,       0.277,      -0.095 },
2289
/*        58 */  { 2016.0,    2019.0,      68.109,       1.277,      -0.007,      -0.139 }
2290
};
2291
double getDeltaTByStephensonMorrisonHohenkerk2016(const double jDay)
150✔
2292
{
2293
        int year, month, day;
2294
        getDateFromJulianDay(jDay, &year, &month, &day);
150✔
2295
        double y=yearFraction(year, month, day);
150✔
2296
        if ((y<-720.) || (y>2019.))
150✔
2297
        {
2298
                double fact=(y-1825.0)/100.;
×
2299
                //return -320.0+32.5*fact*fact;
2300
                return -10+31.4*fact*fact;
×
2301
        }
2302
        int i=0;
150✔
2303
        while (StephensonMorrisonHohenkerk2016DeltaTtableS15[i][1]<y) i++;
4,354✔
2304
        Q_ASSERT(i<58);
150✔
2305
        double t=(y-StephensonMorrisonHohenkerk2016DeltaTtableS15[i][0]) / (StephensonMorrisonHohenkerk2016DeltaTtableS15[i][1]-StephensonMorrisonHohenkerk2016DeltaTtableS15[i][0]);
150✔
2306
        return ((StephensonMorrisonHohenkerk2016DeltaTtableS15[i][5]*t + StephensonMorrisonHohenkerk2016DeltaTtableS15[i][4])*t
150✔
2307
                + StephensonMorrisonHohenkerk2016DeltaTtableS15[i][3])*t + StephensonMorrisonHohenkerk2016DeltaTtableS15[i][2];
150✔
2308
}
2309

2310
double getMoonSecularAcceleration(const double jDay, const double nd, const bool useDE4xx)
×
2311
{
2312
        int year, month, day;
2313
        getDateFromJulianDay(jDay, &year, &month, &day);
×
2314

2315
        const double t = (yearFraction(year, month, day)-1955.5)/100.0;
×
2316
        // n.dot for secular acceleration of the Moon in ELP2000-82B
2317
        // has value -23.8946 "/cy/cy (or -25.8 for DE43x usage)
2318
        const double ephND = (useDE4xx ? -25.8 : -23.8946);
×
2319
        return -0.91072 * (ephND + qAbs(nd))*t*t;
×
2320
}
2321

2322
double getDeltaTStandardError(const double jDay)
6✔
2323
{
2324
        int year, month, day;
2325
        getDateFromJulianDay(jDay, &year, &month, &day);
6✔
2326

2327
        double sigma = -1.;
6✔
2328

2329
        if (-1000 <= year && year <= 1600)
6✔
2330
        {
2331
                double cDiff1820= (jDay-2385800.0)/36525.0; //    1820.0=1820-jan-0.5=2385800.0
6✔
2332
                // sigma = std::pow((yeardec-1820.0)/100,2); // sigma(DeltaT) = 0.8*u^2
2333
                sigma = 0.8 * cDiff1820 * cDiff1820;
6✔
2334
        }
2335
        return sigma;
6✔
2336
}
2337

2338
// Current table contains interpolated data of original table by Spencer Jones, H., "The Rotation of the Earth, and the Secular
2339
// Accelerations of the Sun, Moon and Planets", Monthly Notices of the Royal Astronomical Society, 99 (1939), 541-558
2340
// [http://adsabs.harvard.edu/abs/1939MNRAS..99..541S] see Table I.
2341
static const double MoonFluctuationTable[2555] = {
2342
        -12.720, -12.691, -12.662, -12.632, -12.603, -12.574, -12.545, -12.516, -12.486, -12.457, -12.428, -12.399, -12.369, -12.340,
2343
        -12.311, -12.282, -12.253, -12.223, -12.194, -12.165, -12.136, -12.107, -12.077, -12.048, -12.019, -11.990, -11.960, -11.931,
2344
        -11.902, -11.873, -11.843, -11.814, -11.785, -11.756, -11.726, -11.697, -11.668, -11.639, -11.609, -11.580, -11.551, -11.522,
2345
        -11.492, -11.463, -11.434, -11.404, -11.375, -11.346, -11.317, -11.287, -11.258, -11.229, -11.199, -11.170, -11.141, -11.111,
2346
        -11.082, -11.053, -11.023, -10.994, -10.965, -10.935, -10.906, -10.877, -10.847, -10.818, -10.788, -10.759, -10.730, -10.700,
2347
        -10.671, -10.641, -10.612, -10.583, -10.553, -10.524, -10.494, -10.465, -10.435, -10.406, -10.376, -10.347, -10.317, -10.288,
2348
        -10.258, -10.229, -10.199, -10.170, -10.140, -10.111, -10.081, -10.052, -10.022, -09.993, -09.963, -09.934, -09.904, -09.874,
2349
        -09.845, -09.815, -09.786, -09.756, -09.726, -09.697, -09.667, -09.637, -09.608, -09.578, -09.548, -09.519, -09.489, -09.459,
2350
        -09.430, -09.400, -09.370, -09.340, -09.311, -09.281, -09.251, -09.221, -09.191, -09.162, -09.132, -09.102, -09.072, -09.042,
2351
        -09.013, -08.983, -08.953, -08.923, -08.893, -08.863, -08.833, -08.803, -08.773, -08.743, -08.713, -08.683, -08.653, -08.623,
2352
        -08.593, -08.563, -08.533, -08.503, -08.473, -08.443, -08.413, -08.383, -08.353, -08.323, -08.293, -08.263, -08.232, -08.202,
2353
        -08.172, -08.142, -08.112, -08.082, -08.051, -08.021, -07.991, -07.961, -07.930, -07.900, -07.870, -07.839, -07.809, -07.779,
2354
        -07.748, -07.718, -07.688, -07.657, -07.627, -07.596, -07.566, -07.535, -07.505, -07.474, -07.444, -07.413, -07.383, -07.352,
2355
        -07.322, -07.291, -07.261, -07.230, -07.199, -07.169, -07.138, -07.107, -07.077, -07.046, -07.015, -06.985, -06.954, -06.923,
2356
        -06.892, -06.862, -06.831, -06.800, -06.769, -06.738, -06.707, -06.676, -06.646, -06.615, -06.584, -06.553, -06.522, -06.491,
2357
        -06.460, -06.429, -06.398, -06.367, -06.336, -06.304, -06.273, -06.242, -06.211, -06.180, -06.149, -06.118, -06.086, -06.055,
2358
        -06.024, -05.993, -05.961, -05.930, -05.899, -05.867, -05.836, -05.805, -05.773, -05.742, -05.710, -05.679, -05.647, -05.616,
2359
        -05.584, -05.553, -05.521, -05.490, -05.458, -05.426, -05.395, -05.363, -05.331, -05.300, -05.268, -05.236, -05.204, -05.173,
2360
        -05.141, -05.109, -05.077, -05.045, -05.013, -04.982, -04.950, -04.918, -04.886, -04.854, -04.822, -04.790, -04.758, -04.726,
2361
        -04.693, -04.661, -04.629, -04.597, -04.565, -04.533, -04.500, -04.468, -04.436, -04.404, -04.371, -04.339, -04.307, -04.274,
2362
        -04.242, -04.209, -04.177, -04.144, -04.112, -04.079, -04.047, -04.014, -03.982, -03.949, -03.916, -03.884, -03.851, -03.818,
2363
        -03.785, -03.753, -03.720, -03.687, -03.654, -03.621, -03.588, -03.556, -03.523, -03.490, -03.457, -03.424, -03.391, -03.357,
2364
        -03.324, -03.291, -03.258, -03.225, -03.192, -03.158, -03.125, -03.092, -03.058, -03.025, -02.992, -02.958, -02.925, -02.891,
2365
        -02.858, -02.824, -02.791, -02.757, -02.723, -02.690, -02.656, -02.622, -02.589, -02.555, -02.521, -02.487, -02.453, -02.419,
2366
        -02.385, -02.351, -02.317, -02.283, -02.249, -02.215, -02.181, -02.147, -02.112, -02.078, -02.044, -02.009, -01.975, -01.941,
2367
        -01.906, -01.872, -01.837, -01.803, -01.768, -01.733, -01.699, -01.664, -01.629, -01.594, -01.559, -01.525, -01.490, -01.455,
2368
        -01.420, -01.385, -01.350, -01.315, -01.279, -01.244, -01.209, -01.174, -01.138, -01.103, -01.068, -01.032, -00.997, -00.961,
2369
        -00.926, -00.890, -00.854, -00.819, -00.783, -00.747, -00.711, -00.675, -00.639, -00.603, -00.567, -00.531, -00.495, -00.459,
2370
        -00.423, -00.387, -00.350, -00.314, -00.278, -00.241, -00.205, -00.168, -00.132, -00.095, -00.058, -00.022,  00.015,  00.052,
2371
         00.089,  00.126,  00.163,  00.200,  00.237,  00.274,  00.311,  00.348,  00.385,  00.423,  00.460,  00.497,  00.535,  00.572,
2372
         00.610,  00.647,  00.685,  00.723,  00.761,  00.798,  00.836,  00.874,  00.912,  00.950,  00.988,  01.026,  01.065,  01.103,
2373
         01.141,  01.180,  01.218,  01.257,  01.295,  01.334,  01.372,  01.411,  01.450,  01.489,  01.527,  01.566,  01.605,  01.644,
2374
         01.683,  01.723,  01.762,  01.801,  01.840,  01.880,  01.919,  01.959,  01.998,  02.038,  02.078,  02.117,  02.157,  02.197,
2375
         02.237,  02.277,  02.317,  02.357,  02.397,  02.437,  02.478,  02.518,  02.558,  02.598,  02.639,  02.679,  02.720,  02.760,
2376
         02.800,  02.841,  02.881,  02.922,  02.962,  03.003,  03.043,  03.084,  03.124,  03.165,  03.205,  03.246,  03.286,  03.326,
2377
         03.367,  03.407,  03.448,  03.488,  03.528,  03.568,  03.609,  03.649,  03.689,  03.729,  03.769,  03.809,  03.849,  03.889,
2378
         03.929,  03.968,  04.008,  04.048,  04.087,  04.127,  04.166,  04.205,  04.245,  04.284,  04.323,  04.362,  04.401,  04.440,
2379
         04.478,  04.517,  04.555,  04.594,  04.632,  04.670,  04.708,  04.746,  04.784,  04.822,  04.859,  04.896,  04.934,  04.971,
2380
         05.008,  05.045,  05.082,  05.118,  05.155,  05.191,  05.227,  05.263,  05.299,  05.334,  05.370,  05.405,  05.440,  05.475,
2381
         05.510,  05.545,  05.579,  05.613,  05.647,  05.681,  05.715,  05.748,  05.782,  05.815,  05.848,  05.880,  05.913,  05.945,
2382
         05.977,  06.009,  06.040,  06.072,  06.103,  06.134,  06.165,  06.195,         06.226,  06.256,  06.286,  06.315,  06.345,  06.374,
2383
         06.404,  06.433,  06.461,  06.490,  06.519,  06.547,  06.575,  06.603,  06.631,  06.659,  06.686,  06.713,  06.741,  06.768,
2384
         06.794,  06.821,  06.848,  06.874,  06.900,  06.927,  06.953,  06.979,  07.004,  07.030,  07.055,  07.081,  07.106,  07.131,
2385
         07.156,  07.181,  07.206,  07.231,  07.255,  07.280,  07.304,  07.329,  07.353,  07.377,  07.401,  07.425,  07.449,  07.472,
2386
         07.496,  07.520,  07.543,  07.567,  07.590,  07.613,  07.637,  07.660,  07.683,  07.706,  07.729,  07.752,  07.775,  07.798,
2387
         07.820,  07.843,  07.866,  07.889,  07.911,  07.934,  07.956,  07.979,  08.002,  08.024,  08.047,  08.069,  08.092,  08.114,
2388
         08.136,  08.159,  08.181,  08.204,  08.226,  08.248,  08.271,  08.293,  08.316,  08.338,  08.361,  08.383,  08.406,  08.428,
2389
         08.451,  08.473,  08.496,  08.518,  08.541,  08.564,  08.587,  08.609,  08.632,  08.655,  08.678,  08.700,  08.723,  08.746,
2390
         08.769,  08.792,  08.815,  08.838,  08.861,  08.884,  08.907,  08.930,  08.953,  08.976,  09.000,  09.023,  09.046,  09.069,
2391
         09.092,  09.115,  09.139,  09.162,  09.185,  09.208,  09.231,  09.255,  09.278,  09.301,  09.325,  09.348,  09.371,  09.394,
2392
         09.418,  09.441,  09.464,  09.488,  09.511,  09.534,  09.558,  09.581,  09.604,  09.628,  09.651,  09.674,  09.698,  09.721,
2393
         09.744,  09.768,  09.791,  09.814,  09.837,  09.861,  09.884,  09.907,  09.930,  09.954,  09.977,  10.000,  10.023,  10.047,
2394
         10.070,  10.093,  10.116,  10.139,  10.162,  10.185,  10.209,  10.232,  10.255,  10.278,  10.301,  10.324,  10.347,  10.370,
2395
         10.393,  10.415,  10.438,  10.461,  10.484,  10.507,  10.530,  10.552,  10.575,  10.598,  10.621,  10.643,  10.666,  10.688,
2396
         10.711,  10.734,  10.756,  10.779,  10.801,  10.824,  10.846,  10.868,  10.891,  10.913,  10.935,  10.958,  10.980,  11.002,
2397
         11.024,  11.047,  11.069,  11.091,  11.113,  11.135,  11.157,  11.179,         11.201,  11.223,  11.245,  11.266,  11.288,  11.310,
2398
         11.332,  11.353,  11.375,  11.397,  11.418,  11.440,  11.462,  11.483,  11.504,  11.526,  11.547,  11.569,  11.590,  11.611,
2399
         11.632,  11.654,  11.675,  11.696,  11.717,  11.738,  11.759,  11.780,  11.801,  11.822,  11.843,  11.863,  11.884,  11.905,
2400
         11.926,  11.946,  11.967,  11.987,  12.008,  12.028,  12.049,  12.069,  12.089,  12.110,  12.130,  12.150,  12.170,  12.190,
2401
         12.210,  12.230,  12.250,  12.270,  12.290,  12.310,  12.330,  12.349,  12.369,  12.389,  12.408,  12.428,  12.447,  12.467,
2402
         12.486,  12.505,  12.525,  12.544,  12.563,  12.582,  12.601,  12.620,  12.639,  12.658,  12.677,  12.696,  12.714,  12.733,
2403
         12.752,  12.770,  12.789,  12.807,  12.826,  12.844,  12.862,  12.881,  12.899,  12.917,  12.935,  12.953,  12.971,  12.989,
2404
         13.007,  13.025,  13.042,  13.060,  13.078,  13.095,  13.113,  13.130,  13.148,  13.165,  13.182,  13.199,  13.216,  13.234,
2405
         13.251,  13.267,  13.284,  13.301,  13.318,  13.335,  13.351,  13.368,  13.384,  13.401,  13.417,  13.433,  13.450,  13.466,
2406
         13.482,  13.498,  13.514,  13.530,  13.546,  13.561,  13.577,  13.593,  13.608,  13.624,  13.639,  13.654,  13.670,  13.685,
2407
         13.700,  13.715,  13.730,  13.745,  13.760,  13.775,  13.789,  13.804,  13.818,  13.833,  13.847,  13.861,  13.876,  13.890,
2408
         13.904,  13.918,  13.932,  13.946,  13.959,  13.973,  13.986,  14.000,  14.013,  14.027,  14.040,  14.053,  14.066,  14.079,
2409
         14.092,  14.105,  14.117,  14.130,  14.142,  14.155,  14.167,  14.179,  14.192,  14.204,  14.216,  14.227,  14.239,  14.251,
2410
         14.262,  14.274,  14.285,  14.296,  14.308,  14.319,  14.330,  14.341,  14.351,  14.362,  14.373,  14.383,  14.394,  14.404,
2411
         14.414,  14.424,  14.434,  14.444,  14.454,  14.463,  14.473,  14.482,  14.492,  14.501,  14.510,  14.519,  14.528,  14.537,
2412
         14.545,  14.554,  14.562,  14.571,  14.579,  14.587,  14.595,  14.603,         14.610,  14.618,  14.626,  14.633,  14.640,  14.647,
2413
         14.654,  14.661,  14.668,  14.675,  14.681,  14.688,  14.694,  14.700,  14.706,  14.712,  14.718,  14.724,  14.730,  14.735,
2414
         14.740,  14.745,  14.751,  14.755,  14.760,  14.765,  14.770,  14.774,  14.778,  14.782,  14.786,  14.790,  14.794,  14.798,
2415
         14.801,  14.805,  14.808,  14.811,  14.814,  14.817,  14.819,  14.822,  14.824,  14.826,  14.829,  14.831,  14.832,  14.834,
2416
         14.836,  14.837,  14.838,  14.839,  14.840,  14.841,  14.842,  14.842,  14.843,  14.843,  14.843,  14.843,  14.843,  14.843,
2417
         14.842,  14.841,  14.841,  14.840,  14.839,  14.837,  14.836,  14.834,  14.833,  14.831,  14.829,  14.827,  14.824,  14.822,
2418
         14.819,  14.817,  14.814,  14.811,  14.807,  14.804,  14.800,  14.797,  14.793,  14.789,  14.785,  14.780,  14.776,  14.771,
2419
         14.766,  14.761,  14.756,  14.751,  14.746,  14.740,  14.734,  14.728,  14.722,  14.716,  14.709,  14.703,  14.696,  14.689,
2420
         14.682,  14.675,  14.667,  14.660,  14.652,  14.644,  14.636,  14.628,  14.619,  14.611,  14.602,  14.593,  14.584,  14.575,
2421
         14.565,  14.555,  14.546,  14.536,  14.526,  14.515,  14.505,  14.494,  14.483,  14.472,  14.461,  14.450,  14.438,  14.427,
2422
         14.415,  14.403,  14.391,  14.379,  14.366,  14.354,  14.341,  14.329,  14.316,  14.303,  14.289,  14.276,  14.263,  14.249,
2423
         14.235,  14.222,  14.208,  14.194,  14.179,  14.165,  14.151,  14.136,  14.122,  14.107,  14.092,  14.077,  14.062,  14.047,
2424
         14.032,  14.017,  14.001,  13.986,  13.970,  13.955,  13.939,  13.923,  13.908,  13.892,  13.876,  13.860,  13.843,  13.827,
2425
         13.811,  13.795,  13.778,  13.762,  13.745,  13.729,  13.712,  13.695,  13.679,  13.662,  13.645,  13.628,  13.612,  13.595,
2426
         13.578,  13.561,  13.544,  13.527,  13.510,  13.493,  13.476,  13.459,  13.441,  13.424,  13.407,  13.390,  13.373,  13.356,
2427
         13.338,  13.321,  13.304,  13.287,  13.270,  13.253,  13.236,  13.218,         13.201,  13.184,  13.167,  13.150,  13.133,  13.116,
2428
         13.099,  13.082,  13.065,  13.048,  13.031,  13.014,  12.998,  12.981,  12.964,  12.947,  12.931,  12.914,  12.897,  12.881,
2429
         12.864,  12.847,  12.831,  12.814,  12.798,  12.781,  12.765,  12.748,  12.732,  12.716,  12.699,  12.683,  12.667,  12.650,
2430
         12.634,  12.618,  12.602,  12.585,  12.569,  12.553,  12.537,  12.521,  12.504,  12.488,  12.472,  12.456,  12.440,  12.424,
2431
         12.408,  12.392,  12.376,  12.360,  12.344,  12.328,  12.312,  12.296,  12.280,  12.265,  12.249,  12.233,  12.217,  12.201,
2432
         12.185,  12.169,  12.154,  12.138,  12.122,  12.106,  12.090,  12.075,  12.059,  12.043,  12.027,  12.012,  11.996,  11.980,
2433
         11.965,  11.949,  11.933,  11.917,  11.902,  11.886,  11.870,  11.855,  11.839,  11.823,  11.808,  11.792,  11.776,  11.761,
2434
         11.745,  11.730,  11.714,  11.698,  11.683,  11.667,  11.652,  11.636,  11.621,  11.606,  11.590,  11.575,  11.560,  11.545,
2435
         11.530,  11.515,  11.500,  11.485,  11.470,  11.455,  11.441,  11.426,  11.412,  11.397,  11.383,  11.369,  11.355,  11.341,
2436
         11.327,  11.314,  11.300,  11.286,  11.273,  11.260,  11.247,  11.234,  11.221,  11.208,  11.196,  11.183,  11.171,  11.158,
2437
         11.146,  11.134,  11.122,  11.109,  11.097,  11.085,  11.074,  11.062,  11.050,  11.038,  11.026,  11.014,  11.003,  10.991,
2438
         10.979,  10.968,  10.956,  10.944,  10.932,  10.921,  10.909,  10.897,  10.885,  10.873,  10.861,  10.849,  10.837,  10.825,
2439
         10.813,  10.801,  10.789,  10.776,  10.764,  10.751,  10.738,  10.726,  10.713,  10.700,  10.687,  10.674,  10.660,  10.647,
2440
         10.633,  10.619,  10.605,  10.591,  10.577,  10.563,  10.548,  10.534,  10.519,  10.504,  10.488,  10.473,  10.457,  10.441,
2441
         10.425,  10.409,  10.392,  10.376,  10.359,  10.342,  10.324,  10.306,  10.288,  10.270,  10.252,  10.233,  10.214,  10.195,
2442
         10.175,  10.155,  10.135,  10.115,  10.094,  10.073,  10.052,  10.030,         10.008,  09.985,  09.963,  09.940,  09.917,  09.893,
2443
         09.869,  09.845,  09.820,  09.795,  09.770,  09.745,  09.719,  09.693,  09.667,  09.641,  09.614,  09.587,  09.559,  09.532,
2444
         09.504,  09.476,  09.447,  09.419,  09.390,  09.361,  09.331,  09.301,  09.272,  09.242,  09.211,  09.181,  09.150,  09.119,
2445
         09.088,  09.056,  09.025,  08.993,  08.961,  08.928,  08.896,  08.863,  08.831,  08.798,  08.764,  08.731,  08.697,  08.664,
2446
         08.630,  08.596,  08.561,  08.527,  08.492,  08.458,  08.423,  08.388,  08.353,  08.317,  08.282,  08.246,  08.211,  08.175,
2447
         08.139,  08.103,  08.067,  08.030,  07.994,  07.957,  07.921,  07.884,  07.847,  07.810,  07.773,  07.736,  07.699,  07.662,
2448
         07.624,  07.587,  07.549,  07.512,  07.474,  07.437,  07.399,  07.361,  07.323,  07.285,  07.247,  07.209,  07.171,  07.133,
2449
         07.095,  07.057,  07.019,  06.980,  06.942,  06.904,  06.866,  06.827,  06.789,  06.751,  06.713,  06.674,  06.636,  06.598,
2450
         06.560,  06.522,  06.484,  06.446,  06.409,  06.371,  06.333,  06.296,  06.259,  06.221,  06.184,  06.148,  06.111,  06.074,
2451
         06.038,  06.002,  05.966,  05.931,  05.895,  05.860,  05.825,  05.790,  05.756,  05.722,  05.688,  05.654,  05.621,  05.588,
2452
         05.556,  05.523,  05.491,  05.460,  05.429,  05.398,  05.367,  05.337,  05.308,  05.279,  05.250,  05.221,  05.194,  05.166,
2453
         05.139,  05.113,  05.087,  05.061,  05.036,  05.011,  04.987,  04.964,  04.941,  04.919,  04.897,  04.875,  04.855,  04.835,
2454
         04.815,  04.796,  04.777,  04.759,  04.741,  04.724,  04.708,  04.691,  04.676,  04.661,  04.646,  04.631,  04.617,  04.604,
2455
         04.591,  04.578,  04.566,  04.554,  04.542,  04.531,  04.520,  04.510,  04.500,  04.490,  04.480,  04.471,  04.462,  04.454,
2456
         04.446,  04.438,  04.430,  04.422,  04.415,  04.408,  04.402,  04.395,  04.389,  04.383,  04.377,  04.371,  04.366,  04.361,
2457
         04.355,  04.350,  04.346,  04.341,  04.336,  04.332,  04.328,  04.323,         04.319,  04.315,  04.311,  04.308,  04.304,  04.300,
2458
         04.296,  04.293,  04.289,  04.285,  04.282,  04.278,  04.275,  04.271,  04.268,  04.264,  04.261,  04.257,  04.253,  04.249,
2459
         04.246,  04.242,  04.238,  04.234,  04.230,  04.226,  04.221,  04.217,  04.212,  04.208,  04.203,  04.198,  04.193,  04.188,
2460
         04.183,  04.177,  04.171,  04.165,  04.159,  04.153,  04.147,  04.140,  04.133,  04.126,  04.118,  04.111,  04.103,  04.095,
2461
         04.086,  04.078,  04.069,  04.059,  04.050,  04.040,  04.030,  04.019,  04.009,  03.997,  03.986,  03.974,  03.962,  03.949,
2462
         03.937,  03.923,  03.910,  03.896,  03.882,  03.867,  03.853,  03.838,  03.823,  03.807,  03.791,  03.776,  03.760,  03.743,
2463
         03.727,  03.710,  03.693,  03.676,  03.659,  03.642,  03.625,  03.607,  03.590,  03.572,  03.554,  03.537,  03.519,  03.501,
2464
         03.483,  03.465,  03.447,  03.429,  03.412,  03.394,  03.376,  03.358,  03.340,  03.323,  03.305,  03.287,  03.270,  03.252,
2465
         03.235,  03.217,  03.200,  03.182,  03.164,  03.147,  03.129,  03.111,  03.094,  03.076,  03.058,  03.040,  03.022,  03.004,
2466
         02.985,  02.967,  02.949,  02.930,  02.911,  02.893,  02.874,  02.855,  02.835,  02.816,  02.796,  02.777,  02.757,  02.737,
2467
         02.716,  02.696,  02.675,  02.654,  02.633,  02.612,  02.590,  02.568,  02.546,  02.524,  02.501,  02.478,  02.455,  02.431,
2468
         02.407,  02.383,  02.359,  02.334,  02.309,  02.284,  02.258,  02.233,  02.206,  02.180,  02.153,  02.126,  02.099,  02.072,
2469
         02.044,  02.016,  01.988,  01.960,  01.931,  01.902,  01.873,  01.844,  01.814,  01.785,  01.755,  01.725,  01.694,  01.664,
2470
         01.633,  01.602,  01.571,  01.540,  01.509,  01.477,  01.445,  01.413,  01.381,  01.349,  01.317,  01.284,  01.252,  01.219,
2471
         01.186,  01.153,  01.120,  01.087,  01.054,  01.020,  00.987,  00.953,  00.920,  00.886,  00.852,  00.818,  00.784,  00.750,
2472
         00.715,  00.680,  00.645,  00.609,  00.574,  00.537,  00.500,  00.463,         00.426,  00.387,  00.348,  00.309,  00.269,  00.228,
2473
         00.187,  00.145,  00.102,  00.058,  00.013, -00.032, -00.079, -00.126,        -00.174, -00.223, -00.274, -00.325, -00.378, -00.431,
2474
        -00.486, -00.542, -00.599, -00.658, -00.718, -00.779, -00.841, -00.905,        -00.970, -01.037, -01.105, -01.175, -01.247, -01.320,
2475
        -01.394, -01.471, -01.549, -01.628, -01.710, -01.793, -01.877, -01.964,        -02.051, -02.140, -02.230, -02.322, -02.415, -02.508,
2476
        -02.603, -02.699, -02.796, -02.893, -02.992, -03.091, -03.191, -03.291,        -03.392, -03.494, -03.596, -03.698, -03.801, -03.903,
2477
        -04.006, -04.109, -04.212, -04.315, -04.418, -04.521, -04.624, -04.726,        -04.828, -04.929, -05.030, -05.131, -05.231, -05.330,
2478
        -05.428, -05.526, -05.623, -05.719, -05.813, -05.907, -06.000, -06.091,        -06.182, -06.271, -06.358, -06.444, -06.529, -06.612,
2479
        -06.694, -06.775, -06.854, -06.932, -07.009, -07.084, -07.158, -07.231,        -07.302, -07.373, -07.442, -07.510, -07.578, -07.644,
2480
        -07.708, -07.772, -07.835, -07.897, -07.958, -08.018, -08.077, -08.135,        -08.193, -08.249, -08.305, -08.360, -08.414, -08.467,
2481
        -08.520, -08.572, -08.623, -08.674, -08.724, -08.773, -08.822, -08.870,        -08.918, -08.965, -09.011, -09.058, -09.103, -09.149,
2482
        -09.194, -09.238, -09.282, -09.326, -09.370, -09.413, -09.456, -09.499,        -09.542, -09.584, -09.626, -09.668, -09.709, -09.751,
2483
        -09.792, -09.833, -09.873, -09.914, -09.954, -09.994, -10.034, -10.073,        -10.113, -10.152, -10.191, -10.230, -10.269, -10.307,
2484
        -10.346, -10.384, -10.422, -10.460, -10.498, -10.535, -10.573, -10.610,        -10.648, -10.685, -10.722, -10.759, -10.796, -10.832,
2485
        -10.869, -10.905, -10.942, -10.978, -11.014, -11.051, -11.087, -11.123,        -11.159, -11.195, -11.231, -11.267, -11.302, -11.338,
2486
        -11.374, -11.410, -11.445, -11.481, -11.517, -11.552, -11.588, -11.623,        -11.659, -11.694, -11.730, -11.765, -11.800, -11.836,
2487
        -11.871, -11.906, -11.941, -11.976, -12.011, -12.047, -12.082, -12.117,        -12.151, -12.186, -12.221, -12.256, -12.291, -12.325,
2488
        -12.360, -12.395, -12.429, -12.464, -12.498, -12.533, -12.567, -12.601,        -12.636, -12.670, -12.704, -12.738, -12.772, -12.807,
2489
        -12.841, -12.875, -12.908, -12.942, -12.976, -13.010, -13.044, -13.077,        -13.111, -13.144, -13.178, -13.211, -13.245, -13.278,
2490
        -13.311, -13.344, -13.378, -13.411, -13.444, -13.476, -13.509, -13.542,        -13.575, -13.607, -13.640, -13.673, -13.705, -13.737,
2491
        -13.770, -13.802, -13.834, -13.866, -13.898, -13.930, -13.961, -13.993,        -14.024, -14.056, -14.087, -14.119, -14.150, -14.181,
2492
        -14.212, -14.243, -14.273, -14.304, -14.335, -14.365, -14.395, -14.426,        -14.456, -14.486, -14.516, -14.546, -14.576, -14.605,
2493
        -14.635, -14.665, -14.694, -14.724, -14.754, -14.783, -14.813, -14.842,        -14.871, -14.901, -14.930, -14.960, -14.989, -15.018,
2494
        -15.048, -15.077, -15.107, -15.136, -15.166, -15.195, -15.225, -15.255,        -15.285, -15.314, -15.344, -15.373, -15.403, -15.432,
2495
        -15.461, -15.490, -15.519, -15.547, -15.575, -15.603, -15.630, -15.657,        -15.684, -15.710, -15.735, -15.760, -15.784, -15.808,
2496
        -15.831, -15.853, -15.875, -15.896, -15.916, -15.935, -15.954, -15.971,        -15.988, -16.003, -16.018, -16.031, -16.044, -16.055,
2497
        -16.065, -16.074, -16.082, -16.089, -16.094, -16.098, -16.101, -16.102,        -16.102, -16.100, -16.097, -16.092, -16.086, -16.078,
2498
        -16.068, -16.057, -16.044, -16.029, -16.013, -15.995, -15.974, -15.952,        -15.928, -15.902, -15.874, -15.844, -15.812, -15.778,
2499
        -15.742, -15.705, -15.666, -15.626, -15.584, -15.541, -15.496, -15.451,        -15.404, -15.357, -15.309, -15.260, -15.211, -15.161,
2500
        -15.110, -15.059, -15.008, -14.957, -14.906, -14.855, -14.804, -14.753,        -14.703, -14.653, -14.603, -14.554, -14.506, -14.459,
2501
        -14.412, -14.367, -14.322, -14.278, -14.235, -14.192, -14.151, -14.110,        -14.070, -14.031, -13.993, -13.955, -13.918, -13.882,
2502
        -13.847, -13.813, -13.779, -13.746, -13.714, -13.682, -13.652, -13.622,        -13.593, -13.564, -13.536, -13.509, -13.483, -13.458,
2503
        -13.433, -13.409, -13.385, -13.363, -13.340, -13.319, -13.297, -13.276,        -13.256, -13.236, -13.216, -13.196, -13.176, -13.156,
2504
        -13.137, -13.117, -13.097, -13.078, -13.058, -13.037, -13.017, -12.996,        -12.974, -12.953, -12.930, -12.907, -12.884, -12.860,
2505
        -12.835, -12.809, -12.783, -12.755, -12.727, -12.698, -12.668, -12.637,        -12.606, -12.573, -12.540, -12.506, -12.471, -12.435,
2506
        -12.399, -12.362, -12.324, -12.285, -12.246, -12.205, -12.165, -12.123,        -12.081, -12.038, -11.995, -11.951, -11.906, -11.860,
2507
        -11.814, -11.768, -11.721, -11.673, -11.625, -11.576, -11.526, -11.477,        -11.427, -11.377, -11.326, -11.276, -11.226, -11.176,
2508
        -11.127, -11.078, -11.029, -10.981, -10.934, -10.887, -10.842, -10.797,        -10.754, -10.711, -10.670, -10.631, -10.592, -10.556,
2509
        -10.521, -10.488, -10.456, -10.427, -10.400, -10.375, -10.352, -10.331,        -10.313, -10.297, -10.283, -10.270, -10.260, -10.251,
2510
        -10.243, -10.237, -10.232, -10.229, -10.226, -10.224, -10.223, -10.222,        -10.222, -10.222, -10.223, -10.223, -10.224, -10.224,
2511
        -10.225, -10.224, -10.223, -10.222, -10.220, -10.217, -10.212, -10.207,        -10.201, -10.193, -10.183, -10.173, -10.162, -10.150,
2512
        -10.138, -10.125, -10.112, -10.099, -10.087, -10.075, -10.063, -10.053,        -10.043, -10.035, -10.028, -10.022, -10.019, -10.017,
2513
        -10.017, -10.020, -10.025, -10.033, -10.043, -10.057, -10.074, -10.094,        -10.118, -10.146, -10.178, -10.214, -10.254, -10.297,
2514
        -10.344, -10.394, -10.447, -10.502, -10.560, -10.619, -10.680, -10.743,        -10.806, -10.871, -10.936, -11.001, -11.066, -11.131,
2515
        -11.195, -11.259, -11.321, -11.382, -11.441, -11.498, -11.553, -11.605,        -11.655, -11.701, -11.744, -11.783, -11.818, -11.850,
2516
        -11.877, -11.900, -11.921, -11.938, -11.953, -11.966, -11.978, -11.988,        -11.997, -12.005, -12.013, -12.021, -12.029, -12.038,
2517
        -12.049, -12.061, -12.074, -12.091, -12.109, -12.131, -12.155, -12.182,        -12.212, -12.244, -12.278, -12.314, -12.352, -12.392,
2518
        -12.434, -12.476, -12.520, -12.565, -12.612, -12.658, -12.706, -12.754,        -12.802, -12.850, -12.898, -12.947, -12.995, -13.042,
2519
        -13.090, -13.137, -13.185, -13.232, -13.278, -13.325, -13.372, -13.418,        -13.464, -13.510, -13.556, -13.602, -13.648, -13.693,
2520
        -13.739, -13.784, -13.829, -13.874, -13.919, -13.964, -14.009, -14.054,        -14.099, -14.145, -14.192, -14.238, -14.286, -14.334,
2521
        -14.383, -14.432, -14.483, -14.534, -14.587, -14.640, -14.695, -14.751,        -14.809, -14.868, -14.928, -14.990, -15.052, -15.115,
2522
        -15.178, -15.241, -15.304, -15.367, -15.430, -15.491, -15.552, -15.612,        -15.670, -15.727, -15.782, -15.835, -15.886, -15.934,
2523
        -15.980, -16.022, -16.063, -16.100, -16.135, -16.168, -16.198, -16.227,        -16.254, -16.279, -16.302, -16.324, -16.344, -16.364,
2524
        -16.382, -16.400, -16.417, -16.433, -16.449, -16.465, -16.480
2525
};
2526

2527
double getMoonFluctuation(const double jDay)
50✔
2528
{
2529
        double f = 0.;
50✔
2530
        int year, month, day;
2531
        getDateFromJulianDay(jDay, &year, &month, &day);
50✔
2532

2533
        double t = yearFraction(year, month, day);
50✔
2534
        if (t>=1681.0 && t<=1936.5) {
50✔
2535
                int index = qRound(std::floor((t - 1681.0)*10));
1✔
2536
                f = MoonFluctuationTable[index]*0.07; // Get interpolated data and convert to seconds of time
1✔
2537
        }
2538

2539
        return f;
50✔
2540
}
2541

2542
// Arrays to keep cos/sin of angles and multiples of angles. rho and theta are delta angles, and these arrays
2543
#define MAX_STACKS 4096
2544
static float cos_sin_rho[2*(MAX_STACKS+1)];
2545
#define MAX_SLICES 4096
2546
static float cos_sin_theta[2*(MAX_SLICES+1)];
2547

2548
//! Compute cosines and sines around a circle which is split in "segments" parts.
2549
//! Values are stored in the global static array cos_sin_theta.
2550
//! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh.
2551
//! @param slices number of partitions (elsewhere called "segments") for the circle
2552
float* ComputeCosSinTheta(const unsigned int slices)
×
2553
{
2554
        Q_ASSERT(slices<=MAX_SLICES);
×
2555
        
2556
        // Difference angle between the stops. Always use 2*M_PI/slices!
2557
        const float dTheta = 2.f * static_cast<float>(M_PI) / static_cast<float>(slices);
×
2558
        float *cos_sin = cos_sin_theta;
×
2559
        float *cos_sin_rev = cos_sin + 2*(slices+1);
×
2560
        const float c = std::cos(dTheta);
×
2561
        const float s = std::sin(dTheta);
×
2562
        *cos_sin++ = 1.f;
×
2563
        *cos_sin++ = 0.f;
×
2564
        *--cos_sin_rev = -cos_sin[-1];
×
2565
        *--cos_sin_rev =  cos_sin[-2];
×
2566
        *cos_sin++ = c;
×
2567
        *cos_sin++ = s;
×
2568
        *--cos_sin_rev = -cos_sin[-1];
×
2569
        *--cos_sin_rev =  cos_sin[-2];
×
2570
        while (cos_sin < cos_sin_rev)   // compares array address indices only!
×
2571
        {
2572
                // avoid expensive trig functions by use of the addition theorem.
2573
                cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
×
2574
                cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
×
2575
                cos_sin += 2;
×
2576
                *--cos_sin_rev = -cos_sin[-1];
×
2577
                *--cos_sin_rev =  cos_sin[-2];
×
2578
        }
2579
        return cos_sin_theta;
×
2580
}
2581

2582
//! Compute cosines and sines around a half-circle which is split in "segments" parts.
2583
//! Values are stored in the global static array cos_sin_rho.
2584
//! Used for the sin/cos values along a meridian for a spherical mesh.
2585
//! @param segments number of partitions (elsewhere called "stacks") for the half-circle
2586
float* ComputeCosSinRho(const unsigned int segments)
×
2587
{
2588
        Q_ASSERT(segments<=MAX_STACKS);
×
2589
        
2590
        // Difference angle between the stops. Always use M_PI/segments!
2591
        const float dRho = static_cast<float>(M_PI) / static_cast<float>(segments);
×
2592
        float *cos_sin = cos_sin_rho;
×
2593
        float *cos_sin_rev = cos_sin + 2*(segments+1);
×
2594
        const float c = cosf(dRho);
×
2595
        const float s = sinf(dRho);
×
2596
        *cos_sin++ = 1.f;
×
2597
        *cos_sin++ = 0.f;
×
2598
        *--cos_sin_rev =  cos_sin[-1];
×
2599
        *--cos_sin_rev = -cos_sin[-2];
×
2600
        *cos_sin++ = c;
×
2601
        *cos_sin++ = s;
×
2602
        *--cos_sin_rev =  cos_sin[-1];
×
2603
        *--cos_sin_rev = -cos_sin[-2];
×
2604
        while (cos_sin < cos_sin_rev)    // compares array address indices only!
×
2605
        {
2606
                // avoid expensive trig functions by use of the addition theorem.
2607
                cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
×
2608
                cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
×
2609
                cos_sin += 2;
×
2610
                *--cos_sin_rev =  cos_sin[-1];
×
2611
                *--cos_sin_rev = -cos_sin[-2];
×
2612
        }
2613
        
2614
        return cos_sin_rho;
×
2615
}
2616

2617
//! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts.
2618
//! Values are stored in the global static array cos_sin_rho.
2619
//! Used for the sin/cos values along a meridian.
2620
//! This allows leaving away pole caps. The array now contains values for the region minAngle+segments*phi
2621
//! @param dRho a difference angle between the stops
2622
//! @param segments number of segments
2623
//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi
2624
float *ComputeCosSinRhoZone(const float dRho, const unsigned int segments, const float minAngle)
×
2625
{
2626
        Q_ASSERT(segments<=MAX_STACKS);
×
2627

2628
        float *cos_sin = cos_sin_rho;
×
2629
        const float c = cosf(dRho);
×
2630
        const float s = sinf(dRho);
×
2631
        *cos_sin++ = cosf(minAngle);
×
2632
        *cos_sin++ = sinf(minAngle);
×
2633
        for (unsigned int i=0; i<segments; ++i) // we cannot mirror this, it may be unequal.
×
2634
        {   // efficient computation, avoid expensive trig functions by use of the addition theorem.
2635
                cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
×
2636
                cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
×
2637
                cos_sin += 2;
×
2638
        }
2639
        return cos_sin_rho;
×
2640
}
2641

2642
int getFixedFromGregorian(const int year, const int month, const int day)
15✔
2643
{
2644
        bool leap = false;
15✔
2645
        if (year % 100 == 0)
15✔
2646
                leap = (year % 400 == 0);
6✔
2647
        else
2648
                leap = (year % 4 == 0);
9✔
2649
        int y = year - 1;
15✔
2650
        int r = 365*y + intFloorDiv(y, 4) - intFloorDiv(y, 100) + intFloorDiv(y, 400) + (367*month-362)/12 + day;
15✔
2651
        if (month>2)
15✔
2652
                r += (leap ? -1 : -2);
9✔
2653

2654
        return r;
15✔
2655
}
2656

2657
int compareVersions(const QString v1, const QString v2)
6✔
2658
{
2659
        // result (-1: v1<v2; 0: v1==v2; 1: v1>v2)
2660
        int ver1, ver2, result = 0;
6✔
2661
        QStringList v1s = v1.split(".");        
6✔
2662
        QStringList v2s = v2.split(".");        
6✔
2663
        if (v1s.count()==3) // Full format: X.Y.Z
6✔
2664
                ver1 = v1s.at(0).toInt()*1000 + v1s.at(1).toInt()*100 + v1s.at(2).toInt();
3✔
2665
        else // Short format: X.Y
2666
                ver1 = v1s.at(0).toInt()*1000 + v1s.at(1).toInt()*100;
3✔
2667
        if (v2s.count()==3)
6✔
2668
                ver2 = v2s.at(0).toInt()*1000 + v2s.at(1).toInt()*100 + v2s.at(2).toInt();
3✔
2669
        else
2670
                ver2 = v2s.at(0).toInt()*1000 + v2s.at(1).toInt()*100;
3✔
2671

2672
        if (ver1<ver2)
6✔
2673
                result = -1;
2✔
2674
        else if (ver1 == ver2)
4✔
2675
                result = 0;
2✔
2676
        else if (ver1 > ver2)
2✔
2677
                result = 1;
2✔
2678

2679
        return result;
6✔
2680
}
6✔
2681

2682
int gcd(int a, int b)
×
2683
{
2684
        return b ? gcd(b, a % b) : a;
×
2685
}
2686

2687
int lcm(int a, int b)
×
2688
{
2689
        return (a*b/gcd(a, b));
×
2690
}
2691

2692
//! Uncompress gzip or zlib compressed data.
2693
QByteArray uncompress(const QByteArray& data)
×
2694
{
2695
        if (data.size() <= 4)
×
2696
                return QByteArray();
×
2697

2698
        //needed for const-correctness, no deep copy performed
2699
        QByteArray dataNonConst(data);
×
2700
        QBuffer buf(&dataNonConst);
×
2701
        buf.open(QIODevice::ReadOnly);
×
2702

2703
        return uncompress(buf);
×
2704
}
×
2705

2706
//! Uncompress (gzip/zlib) data from this QIODevice, which must be open and readable.
2707
//! @param device The device to read from, must already be opened with an OpenMode supporting reading
2708
//! @param maxBytes The max. amount of bytes to read from the device, or -1 to read until EOF.  Note that it
2709
//! always stops when inflate() returns Z_STREAM_END. Positive values can be used for interleaving compressed data
2710
//! with other data.
2711
QByteArray uncompress(QIODevice& device, qint64 maxBytes)
×
2712
{
2713
        // this is a basic zlib decompression routine, similar to:
2714
        // http://zlib.net/zlib_how.html
2715

2716
        // buffer size 256k, zlib recommended size
2717
        static const int CHUNK = 262144;
2718
        QByteArray readBuffer(CHUNK, 0);
×
2719
        QByteArray inflateBuffer(CHUNK, 0);
×
2720
        QByteArray out;
×
2721

2722
        // zlib stream
2723
        z_stream strm;
2724
        strm.zalloc = Q_NULLPTR;
×
2725
        strm.zfree = Q_NULLPTR;
×
2726
        strm.opaque = Q_NULLPTR;
×
2727
        strm.avail_in = Z_NULL;
×
2728
        strm.next_in = Q_NULLPTR;
×
2729

2730
        // the amount of bytes already read from the device
2731
        qint64 bytesRead = 0;
×
2732

2733
        // initialize zlib
2734
        // 15 + 32 for gzip automatic header detection.
2735
        int ret = inflateInit2(&strm, 15 +  32);
×
2736
        if (ret != Z_OK)
×
2737
        {
2738
                qWarning()<<"zlib init error ("<<ret<<"), can't uncompress";
×
2739
                if(strm.msg)
×
2740
                        qWarning()<<"zlib message: "<<QString(strm.msg);
×
2741
                return QByteArray();
×
2742
        }
2743

2744
        //zlib double loop - one for reading from file, one for inflating
2745
        do
2746
        {
2747
                qint64 bytesToRead = CHUNK;
×
2748
                if(maxBytes>=0)
×
2749
                {
2750
                        //check if we reach the desired limit with the next read
2751
                        bytesToRead = qMin(static_cast<qint64>(CHUNK),maxBytes-bytesRead);
×
2752
                }
2753

2754
                if(bytesToRead==0)
×
2755
                        break;
×
2756

2757
                //perform read from device
2758
                qint64 read = device.read(readBuffer.data(), bytesToRead);
×
2759
                if (read<0)
×
2760
                {
2761
                        qWarning()<<"Error while reading from device";
×
2762
                        inflateEnd(&strm);
×
2763
                        return QByteArray();
×
2764
                }
2765

2766
                bytesRead += read;
×
2767
                strm.next_in = reinterpret_cast<Bytef*>(readBuffer.data());
×
2768
                strm.avail_in = static_cast<unsigned int>(read);
×
2769

2770
                if(read==0)
×
2771
                        break;
×
2772

2773
                //inflate loop
2774
                do
2775
                {
2776
                        strm.avail_out = CHUNK;
×
2777
                        strm.next_out = reinterpret_cast<Bytef*>(inflateBuffer.data());
×
2778
                        ret = inflate(&strm,Z_NO_FLUSH);
×
2779
                        Q_ASSERT(ret != Z_STREAM_ERROR); // must never happen, indicates a programming error
×
2780

2781
                        if(ret < 0 || ret == Z_NEED_DICT)
×
2782
                        {
2783
                                qWarning()<<"zlib inflate error ("<<ret<<"), can't uncompress";
×
2784
                                if(strm.msg)
×
2785
                                        qWarning()<<"zlib message: "<<QString(strm.msg);
×
2786
                                inflateEnd(&strm);
×
2787
                                return QByteArray();
×
2788
                        }
2789

2790
                        out.append(inflateBuffer.constData(), CHUNK - static_cast<int>(strm.avail_out));
×
2791
                } while(strm.avail_out == 0); //if zlib has more data for us, repeat
×
2792
        } while(ret!=Z_STREAM_END);
×
2793

2794
        // close zlib
2795
        inflateEnd(&strm);
×
2796

2797
        if(ret!=Z_STREAM_END)
×
2798
        {
2799
                qWarning()<<"Premature end of compressed stream";
×
2800
                if(strm.msg)
×
2801
                        qWarning()<<"zlib message: "<<QString(strm.msg);
×
2802
                return QByteArray();
×
2803
        }
2804

2805
        return out;
×
2806
}
×
2807

2808
qint64 getLongLong(const QJsonValue& v)
×
2809
{
2810
        const auto reportError = [&v]{
×
2811
                qWarning().nospace() << "Cannot obtain an integer from JSON value "
×
2812
                                     << v << ". Please format it as a JSON string or"
×
2813
                                     " make sure it's an integer smaller than 2^53.";
×
2814
                return 0;
×
2815
        };
×
2816

2817
        bool ok = false;
×
2818
        if(v.isString())
×
2819
        {
2820
                const auto integer = v.toString().toLongLong(&ok);
×
2821
                if(!ok) return reportError();
×
2822
                return integer;
×
2823
        }
2824
        const auto value = v.toDouble();
×
2825
        constexpr qint64 max = (1LL<<std::numeric_limits<double>::digits) - 1;
×
2826

2827
        if(std::abs(value) > max) return reportError();
×
2828

2829
        const auto integer = static_cast<qint64>(value);
×
2830
        if(value != integer) // fractional part must be zero
×
2831
                return reportError();
×
2832
        return integer;
×
2833
}
2834

2835
} // end of the StelUtils namespace
2836

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