00001 /************************************************************************** 00002 * celestialBody.cxx 00003 * Written by Durk Talsma. Originally started October 1997, for distribution 00004 * with the FlightGear project. Version 2 was written in August and 00005 * September 1998. This code is based upon algorithms and data kindly 00006 * provided by Mr. Paul Schlyter. (pausch@saaf.se). 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * $Id: celestialBody_8cxx-source.html,v 1.15 2007-12-17 15:36:46 curt Exp $ 00023 **************************************************************************/ 00024 00025 #include <simgear/debug/logstream.hxx> 00026 00027 #ifdef SG_MATH_EXCEPTION_CLASH 00028 # define exception c_exception 00029 #endif 00030 #include <math.h> 00031 00032 #include "celestialBody.hxx" 00033 #include "star.hxx" 00034 00035 00036 /************************************************************************** 00037 * void CelestialBody::updatePosition(double mjd, Star *ourSun) 00038 * 00039 * Basically, this member function provides a general interface for 00040 * calculating the right ascension and declinaion. This function is 00041 * used for calculating the planetary positions. For the planets, an 00042 * overloaded member function is provided to additionally calculate the 00043 * planet's magnitude. 00044 * The sun and moon have their own overloaded updatePosition member, as their 00045 * position is calculated an a slightly different manner. 00046 * 00047 * arguments: 00048 * double mjd: provides the modified julian date. 00049 * Star *ourSun: the sun's position is needed to convert heliocentric 00050 * coordinates into geocentric coordinates. 00051 * 00052 * return value: none 00053 * 00054 *************************************************************************/ 00055 void CelestialBody::updatePosition(double mjd, Star *ourSun) 00056 { 00057 double eccAnom, v, ecl, actTime, 00058 xv, yv, xh, yh, zh, xg, yg, zg, xe, ye, ze; 00059 00060 updateOrbElements(mjd); 00061 actTime = sgCalcActTime(mjd); 00062 00063 // calcualate the angle bewteen ecliptic and equatorial coordinate system 00064 ecl = SGD_DEGREES_TO_RADIANS * (23.4393 - 3.563E-7 *actTime); 00065 00066 eccAnom = sgCalcEccAnom(M, e); //calculate the eccentric anomaly 00067 xv = a * (cos(eccAnom) - e); 00068 yv = a * (sqrt (1.0 - e*e) * sin(eccAnom)); 00069 v = atan2(yv, xv); // the planet's true anomaly 00070 r = sqrt (xv*xv + yv*yv); // the planet's distance 00071 00072 // calculate the planet's position in 3D space 00073 xh = r * (cos(N) * cos(v+w) - sin(N) * sin(v+w) * cos(i)); 00074 yh = r * (sin(N) * cos(v+w) + cos(N) * sin(v+w) * cos(i)); 00075 zh = r * (sin(v+w) * sin(i)); 00076 00077 // calculate the ecliptic longitude and latitude 00078 xg = xh + ourSun->getxs(); 00079 yg = yh + ourSun->getys(); 00080 zg = zh; 00081 00082 lonEcl = atan2(yh, xh); 00083 latEcl = atan2(zh, sqrt(xh*xh+yh*yh)); 00084 00085 xe = xg; 00086 ye = yg * cos(ecl) - zg * sin(ecl); 00087 ze = yg * sin(ecl) + zg * cos(ecl); 00088 rightAscension = atan2(ye, xe); 00089 declination = atan2(ze, sqrt(xe*xe + ye*ye)); 00090 /* SG_LOG(SG_GENERAL, SG_INFO, "Planet found at : " 00091 << rightAscension << " (ra), " << declination << " (dec)" ); */ 00092 00093 //calculate some variables specific to calculating the magnitude 00094 //of the planet 00095 R = sqrt (xg*xg + yg*yg + zg*zg); 00096 s = ourSun->getDistance(); 00097 00098 // It is possible from these calculations for the argument to acos 00099 // to exceed the valid range for acos(). So we do a little extra 00100 // checking. 00101 00102 double tmp = (r*r + R*R - s*s) / (2*r*R); 00103 if ( tmp > 1.0) { 00104 tmp = 1.0; 00105 } else if ( tmp < -1.0) { 00106 tmp = -1.0; 00107 } 00108 00109 FV = SGD_RADIANS_TO_DEGREES * acos( tmp ); 00110 } 00111 00112 /**************************************************************************** 00113 * double CelestialBody::sgCalcEccAnom(double M, double e) 00114 * this private member calculates the eccentric anomaly of a celestial body, 00115 * given its mean anomaly and eccentricity. 00116 * 00117 * -Mean anomaly: the approximate angle between the perihelion and the current 00118 * position. this angle increases uniformly with time. 00119 * 00120 * True anomaly: the actual angle between perihelion and current position. 00121 * 00122 * Eccentric anomaly: this is an auxilary angle, used in calculating the true 00123 * anomaly from the mean anomaly. 00124 * 00125 * -eccentricity. Indicates the amount in which the orbit deviates from a 00126 * circle (0 = circle, 0-1, is ellipse, 1 = parabola, > 1 = hyperbola). 00127 * 00128 * This function is also known as solveKeplersEquation() 00129 * 00130 * arguments: 00131 * M: the mean anomaly 00132 * e: the eccentricity 00133 * 00134 * return value: 00135 * the eccentric anomaly 00136 * 00137 ****************************************************************************/ 00138 double CelestialBody::sgCalcEccAnom(double M, double e) 00139 { 00140 double 00141 eccAnom, E0, E1, diff; 00142 00143 eccAnom = M + e * sin(M) * (1.0 + e * cos (M)); 00144 // iterate to achieve a greater precision for larger eccentricities 00145 if (e > 0.05) 00146 { 00147 E0 = eccAnom; 00148 do 00149 { 00150 E1 = E0 - (E0 - e * sin(E0) - M) / (1 - e *cos(E0)); 00151 diff = fabs(E0 - E1); 00152 E0 = E1; 00153 } 00154 while (diff > (SGD_DEGREES_TO_RADIANS * 0.001)); 00155 return E0; 00156 } 00157 return eccAnom; 00158 } 00159 00160 /***************************************************************************** 00161 * inline CelestialBody::CelestialBody 00162 * public constructor for a generic celestialBody object. 00163 * initializes the 6 primary orbital elements. The elements are: 00164 * N: longitude of the ascending node 00165 * i: inclination to the ecliptic 00166 * w: argument of perihelion 00167 * a: semi-major axis, or mean distance from the sun 00168 * e: eccenticity 00169 * M: mean anomaly 00170 * Each orbital element consists of a constant part and a variable part that 00171 * gradually changes over time. 00172 * 00173 * Argumetns: 00174 * the 13 arguments to the constructor constitute the first, constant 00175 * ([NiwaeM]f) and the second variable ([NiwaeM]s) part of the orbital 00176 * elements. The 13th argument is the current time. Note that the inclination 00177 * is written with a capital (If, Is), because 'if' is a reserved word in the 00178 * C/C++ programming language. 00179 ***************************************************************************/ 00180 CelestialBody::CelestialBody(double Nf, double Ns, 00181 double If, double Is, 00182 double wf, double ws, 00183 double af, double as, 00184 double ef, double es, 00185 double Mf, double Ms, double mjd) 00186 { 00187 NFirst = Nf; NSec = Ns; 00188 iFirst = If; iSec = Is; 00189 wFirst = wf; wSec = ws; 00190 aFirst = af; aSec = as; 00191 eFirst = ef; eSec = es; 00192 MFirst = Mf; MSec = Ms; 00193 updateOrbElements(mjd); 00194 } 00195 00196 CelestialBody::CelestialBody(double Nf, double Ns, 00197 double If, double Is, 00198 double wf, double ws, 00199 double af, double as, 00200 double ef, double es, 00201 double Mf, double Ms) 00202 { 00203 NFirst = Nf; NSec = Ns; 00204 iFirst = If; iSec = Is; 00205 wFirst = wf; wSec = ws; 00206 aFirst = af; aSec = as; 00207 eFirst = ef; eSec = es; 00208 MFirst = Mf; MSec = Ms; 00209 } 00210 00211 /**************************************************************************** 00212 * inline void CelestialBody::updateOrbElements(double mjd) 00213 * given the current time, this private member calculates the actual 00214 * orbital elements 00215 * 00216 * Arguments: double mjd: the current modified julian date: 00217 * 00218 * return value: none 00219 ***************************************************************************/ 00220 void CelestialBody::updateOrbElements(double mjd) 00221 { 00222 double actTime = sgCalcActTime(mjd); 00223 M = SGD_DEGREES_TO_RADIANS * (MFirst + (MSec * actTime)); 00224 w = SGD_DEGREES_TO_RADIANS * (wFirst + (wSec * actTime)); 00225 N = SGD_DEGREES_TO_RADIANS * (NFirst + (NSec * actTime)); 00226 i = SGD_DEGREES_TO_RADIANS * (iFirst + (iSec * actTime)); 00227 e = eFirst + (eSec * actTime); 00228 a = aFirst + (aSec * actTime); 00229 } 00230 00231 /***************************************************************************** 00232 * inline double CelestialBody::sgCalcActTime(double mjd) 00233 * this private member function returns the offset in days from the epoch for 00234 * wich the orbital elements are calculated (Jan, 1st, 2000). 00235 * 00236 * Argument: the current time 00237 * 00238 * return value: the (fractional) number of days until Jan 1, 2000. 00239 ****************************************************************************/ 00240 double CelestialBody::sgCalcActTime(double mjd) 00241 { 00242 return (mjd - 36523.5); 00243 } 00244 00245 /***************************************************************************** 00246 * inline void CelestialBody::getPos(double* ra, double* dec) 00247 * gives public access to Right Ascension and declination 00248 * 00249 ****************************************************************************/ 00250 void CelestialBody::getPos(double* ra, double* dec) 00251 { 00252 *ra = rightAscension; 00253 *dec = declination; 00254 } 00255 00256 /***************************************************************************** 00257 * inline void CelestialBody::getPos(double* ra, double* dec, double* magnitude 00258 * gives public acces to the current Right ascension, declination, and 00259 * magnitude 00260 ****************************************************************************/ 00261 void CelestialBody::getPos(double* ra, double* dec, double* magn) 00262 { 00263 *ra = rightAscension; 00264 *dec = declination; 00265 *magn = magnitude; 00266 } 00267 00268
1.5.1