Added support for dispositions (Add, Modify, and Replace) in stc files.
parent
9915c4cb39
commit
e0eeaf5dee
|
@ -1158,6 +1158,11 @@ void Star::setLuminosity(float lum)
|
|||
absMag = astro::lumToAbsMag(lum);
|
||||
}
|
||||
|
||||
StarDetails* Star::getDetails() const
|
||||
{
|
||||
return details;
|
||||
}
|
||||
|
||||
void Star::setDetails(StarDetails* sd)
|
||||
{
|
||||
// TODO: delete existing details if they aren't shared
|
||||
|
|
|
@ -74,6 +74,7 @@ class StarDetails
|
|||
{
|
||||
KnowRadius = 0x1,
|
||||
KnowRotation = 0x2,
|
||||
KnowTexture = 0x4,
|
||||
};
|
||||
inline uint32 getKnowledge() const;
|
||||
inline bool getKnowledge(uint32) const;
|
||||
|
@ -249,6 +250,7 @@ public:
|
|||
void setAbsoluteMagnitude(float);
|
||||
void setLuminosity(float);
|
||||
|
||||
StarDetails* getDetails() const;
|
||||
void setDetails(StarDetails*);
|
||||
void setOrbitBarycenter(Star*);
|
||||
void computeOrbitalRadius();
|
||||
|
|
|
@ -178,11 +178,12 @@ bool StarDatabase::CrossIndexEntry::operator<(const StarDatabase::CrossIndexEntr
|
|||
|
||||
StarDatabase::StarDatabase():
|
||||
nStars (0),
|
||||
capacity (0),
|
||||
stars (NULL),
|
||||
namesDB (NULL),
|
||||
octreeRoot (NULL),
|
||||
nextAutoCatalogNumber(0xfffffffe)
|
||||
nextAutoCatalogNumber(0xfffffffe),
|
||||
binFileCatalogNumberIndex(NULL),
|
||||
binFileStarCount(0)
|
||||
{
|
||||
crossIndexes.resize(MaxCatalog);
|
||||
}
|
||||
|
@ -204,7 +205,7 @@ StarDatabase::~StarDatabase()
|
|||
}
|
||||
|
||||
|
||||
Star* StarDatabase::find(const uint32 catalogNumber) const
|
||||
Star* StarDatabase::find(uint32 catalogNumber) const
|
||||
{
|
||||
Star refStar;
|
||||
refStar.setCatalogNumber(catalogNumber);
|
||||
|
@ -618,6 +619,7 @@ bool StarDatabase::loadCrossIndex(const Catalog catalog, istream& in)
|
|||
|
||||
bool StarDatabase::loadOldFormatBinary(istream& in)
|
||||
{
|
||||
#if 0
|
||||
uint32 nStarsInFile = 0;
|
||||
in.read((char *) &nStarsInFile, sizeof nStarsInFile);
|
||||
LE_TO_CPU_INT32(nStarsInFile, nStarsInFile);
|
||||
|
@ -648,48 +650,48 @@ bool StarDatabase::loadOldFormatBinary(istream& in)
|
|||
|
||||
while (((unsigned int) nStars) < totalStars)
|
||||
{
|
||||
uint32 catNo = 0;
|
||||
uint32 catNo = 0;
|
||||
uint32 hdCatNo = 0;
|
||||
float RA = 0, dec = 0, parallax = 0;
|
||||
int16 appMag;
|
||||
uint16 spectralType;
|
||||
uint8 parallaxError;
|
||||
float RA = 0, dec = 0, parallax = 0;
|
||||
int16 appMag;
|
||||
uint16 spectralType;
|
||||
uint8 parallaxError;
|
||||
|
||||
in.read((char *) &catNo, sizeof catNo);
|
||||
in.read((char *) &catNo, sizeof catNo);
|
||||
LE_TO_CPU_INT32(catNo, catNo);
|
||||
in.read((char *) &hdCatNo, sizeof hdCatNo);
|
||||
LE_TO_CPU_INT32(hdCatNo, hdCatNo);
|
||||
in.read((char *) &RA, sizeof RA);
|
||||
in.read((char *) &RA, sizeof RA);
|
||||
LE_TO_CPU_FLOAT(RA, RA);
|
||||
in.read((char *) &dec, sizeof dec);
|
||||
in.read((char *) &dec, sizeof dec);
|
||||
LE_TO_CPU_FLOAT(dec, dec);
|
||||
in.read((char *) ¶llax, sizeof parallax);
|
||||
in.read((char *) ¶llax, sizeof parallax);
|
||||
LE_TO_CPU_FLOAT(parallax, parallax);
|
||||
in.read((char *) &appMag, sizeof appMag);
|
||||
in.read((char *) &appMag, sizeof appMag);
|
||||
LE_TO_CPU_INT16(appMag, appMag);
|
||||
in.read((char *) &spectralType, sizeof spectralType);
|
||||
in.read((char *) &spectralType, sizeof spectralType);
|
||||
LE_TO_CPU_INT16(spectralType, spectralType);
|
||||
in.read((char *) ¶llaxError, sizeof parallaxError);
|
||||
if ( in.bad() )
|
||||
break;
|
||||
in.read((char *) ¶llaxError, sizeof parallaxError);
|
||||
if (in.bad())
|
||||
break;
|
||||
|
||||
Star* star = &stars[nStars];
|
||||
Star* star = &stars[nStars];
|
||||
|
||||
// Compute distance based on parallax
|
||||
double distance = LY_PER_PARSEC / (parallax > 0.0 ? parallax / 1000.0 : 1e-6);
|
||||
#ifdef DEBUG
|
||||
if (distance > 50000.0)
|
||||
{
|
||||
DPRINTF(0, "Warning, distance of star # %ld of %12.2f ly seems excessive (parallax: %2.5f)!\n", catNo, distance, parallax);
|
||||
}
|
||||
#endif // DEBUG
|
||||
// Compute distance based on parallax
|
||||
double distance = LY_PER_PARSEC / (parallax > 0.0 ? parallax / 1000.0 : 1e-6);
|
||||
#ifdef DEBUG
|
||||
if (distance > 50000.0)
|
||||
{
|
||||
DPRINTF(0, "Warning, distance of star # %ld of %12.2f ly seems excessive (parallax: %2.5f)!\n", catNo, distance, parallax);
|
||||
}
|
||||
#endif // DEBUG
|
||||
Point3d pos = astro::equatorialToCelestialCart((double) RA, (double) dec, distance);
|
||||
star->setPosition(Point3f((float) pos.x, (float) pos.y, (float) pos.z));
|
||||
|
||||
// Use apparent magnitude and distance to determine the absolute
|
||||
// magnitude of the star.
|
||||
star->setAbsoluteMagnitude((float) (appMag / 256.0 + 5 -
|
||||
5 * log10(distance / 3.26)));
|
||||
// Use apparent magnitude and distance to determine the absolute
|
||||
// magnitude of the star.
|
||||
star->setAbsoluteMagnitude((float) (appMag / 256.0 + 5 -
|
||||
5 * log10(distance / 3.26)));
|
||||
|
||||
|
||||
StarDetails* details = NULL;
|
||||
|
@ -706,17 +708,17 @@ bool StarDatabase::loadOldFormatBinary(istream& in)
|
|||
star->setDetails(details);
|
||||
star->setCatalogNumber(catNo);
|
||||
|
||||
// TODO: Use a photometric estimate of distance if parallaxError is
|
||||
// greater than 25%.
|
||||
if (parallaxError > 50)
|
||||
// TODO: Use a photometric estimate of distance if parallaxError is
|
||||
// greater than 25%.
|
||||
if (parallaxError > 50)
|
||||
{
|
||||
if (appMag / 256.0 > 6)
|
||||
throwOut++;
|
||||
else
|
||||
fixUp++;
|
||||
}
|
||||
if (appMag / 256.0 > 6)
|
||||
throwOut++;
|
||||
else
|
||||
fixUp++;
|
||||
}
|
||||
|
||||
nStars++;
|
||||
nStars++;
|
||||
}
|
||||
|
||||
if (in.bad())
|
||||
|
@ -726,6 +728,9 @@ bool StarDatabase::loadOldFormatBinary(istream& in)
|
|||
cout << "nStars: " << nStars << '\n';
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -758,52 +763,33 @@ bool StarDatabase::loadBinary(istream& in)
|
|||
if (!in.good())
|
||||
return false;
|
||||
|
||||
int requiredCapacity = (int) ((nStars + nStarsInFile) * (1.0 + STAR_EXTRA_ROOM));
|
||||
if (capacity < requiredCapacity)
|
||||
{
|
||||
Star* newStars = new Star[requiredCapacity];
|
||||
if (newStars == NULL)
|
||||
return false;
|
||||
|
||||
if (stars != NULL)
|
||||
{
|
||||
copy(stars, stars + nStars, newStars);
|
||||
delete[] stars;
|
||||
}
|
||||
|
||||
stars = newStars;
|
||||
|
||||
capacity = requiredCapacity;
|
||||
}
|
||||
|
||||
unsigned int totalStars = nStars + nStarsInFile;
|
||||
|
||||
while (((unsigned int) nStars) < totalStars)
|
||||
{
|
||||
uint32 catNo = 0;
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
int16 absMag;
|
||||
uint16 spectralType;
|
||||
uint32 catNo = 0;
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
int16 absMag;
|
||||
uint16 spectralType;
|
||||
|
||||
in.read((char *) &catNo, sizeof catNo);
|
||||
in.read((char *) &catNo, sizeof catNo);
|
||||
LE_TO_CPU_INT32(catNo, catNo);
|
||||
in.read((char *) &x, sizeof x);
|
||||
in.read((char *) &x, sizeof x);
|
||||
LE_TO_CPU_FLOAT(x, x);
|
||||
in.read((char *) &y, sizeof y);
|
||||
in.read((char *) &y, sizeof y);
|
||||
LE_TO_CPU_FLOAT(y, y);
|
||||
in.read((char *) &z, sizeof z);
|
||||
in.read((char *) &z, sizeof z);
|
||||
LE_TO_CPU_FLOAT(z, z);
|
||||
in.read((char *) &absMag, sizeof absMag);
|
||||
in.read((char *) &absMag, sizeof absMag);
|
||||
LE_TO_CPU_INT16(absMag, absMag);
|
||||
in.read((char *) &spectralType, sizeof spectralType);
|
||||
in.read((char *) &spectralType, sizeof spectralType);
|
||||
LE_TO_CPU_INT16(spectralType, spectralType);
|
||||
if (in.bad())
|
||||
break;
|
||||
break;
|
||||
|
||||
Star* star = &stars[nStars];
|
||||
|
||||
star->setPosition(x, y, z);
|
||||
star->setAbsoluteMagnitude((float) absMag / 256.0f);
|
||||
Star star;
|
||||
star.setPosition(x, y, z);
|
||||
star.setAbsoluteMagnitude((float) absMag / 256.0f);
|
||||
|
||||
StarDetails* details = NULL;
|
||||
StellarClass sc;
|
||||
|
@ -816,10 +802,11 @@ bool StarDatabase::loadBinary(istream& in)
|
|||
return false;
|
||||
}
|
||||
|
||||
star->setDetails(details);
|
||||
star->setCatalogNumber(catNo);
|
||||
|
||||
nStars++;
|
||||
star.setDetails(details);
|
||||
star.setCatalogNumber(catNo);
|
||||
unsortedStars.add(star);
|
||||
|
||||
nStars++;
|
||||
}
|
||||
|
||||
if (in.bad())
|
||||
|
@ -827,29 +814,38 @@ bool StarDatabase::loadBinary(istream& in)
|
|||
|
||||
DPRINTF(0, "StarDatabase::read: nStars = %d\n", nStarsInFile);
|
||||
clog << nStars << _(" stars in binary database\n");
|
||||
|
||||
|
||||
// Create the temporary list of stars sorted by catalog number; this
|
||||
// will be used to lookup stars during file loading. After loading is
|
||||
// complete, the stars are sorted into an octree and this list gets
|
||||
// replaced.
|
||||
if (unsortedStars.size() > 0)
|
||||
{
|
||||
binFileStarCount = unsortedStars.size();
|
||||
binFileCatalogNumberIndex = new Star*[binFileStarCount];
|
||||
for (unsigned int i = 0; i < binFileStarCount; i++)
|
||||
{
|
||||
binFileCatalogNumberIndex[i] = &unsortedStars[i];
|
||||
}
|
||||
sort(binFileCatalogNumberIndex, binFileCatalogNumberIndex + binFileStarCount,
|
||||
PtrCatalogNumberOrderingPredicate());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void StarDatabase::finish()
|
||||
{
|
||||
// Eliminate duplicate stars; reverse the list so that for stars with
|
||||
// identical catalog numbers, the most recently added one is kept.
|
||||
reverse(stars, stars + nStars);
|
||||
stable_sort(stars, stars + nStars, CatalogNumberOrderingPredicate());
|
||||
Star* lastStar = unique(stars, stars + nStars,
|
||||
CatalogNumberEquivalencePredicate());
|
||||
|
||||
int nUniqueStars = lastStar - stars;
|
||||
clog << _("Total star count: ") << nUniqueStars <<
|
||||
" (" << (nStars - nUniqueStars) <<
|
||||
_(" star(s) with duplicate catalog numbers deleted.)\n");
|
||||
nStars = nUniqueStars;
|
||||
|
||||
clog << _("Total star count: ") << nStars << endl;
|
||||
|
||||
buildOctree();
|
||||
buildIndexes();
|
||||
|
||||
// Delete the temporary indices used only during loading
|
||||
delete binFileCatalogNumberIndex;
|
||||
stcFileCatalogNumberIndex.clear();
|
||||
|
||||
// Resolve all barycenters; this can't be done before star sorting. There's
|
||||
// still a bug here: final orbital radii aren't available until after
|
||||
// the barycenters have been resolved, and these are required when building
|
||||
|
@ -886,37 +882,78 @@ static void stcError(const Tokenizer& tok,
|
|||
}
|
||||
|
||||
|
||||
Star* StarDatabase::createStar(const uint32 catalogNumber,
|
||||
Hash* starData,
|
||||
const string& path,
|
||||
bool isBarycenter)
|
||||
/*! Load star data from a property list into a star instance.
|
||||
*/
|
||||
bool StarDatabase::createStar(Star* star,
|
||||
StcDisposition disposition,
|
||||
uint32 catalogNumber,
|
||||
Hash* starData,
|
||||
const string& path,
|
||||
bool isBarycenter)
|
||||
{
|
||||
StarDetails* details = NULL;
|
||||
string spectralType;
|
||||
|
||||
// Get the magnitude and spectral type; if the star is actually
|
||||
// a barycenter placeholder, these fields are ignored.
|
||||
/*double magnitude = 0.0; Unused*/
|
||||
if (isBarycenter)
|
||||
{
|
||||
details = StarDetails::GetBarycenterDetails();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!starData->getString("SpectralType", spectralType))
|
||||
if (starData->getString("SpectralType", spectralType))
|
||||
{
|
||||
cerr << _("Invalid star: missing spectral type.\n");
|
||||
return NULL;
|
||||
StellarClass sc = StellarClass::parse(spectralType);
|
||||
details = StarDetails::GetStarDetails(sc);
|
||||
if (details == NULL)
|
||||
{
|
||||
cerr << _("Invalid star: bad spectral type.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
StellarClass sc = StellarClass::parse(spectralType);
|
||||
details = StarDetails::GetStarDetails(sc);
|
||||
if (details == NULL)
|
||||
else
|
||||
{
|
||||
cerr << _("Invalid star: bad spectral type.\n");
|
||||
return NULL;
|
||||
// Spectral type is required for new stars
|
||||
if (disposition != ModifyStar)
|
||||
{
|
||||
cerr << _("Invalid star: missing spectral type.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool modifyExistingDetails = false;
|
||||
if (disposition == ModifyStar)
|
||||
{
|
||||
StarDetails* existingDetails = star->getDetails();
|
||||
|
||||
// If we're modifying and existing star and it already has a
|
||||
// customized details record, we'll just modify that.
|
||||
if (!existingDetails->shared())
|
||||
{
|
||||
modifyExistingDetails = true;
|
||||
if (details != NULL)
|
||||
{
|
||||
// If the spectral type was modified, copy the new data
|
||||
// to the custom details record.
|
||||
existingDetails->setSpectralType(details->getSpectralType());
|
||||
existingDetails->setTemperature(details->getTemperature());
|
||||
existingDetails->setBolometricCorrection(details->getBolometricCorrection());
|
||||
if ((existingDetails->getKnowledge() & StarDetails::KnowTexture) == 0)
|
||||
existingDetails->setTexture(details->getTexture());
|
||||
if ((existingDetails->getKnowledge() & StarDetails::KnowRotation) == 0)
|
||||
existingDetails->setRotationModel(details->getRotationModel());
|
||||
}
|
||||
|
||||
details = existingDetails;
|
||||
}
|
||||
else if (details == NULL)
|
||||
{
|
||||
details = existingDetails;
|
||||
}
|
||||
}
|
||||
|
||||
string modelName;
|
||||
string textureName;
|
||||
bool hasTexture = starData->getString("Texture", textureName);
|
||||
|
@ -949,10 +986,14 @@ Star* StarDatabase::createStar(const uint32 catalogNumber,
|
|||
// If the star definition has extended information, clone the
|
||||
// star details so we can customize it without affecting other
|
||||
// stars of the same spectral type.
|
||||
details = new StarDetails(*details);
|
||||
if (!modifyExistingDetails)
|
||||
details = new StarDetails(*details);
|
||||
|
||||
if (hasTexture)
|
||||
{
|
||||
details->setTexture(MultiResTexture(textureName, path));
|
||||
details->addKnowledge(StarDetails::KnowTexture);
|
||||
}
|
||||
|
||||
if (hasModel)
|
||||
{
|
||||
|
@ -1011,34 +1052,19 @@ Star* StarDatabase::createStar(const uint32 catalogNumber,
|
|||
barycenters.push_back(bc);
|
||||
|
||||
// Even though we can't actually get the Star pointer for
|
||||
// the barycenter, we can get the star information. We
|
||||
// need this in order to get the star's position. Since
|
||||
// the stars aren't sorted, we're stuck doing a linear
|
||||
// search of the currently loaded stars. But, since
|
||||
// barycenters are typically defined immediately before
|
||||
// stars that use them, a reverse linear search will have
|
||||
// very good performance most of the time.
|
||||
if (nStars > 0)
|
||||
// the barycenter, we can get the star information.
|
||||
Star* barycenter = findWhileLoading(barycenterCatNo);
|
||||
if (barycenter != NULL)
|
||||
{
|
||||
uint32 starIndex = nStars;
|
||||
do
|
||||
{
|
||||
starIndex--;
|
||||
if (stars[starIndex].getCatalogNumber() ==
|
||||
barycenterCatNo)
|
||||
{
|
||||
hasBarycenter = true;
|
||||
barycenterPosition = stars[starIndex].getPosition();
|
||||
break;
|
||||
}
|
||||
} while (starIndex != 0);
|
||||
}
|
||||
hasBarycenter = true;
|
||||
barycenterPosition = barycenter->getPosition();
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasBarycenter)
|
||||
{
|
||||
cerr << _("Barycenter ") << barycenterName << _(" does not exist.\n");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1047,9 +1073,10 @@ Star* StarDatabase::createStar(const uint32 catalogNumber,
|
|||
details->setRotationModel(rm);
|
||||
}
|
||||
|
||||
Star* star = new Star();
|
||||
star->setDetails(details);
|
||||
star->setCatalogNumber(catalogNumber);
|
||||
if (!modifyExistingDetails)
|
||||
star->setDetails(details);
|
||||
if (disposition != ModifyStar)
|
||||
star->setCatalogNumber(catalogNumber);
|
||||
|
||||
// Compute the position in rectangular coordinates. If a star has an
|
||||
// orbit and barycenter, it's position is the position of the barycenter.
|
||||
|
@ -1062,35 +1089,72 @@ Star* StarDatabase::createStar(const uint32 catalogNumber,
|
|||
double ra = 0.0;
|
||||
double dec = 0.0;
|
||||
double distance = 0.0;
|
||||
if (disposition == ModifyStar)
|
||||
{
|
||||
Point3f pos = star->getPosition();
|
||||
// Convert from Celestia's coordinate system
|
||||
Vec3f v = Vec3f(pos.x, -pos.z, pos.y);
|
||||
v = v * Mat3f::xrotation(-astro::J2000Obliquity);
|
||||
distance = v.length();
|
||||
if (distance > 0.0)
|
||||
{
|
||||
v.normalize();
|
||||
ra = radToDeg(std::atan2(v.y, v.x));
|
||||
dec = radToDeg(std::asin(v.z));
|
||||
}
|
||||
}
|
||||
|
||||
bool modifyPosition = false;
|
||||
if (!starData->getNumber("RA", ra))
|
||||
{
|
||||
cerr << _("Invalid star: missing right ascension\n");
|
||||
delete star;
|
||||
return NULL;
|
||||
if (disposition != ModifyStar)
|
||||
{
|
||||
cerr << _("Invalid star: missing right ascension\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyPosition = true;
|
||||
}
|
||||
|
||||
if (!starData->getNumber("Dec", dec))
|
||||
{
|
||||
cerr << _("Invalid star: missing declination.\n");
|
||||
delete star;
|
||||
return NULL;
|
||||
if (disposition != ModifyStar)
|
||||
{
|
||||
cerr << _("Invalid star: missing declination.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyPosition = true;
|
||||
}
|
||||
|
||||
if (!starData->getNumber("Distance", distance))
|
||||
{
|
||||
cerr << _("Invalid star: missing distance.\n");
|
||||
delete star;
|
||||
return NULL;
|
||||
if (disposition != ModifyStar)
|
||||
{
|
||||
cerr << _("Invalid star: missing distance.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyPosition = true;
|
||||
}
|
||||
|
||||
// Truncate to floats to match behavior of reading from binary file.
|
||||
// The conversion to rectangular coordinates is still performed at
|
||||
// double precision, however.
|
||||
float raf = ((float) (ra * 24.0 / 360.0));
|
||||
float decf = ((float) dec);
|
||||
float distancef = ((float) distance);
|
||||
Point3d pos = astro::equatorialToCelestialCart((double) raf, (double) decf, (double) distancef);
|
||||
star->setPosition(Point3f((float) pos.x, (float) pos.y, (float) pos.z));
|
||||
if (modifyPosition)
|
||||
{
|
||||
float raf = ((float) (ra * 24.0 / 360.0));
|
||||
float decf = ((float) dec);
|
||||
float distancef = ((float) distance);
|
||||
Point3d pos = astro::equatorialToCelestialCart((double) raf, (double) decf, (double) distancef);
|
||||
star->setPosition(Point3f((float) pos.x, (float) pos.y, (float) pos.z));
|
||||
}
|
||||
}
|
||||
|
||||
if (isBarycenter)
|
||||
|
@ -1099,14 +1163,21 @@ Star* StarDatabase::createStar(const uint32 catalogNumber,
|
|||
}
|
||||
else
|
||||
{
|
||||
double magnitude;
|
||||
double magnitude = 0.0;
|
||||
bool magnitudeModified = true;
|
||||
if (!starData->getNumber("AbsMag", magnitude))
|
||||
{
|
||||
if (!starData->getNumber("AppMag", magnitude))
|
||||
{
|
||||
clog << _("Invalid star: missing magnitude.\n");
|
||||
delete star;
|
||||
return NULL;
|
||||
if (disposition != ModifyStar)
|
||||
{
|
||||
clog << _("Invalid star: missing magnitude.\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
magnitudeModified = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1118,20 +1189,53 @@ Star* StarDatabase::createStar(const uint32 catalogNumber,
|
|||
if (distance < 1e-5f)
|
||||
{
|
||||
clog << _("Invalid star: absolute (not apparent) magnitude must be specified for star near origin\n");
|
||||
delete star;
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
magnitude = astro::appToAbsMag((float) magnitude, distance);
|
||||
}
|
||||
}
|
||||
|
||||
star->setAbsoluteMagnitude((float) magnitude);
|
||||
if (magnitudeModified)
|
||||
star->setAbsoluteMagnitude((float) magnitude);
|
||||
}
|
||||
|
||||
return star;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*! Load an STC file with star definitions. Each definition has the form:
|
||||
*
|
||||
* [disposition] [object type] [catalog number] [name]
|
||||
* {
|
||||
* [properties]
|
||||
* }
|
||||
*
|
||||
* Disposition is either Add, Replace, or Modify; Add is the default.
|
||||
* Object type is either Star or Barycenter, with Star the default
|
||||
* It is an error to omit both the catalog number and the name.
|
||||
*
|
||||
* The dispositions are slightly more complicated than suggested by
|
||||
* their names. Every star must have an unique catalog number. But
|
||||
* instead of generating an error, Adding a star with a catalog
|
||||
* number that already exists will actually replace that star. Here
|
||||
* are how all of the possibilities are handled:
|
||||
*
|
||||
* <name> or <number> already exists:
|
||||
* Add <name> : new star
|
||||
* Add <number> : replace star
|
||||
* Replace <name> : replace star
|
||||
* Replace <number> : replace star
|
||||
* Modify <name> : modify star
|
||||
* Modify <number> : modify star
|
||||
*
|
||||
* <name> or <number> doesn't exist:
|
||||
* Add <name> : new star
|
||||
* Add <number> : new star
|
||||
* Replace <name> : new star
|
||||
* Replace <number> : new star
|
||||
* Modify <name> : error
|
||||
* Modify <number> : error
|
||||
*/
|
||||
bool StarDatabase::load(istream& in, const string& resourcePath)
|
||||
{
|
||||
Tokenizer tokenizer(&in);
|
||||
|
@ -1140,6 +1244,31 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
|
||||
{
|
||||
bool isStar = true;
|
||||
|
||||
// Parse the disposition--either Add, Replace, or Modify. The disposition
|
||||
// may be omitted. The default value is Add.
|
||||
StcDisposition disposition = AddStar;
|
||||
if (tokenizer.getTokenType() == Tokenizer::TokenName)
|
||||
{
|
||||
if (tokenizer.getNameValue() == "Modify")
|
||||
{
|
||||
disposition = ModifyStar;
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
else if (tokenizer.getNameValue() == "Replace")
|
||||
{
|
||||
disposition = ReplaceStar;
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
else if (tokenizer.getNameValue() == "Add")
|
||||
{
|
||||
disposition = AddStar;
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the object type--either Star or Barycenter. The object type
|
||||
// may be omitted. The default is Star.
|
||||
if (tokenizer.getTokenType() == Tokenizer::TokenName)
|
||||
{
|
||||
if (tokenizer.getNameValue() == "Star")
|
||||
|
@ -1158,37 +1287,90 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
tokenizer.nextToken();
|
||||
}
|
||||
|
||||
bool autoGenCatalogNumber = true;
|
||||
// Parse the catalog number; it may be omitted if a name is supplied.
|
||||
uint32 catalogNumber = Star::InvalidCatalogNumber;
|
||||
if (tokenizer.getTokenType() == Tokenizer::TokenNumber)
|
||||
{
|
||||
autoGenCatalogNumber = false;
|
||||
catalogNumber = (uint32) tokenizer.getNumberValue();
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
|
||||
if (autoGenCatalogNumber)
|
||||
{
|
||||
catalogNumber = nextAutoCatalogNumber--;
|
||||
}
|
||||
|
||||
string objName;
|
||||
string firstName;
|
||||
if (tokenizer.getTokenType() == Tokenizer::TokenString)
|
||||
{
|
||||
// A star name (or names) is present
|
||||
objName = tokenizer.getStringValue();
|
||||
tokenizer.nextToken();
|
||||
if (!objName.empty())
|
||||
{
|
||||
string::size_type next = objName.find(':', 0);
|
||||
firstName = objName.substr(0, next);
|
||||
}
|
||||
}
|
||||
|
||||
Star* star = NULL;
|
||||
|
||||
switch (disposition)
|
||||
{
|
||||
case AddStar:
|
||||
// Automatically generate a catalog number for the star if one isn't
|
||||
// supplied.
|
||||
if (catalogNumber == Star::InvalidCatalogNumber)
|
||||
{
|
||||
catalogNumber = nextAutoCatalogNumber--;
|
||||
}
|
||||
else
|
||||
{
|
||||
star = findWhileLoading(catalogNumber);
|
||||
}
|
||||
break;
|
||||
|
||||
case ReplaceStar:
|
||||
if (catalogNumber == Star::InvalidCatalogNumber)
|
||||
{
|
||||
if (!firstName.empty())
|
||||
{
|
||||
catalogNumber = namesDB->findCatalogNumberByName(firstName);
|
||||
}
|
||||
}
|
||||
|
||||
if (catalogNumber == Star::InvalidCatalogNumber)
|
||||
{
|
||||
catalogNumber = nextAutoCatalogNumber--;
|
||||
}
|
||||
else
|
||||
{
|
||||
star = findWhileLoading(catalogNumber);
|
||||
}
|
||||
break;
|
||||
|
||||
case ModifyStar:
|
||||
// If no catalog number was specified, try looking up the star by name
|
||||
if (catalogNumber == Star::InvalidCatalogNumber && !firstName.empty())
|
||||
{
|
||||
catalogNumber = namesDB->findCatalogNumberByName(firstName);
|
||||
}
|
||||
|
||||
if (catalogNumber != Star::InvalidCatalogNumber)
|
||||
{
|
||||
star = findWhileLoading(catalogNumber);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bool isNewStar = star == NULL;
|
||||
|
||||
tokenizer.pushBack();
|
||||
|
||||
Value* starDataValue = parser.readValue();
|
||||
if (starDataValue == NULL)
|
||||
{
|
||||
DPRINTF(0, "Error reading star.\n");
|
||||
clog << "Error reading star." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (starDataValue->getType() != Value::HashType)
|
||||
{
|
||||
DPRINTF(0, "Bad star definition.\n");
|
||||
|
@ -1197,40 +1379,31 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
}
|
||||
Hash* starData = starDataValue->getHash();
|
||||
|
||||
Star* star = createStar(catalogNumber, starData, resourcePath, !isStar);
|
||||
if (isNewStar)
|
||||
star = new Star();
|
||||
|
||||
bool ok = false;
|
||||
if (isNewStar && disposition == ModifyStar)
|
||||
{
|
||||
clog << "Modify requested for nonexistent star." << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = createStar(star, disposition, catalogNumber, starData, resourcePath, !isStar);
|
||||
}
|
||||
delete starDataValue;
|
||||
|
||||
if (star != NULL)
|
||||
if (ok)
|
||||
{
|
||||
// Ensure that the star array is large enough
|
||||
if (nStars == capacity)
|
||||
if (isNewStar)
|
||||
{
|
||||
// Grow the array by 5%--this may be too little, but the
|
||||
// assumption here is that there will be small numbers of
|
||||
// stars in text files added to a big collection loaded from
|
||||
// a binary file.
|
||||
capacity = (int) (capacity * 1.05);
|
||||
|
||||
// 100 stars seems like a reasonable minimum
|
||||
if (capacity < 100)
|
||||
capacity = 100;
|
||||
|
||||
Star* newStars = new Star[capacity];
|
||||
if (newStars == NULL)
|
||||
{
|
||||
DPRINTF(0, "Out of memory!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stars != NULL)
|
||||
{
|
||||
copy(stars, stars + nStars, newStars);
|
||||
delete[] stars;
|
||||
}
|
||||
stars = newStars;
|
||||
unsortedStars.add(*star);
|
||||
nStars++;
|
||||
delete star;
|
||||
|
||||
// Add the new star to the temporary (load time) index.
|
||||
stcFileCatalogNumberIndex[catalogNumber] = &unsortedStars[unsortedStars.size() - 1];
|
||||
}
|
||||
stars[nStars++] = *star;
|
||||
delete star;
|
||||
|
||||
if (namesDB != NULL && !objName.empty())
|
||||
{
|
||||
|
@ -1260,6 +1433,8 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (isNewStar)
|
||||
delete star;
|
||||
DPRINTF(1, "Bad star definition--will continue parsing file.\n");
|
||||
}
|
||||
}
|
||||
|
@ -1278,10 +1453,11 @@ void StarDatabase::buildOctree()
|
|||
STAR_OCTREE_ROOT_SIZE * (float) sqrt(3.0));
|
||||
DynamicStarOctree* root = new DynamicStarOctree(Point3f(1000, 1000, 1000),
|
||||
absMag);
|
||||
for (int i=0; i<nStars; ++i)
|
||||
for (unsigned int i = 0; i < unsortedStars.size(); ++i)
|
||||
{
|
||||
root->insertObject(stars[i], STAR_OCTREE_ROOT_SIZE);
|
||||
root->insertObject(unsortedStars[i], STAR_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
|
||||
DPRINTF(1, "Spatially sorting stars for improved locality of reference . . .\n");
|
||||
Star* sortedStars = new Star[nStars];
|
||||
Star* firstStar = sortedStars;
|
||||
|
@ -1305,7 +1481,8 @@ void StarDatabase::buildOctree()
|
|||
#endif
|
||||
|
||||
// Clean up . . .
|
||||
delete[] stars;
|
||||
//delete[] stars;
|
||||
unsortedStars.clear();
|
||||
delete root;
|
||||
|
||||
stars = sortedStars;
|
||||
|
@ -1325,3 +1502,44 @@ void StarDatabase::buildIndexes()
|
|||
|
||||
sort(catalogNumberIndex, catalogNumberIndex + nStars, PtrCatalogNumberOrderingPredicate());
|
||||
}
|
||||
|
||||
|
||||
/*! While loading the star catalogs, this function must be called instead of
|
||||
* find(). The final catalog number index for stars cannot be built until
|
||||
* after all stars have been loaded. During catalog loading, there are two
|
||||
* separate indexes: one for the binary catalog and another index for stars
|
||||
* loaded from stc files. They binary catalog index is a sorted array, while
|
||||
* the stc catalog index is an STL map. Since the binary file can be quite
|
||||
* large, we want to avoid creating a map with as many nodes as there are
|
||||
* stars. Stc files should collectively contain many fewer stars, and stars
|
||||
* in an stc file may reference each other (barycenters). Thus, a dynamic
|
||||
* structure like a map is both practical and essential.
|
||||
*/
|
||||
Star* StarDatabase::findWhileLoading(uint32 catalogNumber) const
|
||||
{
|
||||
// First check for stars loaded from the binary database
|
||||
if (binFileCatalogNumberIndex != NULL)
|
||||
{
|
||||
Star refStar;
|
||||
refStar.setCatalogNumber(catalogNumber);
|
||||
|
||||
Star** star = lower_bound(binFileCatalogNumberIndex,
|
||||
binFileCatalogNumberIndex + binFileStarCount,
|
||||
&refStar,
|
||||
PtrCatalogNumberOrderingPredicate());
|
||||
|
||||
if (star != binFileCatalogNumberIndex + binFileStarCount && (*star)->getCatalogNumber() == catalogNumber)
|
||||
return *star;
|
||||
}
|
||||
|
||||
// Next check for stars loaded from an stc file
|
||||
map<uint32, Star*>::const_iterator iter = stcFileCatalogNumberIndex.find(catalogNumber);
|
||||
if (iter != stcFileCatalogNumberIndex.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
// Star not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <celengine/constellation.h>
|
||||
#include <celengine/starname.h>
|
||||
#include <celengine/star.h>
|
||||
|
@ -21,6 +22,82 @@
|
|||
|
||||
static const unsigned int MAX_STAR_NAMES = 10;
|
||||
|
||||
// TODO: Move BlockArray to celutil; consider making it a full STL
|
||||
// style container with iterator support.
|
||||
|
||||
/*! BlockArray is a container class that is similar to an STL vector
|
||||
* except for two very important differences:
|
||||
* - The elements of a BlockArray are not necessarily in one
|
||||
* contiguous block of memory.
|
||||
* - The address of a BlockArray element is guaranteed not to
|
||||
* change over the lifetime of the BlockArray (or until the
|
||||
* BlockArray is cleared.)
|
||||
*/
|
||||
template<class T> class BlockArray
|
||||
{
|
||||
public:
|
||||
BlockArray() :
|
||||
m_blockSize(1000),
|
||||
m_elementCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
~BlockArray()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
unsigned int size() const
|
||||
{
|
||||
return m_elementCount;
|
||||
}
|
||||
|
||||
/*! Append an item to the BlockArray. */
|
||||
void add(T& element)
|
||||
{
|
||||
unsigned int blockIndex = m_elementCount / m_blockSize;
|
||||
if (blockIndex == m_blocks.size())
|
||||
{
|
||||
T* newBlock = new T[m_blockSize];
|
||||
m_blocks.push_back(newBlock);
|
||||
}
|
||||
|
||||
unsigned int elementIndex = m_elementCount % m_blockSize;
|
||||
m_blocks.back()[elementIndex] = element;
|
||||
|
||||
++m_elementCount;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (typename std::vector<T*>::const_iterator iter = m_blocks.begin(); iter != m_blocks.end(); ++iter)
|
||||
{
|
||||
delete[] *iter;
|
||||
}
|
||||
m_elementCount = 0;
|
||||
m_blocks.clear();
|
||||
}
|
||||
|
||||
T& operator[](int index)
|
||||
{
|
||||
unsigned int blockNumber = index / m_blockSize;
|
||||
unsigned int elementNumber = index % m_blockSize;
|
||||
return m_blocks[blockNumber][elementNumber];
|
||||
}
|
||||
|
||||
const T& operator[](int index) const
|
||||
{
|
||||
unsigned int blockNumber = index / m_blockSize;
|
||||
unsigned int elementNumber = index % m_blockSize;
|
||||
return m_blocks[blockNumber][elementNumber];
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_blockSize;
|
||||
unsigned int m_elementCount;
|
||||
std::vector<T*> m_blocks;
|
||||
};
|
||||
|
||||
|
||||
class StarDatabase
|
||||
{
|
||||
|
@ -32,7 +109,7 @@ class StarDatabase
|
|||
inline Star* getStar(const uint32) const;
|
||||
inline uint32 size() const;
|
||||
|
||||
Star* find(const uint32 catalogNumber) const;
|
||||
Star* find(uint32 catalogNumber) const;
|
||||
Star* find(const std::string&) const;
|
||||
uint32 findCatalogNumberByName(const std::string&) const;
|
||||
|
||||
|
@ -60,11 +137,6 @@ class StarDatabase
|
|||
bool loadBinary(std::istream&);
|
||||
bool loadOldFormatBinary(std::istream&);
|
||||
|
||||
Star* createStar(const uint32 catalogNumber,
|
||||
Hash* starData,
|
||||
const std::string& path,
|
||||
const bool isBarycenter);
|
||||
|
||||
enum Catalog
|
||||
{
|
||||
HenryDraper = 0,
|
||||
|
@ -73,6 +145,13 @@ class StarDatabase
|
|||
MaxCatalog = 3,
|
||||
};
|
||||
|
||||
enum StcDisposition
|
||||
{
|
||||
AddStar,
|
||||
ReplaceStar,
|
||||
ModifyStar,
|
||||
};
|
||||
|
||||
// Not exact, but any star with a catalog number greater than this is assumed to not be
|
||||
// a HIPPARCOS stars.
|
||||
static const uint32 MAX_HIPPARCOS_NUMBER = 999999;
|
||||
|
@ -99,20 +178,36 @@ class StarDatabase
|
|||
static const char* FILE_HEADER;
|
||||
static const char* CROSSINDEX_FILE_HEADER;
|
||||
|
||||
private:
|
||||
private:
|
||||
bool createStar(Star* star,
|
||||
StcDisposition disposition,
|
||||
uint32 catalogNumber,
|
||||
Hash* starData,
|
||||
const std::string& path,
|
||||
const bool isBarycenter);
|
||||
|
||||
void buildOctree();
|
||||
void buildIndexes();
|
||||
Star* findWhileLoading(uint32 catalogNumber) const;
|
||||
|
||||
int nStars;
|
||||
int capacity;
|
||||
Star* stars;
|
||||
|
||||
Star* stars;
|
||||
StarNameDatabase* namesDB;
|
||||
Star** catalogNumberIndex;
|
||||
StarOctree* octreeRoot;
|
||||
Star** catalogNumberIndex;
|
||||
StarOctree* octreeRoot;
|
||||
uint32 nextAutoCatalogNumber;
|
||||
|
||||
std::vector<CrossIndex*> crossIndexes;
|
||||
|
||||
// These values are used by the star database loader; they are
|
||||
// not used after loading is complete.
|
||||
BlockArray<Star> unsortedStars;
|
||||
// List of stars loaded from binary file, sorted by catalog number
|
||||
Star** binFileCatalogNumberIndex;
|
||||
unsigned int binFileStarCount;
|
||||
// Catalog number -> star mapping for stars loaded from stc files
|
||||
std::map<uint32, Star*> stcFileCatalogNumberIndex;
|
||||
|
||||
struct BarycenterUsage
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue