Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

eclipsefinder.cpp

Go to the documentation of this file.
00001 // eclipsefinder.cpp by Christophe Teyssier <chris@teyssier.org>
00002 // adapted form wineclipses.cpp by Kendrix <kendrix@wanadoo.fr>
00003 // 
00004 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
00005 //
00006 // Compute Solar Eclipses for our Solar System planets
00007 //
00008 // This program is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU General Public License
00010 // as published by the Free Software Foundation; either version 2
00011 // of the License, or (at your option) any later version.
00012 
00013 #include <string>
00014 #include <sstream>
00015 #include <algorithm>
00016 #include <set>
00017 #include <cassert>
00018 #include "eclipsefinder.h"
00019 #include "celmath/mathlib.h"
00020 #include "celmath/ray.h"
00021 #include "celmath/distance.h"
00022 
00023 using namespace std;
00024 
00025 Eclipse::Eclipse(int Y, int M, int D) :
00026     body(NULL)
00027 {
00028     date = new astro::Date(Y, M, D);
00029 }
00030 
00031 Eclipse::Eclipse(double JD) :
00032     body(NULL)
00033 {
00034     date = new astro::Date(JD);
00035 }
00036 
00037 
00038 bool EclipseFinder::testEclipse(const Body& receiver, const Body& caster,
00039                  double now) const
00040 {
00041     // Ignore situations where the shadow casting body is much smaller than
00042     // the receiver, as these shadows aren't likely to be relevant.  Also,
00043     // ignore eclipses where the caster is not an ellipsoid, since we can't
00044     // generate correct shadows in this case.
00045     if (caster.getRadius() * 100 >= receiver.getRadius() &&
00046         caster.getModel() == InvalidResource)
00047     {
00048         // All of the eclipse related code assumes that both the caster
00049         // and receiver are spherical.  Irregular receivers will work more
00050         // or less correctly, but casters that are sufficiently non-spherical
00051         // will produce obviously incorrect shadows.  Another assumption we
00052         // make is that the distance between the caster and receiver is much
00053         // less than the distance between the sun and the receiver.  This
00054         // approximation works everywhere in the solar system, and likely
00055         // works for any orbitally stable pair of objects orbiting a star.
00056         Point3d posReceiver = receiver.getHeliocentricPosition(now);
00057         Point3d posCaster = caster.getHeliocentricPosition(now);
00058 
00059         const Star* sun = receiver.getSystem()->getStar();
00060         assert(sun != NULL);
00061         double distToSun = posReceiver.distanceFromOrigin();
00062         float appSunRadius = (float) (sun->getRadius() / distToSun);
00063 
00064         Vec3d dir = posCaster - posReceiver;
00065         double distToCaster = dir.length() - receiver.getRadius();
00066         float appOccluderRadius = (float) (caster.getRadius() / distToCaster);
00067 
00068         // The shadow radius is the radius of the occluder plus some additional
00069         // amount that depends upon the apparent radius of the sun.  For
00070         // a sun that's distant/small and effectively a point, the shadow
00071         // radius will be the same as the radius of the occluder.
00072         float shadowRadius = (1 + appSunRadius / appOccluderRadius) *
00073             caster.getRadius();
00074 
00075         // Test whether a shadow is cast on the receiver.  We want to know
00076         // if the receiver lies within the shadow volume of the caster.  Since
00077         // we're assuming that everything is a sphere and the sun is far
00078         // away relative to the caster, the shadow volume is a
00079         // cylinder capped at one end.  Testing for the intersection of a
00080         // singly capped cylinder is as simple as checking the distance
00081         // from the center of the receiver to the axis of the shadow cylinder.
00082         // If the distance is less than the sum of the caster's and receiver's
00083         // radii, then we have an eclipse.
00084         float R = receiver.getRadius() + shadowRadius;
00085         double dist = distance(posReceiver,
00086                                Ray3d(posCaster, posCaster - Point3d(0, 0, 0)));
00087         if (dist < R)
00088         {
00089             return true;
00090         }
00091     }
00092 
00093     return false;
00094 }
00095 
00096 
00097 double EclipseFinder::findEclipseSpan(const Body& receiver, const Body& caster,
00098                        double now, double dt) const
00099 {
00100     double t = now;
00101     while (testEclipse(receiver, caster, t))
00102         t += dt;
00103 
00104     return t;
00105 }
00106 
00107 
00108 int EclipseFinder::CalculateEclipses()
00109 {
00110     Simulation* sim = appCore->getSimulation();
00111     
00112     Eclipse* eclipse;
00113     double* JDback = NULL;
00114     
00115     int nIDplanetetofindon = 0;
00116     int nSattelites = 0;
00117 
00118     const SolarSystem* sys = sim->getNearestSolarSystem();
00119     
00120     toProcess = false;
00121     
00122     if ((!sys))
00123     {
00124         eclipse = new Eclipse(0.);
00125         eclipse->planete = "None";
00126         Eclipses_.insert(Eclipses_.end(), *eclipse);
00127         delete eclipse;
00128         return 1;
00129     }
00130     else if (sys->getStar()->getCatalogNumber() != 0)
00131     {
00132         eclipse = new Eclipse(0.);
00133         eclipse->planete = "None";
00134         Eclipses_.insert(Eclipses_.end(), *eclipse);
00135         delete eclipse;
00136         return 1;
00137     }
00138 
00139     PlanetarySystem* system = sys->getPlanets();
00140     int nbPlanets = system->getSystemSize();
00141 
00142     for (int i = 0; i < nbPlanets; ++i)
00143     {
00144         Body* planete = system->getBody(i);
00145         if (planete != NULL)
00146             if (strPlaneteToFindOn == planete->getName())
00147             {
00148                 nIDplanetetofindon = i;
00149                 PlanetarySystem* satellites = planete->getSatellites();
00150                 if (satellites)
00151                 {
00152                     nSattelites = satellites->getSystemSize();
00153                     JDback = new double[nSattelites];
00154                     memset(JDback, 0, nSattelites*sizeof(double));
00155                 }
00156                 break;
00157             }
00158     }
00159 
00160     Body* planete = system->getBody(nIDplanetetofindon);
00161     while (JDfrom < JDto)
00162     {
00163         PlanetarySystem* satellites = planete->getSatellites();
00164         if (satellites)
00165         {
00166             for (int j = 0; j < nSattelites; ++j)
00167             {
00168                 Body* caster = NULL;
00169                 Body* receiver = NULL;
00170                 bool test = false;
00171 
00172                 if (satellites->getBody(j)->getClassification() != Body::Spacecraft)
00173                 {
00174                     if (type == Eclipse::Solar)
00175                     {
00176                         caster = satellites->getBody(j);
00177                         receiver = planete;
00178                     }
00179                     else
00180                     {
00181                         caster = planete;
00182                         receiver = satellites->getBody(j);
00183                     }
00184 
00185                     test = testEclipse(*receiver, *caster, JDfrom);
00186                 }
00187 
00188                 if (test && JDfrom - JDback[j] > 1)
00189                 {
00190                     JDback[j] = JDfrom;
00191                     eclipse = new Eclipse(JDfrom);
00192                     eclipse->startTime = findEclipseSpan(*receiver, *caster,
00193                                                          JDfrom,
00194                                                          -1.0 / (24.0 * 60.0));
00195                     eclipse->endTime   = findEclipseSpan(*receiver, *caster,
00196                                                          JDfrom,
00197                                                          1.0 / (24.0 * 60.0));
00198                     eclipse->body = receiver;
00199                     eclipse->planete = planete->getName();
00200                     eclipse->sattelite = satellites->getBody(j)->getName();
00201                     Eclipses_.insert(Eclipses_.end(), *eclipse);
00202                     delete eclipse;
00203                 }
00204             }
00205         }
00206         JDfrom += 1.0 / 24.0;
00207     }
00208     if (JDback)
00209         delete JDback;
00210     if (Eclipses_.empty())
00211     {
00212         eclipse = new Eclipse(0.);
00213         eclipse->planete = "None";
00214         Eclipses_.insert(Eclipses_.end(), *eclipse);
00215         delete eclipse;
00216     }
00217     return 0;
00218 }
00219 

Generated on Sat Jan 14 22:30:30 2006 for Celestia by  doxygen 1.4.1