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 int fpmode = Astronomy::enterHighPrecissionFloatingPointMode ();
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 Astronomy::restoreFloatingPointMode(fpmode);
00264 return jd;
00265 }
00266
00267 LongReal Astronomy::getJulianDayFromGregorianDateTime(
00268 int year, int month, int day,
00269 LongReal secondsFromMidnight)
00270 {
00271 int jdn = getJulianDayFromGregorianDate(year, month, day);
00272 LongReal jd = jdn + secondsFromMidnight / 86400.0 - 0.5;
00273 return jd;
00274 }
00275
00276 void Astronomy::getGregorianDateFromJulianDay(
00277 int julianDay, int &year, int &month, int &day)
00278 {
00279
00280 int J = julianDay;
00281 int j = J + 32044;
00282 int g = j / 146097;
00283 int dg = j % 146097;
00284 int c = (dg / 36524 + 1) * 3 / 4;
00285 int dc = dg - c * 36524;
00286 int b = dc / 1461;
00287 int db = dc % 1461;
00288 int a = (db / 365 + 1) * 3 / 4;
00289 int da = db - a * 365;
00290 int y = g * 400 + c * 100 + b * 4 + a;
00291 int m = (da * 5 + 308) / 153 - 2;
00292 int d = da - (m + 4) * 153 / 5 + 122;
00293 year = y - 4800 + (m + 2) / 12;
00294 month = (m + 2) % 12 + 1;
00295 day = d + 1;
00296 }
00297
00298 void Astronomy::getGregorianDateTimeFromJulianDay(
00299 LongReal julianDay, int &year, int &month, int &day,
00300 int &hour, int &minute, LongReal &second)
00301 {
00302
00303
00304
00305 int ijd = static_cast<int>(floor(julianDay + 0.5));
00306 getGregorianDateFromJulianDay(ijd, year, month, day);
00307
00308 LongReal s = (julianDay + 0.5 - ijd) * 86400.0;
00309 hour = static_cast<int>(floor(s / 3600));
00310 s -= hour * 3600;
00311 minute = static_cast<int>(floor(s / 60));
00312 s -= minute * 60;
00313 second = s;
00314 }
00315
00316 void Astronomy::getGregorianDateFromJulianDay(
00317 LongReal julianDay, int &year, int &month, int &day)
00318 {
00319 int hour;
00320 int minute;
00321 LongReal second;
00322 getGregorianDateTimeFromJulianDay(julianDay, year, month, day, hour, minute, second);
00323 }
00324
00325 #if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && (OGRE_COMPILER == OGRE_COMPILER_MSVC)
00326 int Astronomy::enterHighPrecissionFloatingPointMode ()
00327 {
00328 int oldMode = ::_controlfp (0, 0);
00329 ::_controlfp (_PC_64, _MCW_PC);
00330 return oldMode;
00331 }
00332
00333 void Astronomy::restoreFloatingPointMode (int oldMode)
00334 {
00335 ::_controlfp (oldMode, _MCW_PC);
00336 }
00337 #else
00338 int Astronomy::enterHighPrecissionFloatingPointMode ()
00339 {
00340
00341 return 0xC0FFEE;
00342 }
00343
00344 void Astronomy::restoreFloatingPointMode (int oldMode)
00345 {
00346
00347 assert(oldMode == 0xC0FFEE);
00348 }
00349 #endif
00350 }