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