celestialBody.cxx

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 

Generated on Mon Dec 17 09:30:54 2007 for SimGear by  doxygen 1.5.1