00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "CaelumPrecompiled.h"
00022 #include "Astronomy.h"
00023
00024 namespace Caelum
00025 {
00026 const LongReal Astronomy::PI = 3.1415926535897932384626433832795029L;
00027
00028 const LongReal Astronomy::J2000 = 2451545.0;
00029
00030 LongReal Astronomy::radToDeg (LongReal value)
00031 {
00032 return value * 180 / PI;
00033 }
00034
00035 LongReal Astronomy::degToRad (LongReal value)
00036 {
00037 return value * PI / 180;
00038 }
00039
00040 LongReal Astronomy::sinDeg (LongReal x) {
00041 return std::sin (degToRad (x));
00042 }
00043
00044 LongReal Astronomy::cosDeg (LongReal x) {
00045 return std::cos (degToRad (x));
00046 }
00047
00048 LongReal Astronomy::atan2Deg (LongReal y, LongReal x) {
00049 return radToDeg(std::atan2 (y, x));
00050 }
00051
00052 LongReal Astronomy::normalizeDegrees (LongReal value)
00053 {
00054 value = fmod (value, 360);
00055 if (value < LongReal (0)) {
00056 value += LongReal (360);
00057 }
00058 return value;
00059 }
00060
00061 void Astronomy::convertEclipticToEquatorialRad (
00062 LongReal lon, LongReal lat,
00063 LongReal &rasc, LongReal &decl)
00064 {
00065 double ecl = Astronomy::degToRad(23.439281);
00066
00067 double x = cos(lon) * cos(lat);
00068 double y = cos(ecl) * sin(lon) * cos(lat) - sin(ecl) * sin(lat);
00069 double z = sin(ecl) * sin(lon) * cos(lat) + cos(ecl) * sin(lat);
00070
00071 double r = sqrt(x * x + y * y);
00072 rasc = atan2(y, x);
00073 decl = atan2(z, r);
00074 }
00075
00076 void Astronomy::convertRectangularToSpherical (
00077 LongReal x, LongReal y, LongReal z,
00078 LongReal &rasc, LongReal &decl, LongReal &dist)
00079 {
00080 dist = sqrt (x * x + y * y + z * z);
00081 rasc = atan2Deg (y, x);
00082 decl = atan2Deg (z, sqrt (x * x + y * y));
00083 }
00084
00085 void Astronomy::convertSphericalToRectangular (
00086 LongReal rasc, LongReal decl, LongReal dist,
00087 LongReal &x, LongReal &y, LongReal &z)
00088 {
00089 x = dist * cosDeg (rasc) * cosDeg (decl);
00090 y = dist * sinDeg (rasc) * cosDeg (decl);
00091 z = dist * sinDeg (decl);
00092 }
00093
00094 void Astronomy::convertEquatorialToHorizontal (
00095 LongReal jday,
00096 LongReal longitude, LongReal latitude,
00097 LongReal rasc, LongReal decl,
00098 LongReal &azimuth, LongReal &altitude)
00099 {
00100 LongReal d = jday - 2451543.5;
00101 LongReal w = LongReal (282.9404 + 4.70935E-5 * d);
00102 LongReal M = LongReal (356.0470 + 0.9856002585 * d);
00103
00104 LongReal L = w + M;
00105
00106 LongReal UT = LongReal(fmod(d, 1) * 360);
00107 LongReal hourAngle = longitude + L + LongReal (180) + UT - rasc;
00108
00109 LongReal x = cosDeg (hourAngle) * cosDeg (decl);
00110 LongReal y = sinDeg (hourAngle) * cosDeg (decl);
00111 LongReal z = sinDeg (decl);
00112
00113 LongReal xhor = x * sinDeg (latitude) - z * cosDeg (latitude);
00114 LongReal yhor = y;
00115 LongReal zhor = x * cosDeg (latitude) + z * sinDeg (latitude);
00116
00117 azimuth = atan2Deg (yhor, xhor) + LongReal (180);
00118 altitude = atan2Deg (zhor, sqrt (xhor * xhor + yhor * yhor));
00119 }
00120
00121 void Astronomy::getHorizontalSunPosition (
00122 LongReal jday,
00123 LongReal longitude, LongReal latitude,
00124 LongReal &azimuth, LongReal &altitude)
00125 {
00126
00127
00128 LongReal d = jday - 2451543.5;
00129
00130
00131
00132 LongReal w = LongReal (282.9404 + 4.70935E-5 * d);
00133
00134 LongReal e = 0.016709 - 1.151E-9 * d;
00135
00136 LongReal M = LongReal(356.0470 + 0.9856002585 * d);
00137
00138
00139
00140
00141 LongReal E = M + radToDeg(e * sinDeg (M) * (1 + e * cosDeg (M)));
00142
00143
00144 LongReal xv = cosDeg (E) - e;
00145 LongReal yv = sinDeg (E) * sqrt (1 - e * e);
00146
00147 LongReal lon = atan2Deg (yv, xv) + w;
00148 LongReal lat = 0;
00149
00150 LongReal lambda = degToRad(lon);
00151 LongReal beta = degToRad(lat);
00152 LongReal rasc, decl;
00153 convertEclipticToEquatorialRad (lambda, beta, rasc, decl);
00154 rasc = radToDeg(rasc);
00155 decl = radToDeg(decl);
00156
00157
00158 Astronomy::convertEquatorialToHorizontal (
00159 jday, longitude, latitude, rasc, decl, azimuth, altitude);
00160 }
00161
00162 void Astronomy::getHorizontalSunPosition (
00163 LongReal jday,
00164 Ogre::Degree longitude, Ogre::Degree latitude,
00165 Ogre::Degree &azimuth, Ogre::Degree &altitude)
00166 {
00167 LongReal az, al;
00168 getHorizontalSunPosition(jday, longitude.valueDegrees (), latitude.valueDegrees (), az, al);
00169 azimuth = Ogre::Degree(az);
00170 altitude = Ogre::Degree(al);
00171 }
00172
00173 void Astronomy::getEclipticMoonPositionRad (
00174 LongReal jday,
00175 LongReal &lon, LongReal &lat)
00176 {
00177
00178 double T = (jday - 2451545.0L) / 36525.0L;
00179 double lprim = 3.8104L + 8399.7091L * T;
00180 double mprim = 2.3554L + 8328.6911L * T;
00181 double m = 6.2300L + 648.3019L * T;
00182 double d = 5.1985L + 7771.3772L * T;
00183 double f = 1.6280L + 8433.4663L * T;
00184 lon = lprim
00185 + 0.1098L * sin(mprim)
00186 + 0.0222L * sin(2.0L * d - mprim)
00187 + 0.0115L * sin(2.0L * d)
00188 + 0.0037L * sin(2.0L * mprim)
00189 - 0.0032L * sin(m)
00190 - 0.0020L * sin(2.0L * f)
00191 + 0.0010L * sin(2.0L * d - 2.0L * mprim)
00192 + 0.0010L * sin(2.0L * d - m - mprim)
00193 + 0.0009L * sin(2.0L * d + mprim)
00194 + 0.0008L * sin(2.0L * d - m)
00195 + 0.0007L * sin(mprim - m)
00196 - 0.0006L * sin(d)
00197 - 0.0005L * sin(m + mprim);
00198 lat =
00199 + 0.0895L * sin(f)
00200 + 0.0049L * sin(mprim + f)
00201 + 0.0048L * sin(mprim - f)
00202 + 0.0030L * sin(2.0L * d - f)
00203 + 0.0010L * sin(2.0L * d + f - mprim)
00204 + 0.0008 * sin(2.0L * d - f - mprim)
00205 + 0.0006L * sin(2.0L * d + f);
00206 }
00207
00208 void Astronomy::getHorizontalMoonPosition (
00209 LongReal jday,
00210 LongReal longitude, LongReal latitude,
00211 LongReal &azimuth, LongReal &altitude)
00212 {
00213
00214 LongReal lonecl, latecl;
00215 Astronomy::getEclipticMoonPositionRad (jday, lonecl, latecl);
00216
00217
00218 LongReal rasc, decl;
00219 Astronomy::convertEclipticToEquatorialRad (lonecl, latecl, rasc, decl);
00220
00221
00222 rasc = radToDeg(rasc);
00223 decl = radToDeg(decl);
00224
00225
00226 Astronomy::convertEquatorialToHorizontal (
00227 jday, longitude, latitude, rasc, decl, azimuth, altitude);
00228 }
00229
00230 void Astronomy::getHorizontalMoonPosition (
00231 LongReal jday,
00232 Ogre::Degree longitude, Ogre::Degree latitude,
00233 Ogre::Degree &azimuth, Ogre::Degree &altitude)
00234 {
00235 LongReal az, al;
00236 getHorizontalMoonPosition(jday, longitude.valueDegrees (), latitude.valueDegrees (), az, al);
00237 azimuth = Ogre::Degree(az);
00238 altitude = Ogre::Degree(al);
00239 }
00240
00241 int Astronomy::getJulianDayFromGregorianDate(
00242 int year, int month, int day)
00243 {
00244
00245
00246
00247 int a = (14 - month) / 12;
00248 int y = year + 4800 - a;
00249 int m = month + 12 * a - 3;
00250 return day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045;
00251 }
00252
00253 LongReal Astronomy::getJulianDayFromGregorianDateTime(
00254 int year, int month, int day,
00255 int hour, int minute, LongReal second)
00256 {
00257 ScopedHighPrecissionFloatSwitch precissionSwitch;
00258
00259 int jdn = getJulianDayFromGregorianDate (year, month, day);
00260
00261 LongReal jd = jdn + (hour - 12) / 24.0 + minute / 1440.0 + second / 86400.0;
00262
00263 return jd;
00264 }
00265
00266 LongReal Astronomy::getJulianDayFromGregorianDateTime(
00267 int year, int month, int day,
00268 LongReal secondsFromMidnight)
00269 {
00270 int jdn = getJulianDayFromGregorianDate(year, month, day);
00271 LongReal jd = jdn + secondsFromMidnight / 86400.0 - 0.5;
00272 return jd;
00273 }
00274
00275 void Astronomy::getGregorianDateFromJulianDay(
00276 int julianDay, int &year, int &month, int &day)
00277 {
00278
00279 int J = julianDay;
00280 int j = J + 32044;
00281 int g = j / 146097;
00282 int dg = j % 146097;
00283 int c = (dg / 36524 + 1) * 3 / 4;
00284 int dc = dg - c * 36524;
00285 int b = dc / 1461;
00286 int db = dc % 1461;
00287 int a = (db / 365 + 1) * 3 / 4;
00288 int da = db - a * 365;
00289 int y = g * 400 + c * 100 + b * 4 + a;
00290 int m = (da * 5 + 308) / 153 - 2;
00291 int d = da - (m + 4) * 153 / 5 + 122;
00292 year = y - 4800 + (m + 2) / 12;
00293 month = (m + 2) % 12 + 1;
00294 day = d + 1;
00295 }
00296
00297 void Astronomy::getGregorianDateTimeFromJulianDay(
00298 LongReal julianDay, int &year, int &month, int &day,
00299 int &hour, int &minute, LongReal &second)
00300 {
00301
00302
00303
00304 int ijd = static_cast<int>(floor(julianDay + 0.5));
00305 getGregorianDateFromJulianDay(ijd, year, month, day);
00306
00307 LongReal s = (julianDay + 0.5 - ijd) * 86400.0;
00308 hour = static_cast<int>(floor(s / 3600));
00309 s -= hour * 3600;
00310 minute = static_cast<int>(floor(s / 60));
00311 s -= minute * 60;
00312 second = s;
00313 }
00314
00315 void Astronomy::getGregorianDateFromJulianDay(
00316 LongReal julianDay, int &year, int &month, int &day)
00317 {
00318 int hour;
00319 int minute;
00320 LongReal second;
00321 getGregorianDateTimeFromJulianDay(julianDay, year, month, day, hour, minute, second);
00322 }
00323
00324 #if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && (OGRE_COMPILER == OGRE_COMPILER_MSVC)
00325 int Astronomy::enterHighPrecissionFloatingPointMode ()
00326 {
00327 int oldMode = ::_controlfp (0, 0);
00328 ::_controlfp (_PC_64, _MCW_PC);
00329 return oldMode;
00330 }
00331
00332 void Astronomy::restoreFloatingPointMode (int oldMode)
00333 {
00334 ::_controlfp (oldMode, _MCW_PC);
00335 }
00336 #else
00337 int Astronomy::enterHighPrecissionFloatingPointMode ()
00338 {
00339
00340 return 0xC0FFEE;
00341 }
00342
00343 void Astronomy::restoreFloatingPointMode (int oldMode)
00344 {
00345
00346 assert(oldMode == 0xC0FFEE);
00347 }
00348 #endif
00349 }