SO3Engine
SO3Astronomy.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25/*
26Taken from Caelum (http://www.ogre3d.org/wiki/index.php/Caelum)
27Planetary position computation from http://stjarnhimlen.se/comp/ppcomp.html#5
28Sunrise/sunset & moonrise/moonset computation from http://stjarnhimlen.se/comp/riset.html
29There's also usefull informations in "A physically-based night sky model" concerning the moon position calculation.
30*/
31
33
34namespace SO3
35{
36
37const double SAstronomy::PI = 3.1415926535897932384626433832795029L;
38const double SAstronomy::J2000 = 2451545.0;
39
40double SAstronomy::RadToDeg(const double& value)
41{
42 return value * 180 / PI;
43}
44
45double SAstronomy::DegToRad(const double& value)
46{
47 return value * PI / 180;
48}
49
50double SAstronomy::SinDeg(const double& x)
51{
52 return std::sin(DegToRad(x));
53}
54
55double SAstronomy::CosDeg(const double& x)
56{
57 return std::cos(DegToRad(x));
58}
59
60double SAstronomy::Atan2Deg(const double& y, const double& x)
61{
62 return RadToDeg(std::atan2(y, x));
63}
64
65double SAstronomy::NormalizeDegrees(const double& val)
66{
67 double value = fmod(val, 360);
68 if (value < double(0))
69 value += double(360);
70
71 return value;
72}
73
74void SAstronomy::ConvertEclipticToEquatorialRad(const double& lon, const double& lat, double& rasc, double& decl)
75{
76 double ecl = SAstronomy::DegToRad(23.439281);
77
78 double x = cos(lon) * cos(lat);
79 double y = cos(ecl) * sin(lon) * cos(lat) - sin(ecl) * sin(lat);
80 double z = sin(ecl) * sin(lon) * cos(lat) + cos(ecl) * sin(lat);
81
82 double r = sqrt(x * x + y * y);
83 rasc = atan2(y, x);
84 decl = atan2(z, r);
85}
86
87void SAstronomy::ConvertRectangularToSpherical(const double& x, const double& y, const double& z, double& rasc, double& decl, double& dist)
88{
89 dist = sqrt (x * x + y * y + z * z);
90 rasc = Atan2Deg(y, x);
91 decl = Atan2Deg(z, sqrt (x * x + y * y));
92}
93
94void SAstronomy::ConvertSphericalToRectangular(const double& rasc, const double& decl, const double& dist, double& x, double& y, double& z)
95{
96 x = dist * CosDeg(rasc) * CosDeg(decl);
97 y = dist * SinDeg(rasc) * CosDeg(decl);
98 z = dist * SinDeg(decl);
99}
100
101void SAstronomy::ConvertEquatorialToHorizontal(const double& jday, const double& longitude, const double& latitude, const double& rasc, const double& decl, double& azimuth, double& altitude)
102{
103 double d = jday - 2451543.5;
104 double w = double(282.9404 + 4.70935E-5 * d);
105 double M = double(356.0470 + 0.9856002585 * d);
106
107 // Sun's mean longitude
108 double L = w + M;
109
110 // Universal time of day in degrees.
111 double UT = double(fmod(d, 1) * 360);
112 double hourAngle = longitude + L + double(180) + UT - rasc;
113
114 double x = CosDeg(hourAngle) * CosDeg(decl);
115 double y = SinDeg(hourAngle) * CosDeg(decl);
116 double z = SinDeg(decl);
117
118 double xhor = x * SinDeg(latitude) - z * CosDeg(latitude);
119 double yhor = y;
120 double zhor = x * CosDeg(latitude) + z * SinDeg(latitude);
121
122 azimuth = Atan2Deg(yhor, xhor) + double(180);
123 altitude = Atan2Deg (zhor, sqrt (xhor * xhor + yhor * yhor));
124}
125
126void SAstronomy::GetEclipticSunMeanLongitude(const double& jday, double& sunlon)
127{
128 // 2451544.5 == Astronomy::getJulianDayFromGregorianDateTime(2000, 1, 1, 0, 0, 0));
129 // 2451543.5 == Astronomy::getJulianDayFromGregorianDateTime(1999, 12, 31, 0, 0, 0));
130 double d = jday - 2451543.5;
131
132 // Sun's Orbital elements:
133 // argument of perihelion
134 double w = double(282.9404 + 4.70935E-5 * d);
135 // eccentricity (0=circle, 0-1=ellipse, 1=parabola)
136 double e = 0.016709 - 1.151E-9 * d;
137 // mean anomaly (0 at perihelion; increases uniformly with time)
138 double M = double(356.0470 + 0.9856002585 * d);
139 // Obliquity of the ecliptic.
140 //double oblecl = double(23.4393 - 3.563E-7 * d);
141
142 // Eccentric anomaly
143 double E = M + RadToDeg(e * SinDeg(M) * (1 + e * CosDeg(M)));
144
145 // Sun's Distance(R) and true longitude(L)
146 double xv = CosDeg(E) - e;
147 double yv = SinDeg(E) * sqrt(1 - e * e);
148 sunlon = Atan2Deg(yv, xv) + w;
149}
150
151void SAstronomy::GetEclipticSunPosition(const double& jday, double& lambda, double& beta)
152{
153 double sunlon, sunlat = 0;
154 GetEclipticSunMeanLongitude(jday, sunlon);
155
156 lambda = DegToRad(sunlon);
157 beta = DegToRad(sunlat);
158}
159
160void SAstronomy::GetEquatorialSunPosition(const double& jday, double& sunRightAscension, double& sunDeclinaison)
161{
162 double lambda, beta;
163 GetEclipticSunPosition(jday, lambda, beta);
164 ConvertEclipticToEquatorialRad(lambda, beta, sunRightAscension, sunDeclinaison);
165 sunRightAscension = RadToDeg(sunRightAscension);
166 sunDeclinaison = RadToDeg(sunDeclinaison);
167}
168
169void SAstronomy::GetHorizontalSunPosition(const double& jday, const double& longitude, const double& latitude, double& azimuth, double& altitude)
170{
171 // Horizontal spherical.
172 double sunRightAscension, sunDeclinaison;
173 GetEquatorialSunPosition(jday, sunRightAscension, sunDeclinaison);
174 ConvertEquatorialToHorizontal(jday, longitude, latitude, sunRightAscension, sunDeclinaison, azimuth, altitude);
175}
176
177void SAstronomy::GetHorizontalSunPosition(const double& jday, const Ogre::Degree& longitude, const Ogre::Degree& latitude, Ogre::Degree& azimuth, Ogre::Degree& altitude)
178{
179 double az, al;
180 GetHorizontalSunPosition(jday, longitude.valueDegrees(), latitude.valueDegrees(), az, al);
181 azimuth = Ogre::Degree(static_cast<float>(az));
182 altitude = Ogre::Degree(static_cast<float>(al));
183}
184
185void SAstronomy::GetEclipticMoonPositionRad(const double& jday, double& lon, double& lat)
186{
187 // Julian centuries since January 1, 2000
188 double T = (jday - 2451545.0L) / 36525.0L;
189 double lprim = 3.8104L + 8399.7091L * T;
190 double mprim = 2.3554L + 8328.6911L * T;
191 double m = 6.2300L + 648.3019L * T;
192 double d = 5.1985L + 7771.3772L * T;
193 double f = 1.6280L + 8433.4663L * T;
194 lon = lprim
195 + 0.1098L * sin(mprim)
196 + 0.0222L * sin(2.0L * d - mprim)
197 + 0.0115L * sin(2.0L * d)
198 + 0.0037L * sin(2.0L * mprim)
199 - 0.0032L * sin(m)
200 - 0.0020L * sin(2.0L * f)
201 + 0.0010L * sin(2.0L * d - 2.0L * mprim)
202 + 0.0010L * sin(2.0L * d - m - mprim)
203 + 0.0009L * sin(2.0L * d + mprim)
204 + 0.0008L * sin(2.0L * d - m)
205 + 0.0007L * sin(mprim - m)
206 - 0.0006L * sin(d)
207 - 0.0005L * sin(m + mprim);
208
209 lat = + 0.0895L * sin(f)
210 + 0.0049L * sin(mprim + f)
211 + 0.0048L * sin(mprim - f)
212 + 0.0030L * sin(2.0L * d - f)
213 + 0.0010L * sin(2.0L * d + f - mprim)
214 + 0.0008 * sin(2.0L * d - f - mprim)
215 + 0.0006L * sin(2.0L * d + f);
216}
217
218void SAstronomy::GetHorizontalMoonPosition(const double& jday, const double& longitude, const double& latitude, double& azimuth, double& altitude)
219{
220 // Ecliptic spherical
221 double lonecl, latecl;
222 SAstronomy::GetEclipticMoonPositionRad(jday, lonecl, latecl);
223
224 // Equatorial spherical
225 double rasc, decl;
226 SAstronomy::ConvertEclipticToEquatorialRad(lonecl, latecl, rasc, decl);
227
228 // Radians to degrees (all angles are in radians up to this point)
229 rasc = RadToDeg(rasc);
230 decl = RadToDeg(decl);
231
232 // Equatorial to horizontal
233 SAstronomy::ConvertEquatorialToHorizontal(jday, longitude, latitude, rasc, decl, azimuth, altitude);
234}
235
236void SAstronomy::GetHorizontalMoonPosition(const double& jday, const Ogre::Degree& longitude, const Ogre::Degree& latitude, Ogre::Degree& azimuth, Ogre::Degree& altitude)
237{
238 double az, al;
239 GetHorizontalMoonPosition(jday, longitude.valueDegrees(), latitude.valueDegrees(), az, al);
240 azimuth = Ogre::Degree(static_cast<float>(az));
241 altitude = Ogre::Degree(static_cast<float>(al));
242}
243
244void SAstronomy::GetMoonPhase(const double& jday, float& moonPhase)
245{
246 // Calculates julian days since January 08, 2008 11:38 (new moon) and divides by the time between lunations (synodic month)
247 ScopedHighPrecissionFloatSwitch precissionSwitch;
248 double T = (jday - 2454473.984722L) / 29.531026L;
249
250 float phaseFloat = static_cast<float>(fabs(fmod(T, 1)));
251 moonPhase = ((phaseFloat - 0.5f) * 2.0f);
252}
253
254int SAstronomy::GetJulianDayFromGregorianDate(const int& year, const int& month, const int& day)
255{
256 // Formulas from http://en.wikipedia.org/wiki/Julian_day
257 // These are all integer divisions, but I'm not sure it works
258 // correctly for negative values.
259 int a = (14 - month) / 12;
260 int y = year + 4800 - a;
261 int m = month + 12 * a - 3;
262 return day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045;
263}
264
265double SAstronomy::GetJulianDayFromGregorianDateTime(const int& year, const int& month, const int& day, const int& hour, const int& minute, const double& second)
266{
267 ScopedHighPrecissionFloatSwitch precissionSwitch;
268 int jdn = GetJulianDayFromGregorianDate(year, month, day);
269
270 // These are NOT integer divisions.
271 double jd = jdn + (hour - 12) / 24.0 + minute / 1440.0 + second / 86400.0;
272 return jd;
273}
274
275double SAstronomy::GetJulianDayFromGregorianDateTime(const int& year, const int& month, const int& day, const double& secondsFromMidnight)
276{
277 int jdn = GetJulianDayFromGregorianDate(year, month, day);
278 double jd = jdn + secondsFromMidnight / 86400.0 - 0.5;
279 return jd;
280}
281
282void SAstronomy::GetGregorianDateFromJulianDay(const int& julianDay, int& year, int& month, int& day)
283{
284 // From http://en.wikipedia.org/wiki/Julian_day
285 int J = julianDay;
286 int j = J + 32044;
287 int g = j / 146097;
288 int dg = j % 146097;
289 int c = (dg / 36524 + 1) * 3 / 4;
290 int dc = dg - c * 36524;
291 int b = dc / 1461;
292 int db = dc % 1461;
293 int a = (db / 365 + 1) * 3 / 4;
294 int da = db - a * 365;
295 int y = g * 400 + c * 100 + b * 4 + a;
296 int m = (da * 5 + 308) / 153 - 2;
297 int d = da - (m + 4) * 153 / 5 + 122;
298 year = y - 4800 + (m + 2) / 12;
299 month = (m + 2) % 12 + 1;
300 day = d + 1;
301}
302
303void SAstronomy::GetGregorianDateTimeFromJulianDay(const double& julianDay, int& year, int& month, int& day, int& hour, int& minute, double& second)
304{
305 // Integer julian days are at noon.
306 // static_cast<int)(floor( is more precise than Ogre::Math::IFloor.
307 // Yes, it does matter.
308 int ijd = static_cast<int>(floor(julianDay + 0.5));
309 GetGregorianDateFromJulianDay(ijd, year, month, day);
310
311 double s = (julianDay + 0.5 - ijd) * 86400.0;
312 hour = static_cast<int>(floor(s / 3600));
313 s -= hour * 3600;
314 minute = static_cast<int>(floor(s / 60));
315 s -= minute * 60;
316 second = s;
317}
318
319void SAstronomy::GetGregorianDateFromJulianDay(const double& julianDay, int& year, int& month, int& day)
320{
321 int hour;
322 int minute;
323 double second;
324 GetGregorianDateTimeFromJulianDay(julianDay, year, month, day, hour, minute, second);
325}
326
327#if (OGRE_PLATFORM == OGRE_PLATFORM_WIN32) && (OGRE_COMPILER == OGRE_COMPILER_MSVC) && !defined(_WIN64)
329{
330 int oldMode = ::_controlfp (0, 0);
331 ::_controlfp (_PC_64, _MCW_PC);
332 return oldMode;
333}
334
336{
337 ::_controlfp (oldMode, _MCW_PC);
338}
339#else
341{
342 // Meaningless
343 return 0xC0FFEE;
344}
345
346void SAstronomy::RestoreFloatingPointMode(const int& oldMode)
347{
348 // Useless check.
349 assert(oldMode == 0xC0FFEE);
350}
351#endif
352
353}
SCOL_EXPORT int cbmachine w
Definition SO3SCOL.cpp:5150
static void GetEquatorialSunPosition(const double &jday, double &sunRightAscension, double &sunDeclinaison)
static double DegToRad(const double &x)
static int GetJulianDayFromGregorianDate(const int &year, const int &month, const int &day)
static void GetEclipticSunMeanLongitude(const double &jday, double &sunlon)
static void ConvertEclipticToEquatorialRad(const double &lon, const double &lat, double &rasc, double &decl)
static void GetGregorianDateFromJulianDay(const int &julianDay, int &year, int &month, int &day)
static void GetGregorianDateTimeFromJulianDay(const double &julianDay, int &year, int &month, int &day, int &hour, int &minute, double &second)
static int EnterHighPrecissionFloatingPointMode()
static void ConvertEquatorialToHorizontal(const double &jday, const double &longitude, const double &latitude, const double &rasc, const double &decl, double &azimuth, double &altitude)
static void GetEclipticSunPosition(const double &jday, double &lambda, double &beta)
static const double J2000
January 1, 2000, noon.
static double GetJulianDayFromGregorianDateTime(const int &year, const int &month, const int &day, const int &hour, const int &minute, const double &second)
static double Atan2Deg(const double &y, const double &x)
static void GetHorizontalMoonPosition(const double &jday, const double &longitude, const double &latitude, double &azimuth, double &altitude)
static void ConvertSphericalToRectangular(const double &rasc, const double &decl, const double &dist, double &x, double &y, double &z)
static double RadToDeg(const double &x)
static void GetMoonPhase(const double &jday, float &moonPhase)
static void GetHorizontalSunPosition(const double &jday, const double &longitude, const double &latitude, double &azimuth, double &altitude)
static void GetEclipticMoonPositionRad(const double &jday, double &lon, double &lat)
static double CosDeg(const double &x)
static double NormalizeDegrees(const double &x)
static double SinDeg(const double &x)
static void ConvertRectangularToSpherical(const double &x, const double &y, const double &z, double &rasc, double &decl, double &dist)
static void RestoreFloatingPointMode(const int &oldMode)