Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

astro.cpp

Go to the documentation of this file.
00001 // astro.cpp
00002 //
00003 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
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; // km/s
00020 
00021 // epoch J2000: 12 UT on 1 Jan 2000
00022 const double astro::J2000 = 2451545.0;
00023 
00024 const double astro::G = 6.672e-11; // N m^2 / kg^2
00025 
00026 const double astro::SolarMass = 1.989e30;
00027 const double astro::EarthMass = 5.976e24;
00028 const double astro::LunarMass = 7.354e22;
00029 
00030 // epoch B1950: 22:09 UT on 21 Dec 1949
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 // Return the apparent magnitude of a star with lum times solar
00043 // luminosity viewed at lyrs light years
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 // Compute the fraction of a sphere which is illuminated and visible
00174 // to a viewer.  The source of illumination is assumed to be at (0, 0, 0)
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 // Convert the position in univeral coordinates to a star-centric
00223 // coordinates in units of kilometers.  Note that there are three different
00224 // precisions used here:  star coordinates are stored as floats in units of
00225 // light years, position within a solar system are doubles in units of
00226 // kilometers, and p is highest-precision in units of light years.
00227 Point3d astro::heliocentricPosition(const UniversalCoord& universal,
00228                                     const Point3f& starPosition)
00229 {
00230     // Get the offset vector
00231     Vec3d v = universal - Point3d(starPosition.x * 1e6,
00232                                   starPosition.y * 1e6,
00233                                   starPosition.z * 1e6);
00234 
00235     // . . . and convert it to kilometers
00236     return Point3d(microLightYearsToKilometers(v.x),
00237                    microLightYearsToKilometers(v.y),
00238                    microLightYearsToKilometers(v.z));
00239 }
00240 
00241 // universalPosition is the inverse operation of heliocentricPosition
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 // universalPosition is the inverse operation of heliocentricPosition
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 // Convert equatorial coordinates to Cartesian celestial (or ecliptical)
00265 // coordinates.
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 // Convert equatorial coordinates to Cartesian celestial (or ecliptical)
00279 // coordinates.
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;        // limit while() to maximum of 20 iterations.
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     /* This following used to be 14.0, but gcc was computing it incorrectly, so
00367        it was changed to 14 */
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 // Convert a calendar date to a Julian date
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     // Correct for the lost days in Oct 1582 when the Gregorian calendar
00393     // replaced the Julian calendar.
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         // Cheesy days/month calculation . . .
00427         int maxDay = 31 - ((0xa50 >> month) & 0x1);
00428         if (month == 2)
00429         {
00430             // Check for a leap year
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 

Generated on Sat Jan 14 22:30:26 2006 for Celestia by  doxygen 1.4.1