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 #ifndef STELUTILS_HPP
21 #define STELUTILS_HPP
22 
23 #include <cmath>
24 #include "VecMath.hpp"
25 
26 #include <QVariantMap>
27 #include <QDateTime>
28 #include <QString>
29 
30 // astronomical unit (km)
31 #define AU 149597870.691
32 #define AUf 149597870.691f
33 #define AU_KM (1.0/149597870.691)
34 #define AU_KMf (1.0f/149597870.691f)
35 // Parsec (km)
36 #define PARSEC 30.857e12
37 // speed of light (km/sec)
38 #define SPEED_OF_LIGHT 299792.458
39 // Ecliptic obliquity of J2000.0, degrees
40 #define EPS_0 23.4392803055555555555556
41 
42 // Add a few frequently used extra math-type literals
43 #ifndef M_PI_180
44 	#define M_PI_180    (M_PI/180.)
45 #endif
46 #ifndef M_180_PI
47 	#define M_180_PI    (180./M_PI)
48 #endif
49 // Add some math literals in float version to avoid many static_casts
50 #ifndef M_PIf
51 	#define M_PIf       3.14159265358979323846f   // pi
52 #endif
53 #ifndef M_PI_2f
54 	#define M_PI_2f     1.57079632679489661923f   // pi/2
55 #endif
56 #ifndef M_PI_4f
57 	#define M_PI_4f     0.785398163397448309616f  // pi/4
58 #endif
59 #ifndef M_1_PIf
60 	#define M_1_PIf     0.318309886183790671538f  // 1/pi
61 #endif
62 #ifndef M_2_PIf
63 	#define M_2_PIf     0.636619772367581343076f  // 2/pi
64 #endif
65 #ifndef M_PI_180f
66 	#define M_PI_180f   (M_PIf/180.f)
67 #endif
68 #ifndef M_180_PIf
69 	#define M_180_PIf   (180.f/M_PIf)
70 #endif
71 
72 #define stelpow10f(x) std::exp((x) * 2.3025850930f)
73 
74 //! @namespace StelUtils contains general purpose utility functions.
75 namespace StelUtils
76 {
77 	//! Return the full name of stellarium, i.e. "stellarium 0.9.0"
78 	QString getApplicationName();
79 
80 	//! Return the version of stellarium, i.e. "0.9.0"
81 	QString getApplicationVersion();
82 
83 	//! Return the name and the version of operating system, i.e. "Mac OS X 10.7"
84 	QString getOperatingSystemInfo();
85 
86 	//! Return the user agent name, i.e. "Stellarium/0.15.0 (Linux)"
87 	QString getUserAgentString();
88 
getEndLineChar()89 	inline const QString getEndLineChar() {
90 		#ifdef Q_OS_WIN
91 		const QString stelEndl="\r\n";
92 		#else
93 		const QString stelEndl="\n";
94 		#endif
95 		return stelEndl;
96 	}
97 
98 	//! Convert hours, minutes, seconds to decimal hours
hmsToHours(const unsigned int h,const unsigned int m,const double s)99 	inline double hmsToHours(const unsigned int h, const unsigned int m, const double s){
100 		return static_cast<double>(h)+static_cast<double>(m)/60.+s/3600.;
101 	}
102 
103 	//! Convert an angle in hms format to radian.
104 	//! @param h hour component
105 	//! @param m minute component
106 	//! @param s second component
107 	//! @return angle in radian
hmsToRad(const unsigned int h,const unsigned int m,const double s)108 	inline double hmsToRad(const unsigned int h, const unsigned int m, const double s){
109 		return hmsToHours(h, m, s)*M_PI/12.;
110 	}
111 
112 	//! Convert an angle in +-dms format to radian.
113 	//! @param d degree component
114 	//! @param m arcmin component
115 	//! @param s arcsec component
116 	//! @return angle in radian
dmsToRad(const int d,const unsigned int m,const double s)117 	inline double dmsToRad(const int d, const unsigned int m, const double s){
118 		double rad = M_PI_180*qAbs(d)+M_PI/10800.*m+s*M_PI/648000.;
119 		return (d<0 ? -rad : rad);
120 	}
121 
122 	//! Convert an angle in radian to hms format.
123 	//! @param rad input angle in radian
124 	//! @param h hour component
125 	//! @param m minute component
126 	//! @param s second component
127 	void radToHms(double rad, unsigned int& h, unsigned int& m, double& s);
128 
129 	//! Convert an angle in radian to +-dms format.
130 	//! @param rad input angle in radian
131 	//! @param sign true if positive, false otherwise
132 	//! @param d degree component
133 	//! @param m minute component
134 	//! @param s second component
135 	void radToDms(double rad, bool& sign, unsigned int& d, unsigned int& m, double& s);
136 
137 	//! Convert an angle in radian to decimal degree.
138 	//! @param rad input angle in radian
139 	//! @param sign true if positive, false otherwise
140 	//! @param deg decimal degree
141 	void radToDecDeg(double rad, bool& sign, double& deg);
142 
143 	//! Convert an angle in radian to a decimal degree string.
144 	//! @param angle input angle in radian
145 	//! @param precision
146 	//! @param useD Define if letter "d" must be used instead of deg sign
147 	//! @param useC Define if function should use 0-360 degrees
148 	QString radToDecDegStr(const double angle, const int precision = 4, const bool useD=false, const bool useC=false);
149 
150 	//! Convert an angle in radian to a hms formatted string.
151 	//! If the second, minute part is == 0, it is not output
152 	//! @param angle input angle in radian
153 	QString radToHmsStrAdapt(const double angle);
154 
155 	//! Convert an angle in radian to a hms formatted string.
156 	//! @param angle input angle in radian
157 	//! @param decimal output decimal second value
158 	QString radToHmsStr(const double angle, const bool decimal=false);
159 
160 	//! Convert an angle in radian to a dms formatted string.
161 	//! If the second, minute part is == 0, it is not output
162 	//! @param angle input angle in radian
163 	//! @param useD Define if letter "d" must be used instead of deg sign
164 	QString radToDmsStrAdapt(const double angle, const bool useD=false);
165 
166 	//! Convert an angle in radian to a dms formatted string.
167 	//! @param angle input angle in radian
168 	//! @param decimal output second value with decimal fraction
169 	//! @param useD Define if letter "d" must be used instead of deg sign
170 	QString radToDmsStr(const double angle, const bool decimal=false, const bool useD=false);
171 
172 	//! Convert an angle in radian to a dms formatted string.
173 	//! @param angle input angle in radian
174 	//! @param precision
175 	//! @param useD Define if letter "d" must be used instead of deg sign
176 	QString radToDmsPStr(const double angle, const int precision = 0, const bool useD=false);
177 
178 	//! Convert an angle in decimal degree to +-dms format.
179 	//! @param angle input angle in decimal degree
180 	//! @param sign true if positive, false otherwise
181 	//! @param d degree component
182 	//! @param m minute component
183 	//! @param s second component
184 	void decDegToDms(double angle, bool& sign, unsigned int& d, unsigned int& m, double& s);
185 
186 	//! Convert an angle in decimal degrees to a dms formatted string.
187 	//! @param angle input angle in decimal degrees
188 	QString decDegToDmsStr(const double angle);
189 
190 	//! Convert a dms formatted string to an angle in radian
191 	//! @param s The input string
192 	double dmsStrToRad(const QString& s);
193 
194 	//! Convert from spherical coordinates to Rectangular direction.
195 	//! @param lng longitude in radian
196 	//! @param lat latitude in radian
197 	//! @param v the resulting 3D unit vector
spheToRect(const double lng,const double lat,Vec3d & v)198 	inline void spheToRect(const double lng, const double lat, Vec3d& v){
199 		const double cosLat = cos(lat);
200 		v.set(cos(lng) * cosLat, sin(lng) * cosLat, sin(lat));
201 	}
202 
203 	//! Convert from spherical coordinates to Rectangular direction.
204 	//! @param lng longitude in radian
205 	//! @param lat latitude in radian
206 	//! @param v the resulting 3D unit vector
spheToRect(const float lng,const float lat,Vec3f & v)207 	inline void spheToRect(const float lng, const float lat, Vec3f& v){
208 		const double dlng = static_cast<double>(lng), dlat = static_cast<double>(lat), cosLat = cos(dlat);
209 		v.set(static_cast<float>(cos(dlng) * cosLat), static_cast<float>(sin(dlng) * cosLat), sinf(lat));
210 	}
211 
212 	//! Convert from spherical coordinates to Rectangular direction.
213 	//! @param lng longitude in radian
214 	//! @param lat latitude in radian
215 	//! @param v the resulting 3D unit vector
spheToRect(const double lng,const double lat,Vec3f & v)216 	inline void spheToRect(const double lng, const double lat, Vec3f& v){
217 		const float cosLat = cos(static_cast<float>(lat));
218 		v.set(cos(static_cast<float>(lng)) * cosLat, sin(static_cast<float>(lng)) * cosLat, sin(static_cast<float>(lat)));
219 	}
220 
221 	//! Convert from spherical coordinates to Rectangular direction.
222 	//! @param lng longitude in radian
223 	//! @param lat latitude in radian
224 	//! @param v the resulting 3D unit vector
spheToRect(const float lng,const float lat,Vec3d & v)225 	inline void spheToRect(const float lng, const float lat, Vec3d& v){
226 		const double dlng = static_cast<double>(lng), dlat = static_cast<double>(lat), cosLat = cos(dlat);
227 		v.set(cos(dlng) * cosLat, sin(dlng) * cosLat, sin(dlat));
228 	}
229 
230 	//! Convert from Rectangular direction to spherical coordinate components.
231 	//! @param lng double* to store longitude in radian [-pi, pi]
232 	//! @param lat double* to store latitude in radian
233 	//! @param v the input 3D vector
rectToSphe(double * lng,double * lat,const Vec3d & v)234 	inline void rectToSphe(double *lng, double *lat, const Vec3d& v){
235 		double r = v.length();
236 		*lat = asin(v[2]/r);
237 		*lng = atan2(v[1],v[0]);
238 	}
239 
240 	//! Convert from Rectangular direction to spherical coordinate components.
241 	//! @param lng float* to store longitude in radian [-pi, pi]
242 	//! @param lat float* to store latitude in radian
243 	//! @param v the input 3D vector
rectToSphe(float * lng,float * lat,const Vec3d & v)244 	inline void rectToSphe(float *lng, float *lat, const Vec3d& v){
245 		double r = v.length();
246 		*lat = static_cast<float>(asin(v[2]/r));
247 		*lng = static_cast<float>(atan2(v[1],v[0]));
248 	}
249 
250 
251 	//! Convert from Rectangular direction to spherical coordinate components.
252 	//! @param lng float* to store longitude in radian [-pi, pi]
253 	//! @param lat float* to store latitude in radian
254 	//! @param v the input 3D vector
rectToSphe(float * lng,float * lat,const Vec3f & v)255 	inline void rectToSphe(float *lng, float *lat, const Vec3f& v){
256 		float r = v.length();
257 		*lat = asinf(v[2]/r);
258 		*lng = atan2f(v[1],v[0]);
259 	}
260 
261 	//! Convert from Rectangular direction to spherical coordinate components.
262 	//! @param lng double* to store longitude in radian [-pi, pi]
263 	//! @param lat double* to store latitude in radian
264 	//! @param v the input 3D vector
rectToSphe(double * lng,double * lat,const Vec3f & v)265 	inline void rectToSphe(double *lng, double *lat, const Vec3f &v){
266 		double r = static_cast<double>(v.length());
267 		*lat = asin(static_cast<double>(v[2])/r);
268 		*lng = atan2(static_cast<double>(v[1]),static_cast<double>(v[0]));
269 	}
270 
271 	//! Convert from spherical coordinates (including distance) to Rectangular direction.
272 	//! @param lng longitude in radian
273 	//! @param lat latitude in radian
274 	//! @param r length of radius vector (distance)
275 	//! @param v the resulting 3D unit vector
spheToRect(const double lng,const double lat,const double r,Vec3d & v)276 	inline void spheToRect(const double lng, const double lat, const double r, Vec3d& v){
277 		const double cosLat = cos(lat);
278 		v.set(cos(lng) * cosLat * r, sin(lng) * cosLat * r, sin(lat) * r);
279 	}
280 
281 	//! Convert from Rectangular direction to spherical coordinate components (including distance).
282 	//! @param lng double* to store longitude in radian [-pi, pi]
283 	//! @param lat double* to store latitude in radian
284 	//! @param r double*   length of radius vector (distance)
285 	//! @param v the input 3D vector
rectToSphe(double * lng,double * lat,double * r,const Vec3d & v)286 	inline void rectToSphe(double *lng, double *lat, double *r, const Vec3d& v){
287 		*r = v.length();
288 		*lat = asin(v[2] / *r);
289 		*lng = atan2(v[1],v[0]);
290 	}
291 
292 	//! Coordinate Transformation from equatorial to ecliptical
equToEcl(const double raRad,const double decRad,const double eclRad,double * lambdaRad,double * betaRad)293 	inline void equToEcl(const double raRad, const double decRad, const double eclRad, double *lambdaRad, double *betaRad){
294 		*lambdaRad=std::atan2(std::sin(raRad)*std::cos(eclRad)+std::tan(decRad)*std::sin(eclRad), std::cos(raRad));
295 		*betaRad=std::asin(std::sin(decRad)*std::cos(eclRad)-std::cos(decRad)*std::sin(eclRad)*std::sin(raRad));
296 	}
297 
298 	//! Coordinate Transformation from ecliptical to equatorial
eclToEqu(const double lambdaRad,const double betaRad,const double eclRad,double * raRad,double * decRad)299 	inline void eclToEqu(const double lambdaRad, const double betaRad, const double eclRad, double *raRad, double *decRad){
300 		*raRad = std::atan2(std::sin(lambdaRad)*std::cos(eclRad)-std::tan(betaRad)*std::sin(eclRad), std::cos(lambdaRad));
301 		*decRad = std::asin(std::sin(betaRad)*std::cos(eclRad)+std::cos(betaRad)*std::sin(eclRad)*std::sin(lambdaRad));
302 	}
303 
304 	//! Convert a string longitude, latitude, RA or declination angle
305 	//! to radians.
306 	//! @param str the angle in a format according to:
307 	//!   angle ::= [sign¹] ( real [degs | mins | secs]
308 	//!                     | [integer degs] ( [integer mins] real secs
309 	//!                                       | real mins )
310 	//!                     ) [cardinal¹]
311 	//!   sign ::= + | -
312 	//!   digit := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
313 	//!   integer ::= digit [digits]
314 	//!   real ::= integer [. integer]
315 	//!   degs ::= d | h² | U+00B0 | U+00BA³
316 	//!   mins ::= m | '
317 	//!   secs ::= s | "
318 	//!   cardinal ::= N² | S² | E | W
319 	//!   ¹) A cardinal point overrides any sign. N and E result in a positive,
320 	//!      W and S in a negative angle.
321 	//!   ²) The use of the cardinal points N and S together with the hour sign
322 	//!      'H' or 'h' is forbidden.
323 	//!   ³) The MASCULINE ORDINAL INDICATOR U+00BA is accepted, considering
324 	//!      Spanish QWERTY keyboards.
325 	//! The string is parsed without regarding to case, except that, after a
326 	//! single real, a solitary 's' indicates seconds whereas an 'S' indicates South.
327 	//! It is highly recommended to use lower case for hdms and upper case for NSEW.
328 	//! Latitude: North is positive, South is negative.
329 	//! Longitude: East is positive, West is negative.
330 	//! @return the angle in radians.
331 	double getDecAngle(const QString& str);
332 
333 	//! Check if a number is a power of 2.
isPowerOfTwo(const int value)334 	inline bool isPowerOfTwo(const int value){
335 		return (value & -value) == value;
336 	}
337 
338 	//! Return the first power of two bigger than the given value.
339 	int getBiggerPowerOfTwo(int value);
340 
341 	//! Return the inverse sinus hyperbolic of z.
asinh(const double z)342 	inline double asinh(const double z){
343 		return (z>0 ? std::log(z + std::sqrt(z*z+1)) :
344 			     -std::log(-z + std::sqrt(z*z+1)));
345 	}
346 
347 	//! Integer modulo where the result is always nonnegative. [0..b-1]
imod(const int a,const int b)348 	inline int imod(const int a, const int b){
349 		int ret = a % b;
350 		if(ret < 0)
351 			ret+=b;
352 		return ret;
353 	}
354 	//! Integer modulo where the result is always positive. [1..b]
amod(const int a,const int b)355 	inline int amod(const int a, const int b){
356 		int ret = a % b;
357 		if(ret <= 0)
358 			ret+=b;
359 		return ret;
360 	}
361 	//! Double modulo where the result is always nonnegative. [0..(b
fmodpos(const double a,const double b)362 	inline double fmodpos(const double a, const double b){
363 		double ret = fmod(a, b);
364 		if(ret < 0)
365 			ret+=b;
366 		return ret;
367 	}
368 	//! Float modulo where the result is always nonnegative. [0..(b
fmodpos(const float a,const float b)369 	inline float fmodpos(const float a, const float b){
370 		float ret = fmodf(a, b);
371 		if(ret < 0)
372 			ret+=b;
373 		return ret;
374 	}
375 
376 	//! Floor integer division provides truncating to the next lower integer, also for negative numerators.
377 	//! https://stackoverflow.com/questions/2622441/c-integer-floor-function
378 	//! @returns floor(num/den)
intFloorDiv(long num,long den)379 	inline long intFloorDiv (long num, long den)
380 	{
381 	  if (0 < (num^den)) // lgtm [cpp/bitwise-sign-check]
382 	    return num/den;
383 	  else
384 	    {
385 	      ldiv_t res = ldiv(num,den);
386 	      return (res.rem)? res.quot-1
387 			      : res.quot;
388 	    }
389 	}
390 
391 	//! version of intFloorDiv() for large integers.
intFloorDivLL(long long num,long long den)392 	inline long intFloorDivLL(long long num, long long den)
393 	{
394 	  if (0 < (num^den)) // lgtm [cpp/bitwise-sign-check]
395 	    return static_cast<long>(num/den);
396 	  else
397 	    {
398 	      lldiv_t res = lldiv(num,den);
399 	      long long ret=  (res.rem)? res.quot-1
400 			      : res.quot;
401 	      return static_cast<long>(ret);
402 	    }
403 	}
404 
405 	///////////////////////////////////////////////////
406 	// New Qt based General Calendar Functions.
407 	//! Make from julianDay a year, month, day for the Julian Date julianDay represents.
408 	void getDateFromJulianDay(const double julianDay, int *year, int *month, int *day);
409 
410 	//! Make from julianDay an hour, minute, second.
411 	void getTimeFromJulianDay(const double julianDay, int *hour, int *minute, int *second, int *millis=Q_NULLPTR);
412 
413 	//! Make hours (decimal format) from julianDay
414 	double getHoursFromJulianDay(const double julianDay);
415 
416 	//! Parse an ISO8601 date string.
417 	//! Also handles negative and distant years.
418 	bool getDateTimeFromISO8601String(const QString& iso8601Date, int* y, int* m, int* d, int* h, int* min, float* s);
419 
420 	//! Format the given Julian Day in (UTC) ISO8601 date string.
421 	//! Also handles negative and distant years.
422 	QString julianDayToISO8601String(const double jd, bool addMS = false);
423 
424 	//! Return the Julian Date matching the ISO8601 date string.
425 	//! Also handles negative and distant years.
426 	double getJulianDayFromISO8601String(const QString& iso8601Date, bool* ok);
427 
428 	//! Format the date and day-of-week per the format in fmt
429 	//! (see QDateTime::toString()). Uses the @b system locale, not
430 	//! the one set in Stellarium.
431 	//! @return QString representing the formatted date
432 	QString localeDateString(const int year, const int month, const int day, const int dayOfWeek, const QString &fmt);
433 
434 	//! Format the date and day-of-week per the @b system locale's
435 	//! QLocale::ShortFormat.
436 	//! @return QString representing the formatted date
437 	QString localeDateString(const int year, const int month, const int day, const int dayOfWeek);
438 
439 	//! Return a day number of week for date
440 	//! @return number of day: 0 - sunday, 1 - monday,..
441 	int getDayOfWeek(int year, int month, int day);
getDayOfWeek(double JD)442 	inline int getDayOfWeek(double JD){ double d= fmod(JD+1.5, 7); if (d<0) d+=7.0;
443 		return std::lround(floor(d));
444 	}
445 
446 	//! Get the current Julian Date from system time.
447 	//! @return the current Julian Date
448 	double getJDFromSystem();
449 
450 	//! Get the Julian Day Number (JD) from Besselian epoch.
451 	//! @param epoch Besselian epoch, expressed as year
452 	//! @return Julian Day number (JD) for B<Year>
453 	double getJDFromBesselianEpoch(const double epoch);
454 
455 	//! Convert a time of day to the fraction of a Julian Day.
456 	//! Note that a Julian Day starts at 12:00, not 0:00, and
457 	//! so 12:00 == 0.0 and 0:00 == 0.5
458 	double qTimeToJDFraction(const QTime& time);
459 
460 	//! Convert a fraction of a Julian Day to a QTime
461 	QTime jdFractionToQTime(const double jd);
462 
463 	//! Convert a QT QDateTime class to julian day.
464 	//! @param dateTime the UTC QDateTime to convert
465 	//! @result the matching decimal Julian Day
qDateTimeToJd(const QDateTime & dateTime)466 	inline double qDateTimeToJd(const QDateTime& dateTime){
467 		return dateTime.date().toJulianDay()+static_cast<double>(1./(24*60*60*1000))*QTime(0, 0, 0, 0).msecsTo(dateTime.time())-0.5;
468 	}
469 
470 	//! Convert a julian day to a QDateTime.
471 	//! @param jd to convert
472 	//! @result the matching UTC QDateTime
473 	QDateTime jdToQDateTime(const double& jd);
474 
475 	//! Compute Julian day number from calendar date.
476 	//! Uses QDate functionality if possible, but also works for negative JD.
477 	//! Dates before 1582-10-15 are in the Julian Calendar.
478 	//! @param newjd pointer to JD
479 	//! @param y Calendar year.
480 	//! @param m month, 1=January ... 12=December
481 	//! @param d day
482 	//! @param h hour
483 	//! @param min minute
484 	//! @param s second
485 	//! @result true in all conceivable cases.
486 	bool getJDFromDate(double* newjd, const int y, const int m, const int d, const int h, const int min, const float s);
487 
488 	int numberOfDaysInMonthInYear(const int month, const int year);
489 	//! @result true if year is a leap year. Observes 1582 switch from Julian to Gregorian Calendar.
490 	bool isLeapYear(const int year);
491 	//! Find day number for date in year.
492 	//! Meeus, Astronomical Algorithms 2nd ed., 1998, ch.7, p.65
493 	int dayInYear(const int year, const int month, const int day);
494 	//! Return a fractional year like YYYY.ddddd. For negative years, the year number is decreased. E.g. -500.5 occurs in -501.
495 	double yearFraction(const int year, const int month, const double day);
496 
497 	bool changeDateTimeForRollover(int oy, int om, int od, int oh, int omin, int os,
498 				       int* ry, int* rm, int* rd, int* rh, int* rmin, int* rs);
499 
500 	//! Output a QVariantMap to qDebug().  Formats like a tree where there are nested objects.
501 	void debugQVariantMap(const QVariant& m, const QString& indent="", const QString& key="");
502 
503 
504 	/// Compute acos(x)
505 	//! The taylor serie is not accurate around x=1 and x=-1
fastAcos(const float x)506 	inline float fastAcos(const float x)
507 	{
508 		return static_cast<float>(M_PI_2) - (x + x*x*x * (1.f/6.f + x*x * (3.f/40.f + 5.f/112.f * x*x)) );
509 	}
510 
511 	//! Compute exp(x) for small exponents x
fastExp(const float x)512 	inline float fastExp(const float x)
513 	{
514 		return (x>=0)?
515 			(1.f + x*(1.f+ x/2.f*(1.f+ x/3.f*(1.f+x/4.f*(1.f+x/5.f))))):
516 				1.f / (1.f -x*(1.f -x/2.f*(1.f- x/3.f*(1.f-x/4.f*(1.f-x/5.f)))));
517 	}
518 
519 	// Calculate and return sidereal period in days from semi-major axis (in AU)
520 	//double calculateSiderealPeriod(const double SemiMajorAxis);  MOVED TO Orbit.h
521 
522 	//! Convert decimal hours to hours, minutes, seconds
523 	QString hoursToHmsStr(const double hours, const bool lowprecision = false);
524 	QString hoursToHmsStr(const float hours, const bool lowprecision = false);
525 
526 	//! Convert a hms formatted string to decimal hours
527 	double hmsStrToHours(const QString& s);
528 
529 	//! Convert days (float) to a time string
530 	QString daysFloatToDHMS(float days);
531 
532 	//! Get Delta-T estimation for a given date.
533 	//! This is just an "empty" correction function, returning 0.
534 	double getDeltaTwithoutCorrection(const double jDay);
535 
536 	//! Get Delta-T estimation for a given date.
537 	//! Note that this method is recommended for the year range:
538 	//! -1999 to +3000. It gives details for -500...+2150.
539 	//! Implementation of algorithm by Espenak & Meeus (2006) for DeltaT computation
540 	//! @param jDay the date and time expressed as a Julian day
541 	//! @return Delta-T in seconds
542 	double getDeltaTByEspenakMeeus(const double jDay);
543 
544 	//! Get Delta-T estimation for a given date.
545 	//! Implementation of algorithm by Schoch (1931) for DeltaT computation,
546 	//! outdated but may be useful for science-historical purposes.
547 	//! Source: Schoch, C. (1931). Die sekulare Accelaration des Mondes und der Sonne.
548 	//! Astronomische Abhandlungen, Ergnzungshefte zu den Astronomischen Nachrichten,
549 	//! Band 8, B2. Kiel.
550 	//! @param jDay the date and time expressed as a Julian day
551 	//! @return Delta-T in seconds
552 	double getDeltaTBySchoch(const double jDay);
553 
554 	//! Get Delta-T estimation for a given date.
555 	//! Implementation of algorithm by Clemence (1948) for DeltaT computation,
556 	//! outdated but may be useful for science-historical purposes.
557 	//! Source: On the system of astronomical constants.
558 	//! Clemence, G. M.
559 	//! Astronomical Journal, Vol. 53, p. 169
560 	//! 1948AJ.....53..169C [http://adsabs.harvard.edu/abs/1948AJ.....53..169C]
561 	//! @param jDay the date and time expressed as a Julian day
562 	//! @return Delta-T in seconds
563 	double getDeltaTByClemence(const double jDay);
564 
565 	//! Get Delta-T estimation for a given date.
566 	//! Implementation of algorithm by IAU (1952) for DeltaT computation,
567 	//! outdated but may be useful for science-historical purposes.
568 	//! Source: Spencer Jones, H., "The Rotation of the Earth, and the Secular Accelerations of the Sun, Moon and Planets",
569 	//! Monthly Notices of the Royal Astronomical Society, 99 (1939), 541-558
570 	//! http://adsabs.harvard.edu/abs/1939MNRAS..99..541S
571 	//! @param jDay the date and time expressed as a Julian day
572 	//! @return Delta-T in seconds
573 	double getDeltaTByIAU(const double jDay);
574 
575 	//! Get Delta-T estimation for a given date.
576 	//! Implementation of algorithm by Astronomical Ephemeris (1960) for DeltaT computation.
577 	//! Sources: Spencer Jones, H., "The Rotation of the Earth, and the Secular Accelerations of the Sun, Moon and Planets",
578 	//! Monthly Notices of the Royal Astronomical Society, 99 (1939), 541-558
579 	//! http://adsabs.harvard.edu/abs/1939MNRAS..99..541S
580 	//! or Explanatory Supplement to the Astr. Ephemeris, 1961, p.87.
581 	//! Also used by Mucke&Meeus, Canon of Solar Eclipses, Vienna 1983.
582 	//! @param jDay the date and time expressed as a Julian day
583 	//! @return Delta-T in seconds
584 	double getDeltaTByAstronomicalEphemeris(const double jDay);
585 
586 	//! Get Delta-T estimation for a given date.
587 	//! Implementation of algorithm by Tuckerman (1962, 1964) & Goldstine (1973) for DeltaT computation
588 	//! @param jDay the date and time expressed as a Julian day
589 	//! @return Delta-T in seconds
590 	double getDeltaTByTuckermanGoldstine(const double jDay);
591 
592 	//! Get Delta-T estimation for a given date.
593 	//! Implementation of algorithm by Muller & Stephenson (1975) for DeltaT computation.
594 	//! Source: The accelerations of the earth and moon from early astronomical observations
595 	//! Muller, P. M.; Stephenson, F. R.
596 	//! Growth rhythms and the history of the earth's rotation; Proceedings of the Interdisciplinary
597 	//! Winter Conference on Biological Clocks and Changes in the Earth's Rotation: Geophysical and
598 	//! Astronomical Consequences, Newcastle-upon-Tyne, England, January 8-10, 1974. (A76-18126 06-46)
599 	//! London, Wiley-Interscience, 1975, p. 459-533; Discussion, p. 534.
600 	//! 1975grhe.conf..459M [http://adsabs.harvard.edu/abs/1975grhe.conf..459M]
601 	//! @param jDay the date and time expressed as a Julian day
602 	//! @return Delta-T in seconds
603 	double getDeltaTByMullerStephenson(const double jDay);
604 
605 	//! Get Delta-T estimation for a given date.
606 	//! Implementation of algorithm by Stephenson (1978) for DeltaT computation.
607 	//! Source: Pre-Telescopic Astronomical Observations
608 	//! Stephenson, F. R.
609 	//! Tidal Friction and the Earth's Rotation, Proceedings of a Workshop, held in Bielefeld,
610 	//! September 26-30, 1977, Edited by P. Brosche, and J. Sundermann. Berlin: Springer-Verlag, 1978, p.5
611 	//! 1978tfer.conf....5S [http://adsabs.harvard.edu/abs/1978tfer.conf....5S]
612 	//! @param jDay the date and time expressed as a Julian day
613 	//! @return Delta-T in seconds
614 	double getDeltaTByStephenson1978(const double jDay);
615 
616 	//! Get Delta-T estimation for a given date.
617 	//! Implementation of algorithm by Stephenson (1997) for DeltaT computation.
618 	//! Source: Book "Historical Eclipses and Earth's Rotation" by F. R. Stephenson (1997)
619 	//! http://ebooks.cambridge.org/ebook.jsf?bid=CBO9780511525186
620 	//! @param jDay the date and time expressed as a Julian day
621 	//! @return Delta-T in seconds
622 	double getDeltaTByStephenson1997(const double jDay);
623 
624 	//! Get Delta-T estimation for a given date.
625 	//! Implementation of algorithm by Schmadel & Zech (1979) for DeltaT computation.
626 	//! Outdated, but may be useful for science-historical purposes.
627 	//! Source: Polynomial approximations for the correction delta T E.T.-U.T. in the period 1800-1975
628 	//! Schmadel, L. D.; Zech, G.
629 	//! Acta Astronomica, vol. 29, no. 1, 1979, p. 101-104.
630 	//! 1979AcA....29..101S [http://adsabs.harvard.edu/abs/1979AcA....29..101S]
631 	//! @param jDay the date and time expressed as a Julian day
632 	//! @return Delta-T in seconds
633 	//! @note The polynome is strictly applicable 1800...1975 only! Delivers values for the nearer edge (1800/1989) if jDay is outside.
634 	double getDeltaTBySchmadelZech1979(const double jDay);
635 
636 	//! Get Delta-T estimation for a given date.
637 	//! Implementation of algorithm by Morrison & Stephenson (1982) for DeltaT computation
638 	//! @param jDay the date and time expressed as a Julian day
639 	//! @return Delta-T in seconds
640 	double getDeltaTByMorrisonStephenson1982(const double jDay);
641 
642 	//! Get Delta-T estimation for a given date.
643 	//! Implementation of algorithm by Stephenson & Morrison (1984) for DeltaT computation
644 	//! Source: Long-term changes in the rotation of the earth - 700 B.C. to A.D. 1980.
645 	//! Stephenson, F. R.; Morrison, L. V.
646 	//! Philosophical Transactions, Series A (ISSN 0080-4614), vol. 313, no. 1524, Nov. 27, 1984, p. 47-70.
647 	//! 1984RSPTA.313...47S [http://adsabs.harvard.edu/abs/1984RSPTA.313...47S]
648 	//! @param jDay the date and time expressed as a Julian day
649 	//! @return Delta-T in seconds or Zero if date outside years -391..1600
650 	double getDeltaTByStephensonMorrison1984(const double jDay);
651 
652 	//! Get Delta-T estimation for a given date.
653 	//! Implementation of algorithm by Stephenson & Morrison (1995) for DeltaT computation
654 	//! Source: Long-Term Fluctuations in the Earth's Rotation: 700 BC to AD 1990.
655 	//! Stephenson, F. R.; Morrison, L. V.
656 	//! Philosophical Transactions: Physical Sciences and Engineering, Volume 351, Issue 1695, pp. 165-202
657 	//! 1995RSPTA.351..165S [http://adsabs.harvard.edu/abs/1995RSPTA.351..165S]
658 	//! @param jDay the date and time expressed as a Julian day
659 	//! @return Delta-T in seconds
660 	double getDeltaTByStephensonMorrison1995(const double jDay);
661 
662 	//! Get Delta-T estimation for a given date.
663 	//! Implementation of algorithm by Stephenson & Houlden (1986) for DeltaT computation
664 	//! @param jDay the date and time expressed as a Julian day
665 	//! @return Delta-T in seconds or 0 if year > 1600
666 	double getDeltaTByStephensonHoulden(const double jDay);
667 
668 	//! Get Delta-T estimation for a given date.
669 	//! Implementation of algorithm by Espenak (1987, 1989) for DeltaT computation.
670 	//! This relation should not be used before around 1950 or after around 2100 (Espenak, pers. comm.).
671 	//! @param jDay the date and time expressed as a Julian day
672 	//! @return Delta-T in seconds
673 	double getDeltaTByEspenak(const double jDay);
674 
675 	//! Get Delta-T estimation for a given date.
676 	//! Implementation of algorithm by Borkowski (1988) for DeltaT computation.
677 	//! Source: ELP 2000-85 and the dynamic time-universal time relation
678 	//! Borkowski, K. M.
679 	//! Astronomy and Astrophysics (ISSN 0004-6361), vol. 205, no. 1-2, Oct. 1988, p. L8-L10.
680 	//! 1988A&A...205L...8B [http://adsabs.harvard.edu/abs/1988A&A...205L...8B]
681 	//! @param jDay the date and time expressed as a Julian day
682 	//! @return Delta-T in seconds
683 	double getDeltaTByBorkowski(const double jDay);
684 
685 	//! Get Delta-T estimation for a given date.
686 	//! Implementation of algorithm by Schmadel & Zech (1988) for DeltaT computation.
687 	//! Source: Empirical Transformations from U.T. to E.T. for the Period 1800-1988
688 	//! Schmadel, L. D.; Zech, G.
689 	//! Astronomische Nachrichten 309, 219-221
690 	//! 1988AN....309..219S [http://adsabs.harvard.edu/abs/1988AN....309..219S]
691 	//! @param jDay the date and time expressed as a Julian day
692 	//! @return Delta-T in seconds
693 	//! @note The polynome is strictly applicable 1800...1988 only! Delivers values for the nearer edge (1800/1989) if jDay is outside.
694 	double getDeltaTBySchmadelZech1988(const double jDay);
695 
696 	//! Get Delta-T estimation for a given date.
697 	//! Implementation of algorithm by Chapront-Touzé & Chapront (1991) for DeltaT computation
698 	//! @param jDay the date and time expressed as a Julian day
699 	//! @return Delta-T in seconds or 0 if year not in -391..1600
700 	double getDeltaTByChaprontTouze(const double jDay);
701 
702 	//! Get Delta-T estimation for a given date.
703 	//! Implementation of the "historical" part of the algorithm by JPL Horizons for DeltaT computation.
704 	//! @param jDay the date and time expressed as a Julian day
705 	//! @return Delta-T in seconds or 0 if year not in -2999..1620 (!)
706 	double getDeltaTByJPLHorizons(const double jDay);
707 
708 	//! Get Delta-T estimation for a given date.
709 	//! Implementation of algorithm by Morrison & Stephenson (2004, 2005) for DeltaT computation.
710 	//! Sources: Historical values of the Earth's clock error ΔT and the calculation of eclipses
711 	//! Morrison, L. V.; Stephenson, F. R.
712 	//! Journal for the History of Astronomy (ISSN 0021-8286), Vol. 35, Part 3, No. 120, p. 327 - 336 (2004)
713 	//! 2004JHA....35..327M [http://adsabs.harvard.edu/abs/2004JHA....35..327M]
714 	//! Addendum: Historical values of the Earth's clock error
715 	//! Morrison, L. V.; Stephenson, F. R.
716 	//! Journal for the History of Astronomy (ISSN 0021-8286), Vol. 36, Part 3, No. 124, p. 339 (2005)
717 	//! 2005JHA....36..339M [http://adsabs.harvard.edu/abs/2005JHA....36..339M]
718 	//! @param jDay the date and time expressed as a Julian day
719 	//! @return Delta-T in seconds
720 	double getDeltaTByMorrisonStephenson2004(const double jDay);
721 
722 	//! Get Delta-T estimation for a given date.
723 	//! Implementation of algorithm by Reijs (2006) for DeltaT computation
724 	//! Details: http://www.iol.ie/~geniet/eng/DeltaTeval.htm
725 	//! @param jDay the date and time expressed as a Julian day
726 	//! @return Delta-T in seconds
727 	double getDeltaTByReijs(const double jDay);
728 
729 	//! Get Delta-T estimation for a given date.
730 	//! Implementation of algorithm by Chapront, Chapront-Touze & Francou (1997) & Meeus (1998) for DeltaT computation
731 	//! @param jDay the date and time expressed as a Julian day
732 	//! @return Delta-T in seconds
733 	double getDeltaTByChaprontMeeus(const double jDay);
734 
735 	//! Get Delta-T estimation for a given date.
736 	//! Implementation of algorithm by Meeus & Simons (2000) for DeltaT computation.
737 	//! Source: Polynomial approximations to Delta T, 1620-2000 AD
738 	//! Meeus, J.; Simons, L.
739 	//! Journal of the British Astronomical Association, vol.110, no.6, 323
740 	//! 2000JBAA..110..323M [http://adsabs.harvard.edu/abs/2000JBAA..110..323M]
741 	//! @param jDay the date and time expressed as a Julian day
742 	//! @return Delta-T in seconds or 0 if year not in 1620..2000
743 	double getDeltaTByMeeusSimons(const double jDay);
744 
745 	//! Get Delta-T estimation for a given date.
746 	//! Implementation of algorithm by Montenbruck & Pfleger (2000) for DeltaT computation,
747 	//! a data fit through the table of values found in Meeus, Astronomical algorithms (1991).
748 	//! Book "Astronomy on the Personal Computer" by O. Montenbruck & T. Pfleger (4th ed., 2000), p.181-182
749 	//! @param jDay the date and time expressed as a Julian day
750 	//! @return Delta-T in seconds or 0 if not 1825<=year<2005
751 	double getDeltaTByMontenbruckPfleger(const double jDay);
752 
753 	//! Get Delta-T estimation for a given date.
754 	//! Implementation of algorithm by Reingold & Dershowitz (1997, 2001, 2002, 2007, 2018) for DeltaT computation.
755 	//! This is again mostly a data fit based on the table in Meeus, Astronomical Algorithms (1991).
756 	//! This is the version given in the 4rd edition ("the ultimate edition"; 2018) which added the fit
757 	//! for -500..1699 and 2006..2150 omitted from previous editions.
758 	//! Calendrical Calculations: The Ultimate Edition / Edward M. Reingold, Nachum Dershowitz - 4th Edition,
759 	//! Cambridge University Press, 2018. - 660p. ISBN: 9781107057623, DOI: 10.1017/9781107415058
760 	//! @param jDay the date and time expressed as a Julian day
761 	//! @return Delta-T in seconds
762 	double getDeltaTByReingoldDershowitz(const double jDay);
763 
764 	//! Get Delta-T estimation for a given date.
765 	//! Implementation of algorithm by Banjevic (2006) for DeltaT computation.
766 	//! Source: Ancient eclipses and dating the fall of Babylon
767 	//! Banjevic, B.
768 	//! Publications of the Astronomical Observatory of Belgrade, Vol. 80, p. 251-257 (2006)
769 	//! 2006POBeo..80..251B [http://adsabs.harvard.edu/abs/2006POBeo..80..251B]
770 	//! @param jDay the date and time expressed as a Julian day
771 	//! @return Delta-T in seconds
772 	double getDeltaTByBanjevic(const double jDay);
773 
774 	//! Get Delta-T estimation for a given date.
775 	//! Implementation of algorithm by Islam, Sadiq & Qureshi (2008 + revisited 2013) for DeltaT computation.
776 	//! Source: Error Minimization of Polynomial Approximation of DeltaT
777 	//! Islam, S. & Sadiq, M. & Qureshi, M. S.
778 	//! Journal of Astrophysics & Astronomy, Vol. 29, p. 363-366 (2008)
779 	//! http://www.ias.ac.in/jaa/dec2008/JAA610.pdf
780 	//! Note: These polynomials are based on the uncorrected deltaT table from the Astronomical Almanac, thus
781 	//! ndot = -26.0 arcsec/cy^2. Meeus & Simons (2000) corrected the deltaT table for years before 1955.5 using
782 	//! ndot = -25.7376 arcsec/cy^2. Therefore the accuracies stated by Meeus & Simons are correct and cannot be
783 	//! compared with accuracies from Islam & Sadiq & Qureshi.
784 	//! @param jDay the date and time expressed as a Julian day
785 	//! @return Delta-T in seconds
786 	double getDeltaTByIslamSadiqQureshi(const double jDay);
787 
788 	//! Get Delta-T estimation for a given date.
789 	//! Implementation of polinomial approximation of time period 1620-2013 for DeltaT by M. Khalid, Mariam Sultana and Faheem Zaidi (2014).
790 	//! Source: Delta T: Polynomial Approximation of Time Period 1620-2013
791 	//! Journal of Astrophysics, Vol. 2014, Article ID 480964
792 	//! https://doi.org/10.1155/2014/480964
793 	//! @param jDay the date and time expressed as a Julian day
794 	//! @return Delta-T in seconds
795 	double getDeltaTByKhalidSultanaZaidi(const double jDay);
796 
797 	//! Get Delta-T estimation for a given date.
798 	//! Implementation of a spline approximation for time period -720-2016.0 for DeltaT by Stephenson, Morrison and Hohenkerk (2016).
799 	//! Source: Measurement of the Earth’s rotation: 720 BC to AD 2015
800 	//! Proc. R. Soc. A 472: 20160404.
801 	//! https://doi.org/10.1098/rspa.2016.0404
802 	//! @param jDay the date and time expressed as a Julian day
803 	//! @return Delta-T in seconds. For times outside the limits, return result from the fitting parabola.
804 	double getDeltaTByStephensonMorrisonHohenkerk2016(const double jDay);
805 
806 	//! Get Secular Acceleration estimation for a given year.
807 	//! Method described is here: http://eclipse.gsfc.nasa.gov/SEcat5/secular.html
808 	//! For adapting from -26 to -25.858, use -0.91072 * (-25.858 + 26.0) = -0.12932224
809 	//! For adapting from -26 to -23.895, use -0.91072 * (-23.895 + 26.0) = -1.9170656
810 	//! @param jDay the JD
811 	//! @param ndot value of n-dot (secular acceleration of the Moon) which should be used in the lunar ephemeris instead of the default values.
812 	//! @param useDE4xx true if function should adapt calculation of the secular acceleration of the Moon to the DE43x/DE44x ephemerides
813 	//! @return SecularAcceleration in seconds
814 	//! @note n-dot for secular acceleration of the Moon in ELP2000-82B is -23.8946 "/cy/cy and for DE43x/DE44x is -25.8 "/cy/cy
815 	double getMoonSecularAcceleration(const double jDay, const double ndot, const bool useDE4xx);
816 
817 	//! Get the standard error (sigma) for the value of DeltaT
818 	//! @param jDay the JD
819 	//! @return sigma in seconds
820 	double getDeltaTStandardError(const double jDay);
821 
822 	//! Get value of the Moon fluctuation
823 	//! Source: The Rotation of the Earth, and the Secular Accelerations of the Sun, Moon and Planets
824 	//! Spencer Jones, H.
825 	//! Monthly Notices of the Royal Astronomical Society, 99 (1939), 541-558
826 	//! 1939MNRAS..99..541S [http://adsabs.harvard.edu/abs/1939MNRAS..99..541S]
827 	//! @param jDay the JD
828 	//! @return fluctuation in seconds
829 	double getMoonFluctuation(const double jDay);
830 
831 	//! Sign function from http://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
sign(T val)832 	template <typename T> int sign(T val)
833 	{
834 		return (T(0) < val) - (val < T(0));
835 	}
836 
837 	//! Compute cosines and sines around a circle which is split in "slices" parts.
838 	//! Values are stored in the global static array cos_sin_theta.
839 	//! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh.
840 	//! @param slices number of partitions (elsewhere called "segments") for the circle
841 	float *ComputeCosSinTheta(const unsigned int slices);
842 
843 	//! Compute cosines and sines around a half-circle which is split in "segments" parts.
844 	//! Values are stored in the global static array cos_sin_rho.
845 	//! Used for the sin/cos values along a meridian for a spherical mesh.
846 	//! @param segments number of partitions (elsewhere called "stacks") for the half-circle
847 	float *ComputeCosSinRho(const unsigned int segments);
848 
849 	//! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts.
850 	//! Values are stored in the global static array cos_sin_rho.
851 	//! Used for the sin/cos values along a meridian.
852 	//! This allows leaving away pole caps. The array now contains values for the region minAngle+segments*phi
853 	//! @param dRho a difference angle between the stops
854 	//! @param segments number of segments
855 	//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi
856 	float* ComputeCosSinRhoZone(const float dRho, const unsigned int segments, const float minAngle);
857 
858 	//! Calculate fixed days (R.D.) from Gregorian date
859 	//! @param year
860 	//! @param month
861 	//! @param day
862 	//! @return days from Rata Die
863 	int getFixedFromGregorian(const int year, const int month, const int day);
864 
865 	//! Comparison two string versions and return a result in range -1,0,1
866 	//! @param v1 string for version 1
867 	//! @param v2 string for version 2
868 	//! @return result (-1: v1<v2; 0: v1==v2; 1: v1>v2)
869 	int compareVersions(const QString v1, const QString v2);
870 
871 	//! Uncompress gzip or zlib compressed data.
872 	QByteArray uncompress(const QByteArray& data);
873 
874 	//! Uncompress (gzip/zlib) data from this QIODevice, which must be open and readable.
875 	//! @param device The device to read from, must already be opened with an OpenMode supporting reading
876 	//! @param maxBytes The max. amount of bytes to read from the device, or -1 to read until EOF.  Note that it
877 	//! always stops when inflate() returns Z_STREAM_END. Positive values can be used for interleaving compressed data
878 	//! with other data.
879 	QByteArray uncompress(QIODevice &device, qint64 maxBytes=-1);
880 
881 	//! Greatest Common Divisor (Euclid's algorithm)
882 	//! @param a first number
883 	//! @param b second number
884 	//! @return Greatest Common Divisor
885 	int gcd(int a, int b);
886 
887 	//! Least Common Multiple
888 	//! @param a first number
889 	//! @param b second number
890 	//! @return Least Common Multiple
891 	int lcm(int a, int b);
892 
893 	//! Given regularly spaced steps x1, x2, x3 and curve values y1, y2, y3,
894 	//! calculate an intermediate value of the 3 arguments for the given interpolation point n.
895 	//! @param n Interpolation factor: steps from x2
896 	//! @param y1 Argument 1
897 	//! @param y2 Argument 2
898 	//! @param y3 Argument 3
899 	//! @return interpolation value
interpolate3(T n,T y1,T y2,T y3)900 	template<class T> T interpolate3(T n, T y1, T y2, T y3)
901 	{
902 		// See "Astronomical Algorithms" by J. Meeus
903 
904 		// Equation 3.2
905 		T a = y2-y1;
906 		T b = y3-y2;
907 		T c = b-a;
908 
909 		// Equation 3.3
910 		return y2 + n * 0.5f * (a + b + n * c);
911 	}
912 
913 	//! Given regularly spaced steps x1, x2, x3, x4, x5 and curve values y1, y2, y3, y4, y5,
914 	//! calculate an intermediate value of the 5 arguments for the given interpolation point n.
915 	//! @param n Interpolation factor: steps from x3
916 	//! @param y1 Argument 1
917 	//! @param y2 Argument 2
918 	//! @param y3 Argument 3
919 	//! @param y3 Argument 4
920 	//! @param y3 Argument 5
921 	//! @return interpolation value
interpolate5(T n,T y1,T y2,T y3,T y4,T y5)922 	template<class T> T interpolate5(T n, T y1, T y2, T y3, T y4, T y5)
923 	{
924 		// See "Astronomical Algorithms" by J. Meeus
925 		// Eq. 3.8
926 		T A=y2-y1; T B=y3-y2; T C=y4-y3; T D=y5-y4;
927 		T E=B-A; T F=C-B; T G=D-C;
928 		T H=F-E; T J=G-F;
929 		T K=J-H;
930 
931 		return (((K*(1.0/24.0)*n + (H+J)/12.0)*n  + (F*0.5-K/24.0))*n + ((B+C)*0.5 - (H+J)/12.0))*n +y3;
932 	}
933 
934 	//! Interval test. This checks whether @param value is within [@param low, @param high]
isWithin(const T & value,const T & low,const T & high)935 	template <typename T> bool isWithin(const T& value, const T& low, const T& high)
936 	{
937 	    return !(value < low) && !(high < value);
938 	}
939 
940 
941 #ifdef _MSC_BUILD
trunc(double x)942 	inline double trunc(double x)
943 	{
944 		return (x < 0 ? std::ceil(x) : std::floor(x));
945 	}
trunc(float x)946 	inline float trunc(float x)
947 	{
948 		return (x < 0 ? std::ceil(x) : std::floor(x));
949 	}
950 #else
trunc(double x)951 	inline double trunc(double x) { return ::trunc(x); }
trunc(float x)952 	inline float trunc(float x) { return ::trunc(x); }
953 #endif
954 }
955 
956 #endif // STELUTILS_HPP
957