00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <cstdlib>
00011
00012
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
00033
00034
00035
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
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
00119
00120
00121 float Body::getBoundingRadius() const
00122 {
00123 if (model == InvalidResource)
00124 return radius;
00125 else
00126 return radius * 1.7320508f;
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
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
00289 if (system != NULL && system->getPrimaryBody() != NULL)
00290 frame = frame * system->getPrimaryBody()->getLocalToHeliocentric(when);
00291
00292 return frame;
00293 }
00294
00295
00296
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
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
00327
00328
00329
00330
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
00339
00340
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
00421 double power = SOLAR_POWER * sunLuminosity;
00422
00423
00424
00425
00426
00427 double satIrradiance = power / sphereArea(distanceFromSun * 1000);
00428
00429
00430 double incidentEnergy = satIrradiance * circleArea(radius * 1000);
00431
00432 double reflectedEnergy = incidentEnergy * albedo;
00433
00434
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
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
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
00569
00570
00571
00572
00573 void Body::computeLocations()
00574 {
00575 if (locationsComputed)
00576 return;
00577
00578 locationsComputed = true;
00579
00580
00581 if (model == InvalidResource)
00582 return;
00583 Model* m = GetModelManager()->find(model);
00584 if (m == NULL)
00585 return;
00586
00587
00588
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
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
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 }