body.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:33k
- // body.cpp
- //
- // Copyright (C) 2001-2006 Chris Laurel <claurel@shatters.net>
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- #include <cstdlib>
- #include <cassert>
- #include <algorithm>
- #include <celmath/mathlib.h>
- #include <celutil/util.h>
- #include <celutil/utf8.h>
- #include "mesh.h"
- #include "meshmanager.h"
- #include "body.h"
- #include "frame.h"
- #include "timeline.h"
- #include "timelinephase.h"
- #include "frametree.h"
- #include "referencemark.h"
- using namespace std;
- Body::Body(PlanetarySystem* _system, const string& _name) :
- names(1),
- localizedNameIndex(0),
- system(_system),
- satellites(NULL),
- timeline(NULL),
- frameTree(NULL),
- radius(1.0f),
- semiAxes(1.0f, 1.0f, 1.0f),
- mass(0.0f),
- albedo(0.5f),
- orientation(1.0f),
- geometry(InvalidResource),
- geometryScale(1.0f),
- surface(Color(1.0f, 1.0f, 1.0f)),
- atmosphere(NULL),
- rings(NULL),
- classification(Unknown),
- altSurfaces(NULL),
- locations(NULL),
- locationsComputed(false),
- referenceMarks(NULL),
- visible(1),
- clickable(1),
- visibleAsPoint(1),
- overrideOrbitColor(0),
- orbitVisibility(UseClassVisibility),
- secondaryIlluminator(true)
- {
- setName(_name);
- recomputeCullingRadius();
- system->addBody(this);
- }
- Body::~Body()
- {
- if (system != NULL)
- system->removeBody(this);
- // Remove from frame hierarchy
- // Clean up the reference mark list
- if (referenceMarks != NULL)
- {
- for (list<ReferenceMark*>::iterator iter = referenceMarks->begin(); iter != referenceMarks->end(); ++iter)
- delete *iter;
- delete referenceMarks;
- }
- delete timeline;
- delete satellites;
- delete frameTree;
- }
- /*! Reset body attributes to their default values. The object hierarchy is left untouched,
- * i.e. child objects are not removed. Alternate surfaces and locations are not removed
- * either.
- */
- void Body::setDefaultProperties()
- {
- radius = 1.0f;
- semiAxes = Vec3f(1.0f, 1.0f, 1.0f);
- mass = 0.0f;
- albedo = 0.5f;
- orientation = Quatf(1.0f);
- geometry = InvalidResource;
- surface = Surface(Color::White);
- delete atmosphere;
- atmosphere = NULL;
- delete rings;
- rings = NULL;
- classification = Unknown;
- visible = 1;
- clickable = 1;
- visibleAsPoint = 1;
- overrideOrbitColor = 0;
- orbitVisibility = UseClassVisibility;
- recomputeCullingRadius();
- }
- /*! Return the list of all names (non-localized) by which this
- * body is known.
- */
- const vector<string>& Body::getNames() const
- {
- return names;
- }
- /*! Return the primary name for the body; if i18n, return the
- * localized name of the body.
- */
- string Body::getName(bool i18n) const
- {
- if (!i18n)
- return names[0];
- else
- return names[localizedNameIndex];
- }
- /*! Get the localized name for the body. If no localized name
- * has been set, the primary name is returned.
- */
- string Body::getLocalizedName() const
- {
- return names[localizedNameIndex];
- }
- bool Body::hasLocalizedName() const
- {
- return localizedNameIndex != 0;
- }
- /*! Set the primary name of the body. The localized name is updated
- * automatically as well.
- * Note: setName() is private, and only called from the Body constructor.
- * It shouldn't be called elsewhere.
- */
- void Body::setName(const string& name)
- {
- names[0] = name;
- string localizedName = _(name.c_str());
- if (name == localizedName)
- {
- // No localized name; set the localized name index to zero to
- // indicate this.
- localizedNameIndex = 0;
- }
- else
- {
- names.push_back(localizedName);
- localizedNameIndex = names.size() - 1;
- }
- }
- /*! Add a new name for this body. Aliases are non localized.
- */
- void Body::addAlias(const string& alias)
- {
- names.push_back(alias);
- system->addAlias(this, alias);
- }
- PlanetarySystem* Body::getSystem() const
- {
- return system;
- }
- FrameTree* Body::getFrameTree() const
- {
- return frameTree;
- }
- FrameTree* Body::getOrCreateFrameTree()
- {
- if (frameTree == NULL)
- frameTree = new FrameTree(this);
- return frameTree;
- }
- const Timeline* Body::getTimeline() const
- {
- return timeline;
- }
- void Body::setTimeline(Timeline* newTimeline)
- {
- if (timeline != newTimeline)
- {
- delete timeline;
- timeline = newTimeline;
- markChanged();
- }
- }
- void Body::markChanged()
- {
- if (timeline != NULL)
- timeline->markChanged();
- }
- void Body::markUpdated()
- {
- if (frameTree != NULL)
- frameTree->markUpdated();
- }
- const ReferenceFrame* Body::getOrbitFrame(double tdb) const
- {
- return timeline->findPhase(tdb)->orbitFrame();
- }
- const Orbit* Body::getOrbit(double tdb) const
- {
- return timeline->findPhase(tdb)->orbit();
- }
- const ReferenceFrame* Body::getBodyFrame(double tdb) const
- {
- return timeline->findPhase(tdb)->bodyFrame();
- }
- const RotationModel* Body::getRotationModel(double tdb) const
- {
- return timeline->findPhase(tdb)->rotationModel();
- }
- /*! Get the radius of a sphere large enough to contain the primary
- * geometry of the object: either a mesh or an ellipsoid.
- * For an irregular (mesh) object, the radius is defined to be
- * the largest semi-axis of the axis-aligned bounding box. The
- * radius of the smallest sphere containing the object is potentially
- * larger by a factor of sqrt(3).
- *
- * This method does not consider additional object features
- * such as rings, atmospheres, or reference marks; use
- * getCullingRadius() for that.
- */
- float Body::getBoundingRadius() const
- {
- if (geometry == InvalidResource)
- return radius;
- else
- return radius * 1.7320508f; // sqrt(3)
- }
- /*! Return the radius of sphere large enough to contain any geometry
- * associated with this object: the primary geometry, comet tail,
- * rings, atmosphere shell, cloud layers, or reference marks.
- */
- float Body::getCullingRadius() const
- {
- return cullingRadius;
- }
- float Body::getMass() const
- {
- return mass;
- }
- void Body::setMass(float _mass)
- {
- mass = _mass;
- }
- float Body::getAlbedo() const
- {
- return albedo;
- }
- void Body::setAlbedo(float _albedo)
- {
- albedo = _albedo;
- }
- Quatf Body::getOrientation() const
- {
- return orientation;
- }
- void Body::setOrientation(const Quatf& q)
- {
- orientation = q;
- }
- /*! Set the semiaxes of a body.
- */
- void Body::setSemiAxes(const Vec3f& _semiAxes)
- {
- semiAxes = _semiAxes;
- // Radius will always be the largest of the three semi axes
- radius = max(semiAxes.x, max(semiAxes.y, semiAxes.z));
- recomputeCullingRadius();
- }
- /*! Retrieve the body's semiaxes
- */
- Vec3f Body::getSemiAxes() const
- {
- return semiAxes;
- }
- /*! Get the radius of the body. For a spherical body, this is simply
- * the sphere's radius. For an ellipsoidal body, the radius is the
- * largest of the three semiaxes. For irregular bodies (with a shape
- * represented by a mesh), the radius is the largest semiaxis of the
- * mesh's axis aligned bounding axis. Note that this means some portions
- * of the mesh may extend outside the sphere of the retrieved radius.
- * To obtain the radius of a sphere that will definitely enclose the
- * body, call getBoundingRadius() instead.
- */
- float Body::getRadius() const
- {
- return radius;
- }
- /*! Return true if the body is a perfect sphere.
- */
- bool Body::isSphere() const
- {
- return (geometry == InvalidResource) &&
- (semiAxes.x == semiAxes.y) &&
- (semiAxes.x == semiAxes.z);
- }
- /*! Return true if the body is ellipsoidal, with geometry determined
- * completely by its semiaxes rather than a triangle based model.
- */
- bool Body::isEllipsoid() const
- {
- return geometry == InvalidResource;
- }
- const Surface& Body::getSurface() const
- {
- return surface;
- }
- Surface& Body::getSurface()
- {
- return surface;
- }
- void Body::setSurface(const Surface& surf)
- {
- surface = surf;
- }
- void Body::setGeometry(ResourceHandle _geometry)
- {
- geometry = _geometry;
- }
- /*! Set the scale factor for geometry; this is only used with unnormalized meshes.
- * When a mesh is normalized, the effective scale factor is the radius.
- */
- void Body::setGeometryScale(float scale)
- {
- geometryScale = scale;
- }
- PlanetarySystem* Body::getSatellites() const
- {
- return satellites;
- }
- void Body::setSatellites(PlanetarySystem* ssys)
- {
- satellites = ssys;
- }
- RingSystem* Body::getRings() const
- {
- return rings;
- }
- void Body::setRings(const RingSystem& _rings)
- {
- if (rings == NULL)
- rings = new RingSystem(_rings);
- else
- *rings = _rings;
- recomputeCullingRadius();
- }
- const Atmosphere* Body::getAtmosphere() const
- {
- return atmosphere;
- }
- Atmosphere* Body::getAtmosphere()
- {
- return atmosphere;
- }
- void Body::setAtmosphere(const Atmosphere& _atmosphere)
- {
- if (atmosphere == NULL)
- atmosphere = new Atmosphere();
- *atmosphere = _atmosphere;
- recomputeCullingRadius();
- }
- // The following four functions are used to get the state of the body
- // in universal coordinates:
- // * getPosition
- // * getOrientation
- // * getVelocity
- // * getAngularVelocity
- /*! Get the position of the body in the universal coordinate system.
- * This method uses high-precision coordinates and is thus
- * slower relative to getAstrocentricPosition(), which works strictly
- * with standard double precision. For most purposes,
- * getAstrocentricPosition() should be used instead of the more
- * general getPosition().
- */
- UniversalCoord Body::getPosition(double tdb) const
- {
- Point3d position(0.0, 0.0, 0.0);
- const TimelinePhase* phase = timeline->findPhase(tdb);
- Point3d p = phase->orbit()->positionAtTime(tdb);
- ReferenceFrame* frame = phase->orbitFrame();
- while (frame->getCenter().getType() == Selection::Type_Body)
- {
- phase = frame->getCenter().body()->timeline->findPhase(tdb);
- position += Vec3d(p.x, p.y, p.z) * frame->getOrientation(tdb).toMatrix3();
- p = phase->orbit()->positionAtTime(tdb);
- frame = phase->orbitFrame();
- }
- position += Vec3d(p.x, p.y, p.z) * frame->getOrientation(tdb).toMatrix3();
- if (frame->getCenter().star())
- return astro::universalPosition(position, frame->getCenter().star()->getPosition(tdb));
- else
- return astro::universalPosition(position, frame->getCenter().getPosition(tdb));
- }
- /*! Get the orientation of the body in the universal coordinate system.
- */
- Quatd Body::getOrientation(double tdb) const
- {
- // TODO: This method overloads getOrientation(), but the two do very
- // different things. The other method should be renamed to
- // getModelOrientation().
- const TimelinePhase* phase = timeline->findPhase(tdb);
- return phase->rotationModel()->orientationAtTime(tdb) *
- phase->bodyFrame()->getOrientation(tdb);
- }
- /*! Get the velocity of the body in the universal frame.
- */
- Vec3d Body::getVelocity(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- ReferenceFrame* orbitFrame = phase->orbitFrame();
- Vec3d v = phase->orbit()->velocityAtTime(tdb);
- v = v * orbitFrame->getOrientation(tdb).toMatrix3() + orbitFrame->getCenter().getVelocity(tdb);
- if (!orbitFrame->isInertial())
- {
- Vec3d r = Selection(const_cast<Body*>(this)).getPosition(tdb) - orbitFrame->getCenter().getPosition(tdb);
- r = r * astro::microLightYearsToKilometers(1.0);
- v += cross(orbitFrame->getAngularVelocity(tdb), r);
- }
- return v;
- }
- /*! Get the angular velocity of the body in the universal frame.
- */
- Vec3d Body::getAngularVelocity(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- Vec3d v = phase->rotationModel()->angularVelocityAtTime(tdb);
- ReferenceFrame* bodyFrame = phase->bodyFrame();
- v = v * bodyFrame->getOrientation(tdb).toMatrix3();
- if (!bodyFrame->isInertial())
- {
- v += bodyFrame->getAngularVelocity(tdb);
- }
- return v;
- }
- /*! Get the transformation which converts body coordinates into
- * astrocentric coordinates. Some clarification on the meaning
- * of 'astrocentric': the position of every solar system body
- * is ultimately defined with respect to some star or star
- * system barycenter.
- */
- Mat4d Body::getLocalToAstrocentric(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- Point3d p = phase->orbitFrame()->convertToAstrocentric(phase->orbit()->positionAtTime(tdb), tdb);
- return Mat4d::translation(p);
- }
- /*! Get the position of the center of the body in astrocentric ecliptic coordinates.
- */
- Point3d Body::getAstrocentricPosition(double tdb) const
- {
- // TODO: Switch the iterative method used in getPosition
- const TimelinePhase* phase = timeline->findPhase(tdb);
- return phase->orbitFrame()->convertToAstrocentric(phase->orbit()->positionAtTime(tdb), tdb);
- }
- /*! Get a rotation that converts from the ecliptic frame to the body frame.
- */
- Quatd Body::getEclipticToFrame(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- return phase->bodyFrame()->getOrientation(tdb);
- }
- /*! Get a rotation that converts from the ecliptic frame to the body's
- * mean equatorial frame.
- */
- Quatd Body::getEclipticToEquatorial(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- return phase->rotationModel()->equatorOrientationAtTime(tdb) *
- phase->bodyFrame()->getOrientation(tdb);
- }
- /*! Get a rotation that converts from the ecliptic frame to this
- * objects's body fixed frame.
- */
- Quatd Body::getEclipticToBodyFixed(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- return phase->rotationModel()->orientationAtTime(tdb) *
- phase->bodyFrame()->getOrientation(tdb);
- }
- // The body-fixed coordinate system has an origin at the center of the
- // body, y-axis parallel to the rotation axis, x-axis through the prime
- // meridian, and z-axis at a right angle the xy plane.
- Quatd Body::getEquatorialToBodyFixed(double tdb) const
- {
- const TimelinePhase* phase = timeline->findPhase(tdb);
- return phase->rotationModel()->spin(tdb);
- }
- /*! Get a transformation to convert from the object's body fixed frame
- * to the astrocentric ecliptic frame.
- */
- Mat4d Body::getBodyFixedToAstrocentric(double tdb) const
- {
- return getEquatorialToBodyFixed(tdb).toMatrix4() * getLocalToAstrocentric(tdb);
- }
- Vec3d Body::planetocentricToCartesian(double lon, double lat, double alt) const
- {
- double phi = -degToRad(lat) + PI / 2;
- double theta = degToRad(lon) - PI;
- Vec3d pos(cos(theta) * sin(phi),
- cos(phi),
- -sin(theta) * sin(phi));
- return pos * (getRadius() + alt);
- }
- Vec3d Body::planetocentricToCartesian(const Vec3d& lonLatAlt) const
- {
- return planetocentricToCartesian(lonLatAlt.x, lonLatAlt.y, lonLatAlt.z);
- }
- /*! Convert cartesian body-fixed coordinates to spherical planetocentric
- * coordinates.
- */
- Vec3d Body::cartesianToPlanetocentric(const Vec3d& v) const
- {
- Vec3d w = v;
- w.normalize();
- double lat = PI / 2.0 - acos(w.y);
- double lon = atan2(w.z, -w.x);
- return Vec3d(lon, lat, v.length() - getRadius());
- }
- /*! Convert body-centered ecliptic coordinates to spherical planetocentric
- * coordinates.
- */
- Vec3d Body::eclipticToPlanetocentric(const Vec3d& ecl, double tdb) const
- {
- Quatd q = getEclipticToBodyFixed(tdb);
- Vec3d bf = ecl * (~q).toMatrix3();
- return cartesianToPlanetocentric(bf);
- }
- bool Body::extant(double t) const
- {
- return timeline->includes(t);
- }
- void Body::getLifespan(double& begin, double& end) const
- {
- begin = timeline->startTime();
- end = timeline->endTime();
- }
- float Body::getLuminosity(const Star& sun,
- float distanceFromSun) const
- {
- return getLuminosity(sun.getLuminosity(), distanceFromSun);
- }
- float Body::getLuminosity(float sunLuminosity,
- float distanceFromSun) const
- {
- // Compute the total power of the star in Watts
- double power = astro::SOLAR_POWER * sunLuminosity;
- // Compute the irradiance at a distance of 1au from the star in W/m^2
- // double irradiance = power / sphereArea(astro::AUtoKilometers(1.0) * 1000);
- // Compute the irradiance at the body's distance from the star
- double satIrradiance = power / sphereArea(distanceFromSun * 1000);
- // Compute the total energy hitting the planet
- double incidentEnergy = satIrradiance * circleArea(radius * 1000);
- double reflectedEnergy = incidentEnergy * albedo;
-
- // Compute the luminosity (i.e. power relative to solar power)
- return (float) (reflectedEnergy / astro::SOLAR_POWER);
- }
- /*! Get the apparent magnitude of the body, neglecting the phase (as if
- * the body was at opposition.
- */
- float Body::getApparentMagnitude(const Star& sun,
- float distanceFromSun,
- float distanceFromViewer) const
- {
- return astro::lumToAppMag(getLuminosity(sun, distanceFromSun),
- astro::kilometersToLightYears(distanceFromViewer));
- }
- /*! Get the apparent magnitude of the body, neglecting the phase (as if
- * the body was at opposition.
- */
- float Body::getApparentMagnitude(float sunLuminosity,
- float distanceFromSun,
- float distanceFromViewer) const
- {
- return astro::lumToAppMag(getLuminosity(sunLuminosity, distanceFromSun),
- astro::kilometersToLightYears(distanceFromViewer));
- }
- /*! Get the apparent magnitude of the body, corrected for its phase.
- */
- float Body::getApparentMagnitude(const Star& sun,
- const Vec3d& sunPosition,
- const Vec3d& viewerPosition) const
- {
- return getApparentMagnitude(sun.getLuminosity(),
- sunPosition,
- viewerPosition);
- }
- /*! Get the apparent magnitude of the body, corrected for its phase.
- */
- float Body::getApparentMagnitude(float sunLuminosity,
- const Vec3d& sunPosition,
- const Vec3d& viewerPosition) const
- {
- double distanceToViewer = viewerPosition.length();
- double distanceToSun = sunPosition.length();
- float illuminatedFraction = (float) (1.0 + (viewerPosition / distanceToViewer) *
- (sunPosition / distanceToSun)) / 2.0f;
- return astro::lumToAppMag(getLuminosity(sunLuminosity, (float) distanceToSun) * illuminatedFraction, (float) astro::kilometersToLightYears(distanceToViewer));
- }
- int Body::getClassification() const
- {
- return classification;
- }
- void Body::setClassification(int _classification)
- {
- classification = _classification;
- recomputeCullingRadius();
- markChanged();
- }
- /*! Return the effective classification of this body used when rendering
- * orbits. Normally, this is just the classification of the object, but
- * invisible objects are treated specially: they behave as if they have
- * the classification of their child objects. This fixes annoyances when
- * planets are defined with orbits relative to their system barycenters.
- * For example, Pluto's orbit can seen in a solar system scale view, even
- * though its orbit is defined relative to the Pluto-Charon barycenter
- * and is this just a few hundred kilometers in size.
- */
- int Body::getOrbitClassification() const
- {
- if (classification != Invisible || frameTree == NULL)
- {
- return classification;
- }
- else
- {
- int orbitClass = frameTree->childClassMask();
- if (orbitClass & Planet)
- return Planet;
- else if (orbitClass & DwarfPlanet)
- return DwarfPlanet;
- else if (orbitClass & Moon)
- return Moon;
- else if (orbitClass & MinorMoon)
- return MinorMoon;
- else if (orbitClass & Asteroid)
- return Asteroid;
- else if (orbitClass & Spacecraft)
- return Spacecraft;
- else
- return Invisible;
- }
- }
- string Body::getInfoURL() const
- {
- return infoURL;
- }
- void Body::setInfoURL(const string& _infoURL)
- {
- infoURL = _infoURL;
- }
- Surface* Body::getAlternateSurface(const string& name) const
- {
- if (altSurfaces == NULL)
- return NULL;
- AltSurfaceTable::iterator iter = altSurfaces->find(name);
- if (iter == altSurfaces->end())
- return NULL;
- else
- return iter->second;
- }
- void Body::addAlternateSurface(const string& name, Surface* surface)
- {
- if (altSurfaces == NULL)
- altSurfaces = new AltSurfaceTable();
- //altSurfaces->insert(AltSurfaceTable::value_type(name, surface));
- (*altSurfaces)[name] = surface;
- }
- vector<string>* Body::getAlternateSurfaceNames() const
- {
- vector<string>* names = new vector<string>();
- if (altSurfaces != NULL)
- {
- for (AltSurfaceTable::const_iterator iter = altSurfaces->begin();
- iter != altSurfaces->end(); iter++)
- {
- names->insert(names->end(), iter->first);
- }
- }
- return names;
- }
- void Body::addLocation(Location* loc)
- {
- assert(loc != NULL);
- if (loc == NULL)
- return;
- if (locations == NULL)
- locations = new vector<Location*>();
- locations->insert(locations->end(), loc);
- loc->setParentBody(this);
- }
- vector<Location*>* Body::getLocations() const
- {
- return locations;
- }
- Location* Body::findLocation(const string& name, bool i18n) const
- {
- if (locations == NULL)
- return NULL;
- for (vector<Location*>::const_iterator iter = locations->begin();
- iter != locations->end(); iter++)
- {
- if (!UTF8StringCompare(name, (*iter)->getName(i18n)))
- return *iter;
- }
- return NULL;
- }
- // Compute the positions of locations on an irregular object using ray-mesh
- // intersections. This is not automatically done when a location is added
- // because it would force the loading of all meshes for objects with
- // defined locations; on-demand (i.e. when the object becomes visible to
- // a user) loading of meshes is preferred.
- void Body::computeLocations()
- {
- if (locationsComputed)
- return;
- locationsComputed = true;
- // No work to do if there's no mesh, or if the mesh cannot be loaded
- if (geometry == InvalidResource)
- return;
- Geometry* g = GetGeometryManager()->find(geometry);
- if (g == NULL)
- return;
- // TODO: Implement separate radius and bounding radius so that this hack is
- // not necessary.
- double boundingRadius = 2.0;
- for (vector<Location*>::const_iterator iter = locations->begin();
- iter != locations->end(); iter++)
- {
- Vec3f v = (*iter)->getPosition();
- float alt = v.length() - radius;
- if (alt != -radius)
- v.normalize();
- v *= (float) boundingRadius;
- Ray3d ray(Point3d(v.x, v.y, v.z), Vec3d(-v.x, -v.y, -v.z));
- double t = 0.0;
- if (g->pick(ray, t))
- {
- v *= (float) ((1.0 - t) * radius + alt);
- (*iter)->setPosition(v);
- }
- }
- }
- /*! Add a new reference mark.
- */
- void
- Body::addReferenceMark(ReferenceMark* refMark)
- {
- if (referenceMarks == NULL)
- referenceMarks = new list<ReferenceMark*>();
- referenceMarks->push_back(refMark);
- recomputeCullingRadius();
- }
- /*! Remove the first reference mark with the specified tag.
- */
- void
- Body::removeReferenceMark(const string& tag)
- {
- if (referenceMarks != NULL)
- {
- ReferenceMark* refMark = findReferenceMark(tag);
- if (refMark != NULL)
- {
- referenceMarks->remove(refMark);
- delete refMark;
- recomputeCullingRadius();
- }
- }
- }
- /*! Find the first reference mark with the specified tag. If the body has
- * no reference marks with the specified tag, this method will return
- * NULL.
- */
- ReferenceMark*
- Body::findReferenceMark(const string& tag) const
- {
- if (referenceMarks != NULL)
- {
- for (list<ReferenceMark*>::iterator iter = referenceMarks->begin(); iter != referenceMarks->end(); ++iter)
- {
- if ((*iter)->getTag() == tag)
- return *iter;
- }
- }
- return NULL;
- }
- /*! Get the list of reference marks associated with this body. May return
- * NULL if there are no reference marks.
- */
- const list<ReferenceMark*>*
- Body::getReferenceMarks() const
- {
- return referenceMarks;
- }
- /*! Sets whether or not the object is visible.
- */
- void Body::setVisible(bool _visible)
- {
- visible = _visible ? 1 : 0;
- }
- /*! Sets whether or not the object can be selected by clicking on
- * it. If set to false, the object is completely ignored when the
- * user clicks it, making it possible to select background objects.
- */
- void Body::setClickable(bool _clickable)
- {
- clickable = _clickable ? 1 : 0;
- }
- /*! Set whether or not the object is visible as a starlike point
- * when it occupies less than a pixel onscreen. This is appropriate
- * for planets and moons, but generally not desireable for buildings
- * or spacecraft components.
- */
- void Body::setVisibleAsPoint(bool _visibleAsPoint)
- {
- visibleAsPoint = _visibleAsPoint ? 1 : 0;
- }
- /*! The orbitColorOverride flag is set to true if an alternate orbit
- * color should be used (specified via setOrbitColor) instead of the
- * default class orbit color.
- */
- void Body::setOrbitColorOverridden(bool override)
- {
- overrideOrbitColor = override ? 1 : 0;
- }
- /*! Set the visibility policy for the orbit of this object:
- * - NeverVisible: Never show the orbit of this object.
- * - UseClassVisibility: (Default) Show the orbit of this object
- * its class is enabled in the orbit mask.
- * - AlwaysVisible: Always show the orbit of this object whenever
- * orbit paths are enabled.
- */
- void Body::setOrbitVisibility(VisibilityPolicy _orbitVisibility)
- {
- orbitVisibility = _orbitVisibility;
- }
- /*! Set the color used when rendering the orbit. This is only used
- * when the orbitColorOverride flag is set to true; otherwise, the
- * standard orbit color for all objects of the class is used.
- */
- void Body::setOrbitColor(const Color& c)
- {
- orbitColor = c;
- }
- /*! Set whether or not the object should be considered when calculating
- * secondary illumination (e.g. planetshine.)
- */
- void Body::setSecondaryIlluminator(bool enable)
- {
- if (enable != secondaryIlluminator)
- {
- markChanged();
- secondaryIlluminator = enable;
- }
- }
- void Body::recomputeCullingRadius()
- {
- float r = getBoundingRadius();
- if (rings != NULL)
- r = max(r, rings->outerRadius);
- if (atmosphere != NULL)
- {
- r = max(r, atmosphere->height);
- r = max(r, atmosphere->cloudHeight);
- }
- if (referenceMarks != NULL)
- {
- for (std::list<ReferenceMark*>::const_iterator iter = referenceMarks->begin();
- iter != referenceMarks->end(); iter++)
- {
- r = max(r, (*iter)->boundingSphereRadius());
- }
- }
- if (classification == Body::Comet)
- r = max(r, astro::AUtoKilometers(1.0f));
- if (r != cullingRadius)
- {
- cullingRadius = r;
- markChanged();
- }
- }
- /**** Implementation of PlanetarySystem ****/
- /*! Return the equatorial frame for this object. This frame is used as
- * the default frame for objects in SSC files that orbit non-stellar bodies.
- * In order to avoid wasting memory, it is created until the first time it
- * is requested.
- */
- PlanetarySystem::PlanetarySystem(Body* _primary) :
- star(NULL),
- primary(_primary)
- {
- if (primary != NULL && primary->getSystem() != NULL)
- star = primary->getSystem()->getStar();
- }
- PlanetarySystem::PlanetarySystem(Star* _star) :
- star(_star),
- primary(NULL)
- {
- }
- PlanetarySystem::~PlanetarySystem()
- {
- }
- /*! Add a new alias for an object. If an object with the specified
- * alias already exists in the planetary system, the old entry will
- * be replaced.
- */
- void PlanetarySystem::addAlias(Body* body, const string& alias)
- {
- assert(body->getSystem() == this);
-
- objectIndex.insert(make_pair(alias, body));
- }
- /*! Remove the an alias for an object. This method does nothing
- * if the alias is not present in the index, or if the alias
- * refers to a different object.
- */
- void PlanetarySystem::removeAlias(const Body* body, const string& alias)
- {
- assert(body->getSystem() == this);
-
- ObjectIndex::iterator iter = objectIndex.find(alias);
- if (iter != objectIndex.end())
- {
- if (iter->second == body)
- objectIndex.erase(iter);
- }
- }
- void PlanetarySystem::addBody(Body* body)
- {
- satellites.insert(satellites.end(), body);
- addBodyToNameIndex(body);
- }
- // Add all aliases for the body to the name index
- void PlanetarySystem::addBodyToNameIndex(Body* body)
- {
- const vector<string>& names = body->getNames();
- for (vector<string>::const_iterator iter = names.begin(); iter != names.end(); iter++)
- {
- objectIndex.insert(make_pair(*iter, body));
- }
- }
- // Remove all references to the body in the name index.
- void PlanetarySystem::removeBodyFromNameIndex(const Body* body)
- {
- assert(body->getSystem() == this);
-
- // Erase the object from the object indices
- const vector<string>& names = body->getNames();
- for (vector<string>::const_iterator iter = names.begin(); iter != names.end(); iter++)
- {
- removeAlias(body, *iter);
- }
- }
- void PlanetarySystem::removeBody(Body* body)
- {
- for (vector<Body*>::iterator iter = satellites.begin();
- iter != satellites.end(); iter++)
- {
- if (*iter == body)
- {
- satellites.erase(iter);
- break;
- }
- }
-
- removeBodyFromNameIndex(body);
- }
- void PlanetarySystem::replaceBody(Body* oldBody, Body* newBody)
- {
- for (vector<Body*>::iterator iter = satellites.begin();
- iter != satellites.end(); iter++)
- {
- if (*iter == oldBody)
- {
- *iter = newBody;
- break;
- }
- }
- removeBodyFromNameIndex(oldBody);
- addBodyToNameIndex(newBody);
- }
- /*! Find a body with the specified name within a planetary system.
- *
- * deepSearch: if true, recursively search the systems of child objects
- * i18n: if true, allow matching of localized body names. When responding
- * to a user query, this flag should be true. In other cases--such
- * as resolving an object name in an ssc file--it should be false. Otherwise,
- * object lookup will behave differently based on the locale.
- */
- Body* PlanetarySystem::find(const string& _name, bool deepSearch, bool i18n) const
- {
- ObjectIndex::const_iterator firstMatch = objectIndex.find(_name);
- if (firstMatch != objectIndex.end())
- {
- Body* matchedBody = firstMatch->second;
-
- if (i18n)
- {
- return matchedBody;
- }
- else
- {
- // Ignore localized names
- if (!matchedBody->hasLocalizedName() || _name != matchedBody->getLocalizedName())
- return matchedBody;
- }
- }
- if (deepSearch)
- {
- for (vector<Body*>::const_iterator iter = satellites.begin();
- iter != satellites.end(); iter++)
- {
- if (UTF8StringCompare((*iter)->getName(i18n), _name) == 0)
- {
- return *iter;
- }
- else if (deepSearch && (*iter)->getSatellites() != NULL)
- {
- Body* body = (*iter)->getSatellites()->find(_name, deepSearch, i18n);
- if (body != NULL)
- return body;
- }
- }
- }
- return NULL;
- }
- bool PlanetarySystem::traverse(TraversalFunc func, void* info) const
- {
- for (int i = 0; i < getSystemSize(); i++)
- {
- Body* body = getBody(i);
- // assert(body != NULL);
- if (!func(body, info))
- return false;
- if (body->getSatellites() != NULL)
- {
- if (!body->getSatellites()->traverse(func, info))
- return false;
- }
- }
- return true;
- }
- std::vector<std::string> PlanetarySystem::getCompletion(const std::string& _name, bool deepSearch) const
- {
- std::vector<std::string> completion;
- int _name_length = UTF8Length(_name);
- // Search through all names in this planetary system.
- for (ObjectIndex::const_iterator iter = objectIndex.begin();
- iter != objectIndex.end(); iter++)
- {
- const string& alias = iter->first;
-
- if (UTF8StringCompare(alias, _name, _name_length) == 0)
- {
- completion.push_back(alias);
- }
- }
-
- // Scan child objects
- if (deepSearch)
- {
- for (vector<Body*>::const_iterator iter = satellites.begin();
- iter != satellites.end(); iter++)
- {
- if ((*iter)->getSatellites() != NULL)
- {
- vector<string> bodies = (*iter)->getSatellites()->getCompletion(_name);
- completion.insert(completion.end(), bodies.begin(), bodies.end());
- }
- }
- }
-
- return completion;
- }
- /*! Get the order of the object in the list of children. Returns -1 if the
- * specified body is not a child object.
- */
- int PlanetarySystem::getOrder(const Body* body) const
- {
- vector<Body*>::const_iterator iter = std::find(satellites.begin(), satellites.end(), body);
- if (iter == satellites.end())
- return -1;
- else
- return iter - satellites.begin();
- }