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 #ifdef CYGWIN
21 #include <malloc.h>
22 #endif
23
24 #include "StelUtils.hpp"
25 #include "VecMath.hpp"
26 #include "StelLocaleMgr.hpp"
27 #include <QBuffer>
28 #include <QString>
29 #include <QStringList>
30 #include <QTextStream>
31 #include <QFile>
32 #include <QDebug>
33 #include <QLocale>
34 #include <QRegularExpression>
35 #include <QProcess>
36 #include <QSysInfo>
37 #include <cmath> // std::fmod
38 #include <zlib.h>
39
40 namespace StelUtils
41 {
42 //! Return the full name of stellarium, i.e. "stellarium 0.19.0"
getApplicationName()43 QString getApplicationName()
44 {
45 return QString("Stellarium")+" "+StelUtils::getApplicationVersion();
46 }
47
48 //! Return the version of stellarium, i.e. "0.19.0"
getApplicationVersion()49 QString getApplicationVersion()
50 {
51 #if defined(STELLARIUM_VERSION)
52 return QString(STELLARIUM_VERSION);
53 #elif defined(GIT_REVISION)
54 return QString("%1-%2 [%3]").arg(PACKAGE_VERSION).arg(GIT_REVISION).arg(GIT_BRANCH);
55 #else
56 return QString(PACKAGE_VERSION);
57 #endif
58 }
59
getUserAgentString()60 QString getUserAgentString()
61 {
62 // Get info about operating system
63 QString os = StelUtils::getOperatingSystemInfo();
64 if (os.contains("FreeBSD"))
65 os = "FreeBSD";
66 else if (os.contains("NetBSD"))
67 os = "NetBSD";
68 else if (os.contains("OpenBSD"))
69 os = "OpenBSD";
70
71 // Set user agent as "Stellarium/$version$ ($operating system$; $CPU architecture$)"
72 return QString("Stellarium/%1 (%2; %3)").arg(StelUtils::getApplicationVersion(), os, QSysInfo::currentCpuArchitecture());
73 }
74
getOperatingSystemInfo()75 QString getOperatingSystemInfo()
76 {
77 QString OS = "Unknown operating system";
78
79 #if defined(Q_OS_BSD4) || defined(Q_OS_SOLARIS)
80 // Check FreeBSD, NetBSD, OpenBSD and DragonFly BSD
81 QProcess uname;
82 uname.start("/usr/bin/uname -srm");
83 uname.waitForStarted();
84 uname.waitForFinished();
85 const QString BSDsystem = uname.readAllStandardOutput();
86 OS = BSDsystem.trimmed();
87 #else
88 OS = QSysInfo::prettyProductName();
89 #endif
90
91 return OS;
92 }
93
hmsStrToHours(const QString & s)94 double hmsStrToHours(const QString& s)
95 {
96 QRegularExpression reg("(\\d+)h(\\d+)m(\\d+)s");
97 QRegularExpressionMatch match=reg.match(s);
98 if (!match.hasMatch())
99 return 0.;
100 uint hrs = match.captured(1).toUInt();
101 uint min = match.captured(2).toUInt();
102 int sec = match.captured(3).toInt();
103
104 return hmsToHours(hrs, min, sec);
105 }
106
107 /*************************************************************************
108 Convert a real duration in days to DHMS formatted string
109 *************************************************************************/
daysFloatToDHMS(float days)110 QString daysFloatToDHMS(float days)
111 {
112 float remain = days;
113
114 int d = static_cast<int> (remain); remain -= d;
115 remain *= 24.0f;
116 int h = static_cast<int> (remain); remain -= h;
117 remain *= 60.0f;
118 int m = static_cast<int> (remain); remain -= m;
119 remain *= 60.0f;
120
121 auto r = QString("%1%2 %3%4 %5%6 %7%8")
122 .arg(d) .arg(qc_("d", "duration"))
123 .arg(h) .arg(qc_("h", "duration"))
124 .arg(m) .arg(qc_("m", "duration"))
125 .arg(remain) .arg(qc_("s", "duration"));
126
127 return r;
128 }
129
130
131 /*************************************************************************
132 Convert an angle in radian to hms
133 *************************************************************************/
radToHms(double angle,unsigned int & h,unsigned int & m,double & s)134 void radToHms(double angle, unsigned int& h, unsigned int& m, double& s)
135 {
136 angle = std::fmod(angle,2.0*M_PI);
137 if (angle < 0.0) angle += 2.0*M_PI; // range: [0..2.0*M_PI)
138
139 angle *= 12./M_PI;
140
141 h = static_cast<unsigned int>(angle);
142 m = static_cast<unsigned int>((angle-h)*60);
143 s = (angle-h)*3600.-60.*m;
144 }
145
146 /*************************************************************************
147 Convert an angle in radian to dms
148 *************************************************************************/
radToDms(double angle,bool & sign,unsigned int & d,unsigned int & m,double & s)149 void radToDms(double angle, bool& sign, unsigned int& d, unsigned int& m, double& s)
150 {
151 angle = std::fmod(angle,2.0*M_PI);
152 sign=true;
153 if (angle<0)
154 {
155 angle *= -1;
156 sign = false;
157 }
158 angle *= M_180_PI;
159
160 d = static_cast<unsigned int>(angle);
161 m = static_cast<unsigned int>((angle - d)*60);
162 s = (angle-d)*3600-60*m;
163 // workaround for rounding numbers
164 if (s>59.9)
165 {
166 s = 0.;
167 m += 1;
168 }
169 if (m==60)
170 {
171 m = 0;
172 d += 1;
173 }
174 }
175
radToDecDeg(double rad,bool & sign,double & deg)176 void radToDecDeg(double rad, bool &sign, double °)
177 {
178 rad = std::fmod(rad,2.0*M_PI);
179 sign=true;
180 if (rad<0)
181 {
182 rad *= -1;
183 sign = false;
184 }
185 deg = rad*M_180_PI;
186 }
187
radToDecDegStr(const double angle,const int precision,const bool useD,const bool useC)188 QString radToDecDegStr(const double angle, const int precision, const bool useD, const bool useC)
189 {
190 const QChar degsign = (useD ? 'd' : 0x00B0);
191 bool sign;
192 double deg;
193 StelUtils::radToDecDeg(angle, sign, deg);
194 QString str = QString("%1%2%3").arg((sign?"+":"-"), QString::number(deg, 'f', precision), degsign);
195 if (useC)
196 {
197 if (!sign)
198 deg = 360. - deg;
199
200 str = QString("+%1%2").arg(QString::number(deg, 'f', precision), degsign);
201 }
202
203 return str;
204 }
205
206 /*************************************************************************
207 Convert an angle in radian to a hms formatted string
208 If the minute and second part are null are too small, don't print them
209 *************************************************************************/
radToHmsStrAdapt(const double angle)210 QString radToHmsStrAdapt(const double angle)
211 {
212 unsigned int h,m;
213 double s;
214 QString buf;
215 QTextStream ts(&buf);
216 StelUtils::radToHms(angle+0.005*M_PI/12/(60*60), h, m, s);
217 ts << h << 'h';
218 if (std::fabs(s*100-static_cast<int>(s)*100)>=1)
219 {
220 ts << m << 'm';
221 ts.setRealNumberNotation(QTextStream::FixedNotation);
222 ts.setPadChar('0');
223 ts.setFieldWidth(4);
224 ts.setRealNumberPrecision(1);
225 ts << s;
226 ts.reset();
227 ts << 's';
228 }
229 else if (static_cast<int>(s)!=0)
230 {
231 ts << m << 'm' << static_cast<int>(s) << 's';
232 }
233 else if (m!=0)
234 {
235 ts << m << 'm';
236 }
237 return buf;
238 }
239
240 /*************************************************************************
241 Convert an angle in radian to a hms formatted string
242 If decimal is true, output should be like this: " 16h29m55.3s"
243 If decimal is true, output should be like this: " 16h20m00.4s"
244 If decimal is false, output should be like this: " 0h26m5s"
245 *************************************************************************/
radToHmsStr(const double angle,const bool decimal)246 QString radToHmsStr(const double angle, const bool decimal)
247 {
248 unsigned int h,m;
249 double s;
250 StelUtils::radToHms(angle+0.005*M_PI/12/(60*60), h, m, s);
251 int width, precision;
252 QString carry, r;
253 if (decimal)
254 {
255 width=5;
256 precision=2;
257 carry="60.00";
258 }
259 else
260 {
261 width=4;
262 precision=1;
263 carry="60.0";
264 }
265
266 // handle carry case (when seconds are rounded up)
267 if (QString("%1").arg(s, 0, 'f', precision) == carry)
268 {
269 s=0.;
270 m+=1;
271 }
272 if (m==60)
273 {
274 m=0;
275 h+=1;
276 }
277 if (h==24 && m==0 && s==0.)
278 h=0;
279
280 return QString("%1h%2m%3s").arg(h, width).arg(m, 2, 10, QChar('0')).arg(s, 3+precision, 'f', precision, QChar('0'));
281 }
282
283 /*************************************************************************
284 Convert an angle in radian to a dms formatted string
285 If the minute and second part are null are too small, don't print them
286 *************************************************************************/
radToDmsStrAdapt(const double angle,const bool useD)287 QString radToDmsStrAdapt(const double angle, const bool useD)
288 {
289 const QChar degsign = (useD ? 'd' : 0x00B0);
290 bool sign;
291 unsigned int d,m;
292 double s;
293 StelUtils::radToDms(angle+0.005*M_PI/180/(60*60)*(angle<0?-1.:1.), sign, d, m, s); // NOTE: WTF???
294 QString str;
295 QTextStream os(&str);
296
297 os << (sign?'+':'-') << d << degsign;
298 if (std::fabs(s*100-static_cast<int>(s)*100)>=1)
299 {
300 os << m << '\'' << fixed << qSetRealNumberPrecision(2) << qSetFieldWidth(5) << qSetPadChar('0') << s << qSetFieldWidth(0) << '\"';
301 }
302 else if (static_cast<int>(s)!=0)
303 {
304 os << m << '\'' << static_cast<int>(s) << '\"';
305 }
306 else if (m!=0)
307 {
308 os << m << '\'';
309 }
310 //qDebug() << "radToDmsStrAdapt(" << angle << ", " << useD << ") = " << str;
311 return str;
312 }
313
314
315 /*************************************************************************
316 Convert an angle in radian to a dms formatted string
317 *************************************************************************/
radToDmsStr(const double angle,const bool decimal,const bool useD)318 QString radToDmsStr(const double angle, const bool decimal, const bool useD)
319 {
320 const int precision = decimal ? 1 : 0;
321 return StelUtils::radToDmsPStr(angle, precision, useD);
322 }
323
324 /*************************************************************************
325 Convert an angle in radian to a dms formatted string
326 *************************************************************************/
radToDmsPStr(const double angle,const int precision,const bool useD)327 QString radToDmsPStr(const double angle, const int precision, const bool useD)
328 {
329 const QChar degsign = (useD ? 'd' : 0x00B0);
330 bool sign;
331 unsigned int d,m;
332 double s;
333 StelUtils::radToDms(angle, sign, d, m, s);
334 QString str;
335 QTextStream os(&str);
336 os << (sign?'+':'-') << d << degsign;
337
338 os << qSetFieldWidth(2) << qSetPadChar('0') << m << qSetFieldWidth(0) << '\'';
339 int width = 2;
340 if (precision>0)
341 width = 3 + precision;
342 os << qSetRealNumberPrecision(precision);
343 os << fixed << qSetFieldWidth(width) << qSetPadChar('0') << s << qSetFieldWidth(0) << '\"';
344
345 return str;
346 }
347
decDegToDms(double angle,bool & sign,unsigned int & d,unsigned int & m,double & s)348 void decDegToDms(double angle, bool &sign, unsigned int &d, unsigned int &m, double &s)
349 {
350 sign = true;
351 if (angle<0.)
352 {
353 sign = false;
354 angle *= -1;
355 }
356
357 d = static_cast<unsigned int>(angle);
358 m = static_cast<unsigned int>((angle-d)*60);
359 s = (angle-d)*3600.-60.*m;
360
361 if (s>59.9)
362 {
363 s = 0.;
364 m += 1;
365 }
366 if (m==60)
367 {
368 m = 0;
369 d += 1;
370 }
371 }
372
373 // Convert an angle in decimal degrees to a dms formatted string
decDegToDmsStr(const double angle)374 QString decDegToDmsStr(const double angle)
375 {
376 bool sign;
377 double s;
378 unsigned int d, m;
379 decDegToDms(angle, sign, d, m, s);
380 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'));
381 }
382
383 // Convert a dms formatted string to an angle in radian
dmsStrToRad(const QString & s)384 double dmsStrToRad(const QString& s)
385 {
386 QRegularExpression reg("([\\+\\-])(\\d+)d(\\d+)'(\\d+)\"");
387 QRegularExpressionMatch match=reg.match(s);
388 if (!match.hasMatch())
389 return 0;
390 bool sign = (match.captured(1) == "-");
391 int deg = match.captured(2).toInt();
392 uint min = match.captured(3).toUInt();
393 int sec = match.captured(4).toInt();
394
395 double rad = dmsToRad(qAbs(deg), min, sec);
396 if (sign)
397 rad *= -1;
398
399 return rad;
400 }
401
getDecAngle(const QString & str)402 double getDecAngle(const QString& str)
403 {
404 static const QString reStr("([-+]?)\\s*" // [sign] (1)
405 "(?:" // either
406 "(\\d+(?:\\.\\d+)?)\\s*" // fract (2)
407 "([dhms°º]?)" // [dhms] (3) \u00B0\u00BA
408 "|" // or
409 "(?:(\\d+)\\s*([hHdD°º])\\s*)?" // [int degs] (4) (5)
410 "(?:" // either
411 "(?:(\\d+)\\s*['mM]\\s*)?" // [int mins] (6)
412 "(\\d+(?:\\.\\d+)?)\\s*[\"sS]" // fract secs (7)
413 "|" // or
414 "(\\d+(?:\\.\\d+)?)\\s*['mM]" // fract mins (8)
415 ")" // end
416 ")" // end
417 "\\s*([NSEW]?)" // [point] (9)
418 );
419
420 #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
421 QRegularExpression rex(QRegularExpression::anchoredPattern(reStr), QRegularExpression::CaseInsensitiveOption);
422 QRegularExpressionMatch match=rex.match(str);
423 if( match.hasMatch() )
424 {
425 QStringList caps = match.capturedTexts();
426 #else
427 QRegExp rex(reStr, Qt::CaseInsensitive);
428 if( rex.exactMatch(str) )
429 {
430 QStringList caps = rex.capturedTexts();
431 #endif
432 #if 0
433 qDebug() << "reg exp: ";
434 for( int i = 1; i <= rex.captureCount() ; ++i ){
435 qDebug() << i << "=\"" << caps.at(i) << "\" ";
436 }
437 #endif
438 double d = 0;
439 double m = 0;
440 double s = 0;
441 ushort hd = caps.at(5).isEmpty() ? 'd' : caps.at(5).toLower().at(0).unicode();
442 QString pointStr = caps.at(9).toUpper() + " ";
443 if( caps.at(7) != "" )
444 {
445 // [dh, degs], [m] and s entries at 4, 5, 6, 7
446 d = caps.at(4).toDouble();
447 m = caps.at(6).toDouble();
448 s = caps.at(7).toDouble();
449 }
450 else if( caps.at(8) != "" )
451 {
452 // [dh, degs] and m entries at 4, 5, 8
453 d = caps.at(4).toDouble();
454 m = caps.at(8).toDouble();
455 }
456 else if( caps.at(2) != "" )
457 {
458 // some value at 2, dh|m|s at 3
459 double x = caps.at(2).toDouble();
460 QString sS = caps.at(3) + caps.at(9);
461 switch( sS.length() )
462 {
463 case 0:
464 // degrees, no point
465 hd = 'd';
466 break;
467 case 1:
468 // NnSEeWw is point for degrees, "dhms°..." distinguish dhms
469 if( QString("NnSEeWw").contains(sS.at(0)) )
470 {
471 pointStr = sS.toUpper();
472 hd = 'd';
473 }
474 else
475 hd = sS.toLower().at(0).unicode();
476 break;
477 case 2:
478 // hdms selected by 1st char, NSEW by 2nd
479 hd = sS.at(0).toLower().unicode();
480 pointStr = sS.right(1).toUpper();
481 break;
482 }
483 switch( hd )
484 {
485 case 'h':
486 case 'd':
487 case 0x00B0:
488 case 0x00BA:
489 d = x;
490 break;
491 case 'm':
492 case '\'':
493 m = x;
494 break;
495 case 's':
496 case '"':
497 s = x;
498 break;
499 default:
500 qDebug() << "internal error, hd = " << hd;
501 }
502 }
503 else
504 {
505 qDebug() << "getDecAngle failed to parse angle string: " << str;
506 return -0.0;
507 }
508
509 // General sign handling: group 1 or overruled by point
510 int sgn = caps.at(1) == "-" ? -1 : 1;
511 bool isNS = false;
512 switch( pointStr.at(0).unicode() )
513 {
514 case 'N':
515 sgn = 1;
516 isNS = 1;
517 break;
518 case 'S':
519 sgn = -1;
520 isNS = 1;
521 break;
522 case 'E':
523 sgn = 1;
524 break;
525 case 'W':
526 sgn = -1;
527 break;
528 default: // OK, there is no NSEW.
529 break;
530 }
531
532 int h2d = 1;
533 if( hd == 'h' )
534 {
535 // Sanity check - h and N/S not accepted together
536 if( isNS )
537 {
538 qDebug() << "getDecAngle does not accept ...H...N/S: " << str;
539 return -0.0;
540 }
541 h2d = 15;
542 }
543 double deg = (d + (m/60) + (s/3600))*h2d*sgn;
544 return deg * 2 * M_PI / 360.;
545 }
546
547 qDebug() << "getDecAngle failed to parse angle string: " << str;
548 return -0.0;
549 }
550
551 // Return the first power of two bigger than the given value
552 int getBiggerPowerOfTwo(int value)
553 {
554 int p=1;
555 while (p<value)
556 p<<=1;
557 return p;
558 }
559
560 /*************************************************************************
561 Convert a QT QDateTime class to julian day
562 *************************************************************************/
563
564 QDateTime jdToQDateTime(const double& jd)
565 {
566 int year, month, day;
567 getDateFromJulianDay(jd, &year, &month, &day);
568 QDateTime result = QDateTime::fromString(QString("%1.%2.%3").arg(year, 4, 10, QLatin1Char('0')).arg(month).arg(day), "yyyy.M.d");
569 result.setTime(jdFractionToQTime(jd));
570 return result;
571 }
572
573 void getDateFromJulianDay(const double jd, int *yy, int *mm, int *dd)
574 {
575 /*
576 * This algorithm is taken from
577 * "Numerical Recipes in C, 2nd Ed." (1992), pp. 14-15
578 * and converted to integer math.
579 * The electronic version of the book is freely available
580 * at http://www.nr.com/ , under "Obsolete Versions - Older
581 * book and code versions".
582 */
583
584 static const long JD_GREG_CAL = 2299161;
585 static const int JB_MAX_WITHOUT_OVERFLOW = 107374182;
586 const long julian = static_cast<long>(floor(jd + 0.5));
587
588 long ta, jalpha, tb, tc, td, te;
589
590 if (julian >= JD_GREG_CAL)
591 {
592 jalpha = (4*(julian - 1867216) - 1) / 146097;
593 ta = julian + 1 + jalpha - jalpha / 4;
594 }
595 else if (julian < 0)
596 {
597 ta = julian + 36525 * (1 - julian / 36525);
598 }
599 else
600 {
601 ta = julian;
602 }
603
604 tb = ta + 1524;
605 if (tb <= JB_MAX_WITHOUT_OVERFLOW)
606 {
607 tc = (tb*20 - 2442) / 7305;
608 }
609 else
610 {
611 tc = static_cast<long>((static_cast<unsigned long long>(tb)*20 - 2442) / 7305);
612 }
613 td = 365 * tc + tc/4;
614 te = ((tb - td) * 10000)/306001;
615
616 *dd = tb - td - (306001 * te) / 10000;
617
618 *mm = te - 1;
619 if (*mm > 12)
620 {
621 *mm -= 12;
622 }
623 *yy = tc - 4715;
624 if (*mm > 2)
625 {
626 --(*yy);
627 }
628 if (julian < 0)
629 {
630 *yy -= 100 * (1 - julian / 36525);
631 }
632 }
633
634 void getTimeFromJulianDay(const double julianDay, int *hour, int *minute, int *second, int *millis)
635 {
636 double frac = julianDay - (floor(julianDay));
637 double secs = frac * 24.0 * 60.0 * 60.0 + 0.0001; // add constant to fix floating-point truncation error
638 int s = static_cast<int>(floor(secs));
639
640 *hour = ((s / (60 * 60))+12)%24;
641 *minute = (s/(60))%60;
642 *second = s % 60;
643 if(millis)
644 {
645 *millis = static_cast<int>(floor((secs - floor(secs)) * 1000.0));
646 }
647 }
648
649 double getHoursFromJulianDay(const double julianDay)
650 {
651 int hr, min, sec, millis;
652 getTimeFromJulianDay(julianDay, &hr, &min, &sec, &millis);
653 return static_cast<double>(hr)+static_cast<double>(min)/60.+static_cast<double>(sec + millis/1000.)/3600.;
654 }
655
656
657 QString julianDayToISO8601String(const double jd, bool addMS)
658 {
659 int year, month, day, hour, minute, second, millis=0;
660 getDateFromJulianDay(jd, &year, &month, &day);
661 getTimeFromJulianDay(jd, &hour, &minute, &second, addMS ? &millis : Q_NULLPTR );
662
663 QString res = QString("%1-%2-%3T%4:%5:%6")
664 .arg((year >= 0 ? year : -1* year),4,10,QLatin1Char('0'))
665 .arg(month,2,10,QLatin1Char('0'))
666 .arg(day,2,10,QLatin1Char('0'))
667 .arg(hour,2,10,QLatin1Char('0'))
668 .arg(minute,2,10,QLatin1Char('0'))
669 .arg(second,2,10,QLatin1Char('0'));
670
671 if(addMS)
672 {
673 res.append(".%1").arg(millis,3,10,QLatin1Char('0'));
674 }
675 if (year < 0)
676 {
677 res.prepend("-");
678 }
679 return res;
680 }
681
682 // Format the date per the fmt.
683 QString localeDateString(const int year, const int month, const int day, const int dayOfWeek, const QString &fmt)
684 {
685 /* we have to handle the year zero, and the years before qdatetime can represent. */
686 const QLatin1Char quote('\'');
687 QString out;
688 int quotestartedat = -1;
689
690 for (int i = 0; i < fmt.length(); i++)
691 {
692 if (fmt.at(i) == quote)
693 {
694 if (quotestartedat >= 0)
695 {
696 if ((quotestartedat+1) == i)
697 {
698 out += quote;
699 quotestartedat = -1;
700 }
701 else
702 {
703 quotestartedat = -1;
704 }
705 }
706 else
707 {
708 quotestartedat = i;
709 }
710 }
711 else if (quotestartedat > 0)
712 {
713 out += fmt.at(i);
714 }
715 else if (fmt.at(i) == QLatin1Char('d') ||
716 fmt.at(i) == QLatin1Char('M') ||
717 fmt.at(i) == QLatin1Char('y'))
718 {
719 int j = i+1;
720 while ((j < fmt.length()) && (fmt.at(j) == fmt.at(i)) && (4 >= (j-i+1)))
721 {
722 j++;
723 }
724
725 QString frag = fmt.mid(i,(j-i));
726
727 if (frag == "d")
728 {
729 out += QString("%1").arg(day);
730 }
731 else if (frag == "dd")
732 {
733 out += QString("%1").arg(day, 2, 10, QLatin1Char('0'));
734 }
735 else if (frag == "ddd")
736 {
737 out += StelLocaleMgr::shortDayName(dayOfWeek+1);
738 }
739 else if (frag == "dddd")
740 {
741 out += StelLocaleMgr::longDayName(dayOfWeek+1);
742 }
743 else if (frag == "M")
744 {
745 out += QString("%1").arg(month);
746 }
747 else if (frag == "MM")
748 {
749 out += QString("%1").arg(month, 2, 10, QLatin1Char('0'));
750 }
751 else if (frag == "MMM")
752 {
753 out += StelLocaleMgr::shortMonthName(month);
754 }
755 else if (frag == "MMMM")
756 {
757 out += StelLocaleMgr::longMonthName(month);
758 }
759 else if (frag == "y")
760 {
761 out += frag;
762 }
763 else if (frag == "yy")
764 {
765 int dispyear = year % 100;
766 out += QString("%1").arg(dispyear,2,10,QLatin1Char('0'));
767 }
768 else if (frag == "yyy")
769 {
770 // assume greedy: understand yy before y.
771 int dispyear = year % 100;
772 out += QString("%1").arg(dispyear,2,10,QLatin1Char('0'));
773 out += QLatin1Char('y');
774 }
775 else if (frag == "yyyy")
776 {
777 int dispyear = abs(year);
778 if (year < 0)
779 {
780 out += QLatin1Char('-');
781 }
782 out += QString("%1").arg(dispyear,4,10,QLatin1Char('0'));
783 }
784
785 i = j-1;
786 }
787 else
788 {
789 out += fmt.at(i);
790 }
791 }
792
793 return out;
794 }
795
796 //! try to get a reasonable locale date string from the system, trying to work around
797 //! limitations of qdatetime for large dates in the past. see QDateTime::toString().
798 QString localeDateString(const int year, const int month, const int day, const int dayOfWeek)
799 {
800 // try the QDateTime first
801 QDate test(year, month, day);
802
803 // try to avoid QDate's non-astronomical time here, don't do BCE or year 0.
804 if (year > 0 && test.isValid() && !test.toString(Qt::DefaultLocaleShortDate).isEmpty())
805 {
806 return test.toString(Qt::DefaultLocaleShortDate);
807 }
808 else
809 {
810 return localeDateString(year,month,day,dayOfWeek,QLocale().dateFormat(QLocale::ShortFormat));
811 }
812 }
813
814 int getDayOfWeek(int year, int month, int day)
815 {
816 double JD;
817 getJDFromDate(&JD, year, month, day, 0, 0, 0);
818 return getDayOfWeek(JD);
819 }
820
821 //! use QDateTime to get a Julian Date from the system's current time.
822 //! this is an acceptable use of QDateTime because the system's current
823 //! time is more than likely always going to be expressible by QDateTime.
824 double getJDFromSystem()
825 {
826 return qDateTimeToJd(QDateTime::currentDateTime().toUTC());
827 }
828
829 double getJDFromBesselianEpoch(const double epoch)
830 {
831 return 2400000.5 + (15019.81352 + (epoch - 1900.0) * 365.242198781);
832 }
833
834 double qTimeToJDFraction(const QTime& time)
835 {
836 return static_cast<double>(1./(24*60*60*1000)*QTime(0, 0, 0, 0).msecsTo(time))-0.5;
837 }
838
839 QTime jdFractionToQTime(const double jd)
840 {
841 double decHours = std::fmod(jd+0.5, 1.0);
842 int hours = static_cast<int>(decHours/0.041666666666666666666);
843 int mins = static_cast<int>((decHours-(hours*0.041666666666666666666))/0.00069444444444444444444);
844 return QTime::fromString(QString("%1.%2").arg(hours).arg(mins), "h.m");
845 }
846
847 // UTC !
848 bool getJDFromDate(double* newjd, const int y, const int m, const int d, const int h, const int min, const float s)
849 {
850 static const long IGREG2 = 15+31L*(10+12L*1582);
851 double deltaTime = (h / 24.0) + (min / (24.0*60.0)) + (static_cast<double>(s) / (24.0 * 60.0 * 60.0)) - 0.5;
852 QDate test((y <= 0 ? y-1 : y), m, d);
853 // if QDate will oblige, do so.
854 // added hook for Julian calendar, because it has been removed from Qt5 --AW
855 if ( test.isValid() && y>1582)
856 {
857 double qdjd = static_cast<double>(test.toJulianDay());
858 qdjd += deltaTime;
859 *newjd = qdjd;
860 return true;
861 }
862 else
863 {
864 /*
865 * Algorithm taken from "Numerical Recipes in C, 2nd Ed." (1992), pp. 11-12
866 */
867 long ljul;
868 long jy, jm;
869 long laa, lbb, lcc, lee;
870
871 jy = y;
872 if (m > 2)
873 {
874 jm = m + 1;
875 }
876 else
877 {
878 --jy;
879 jm = m + 13;
880 }
881
882 laa = 1461 * jy / 4;
883 if (jy < 0 && jy % 4)
884 {
885 --laa;
886 }
887 lbb = 306001 * jm / 10000;
888 ljul = laa + lbb + d + 1720995L;
889
890 if (d + 31L*(m + 12L * y) >= IGREG2)
891 {
892 lcc = jy/100;
893 if (jy < 0 && jy % 100)
894 {
895 --lcc;
896 }
897 lee = lcc/4;
898 if (lcc < 0 && lcc % 4)
899 {
900 --lee;
901 }
902 ljul += 2 - lcc + lee;
903 }
904 double jd = static_cast<double>(ljul);
905 jd += deltaTime;
906 *newjd = jd;
907 return true;
908 }
909 }
910
911 double getJDFromDate_alg2(const int y, const int m, const int d, const int h, const int min, const int s)
912 {
913 double extra = (100.0* y) + m - 190002.5;
914 double rjd = 367.0 * y;
915 rjd -= floor(7.0*(y+floor((m+9.0)/12.0))/4.0);
916 rjd += floor(275.0*m/9.0) ;
917 rjd += d;
918 rjd += (h + (min + s/60.0)/60.)/24.0;
919 rjd += 1721013.5;
920 rjd -= 0.5*extra/std::fabs(extra);
921 rjd += 0.5;
922 return rjd;
923 }
924
925 int numberOfDaysInMonthInYear(const int month, const int year)
926 {
927 switch(month)
928 {
929 case 1:
930 case 3:
931 case 5:
932 case 7:
933 case 8:
934 case 10:
935 case 12:
936 return 31;
937 case 4:
938 case 6:
939 case 9:
940 case 11:
941 return 30;
942 case 2:
943 if ( year > 1582 )
944 {
945 if ( year % 4 == 0 )
946 {
947 if ( year % 100 == 0 )
948 {
949 return ( year % 400 == 0 ? 29 : 28 );
950 }
951 else
952 {
953 return 29;
954 }
955 }
956 else
957 {
958 return 28;
959 }
960 }
961 else
962 {
963 return ( year % 4 == 0 ? 29 : 28 );
964 }
965 case 0:
966 return numberOfDaysInMonthInYear(12, year-1);
967 case 13:
968 return numberOfDaysInMonthInYear(1, year+1);
969 default:
970 break;
971 }
972
973 return 0;
974 }
975
976 // return true if year is a leap year. Observes 1582 switch from Julian to Gregorian Calendar.
977 bool isLeapYear(const int year)
978 {
979 if (year>1582)
980 {
981 if (year % 100 == 0)
982 return (year % 400 == 0);
983 else
984 return (year % 4 == 0);
985 }
986 else
987 return (year % 4 == 0); // astronomical year counting: strictly every 4th year.
988 }
989
990 // Find day number for date in year.
991 // Meeus, AA 2nd, 1998, ch.7 p.65
992 int dayInYear(const int year, const int month, const int day)
993 {
994 int k=(isLeapYear(year) ? 1:2);
995 return static_cast<int>(275*month/9) - k*static_cast<int>((month+9)/12) + day -30;
996 }
997
998 // Return a fractional year like YYYY.ddddd. For negative years, the year number is of course decrease. E.g. -500.5 occurs in -501.
999 double yearFraction(const int year, const int month, const double day)
1000 {
1001 double d=dayInYear(year, month, 0)+day;
1002 double daysInYear=( isLeapYear(year) ? 366.0 : 365.0);
1003 return year+d/daysInYear;
1004 }
1005
1006 //! given the submitted year/month/day hour:minute:second, try to
1007 //! normalize into an actual year/month/day. values can be positive, 0,
1008 //! or negative. start assessing from seconds to larger increments.
1009 bool changeDateTimeForRollover(int oy, int om, int od, int oh, int omin, int os,
1010 int* ry, int* rm, int* rd, int* rh, int* rmin, int* rs)
1011 {
1012 bool change = false;
1013
1014 while ( os > 59 ) {
1015 os -= 60;
1016 omin += 1;
1017 change = true;
1018 }
1019 while ( os < 0 ) {
1020 os += 60;
1021 omin -= 1;
1022 change = true;
1023 }
1024
1025 while (omin > 59 ) {
1026 omin -= 60;
1027 oh += 1;
1028 change = true;
1029 }
1030 while (omin < 0 ) {
1031 omin += 60;
1032 oh -= 1;
1033 change = true;
1034 }
1035
1036 while ( oh > 23 ) {
1037 oh -= 24;
1038 od += 1;
1039 change = true;
1040 }
1041 while ( oh < 0 ) {
1042 oh += 24;
1043 od -= 1;
1044 change = true;
1045 }
1046
1047 while ( od > numberOfDaysInMonthInYear(om, oy) ) {
1048 od -= numberOfDaysInMonthInYear(om, oy);
1049 om++;
1050 if ( om > 12 ) {
1051 om -= 12;
1052 oy += 1;
1053 }
1054 change = true;
1055 }
1056 while ( od < 1 ) {
1057 od += numberOfDaysInMonthInYear(om-1,oy);
1058 om--;
1059 if ( om < 1 ) {
1060 om += 12;
1061 oy -= 1;
1062 }
1063 change = true;
1064 }
1065
1066 while ( om > 12 ) {
1067 om -= 12;
1068 oy += 1;
1069 change = true;
1070 }
1071 while ( om < 1 ) {
1072 om += 12;
1073 oy -= 1;
1074 change = true;
1075 }
1076
1077 // and the julian-gregorian epoch hole: round up to the 15th
1078 if ( oy == 1582 && om == 10 && ( od > 4 && od < 15 ) ) {
1079 od = 15;
1080 change = true;
1081 }
1082
1083 if ( change ) {
1084 *ry = oy;
1085 *rm = om;
1086 *rd = od;
1087 *rh = oh;
1088 *rmin = omin;
1089 *rs = os;
1090 }
1091 return change;
1092 }
1093
1094 void debugQVariantMap(const QVariant& m, const QString& indent, const QString& key)
1095 {
1096 QVariant::Type t = m.type();
1097 if (t == QVariant::Map)
1098 {
1099 qDebug() << indent + key + "(map):";
1100 QList<QString> keys = m.toMap().keys();
1101 std::sort(keys.begin(), keys.end());
1102 for (auto k : keys)
1103 {
1104 debugQVariantMap(m.toMap()[k], indent + " ", k);
1105 }
1106 }
1107 else if (t == QVariant::List)
1108 {
1109 qDebug() << indent + key + "(list):";
1110 for (const auto& item : m.toList())
1111 {
1112 debugQVariantMap(item, indent + " ");
1113 }
1114 }
1115 else
1116 qDebug() << indent + key + " => " + m.toString();
1117 }
1118
1119 double getJulianDayFromISO8601String(const QString& iso8601Date, bool* ok)
1120 {
1121 int y, m, d, h, min;
1122 float s;
1123 *ok = getDateTimeFromISO8601String(iso8601Date, &y, &m, &d, &h, &min, &s);
1124 if (*ok)
1125 {
1126 double jd;
1127 if (!StelUtils::getJDFromDate(&jd, y, m, d, h, min, s))
1128 {
1129 *ok = false;
1130 return 0.0;
1131 }
1132 return jd;
1133 }
1134 return 0.0;
1135 }
1136
1137 bool getDateTimeFromISO8601String(const QString& iso8601Date, int* y, int* m, int* d, int* h, int* min, float* s)
1138 {
1139 // Represents an ISO8601 complete date string.
1140 QRegularExpression finalRe("^([+\\-]?\\d+)[:\\-](\\d\\d)[:\\-](\\d\\d)T(\\d?\\d):(\\d\\d):(\\d\\d(?:\\.\\d*)?)$");
1141 QRegularExpressionMatch match=finalRe.match(iso8601Date);
1142 if (match.hasMatch() && finalRe.captureCount()==6)
1143 {
1144 bool error = false;
1145 bool ok;
1146 *y = match.captured(1).toInt(&ok);
1147 error = error || !ok;
1148 *m = match.captured(2).toInt(&ok);
1149 error = error || !ok;
1150 *d = match.captured(3).toInt(&ok);
1151 error = error || !ok;
1152 *h = match.captured(4).toInt(&ok);
1153 error = error || !ok;
1154 *min = match.captured(5).toInt(&ok);
1155 error = error || !ok;
1156 *s = match.captured(6).toFloat(&ok);
1157 error = error || !ok;
1158 if (!error)
1159 return true;
1160 }
1161 return false;
1162 }
1163
1164 QString hoursToHmsStr(const double hours, const bool lowprecision)
1165 {
1166 int h = static_cast<int>(hours);
1167 double minutes = (qAbs(hours)-qAbs(double(h)))*60.;
1168 if (lowprecision)
1169 {
1170 int m = qRound(minutes);
1171 if (m==60)
1172 {
1173 h += 1;
1174 m = 0;
1175 }
1176 return QString("%1h%2m").arg(h).arg(m, 2, 10, QChar('0'));
1177 }
1178 else
1179 {
1180 int m = static_cast<int>(minutes);
1181 float s = static_cast<float>((((qAbs(hours)-qAbs(double(h)))*60.)-m)*60.);
1182 if (s>59.9f)
1183 {
1184 m += 1;
1185 s = 0.f;
1186 }
1187 if (m==60)
1188 {
1189 h += 1;
1190 m = 0;
1191 }
1192 return QString("%1h%2m%3s").arg(h).arg(m, 2, 10, QChar('0')).arg(s, 4, 'f', 1, QChar('0'));
1193 }
1194 }
1195
1196 QString hoursToHmsStr(const float hours, const bool lowprecision)
1197 {
1198 return hoursToHmsStr(static_cast<double>(hours), lowprecision);
1199 }
1200
1201 /* /////////////////// DELTA T VARIANTS
1202 // For the standard epochs for many formulae, we use
1203 // J2000.0=2000-jan-1.5=2451545.0,
1204 // 1900.0=1900-jan-0.5=2415020.0
1205 // 1820.0=1820-jan-0.5=2385800.0
1206 // 1810.0=1810-jan-0.5=2382148.0
1207 // 1800.0=1800-jan-0.5=2378496.0
1208 // 1735.0=1735-jan-0.5=2354755.0
1209 // 1625.0=1625-jan-0.5=2314579.0
1210 //
1211 // Up to V0.15.1, if the requested year was outside validity range, we returned zero or some useless value.
1212 // Starting with V0.15.2 the value from the edge of the range is returned instead.
1213 */
1214
1215 double getDeltaTwithoutCorrection(const double jDay)
1216 {
1217 Q_UNUSED(jDay)
1218 return 0.;
1219 }
1220
1221 // Implementation of algorithm by Espenak & Meeus (2006) for DeltaT computation
1222 double getDeltaTByEspenakMeeus(const double jDay)
1223 {
1224 int year, month, day;
1225 getDateFromJulianDay(jDay, &year, &month, &day);
1226
1227 // Note: the method here is adapted from
1228 // "Five Millennium Canon of Solar Eclipses" [Espenak and Meeus, 2006]
1229 // A summary is described here:
1230 // http://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html
1231
1232 double y = yearFraction(year, month, day);
1233
1234 // set the default value for Delta T
1235 double u = (y-1820)/100.;
1236 double r = (-20 + 32 * u * u);
1237
1238 if (y < -500)
1239 {
1240 // values are equal to defaults!
1241 // u = (y-1820)/100.;
1242 // r = (-20 + 32 * u * u);
1243 }
1244 else if (y < 500)
1245 {
1246 u = y/100;
1247 //r = (10583.6 - 1014.41 * u + 33.78311 * std::pow(u,2) - 5.952053 * std::pow(u,3)
1248 // - 0.1798452 * std::pow(u,4) + 0.022174192 * std::pow(u,5) + 0.0090316521 * std::pow(u,6));
1249 r = (((((0.0090316521*u + 0.022174192)*u - 0.1798452)*u - 5.952053)*u + 33.78311)*u -1014.41)*u +10583.6;
1250 }
1251 else if (y < 1600)
1252 {
1253 u = (y-1000)/100;
1254 //r = (1574.2 - 556.01 * u + 71.23472 * std::pow(u,2) + 0.319781 * std::pow(u,3)
1255 // - 0.8503463 * std::pow(u,4) - 0.005050998 * std::pow(u,5) + 0.0083572073 * std::pow(u,6));
1256 r = (((((0.0083572073*u - 0.005050998)*u -0.8503463)*u +0.319781)*u + 71.23472)*u -556.01)*u + 1574.2;
1257 }
1258 else if (y < 1700)
1259 {
1260 double t = y - 1600;
1261 //r = (120 - 0.9808 * t - 0.01532 * std::pow(t,2) + std::pow(t,3) / 7129);
1262 r = ((t/7129.0 - 0.01532)*t - 0.9808)*t +120.0;
1263 }
1264 else if (y < 1800)
1265 {
1266 double t = y - 1700;
1267 //r = (8.83 + 0.1603 * t - 0.0059285 * std::pow(t,2) + 0.00013336 * std::pow(t,3) - std::pow(t,4) / 1174000);
1268 r = (((-t/1174000.0 + 0.00013336)*t - 0.0059285)*t + 0.1603)*t +8.83;
1269 }
1270 else if (y < 1860)
1271 {
1272 double t = y - 1800;
1273 //r = (13.72 - 0.332447 * t + 0.0068612 * std::pow(t,2) + 0.0041116 * std::pow(t,3) - 0.00037436 * std::pow(t,4)
1274 // + 0.0000121272 * std::pow(t,5) - 0.0000001699 * std::pow(t,6) + 0.000000000875 * std::pow(t,7));
1275 r = ((((((.000000000875*t -.0000001699)*t + 0.0000121272)*t - 0.00037436)*t + 0.0041116)*t + 0.0068612)*t - 0.332447)*t +13.72;
1276 }
1277 else if (y < 1900)
1278 {
1279 double t = y - 1860;
1280 //r = (7.62 + 0.5737 * t - 0.251754 * std::pow(t,2) + 0.01680668 * std::pow(t,3)
1281 // -0.0004473624 * std::pow(t,4) + std::pow(t,5) / 233174);
1282 r = ((((t/233174.0 -0.0004473624)*t + 0.01680668)*t - 0.251754)*t + 0.5737)*t + 7.62;
1283 }
1284 else if (y < 1920)
1285 {
1286 double t = y - 1900;
1287 //r = (-2.79 + 1.494119 * t - 0.0598939 * std::pow(t,2) + 0.0061966 * std::pow(t,3) - 0.000197 * std::pow(t,4));
1288 r = (((-0.000197*t + 0.0061966)*t - 0.0598939)*t + 1.494119)*t -2.79;
1289 }
1290 else if (y < 1941)
1291 {
1292 double t = y - 1920;
1293 //r = (21.20 + 0.84493*t - 0.076100 * std::pow(t,2) + 0.0020936 * std::pow(t,3));
1294 r = ((0.0020936*t - 0.076100)*t+ 0.84493)*t +21.20;
1295 }
1296 else if (y < 1961)
1297 {
1298 double t = y - 1950;
1299 //r = (29.07 + 0.407*t - std::pow(t,2)/233 + std::pow(t,3) / 2547);
1300 r = ((t/2547.0 -1.0/233.0)*t + 0.407)*t +29.07;
1301 }
1302 else if (y < 1986)
1303 {
1304 double t = y - 1975;
1305 //r = (45.45 + 1.067*t - std::pow(t,2)/260 - std::pow(t,3) / 718);
1306 r = ((-t/718.0 -1/260.0)*t + 1.067)*t +45.45;
1307 }
1308 else if (y < 2005)
1309 {
1310 double t = y - 2000;
1311 //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));
1312 r = ((((0.00002373599*t + 0.000651814)*t + 0.0017275)*t - 0.060374)*t + 0.3345)*t +63.86;
1313 }
1314 else if (y < 2050)
1315 {
1316 double t = y - 2000;
1317 //r = (62.92 + 0.32217 * t + 0.005589 * std::pow(t,2));
1318 r = (0.005589*t +0.32217)*t + 62.92;
1319 }
1320 else if (y < 2150)
1321 {
1322 //r = (-20 + 32 * std::pow((y-1820)/100,2) - 0.5628 * (2150 - y));
1323 // r has been precomputed before, just add the term patching the discontinuity
1324 r -= 0.5628*(2150.0-y);
1325 }
1326
1327 return r;
1328 }
1329
1330 // Implementation of algorithm by Schoch (1931) for DeltaT computation
1331 double getDeltaTBySchoch(const double jDay)
1332 {
1333 double u=(jDay-2378496.0)/36525.0; // (1800-jan-0.5)
1334 return -36.28 + 36.28*u*u;
1335 }
1336
1337 // Implementation of algorithm by Clemence (1948) for DeltaT computation
1338 double getDeltaTByClemence(const double jDay)
1339 {
1340 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1341 return +8.72 + 26.75*u + 11.22*u*u;
1342 }
1343
1344 // Implementation of algorithm by IAU (1952) for DeltaT computation
1345 double getDeltaTByIAU(const double jDay)
1346 {
1347 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1348 return (29.950*u +72.318)*u +24.349 + 1.82144*getMoonFluctuation(jDay) ;
1349 }
1350
1351 // Implementation of algorithm by Astronomical Ephemeris (1960) for DeltaT computation, also used by Mucke&Meeus, Canon of Solar Eclipses, Vienna 1983
1352 double getDeltaTByAstronomicalEphemeris(const double jDay)
1353 {
1354 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1355 // TODO: Calculate Moon's longitude fluctuation
1356 // Note: also Mucke&Meeus 1983 ignore b
1357 return (29.949*u +72.3165)*u +24.349 /* + 1.821*b*/ ;
1358 }
1359
1360 // Implementation of algorithm by Tuckerman (1962, 1964) & Goldstine (1973) for DeltaT computation
1361 double getDeltaTByTuckermanGoldstine(const double jDay)
1362 {
1363 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1364 return (36.79*u +35.06)*u + 4.87;
1365 }
1366
1367 // Implementation of algorithm by Muller & Stephenson (1975) for DeltaT computation
1368 double getDeltaTByMullerStephenson(const double jDay)
1369 {
1370 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1371 return (45.78*u +120.38)*u +66.0;
1372 }
1373
1374 // Implementation of algorithm by Stephenson (1978) for DeltaT computation
1375 double getDeltaTByStephenson1978(const double jDay)
1376 {
1377 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1378 return (38.30*u +114.0)*u +20.0;
1379 }
1380
1381 // Implementation of algorithm by Stephenson (1997) for DeltaT computation
1382 double getDeltaTByStephenson1997(const double jDay)
1383 {
1384 double u=(jDay-2354755.0)/36525.0; // (1735-jan-0.5)
1385 return -20.0 + 35.0*u*u;
1386 }
1387
1388 // Implementation of algorithm by Schmadel & Zech (1979) for DeltaT computation. STRICTLY 1800...1975 ONLY!! Now delivers values for the edges.
1389 double getDeltaTBySchmadelZech1979(const double jDay)
1390 {
1391 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1392 u=qBound(-1.0, u, 0.76); // Limit range to 1800...1975. Else we have crazy values which cause strange artefacts.
1393 double deltaT=(((((((((((-0.089491*u -0.117389)*u + 0.185489)*u + 0.247433)*u - 0.159732)*u - 0.200097)*u + 0.075456)*u
1394 + 0.076929)*u - 0.020446)*u - 0.013867)*u + 0.003081)*u + 0.001233)*u -0.000029;
1395 return deltaT * 86400.0;
1396 }
1397
1398 // Implementation of algorithm by Morrison & Stephenson (1982) for DeltaT computation
1399 double getDeltaTByMorrisonStephenson1982(const double jDay)
1400 {
1401 double u=(jDay-2382148.0)/36525.0; // (1810-jan-0.5)
1402 return -15.0+32.50*u*u;
1403 }
1404
1405 // Implementation of algorithm by Stephenson & Morrison (1984) for DeltaT computation
1406 double getDeltaTByStephensonMorrison1984(const double jDay)
1407 {
1408 int year, month, day;
1409 double deltaT = 0.;
1410 getDateFromJulianDay(jDay, &year, &month, &day);
1411
1412 // Limited years!
1413 year=qBound(-391, year, 1600);
1414
1415 double u = (yearFraction(year, month, day)-1800)/100;
1416
1417 if (-391 < year && year <= 948)
1418 deltaT = (44.3*u +320.0)*u +1360.0;
1419 if (948 < year && year <= 1600)
1420 deltaT = 25.5*u*u;
1421
1422 return deltaT;
1423 }
1424
1425 // Implementation of algorithm by Stephenson & Morrison (1995) for DeltaT computation
1426 double getDeltaTByStephensonMorrison1995(const double jDay)
1427 {
1428 double u=(jDay-2385800.0)/36525.0; // (1820-jan-0.5)
1429 return -20.0 + 31.0*u*u;
1430 }
1431
1432 // Implementation of algorithm by Stephenson & Houlden (1986) for DeltaT computation
1433 double getDeltaTByStephensonHoulden(const double jDay)
1434 {
1435 // This formula found in the cited book, page (ii), formula (1).
1436 double T=(jDay-2415020.0)/36525; // centuries from J1900.0
1437 return (36.79*T+35.06)*T+4.87;
1438 }
1439
1440 // Implementation of algorithm by Espenak (1987, 1989) for DeltaT computation
1441 double getDeltaTByEspenak(const double jDay)
1442 {
1443 double u=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
1444 return (64.3*u +61.0)*u +67.0;
1445 }
1446
1447 // Implementation of algorithm by Borkowski (1988) for DeltaT computation
1448 // This is explicitly compatible with ELP2000-85.
1449 double getDeltaTByBorkowski(const double jDay)
1450 {
1451 double u=(jDay-2451545.0)/36525.0 + 3.75; // (2000-jan-1.5), deviation from 1625 as given in the paper.
1452 return 40.0 + 35.0*u*u;
1453 }
1454
1455 // Implementation of algorithm by Schmadel & Zech (1988) for DeltaT computation. STRICTLY 1800...1988 ONLY!! Now delivers values for the edges.
1456 double getDeltaTBySchmadelZech1988(const double jDay)
1457 {
1458 double u=(jDay-2415020.0)/36525.0; // (1900-jan-0.5)
1459 u=qBound(-1.0, u, 0.89); // Limit range to 1800...1988. Else we have crazy values which cause strange artefacts.
1460 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;
1461 return deltaT * 86400.0;
1462 }
1463
1464 // Implementation of algorithm by Chapront-Touzé & Chapront (1991) for DeltaT computation
1465 double getDeltaTByChaprontTouze(const double jDay)
1466 {
1467 int year, month, day;
1468 double deltaT = 0.;
1469 getDateFromJulianDay(jDay, &year, &month, &day);
1470
1471 // Limited years!
1472 year=qBound(-391, year, 1600);
1473
1474 double u=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
1475
1476 if (-391 < year && year <= 948)
1477 deltaT = (42.4*u +495.0)*u + 2177.0;
1478 if (948 < year && year <= 1600)
1479 deltaT = (23.6*u +100.0)*u + 102.0;
1480
1481 return deltaT;
1482 }
1483
1484 // Implementation of algorithm by JPL Horizons for DeltaT computation
1485 double getDeltaTByJPLHorizons(const double jDay)
1486 { // FIXME: It does not make sense to have zeros after 1620 in a JPL Horizons compatible implementation!
1487 int year, month, day;
1488 double u;
1489 double deltaT = 0.;
1490 getDateFromJulianDay(jDay, &year, &month, &day);
1491
1492 // Limited years!
1493 year=qBound(-2999, year, 1620);
1494
1495 if (-2999 < year && year < 948)
1496 {
1497 u=(jDay-2385800.0)/36525.0; // (1820-jan-1.5)
1498 deltaT = 31.0*u*u;
1499 }
1500 if (948 < year && year <= 1620)
1501 {
1502 u=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
1503 deltaT = (22.5*u +67.5)*u + 50.6;
1504 }
1505
1506 return deltaT;
1507 }
1508
1509 // Implementation of algorithm by Morrison & Stephenson (2004, 2005) for DeltaT computation
1510 double getDeltaTByMorrisonStephenson2004(const double jDay)
1511 {
1512 double u=(jDay-2385800.0)/36525.0; // (1820-jan-0.5)
1513 return -20.0 + 32.0 * u*u;
1514 }
1515
1516 // Implementation of algorithm by Reijs (2006) for DeltaT computation
1517 double getDeltaTByReijs(const double jDay)
1518 {
1519 double OffSetYear = (2385800.0 - jDay)/365.25;
1520
1521 return ((1.8 * OffSetYear*OffSetYear/200 + 1443*3.76/(2*M_PI)*(std::cos(2*M_PI*OffSetYear/1443)-1))*365.25)/1000;
1522 }
1523
1524 // Implementation of algorithm by Chapront, Chapront-Touze & Francou (1997) & Meeus (1998) for DeltaT computation
1525 // 191 values in tenths of second for interpolation table 1620..2000, every 2nd year.
1526 static const int MeeusDeltaTTable[] = { 1210, 1120, 1030, 950, 880, 820, 770, 720, 680, 630, 600, 560, 530, 510, 480,
1527 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
1528 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
1529 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
1530 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
1531 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
1532 -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
1533 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
1534 double getDeltaTByChaprontMeeus(const double jDay)
1535 {
1536 int year, month, day;
1537 double deltaT = 0.;
1538 getDateFromJulianDay(jDay, &year, &month, &day);
1539
1540 //const double u19=(jDay-2415020.0)/36525.0; // (1900-jan-0.5) Only for approx form.
1541 const double u20=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
1542
1543 if (year<948)
1544 deltaT=(44.1*u20 +497.0)*u20+2177.0;
1545 else if (year<1620)
1546 deltaT=(25.3*u20 + 102.0)*u20+102.0;
1547 // The next terms are the short approximative formulae. But Meeus gives exact values, table, etc. for 1620..2000.
1548 //else if (year<1900)
1549 // deltaT= ((((((((( 123563.95*u19 + 727058.63)*u19 + 1818961.41)*u19 + 2513807.78)*u19 + 2087298.89)*u19 + 1061660.75)*u19 +
1550 // 324011.78)*u19 + 56282.84)*u19 + 5218.61)*u19 + 228.95)*u19 - 2.50;
1551 //else if (year<1997)
1552 // 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;
1553 else if (year <2000)
1554 {
1555 double yeardec=yearFraction(year, month, day);
1556 int pos=(year-1620)/2; // this is a deliberate integer division! 2->1, 3->1, 4->2, 5->2 etc.
1557 deltaT= MeeusDeltaTTable[pos]+ (yeardec-(2*pos+1620))*0.5 *(MeeusDeltaTTable[pos+1]-MeeusDeltaTTable[pos]);
1558 deltaT /= 10.0;
1559 }
1560 else if (year<2100)
1561 deltaT=(25.3*u20 + 102.0)*u20+102.0 + 0.37*(year-2100);
1562 else // year > 2100
1563 deltaT=(25.3*u20 + 102.0)*u20+102.0;
1564 return deltaT;
1565 }
1566
1567 // Implementation of algorithm by Montenbruck & Pfleger (2000) for DeltaT computation
1568 // Their implementation explicitly returns 0 for out-of-range data, so must ours!
1569 // Note: the polynomes do not form a well-behaved continuous line.
1570 // The source of their data is likely the data table from Meeus, Astr. Alg. 1991.
1571 double getDeltaTByMontenbruckPfleger(const double jDay)
1572 {
1573 double deltaT = 0.;
1574 const double T=(jDay-2451545.)/36525.;
1575 double t;
1576 if (jDay<2387627.5 || jDay >=2453736.5) // ...1825-01-01 0:00 or 2006-01-01 0:00...
1577 deltaT=0.0;
1578 else if (jDay < 2396758.5) // 1850-01-01 0:00
1579 {
1580 t=T+1.75;
1581 deltaT=(( -572.3*t+413.9)*t -80.8)*t +10.4;
1582 }
1583 else if (jDay < 2405889.5) // 1875-01-01 0:00
1584 {
1585 t=T+1.50;
1586 deltaT=(( 18.8*t-358.4)*t +46.3)*t + 6.6;
1587 }
1588 else if (jDay < 2415020.5) // 1900-01-01 0:00
1589 {
1590 t=T+1.25;
1591 deltaT=(( 867.4*t-166.2)*t -10.8)*t - 3.9;
1592 }
1593 else if (jDay < 2424151.5) // 1925-01-01 0:00
1594 {
1595 t=T+1.00;
1596 deltaT=((-1467.4*t+327.5)*t +114.1)*t - 2.6;
1597 }
1598 else if (jDay < 2433282.5) // 1950-01-01 0:00
1599 {
1600 t=T+0.75;
1601 deltaT=(( 483.4*t - 8.2)*t - 6.3)*t +24.2;
1602 }
1603 else if (jDay < 2442413.5) // 1975-01-01 0:00
1604 {
1605 t=T+0.50;
1606 deltaT=(( 550.7*t - 3.8)*t +32.5)*t +29.3;
1607 }
1608 else if (jDay < 2451545.5) // 2000-01-01 0:00
1609 {
1610 t=T+0.25;
1611 deltaT=(( 1516.7*t-570.5)*t +130.5)*t +45.3;
1612 }
1613 else if (jDay < 2453736.5) // 2006-01-01 0:00 [extrapolation from 2000]
1614 {
1615 t=T+0.5;
1616 deltaT=(( 1516.7*t-570.5)*t +130.5)*t +45.3;
1617 }
1618
1619 return deltaT;
1620 }
1621
1622 // Implementation of algorithm by Meeus & Simons (2000) for DeltaT computation
1623 // Zero outside defined range 1620..2000!
1624 double getDeltaTByMeeusSimons(const double jDay)
1625 {
1626 int year, month, day;
1627 double u;
1628 double deltaT = 0.0;
1629 getDateFromJulianDay(jDay, &year, &month, &day);
1630 const double ub=(jDay-2451545.0)/36525.0; // (2000-jan-1.5)
1631
1632 if (year<1620)
1633 deltaT = 0.0;
1634 else if (year < 1690)
1635 {
1636 u = 3.45 + ub;
1637 deltaT = (((1244.0*u -454.0)*u + 50.0)*u -107.0)*u +40.3;
1638 }
1639 else if (year < 1770)
1640 {
1641 u = 2.70 + ub;
1642 deltaT = (((70.0*u -16.0)*u -1.0)*u +11.3)*u +10.2;
1643 }
1644 else if (year < 1820)
1645 {
1646 u = 2.05 + ub;
1647 deltaT = (((6.0*u +173.0)*u -22.0)*u -18.8)*u +14.7;
1648 }
1649 else if (year < 1870)
1650 {
1651 u = 1.55 + ub;
1652 deltaT = (((-1654.0*u -534.0)*u +111)*u +12.7)*u +5.7;
1653 }
1654 else if (year < 1900)
1655 {
1656 u = 1.15 + ub;
1657 deltaT = (((8234.0*u +101.0)*u +27.0)*u - 14.6)*u -5.8;
1658 }
1659 else if (year < 1940)
1660 {
1661 u = 0.80 + ub;
1662 deltaT = (((4441.0*u + 19.0)*u -443.0)*u +67.0)*u +21.4;
1663 }
1664 else if (year < 1990)
1665 {
1666 u = 0.35 + ub;
1667 deltaT = (((-1883.0*u -140.0)*u +189.0)*u +74.0)*u +36.2;
1668 }
1669 else if (year <= 2000)
1670 {
1671 u = 0.05 + ub;
1672 deltaT = ((-5034.0*u -188.0)*u +82.0)*u +60.8;
1673 }
1674
1675 return deltaT;
1676 }
1677
1678 // Implementation of algorithm by Reingold & Dershowitz (Cal. Calc. 1997, 2001, 2007, 2018, Cal. Tab. 2002) for DeltaT computation.
1679 // Created as yet another multi-segment polynomial fit through the table in Meeus: Astronomical Algorithms (1991).
1680 // Note that only the Third edition (2007) adds the 1700-1799 term.
1681 // Note that only the ultimate edition (2018) adds the -500..1699 and 2006..2150 terms.
1682 // More efficient reimplementation with stricter adherence to the source.
1683 double getDeltaTByReingoldDershowitz(const double jDay)
1684 {
1685 int year, month, day;
1686 getDateFromJulianDay(jDay, &year, &month, &day);
1687 // 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.
1688 // We cannot do that, but the difference is negligible.
1689 double deltaT=0.0; // If it returns 0, there is a bug!
1690
1691 if ((year>= 2051) && (year <= 2150))
1692 {
1693 // [2051..2150]
1694 double x = (year-1820)/100.;
1695 deltaT = (- 20 + 32*x*x + 0.5628*(2150-year));
1696 }
1697 else if ((year >= 1987) && (year <= 2050))
1698 {
1699 int y2000 = year-2000;
1700 if (year>=2006) // [2006..2050]
1701 {
1702 deltaT = ((0.005589*y2000 + 0.32217)*y2000 + 62.92);
1703 }
1704 else // [1987..2005]
1705 {
1706 deltaT = (((((0.00002373599*y2000 + 0.000651814)*y2000 + 0.0017275)*y2000 - 0.060374)*y2000 + 0.3345)*y2000 + 63.86);
1707 }
1708 }
1709 else if ((year >= 1800) && (year <= 1986))
1710 {
1711 // FIXME: This part should be check because this part gives the strange values of DeltaT (see unit tests)
1712 double c = (getFixedFromGregorian(1900, 1, 1)-getFixedFromGregorian(year, 7, 1))/36525.;
1713
1714 if (year >= 1900) // [1900..1986]
1715 {
1716 deltaT = ((((((-0.212591*c + 0.677066)*c - 0.861938)*c + 0.553040)*c - 0.181133)*c + 0.025184)*c + 0.000297)*c - 0.00002;
1717 }
1718 else // [1800..1899]
1719 {
1720 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;
1721 }
1722 deltaT *= 86400.; // convert to seconds
1723 }
1724 else if ((year>=1700) && (year<=1799))
1725 {
1726 // [1700..1799]
1727 int y1700 = year-1700;
1728 deltaT = (((-0.0000266484*y1700 + 0.003336121)*y1700 - 0.005092142)*y1700 + 8.118780842);
1729 }
1730 else if ((year>=1600) && (year<=1699))
1731 {
1732 // [1600..1699]
1733 int y1600 = year-1600;
1734 deltaT = (((0.000140272128*y1600 - 0.01532)*y1600 - 0.9808)*y1600 + 120);
1735 }
1736 else if ((year>=500) && (year<=1599))
1737 {
1738 // [500..1599]
1739 double y1000 = (year-1000)/100.;
1740 deltaT = ((((((0.0083572073*y1000 - 0.005050998)*y1000 - 0.8503463)*y1000 + 0.319781)*y1000 + 71.23472)*y1000 - 556.01)*y1000 + 1574.2);
1741 }
1742 else if ((year>-500) && (year<500))
1743 {
1744 // (-500..500)
1745 double y0 = year/100.;
1746 deltaT = ((((((0.0090316521*y0 + 0.022174192)*y0 - 0.1798452)*y0 - 5.952053)*y0 + 33.78311)*y0 - 1014.41)*y0 + 10583.6);
1747 }
1748 else
1749 {
1750 // otherwise
1751 double x = (year-1820)/100.;
1752 deltaT = (-20 + 32*x*x);
1753 }
1754
1755 return deltaT;
1756 }
1757
1758 // Implementation of algorithm by Banjevic (2006) for DeltaT computation.
1759 double getDeltaTByBanjevic(const double jDay)
1760 {
1761 int year, month, day;
1762 getDateFromJulianDay(jDay, &year, &month, &day);
1763 double u, c;
1764
1765 // Limited years!
1766 year=qBound(-2020, year, 1620);
1767
1768 if (year<=-700)
1769 {
1770 u = (jDay-2378496.0)/36525.0; // 1800.0=1800-jan-0.5=2378496.0
1771 c = 30.86;
1772 }
1773 else // if (year>-700 && year<=1620)
1774 {
1775 u = (jDay-2385800.0)/36525.0; // 1820.0=1820-jan-0.5=2385800.0
1776 c = 31;
1777 }
1778
1779 return c*u*u;
1780 }
1781
1782 // Implementation of algorithm by Islam, Sadiq & Qureshi (2008 + revisited 2013) for DeltaT computation.
1783 double getDeltaTByIslamSadiqQureshi(const double jDay)
1784 {
1785 int year, month, day;
1786 getDateFromJulianDay(jDay, &year, &month, &day);
1787 double deltaT; // Return deltaT for the edge year outside valid range.
1788 double u, ub;
1789
1790 // Limited years: Apply border values!
1791 //year=qBound(1620, year, 2007);
1792 if (year<1620)
1793 {
1794 const double j1620=qDateTimeToJd(QDateTime(QDate(1620, 1, 1), QTime(0, 0, 0), Qt::UTC));
1795 ub=(j1620-2454101.0)/36525.0;
1796 }
1797 else if (year>2007)
1798 {
1799 const double j2008=qDateTimeToJd(QDateTime(QDate(2008, 1, 1), QTime(0, 0, 0), Qt::UTC));
1800 ub=(j2008-2454101.0)/36525.0;
1801 }
1802 else
1803 ub=(jDay-2454101.0)/36525.0; // (2007-jan-0.5)
1804
1805
1806 if (year <= 1698)
1807 {
1808 u = 3.48 + ub;
1809 deltaT = (((1162.805 * u - 273.116) * u + 14.523) * u - 105.262) * u + 38.067;
1810 }
1811 else if (year <= 1806)
1812 {
1813 u = 2.545 + ub;
1814 deltaT = (((-71.724 * u - 39.048) * u + 7.591) * u + 13.893) * u + 13.759;
1815 }
1816 else if (year <= 1872)
1817 {
1818 u = 1.675 + ub;
1819 deltaT = (((-1612.55 * u - 157.977) * u + 161.524) * u - 3.654) * u + 5.859;
1820 }
1821 else if (year <= 1906)
1822 {
1823 u = 1.175 + ub;
1824 deltaT = (((6250.501 * u + 1006.463) * u + 139.921) * u - 2.732) * u - 6.203;
1825 }
1826 else if (year <= 1953)
1827 {
1828 // revised 2013 per email
1829 u = 0.77 + ub;
1830 deltaT = (((-390.785 * u + 901.514) * u - 88.044) * u + 8.997) * u + 24.006;
1831 }
1832 else //if (year <= 2007)
1833 {
1834 // revised 2013 per email
1835 u = 0.265 + ub;
1836 deltaT = (((1314.759 * u - 296.018) * u - 101.898) * u + 88.659) * u + 49.997;
1837 }
1838
1839 return deltaT;
1840 }
1841
1842 // Implementation of polynomial approximation of time period 1620-2013 for DeltaT by M. Khalid, Mariam Sultana and Faheem Zaidi (2014).
1843 double getDeltaTByKhalidSultanaZaidi(const double jDay)
1844 {
1845 int year, month, day;
1846 getDateFromJulianDay(jDay, &year, &month, &day);
1847 //double a0, a1, a2, a3, a4;
1848 const double k[9] ={ 3.670, 3.120, 2.495, 1.925, 1.525, 1.220, 0.880, 0.455, 0.115};
1849 const double a0[9]={ 76.541, 10.872, 13.480, 12.584, 6.364, -5.058, 13.392, 30.782, 55.281};
1850 const double a1[9]={ -253.532, -40.744, 13.075, 1.929, 11.004, -1.701, 128.592, 34.348, 91.248};
1851 const double a2[9]={ 695.901, 236.890, 8.635, 60.896, 407.776, -46.403, -279.165, 46.452, 87.202};
1852 const double a3[9]={ -1256.982, -351.537, -3.307, -1432.216, -4168.394, -866.171, -1282.050, 1295.550, -3092.565};
1853 const double a4[9]={ 627.152, 36.612, -128.294, 3129.071, 7561.686, 5917.585, 4039.490, -3210.913, 8255.422};
1854 int i;
1855 // Limited years! Deliver border values.
1856 year=qBound(1620, year, 2013);
1857
1858 if (year<=1672)
1859 i=0;
1860 else if (year<=1729)
1861 i=1;
1862 else if (year<=1797)
1863 i=2;
1864 else if (year<=1843)
1865 i=3;
1866 else if (year<=1877)
1867 i=4;
1868 else if (year<=1904)
1869 i=5;
1870 else if (year<=1945)
1871 i=6;
1872 else if (year<=1989)
1873 i=7;
1874 else // if (year<=2013)
1875 i=8;
1876
1877 double u = k[i] + (year - 2000.)/100.; // Avoid possible wrong calculations!
1878
1879 return (((a4[i]*u + a3[i])*u + a2[i])*u + a1[i])*u + a0[i];
1880 }
1881
1882 static const double StephensonMorrisonHohenkerk2016DeltaTtableS15[54][6]={
1883 // Row Years Polynomial Coefficients
1884 // i K_i K_{i+1} a_0 a_1 a_2 a_3
1885 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1886 /* 1 */ {-720.0, 400.0, 20550.593, -21268.478, 11863.418, -4541.129},
1887 /* 2 */ { 400.0, 1000.0, 6604.404, -5981.266, -505.093, 1349.609},
1888 /* 3 */ {1000.0, 1500.0, 1467.654, -2452.187, 2460.927, -1183.759},
1889 /* 4 */ {1500.0, 1600.0, 292.635, -216.322, -43.614, 56.681},
1890 /* 5 */ {1600.0, 1650.0, 89.380, -66.754, 31.607, -10.497},
1891 /* 6 */ {1650.0, 1720.0, 43.736, -49.043, 0.227, 15.811},
1892 /* 7 */ {1720.0, 1800.0, 10.730, -1.321, 62.250, -52.946},
1893 /* 8 */ {1800.0, 1810.0, 18.714, -4.457, -1.509, 2.507},
1894 /* 9 */ {1810.0, 1820.0, 15.255, 0.046, 6.012, -4.634},
1895 /* 10 */ {1820.0, 1830.0, 16.679, -1.831, -7.889, 3.799},
1896 /* 11 */ {1830.0, 1840.0, 10.758, -6.211, 3.509, -0.388},
1897 /* 12 */ {1840.0, 1850.0, 7.668, -0.357, 2.345, -0.338},
1898 /* 13 */ {1850.0, 1855.0, 9.317, 1.659, 0.332, -0.932},
1899 /* 14 */ {1855.0, 1860.0, 10.376, -0.472, -2.463, 1.596},
1900 /* 15 */ {1860.0, 1865.0, 9.038, -0.610, 2.325, -2.497},
1901 /* 16 */ {1865.0, 1870.0, 8.256, -3.450, -5.166, 2.729},
1902 /* 17 */ {1870.0, 1875.0, 2.369, -5.596, 3.020, -0.919},
1903 /* 18 */ {1875.0, 1880.0, -1.126, -2.312, 0.264, -0.037},
1904 /* 19 */ {1880.0, 1885.0, -3.211, -1.894, 0.154, 0.562},
1905 /* 20 */ {1885.0, 1890.0, -4.388, 0.101, 1.841, -1.438},
1906 /* 21 */ {1890.0, 1895.0, -3.884, -0.531, -2.473, 1.870},
1907 /* 22 */ {1895.0, 1900.0, -5.017, 0.134, 3.138, -0.232},
1908 /* 23 */ {1900.0, 1905.0, -1.977, 5.715, 2.443, -1.257},
1909 /* 24 */ {1905.0, 1910.0, 4.923, 6.828, -1.329, 0.720},
1910 /* 25 */ {1910.0, 1915.0, 11.142, 6.330, 0.831, -0.825},
1911 /* 26 */ {1915.0, 1920.0, 17.479, 5.518, -1.643, 0.262},
1912 /* 27 */ {1920.0, 1925.0, 21.617, 3.020, -0.856, 0.008},
1913 /* 28 */ {1925.0, 1930.0, 23.789, 1.333, -0.831, 0.127},
1914 /* 29 */ {1930.0, 1935.0, 24.418, 0.052, -0.449, 0.142},
1915 /* 30 */ {1935.0, 1940.0, 24.164, -0.419, -0.022, 0.702},
1916 /* 31 */ {1940.0, 1945.0, 24.426, 1.645, 2.086, -1.106},
1917 /* 32 */ {1945.0, 1950.0, 27.050, 2.499, -1.232, 0.614},
1918 /* 33 */ {1950.0, 1953.0, 28.932, 1.127, 0.220, -0.277},
1919 /* 34 */ {1953.0, 1956.0, 30.002, 0.737, -0.610, 0.631},
1920 /* 35 */ {1956.0, 1959.0, 30.760, 1.409, 1.282, -0.799},
1921 /* 36 */ {1959.0, 1962.0, 32.652, 1.577, -1.115, 0.507},
1922 /* 37 */ {1962.0, 1965.0, 33.621, 0.868, 0.406, 0.199},
1923 /* 38 */ {1965.0, 1968.0, 35.093, 2.275, 1.002, -0.414},
1924 /* 39 */ {1968.0, 1971.0, 37.956, 3.035, -0.242, 0.202},
1925 /* 40 */ {1971.0, 1974.0, 40.951, 3.157, 0.364, -0.229},
1926 /* 41 */ {1974.0, 1977.0, 44.244, 3.198, -0.323, 0.172},
1927 /* 42 */ {1977.0, 1980.0, 47.291, 3.069, 0.193, -0.192},
1928 /* 43 */ {1980.0, 1983.0, 50.361, 2.878, -0.384, 0.081},
1929 /* 44 */ {1983.0, 1986.0, 52.936, 2.354, -0.140, -0.166},
1930 /* 45 */ {1986.0, 1989.0, 54.984, 1.577, -0.637, 0.448},
1931 /* 46 */ {1989.0, 1992.0, 56.373, 1.649, 0.709, -0.277},
1932 /* 47 */ {1992.0, 1995.0, 58.453, 2.235, -0.122, 0.111},
1933 /* 48 */ {1995.0, 1998.0, 60.677, 2.324, 0.212, -0.315},
1934 /* 49 */ {1998.0, 2001.0, 62.899, 1.804, -0.732, 0.112},
1935 /* 50 */ {2001.0, 2004.0, 64.082, 0.675, -0.396, 0.193},
1936 /* 51 */ {2004.0, 2007.0, 64.555, 0.463, 0.184, -0.008},
1937 /* 52 */ {2007.0, 2010.0, 65.194, 0.809, 0.161, -0.101},
1938 /* 53 */ {2010.0, 2013.0, 66.063, 0.828, -0.142, 0.168},
1939 /* 54 */ {2013.0, 2016.0, 66.917, 1.046, 0.360, -0.282}
1940 };
1941 double getDeltaTByStephensonMorrisonHohenkerk2016(const double jDay)
1942 {
1943 int year, month, day;
1944 getDateFromJulianDay(jDay, &year, &month, &day);
1945 double y=yearFraction(year, month, day);
1946 if ((y<-720.) || (y>2016.))
1947 {
1948 double fact=(y-1825.0)/100.;
1949 return -320.0+32.5*fact*fact;
1950 }
1951 int i=0;
1952 while (StephensonMorrisonHohenkerk2016DeltaTtableS15[i][1]<y) i++;
1953 Q_ASSERT(i<54);
1954 double t=(y-StephensonMorrisonHohenkerk2016DeltaTtableS15[i][0]) / (StephensonMorrisonHohenkerk2016DeltaTtableS15[i][1]-StephensonMorrisonHohenkerk2016DeltaTtableS15[i][0]);
1955 return ((StephensonMorrisonHohenkerk2016DeltaTtableS15[i][5]*t + StephensonMorrisonHohenkerk2016DeltaTtableS15[i][4])*t
1956 + StephensonMorrisonHohenkerk2016DeltaTtableS15[i][3])*t + StephensonMorrisonHohenkerk2016DeltaTtableS15[i][2];
1957 }
1958
1959 double getMoonSecularAcceleration(const double jDay, const double nd, const bool useDE4xx)
1960 {
1961 int year, month, day;
1962 getDateFromJulianDay(jDay, &year, &month, &day);
1963
1964 const double t = (yearFraction(year, month, day)-1955.5)/100.0;
1965 // n.dot for secular acceleration of the Moon in ELP2000-82B
1966 // has value -23.8946 "/cy/cy (or -25.8 for DE43x usage)
1967 const double ephND = (useDE4xx ? -25.8 : -23.8946);
1968 return -0.91072 * (ephND + qAbs(nd))*t*t;
1969 }
1970
1971 double getDeltaTStandardError(const double jDay)
1972 {
1973 int year, month, day;
1974 getDateFromJulianDay(jDay, &year, &month, &day);
1975
1976 double sigma = -1.;
1977
1978 if (-1000 <= year && year <= 1600)
1979 {
1980 double cDiff1820= (jDay-2385800.0)/36525.0; // 1820.0=1820-jan-0.5=2385800.0
1981 // sigma = std::pow((yeardec-1820.0)/100,2); // sigma(DeltaT) = 0.8*u^2
1982 sigma = 0.8 * cDiff1820 * cDiff1820;
1983 }
1984 return sigma;
1985 }
1986
1987 // Current table contains interpolated data of original table by Spencer Jones, H., "The Rotation of the Earth, and the Secular
1988 // Accelerations of the Sun, Moon and Planets", Monthly Notices of the Royal Astronomical Society, 99 (1939), 541-558
1989 // [http://adsabs.harvard.edu/abs/1939MNRAS..99..541S] see Table I.
1990 static const double MoonFluctuationTable[2555] = {
1991 -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,
1992 -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,
1993 -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,
1994 -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,
1995 -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,
1996 -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,
1997 -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,
1998 -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,
1999 -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,
2000 -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,
2001 -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,
2002 -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,
2003 -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,
2004 -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,
2005 -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,
2006 -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,
2007 -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,
2008 -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,
2009 -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,
2010 -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,
2011 -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,
2012 -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,
2013 -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,
2014 -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,
2015 -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,
2016 -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,
2017 -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,
2018 -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,
2019 -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,
2020 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,
2021 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,
2022 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,
2023 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,
2024 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,
2025 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,
2026 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,
2027 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,
2028 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,
2029 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,
2030 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,
2031 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,
2032 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,
2033 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,
2034 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,
2035 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,
2036 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,
2037 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,
2038 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,
2039 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,
2040 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,
2041 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,
2042 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,
2043 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,
2044 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,
2045 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,
2046 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,
2047 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,
2048 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,
2049 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,
2050 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,
2051 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,
2052 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,
2053 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,
2054 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,
2055 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,
2056 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,
2057 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,
2058 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,
2059 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,
2060 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,
2061 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,
2062 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,
2063 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,
2064 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,
2065 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,
2066 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,
2067 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,
2068 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,
2069 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,
2070 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,
2071 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,
2072 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,
2073 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,
2074 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,
2075 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,
2076 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,
2077 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,
2078 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,
2079 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,
2080 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,
2081 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,
2082 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,
2083 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,
2084 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,
2085 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,
2086 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,
2087 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,
2088 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,
2089 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,
2090 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,
2091 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,
2092 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,
2093 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,
2094 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,
2095 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,
2096 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,
2097 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,
2098 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,
2099 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,
2100 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,
2101 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,
2102 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,
2103 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,
2104 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,
2105 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,
2106 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,
2107 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,
2108 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,
2109 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,
2110 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,
2111 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,
2112 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,
2113 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,
2114 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,
2115 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,
2116 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,
2117 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,
2118 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,
2119 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,
2120 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,
2121 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,
2122 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,
2123 -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,
2124 -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,
2125 -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,
2126 -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,
2127 -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,
2128 -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,
2129 -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,
2130 -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,
2131 -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,
2132 -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,
2133 -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,
2134 -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,
2135 -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,
2136 -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,
2137 -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,
2138 -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,
2139 -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,
2140 -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,
2141 -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,
2142 -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,
2143 -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,
2144 -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,
2145 -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,
2146 -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,
2147 -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,
2148 -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,
2149 -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,
2150 -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,
2151 -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,
2152 -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,
2153 -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,
2154 -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,
2155 -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,
2156 -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,
2157 -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,
2158 -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,
2159 -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,
2160 -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,
2161 -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,
2162 -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,
2163 -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,
2164 -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,
2165 -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,
2166 -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,
2167 -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,
2168 -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,
2169 -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,
2170 -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,
2171 -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,
2172 -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,
2173 -16.382, -16.400, -16.417, -16.433, -16.449, -16.465, -16.480
2174 };
2175
2176 double getMoonFluctuation(const double jDay)
2177 {
2178 double f = 0.;
2179 int year, month, day, index;
2180 getDateFromJulianDay(jDay, &year, &month, &day);
2181
2182 double t = yearFraction(year, month, day);
2183 if (t>=1681.0 && t<=1936.5) {
2184 index = qRound(std::floor((t - 1681.0)*10));
2185 f = MoonFluctuationTable[index]*0.07; // Get interpolated data and convert to seconds of time
2186 }
2187
2188 return f;
2189 }
2190
2191 // Arrays to keep cos/sin of angles and multiples of angles. rho and theta are delta angles, and these arrays
2192 #define MAX_STACKS 4096
2193 static float cos_sin_rho[2*(MAX_STACKS+1)];
2194 #define MAX_SLICES 4096
2195 static float cos_sin_theta[2*(MAX_SLICES+1)];
2196
2197 //! Compute cosines and sines around a circle which is split in "segments" parts.
2198 //! Values are stored in the global static array cos_sin_theta.
2199 //! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh.
2200 //! @param slices number of partitions (elsewhere called "segments") for the circle
2201 float* ComputeCosSinTheta(const unsigned int slices)
2202 {
2203 Q_ASSERT(slices<=MAX_SLICES);
2204
2205 // Difference angle between the stops. Always use 2*M_PI/slices!
2206 const float dTheta = 2.f * static_cast<float>(M_PI) / slices;
2207 float *cos_sin = cos_sin_theta;
2208 float *cos_sin_rev = cos_sin + 2*(slices+1);
2209 const float c = std::cos(dTheta);
2210 const float s = std::sin(dTheta);
2211 *cos_sin++ = 1.f;
2212 *cos_sin++ = 0.f;
2213 *--cos_sin_rev = -cos_sin[-1];
2214 *--cos_sin_rev = cos_sin[-2];
2215 *cos_sin++ = c;
2216 *cos_sin++ = s;
2217 *--cos_sin_rev = -cos_sin[-1];
2218 *--cos_sin_rev = cos_sin[-2];
2219 while (cos_sin < cos_sin_rev) // compares array address indices only!
2220 {
2221 // avoid expensive trig functions by use of the addition theorem.
2222 cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
2223 cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
2224 cos_sin += 2;
2225 *--cos_sin_rev = -cos_sin[-1];
2226 *--cos_sin_rev = cos_sin[-2];
2227 }
2228 return cos_sin_theta;
2229 }
2230
2231 //! Compute cosines and sines around a half-circle which is split in "segments" parts.
2232 //! Values are stored in the global static array cos_sin_rho.
2233 //! Used for the sin/cos values along a meridian for a spherical mesh.
2234 //! @param segments number of partitions (elsewhere called "stacks") for the half-circle
2235 float* ComputeCosSinRho(const unsigned int segments)
2236 {
2237 Q_ASSERT(segments<=MAX_STACKS);
2238
2239 // Difference angle between the stops. Always use M_PI/segments!
2240 const float dRho = static_cast<float>(M_PI) / segments;
2241 float *cos_sin = cos_sin_rho;
2242 float *cos_sin_rev = cos_sin + 2*(segments+1);
2243 const float c = cosf(dRho);
2244 const float s = sinf(dRho);
2245 *cos_sin++ = 1.f;
2246 *cos_sin++ = 0.f;
2247 *--cos_sin_rev = cos_sin[-1];
2248 *--cos_sin_rev = -cos_sin[-2];
2249 *cos_sin++ = c;
2250 *cos_sin++ = s;
2251 *--cos_sin_rev = cos_sin[-1];
2252 *--cos_sin_rev = -cos_sin[-2];
2253 while (cos_sin < cos_sin_rev) // compares array address indices only!
2254 {
2255 // avoid expensive trig functions by use of the addition theorem.
2256 cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
2257 cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
2258 cos_sin += 2;
2259 *--cos_sin_rev = cos_sin[-1];
2260 *--cos_sin_rev = -cos_sin[-2];
2261 }
2262
2263 return cos_sin_rho;
2264 }
2265
2266 //! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts.
2267 //! Values are stored in the global static array cos_sin_rho.
2268 //! Used for the sin/cos values along a meridian.
2269 //! This allows leaving away pole caps. The array now contains values for the region minAngle+segments*phi
2270 //! @param dRho a difference angle between the stops
2271 //! @param segments number of segments
2272 //! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi
2273 float *ComputeCosSinRhoZone(const float dRho, const unsigned int segments, const float minAngle)
2274 {
2275 float *cos_sin = cos_sin_rho;
2276 const float c = cosf(dRho);
2277 const float s = sinf(dRho);
2278 *cos_sin++ = cosf(minAngle);
2279 *cos_sin++ = sinf(minAngle);
2280 for (unsigned int i=0; i<segments; ++i) // we cannot mirror this, it may be unequal.
2281 { // efficient computation, avoid expensive trig functions by use of the addition theorem.
2282 cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s;
2283 cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c;
2284 cos_sin += 2;
2285 }
2286 return cos_sin_rho;
2287 }
2288
2289 int getFixedFromGregorian(const int year, const int month, const int day)
2290 {
2291 int y = year - 1;
2292 int r = 365*y + intFloorDiv(y, 4) - intFloorDiv(y, 100) + intFloorDiv(y, 400) + (367*month-362)/12 + day;
2293 if (month>2)
2294 r += (isLeapYear(year) ? -1 : -2);
2295
2296 return r;
2297 }
2298
2299 int compareVersions(const QString v1, const QString v2)
2300 {
2301 // result (-1: v1<v2; 0: v1==v2; 1: v1>v2)
2302 int ver1, ver2, result = 0;
2303 QStringList v1s = v1.split(".");
2304 QStringList v2s = v2.split(".");
2305 if (v1s.count()==3) // Full format: X.Y.Z
2306 ver1 = v1s.at(0).toInt()*1000 + v1s.at(1).toInt()*100 + v1s.at(2).toInt();
2307 else // Short format: X.Y
2308 ver1 = v1s.at(0).toInt()*1000 + v1s.at(1).toInt()*100;
2309 if (v2s.count()==3)
2310 ver2 = v2s.at(0).toInt()*1000 + v2s.at(1).toInt()*100 + v2s.at(2).toInt();
2311 else
2312 ver2 = v2s.at(0).toInt()*1000 + v2s.at(1).toInt()*100;
2313
2314 if (ver1<ver2)
2315 result = -1;
2316 else if (ver1 == ver2)
2317 result = 0;
2318 else if (ver1 > ver2)
2319 result = 1;
2320
2321 return result;
2322 }
2323
2324 int gcd(int a, int b)
2325 {
2326 return b ? gcd(b, a % b) : a;
2327 }
2328
2329 int lcm(int a, int b)
2330 {
2331 return (a*b/gcd(a, b));
2332 }
2333
2334 //! Uncompress gzip or zlib compressed data.
2335 QByteArray uncompress(const QByteArray& data)
2336 {
2337 if (data.size() <= 4)
2338 return QByteArray();
2339
2340 //needed for const-correctness, no deep copy performed
2341 QByteArray dataNonConst(data);
2342 QBuffer buf(&dataNonConst);
2343 buf.open(QIODevice::ReadOnly);
2344
2345 return uncompress(buf);
2346 }
2347
2348 //! Uncompress (gzip/zlib) data from this QIODevice, which must be open and readable.
2349 //! @param device The device to read from, must already be opened with an OpenMode supporting reading
2350 //! @param maxBytes The max. amount of bytes to read from the device, or -1 to read until EOF. Note that it
2351 //! always stops when inflate() returns Z_STREAM_END. Positive values can be used for interleaving compressed data
2352 //! with other data.
2353 QByteArray uncompress(QIODevice& device, qint64 maxBytes)
2354 {
2355 // this is a basic zlib decompression routine, similar to:
2356 // http://zlib.net/zlib_how.html
2357
2358 // buffer size 256k, zlib recommended size
2359 static const int CHUNK = 262144;
2360 QByteArray readBuffer(CHUNK, 0);
2361 QByteArray inflateBuffer(CHUNK, 0);
2362 QByteArray out;
2363
2364 // zlib stream
2365 z_stream strm;
2366 strm.zalloc = Q_NULLPTR;
2367 strm.zfree = Q_NULLPTR;
2368 strm.opaque = Q_NULLPTR;
2369 strm.avail_in = Z_NULL;
2370 strm.next_in = Q_NULLPTR;
2371
2372 // the amount of bytes already read from the device
2373 qint64 bytesRead = 0;
2374
2375 // initialize zlib
2376 // 15 + 32 for gzip automatic header detection.
2377 int ret = inflateInit2(&strm, 15 + 32);
2378 if (ret != Z_OK)
2379 {
2380 qWarning()<<"zlib init error ("<<ret<<"), can't uncompress";
2381 if(strm.msg)
2382 qWarning()<<"zlib message: "<<QString(strm.msg);
2383 return QByteArray();
2384 }
2385
2386 //zlib double loop - one for reading from file, one for inflating
2387 do
2388 {
2389 qint64 bytesToRead = CHUNK;
2390 if(maxBytes>=0)
2391 {
2392 //check if we reach the desired limit with the next read
2393 bytesToRead = qMin(static_cast<qint64>(CHUNK),maxBytes-bytesRead);
2394 }
2395
2396 if(bytesToRead==0)
2397 break;
2398
2399 //perform read from device
2400 qint64 read = device.read(readBuffer.data(), bytesToRead);
2401 if (read<0)
2402 {
2403 qWarning()<<"Error while reading from device";
2404 inflateEnd(&strm);
2405 return QByteArray();
2406 }
2407
2408 bytesRead += read;
2409 strm.next_in = reinterpret_cast<Bytef*>(readBuffer.data());
2410 strm.avail_in = static_cast<unsigned int>(read);
2411
2412 if(read==0)
2413 break;
2414
2415 //inflate loop
2416 do
2417 {
2418 strm.avail_out = CHUNK;
2419 strm.next_out = reinterpret_cast<Bytef*>(inflateBuffer.data());
2420 ret = inflate(&strm,Z_NO_FLUSH);
2421 Q_ASSERT(ret != Z_STREAM_ERROR); // must never happen, indicates a programming error
2422
2423 if(ret < 0 || ret == Z_NEED_DICT)
2424 {
2425 qWarning()<<"zlib inflate error ("<<ret<<"), can't uncompress";
2426 if(strm.msg)
2427 qWarning()<<"zlib message: "<<QString(strm.msg);
2428 inflateEnd(&strm);
2429 return QByteArray();
2430 }
2431
2432 out.append(inflateBuffer.constData(), CHUNK - static_cast<int>(strm.avail_out));
2433 } while(strm.avail_out == 0); //if zlib has more data for us, repeat
2434 } while(ret!=Z_STREAM_END);
2435
2436 // close zlib
2437 inflateEnd(&strm);
2438
2439 if(ret!=Z_STREAM_END)
2440 {
2441 qWarning()<<"Premature end of compressed stream";
2442 if(strm.msg)
2443 qWarning()<<"zlib message: "<<QString(strm.msg);
2444 return QByteArray();
2445 }
2446
2447 return out;
2448 }
2449
2450
2451 } // end of the StelUtils namespace
2452
2453