00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <cmath>
00011 #include <iomanip>
00012 #include <cstdio>
00013 #include <celmath/mathlib.h>
00014 #include "celestia.h"
00015 #include "astro.h"
00016
00017 using namespace std;
00018
00019 const double astro::speedOfLight = 299792.458;
00020
00021
00022 const double astro::J2000 = 2451545.0;
00023
00024 const double astro::G = 6.672e-11;
00025
00026 const double astro::SolarMass = 1.989e30;
00027 const double astro::EarthMass = 5.976e24;
00028 const double astro::LunarMass = 7.354e22;
00029
00030
00031 #define B1950 2433282.423
00032
00033 static Mat3f equatorialToCelestial = Mat3f::xrotation(degToRad(23.4392911f));
00034 static Mat3d equatorialToCelestiald = Mat3d::xrotation(degToRad(23.4392911));
00035
00036
00037 float astro::lumToAbsMag(float lum)
00038 {
00039 return (float) (SOLAR_ABSMAG - log(lum) * LN_MAG);
00040 }
00041
00042
00043
00044 float astro::lumToAppMag(float lum, float lyrs)
00045 {
00046 return absToAppMag(lumToAbsMag(lum), lyrs);
00047 }
00048
00049 float astro::absMagToLum(float mag)
00050 {
00051 return (float) exp((SOLAR_ABSMAG - mag) / LN_MAG);
00052 }
00053
00054 float astro::appMagToLum(float mag, float lyrs)
00055 {
00056 return absMagToLum(appToAbsMag(mag, lyrs));
00057 }
00058
00059 float astro::absToAppMag(float absMag, float lyrs)
00060 {
00061 return (float) (absMag - 5 + 5 * log10(lyrs / LY_PER_PARSEC));
00062 }
00063
00064 float astro::appToAbsMag(float appMag, float lyrs)
00065 {
00066 return (float) (appMag + 5 - 5 * log10(lyrs / LY_PER_PARSEC));
00067 }
00068
00069 float astro::lightYearsToParsecs(float ly)
00070 {
00071 return ly / (float) LY_PER_PARSEC;
00072 }
00073
00074 double astro::lightYearsToParsecs(double ly)
00075 {
00076 return ly / (double) LY_PER_PARSEC;
00077 }
00078
00079 float astro::parsecsToLightYears(float pc)
00080 {
00081 return pc * (float) LY_PER_PARSEC;
00082 }
00083
00084 double astro::parsecsToLightYears(double pc)
00085 {
00086 return pc * (double) LY_PER_PARSEC;
00087 }
00088
00089 float astro::lightYearsToKilometers(float ly)
00090 {
00091 return ly * (float) KM_PER_LY;
00092 }
00093
00094 double astro::lightYearsToKilometers(double ly)
00095 {
00096 return ly * KM_PER_LY;
00097 }
00098
00099 float astro::kilometersToLightYears(float km)
00100 {
00101 return km / (float) KM_PER_LY;
00102 }
00103
00104 double astro::kilometersToLightYears(double km)
00105 {
00106 return km / KM_PER_LY;
00107 }
00108
00109 float astro::lightYearsToAU(float ly)
00110 {
00111 return ly * (float) AU_PER_LY;
00112 }
00113
00114 double astro::lightYearsToAU(double ly)
00115 {
00116 return ly * AU_PER_LY;
00117 }
00118
00119 float astro::AUtoLightYears(float au)
00120 {
00121 return au / (float) AU_PER_LY;
00122 }
00123
00124 float astro::AUtoKilometers(float au)
00125 {
00126 return au * (float) KM_PER_AU;
00127 }
00128
00129 double astro::AUtoKilometers(double au)
00130 {
00131 return au * (double) KM_PER_AU;
00132 }
00133
00134 float astro::kilometersToAU(float km)
00135 {
00136 return km / (float) KM_PER_AU;
00137 }
00138
00139 double astro::kilometersToAU(double km)
00140 {
00141 return km / KM_PER_AU;
00142 }
00143
00144 double astro::secondsToJulianDate(double sec)
00145 {
00146 return sec / 86400.0;
00147 }
00148
00149 double astro::julianDateToSeconds(double jd)
00150 {
00151 return jd * 86400.0;
00152 }
00153
00154 void astro::decimalToDegMinSec(double angle, int& hours, int& minutes, double& seconds)
00155 {
00156 double A, B, C;
00157
00158 hours = (int) angle;
00159
00160 A = angle - (double) hours;
00161 B = A * 60.0;
00162 minutes = (int) B;
00163 C = B - (double) minutes;
00164 seconds = C * 60.0;
00165 }
00166
00167 double astro::degMinSecToDecimal(int hours, int minutes, double seconds)
00168 {
00169 return (double)hours + (seconds/60.0 + (double)minutes)/60.0;
00170 }
00171
00172
00173
00174
00175 float astro::sphereIlluminationFraction(Point3d spherePos,
00176 Point3d viewerPos)
00177 {
00178 return 1.0f;
00179 }
00180
00181 float astro::microLightYearsToKilometers(float ly)
00182 {
00183 return ly * ((float) KM_PER_LY * 1e-6f);
00184 }
00185
00186 double astro::microLightYearsToKilometers(double ly)
00187 {
00188 return ly * (KM_PER_LY * 1e-6);
00189 }
00190
00191 float astro::kilometersToMicroLightYears(float km)
00192 {
00193 return km / ((float) KM_PER_LY * 1e-6f);
00194 }
00195
00196 double astro::kilometersToMicroLightYears(double km)
00197 {
00198 return km / (KM_PER_LY * 1e-6);
00199 }
00200
00201 float astro::microLightYearsToAU(float ly)
00202 {
00203 return ly * (float) AU_PER_LY * 1e-6f;
00204 }
00205
00206 double astro::microLightYearsToAU(double ly)
00207 {
00208 return ly * AU_PER_LY * 1e-6;
00209 }
00210
00211 float astro::AUtoMicroLightYears(float au)
00212 {
00213 return au / ((float) AU_PER_LY * 1e-6f);
00214 }
00215
00216 double astro::AUtoMicroLightYears(double au)
00217 {
00218 return au / (AU_PER_LY * 1e-6);
00219 }
00220
00221
00222
00223
00224
00225
00226
00227 Point3d astro::heliocentricPosition(const UniversalCoord& universal,
00228 const Point3f& starPosition)
00229 {
00230
00231 Vec3d v = universal - Point3d(starPosition.x * 1e6,
00232 starPosition.y * 1e6,
00233 starPosition.z * 1e6);
00234
00235
00236 return Point3d(microLightYearsToKilometers(v.x),
00237 microLightYearsToKilometers(v.y),
00238 microLightYearsToKilometers(v.z));
00239 }
00240
00241
00242 UniversalCoord astro::universalPosition(const Point3d& heliocentric,
00243 const Point3f& starPosition)
00244 {
00245 return UniversalCoord(Point3d(starPosition.x * 1e6,
00246 starPosition.y * 1e6,
00247 starPosition.z * 1e6)) +
00248 Vec3d(kilometersToMicroLightYears(heliocentric.x),
00249 kilometersToMicroLightYears(heliocentric.y),
00250 kilometersToMicroLightYears(heliocentric.z));
00251 }
00252
00253
00254 UniversalCoord astro::universalPosition(const Point3d& heliocentric,
00255 const UniversalCoord& starPosition)
00256 {
00257 return starPosition +
00258 Vec3d(kilometersToMicroLightYears(heliocentric.x),
00259 kilometersToMicroLightYears(heliocentric.y),
00260 kilometersToMicroLightYears(heliocentric.z));
00261 }
00262
00263
00264
00265
00266 Point3f astro::equatorialToCelestialCart(float ra, float dec, float distance)
00267 {
00268 double theta = ra / 24.0 * PI * 2 + PI;
00269 double phi = (dec / 90.0 - 1.0) * PI / 2;
00270 double x = cos(theta) * sin(phi) * distance;
00271 double y = cos(phi) * distance;
00272 double z = -sin(theta) * sin(phi) * distance;
00273
00274 return (Point3f((float) x, (float) y, (float) z) * equatorialToCelestial);
00275 }
00276
00277
00278
00279
00280 Point3d astro::equatorialToCelestialCart(double ra, double dec, double distance)
00281 {
00282 double theta = ra / 24.0 * PI * 2 + PI;
00283 double phi = (dec / 90.0 - 1.0) * PI / 2;
00284 double x = cos(theta) * sin(phi) * distance;
00285 double y = cos(phi) * distance;
00286 double z = -sin(theta) * sin(phi) * distance;
00287
00288 return (Point3d(x, y, z) * equatorialToCelestiald);
00289 }
00290
00291
00292 void astro::anomaly(double meanAnomaly, double eccentricity,
00293 double& trueAnomaly, double& eccentricAnomaly)
00294 {
00295 double e, delta, err;
00296 double tol = 0.00000001745;
00297 int iterations = 20;
00298
00299 e = meanAnomaly - 2*PI * (int) (meanAnomaly / (2*PI));
00300 err = 1;
00301 while(abs(err) > tol && iterations > 0)
00302 {
00303 err = e - eccentricity*sin(e) - meanAnomaly;
00304 delta = err / (1 - eccentricity * cos(e));
00305 e -= delta;
00306 iterations--;
00307 }
00308
00309 trueAnomaly = 2*atan(sqrt((1+eccentricity)/(1-eccentricity))*tan(e/2));
00310 eccentricAnomaly = e;
00311 }
00312
00313
00314 double astro::meanEclipticObliquity(double jd)
00315 {
00316 double t, de;
00317
00318 jd -= 2451545.0;
00319 t = jd / 36525;
00320 de = (46.815 * t + 0.0006 * t * t - 0.00181 * t * t * t) / 3600;
00321
00322 return 23.439292 - de;
00323 }
00324
00325 astro::Date::Date()
00326 {
00327 year = 0;
00328 month = 0;
00329 day = 0;
00330 hour = 0;
00331 minute = 0;
00332 seconds = 0.0;
00333 }
00334
00335 astro::Date::Date(int Y, int M, int D)
00336 {
00337 year = Y;
00338 month = M;
00339 day = D;
00340 hour = 0;
00341 minute = 0;
00342 seconds = 0.0;
00343 }
00344
00345
00346 astro::Date::Date(double jd)
00347 {
00348 int a = (int) (jd + 0.5);
00349 double c;
00350 if (a < 2299161)
00351 {
00352 c = a + 1524;
00353 }
00354 else
00355 {
00356 double b = (int) ((a - 1867216.25) / 36524.25);
00357 c = a + b - (int) (b / 4) + 1525;
00358 }
00359
00360 int d = (int) ((c - 122.1) / 365.25);
00361 int e = (int) (365.25 * d);
00362 int f = (int) ((c - e) / 30.6001);
00363
00364 double dday = c - e - (int) (30.6001 * f) + ((jd + 0.5) - (int) (jd + 0.5));
00365
00366
00367
00368 month = f - 1 - 12 * (int) (f / 14);
00369 year = d - 4715 - (int) ((7.0 + month) / 10.0);
00370 day = (int) dday;
00371
00372 double dhour = (dday - day) * 24;
00373 hour = (int) dhour;
00374
00375 double dminute = (dhour - hour) * 60;
00376 minute = (int) dminute;
00377
00378 seconds = (dminute - minute) * 60;
00379 }
00380
00381
00382
00383 astro::Date::operator double() const
00384 {
00385 int y = year, m = month;
00386 if (month <= 2)
00387 {
00388 y = year - 1;
00389 m = month + 12;
00390 }
00391
00392
00393
00394 int B = -2;
00395 if (year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15))))
00396 {
00397 B = y / 400 - y / 100;
00398 }
00399
00400 return (floor(365.25 * y) +
00401 floor(30.6001 * (m + 1)) + B + 1720996.5 +
00402 day + hour / 24.0 + minute / 1440.0 + seconds / 86400.0);
00403 }
00404
00405
00406 bool astro::parseDate(const string& s, astro::Date& date)
00407 {
00408 int year = 0;
00409 unsigned int month = 1;
00410 unsigned int day = 1;
00411 unsigned int hour = 0;
00412 unsigned int minute = 0;
00413 unsigned int second = 0;
00414
00415 if (sscanf(s.c_str(), " %d %u %u %u:%u:%u ",
00416 &year, &month, &day, &hour, &minute, &second) == 6 ||
00417 sscanf(s.c_str(), " %d %u %u %u:%u ",
00418 &year, &month, &day, &hour, &minute) == 5 ||
00419 sscanf(s.c_str(), " %d %u %u ", &year, &month, &day) == 3)
00420 {
00421 if (month < 1 || month > 12)
00422 return false;
00423 if (hour > 23 || minute > 59 || second > 59)
00424 return false;
00425
00426
00427 int maxDay = 31 - ((0xa50 >> month) & 0x1);
00428 if (month == 2)
00429 {
00430
00431 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
00432 maxDay = 29;
00433 else
00434 maxDay = 28;
00435 }
00436 if (day > (unsigned int)maxDay || day < 1)
00437 return false;
00438
00439 date.year = year;
00440 date.month = month;
00441 date.day = day;
00442 date.hour = hour;
00443 date.minute = minute;
00444 date.seconds = second;
00445
00446 return true;
00447 }
00448
00449 return false;
00450 }
00451
00452
00453 ostream& operator<<(ostream& s, const astro::Date d)
00454 {
00455 s << d.year << ' ' << setw(2) << setfill('0') << d.month << ' ';
00456 s << setw(2) << setfill('0') << d.day << ' ';
00457 s << setw(2) << setfill('0') << d.hour << ':';
00458 s << setw(2) << setfill('0') << d.minute << ':';
00459 s << setw(2) << setfill('0') << (int) d.seconds;
00460 return s;
00461 }
00462