448 lines
13 KiB
C++
448 lines
13 KiB
C++
// solarsys.h
|
|
//
|
|
// Copyright (C) 2001 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 "mathlib.h"
|
|
#include "astro.h"
|
|
#include "parser.h"
|
|
#include "solarsys.h"
|
|
|
|
|
|
typedef struct
|
|
{
|
|
char *name;
|
|
float radius;
|
|
float obliquity;
|
|
float albedo;
|
|
double period;
|
|
double semiMajorAxis;
|
|
double eccentricity;
|
|
double inclination;
|
|
double ascendingNode;
|
|
double argOfPeriapsis;
|
|
double trueAnomaly;
|
|
} Planet;
|
|
|
|
|
|
Planet SolSystem[] =
|
|
{
|
|
{ "Mercury", 2440, 7.0f, 0.06f,
|
|
0.2408, 0.3871, 0.2056, 7.0049, 77.456, 48.331, 252.251 },
|
|
{ "Venus", 6052, 177.4f, 0.77f,
|
|
0.6152, 0.7233, 0.0068, 3.3947, 131.533, 76.681, 181.979 },
|
|
{ "Earth", 6378, 23.45f, 0.30f,
|
|
1.0000, 1.0000, 0.0167, 0.0001, 102.947, 348.739, 100.464 },
|
|
{ "Mars", 3394, 23.98f, 0.15f,
|
|
1.8809, 1.5237, 0.0934, 1.8506, 336.041, 49.579, 355.453 },
|
|
{ "Jupiter", 71398, 3.08f, 0.51f,
|
|
11.8622, 5.2034, 0.0484, 1.3053, 14.7539, 100.556, 34.404 },
|
|
{ "Saturn", 60330, 26.73f, 0.50f,
|
|
29.4577, 9.5371, 0.0542, 2.4845, 92.432, 113.715, 49.944 },
|
|
{ "Uranus", 26200, 97.92f, 0.66f,
|
|
84.0139, 19.1913, 0.0472, 0.7699, 170.964, 74.230, 313.232 },
|
|
{ "Neptune", 25225, 28.8f, 0.62f,
|
|
164.793, 30.0690, 0.0086, 1.7692, 44.971, 131.722, 304.880 },
|
|
{ "Pluto", 1137, 122.46f, 0.6f,
|
|
248.54, 39.4817, 0.2488, 17.142, 224.067, 110.303, 238.928 },
|
|
};
|
|
|
|
|
|
static Body* createSatellite(Planet* p)
|
|
{
|
|
EllipticalOrbit* orbit = new EllipticalOrbit(astro::AUtoKilometers(p->semiMajorAxis),
|
|
p->eccentricity,
|
|
degToRad(p->inclination),
|
|
degToRad(p->ascendingNode),
|
|
degToRad(p->argOfPeriapsis),
|
|
degToRad(p->trueAnomaly),
|
|
p->period * 365.25f);
|
|
Body* body = new Body(NULL);
|
|
body->setName(string(p->name));
|
|
body->setOrbit(orbit);
|
|
body->setRadius(p->radius);
|
|
body->setObliquity(degToRad(p->obliquity));
|
|
body->setAlbedo(p->albedo);
|
|
|
|
return body;
|
|
}
|
|
|
|
|
|
// Create a solar system with our nine familiar planets
|
|
SolarSystem* CreateOurSolarSystem()
|
|
{
|
|
SolarSystem* solarSystem = new SolarSystem(0);
|
|
|
|
for (int i = 0; i < sizeof(SolSystem) / sizeof(SolSystem[0]); i++)
|
|
{
|
|
solarSystem->getPlanets()->addBody(createSatellite(&SolSystem[i]));
|
|
}
|
|
|
|
return solarSystem;
|
|
}
|
|
|
|
|
|
// Create a body (planet or moon) using the values from a hash
|
|
// The usePlanetsUnits flags specifies whether period and semi-major axis
|
|
// are in years and AU rather than days and kilometers
|
|
static Body* CreatePlanet(PlanetarySystem* system,
|
|
Hash* planetData,
|
|
bool usePlanetUnits = true)
|
|
{
|
|
Body* body = new Body(system);
|
|
|
|
string name("Unnamed");
|
|
planetData->getString("Name", name);
|
|
body->setName(name);
|
|
|
|
cout << "Reading planet " << name << "\n";
|
|
|
|
double semiMajorAxis = 0.0;
|
|
if (!planetData->getNumber("SemiMajorAxis", semiMajorAxis))
|
|
{
|
|
cout << "SemiMajorAxis missing! Skipping planet . . .\n";
|
|
delete body;
|
|
return NULL;
|
|
}
|
|
|
|
double period = 0.0;
|
|
if (!planetData->getNumber("Period", period))
|
|
{
|
|
cout << "Period missing! Skipping planet . . .\n";
|
|
delete body;
|
|
return NULL;
|
|
}
|
|
|
|
double eccentricity = 0.0;
|
|
planetData->getNumber("Eccentricity", eccentricity);
|
|
|
|
double inclination = 0.0;
|
|
planetData->getNumber("Inclination", inclination);
|
|
|
|
double ascendingNode = 0.0;
|
|
planetData->getNumber("AscendingNode", ascendingNode);
|
|
|
|
double argOfPeriapsis = 0.0;
|
|
planetData->getNumber("ArgOfPeriapsis", argOfPeriapsis);
|
|
|
|
double trueAnomaly = 0.0;
|
|
planetData->getNumber("TrueAnomaly", trueAnomaly);
|
|
|
|
if (usePlanetUnits)
|
|
{
|
|
semiMajorAxis = astro::AUtoKilometers(semiMajorAxis);
|
|
period = period * 265.25f;
|
|
}
|
|
|
|
body->setOrbit(new EllipticalOrbit(semiMajorAxis,
|
|
eccentricity,
|
|
degToRad(inclination),
|
|
degToRad(ascendingNode),
|
|
degToRad(argOfPeriapsis),
|
|
degToRad(trueAnomaly),
|
|
period));
|
|
|
|
double obliquity = 0.0;
|
|
planetData->getNumber("Obliquity", obliquity);
|
|
body->setObliquity(degToRad(obliquity));
|
|
|
|
double albedo = 0.5;
|
|
planetData->getNumber("Albedo", albedo);
|
|
body->setAlbedo(albedo);
|
|
|
|
double radius = 10000.0;
|
|
planetData->getNumber("Radius", radius);
|
|
body->setRadius(radius);
|
|
|
|
double oblateness = 0.0;
|
|
planetData->getNumber("Oblateness", oblateness);
|
|
body->setOblateness(oblateness);
|
|
|
|
// The default rotation period is the same as the orbital period
|
|
double rotationPeriod = period * 24.0;
|
|
planetData->getNumber("RotationPeriod", rotationPeriod);
|
|
body->setRotationPeriod(rotationPeriod);
|
|
|
|
Surface surface;
|
|
surface.color = Color(1.0f, 1.0f, 1.0f);
|
|
planetData->getColor("Color", surface.color);
|
|
bool applyBaseTexture = planetData->getString("Texture", surface.baseTexture);
|
|
bool applyBumpMap = planetData->getString("BumpMap", surface.bumpTexture);
|
|
bool blendTexture = false;
|
|
planetData->getBoolean("BlendTexture", blendTexture);
|
|
if (blendTexture)
|
|
surface.appearanceFlags |= Surface::BlendTexture;
|
|
if (applyBaseTexture)
|
|
surface.appearanceFlags |= Surface::ApplyBaseTexture;
|
|
if (applyBumpMap)
|
|
surface.appearanceFlags |= Surface::ApplyBumpMap;
|
|
body->setSurface(surface);
|
|
|
|
string mesh("");
|
|
planetData->getString("Mesh", mesh);
|
|
body->setMesh(mesh);
|
|
|
|
// Read the ring system
|
|
{
|
|
Value* ringsDataValue = planetData->getValue("Rings");
|
|
if (ringsDataValue != NULL)
|
|
{
|
|
if (ringsDataValue->getType() != Value::HashType)
|
|
{
|
|
cout << "ReadSolarSystem: Rings must be an assoc array.\n";
|
|
}
|
|
else
|
|
{
|
|
Hash* ringsData = ringsDataValue->getHash();
|
|
// ASSERT(ringsData != NULL);
|
|
|
|
double inner = 0.0, outer = 0.0;
|
|
ringsData->getNumber("Inner", inner);
|
|
ringsData->getNumber("Outer", outer);
|
|
|
|
Color color(1.0f, 1.0f, 1.0f);
|
|
ringsData->getColor("Color", color);
|
|
|
|
body->setRings(RingSystem((float) inner, (float) outer,
|
|
color));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read the moons
|
|
// TODO: This is largely cut-and-pasted from the ReadSolarSystem function
|
|
// It would be better if they actually used the same code
|
|
|
|
Value* moonsDataValue = planetData->getValue("Moons");
|
|
if (moonsDataValue != NULL)
|
|
{
|
|
if (moonsDataValue->getType() != Value::ArrayType)
|
|
{
|
|
cout << "ReadSolarSystem: Moons must be an array.\n";
|
|
}
|
|
else
|
|
{
|
|
Array* moonsData = moonsDataValue->getArray();
|
|
// ASSERT(moonsData != NULL);
|
|
|
|
PlanetarySystem* satellites = NULL;
|
|
if (moonsData->size() != 0)
|
|
satellites = new PlanetarySystem(body);
|
|
|
|
for (int i = 0; i < moonsData->size(); i++)
|
|
{
|
|
Value* moonValue = (*moonsData)[i];
|
|
if (moonValue != NULL &&
|
|
moonValue->getType() == Value::HashType)
|
|
{
|
|
Body* moon = CreatePlanet(satellites,
|
|
moonValue->getHash(),
|
|
false);
|
|
if (moon != NULL)
|
|
satellites->addBody(moon);
|
|
}
|
|
else
|
|
{
|
|
cout << "ReadSolarSystem: Moon data must be an assoc array.\n";
|
|
}
|
|
}
|
|
body->setSatellites(satellites);
|
|
}
|
|
}
|
|
|
|
return body;
|
|
}
|
|
|
|
|
|
static SolarSystem* ReadSolarSystem(Parser& parser,
|
|
const StarDatabase& starDB)
|
|
{
|
|
Value* starName = parser.readValue();
|
|
if (starName == NULL)
|
|
{
|
|
cout << "ReadSolarSystem: Error reading star name.\n";
|
|
return NULL;
|
|
}
|
|
|
|
if (starName->getType() != Value::StringType)
|
|
{
|
|
cout << "ReadSolarSystem: Star name is not a string.\n";
|
|
delete starName;
|
|
return NULL;
|
|
}
|
|
|
|
Value* solarSystemDataValue = parser.readValue();
|
|
if (solarSystemDataValue == NULL)
|
|
{
|
|
cout << "ReadSolarSystem: Error reading solar system data\n";
|
|
delete starName;
|
|
return NULL;
|
|
}
|
|
|
|
if (solarSystemDataValue->getType() != Value::HashType)
|
|
{
|
|
cout << "ReadSolarSystem: Solar system data must be an assoc array\n";
|
|
delete starName;
|
|
delete solarSystemDataValue;
|
|
return NULL;
|
|
}
|
|
|
|
Hash* solarSystemData = solarSystemDataValue->getHash();
|
|
// ASSERT(solarSystemData != NULL);
|
|
|
|
Star* star = starDB.find(starName->getString());
|
|
if (star == NULL)
|
|
{
|
|
cout << "Cannot find star named '" << starName->getString() << "'\n";
|
|
delete starName;
|
|
delete solarSystemDataValue;
|
|
return NULL;
|
|
}
|
|
uint32 starNumber = star->getCatalogNumber();
|
|
|
|
SolarSystem* solarSys = new SolarSystem(starNumber);
|
|
|
|
Value* planetsDataValue = solarSystemData->getValue("Planets");
|
|
if (planetsDataValue != NULL)
|
|
{
|
|
if (planetsDataValue->getType() != Value::ArrayType)
|
|
{
|
|
cout << "ReadSolarSystem: Planets must be an array.\n";
|
|
}
|
|
else
|
|
{
|
|
Array* planetsData = planetsDataValue->getArray();
|
|
// ASSERT(planetsData != NULL);
|
|
for (int i = 0; i < planetsData->size(); i++)
|
|
{
|
|
Value* planetValue = (*planetsData)[i];
|
|
if (planetValue != NULL &&
|
|
planetValue->getType() == Value::HashType)
|
|
{
|
|
Body* body = CreatePlanet(solarSys->getPlanets(),
|
|
planetValue->getHash());
|
|
if (body != NULL)
|
|
solarSys->getPlanets()->addBody(body);
|
|
}
|
|
else
|
|
{
|
|
cout << "ReadSolarSystem: Planet data must be an assoc array.\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete starName;
|
|
delete solarSystemDataValue;
|
|
|
|
return solarSys;
|
|
}
|
|
|
|
|
|
SolarSystemCatalog* ReadSolarSystemCatalog(istream& in,
|
|
StarDatabase& starDB)
|
|
{
|
|
Tokenizer tokenizer(&in);
|
|
Parser parser(&tokenizer);
|
|
|
|
SolarSystemCatalog* catalog = new SolarSystemCatalog();
|
|
|
|
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
|
|
{
|
|
tokenizer.pushBack();
|
|
SolarSystem* solarSystem = ReadSolarSystem(parser, starDB);
|
|
if (solarSystem != NULL)
|
|
{
|
|
catalog->insert(SolarSystemCatalog::value_type(solarSystem->getStarNumber(),
|
|
solarSystem));
|
|
}
|
|
}
|
|
|
|
return catalog;
|
|
}
|
|
|
|
|
|
bool ReadSolarSystems(istream& in,
|
|
const StarDatabase& starDB,
|
|
SolarSystemCatalog& catalog)
|
|
{
|
|
Tokenizer tokenizer(&in);
|
|
Parser parser(&tokenizer);
|
|
|
|
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
|
|
{
|
|
tokenizer.pushBack();
|
|
SolarSystem* solarSystem = ReadSolarSystem(parser, starDB);
|
|
if (solarSystem != NULL)
|
|
{
|
|
catalog.insert(SolarSystemCatalog::value_type(solarSystem->getStarNumber(),
|
|
solarSystem));
|
|
}
|
|
}
|
|
|
|
// TODO: Return some notification if there's an error parsring the file
|
|
return true;
|
|
}
|
|
|
|
|
|
SolarSystem::SolarSystem(uint32 _starNumber) : starNumber(_starNumber)
|
|
{
|
|
planets = new PlanetarySystem(starNumber);
|
|
}
|
|
|
|
|
|
uint32 SolarSystem::getStarNumber() const
|
|
{
|
|
return starNumber;
|
|
}
|
|
|
|
PlanetarySystem* SolarSystem::getPlanets() const
|
|
{
|
|
return planets;
|
|
}
|
|
|
|
|
|
#if 0
|
|
int SolarSystem::getSystemSize() const
|
|
{
|
|
return bodies.size();
|
|
}
|
|
|
|
Body* SolarSystem::getBody(int n) const
|
|
{
|
|
return bodies[n];
|
|
}
|
|
|
|
void SolarSystem::addBody(Body* sat)
|
|
{
|
|
bodies.insert(bodies.end(), sat);
|
|
}
|
|
|
|
|
|
Body* SolarSystem::find(string _name, bool deepSearch) const
|
|
{
|
|
for (int i = 0; i < bodies.size(); i++)
|
|
{
|
|
if (bodies[i]->getName() == _name)
|
|
{
|
|
return bodies[i];
|
|
}
|
|
else if (deepSearch && bodies[i]->getSatellites() != NULL)
|
|
{
|
|
Body* body = bodies[i]->getSatellites()->find(_name, deepSearch);
|
|
if (body != NULL)
|
|
return body;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
|