Implemented synchronous orbits which allow easy placement of objects on the surface of planets.
parent
355fe91be1
commit
5fb0d163a6
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue