Implemented synchronous orbits which allow easy placement of objects on the surface of planets.

ver1_5_1
Chris Laurel 2004-03-10 11:01:48 +00:00
parent 355fe91be1
commit 5fb0d163a6
7 changed files with 147 additions and 39 deletions

View File

@ -116,6 +116,11 @@ float astro::AUtoKilometers(float au)
return au * (float) KM_PER_AU;
}
double astro::AUtoKilometers(double au)
{
return au * (double) KM_PER_AU;
}
float astro::kilometersToAU(float km)
{
return km / (float) KM_PER_AU;
@ -185,7 +190,7 @@ double astro::kilometersToMicroLightYears(double km)
float astro::microLightYearsToAU(float ly)
{
return ly * AU_PER_LY * 1e-6f;
return ly * (float) AU_PER_LY * 1e-6f;
}
double astro::microLightYearsToAU(double ly)

View File

@ -55,6 +55,13 @@ namespace astro
Chase = 6,
};
enum ReferencePlane
{
BodyEquator, // planet equator if moon, ecliptic if planet
Ecliptic_J2000,
Equator_J2000,
};
float lumToAbsMag(float lum);
float lumToAppMag(float lum, float lyrs);
float absMagToLum(float mag);
@ -71,6 +78,7 @@ namespace astro
double lightYearsToAU(double);
float AUtoLightYears(float);
float AUtoKilometers(float);
double AUtoKilometers(double);
float kilometersToAU(float);
double kilometersToAU(double);

View File

@ -34,7 +34,7 @@ RotationElements::RotationElements() :
Body::Body(PlanetarySystem* _system) :
orbit(NULL),
orbitFrame(astro::Equatorial),
orbitRefPlane(astro::BodyEquator),
oblateness(0),
orientation(1.0f),
// Ugh. Numeric_limits class is missing from g++
@ -97,26 +97,18 @@ void Body::setOrbit(Orbit* _orbit)
}
astro::CoordinateSystem Body::getOrbitFrame() const
astro::ReferencePlane Body::getOrbitReferencePlane() const
{
return orbitFrame;
return orbitRefPlane;
}
void Body::setOrbitFrame(astro::CoordinateSystem _orbitFrame)
void Body::setOrbitReferencePlane(astro::ReferencePlane refPlane)
{
switch (_orbitFrame)
{
case astro::Equatorial:
case astro::Ecliptical:
case astro::Geographic:
orbitFrame = _orbitFrame;
break;
default:
assert(0);
}
orbitRefPlane = refPlane;
}
float Body::getRadius() const
{
return radius;
@ -268,10 +260,24 @@ Mat4d Body::getLocalToHeliocentric(double when) const
rotationElements.precessionRate * (when - astro::J2000);
Point3d pos = orbit->positionAtTime(when);
Mat4d frame =
Mat4d::xrotation(-rotationElements.obliquity) *
Mat4d::yrotation(-ascendingNode) *
Mat4d::translation(pos);
Mat4d frame;
switch (orbitRefPlane)
{
case astro::BodyEquator:
frame = (Mat4d::xrotation(-rotationElements.obliquity) *
Mat4d::yrotation(-ascendingNode) *
Mat4d::translation(pos));
break;
case astro::Ecliptic_J2000:
frame = Mat4d::translation(pos);
break;
case astro::Equator_J2000:
frame = Mat4d::translation(pos);
break;
default:
assert(0);
}
// Recurse up the hierarchy . . .
if (system != NULL && system->getPrimaryBody() != NULL)
@ -305,7 +311,7 @@ Quatd Body::getEclipticalToEquatorial(double when) const
}
Quatd Body::getEclipticalToGeographic(double when)
Quatd Body::getEclipticalToGeographic(double when) const
{
return getEquatorialToGeographic(when) * getEclipticalToEquatorial(when);
}
@ -316,7 +322,7 @@ Quatd Body::getEclipticalToGeographic(double when)
// meridian, and z-axis at a right angle the xy plane. An object with
// constant geographic coordinates will thus remain fixed with respect
// to a point on the surface of the body.
Quatd Body::getEquatorialToGeographic(double when)
Quatd Body::getEquatorialToGeographic(double when) const
{
double t = when - rotationElements.epoch;
double rotations = t / (double) rotationElements.period;
@ -334,7 +340,7 @@ Quatd Body::getEquatorialToGeographic(double when)
}
Mat4d Body::getGeographicToHeliocentric(double when)
Mat4d Body::getGeographicToHeliocentric(double when) const
{
return getEquatorialToGeographic(when).toMatrix4() *
getLocalToHeliocentric(when);

View File

@ -112,8 +112,8 @@ class Body
void setName(const std::string);
Orbit* getOrbit() const;
void setOrbit(Orbit*);
astro::CoordinateSystem getOrbitFrame() const;
void setOrbitFrame(astro::CoordinateSystem);
astro::ReferencePlane getOrbitReferencePlane() const;
void setOrbitReferencePlane(astro::ReferencePlane);
RotationElements getRotationElements() const;
void setRotationElements(const RotationElements&);
float getRadius() const;
@ -157,10 +157,10 @@ class Body
Mat4d getLocalToHeliocentric(double) const;
Point3d getHeliocentricPosition(double) const;
Quatd getEquatorialToGeographic(double);
Quatd getEquatorialToGeographic(double) const;
Quatd getEclipticalToEquatorial(double) const;
Quatd getEclipticalToGeographic(double);
Mat4d getGeographicToHeliocentric(double);
Quatd getEclipticalToGeographic(double) const;
Mat4d getGeographicToHeliocentric(double) const;
Vec3f planetocentricToCartesian(float lon, float lat, float alt) const;
Vec3f planetocentricToCartesian(const Vec3f& lonLatAlt) const;
@ -184,7 +184,7 @@ class Body
PlanetarySystem* system;
Orbit* orbit;
astro::CoordinateSystem orbitFrame;
astro::ReferencePlane orbitRefPlane;
RotationElements rotationElements;
float radius;

View File

@ -15,6 +15,7 @@
#include <celmath/solve.h>
#include "astro.h"
#include "orbit.h"
#include "body.h"
using namespace std;
@ -390,3 +391,41 @@ void MixedOrbit::sample(double t0, double t1, int nSamples,
}
SynchronousOrbit::SynchronousOrbit(const Body& _body,
const Point3d& _position) :
body(_body),
position(_position)
{
}
SynchronousOrbit::~SynchronousOrbit()
{
}
Point3d SynchronousOrbit::positionAtTime(double jd) const
{
//Quatd q = body.getEclipticalToGeographic(jd);
Quatd q = body.getEquatorialToGeographic(jd);
return position * q.toMatrix3();
}
double SynchronousOrbit::getPeriod() const
{
return body.getRotationElements().period;
}
double SynchronousOrbit::getBoundingRadius() const
{
return position.distanceFromOrigin();
}
void SynchronousOrbit::sample(double, double, int, OrbitSampleProc&) const
{
// Empty method--we never want to show a synchronous orbit.
}

View File

@ -66,12 +66,13 @@ class OrbitSampleProc
// Custom orbit classes should be derived from CachingOrbit. The custom
// orbits can be expensive to compute, with more than 50 periodic terms.
// Celestia may need require position of a planet more than once per frame; in
// order to avoid redundant calculation, the CachingOrbit class saves the
// result of the last calculation and uses it if the time matches the cached
// time.
/*! Custom orbit classes should be derived from CachingOrbit. The custom
* orbits can be expensive to compute, with more than 50 periodic terms.
* Celestia may need require position of a planet more than once per frame; in
* order to avoid redundant calculation, the CachingOrbit class saves the
* result of the last calculation and uses it if the time matches the cached
* time.
*/
class CachingOrbit : public Orbit
{
public:
@ -91,7 +92,12 @@ private:
};
/*! A mixed orbit is a composite orbit, typically used when you have a
* custom orbit calculation that is only valid over limited span of time.
* When a mixed orbit is constructed, it computes elliptical orbits
* to approximate the behavior of the primary orbit before and after the
* span over which it is valid.
*/
class MixedOrbit : public Orbit
{
public:
@ -113,4 +119,28 @@ class MixedOrbit : public Orbit
};
class Body;
/*! An object in a synchronous orbit will always hover of the same spot on
* the surface of the body it orbits. Only equatorial orbits of a certain
* radius are stable in the real world. In Celestia, synchronous orbits are
* a convenient way to fix objects to a planet surface.
*/
class SynchronousOrbit : public Orbit
{
public:
SynchronousOrbit(const Body& _body, const Point3d& _position);
virtual ~SynchronousOrbit();
Point3d positionAtTime(double jd) const;
virtual double getPeriod() const;
virtual double getBoundingRadius() const;
virtual void sample(double, double, int, OrbitSampleProc& proc) const;
private:
const Body& body;
Point3d position;
};
#endif // _ORBIT_H_

View File

@ -351,6 +351,26 @@ static Body* CreatePlanet(PlanetarySystem* system,
}
}
}
if (orbit == NULL)
{
Vec3d longlat(0.0, 0.0, 0.0);
if (planetData->getVector("LongLat", longlat))
{
Body* parent = system->getPrimaryBody();
if (parent != NULL)
{
Vec3f pos = parent->planetocentricToCartesian((float) longlat.x, (float) longlat.y, (float) longlat.z);
Point3d posd(pos.x, pos.y, pos.z);
orbit = new SynchronousOrbit(*parent, posd);
}
else
{
// TODO: Allow fixing objects to the surface of stars.
}
}
}
if (orbit == NULL)
{
DPRINTF(0, "No valid orbit specified for object '%s'; skipping . . .\n",
@ -362,7 +382,7 @@ static Body* CreatePlanet(PlanetarySystem* system,
double radius = 10000.0;
planetData->getNumber("Radius", radius);
body->setRadius(radius);
body->setRadius((float) radius);
int classification = Body::Unknown;
string classificationName;
@ -419,17 +439,17 @@ static Body* CreatePlanet(PlanetarySystem* system,
double albedo = 0.5;
planetData->getNumber("Albedo", albedo);
body->setAlbedo(albedo);
body->setAlbedo((float) albedo);
double oblateness = 0.0;
planetData->getNumber("Oblateness", oblateness);
body->setOblateness(oblateness);
body->setOblateness((float) oblateness);
Quatf orientation;
if (planetData->getRotation("Orientation", orientation))
body->setOrientation(orientation);
body->setRotationElements(CreateRotationElements(planetData, orbit->getPeriod()));
body->setRotationElements(CreateRotationElements(planetData, (float) orbit->getPeriod()));
Surface* surface = CreateSurface(planetData, path);
body->setSurface(*surface);