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

body.cpp

Go to the documentation of this file.
00001 // body.cpp
00002 //
00003 // Copyright (C) 2001 Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 #include <cstdlib>
00011 // Missing from g++ . . . why???
00012 // #include <limits>
00013 #include <cassert>
00014 #include <celmath/mathlib.h>
00015 #include <celutil/util.h>
00016 #include <celutil/utf8.h>
00017 #include "mesh.h"
00018 #include "meshmanager.h"
00019 #include "body.h"
00020 
00021 using namespace std;
00022 
00023 
00024 Body::Body(PlanetarySystem* _system) :
00025     orbit(NULL),
00026     orbitRefPlane(astro::BodyEquator),
00027     radius(10000.0f),
00028     mass(0.0f),
00029     oblateness(0),
00030     albedo(0.5),
00031     orientation(1.0f),
00032     // Ugh.  Numeric_limits class is missing from g++
00033     // protos(-numeric_limits<double>::infinity()),
00034     // eschatos(numeric_limits<double>::infinity()),
00035     // Do it the ugly way instead:
00036     protos(-1.0e+50),
00037     eschatos(1.0e+50),
00038     model(InvalidResource),
00039     surface(Color(1.0f, 1.0f, 1.0f)),
00040     atmosphere(NULL),
00041     rings(NULL),
00042     satellites(NULL),
00043     classification(Unknown),
00044     altSurfaces(NULL),
00045     locations(NULL),
00046     locationsComputed(false)
00047 {
00048     system = _system;
00049 }
00050 
00051 
00052 Body::~Body()
00053 {
00054     // clean up orbit, atmosphere, etc.
00055     if (system != NULL)
00056         system->removeBody(this);
00057 }
00058 
00059 
00060 PlanetarySystem* Body::getSystem() const
00061 {
00062     return system;
00063 }
00064 
00065 
00066 string Body::getName(bool i18n) const
00067 {
00068     if (!i18n || i18nName == "") return name;
00069     return i18nName;
00070 }
00071 
00072 
00073 void Body::setName(const string _name)
00074 {
00075     name = _name;
00076     i18nName = _(_name.c_str());
00077     if (name == i18nName) i18nName = "";
00078 }
00079 
00080 
00081 Orbit* Body::getOrbit() const
00082 {
00083     return orbit;
00084 }
00085 
00086 
00087 void Body::setOrbit(Orbit* _orbit)
00088 {
00089     delete orbit;
00090     orbit = _orbit;
00091 }
00092 
00093 
00094 astro::ReferencePlane Body::getOrbitReferencePlane() const
00095 {
00096     return orbitRefPlane;
00097 }
00098 
00099 
00100 void Body::setOrbitReferencePlane(astro::ReferencePlane refPlane)
00101 {
00102     orbitRefPlane = refPlane;
00103 }
00104 
00105 
00106 float Body::getRadius() const
00107 {
00108     return radius;
00109 }
00110 
00111 
00112 void Body::setRadius(float _radius)
00113 {
00114     radius = _radius;
00115 }
00116 
00117 
00118 // For an irregular object, the radius is defined to be the largest semi-axis
00119 // of the axis-aligned bounding box.  The radius of the smallest sphere containing
00120 // the object is potentially larger by a factor of sqrt(3)
00121 float Body::getBoundingRadius() const
00122 {
00123     if (model == InvalidResource)
00124         return radius;
00125     else
00126         return radius * 1.7320508f; // sqrt(3)
00127 }
00128 
00129 
00130 float Body::getMass() const
00131 {
00132     return mass;
00133 }
00134 
00135 
00136 void Body::setMass(float _mass)
00137 {
00138     mass = _mass;
00139 }
00140 
00141 
00142 float Body::getOblateness() const
00143 {
00144     return oblateness;
00145 }
00146 
00147 
00148 void Body::setOblateness(float _oblateness)
00149 {
00150     oblateness = _oblateness;
00151 }
00152 
00153 
00154 float Body::getAlbedo() const
00155 {
00156     return albedo;
00157 }
00158 
00159 
00160 void Body::setAlbedo(float _albedo)
00161 {
00162     albedo = _albedo;
00163 }
00164 
00165 
00166 Quatf Body::getOrientation() const
00167 {
00168     return orientation;
00169 }
00170 
00171 
00172 void Body::setOrientation(const Quatf& q)
00173 {
00174     orientation = q;
00175 }
00176 
00177 
00178 RotationElements Body::getRotationElements() const
00179 {
00180     return rotationElements;
00181 }
00182 
00183 
00184 void Body::setRotationElements(const RotationElements& re)
00185 {
00186     rotationElements = re;
00187 }
00188 
00189 
00190 const Surface& Body::getSurface() const
00191 {
00192     return surface;
00193 }
00194 
00195 
00196 Surface& Body::getSurface()
00197 {
00198     return surface;
00199 }
00200 
00201 
00202 void Body::setSurface(const Surface& surf)
00203 {
00204     surface = surf;
00205 }
00206 
00207 
00208 ResourceHandle Body::getModel() const
00209 {
00210     return model;
00211 }
00212 
00213 void Body::setModel(ResourceHandle _model)
00214 {
00215     model = _model;
00216 }
00217 
00218 
00219 PlanetarySystem* Body::getSatellites() const
00220 {
00221     return satellites;
00222 }
00223 
00224 void Body::setSatellites(PlanetarySystem* ssys)
00225 {
00226     satellites = ssys;
00227 }
00228 
00229 
00230 RingSystem* Body::getRings() const
00231 {
00232     return rings;
00233 }
00234 
00235 void Body::setRings(const RingSystem& _rings)
00236 {
00237     if (rings == NULL)
00238         rings = new RingSystem(_rings);
00239     else
00240         *rings = _rings;
00241 }
00242 
00243 
00244 const Atmosphere* Body::getAtmosphere() const
00245 {
00246     return atmosphere;
00247 }
00248 
00249 Atmosphere* Body::getAtmosphere()
00250 {
00251     return atmosphere;
00252 }
00253 
00254 void Body::setAtmosphere(const Atmosphere& _atmosphere)
00255 {
00256     if (atmosphere == NULL)
00257         atmosphere = new Atmosphere();
00258     *atmosphere = _atmosphere;
00259 }
00260 
00261 
00262 // Get a matrix which converts from local to heliocentric coordinates
00263 Mat4d Body::getLocalToHeliocentric(double when) const
00264 {
00265     double ascendingNode = (double) rotationElements.ascendingNode +
00266         rotationElements.precessionRate * (when - astro::J2000);
00267 
00268     Point3d pos = orbit->positionAtTime(when);
00269     Mat4d frame;
00270 
00271     switch (orbitRefPlane)
00272     {
00273     case astro::BodyEquator:
00274         frame = (Mat4d::xrotation(-rotationElements.obliquity) *
00275                  Mat4d::yrotation(-ascendingNode) *
00276                  Mat4d::translation(pos));
00277         break;
00278     case astro::Ecliptic_J2000:
00279         frame = Mat4d::translation(pos);
00280         break;
00281     case astro::Equator_J2000:
00282         frame = Mat4d::translation(pos);
00283         break;
00284     default:
00285         assert(0);
00286     }
00287  
00288     // Recurse up the hierarchy . . .
00289     if (system != NULL && system->getPrimaryBody() != NULL)
00290         frame = frame * system->getPrimaryBody()->getLocalToHeliocentric(when);
00291 
00292     return frame;
00293 }
00294 
00295 
00296 // Return the position of the center of the body in heliocentric coordinates
00297 Point3d Body::getHeliocentricPosition(double when) const
00298 {
00299     return Point3d(0.0, 0.0, 0.0) * getLocalToHeliocentric(when);
00300 }
00301 
00302 
00303 Quatd Body::getEclipticalToEquatorial(double when) const
00304 {
00305     double ascendingNode = (double) rotationElements.ascendingNode +
00306         rotationElements.precessionRate * (when - astro::J2000);
00307 
00308     Quatd q =
00309         Quatd::xrotation(-rotationElements.obliquity) *
00310         Quatd::yrotation(-ascendingNode);
00311 
00312     // Recurse up the hierarchy . . .
00313     if (system != NULL && system->getPrimaryBody() != NULL)
00314         q = q * system->getPrimaryBody()->getEclipticalToEquatorial(when);
00315 
00316     return q;
00317 }
00318 
00319 
00320 Quatd Body::getEclipticalToGeographic(double when) const
00321 {
00322     return getEquatorialToGeographic(when) * getEclipticalToEquatorial(when);
00323 }
00324 
00325 
00326 // The geographic coordinate system has an origin at the center of the
00327 // body, y-axis parallel to the rotation axis, x-axis through the prime
00328 // meridian, and z-axis at a right angle the xy plane.  An object with
00329 // constant geographic coordinates will thus remain fixed with respect
00330 // to a point on the surface of the body.
00331 Quatd Body::getEquatorialToGeographic(double when) const
00332 {
00333     double t = when - rotationElements.epoch;
00334     double rotations = t / (double) rotationElements.period;
00335     double wholeRotations = floor(rotations);
00336     double remainder = rotations - wholeRotations;
00337 
00338     // Add an extra half rotation because of the convention in all
00339     // planet texture maps where zero deg long. is in the middle of
00340     // the texture.
00341     remainder += 0.5;
00342     
00343     Quatd q(1);
00344     q.yrotate(-remainder * 2 * PI - rotationElements.offset);
00345     return q;
00346 }
00347 
00348 
00349 Mat4d Body::getGeographicToHeliocentric(double when) const
00350 {
00351     return getEquatorialToGeographic(when).toMatrix4() *
00352         getLocalToHeliocentric(when);
00353 }
00354 
00355 
00356 Vec3f Body::planetocentricToCartesian(float lon, float lat, float alt) const
00357 {
00358     float phi = -degToRad(lat) + (float) PI / 2;
00359     float theta = degToRad(lon) - (float) PI;
00360 
00361     Vec3f pos((float) (cos(theta) * sin(phi)),
00362               (float) (cos(phi)),
00363               (float) (-sin(theta) * sin(phi)));
00364 
00365     return pos * (getRadius() + alt);
00366 }
00367 
00368 
00369 Vec3f Body::planetocentricToCartesian(const Vec3f& lonLatAlt) const
00370 {
00371     return planetocentricToCartesian(lonLatAlt.x, lonLatAlt.y, lonLatAlt.z);
00372 }
00373 
00374 
00375 Vec3f Body::cartesianToPlanetocentric(const Vec3f& v) const
00376 {
00377     Vec3f w = v;
00378     w.normalize();
00379 
00380     double lat = (float) PI / 2.0f - acos(w.y);
00381     double lon = atan2(w.z, -w.x);
00382 
00383     return Vec3f((float) lon, (float) lat, v.length() - getRadius());
00384 }
00385 
00386 
00387 bool Body::extant(double t) const
00388 {
00389     return t >= protos && t < eschatos;
00390 }
00391 
00392 
00393 void Body::setLifespan(double begin, double end)
00394 {
00395     protos = begin;
00396     eschatos = end;
00397 }
00398 
00399 
00400 void Body::getLifespan(double& begin, double& end) const
00401 {
00402     begin = protos;
00403     end = eschatos;
00404 }
00405 
00406 
00407 #define SOLAR_IRRADIANCE   1367.6
00408 #define SOLAR_POWER           3.8462e26  // Watts
00409 
00410 float Body::getLuminosity(const Star& sun,
00411                           float distanceFromSun) const
00412 {
00413     return getLuminosity(sun.getLuminosity(), distanceFromSun);
00414 }
00415 
00416 
00417 float Body::getLuminosity(float sunLuminosity,
00418                           float distanceFromSun) const
00419 {
00420     // Compute the total power of the star in Watts
00421     double power = SOLAR_POWER * sunLuminosity;
00422 
00423     // Compute the irradiance at a distance of 1au from the star in W/m^2
00424     // double irradiance = power / sphereArea(astro::AUtoKilometers(1.0) * 1000);
00425 
00426     // Compute the irradiance at the body's distance from the star
00427     double satIrradiance = power / sphereArea(distanceFromSun * 1000);
00428 
00429     // Compute the total energy hitting the planet
00430     double incidentEnergy = satIrradiance * circleArea(radius * 1000);
00431 
00432     double reflectedEnergy = incidentEnergy * albedo;
00433     
00434     // Compute the luminosity (i.e. power relative to solar power)
00435     return (float) (reflectedEnergy / SOLAR_POWER);
00436 }
00437 
00438 
00439 float Body::getApparentMagnitude(const Star& sun,
00440                                  float distanceFromSun,
00441                                  float distanceFromViewer) const
00442 {
00443     return astro::lumToAppMag(getLuminosity(sun, distanceFromSun),
00444                               astro::kilometersToLightYears(distanceFromViewer));
00445 }
00446 
00447 
00448 // Return the apparent magnitude of the body, corrected for the phase.
00449 float Body::getApparentMagnitude(const Star& sun,
00450                                  const Vec3d& sunPosition,
00451                                  const Vec3d& viewerPosition) const
00452 {
00453     return getApparentMagnitude(sun.getLuminosity(),
00454                                 sunPosition,
00455                                 viewerPosition);
00456 }
00457 
00458 
00459 float Body::getApparentMagnitude(float sunLuminosity,
00460                                  const Vec3d& sunPosition,
00461                                  const Vec3d& viewerPosition) const
00462 {
00463     double distanceToViewer = viewerPosition.length();
00464     double distanceToSun = sunPosition.length();
00465     float illuminatedFraction = (float) (1.0 + (viewerPosition / distanceToViewer) *
00466                                          (sunPosition / distanceToSun)) / 2.0f;
00467 
00468     return astro::lumToAppMag(getLuminosity(sunLuminosity, (float) distanceToSun) * illuminatedFraction, (float) astro::kilometersToLightYears(distanceToViewer));
00469 }
00470 
00471 
00472 int Body::getClassification() const
00473 {
00474     return classification;
00475 }
00476 
00477 void Body::setClassification(int _classification)
00478 {
00479     classification = _classification;
00480 }
00481 
00482 
00483 string Body::getInfoURL() const
00484 {
00485     return infoURL;
00486 }
00487 
00488 void Body::setInfoURL(const string& _infoURL)
00489 {
00490     infoURL = _infoURL;
00491 }
00492 
00493 
00494 Surface* Body::getAlternateSurface(const string& name) const
00495 {
00496     if (altSurfaces == NULL)
00497         return NULL;
00498 
00499     AltSurfaceTable::iterator iter = altSurfaces->find(name);
00500     if (iter == altSurfaces->end())
00501         return NULL;
00502     else
00503         return iter->second;
00504 }
00505 
00506 
00507 void Body::addAlternateSurface(const string& name, Surface* surface)
00508 {
00509     if (altSurfaces == NULL)
00510         altSurfaces = new AltSurfaceTable();
00511 
00512     //altSurfaces->insert(AltSurfaceTable::value_type(name, surface));
00513     (*altSurfaces)[name] = surface;
00514 }
00515 
00516 
00517 vector<string>* Body::getAlternateSurfaceNames() const
00518 {
00519     vector<string>* names = new vector<string>();
00520     if (altSurfaces != NULL)
00521     {
00522         for (AltSurfaceTable::const_iterator iter = altSurfaces->begin();
00523              iter != altSurfaces->end(); iter++)
00524         {
00525             names->insert(names->end(), iter->first);
00526         }
00527     }
00528 
00529     return names;
00530 }
00531 
00532 
00533 void Body::addLocation(Location* loc)
00534 {
00535     assert(loc != NULL);
00536     if (loc == NULL)
00537         return;
00538 
00539     if (locations == NULL)
00540         locations = new vector<Location*>();
00541     locations->insert(locations->end(), loc);
00542     loc->setParentBody(this);
00543 }
00544 
00545 
00546 vector<Location*>* Body::getLocations() const
00547 {
00548     return locations;
00549 }
00550 
00551 
00552 Location* Body::findLocation(const string& name, bool i18n) const
00553 {
00554     if (locations == NULL)
00555         return NULL;
00556 
00557     for (vector<Location*>::const_iterator iter = locations->begin();
00558          iter != locations->end(); iter++)
00559     {
00560         if (!UTF8StringCompare(name, (*iter)->getName(i18n)))
00561             return *iter;
00562     }
00563 
00564     return NULL;
00565 }
00566 
00567 
00568 // Compute the positions of locations on an irregular object using ray-mesh
00569 // intersections.  This is not automatically done when a location is added
00570 // because it would force the loading of all meshes for objects with 
00571 // defined locations; on-demand (i.e. when the object becomes visible to
00572 // a user) loading of meshes is preferred.
00573 void Body::computeLocations()
00574 {
00575     if (locationsComputed)
00576         return;
00577 
00578     locationsComputed = true;
00579 
00580     // No work to do if there's no mesh, or if the mesh cannot be loaded
00581     if (model == InvalidResource)
00582         return;
00583     Model* m = GetModelManager()->find(model);
00584     if (m == NULL)
00585         return;
00586 
00587     // TODO: Implement separate radius and bounding radius so that this hack is
00588     // not necessary.
00589     double boundingRadius = 2.0;
00590 
00591     for (vector<Location*>::const_iterator iter = locations->begin();
00592          iter != locations->end(); iter++)
00593     {
00594         Vec3f v = (*iter)->getPosition();
00595         float alt = v.length() - radius;
00596         if (alt != -radius)
00597             v.normalize();
00598         v *= (float) boundingRadius;
00599 
00600         Ray3d ray(Point3d(v.x, v.y, v.z), Vec3d(-v.x, -v.y, -v.z));
00601         double t = 0.0;
00602         if (m->pick(ray, t))
00603         {
00604             v *= (float) ((1.0 - t) * radius + alt);
00605             (*iter)->setPosition(v);
00606         }
00607     }
00608 }
00609 
00610 
00611 /**** Implementation of PlanetarySystem ****/
00612 
00613 PlanetarySystem::PlanetarySystem(Body* _primary) : primary(_primary)
00614 {
00615     if (primary != NULL && primary->getSystem() != NULL)
00616         star = primary->getSystem()->getStar();
00617     else
00618         star = NULL;
00619 }
00620 
00621 PlanetarySystem::PlanetarySystem(Star* _star) :
00622     star(_star), primary(NULL)
00623 {
00624 }
00625 
00626 
00627 void PlanetarySystem::addBody(Body* body)
00628 {
00629     satellites.insert(satellites.end(), body);
00630 }
00631 
00632 
00633 void PlanetarySystem::removeBody(Body* body)
00634 {
00635     for (vector<Body*>::iterator iter = satellites.begin();
00636          iter != satellites.end(); iter++)
00637     {
00638         if (*iter == body)
00639         {
00640             satellites.erase(iter);
00641             break;
00642         }
00643     }
00644 }
00645 
00646 
00647 void PlanetarySystem::replaceBody(Body* oldBody, Body* newBody)
00648 {
00649     for (vector<Body*>::iterator iter = satellites.begin();
00650          iter != satellites.end(); iter++)
00651     {
00652         if (*iter == oldBody)
00653         {
00654             *iter = newBody;
00655             break;
00656         }
00657     }
00658 }
00659 
00660 
00661 Body* PlanetarySystem::find(string _name, bool deepSearch, bool i18n) const
00662 {
00663     for (vector<Body*>::const_iterator iter = satellites.begin();
00664          iter != satellites.end(); iter++)
00665     {
00666         if (UTF8StringCompare((*iter)->getName(i18n), _name) == 0)
00667         {
00668             return *iter;
00669         }
00670         else if (deepSearch && (*iter)->getSatellites() != NULL)
00671         {
00672             Body* body = (*iter)->getSatellites()->find(_name, deepSearch, i18n);
00673             if (body != NULL)
00674                 return body;
00675         }
00676     }
00677 
00678     return NULL;
00679 }
00680 
00681 
00682 bool PlanetarySystem::traverse(TraversalFunc func, void* info) const
00683 {
00684     for (int i = 0; i < getSystemSize(); i++)
00685     {
00686         Body* body = getBody(i);
00687         // assert(body != NULL);
00688         if (!func(body, info))
00689             return false;
00690         if (body->getSatellites() != NULL)
00691         {
00692             if (!body->getSatellites()->traverse(func, info))
00693                 return false;
00694         }
00695     }
00696 
00697     return true;
00698 }
00699 
00700 std::vector<std::string> PlanetarySystem::getCompletion(const std::string& _name, bool rec) const
00701 {
00702     std::vector<std::string> completion;
00703       
00704     for (vector<Body*>::const_iterator iter = satellites.begin();
00705          iter != satellites.end(); iter++)
00706     {
00707         if (UTF8StringCompare((*iter)->getName(true), _name, _name.length()) == 0)
00708         {
00709             completion.push_back((*iter)->getName(true));
00710         }
00711         if (rec && (*iter)->getSatellites() != NULL)
00712         {
00713             std::vector<std::string> bodies = (*iter)->getSatellites()->getCompletion(_name);
00714             completion.insert(completion.end(), bodies.begin(), bodies.end());
00715         }
00716     }
00717 
00718     return completion;
00719 }

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