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 &deg)
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