Integrated changes from Fridger and Toti's Celestia FT 1.2
parent
48849e4b32
commit
974213f905
|
@ -668,6 +668,8 @@ int parseRenderFlags(string s)
|
|||
flags |= Renderer::ShowDiagrams;
|
||||
else if (compareIgnoringCase(name, "galaxies") == 0)
|
||||
flags |= Renderer::ShowGalaxies;
|
||||
else if (compareIgnoringCase(name, "nebulae") == 0)
|
||||
flags |= Renderer::ShowNebulae;
|
||||
else if (compareIgnoringCase(name, "planets") == 0)
|
||||
flags |= Renderer::ShowPlanets;
|
||||
else if (compareIgnoringCase(name, "stars") == 0)
|
||||
|
|
|
@ -22,12 +22,15 @@
|
|||
using namespace std;
|
||||
|
||||
|
||||
const float DSO_DEFAULT_ABS_MAGNITUDE = -1000.0f;
|
||||
|
||||
|
||||
DeepSkyObject::DeepSkyObject() :
|
||||
name(""),
|
||||
catalogNumber(InvalidCatalogNumber),
|
||||
position(0, 0, 0),
|
||||
orientation(1),
|
||||
radius(1),
|
||||
absMag(30.0f),
|
||||
absMag(DSO_DEFAULT_ABS_MAGNITUDE),
|
||||
infoURL(NULL)
|
||||
{
|
||||
}
|
||||
|
@ -36,7 +39,12 @@ DeepSkyObject::~DeepSkyObject()
|
|||
{
|
||||
}
|
||||
|
||||
void DeepSkyObject::setCatalogNumber(uint32 n)
|
||||
{
|
||||
catalogNumber = n;
|
||||
}
|
||||
|
||||
/*
|
||||
string DeepSkyObject::getName() const
|
||||
{
|
||||
return name;
|
||||
|
@ -46,13 +54,14 @@ void DeepSkyObject::setName(const string& s)
|
|||
{
|
||||
name = s;
|
||||
}
|
||||
*/
|
||||
|
||||
Point3d DeepSkyObject::getPosition() const
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
void DeepSkyObject::setPosition(Point3d p)
|
||||
void DeepSkyObject::setPosition(const Point3d& p)
|
||||
{
|
||||
position = p;
|
||||
}
|
||||
|
@ -62,7 +71,7 @@ Quatf DeepSkyObject::getOrientation() const
|
|||
return orientation;
|
||||
}
|
||||
|
||||
void DeepSkyObject::setOrientation(Quatf q)
|
||||
void DeepSkyObject::setOrientation(const Quatf& q)
|
||||
{
|
||||
orientation = q;
|
||||
}
|
||||
|
@ -95,7 +104,7 @@ string DeepSkyObject::getInfoURL() const
|
|||
return *infoURL;
|
||||
}
|
||||
|
||||
void DeepSkyObject::setInfoURL(const std::string& s)
|
||||
void DeepSkyObject::setInfoURL(const string& s)
|
||||
{
|
||||
if (infoURL == NULL)
|
||||
infoURL = new string(s);
|
||||
|
@ -103,7 +112,7 @@ void DeepSkyObject::setInfoURL(const std::string& s)
|
|||
*infoURL = s;
|
||||
}
|
||||
|
||||
bool DeepSkyObject::load(AssociativeArray* params, const string&)
|
||||
bool DeepSkyObject::load(AssociativeArray* params, const string& resPath)
|
||||
{
|
||||
// Get position
|
||||
Vec3d position(0.0, 0.0, 0.0);
|
||||
|
@ -147,70 +156,3 @@ bool DeepSkyObject::load(AssociativeArray* params, const string&)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int LoadDeepSkyObjects(DeepSkyCatalog& catalog, istream& in,
|
||||
const string& path)
|
||||
{
|
||||
int count = 0;
|
||||
Tokenizer tokenizer(&in);
|
||||
Parser parser(&tokenizer);
|
||||
|
||||
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
|
||||
{
|
||||
string objType;
|
||||
string objName;
|
||||
|
||||
if (tokenizer.getTokenType() != Tokenizer::TokenName)
|
||||
{
|
||||
DPRINTF(0, "Error parsing deep sky catalog file.\n");
|
||||
break;
|
||||
}
|
||||
objType = tokenizer.getNameValue();
|
||||
|
||||
if (tokenizer.nextToken() != Tokenizer::TokenString)
|
||||
{
|
||||
DPRINTF(0, "Error parsing deep sky catalog file: bad name.\n");
|
||||
break;
|
||||
}
|
||||
objName = tokenizer.getStringValue();
|
||||
|
||||
Value* objParamsValue = parser.readValue();
|
||||
if (objParamsValue == NULL ||
|
||||
objParamsValue->getType() != Value::HashType)
|
||||
{
|
||||
DPRINTF(0, "Error parsing deep sky catalog entry %s\n",
|
||||
objName.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
Hash* objParams = objParamsValue->getHash();
|
||||
assert(objParams != NULL);
|
||||
|
||||
DeepSkyObject* obj = NULL;
|
||||
if (compareIgnoringCase(objType, "Galaxy") == 0)
|
||||
obj = new Galaxy();
|
||||
else if (compareIgnoringCase(objType, "Nebula") == 0)
|
||||
obj = new Nebula();
|
||||
else if (compareIgnoringCase(objType, "OpenCluster") == 0)
|
||||
obj = new OpenCluster();
|
||||
|
||||
if (obj != NULL)
|
||||
{
|
||||
obj->setName(objName);
|
||||
if (obj->load(objParams, path))
|
||||
{
|
||||
catalog.insert(catalog.end(), obj);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
delete objParamsValue;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <celutil/basictypes.h>
|
||||
#include <celmath/vecmath.h>
|
||||
#include <celmath/quaternion.h>
|
||||
#include <celengine/glcontext.h>
|
||||
#include <celengine/parser.h>
|
||||
|
||||
extern const float DSO_DEFAULT_ABS_MAGNITUDE;
|
||||
|
||||
class Nebula;
|
||||
class Galaxy;
|
||||
|
@ -29,14 +31,20 @@ class DeepSkyObject
|
|||
DeepSkyObject();
|
||||
virtual ~DeepSkyObject();
|
||||
|
||||
std::string getName() const;
|
||||
void setName(const std::string&);
|
||||
inline uint32 getCatalogNumber() const
|
||||
{
|
||||
return catalogNumber;
|
||||
}
|
||||
void setCatalogNumber(uint32);
|
||||
|
||||
Point3d getPosition() const;
|
||||
void setPosition(Point3d);
|
||||
void setPosition(const Point3d&);
|
||||
|
||||
virtual const char* getType() const = 0;
|
||||
virtual void setType(const std::string&) = 0;
|
||||
|
||||
Quatf getOrientation() const;
|
||||
void setOrientation(Quatf);
|
||||
void setOrientation(const Quatf&);
|
||||
|
||||
float getRadius() const;
|
||||
void setRadius(float);
|
||||
|
@ -55,15 +63,20 @@ class DeepSkyObject
|
|||
float brightness,
|
||||
float pixelSize) = 0;
|
||||
|
||||
virtual unsigned int getRenderMask() { return 0; };
|
||||
virtual unsigned int getLabelMask() { return 0; };
|
||||
virtual unsigned int getRenderMask() const { return 0; }
|
||||
virtual unsigned int getLabelMask() const { return 0; }
|
||||
|
||||
enum
|
||||
{
|
||||
InvalidCatalogNumber = 0xffffffff
|
||||
};
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
Point3d position;
|
||||
Quatf orientation;
|
||||
float radius;
|
||||
float absMag;
|
||||
uint32 catalogNumber;
|
||||
Point3d position;
|
||||
Quatf orientation;
|
||||
float radius;
|
||||
float absMag;
|
||||
std::string* infoURL;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,441 @@
|
|||
//
|
||||
// C++ Implementation: dsodb
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <celmath/mathlib.h>
|
||||
#include <celmath/plane.h>
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/bytes.h>
|
||||
#include <celutil/utf8.h>
|
||||
#include <celengine/dsodb.h>
|
||||
#include "celestia.h"
|
||||
#include "astro.h"
|
||||
#include "parser.h"
|
||||
#include "parseobject.h"
|
||||
#include "multitexture.h"
|
||||
#include "meshmanager.h"
|
||||
#include <celutil/debug.h>
|
||||
|
||||
#include <celengine/galaxy.h>
|
||||
#include <celengine/opencluster.h>
|
||||
#include <celengine/nebula.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
static const float DSO_OCTREE_ROOT_SIZE = 4.0e8f;
|
||||
static const float DSO_OCTREE_MAGNITUDE = 12.0f;
|
||||
static const float DSO_EXTRA_ROOM = 0.01f; // Reserve 1% capacity for extra DSOs
|
||||
// (useful as a complement of binary loaded DSOs)
|
||||
|
||||
const char* DSODatabase::FILE_HEADER = "CEL_DSOs";
|
||||
|
||||
// Used to sort DSO pointers by catalog number
|
||||
struct PtrCatalogNumberOrderingPredicate
|
||||
{
|
||||
int unused;
|
||||
|
||||
PtrCatalogNumberOrderingPredicate() {};
|
||||
|
||||
bool operator()(const DeepSkyObject* const & dso0, const DeepSkyObject* const & dso1) const
|
||||
{
|
||||
return (dso0->getCatalogNumber() < dso1->getCatalogNumber());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DSODatabase::DSODatabase():
|
||||
nDSOs (0),
|
||||
capacity (0),
|
||||
DSOs (NULL),
|
||||
namesDB (NULL),
|
||||
octreeRoot (NULL),
|
||||
nextAutoCatalogNumber(0xfffffffe),
|
||||
avgAbsMag (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DSODatabase::~DSODatabase()
|
||||
{
|
||||
if (DSOs != NULL)
|
||||
delete [] DSOs;
|
||||
|
||||
if (catalogNumberIndex != NULL)
|
||||
delete [] catalogNumberIndex;
|
||||
}
|
||||
|
||||
|
||||
DeepSkyObject* DSODatabase::find(const uint32 catalogNumber) const
|
||||
{
|
||||
Galaxy refDSO; //terrible hack !!
|
||||
refDSO.setCatalogNumber(catalogNumber);
|
||||
|
||||
DeepSkyObject** dso = lower_bound(catalogNumberIndex,
|
||||
catalogNumberIndex + nDSOs,
|
||||
&refDSO,
|
||||
PtrCatalogNumberOrderingPredicate());
|
||||
|
||||
if (dso != catalogNumberIndex + nDSOs && (*dso)->getCatalogNumber() == catalogNumber)
|
||||
return *dso;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
DeepSkyObject* DSODatabase::find(const string& name) const
|
||||
{
|
||||
if (name.empty())
|
||||
return NULL;
|
||||
|
||||
if (namesDB != NULL)
|
||||
{
|
||||
uint32 catalogNumber = namesDB->findCatalogNumberByName(name);
|
||||
if (catalogNumber != DeepSkyObject::InvalidCatalogNumber)
|
||||
return find(catalogNumber);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
vector<string> DSODatabase::getCompletion(const string& name) const
|
||||
{
|
||||
vector<string> completion;
|
||||
|
||||
// only named DSOs are supported by completion.
|
||||
if (!name.empty() && namesDB != NULL)
|
||||
return namesDB->getCompletion(name);
|
||||
else
|
||||
return completion;
|
||||
}
|
||||
|
||||
|
||||
string DSODatabase::getDSOName(const DeepSkyObject* const & dso) const
|
||||
{
|
||||
uint32 catalogNumber = dso->getCatalogNumber();
|
||||
|
||||
if (namesDB != NULL)
|
||||
{
|
||||
DSONameDatabase::NumberIndex::const_iterator iter = namesDB->getFirstNameIter(catalogNumber);
|
||||
if (iter != namesDB->getFinalNameIter() && iter->first == catalogNumber)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
string DSODatabase::getDSONameList(const DeepSkyObject* const & dso, const unsigned int maxNames) const
|
||||
{
|
||||
string dsoNames;
|
||||
|
||||
unsigned int catalogNumber = dso->getCatalogNumber();
|
||||
|
||||
DSONameDatabase::NumberIndex::const_iterator iter = namesDB->getFirstNameIter(catalogNumber);
|
||||
|
||||
unsigned int count = 0;
|
||||
while (iter != namesDB->getFinalNameIter() && iter->first == catalogNumber && count < maxNames)
|
||||
{
|
||||
if (count != 0)
|
||||
dsoNames += " / ";
|
||||
|
||||
dsoNames += iter->second;
|
||||
++iter;
|
||||
++count;
|
||||
}
|
||||
|
||||
return dsoNames;
|
||||
}
|
||||
|
||||
|
||||
void DSODatabase::findVisibleDSOs(DSOHandler& dsoHandler,
|
||||
const Point3d& obsPos,
|
||||
const Quatf& obsOrient,
|
||||
float fovY,
|
||||
float aspectRatio,
|
||||
float limitingMag) const
|
||||
{
|
||||
// Compute the bounding planes of an infinite view frustum
|
||||
Planef frustumPlanes[5];
|
||||
Vec3f planeNormals[5];
|
||||
|
||||
Mat3f rot = obsOrient.toMatrix3();
|
||||
float h = (float) tan(fovY / 2);
|
||||
float w = h * aspectRatio;
|
||||
|
||||
planeNormals[0] = Vec3f(0, 1, -h);
|
||||
planeNormals[1] = Vec3f(0, -1, -h);
|
||||
planeNormals[2] = Vec3f(1, 0, -w);
|
||||
planeNormals[3] = Vec3f(-1, 0, -w);
|
||||
planeNormals[4] = Vec3f(0, 0, -1);
|
||||
|
||||
for (int i=0; i<5; ++i)
|
||||
{
|
||||
planeNormals[i].normalize(); //TODO: prenormalize ?
|
||||
planeNormals[i] = planeNormals[i] * rot;
|
||||
frustumPlanes[i] = Planef(planeNormals[i], Point3f((float) obsPos.x, (float) obsPos.y, (float) obsPos.z) );
|
||||
}
|
||||
|
||||
octreeRoot->processVisibleObjects(dsoHandler,
|
||||
obsPos,
|
||||
frustumPlanes,
|
||||
limitingMag,
|
||||
DSO_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
|
||||
|
||||
void DSODatabase::findCloseDSOs(DSOHandler& dsoHandler,
|
||||
const Point3d& obsPos,
|
||||
float radius) const
|
||||
{
|
||||
octreeRoot->processCloseObjects(dsoHandler,
|
||||
obsPos,
|
||||
radius,
|
||||
DSO_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
|
||||
|
||||
DSONameDatabase* DSODatabase::getNameDatabase() const
|
||||
{
|
||||
return namesDB;
|
||||
}
|
||||
|
||||
|
||||
void DSODatabase::setNameDatabase(DSONameDatabase* _namesDB)
|
||||
{
|
||||
namesDB = _namesDB;
|
||||
}
|
||||
|
||||
|
||||
bool DSODatabase::load(istream& in, const string& resourcePath)
|
||||
{
|
||||
Tokenizer tokenizer(&in);
|
||||
Parser parser(&tokenizer);
|
||||
|
||||
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
|
||||
{
|
||||
string objType;
|
||||
string objName;
|
||||
|
||||
if (tokenizer.getTokenType() != Tokenizer::TokenName)
|
||||
{
|
||||
DPRINTF(0, "Error parsing deep sky catalog file.\n");
|
||||
return false;
|
||||
}
|
||||
objType = tokenizer.getNameValue();
|
||||
|
||||
bool autoGenCatalogNumber = true;
|
||||
uint32 objCatalogNumber = DeepSkyObject::InvalidCatalogNumber;
|
||||
if (tokenizer.getTokenType() == Tokenizer::TokenNumber)
|
||||
{
|
||||
autoGenCatalogNumber = false;
|
||||
objCatalogNumber = (uint32) tokenizer.getNumberValue();
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
|
||||
if (autoGenCatalogNumber)
|
||||
{
|
||||
objCatalogNumber = nextAutoCatalogNumber--;
|
||||
}
|
||||
|
||||
if (tokenizer.nextToken() != Tokenizer::TokenString)
|
||||
{
|
||||
DPRINTF(0, "Error parsing deep sky catalog file: bad name.\n");
|
||||
return false;
|
||||
}
|
||||
objName = tokenizer.getStringValue();
|
||||
|
||||
Value* objParamsValue = parser.readValue();
|
||||
if (objParamsValue == NULL ||
|
||||
objParamsValue->getType() != Value::HashType)
|
||||
{
|
||||
DPRINTF(0, "Error parsing deep sky catalog entry %s\n", objName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
Hash* objParams = objParamsValue->getHash();
|
||||
assert(objParams != NULL);
|
||||
|
||||
DeepSkyObject* obj = NULL;
|
||||
if (compareIgnoringCase(objType, "Galaxy") == 0)
|
||||
obj = new Galaxy();
|
||||
else if (compareIgnoringCase(objType, "Nebula") == 0)
|
||||
obj = new Nebula();
|
||||
else if (compareIgnoringCase(objType, "OpenCluster") == 0)
|
||||
obj = new OpenCluster();
|
||||
|
||||
|
||||
if (obj != NULL && obj->load(objParams, resourcePath))
|
||||
{
|
||||
// Ensure that the DSO array is large enough
|
||||
if (nDSOs == capacity)
|
||||
{
|
||||
// Grow the array by 5%--this may be too little, but the
|
||||
// assumption here is that there will be small numbers of
|
||||
// DSOs in text files added to a big collection loaded from
|
||||
// a binary file.
|
||||
capacity = (int) (capacity * 1.05);
|
||||
|
||||
// 100 DSOs seems like a reasonable minimum
|
||||
if (capacity < 100)
|
||||
capacity = 100;
|
||||
|
||||
DeepSkyObject** newDSOs = new DeepSkyObject*[capacity];
|
||||
if (newDSOs == NULL)
|
||||
{
|
||||
DPRINTF(0, "Out of memory!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DSOs != NULL)
|
||||
{
|
||||
copy(DSOs, DSOs + nDSOs, newDSOs);
|
||||
delete[] DSOs;
|
||||
}
|
||||
DSOs = newDSOs;
|
||||
}
|
||||
|
||||
DSOs[nDSOs++] = obj;
|
||||
|
||||
obj->setCatalogNumber(objCatalogNumber);
|
||||
|
||||
if (namesDB != NULL && !objName.empty())
|
||||
{
|
||||
// List of names will replace any that already exist for
|
||||
// this DSO.
|
||||
namesDB->erase(objCatalogNumber);
|
||||
|
||||
// Iterate through the string for names delimited
|
||||
// by ':', and insert them into the DSO database.
|
||||
// Note that db->add() will skip empty names.
|
||||
string::size_type startPos = 0;
|
||||
while (startPos != string::npos)
|
||||
{
|
||||
string::size_type next = objName.find(':', startPos);
|
||||
string::size_type length = string::npos;
|
||||
if (next != string::npos)
|
||||
{
|
||||
length = next - startPos;
|
||||
++next;
|
||||
}
|
||||
namesDB->add(objCatalogNumber, objName.substr(startPos, length));
|
||||
startPos = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINTF(1, "Bad Deep Sky Object definition--will continue parsing file.\n");
|
||||
if (objParamsValue != NULL)
|
||||
delete objParamsValue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DSODatabase::loadBinary(istream& in)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DSODatabase::finish()
|
||||
{
|
||||
buildOctree();
|
||||
buildIndexes();
|
||||
calcAvgAbsMag();
|
||||
/*
|
||||
// Put AbsMag = avgAbsMag for Add-ons without AbsMag entry
|
||||
for (int i = 0; i < nDSOs; ++i)
|
||||
{
|
||||
if(DSOs[i]->getAbsoluteMagnitude() == DSO_DEFAULT_ABS_MAGNITUDE)
|
||||
DSOs[i]->setAbsoluteMagnitude((float)avgAbsMag);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void DSODatabase::buildOctree()
|
||||
{
|
||||
DPRINTF(1, "Sorting DSOs into octree . . .\n");
|
||||
float absMag = astro::appToAbsMag(DSO_OCTREE_MAGNITUDE, DSO_OCTREE_ROOT_SIZE * (float) sqrt(3.0));
|
||||
DynamicDSOOctree* root = new DynamicDSOOctree(Point3d(1000, 1000, 1000), absMag); //TODO: center??
|
||||
for (int i = 0; i < nDSOs; ++i)
|
||||
{
|
||||
root->insertObject(DSOs[i], DSO_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
|
||||
DPRINTF(1, "Spatially sorting DSOs for improved locality of reference . . .\n");
|
||||
DeepSkyObject** sortedDSOs = new DeepSkyObject*[nDSOs];
|
||||
DeepSkyObject** firstDSO = sortedDSOs;
|
||||
root->rebuildAndSort(octreeRoot, firstDSO);
|
||||
|
||||
DPRINTF(1, "%d DSOs total\n", (int) (firstDSO - sortedDSOs));
|
||||
DPRINTF(1, "Octree has %d nodes and %d DSOs.\n",
|
||||
1 + octreeRoot->countChildren(), octreeRoot->countObjects());
|
||||
//cout<<"DSOs: "<< octreeRoot->countObjects()<<" Nodes:"
|
||||
// <<octreeRoot->countChildren() <<endl;
|
||||
// Clean up . . .
|
||||
delete[] DSOs;
|
||||
delete root;
|
||||
|
||||
DSOs = sortedDSOs;
|
||||
}
|
||||
|
||||
void DSODatabase::calcAvgAbsMag()
|
||||
{
|
||||
uint32 nDSOeff = size();
|
||||
for (int i = 0; i < nDSOs; ++i)
|
||||
{
|
||||
double DSOmag = DSOs[i]->getAbsoluteMagnitude();
|
||||
|
||||
// take only DSO's with realistic AbsMag entry
|
||||
// (> DSO_DEFAULT_ABS_MAGNITUDE) into account
|
||||
if (DSOmag > DSO_DEFAULT_ABS_MAGNITUDE)
|
||||
avgAbsMag += DSOmag;
|
||||
else if (nDSOeff > 1)
|
||||
nDSOeff--;
|
||||
//cout << nDSOs<<" "<<DSOmag<<" "<<nDSOeff<<endl;
|
||||
}
|
||||
avgAbsMag /= (double) nDSOeff;
|
||||
//cout<<avgAbsMag<<endl;
|
||||
}
|
||||
|
||||
|
||||
void DSODatabase::buildIndexes()
|
||||
{
|
||||
// This should only be called once for the database
|
||||
// assert(catalogNumberIndexes[0] == NULL);
|
||||
|
||||
DPRINTF(1, "Building catalog number indexes . . .\n");
|
||||
|
||||
catalogNumberIndex = new DeepSkyObject*[nDSOs];
|
||||
for (int i = 0; i < nDSOs; ++i)
|
||||
catalogNumberIndex[i] = DSOs[i];
|
||||
|
||||
sort(catalogNumberIndex, catalogNumberIndex + nDSOs, PtrCatalogNumberOrderingPredicate());
|
||||
}
|
||||
|
||||
|
||||
double DSODatabase::getAverageAbsoluteMagnitude() const
|
||||
{
|
||||
return avgAbsMag;
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// C++ Interface: dsodb
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _DSODB_H_
|
||||
#define _DSODB_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <celengine/dsoname.h>
|
||||
#include <celengine/deepskyobj.h>
|
||||
#include <celengine/dsooctree.h>
|
||||
#include <celengine/parser.h>
|
||||
|
||||
|
||||
static const unsigned int MAX_DSO_NAMES = 10;
|
||||
|
||||
//NOTE: this one and starDatabase should be derived from a common base class since they share lots of code and functionality.
|
||||
class DSODatabase
|
||||
{
|
||||
public:
|
||||
DSODatabase();
|
||||
~DSODatabase();
|
||||
|
||||
|
||||
inline DeepSkyObject* getDSO(const uint32) const;
|
||||
inline uint32 size() const;
|
||||
|
||||
DeepSkyObject* find(const uint32 catalogNumber) const;
|
||||
DeepSkyObject* find(const std::string&) const;
|
||||
|
||||
std::vector<std::string> getCompletion(const std::string&) const;
|
||||
|
||||
void findVisibleDSOs(DSOHandler& dsoHandler,
|
||||
const Point3d& obsPosition,
|
||||
const Quatf& obsOrientation,
|
||||
float fovY,
|
||||
float aspectRatio,
|
||||
float limitingMag) const;
|
||||
|
||||
void findCloseDSOs(DSOHandler& dsoHandler,
|
||||
const Point3d& obsPosition,
|
||||
float radius) const;
|
||||
|
||||
std::string getDSOName (const DeepSkyObject* const &) const;
|
||||
std::string getDSONameList(const DeepSkyObject* const &, const unsigned int maxNames = MAX_DSO_NAMES) const;
|
||||
|
||||
DSONameDatabase* getNameDatabase() const;
|
||||
void setNameDatabase(DSONameDatabase*);
|
||||
|
||||
bool load(std::istream&, const std::string& resourcePath);
|
||||
bool loadBinary(std::istream&);
|
||||
void finish();
|
||||
|
||||
static DSODatabase* read(std::istream&);
|
||||
|
||||
static const char* FILE_HEADER;
|
||||
|
||||
double getAverageAbsoluteMagnitude() const;
|
||||
|
||||
private:
|
||||
void buildIndexes();
|
||||
void buildOctree();
|
||||
void calcAvgAbsMag();
|
||||
|
||||
int nDSOs;
|
||||
int capacity;
|
||||
DeepSkyObject** DSOs;
|
||||
DSONameDatabase* namesDB;
|
||||
DeepSkyObject** catalogNumberIndex;
|
||||
DSOOctree* octreeRoot;
|
||||
uint32 nextAutoCatalogNumber;
|
||||
|
||||
double avgAbsMag;
|
||||
};
|
||||
|
||||
|
||||
DeepSkyObject* DSODatabase::getDSO(const uint32 n) const
|
||||
{
|
||||
return *(DSOs + n);
|
||||
}
|
||||
|
||||
|
||||
uint32 DSODatabase::size() const
|
||||
{
|
||||
return nDSOs;
|
||||
}
|
||||
|
||||
#endif // _DSODB_H_
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// C++ Implementation: dsoname
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#include <celengine/dsoname.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//NOTE: this could be expanded in the near future, so we place it here:
|
||||
uint32 DSONameDatabase::findCatalogNumberByName(const string& name) const
|
||||
{
|
||||
return getCatalogNumberByName(name);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// C++ Interface: dsoname
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _DSONAME_H_
|
||||
#define _DSONAME_H_
|
||||
|
||||
#include <celengine/name.h>
|
||||
#include <celengine/deepskyobj.h>
|
||||
|
||||
|
||||
class DSONameDatabase: public NameDatabase<DeepSkyObject>
|
||||
{
|
||||
public:
|
||||
DSONameDatabase() {};
|
||||
|
||||
|
||||
uint32 findCatalogNumberByName(const std::string&) const;
|
||||
};
|
||||
|
||||
#endif // _DSONAME_H_
|
|
@ -0,0 +1,176 @@
|
|||
//
|
||||
// C++ Implementation: dsooctree
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#include <celengine/dsooctree.h>
|
||||
|
||||
// The octree node into which a dso is placed is dependent on two properties:
|
||||
// its obsPosition and its luminosity--the fainter the dso, the deeper the node
|
||||
// in which it will reside. Each node stores an absolute magnitude; no child
|
||||
// of the node is allowed contain a dso brighter than this value, making it
|
||||
// possible to determine quickly whether or not to cull subtrees.
|
||||
|
||||
bool dsoAbsoluteMagnitudePredicate(DeepSkyObject* const & _dso, const float absMag)
|
||||
{
|
||||
return _dso->getAbsoluteMagnitude() <= absMag;
|
||||
}
|
||||
|
||||
|
||||
bool dsoStraddlesNodesPredicate(const Point3d& cellCenterPos, DeepSkyObject* const & _dso, const float absMag)
|
||||
{
|
||||
//checks if this dso's radius straddles child nodes
|
||||
float dsoRadius = _dso->getRadius();
|
||||
|
||||
Point3d dsoPos = _dso->getPosition();
|
||||
|
||||
return abs(dsoPos.x - cellCenterPos.x) < dsoRadius ||
|
||||
abs(dsoPos.y - cellCenterPos.y) < dsoRadius ||
|
||||
abs(dsoPos.z - cellCenterPos.z) < dsoRadius;
|
||||
}
|
||||
|
||||
|
||||
double dsoAbsoluteMagnitudeDecayFunction(const double excludingFactor)
|
||||
{
|
||||
return excludingFactor + 0.5f;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
DynamicDSOOctree* DynamicDSOOctree::getChild(DeepSkyObject* const & _obj, const Point3d& cellCenterPos)
|
||||
{
|
||||
Point3d objPos = _obj->getPosition();
|
||||
|
||||
int child = 0;
|
||||
child |= objPos.x < cellCenterPos.x ? 0 : XPos;
|
||||
child |= objPos.y < cellCenterPos.y ? 0 : YPos;
|
||||
child |= objPos.z < cellCenterPos.z ? 0 : ZPos;
|
||||
|
||||
return _children[child];
|
||||
}
|
||||
|
||||
|
||||
template<> unsigned int DynamicDSOOctree::SPLIT_THRESHOLD = 10;
|
||||
template<> DynamicDSOOctree::LimitingFactorPredicate*
|
||||
DynamicDSOOctree::limitingFactorPredicate = dsoAbsoluteMagnitudePredicate;
|
||||
template<> DynamicDSOOctree::StraddlingPredicate*
|
||||
DynamicDSOOctree::straddlingPredicate = dsoStraddlesNodesPredicate;
|
||||
template<> DynamicDSOOctree::ExclusionFactorDecayFunction*
|
||||
DynamicDSOOctree::decayFunction = dsoAbsoluteMagnitudeDecayFunction;
|
||||
|
||||
|
||||
// total specialization of the StaticOctree template process*() methods for DSOs:
|
||||
template<>
|
||||
void DSOOctree::processVisibleObjects(DSOHandler& processor,
|
||||
const Point3d& obsPosition,
|
||||
const Planef* frustumPlanes,
|
||||
float limitingFactor,
|
||||
double scale) const
|
||||
{
|
||||
// See if this node lies within the view frustum
|
||||
|
||||
// Test the cubic octree node against each one of the five
|
||||
// planes that define the infinite view frustum.
|
||||
for (int i=0; i<5; ++i)
|
||||
{
|
||||
const Planef* plane = frustumPlanes + i;
|
||||
double r = scale * (abs(plane->normal.x) +
|
||||
abs(plane->normal.y) +
|
||||
abs(plane->normal.z));
|
||||
|
||||
Vec3d vecDbl((double) plane->normal.x, (double) plane->normal.y, (double) plane->normal.z);
|
||||
|
||||
if (vecDbl * Vec3d(cellCenterPos.x, cellCenterPos.y, cellCenterPos.z) - plane->d < -r)
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the distance to node; this is equal to the distance to
|
||||
// the cellCenterPos of the node minus the boundingRadius of the node, scale * SQRT3.
|
||||
double minDistance = (obsPosition - cellCenterPos).length() - scale * DSOOctree::SQRT3;
|
||||
|
||||
// Process the objects in this node
|
||||
double dimmest = minDistance > 0 ? astro::appToAbsMag(limitingFactor, minDistance) : 1000;
|
||||
|
||||
for (unsigned int i=0; i<nObjects; ++i)
|
||||
{
|
||||
DeepSkyObject* _obj = _firstObject[i];
|
||||
float absMag = _obj->getAbsoluteMagnitude();
|
||||
if ( absMag < dimmest)
|
||||
{
|
||||
double distance = obsPosition.distanceTo(_obj->getPosition()) - _obj->getRadius();
|
||||
float appMag = (distance >= 32.6167)? astro::absToAppMag(absMag, distance): absMag;
|
||||
|
||||
if ( appMag < limitingFactor)
|
||||
processor.process(_obj, distance, absMag);
|
||||
}
|
||||
}
|
||||
|
||||
// See if any of the objects in child nodes are potentially included
|
||||
// that we need to recurse deeper.
|
||||
if (minDistance <= 0 || astro::absToAppMag(exclusionFactor, minDistance) <= limitingFactor)
|
||||
// Recurse into the child nodes
|
||||
if (_children != NULL)
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
_children[i]->processVisibleObjects(processor,
|
||||
obsPosition,
|
||||
frustumPlanes,
|
||||
limitingFactor,
|
||||
scale * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void DSOOctree::processCloseObjects(DSOHandler& processor,
|
||||
const Point3d& obsPosition,
|
||||
double boundingRadius,
|
||||
double scale) const
|
||||
{
|
||||
// Compute the distance to node; this is equal to the distance to
|
||||
// the cellCenterPos of the node minus the boundingRadius of the node, scale * SQRT3.
|
||||
double nodeDistance = (obsPosition - cellCenterPos).length() - scale * DSOOctree::SQRT3; //
|
||||
|
||||
if (nodeDistance > boundingRadius)
|
||||
return;
|
||||
|
||||
// At this point, we've determined that the cellCenterPos of the node is
|
||||
// close enough that we must check individual objects for proximity.
|
||||
|
||||
// Compute distance squared to avoid having to sqrt for distance
|
||||
// comparison.
|
||||
double radiusSquared = boundingRadius * boundingRadius; //
|
||||
|
||||
// Check all the objects in the node.
|
||||
for (unsigned int i=0; i<nObjects; ++i)
|
||||
{
|
||||
DeepSkyObject* _obj = _firstObject[i]; //
|
||||
|
||||
if (obsPosition.distanceToSquared(_obj->getPosition()) < radiusSquared) //
|
||||
{
|
||||
float absMag = _obj->getAbsoluteMagnitude();
|
||||
double distance = obsPosition.distanceTo(_obj->getPosition()) - _obj->getRadius();
|
||||
|
||||
processor.process(_obj, distance, absMag);
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into the child nodes
|
||||
if (_children != NULL)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
_children[i]->processCloseObjects(processor,
|
||||
obsPosition,
|
||||
boundingRadius,
|
||||
scale * 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// C++ Interface: dsooctree
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _DSOOCTREE_H_
|
||||
#define _DSOOCTREE_H_
|
||||
|
||||
#include <celengine/deepskyobj.h>
|
||||
#include <celengine/octree.h>
|
||||
|
||||
|
||||
typedef DynamicOctree <DeepSkyObject*, double> DynamicDSOOctree;
|
||||
typedef StaticOctree <DeepSkyObject*, double> DSOOctree;
|
||||
typedef OctreeProcessor<DeepSkyObject*, double> DSOHandler;
|
||||
|
||||
#endif // _DSOOCTREE_H_
|
|
@ -31,6 +31,9 @@ OBJS=\
|
|||
$(INTDIR)\dds.obj \
|
||||
$(INTDIR)\deepskyobj.obj \
|
||||
$(INTDIR)\dispmap.obj \
|
||||
$(INTDIR)\dsodb.obj \
|
||||
$(INTDIR)\dsoname.obj \
|
||||
$(INTDIR)\dsooctree.obj \
|
||||
$(INTDIR)\execution.obj \
|
||||
$(INTDIR)\fragmentprog.obj \
|
||||
$(INTDIR)\frame.obj \
|
||||
|
@ -50,7 +53,6 @@ OBJS=\
|
|||
$(INTDIR)\multitexture.obj \
|
||||
$(INTDIR)\nebula.obj \
|
||||
$(INTDIR)\observer.obj \
|
||||
$(INTDIR)\octree.obj \
|
||||
$(INTDIR)\opencluster.obj \
|
||||
$(INTDIR)\orbit.obj \
|
||||
$(INTDIR)\overlay.obj \
|
||||
|
@ -69,6 +71,7 @@ OBJS=\
|
|||
$(INTDIR)\starcolors.obj \
|
||||
$(INTDIR)\stardb.obj \
|
||||
$(INTDIR)\starname.obj \
|
||||
$(INTDIR)\staroctree.obj \
|
||||
$(INTDIR)\stellarclass.obj \
|
||||
$(INTDIR)\texmanager.obj \
|
||||
$(INTDIR)\texture.obj \
|
||||
|
|
|
@ -27,7 +27,7 @@ using namespace std;
|
|||
|
||||
static Color colorTable[256];
|
||||
|
||||
static const unsigned int GALAXY_POINTS = 5000;
|
||||
static const unsigned int GALAXY_POINTS = 7000;
|
||||
|
||||
static bool formsInitialized = false;
|
||||
|
||||
|
@ -42,30 +42,29 @@ static void InitializeForms();
|
|||
float Galaxy::lightGain = 0.0f;
|
||||
|
||||
|
||||
struct GalaxyTypeName
|
||||
struct GalaxyTypeName
|
||||
{
|
||||
const char* name;
|
||||
Galaxy::GalaxyType type;
|
||||
};
|
||||
|
||||
|
||||
static GalaxyTypeName GalaxyTypeNames[] =
|
||||
{
|
||||
{ "S0", Galaxy::S0 },
|
||||
{ "Sa", Galaxy::Sa },
|
||||
{ "Sb", Galaxy::Sb },
|
||||
{ "Sc", Galaxy::Sc },
|
||||
{ "S0", Galaxy::S0 },
|
||||
{ "Sa", Galaxy::Sa },
|
||||
{ "Sb", Galaxy::Sb },
|
||||
{ "Sc", Galaxy::Sc },
|
||||
{ "SBa", Galaxy::SBa },
|
||||
{ "SBb", Galaxy::SBb },
|
||||
{ "SBc", Galaxy::SBc },
|
||||
{ "E0", Galaxy::E0 },
|
||||
{ "E1", Galaxy::E1 },
|
||||
{ "E2", Galaxy::E2 },
|
||||
{ "E3", Galaxy::E3 },
|
||||
{ "E4", Galaxy::E4 },
|
||||
{ "E5", Galaxy::E5 },
|
||||
{ "E6", Galaxy::E6 },
|
||||
{ "E7", Galaxy::E7 },
|
||||
{ "E0", Galaxy::E0 },
|
||||
{ "E1", Galaxy::E1 },
|
||||
{ "E2", Galaxy::E2 },
|
||||
{ "E3", Galaxy::E3 },
|
||||
{ "E4", Galaxy::E4 },
|
||||
{ "E5", Galaxy::E5 },
|
||||
{ "E6", Galaxy::E6 },
|
||||
{ "E7", Galaxy::E7 },
|
||||
{ "Irr", Galaxy::Irr },
|
||||
};
|
||||
|
||||
|
@ -104,14 +103,22 @@ void Galaxy::setDetail(float d)
|
|||
}
|
||||
|
||||
|
||||
Galaxy::GalaxyType Galaxy::getType() const
|
||||
const char* Galaxy::getType() const
|
||||
{
|
||||
return type;
|
||||
return GalaxyTypeNames[(int) type].name;
|
||||
}
|
||||
|
||||
void Galaxy::setType(Galaxy::GalaxyType _type)
|
||||
void Galaxy::setType(const std::string& typeStr)
|
||||
{
|
||||
type = _type;
|
||||
type = Galaxy::Irr;
|
||||
for (int i = 0; i < (int) (sizeof(GalaxyTypeNames) / sizeof(GalaxyTypeNames[0])); ++i)
|
||||
{
|
||||
if (GalaxyTypeNames[i].name == typeStr)
|
||||
{
|
||||
type = GalaxyTypeNames[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!formsInitialized)
|
||||
InitializeForms();
|
||||
|
@ -158,16 +165,7 @@ bool Galaxy::load(AssociativeArray* params, const string& resPath)
|
|||
|
||||
string typeName;
|
||||
params->getString("Type", typeName);
|
||||
Galaxy::GalaxyType type = Galaxy::Irr;
|
||||
for (int i = 0; i < (int) (sizeof(GalaxyTypeNames) / sizeof(GalaxyTypeNames[0])); ++i)
|
||||
{
|
||||
if (GalaxyTypeNames[i].name == typeName)
|
||||
{
|
||||
type = GalaxyTypeNames[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setType(type);
|
||||
setType(typeName);
|
||||
|
||||
return DeepSkyObject::load(params, resPath);
|
||||
}
|
||||
|
@ -211,26 +209,61 @@ void Galaxy::renderGalaxyPointSprites(const GLContext& context,
|
|||
Vec3f v2 = Vec3f( 1, 1, 0) * viewMat;
|
||||
Vec3f v3 = Vec3f(-1, 1, 0) * viewMat;
|
||||
|
||||
float distanceToObject = offset.length() - getRadius();
|
||||
if (distanceToObject < 0)
|
||||
distanceToObject = 0;
|
||||
float minimumFeatureSize = pixelSize * 0.5f * distanceToObject;
|
||||
float distanceToDSO = offset.length() - getRadius();
|
||||
if (distanceToDSO < 0)
|
||||
distanceToDSO = 0;
|
||||
|
||||
float minimumFeatureSize = pixelSize * distanceToDSO;
|
||||
|
||||
//Mat4f m = (getOrientation().toMatrix4() *
|
||||
// Mat4f::scaling(form->scale) *
|
||||
// Mat4f::scaling(getRadius()));
|
||||
|
||||
float size = 2 * getRadius();
|
||||
Mat3f m =
|
||||
Mat3f::scaling(form->scale)*getOrientation().toMatrix3()*Mat3f::scaling(size);
|
||||
|
||||
// Note: fixed missing factor of 2 in getRadius() scaling of galaxy diameter!
|
||||
// Note: fixed correct ordering of (non-commuting) operations!
|
||||
|
||||
Mat4f m = (getOrientation().toMatrix4() *
|
||||
Mat4f::scaling(form->scale) *
|
||||
Mat4f::scaling(getRadius()));
|
||||
float size = getRadius() * 1.25f;
|
||||
int pow2 = 1;
|
||||
|
||||
vector<Blob>* points = form->blobs;
|
||||
unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail()));
|
||||
|
||||
// corrections to avoid excessive brightening if viewed e.g. edge-on
|
||||
|
||||
float brightness_corr = 1.0f;
|
||||
float cosi;
|
||||
|
||||
if (type < E0 || type > E3) //all galaxies, except ~round elliptics
|
||||
{
|
||||
cosi = Vec3f(0,1,0) * getOrientation().toMatrix3()
|
||||
* offset/offset.length();
|
||||
brightness_corr = (float) sqrt(abs(cosi));
|
||||
if (brightness_corr < 0.2f)
|
||||
brightness_corr = 0.2f;
|
||||
}
|
||||
|
||||
if (type > E3) // only elliptics with higher ellipticities
|
||||
{
|
||||
cosi = Vec3f(1,0,0) * getOrientation().toMatrix3()
|
||||
* offset/offset.length();
|
||||
brightness_corr = brightness_corr * (float) sqrt(abs((cosi)));
|
||||
if (brightness_corr < 0.65f)
|
||||
brightness_corr = 0.65f;
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
for (unsigned int i = 0; i < nPoints; ++i)
|
||||
{
|
||||
Blob b = (*points)[i];
|
||||
Point3f p = b.position * m;
|
||||
float br = b.brightness;
|
||||
|
||||
// Reddening for elliptical galaxies
|
||||
|
||||
b.colorIndex = type < E0 ? b.colorIndex : (unsigned int) ceil(0.3f*b.colorIndex);
|
||||
Color c = colorTable[b.colorIndex]; // lookup static color table
|
||||
|
||||
Point3f relPos = p + offset;
|
||||
|
@ -238,18 +271,18 @@ void Galaxy::renderGalaxyPointSprites(const GLContext& context,
|
|||
if ((i & pow2) != 0)
|
||||
{
|
||||
pow2 <<= 1;
|
||||
size /= 1.5f;
|
||||
size /= 1.57f;
|
||||
if (size < minimumFeatureSize)
|
||||
break;
|
||||
}
|
||||
|
||||
float screenFrac = size / relPos.distanceFromOrigin();
|
||||
|
||||
if (screenFrac < 0.05f)
|
||||
if (screenFrac < 0.1f)
|
||||
{
|
||||
float a = 20 * (0.05f - screenFrac) * brightness * br;
|
||||
float a = 3.5f * (0.1f - screenFrac) * brightness_corr * brightness * br;
|
||||
|
||||
glColor4f(c.red(), c.green(), c.blue(), (0.975f*a)*lightGain + 0.025f*a);
|
||||
glColor4f(c.red(), c.green(), c.blue(), (4.0f*lightGain + 1.0f)*a);
|
||||
|
||||
glTexCoord2f(0, 0); glVertex(p + (v0 * size));
|
||||
glTexCoord2f(1, 0); glVertex(p + (v1 * size));
|
||||
|
@ -321,13 +354,13 @@ void Galaxy::renderGalaxyEllipsoid(const GLContext& context,
|
|||
}
|
||||
|
||||
|
||||
unsigned int Galaxy::getRenderMask()
|
||||
unsigned int Galaxy::getRenderMask() const
|
||||
{
|
||||
return Renderer::ShowGalaxies;
|
||||
}
|
||||
|
||||
|
||||
unsigned int Galaxy::getLabelMask()
|
||||
unsigned int Galaxy::getLabelMask() const
|
||||
{
|
||||
return Renderer::GalaxyLabels;
|
||||
}
|
||||
|
@ -335,7 +368,7 @@ unsigned int Galaxy::getLabelMask()
|
|||
|
||||
void Galaxy::increaseLightGain()
|
||||
{
|
||||
lightGain += 0.0125f;
|
||||
lightGain += 0.05f;
|
||||
if (lightGain > 1.0f)
|
||||
lightGain = 1.0f;
|
||||
}
|
||||
|
@ -343,7 +376,7 @@ void Galaxy::increaseLightGain()
|
|||
|
||||
void Galaxy::decreaseLightGain()
|
||||
{
|
||||
lightGain -= 0.0125f;
|
||||
lightGain -= 0.05f;
|
||||
if (lightGain < 0.0f)
|
||||
lightGain = 0.0f;
|
||||
}
|
||||
|
@ -355,11 +388,67 @@ float Galaxy::getLightGain()
|
|||
}
|
||||
|
||||
|
||||
GalacticForm* buildSpiralForms(const std::string& filename)
|
||||
void Galaxy::hsv2rgb( float *r, float *g, float *b, float h, float s, float v )
|
||||
{
|
||||
// r,g,b values are from 0 to 1
|
||||
// h = [0,360], s = [0,1], v = [0,1]
|
||||
|
||||
int i;
|
||||
float f, p, q, t;
|
||||
|
||||
if( s == 0 ) {
|
||||
// achromatic (grey)
|
||||
*r = *g = *b = v;
|
||||
return;
|
||||
}
|
||||
|
||||
h /= 60; // sector 0 to 5
|
||||
i = (int) floorf( h );
|
||||
f = h - (float) i; // factorial part of h
|
||||
p = v * ( 1 - s );
|
||||
q = v * ( 1 - s * f );
|
||||
t = v * ( 1 - s * ( 1 - f ) );
|
||||
|
||||
switch( i ) {
|
||||
case 0:
|
||||
*r = v;
|
||||
*g = t;
|
||||
*b = p;
|
||||
break;
|
||||
case 1:
|
||||
*r = q;
|
||||
*g = v;
|
||||
*b = p;
|
||||
break;
|
||||
case 2:
|
||||
*r = p;
|
||||
*g = v;
|
||||
*b = t;
|
||||
break;
|
||||
case 3:
|
||||
*r = p;
|
||||
*g = q;
|
||||
*b = v;
|
||||
break;
|
||||
case 4:
|
||||
*r = t;
|
||||
*g = p;
|
||||
*b = v;
|
||||
break;
|
||||
default: *r = v;
|
||||
*g = p;
|
||||
*b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GalacticForm* buildGalacticForms(const std::string& filename)
|
||||
{
|
||||
unsigned int galaxySize = GALAXY_POINTS;
|
||||
Blob b;
|
||||
vector<Blob>* spiralPoints = new vector<Blob>;
|
||||
//spiralPoints->reserve(galaxySize); //TODO!!
|
||||
vector<Blob>* galacticPoints = new vector<Blob>;
|
||||
galacticPoints->reserve(galaxySize);
|
||||
|
||||
ifstream inFile(filename.c_str());
|
||||
while (inFile.good())
|
||||
|
@ -372,16 +461,16 @@ GalacticForm* buildSpiralForms(const std::string& filename)
|
|||
|
||||
b.position = Point3f(x, y, z);
|
||||
b.brightness = br;
|
||||
b.colorIndex = (unsigned int) (b.position.distanceFromOrigin() * 256);
|
||||
b.colorIndex = (unsigned int) (b.position.distanceFromOrigin() * 255);
|
||||
|
||||
spiralPoints->push_back(b);
|
||||
galacticPoints->push_back(b);
|
||||
}
|
||||
|
||||
GalacticForm* spiralForm = new GalacticForm();
|
||||
spiralForm->blobs = spiralPoints;
|
||||
spiralForm->scale = Vec3f(1.0f, 1.0f, 1.0f);
|
||||
GalacticForm* galacticForm = new GalacticForm();
|
||||
galacticForm->blobs = galacticPoints;
|
||||
galacticForm->scale = Vec3f(1.0f, 1.0f, 1.0f);
|
||||
|
||||
return spiralForm;
|
||||
return galacticForm;
|
||||
};
|
||||
|
||||
|
||||
|
@ -392,29 +481,47 @@ void InitializeForms()
|
|||
// build color table:
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
float f = (float) i / 256.0f * 0.9f;
|
||||
|
||||
colorTable[i] = Color( 0.9f - 1.0f*square(f),
|
||||
0.9f - 1.0f*f,
|
||||
0.9f - 1.0f*cube(f)
|
||||
);
|
||||
float rr,gg,bb;
|
||||
float rho = (float) i / 255.0f;
|
||||
// generic Hue profile as deduced from true-color imaging for spirals
|
||||
float h = 30.0f*tanh(15.68f*(0.1086f-rho));
|
||||
if ( rho > 0.1086f)
|
||||
h += 260.0f;
|
||||
//convert Hue to RGB
|
||||
Galaxy::hsv2rgb( &rr, &gg, &bb, h , 0.15f, 1.0f);
|
||||
colorTable[i] = Color( rr,gg,bb);
|
||||
}
|
||||
|
||||
// Spiral Galaxies, 7 classical Hubble types
|
||||
|
||||
spiralForms = new GalacticForm*[7];
|
||||
|
||||
spiralForms[Galaxy::S0] = buildSpiralForms("Sa.pts");
|
||||
|
||||
spiralForms[Galaxy::Sa] = buildSpiralForms("Sa.pts");
|
||||
spiralForms[Galaxy::Sb] = buildSpiralForms("Sb.pts");
|
||||
spiralForms[Galaxy::Sc] = buildSpiralForms("Sc.pts");
|
||||
|
||||
spiralForms[Galaxy::SBa] = buildSpiralForms("SBa.pts");
|
||||
spiralForms[Galaxy::SBb] = buildSpiralForms("SBa.pts");
|
||||
spiralForms[Galaxy::SBc] = buildSpiralForms("SBc.pts");
|
||||
|
||||
|
||||
unsigned int galaxySize = 5000;
|
||||
spiralForms[Galaxy::S0] = buildGalacticForms("models/S0.pts");
|
||||
spiralForms[Galaxy::Sa] = buildGalacticForms("models/Sa.pts");
|
||||
spiralForms[Galaxy::Sb] = buildGalacticForms("models/Sb.pts");
|
||||
spiralForms[Galaxy::Sc] = buildGalacticForms("models/Sc.pts");
|
||||
spiralForms[Galaxy::SBa] = buildGalacticForms("models/SBa.pts");
|
||||
|
||||
spiralForms[Galaxy::SBb] = buildGalacticForms("models/SBb.pts");
|
||||
spiralForms[Galaxy::SBc] = buildGalacticForms("models/SBc.pts");
|
||||
|
||||
// Elliptical Galaxies , 8 classical Hubble types, E0..E7,
|
||||
//
|
||||
// To save space: generate spherical E0 template from S0 disk
|
||||
// via rescaling by (1.0f, 3.8f, 1.0f).
|
||||
|
||||
ellipticalForms = new GalacticForm*[8];
|
||||
|
||||
for (unsigned int eform = 0; eform <= 7; ++eform)
|
||||
{
|
||||
float ell = 1.0f - (float) eform / 8.0f;
|
||||
ellipticalForms[eform] = new GalacticForm();
|
||||
ellipticalForms[eform]->blobs = spiralForms[Galaxy::S0]->blobs;
|
||||
// note the correct x,y-alignment of 'ell' scaling!!
|
||||
ellipticalForms[eform]->scale = Vec3f(ell, 3.8*ell, 1.0f);
|
||||
}
|
||||
|
||||
//Irregular Galaxies
|
||||
unsigned int galaxySize = GALAXY_POINTS;
|
||||
Blob b;
|
||||
Point3f p;
|
||||
|
||||
|
@ -434,7 +541,7 @@ void InitializeForms()
|
|||
{
|
||||
b.position = p;
|
||||
b.brightness = 1.0f;
|
||||
b.colorIndex = (unsigned int) (r*256);
|
||||
b.colorIndex = (unsigned int) (r*255);
|
||||
irregularPoints->push_back(b);
|
||||
++i;
|
||||
}
|
||||
|
@ -442,37 +549,7 @@ void InitializeForms()
|
|||
}
|
||||
irregularForm = new GalacticForm();
|
||||
irregularForm->blobs = irregularPoints;
|
||||
irregularForm->scale = Vec3f(1, 1, 1);
|
||||
|
||||
|
||||
|
||||
vector<Blob>* ellipticalPoints = new vector<Blob>;
|
||||
ellipticalPoints->reserve(galaxySize);
|
||||
|
||||
i = 0;
|
||||
while (i < galaxySize)
|
||||
{
|
||||
p = Point3f(Mathf::sfrand(), Mathf::sfrand(), Mathf::sfrand());
|
||||
float r = p.distanceFromOrigin();
|
||||
if (r < 1)
|
||||
{
|
||||
if (Mathf::frand() < cube(1 - r))
|
||||
{
|
||||
b.position = p;
|
||||
b.brightness = 1.0f;
|
||||
b.colorIndex = (unsigned int) (r*256);
|
||||
ellipticalPoints->push_back(b);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
ellipticalForms = new GalacticForm*[8];
|
||||
for (unsigned int eform = 0; eform <= 7; ++eform)
|
||||
{
|
||||
ellipticalForms[eform] = new GalacticForm();
|
||||
ellipticalForms[eform]->blobs = ellipticalPoints;
|
||||
ellipticalForms[eform]->scale = Vec3f(1.0f, 1.0f - (float) eform / 8.0f, 1.0f);
|
||||
}
|
||||
irregularForm->scale = Vec3f(1.0f, 0.1f, 1.0f);
|
||||
|
||||
formsInitialized = true;
|
||||
}
|
||||
|
|
|
@ -34,31 +34,12 @@ struct GalacticForm
|
|||
|
||||
class Galaxy : public DeepSkyObject
|
||||
{
|
||||
public:
|
||||
enum GalaxyType {
|
||||
S0 = 0,
|
||||
Sa = 1,
|
||||
Sb = 2,
|
||||
Sc = 3,
|
||||
SBa = 4,
|
||||
SBb = 5,
|
||||
SBc = 6,
|
||||
E0 = 7,
|
||||
E1 = 8,
|
||||
E2 = 9,
|
||||
E3 = 10,
|
||||
E4 = 11,
|
||||
E5 = 12,
|
||||
E6 = 13,
|
||||
E7 = 14,
|
||||
Irr = 15,
|
||||
};
|
||||
|
||||
public:
|
||||
Galaxy();
|
||||
|
||||
GalaxyType getType() const;
|
||||
void setType(GalaxyType);
|
||||
virtual const char* getType() const;
|
||||
virtual void setType(const std::string&);
|
||||
|
||||
float getDetail() const;
|
||||
void setDetail(float);
|
||||
// float getBrightness() const;
|
||||
|
@ -86,18 +67,40 @@ class Galaxy : public DeepSkyObject
|
|||
static void increaseLightGain();
|
||||
static void decreaseLightGain();
|
||||
static float getLightGain();
|
||||
static void hsv2rgb( float *r, float *g, float *b, float h, float s, float v );
|
||||
|
||||
virtual unsigned int getRenderMask();
|
||||
virtual unsigned int getLabelMask();
|
||||
|
||||
virtual unsigned int getRenderMask() const;
|
||||
virtual unsigned int getLabelMask() const;
|
||||
|
||||
public:
|
||||
enum GalaxyType {
|
||||
S0 = 0,
|
||||
Sa = 1,
|
||||
Sb = 2,
|
||||
Sc = 3,
|
||||
SBa = 4,
|
||||
SBb = 5,
|
||||
SBc = 6,
|
||||
E0 = 7,
|
||||
E1 = 8,
|
||||
E2 = 9,
|
||||
E3 = 10,
|
||||
E4 = 11,
|
||||
E5 = 12,
|
||||
E6 = 13,
|
||||
E7 = 14,
|
||||
Irr = 15
|
||||
};
|
||||
|
||||
private:
|
||||
float detail;
|
||||
static float lightGain;
|
||||
// float brightness;
|
||||
GalaxyType type;
|
||||
GalacticForm* form;
|
||||
|
||||
static float lightGain;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const Galaxy::GalaxyType& sc);
|
||||
//std::ostream& operator<<(std::ostream& s, const Galaxy::GalaxyType& sc);
|
||||
|
||||
#endif // _GALAXY_H_
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
// C++ Interface: name
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _NAME_H_
|
||||
#define _NAME_H_
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <celutil/basictypes.h>
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/utf8.h>
|
||||
|
||||
|
||||
// TODO: this can be "detemplatized" by creating e.g. a global-scope enum InvalidCatalogNumber since there
|
||||
// lies the one and only need for type genericity.
|
||||
template <class OBJ> class NameDatabase
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, uint32, CompareIgnoringCasePredicate> NameIndex;
|
||||
typedef std::multimap<uint32, std::string> NumberIndex;
|
||||
|
||||
public:
|
||||
NameDatabase() {};
|
||||
|
||||
|
||||
uint32 getNameCount() const;
|
||||
|
||||
void add(const uint32, const std::string&);
|
||||
|
||||
// delete all names associated with the specified catalog number
|
||||
void erase(const uint32);
|
||||
|
||||
uint32 getCatalogNumberByName(const std::string&) const;
|
||||
std::string getNameByCatalogNumber(const uint32) const;
|
||||
|
||||
NumberIndex::const_iterator getFirstNameIter(const uint32 catalogNumber) const;
|
||||
NumberIndex::const_iterator getFinalNameIter() const;
|
||||
|
||||
std::vector<std::string> getCompletion(const std::string& name) const;
|
||||
|
||||
protected:
|
||||
NameIndex nameIndex;
|
||||
NumberIndex numberIndex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <class OBJ>
|
||||
uint32 NameDatabase<OBJ>::getNameCount() const
|
||||
{
|
||||
return nameIndex.size();
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ>
|
||||
void NameDatabase<OBJ>::add(const uint32 catalogNumber, const std::string& name)
|
||||
{
|
||||
if (name.length() != 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
uint32 tmp;
|
||||
if ((tmp = getCatalogNumberByName(name)) != OBJ::InvalidCatalogNumber)
|
||||
DPRINTF(2,"Duplicated name '%s' on object with catalog numbers: %d and %d\n", name.c_str(), tmp, catalogNumber);
|
||||
#endif
|
||||
// Add the new name
|
||||
//nameIndex.insert(NameIndex::value_type(name, catalogNumber));
|
||||
|
||||
nameIndex[name] = catalogNumber;
|
||||
numberIndex.insert(NumberIndex::value_type(catalogNumber, name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ>
|
||||
void NameDatabase<OBJ>::erase(const uint32 catalogNumber)
|
||||
{
|
||||
numberIndex.erase(catalogNumber);
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ>
|
||||
uint32 NameDatabase<OBJ>::getCatalogNumberByName(const std::string& name) const
|
||||
{
|
||||
NameIndex::const_iterator iter = nameIndex.find(name);
|
||||
|
||||
if (iter == nameIndex.end())
|
||||
return OBJ::InvalidCatalogNumber;
|
||||
else
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
|
||||
// Return the first name matching the catalog number or end()
|
||||
// if there are no matching names. The first name *should* be the
|
||||
// proper name of the OBJ, if one exists. This requires the
|
||||
// OBJ name database file to have the proper names listed before
|
||||
// other designations. Also, the STL implementation must
|
||||
// preserve this order when inserting the names into the multimap
|
||||
// (not certain whether or not this behavior is in the STL spec.
|
||||
// but it works on the implementations I've tried so far.)
|
||||
template <class OBJ>
|
||||
std::string NameDatabase<OBJ>::getNameByCatalogNumber(const uint32 catalogNumber) const
|
||||
{
|
||||
if (catalogNumber == OBJ::InvalidCatalogNumber)
|
||||
return "";
|
||||
|
||||
NumberIndex::const_iterator iter = numberIndex.lower_bound(catalogNumber);
|
||||
|
||||
if (iter != numberIndex.end() && iter->first == catalogNumber)
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
|
||||
// Return the first name matching the catalog number or end()
|
||||
// if there are no matching names. The first name *should* be the
|
||||
// proper name of the OBJ, if one exists. This requires the
|
||||
// OBJ name database file to have the proper names listed before
|
||||
// other designations. Also, the STL implementation must
|
||||
// preserve this order when inserting the names into the multimap
|
||||
// (not certain whether or not this behavior is in the STL spec.
|
||||
// but it works on the implementations I've tried so far.)
|
||||
template <class OBJ>
|
||||
NameDatabase<OBJ>::NumberIndex::const_iterator NameDatabase<OBJ>::getFirstNameIter(const uint32 catalogNumber) const
|
||||
{
|
||||
NumberIndex::const_iterator iter = numberIndex.lower_bound(catalogNumber);
|
||||
|
||||
if (iter == numberIndex.end() || iter->first != catalogNumber)
|
||||
return getFinalNameIter();
|
||||
else
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ>
|
||||
NameDatabase<OBJ>::NumberIndex::const_iterator NameDatabase<OBJ>::getFinalNameIter() const
|
||||
{
|
||||
return numberIndex.end();
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ>
|
||||
std::vector<std::string> NameDatabase<OBJ>::getCompletion(const std::string& name) const
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
for (NameIndex::const_iterator iter = nameIndex.begin(); iter != nameIndex.end(); ++iter)
|
||||
{
|
||||
if (!UTF8StringCompare(iter->first, name, name.length()))
|
||||
{
|
||||
completion.push_back(iter->first);
|
||||
}
|
||||
}
|
||||
return completion;
|
||||
}
|
||||
|
||||
#endif // _NAME_H_
|
|
@ -30,6 +30,17 @@ Nebula::Nebula() :
|
|||
}
|
||||
|
||||
|
||||
const char* Nebula::getType() const
|
||||
{
|
||||
return "Nebula";
|
||||
}
|
||||
|
||||
|
||||
void Nebula::setType(const string& typeStr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ResourceHandle Nebula::getModel() const
|
||||
{
|
||||
return model;
|
||||
|
@ -87,13 +98,13 @@ void Nebula::render(const GLContext&,
|
|||
}
|
||||
|
||||
|
||||
unsigned int Nebula::getRenderMask()
|
||||
unsigned int Nebula::getRenderMask() const
|
||||
{
|
||||
return Renderer::ShowNebulae;
|
||||
}
|
||||
|
||||
|
||||
unsigned int Nebula::getLabelMask()
|
||||
unsigned int Nebula::getLabelMask() const
|
||||
{
|
||||
return Renderer::NebulaLabels;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ class Nebula : public DeepSkyObject
|
|||
public:
|
||||
Nebula();
|
||||
|
||||
virtual const char* getType() const;
|
||||
virtual void setType(const std::string&);
|
||||
|
||||
virtual bool load(AssociativeArray*, const std::string&);
|
||||
virtual void render(const GLContext& context,
|
||||
const Vec3f& offset,
|
||||
|
@ -31,12 +34,25 @@ class Nebula : public DeepSkyObject
|
|||
float brightness,
|
||||
float pixelSize);
|
||||
|
||||
virtual unsigned int getRenderMask();
|
||||
virtual unsigned int getLabelMask();
|
||||
virtual unsigned int getRenderMask() const;
|
||||
virtual unsigned int getLabelMask() const;
|
||||
|
||||
void setModel(ResourceHandle);
|
||||
ResourceHandle getModel() const;
|
||||
|
||||
public:
|
||||
enum NebulaType
|
||||
{
|
||||
Emissive = 0,
|
||||
Reflective = 1,
|
||||
Dark = 2,
|
||||
Planetary = 3,
|
||||
Galactic = 4,
|
||||
SupernovaRemnant = 5,
|
||||
Bright_HII_Region = 6,
|
||||
NotDefined = 7
|
||||
};
|
||||
|
||||
private:
|
||||
ResourceHandle model;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// octree.h
|
||||
//
|
||||
// Octree-based visibility determination for a star database.
|
||||
// Octree-based visibility determination for objects.
|
||||
//
|
||||
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
|
||||
//
|
||||
|
@ -15,72 +15,328 @@
|
|||
#include <vector>
|
||||
#include <celmath/quaternion.h>
|
||||
#include <celmath/plane.h>
|
||||
#include <celengine/star.h>
|
||||
#include <celengine/observer.h>
|
||||
|
||||
|
||||
class StarHandler
|
||||
// The DynamicOctree and StaticOctree template arguments are:
|
||||
// OBJ: object hanging from the node,
|
||||
// PREC: floating point precision of the culling operations at node level.
|
||||
// The hierarchy of octree nodes is built using a single precision value (excludingFactor), which relates to an
|
||||
// OBJ's limiting property defined by the octree particular specialization: ie. we use [absolute magnitude] for star octrees, etc.
|
||||
// For details, see notes below.
|
||||
|
||||
|
||||
template <class OBJ, class PREC> class OctreeProcessor
|
||||
{
|
||||
public:
|
||||
StarHandler() {};
|
||||
virtual ~StarHandler() {};
|
||||
OctreeProcessor() {};
|
||||
virtual ~OctreeProcessor() {};
|
||||
|
||||
virtual void process(const Star& star, float distance, float appMag) = 0;
|
||||
virtual void process(const OBJ& obj, PREC distance, float appMag) = 0;
|
||||
};
|
||||
|
||||
|
||||
class StarOctree;
|
||||
|
||||
class DynamicStarOctree
|
||||
|
||||
|
||||
template <class OBJ, class PREC> class StaticOctree;
|
||||
template <class OBJ, class PREC> class DynamicOctree
|
||||
{
|
||||
public:
|
||||
DynamicStarOctree(const Point3f& _center, float _absMag);
|
||||
~DynamicStarOctree();
|
||||
typedef std::vector<const OBJ*> ObjectList;
|
||||
|
||||
void insertStar(const Star&, float);
|
||||
void rebuildAndSort(StarOctree*& node, Star*& sortedStars);
|
||||
typedef bool (LimitingFactorPredicate) (const OBJ&, const float);
|
||||
typedef bool (StraddlingPredicate) (const Point3<PREC>&, const OBJ&, const float);
|
||||
typedef PREC (ExclusionFactorDecayFunction)(const PREC);
|
||||
|
||||
public:
|
||||
DynamicOctree(const Point3<PREC>& cellCenterPos,
|
||||
const float exclusionFactor);
|
||||
~DynamicOctree();
|
||||
|
||||
void insertObject (const OBJ&, const PREC);
|
||||
void rebuildAndSort(StaticOctree<OBJ, PREC>*&, OBJ*&);
|
||||
|
||||
private:
|
||||
void addStar(const Star&);
|
||||
void split(float);
|
||||
void sortStarsIntoChildNodes();
|
||||
static unsigned int SPLIT_THRESHOLD;
|
||||
|
||||
std::vector<const Star*>* stars;
|
||||
DynamicStarOctree** children;
|
||||
Point3f center;
|
||||
float absMag;
|
||||
static LimitingFactorPredicate* limitingFactorPredicate;
|
||||
static StraddlingPredicate* straddlingPredicate;
|
||||
static ExclusionFactorDecayFunction* decayFunction;
|
||||
|
||||
private:
|
||||
void add (const OBJ&);
|
||||
void split(const PREC);
|
||||
void sortIntoChildNodes();
|
||||
DynamicOctree* getChild(const OBJ&, const Point3<PREC>&);
|
||||
|
||||
DynamicOctree** _children;
|
||||
Point3<PREC> cellCenterPos;
|
||||
PREC exclusionFactor;
|
||||
ObjectList* _objects;
|
||||
};
|
||||
|
||||
|
||||
class StarOctree
|
||||
{
|
||||
public:
|
||||
StarOctree(const Point3f& _center,
|
||||
float _absMag,
|
||||
Star* _firstStar,
|
||||
uint32 _nStars);
|
||||
~StarOctree();
|
||||
|
||||
void findVisibleStars(StarHandler& starHandler,
|
||||
const Point3f& position,
|
||||
const Planef* frustumPlanes,
|
||||
float limitingMag,
|
||||
float scale) const;
|
||||
void findCloseStars(StarHandler& starHandler,
|
||||
const Point3f& position,
|
||||
float radius,
|
||||
float scale) const;
|
||||
|
||||
|
||||
template <class OBJ, class PREC> class StaticOctree
|
||||
{
|
||||
friend class DynamicOctree<OBJ, PREC>;
|
||||
|
||||
public:
|
||||
StaticOctree(const Point3<PREC>& cellCenterPos,
|
||||
const float exclusionFactor,
|
||||
OBJ* _firstObject,
|
||||
unsigned int nObjects);
|
||||
~StaticOctree();
|
||||
|
||||
// These methods are only declared at the template level; we'll implement them as
|
||||
// full specializations, allowing for different traversal strategies depending on the
|
||||
// object type and nature.
|
||||
|
||||
// This method searches the octree for objects that are likely to be visible
|
||||
// to a viewer with the specified obsPosition and limitingFactor. The
|
||||
// octreeProcessor is invoked for each potentially visible object --no object with
|
||||
// a property greater than limitingFactor will be processed, but
|
||||
// objects that are outside the view frustum may be. Frustum tests are performed
|
||||
// only at the node level to optimize the octree traversal, so an exact test
|
||||
// (if one is required) is the responsibility of the callback method.
|
||||
void processVisibleObjects(OctreeProcessor<OBJ, PREC>& processor,
|
||||
const Point3<PREC>& obsPosition,
|
||||
const Plane<float>* frustumPlanes,
|
||||
float limitingFactor,
|
||||
PREC scale) const;
|
||||
|
||||
void processCloseObjects(OctreeProcessor<OBJ, PREC>& processor,
|
||||
const Point3<PREC>& obsPosition,
|
||||
PREC boundingRadius,
|
||||
PREC scale) const;
|
||||
|
||||
int countChildren() const;
|
||||
int countStars() const;
|
||||
|
||||
friend class DynamicStarOctree;
|
||||
int countObjects() const;
|
||||
|
||||
private:
|
||||
Point3f center;
|
||||
float absMag;
|
||||
Star* firstStar;
|
||||
uint32 nStars;
|
||||
StarOctree** children;
|
||||
static const PREC SQRT3;
|
||||
|
||||
private:
|
||||
StaticOctree** _children;
|
||||
Point3<PREC> cellCenterPos;
|
||||
float exclusionFactor;
|
||||
OBJ* _firstObject;
|
||||
unsigned int nObjects;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// There are two classes implemented in this module: StaticOctree and
|
||||
// DynamicOctree. The DynamicOctree is built first by inserting
|
||||
// objects from a database or catalog and is then 'compiled' into a StaticOctree.
|
||||
// In the process of building the StaticOctree, the original object database is
|
||||
// reorganized, with objects in the same octree node all placed adjacent to each
|
||||
// other. This spatial sorting of the objects dramatically improves the
|
||||
// performance of octree operations through much more coherent memory access.
|
||||
enum
|
||||
{
|
||||
XPos = 1,
|
||||
YPos = 2,
|
||||
ZPos = 4,
|
||||
};
|
||||
|
||||
// The SPLIT_THRESHOLD is the number of objects a node must contain before its
|
||||
// children are generated. Increasing this number will decrease the number of
|
||||
// octree nodes in the tree, which will use less memory but make culling less
|
||||
// efficient.
|
||||
template <class OBJ, class PREC>
|
||||
inline DynamicOctree<OBJ, PREC>::DynamicOctree(const Point3<PREC>& cellCenterPos,
|
||||
const float exclusionFactor):
|
||||
_children (NULL),
|
||||
cellCenterPos (cellCenterPos),
|
||||
exclusionFactor(exclusionFactor),
|
||||
_objects (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline DynamicOctree<OBJ, PREC>::~DynamicOctree()
|
||||
{
|
||||
if (_children != NULL)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
delete _children[i];
|
||||
}
|
||||
|
||||
delete[] _children;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline void DynamicOctree<OBJ, PREC>::insertObject(const OBJ& obj, const PREC scale)
|
||||
{
|
||||
// If the object can't be placed into this node's children, then put it here:
|
||||
if (limitingFactorPredicate(obj, exclusionFactor) || straddlingPredicate(cellCenterPos, obj, exclusionFactor) )
|
||||
add(obj);
|
||||
else
|
||||
{
|
||||
// If we haven't allocated child nodes yet, try to fit
|
||||
// the object in this node, even though it could be put
|
||||
// in a child. Only if there are more than SPLIT_THRESHOLD
|
||||
// objects in the node will we attempt to place the
|
||||
// object into a child node. This is done in order
|
||||
// to avoid having the octree degenerate into one object
|
||||
// per node.
|
||||
if (_children == NULL)
|
||||
{
|
||||
// Make sure that there's enough room left in this node
|
||||
if (_objects != NULL && _objects->size() >= DynamicOctree<OBJ, PREC>::SPLIT_THRESHOLD)
|
||||
split(scale * 0.5f);
|
||||
add(obj);
|
||||
}
|
||||
else
|
||||
// We've already allocated child nodes; place the object
|
||||
// into the appropriate one.
|
||||
this->getChild(obj, cellCenterPos)->insertObject(obj, scale * (PREC) 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline void DynamicOctree<OBJ, PREC>::add(const OBJ& obj)
|
||||
{
|
||||
if (_objects == NULL)
|
||||
_objects = new ObjectList;
|
||||
|
||||
_objects->push_back(&obj);
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline void DynamicOctree<OBJ, PREC>::split(const PREC scale)
|
||||
{
|
||||
_children = new DynamicOctree*[8];
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
Point3<PREC> centerPos = cellCenterPos;
|
||||
|
||||
centerPos.x += ((i & XPos) != 0) ? scale : -scale;
|
||||
centerPos.y += ((i & YPos) != 0) ? scale : -scale;
|
||||
centerPos.z += ((i & ZPos) != 0) ? scale : -scale;
|
||||
|
||||
_children[i] = new DynamicOctree(centerPos,
|
||||
decayFunction(exclusionFactor));
|
||||
}
|
||||
sortIntoChildNodes();
|
||||
}
|
||||
|
||||
|
||||
// Sort this node's objects into objects that can remain here,
|
||||
// and objects that should be placed into one of the eight
|
||||
// child nodes.
|
||||
template <class OBJ, class PREC>
|
||||
inline void DynamicOctree<OBJ, PREC>::sortIntoChildNodes()
|
||||
{
|
||||
unsigned int nKeptInParent = 0;
|
||||
|
||||
for (unsigned int i=0; i<_objects->size(); ++i)
|
||||
{
|
||||
const OBJ& obj = *(*_objects)[i];
|
||||
|
||||
if (straddlingPredicate(cellCenterPos, obj, exclusionFactor) )
|
||||
(*_objects)[nKeptInParent++] = (*_objects)[i];
|
||||
else
|
||||
this->getChild(obj, cellCenterPos)->add(obj);
|
||||
}
|
||||
|
||||
_objects->resize(nKeptInParent);
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline void DynamicOctree<OBJ, PREC>::rebuildAndSort(StaticOctree<OBJ, PREC>*& _staticNode, OBJ*& _sortedObjects)
|
||||
{
|
||||
OBJ* _firstObject = _sortedObjects;
|
||||
|
||||
if (_objects != NULL)
|
||||
for (typename ObjectList::const_iterator iter = _objects->begin(); iter != _objects->end(); ++iter)
|
||||
{
|
||||
*_sortedObjects++ = **iter;
|
||||
}
|
||||
|
||||
unsigned int nObjects = (unsigned int) (_sortedObjects - _firstObject);
|
||||
_staticNode = new StaticOctree<OBJ, PREC>(cellCenterPos, exclusionFactor, _firstObject, nObjects);
|
||||
|
||||
if (_children != NULL)
|
||||
{
|
||||
_staticNode->_children = new StaticOctree<OBJ, PREC>*[8];
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
_children[i]->rebuildAndSort(_staticNode->_children[i], _sortedObjects);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MS VC++ wants this to be placed here:
|
||||
template <class OBJ, class PREC>
|
||||
const PREC StaticOctree<OBJ, PREC>::SQRT3 = (PREC) 1.732050807568877;
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline StaticOctree<OBJ, PREC>::StaticOctree(const Point3<PREC>& cellCenterPos,
|
||||
const float exclusionFactor,
|
||||
OBJ* _firstObject,
|
||||
unsigned int nObjects):
|
||||
_children (NULL),
|
||||
cellCenterPos (cellCenterPos),
|
||||
exclusionFactor(exclusionFactor),
|
||||
_firstObject (_firstObject),
|
||||
nObjects (nObjects)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline StaticOctree<OBJ, PREC>::~StaticOctree()
|
||||
{
|
||||
if (_children != NULL)
|
||||
{
|
||||
for (int i=0; i<8; ++i)
|
||||
delete _children[i];
|
||||
|
||||
delete[] _children;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline int StaticOctree<OBJ, PREC>::countChildren() const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
count += _children != NULL ? 1 + _children[i]->countChildren() : 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
inline int StaticOctree<OBJ, PREC>::countObjects() const
|
||||
{
|
||||
int count = nObjects;
|
||||
|
||||
if (_children != NULL)
|
||||
for (int i=0; i<8; ++i)
|
||||
count += _children[i]->countObjects();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif // _OCTREE_H_
|
||||
|
|
|
@ -28,6 +28,17 @@ OpenCluster::OpenCluster()
|
|||
}
|
||||
|
||||
|
||||
const char* OpenCluster::getType() const
|
||||
{
|
||||
return "Cluster";
|
||||
}
|
||||
|
||||
|
||||
void OpenCluster::setType(const std::string& typeStr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool OpenCluster::load(AssociativeArray* params, const string& resPath)
|
||||
{
|
||||
// No parameters specific to open cluster, though a list of member stars
|
||||
|
@ -49,13 +60,13 @@ void OpenCluster::render(const GLContext&,
|
|||
}
|
||||
|
||||
|
||||
unsigned int OpenCluster::getRenderMask()
|
||||
unsigned int OpenCluster::getRenderMask() const
|
||||
{
|
||||
return Renderer::ShowOpenClusters;
|
||||
}
|
||||
|
||||
|
||||
unsigned int OpenCluster::getLabelMask()
|
||||
unsigned int OpenCluster::getLabelMask() const
|
||||
{
|
||||
return Renderer::OpenClusterLabels;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ class OpenCluster : public DeepSkyObject
|
|||
public:
|
||||
OpenCluster();
|
||||
|
||||
virtual const char* getType() const;
|
||||
virtual void setType(const std::string&);
|
||||
|
||||
virtual bool load(AssociativeArray*, const std::string&);
|
||||
virtual void render(const GLContext& context,
|
||||
const Vec3f& offset,
|
||||
|
@ -31,8 +34,15 @@ class OpenCluster : public DeepSkyObject
|
|||
float brightness,
|
||||
float pixelSize);
|
||||
|
||||
virtual unsigned int getRenderMask();
|
||||
virtual unsigned int getLabelMask();
|
||||
virtual unsigned int getRenderMask() const;
|
||||
virtual unsigned int getLabelMask() const;
|
||||
|
||||
public:
|
||||
enum ClusterType {
|
||||
Open = 0,
|
||||
Globular = 1,
|
||||
NotDefined = 2
|
||||
};
|
||||
|
||||
private:
|
||||
// TODO: It could be very useful to have a list of stars that are members
|
||||
|
|
|
@ -50,6 +50,14 @@ using namespace std;
|
|||
#define GL_COLOR_SUM_EXT 0x8458
|
||||
#endif
|
||||
|
||||
|
||||
static const float STAR_DISTANCE_LIMIT = 1.0e6f;
|
||||
static const double DSO_DISTANCE_LIMIT = 1.0e9;
|
||||
|
||||
static const float LABELLED_STAR_DISTANCE_LIMIT = 5.0e4f;
|
||||
static const double LABELLED_DSO_DISTANCE_LIMIT = 5.0e6;
|
||||
|
||||
|
||||
static const int StarVertexListSize = 1024;
|
||||
|
||||
// Fractional pixel offset used when rendering text as texture mapped
|
||||
|
@ -129,7 +137,7 @@ Renderer::Renderer() :
|
|||
windowHeight(0),
|
||||
fov(FOV),
|
||||
corrFac(1.12f),
|
||||
faintestAutoMag45deg(8.5f),
|
||||
faintestAutoMag45deg(7.0f),
|
||||
renderMode(GL_FILL),
|
||||
labelMode(NoLabels),
|
||||
renderFlags(ShowStars | ShowPlanets),
|
||||
|
@ -662,7 +670,7 @@ Renderer::setStarColorTable(const ColorTemperatureTable* ct)
|
|||
|
||||
void Renderer::addLabelledStar(Star* star, const string& label)
|
||||
{
|
||||
labelledStars.insert(labelledStars.end(), StarLabel(star, label));
|
||||
labelledStars.push_back(StarLabel(star, label));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1417,8 +1425,8 @@ void Renderer::render(const Observer& observer,
|
|||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if (universe.getDeepSkyCatalog() != NULL)
|
||||
renderDeepSkyObjects(*universe.getDeepSkyCatalog(), observer);
|
||||
if (universe.getDSOCatalog() != NULL)
|
||||
renderDeepSkyObjects(universe, observer, faintestMag);
|
||||
|
||||
// Translate the camera before rendering the stars
|
||||
glPushMatrix();
|
||||
|
@ -1469,8 +1477,6 @@ void Renderer::render(const Observer& observer,
|
|||
disableSmoothLines();
|
||||
}
|
||||
|
||||
if (universe.getDeepSkyCatalog() != NULL)
|
||||
labelDeepSkyObjects(*universe.getDeepSkyCatalog(), observer);
|
||||
if ((labelMode & StarLabels) != 0 && universe.getStarCatalog() != NULL)
|
||||
labelStars(labelledStars, *universe.getStarCatalog(), observer);
|
||||
if ((labelMode & ConstellationLabels) != 0 &&
|
||||
|
@ -1928,7 +1934,7 @@ void Renderer::renderBodyAsParticle(Point3f position,
|
|||
discSize = min(discSize * (2.0f * a - 1.0f), maxDiscSize);
|
||||
a = clamp(a) * fade;
|
||||
|
||||
// We scale up the particle by a factor of 1.5 (at fov = 45deg)
|
||||
// We scale up the particle by a factor of 1.6 (at fov = 45deg)
|
||||
// so that it's more
|
||||
// visible--the texture we use has fuzzy edges, and if we render it
|
||||
// in just one pixel, it's likely to disappear. Also, the render
|
||||
|
@ -6190,54 +6196,88 @@ void Renderer::renderPlanetarySystem(const Star& sun,
|
|||
}
|
||||
|
||||
|
||||
class StarRenderer : public StarHandler
|
||||
{
|
||||
public:
|
||||
StarRenderer();
|
||||
~StarRenderer() {};
|
||||
|
||||
void process(const Star&, float, float);
|
||||
|
||||
public:
|
||||
|
||||
template <class OBJ, class PREC> class ObjectRenderer : public OctreeProcessor<OBJ, PREC>
|
||||
{
|
||||
public:
|
||||
ObjectRenderer(const PREC distanceLimit);
|
||||
|
||||
void process(const OBJ&, PREC, float) {};
|
||||
|
||||
public:
|
||||
const Observer* observer;
|
||||
Point3f position;
|
||||
|
||||
GLContext* context;
|
||||
Renderer* renderer;
|
||||
|
||||
Vec3f viewNormal;
|
||||
|
||||
vector<Renderer::Particle>* glareParticles;
|
||||
vector<RenderListEntry>* renderList;
|
||||
Renderer::StarVertexBuffer* starVertexBuffer;
|
||||
|
||||
float faintestMagNight;
|
||||
float fov;
|
||||
float size;
|
||||
float pixelSize;
|
||||
float faintestMag;
|
||||
float faintestMagNight;
|
||||
float saturationMag;
|
||||
float brightnessScale;
|
||||
float brightnessBias;
|
||||
float distanceLimit;
|
||||
|
||||
// These are not fully used by this template's descendants
|
||||
// but we place them here just in case a more sophisticated
|
||||
// rendering scheme is implemented:
|
||||
int nRendered;
|
||||
int nClose;
|
||||
int nBright;
|
||||
int nProcessed;
|
||||
int nLabelled;
|
||||
|
||||
bool useDiscs;
|
||||
int renderFlags;
|
||||
int labelMode;
|
||||
};
|
||||
|
||||
|
||||
template <class OBJ, class PREC>
|
||||
ObjectRenderer<OBJ, PREC>::ObjectRenderer(const PREC _distanceLimit) :
|
||||
distanceLimit((float) _distanceLimit),
|
||||
nRendered (0),
|
||||
nClose (0),
|
||||
nBright (0),
|
||||
nProcessed (0),
|
||||
nLabelled (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class StarRenderer : public ObjectRenderer<Star, float>
|
||||
{
|
||||
public:
|
||||
StarRenderer();
|
||||
|
||||
void process(const Star& star, float distance, float appMag);
|
||||
|
||||
public:
|
||||
Point3f obsPos;
|
||||
|
||||
vector<Renderer::Particle>* glareParticles;
|
||||
vector<RenderListEntry>* renderList;
|
||||
Renderer::StarVertexBuffer* starVertexBuffer;
|
||||
|
||||
bool useDiscs;
|
||||
float maxDiscSize;
|
||||
|
||||
|
||||
const ColorTemperatureTable* colorTemp;
|
||||
};
|
||||
|
||||
|
||||
StarRenderer::StarRenderer() :
|
||||
ObjectRenderer<Star, float>(STAR_DISTANCE_LIMIT),
|
||||
starVertexBuffer(0),
|
||||
distanceLimit(1.0e6f),
|
||||
nRendered(0),
|
||||
nClose(0),
|
||||
nBright(0),
|
||||
nProcessed(0),
|
||||
useDiscs(false),
|
||||
maxDiscSize(1.0f),
|
||||
colorTemp(NULL)
|
||||
useDiscs (false),
|
||||
maxDiscSize (1.0f),
|
||||
colorTemp (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -6247,9 +6287,9 @@ void StarRenderer::process(const Star& star, float distance, float appMag)
|
|||
nProcessed++;
|
||||
|
||||
Point3f starPos = star.getPosition();
|
||||
Vec3f relPos = starPos - position;
|
||||
float orbitalRadius = star.getOrbitalRadius();
|
||||
bool hasOrbit = orbitalRadius > 0.0f;
|
||||
Vec3f relPos = starPos - obsPos;
|
||||
float orbitalRadius = star.getOrbitalRadius();
|
||||
bool hasOrbit = orbitalRadius > 0.0f;
|
||||
|
||||
if (distance > distanceLimit)
|
||||
return;
|
||||
|
@ -6289,16 +6329,15 @@ void StarRenderer::process(const Star& star, float distance, float appMag)
|
|||
distance = relPos.length();
|
||||
|
||||
// Recompute apparent magnitude using new distance computation
|
||||
appMag = astro::absToAppMag(star.getAbsoluteMagnitude(),
|
||||
distance);
|
||||
appMag = astro::absToAppMag(star.getAbsoluteMagnitude(), distance);
|
||||
|
||||
float f = RenderDistance / distance;
|
||||
float f = RenderDistance / distance;
|
||||
renderDistance = RenderDistance;
|
||||
starPos = position + relPos * f;
|
||||
starPos = obsPos + relPos * f;
|
||||
|
||||
float radius = star.getRadius();
|
||||
discSizeInPixels = radius / astro::lightYearsToKilometers(distance) / pixelSize;
|
||||
nClose++;
|
||||
++nClose;
|
||||
}
|
||||
|
||||
if (discSizeInPixels <= 1)
|
||||
|
@ -6329,7 +6368,7 @@ void StarRenderer::process(const Star& star, float distance, float appMag)
|
|||
renderDistance * size);
|
||||
}
|
||||
|
||||
nRendered++;
|
||||
++nRendered;
|
||||
|
||||
// If the star is brighter than the saturation magnitude, add a
|
||||
// halo around it to make it appear more brilliant. This is a
|
||||
|
@ -6349,7 +6388,7 @@ void StarRenderer::process(const Star& star, float distance, float appMag)
|
|||
p.size = p.size * 3;
|
||||
p.color = Color(starColor, alpha);
|
||||
glareParticles->insert(glareParticles->end(), p);
|
||||
nBright++;
|
||||
++nBright;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -6379,27 +6418,30 @@ void Renderer::renderStars(const StarDatabase& starDB,
|
|||
const Observer& observer)
|
||||
{
|
||||
StarRenderer starRenderer;
|
||||
Point3f observerPos = (Point3f) observer.getPosition();
|
||||
observerPos.x *= 1e-6f;
|
||||
observerPos.y *= 1e-6f;
|
||||
observerPos.z *= 1e-6f;
|
||||
Point3f obsPos = (Point3f) observer.getPosition();
|
||||
obsPos.x *= 1e-6f;
|
||||
obsPos.y *= 1e-6f;
|
||||
obsPos.z *= 1e-6f;
|
||||
|
||||
starRenderer.observer = &observer;
|
||||
starRenderer.position = observerPos;
|
||||
starRenderer.viewNormal = Vec3f(0, 0, -1) * observer.getOrientation().toMatrix3();
|
||||
starRenderer.glareParticles = &glareParticles;
|
||||
starRenderer.renderList = &renderList;
|
||||
starRenderer.context = context;
|
||||
starRenderer.observer = &observer;
|
||||
starRenderer.obsPos = obsPos;
|
||||
starRenderer.viewNormal = Vec3f(0, 0, -1) * observer.getOrientation().toMatrix3();
|
||||
starRenderer.glareParticles = &glareParticles;
|
||||
starRenderer.renderList = &renderList;
|
||||
starRenderer.starVertexBuffer = starVertexBuffer;
|
||||
starRenderer.faintestMagNight = faintestMagNight;
|
||||
starRenderer.fov = fov;
|
||||
|
||||
// size/pixelSize =0.86 at 120deg, 1.43 at 45deg and 1.6 at 0deg.
|
||||
starRenderer.size = pixelSize * 1.6f / corrFac;
|
||||
starRenderer.pixelSize = pixelSize;
|
||||
starRenderer.brightnessScale = brightnessScale * corrFac;
|
||||
starRenderer.brightnessBias = brightnessBias;
|
||||
starRenderer.faintestMag = faintestMag;
|
||||
starRenderer.saturationMag = saturationMag;
|
||||
starRenderer.distanceLimit = distanceLimit;
|
||||
starRenderer.size = pixelSize * 1.6f / corrFac;
|
||||
starRenderer.pixelSize = pixelSize;
|
||||
starRenderer.brightnessScale = brightnessScale * corrFac;
|
||||
starRenderer.brightnessBias = brightnessBias;
|
||||
starRenderer.faintestMag = faintestMag;
|
||||
starRenderer.faintestMagNight = faintestMagNight;
|
||||
starRenderer.saturationMag = saturationMag;
|
||||
starRenderer.distanceLimit = distanceLimit;
|
||||
|
||||
if (starStyle == ScaledDiscStars)
|
||||
{
|
||||
starRenderer.useDiscs = true;
|
||||
|
@ -6418,7 +6460,7 @@ void Renderer::renderStars(const StarDatabase& starDB,
|
|||
starTex->bind();
|
||||
starRenderer.starVertexBuffer->start(starStyle == PointStars);
|
||||
starDB.findVisibleStars(starRenderer,
|
||||
observerPos,
|
||||
obsPos,
|
||||
observer.getOrientation(),
|
||||
degToRad(fov),
|
||||
(float) windowWidth / (float) windowHeight,
|
||||
|
@ -6430,102 +6472,197 @@ void Renderer::renderStars(const StarDatabase& starDB,
|
|||
}
|
||||
|
||||
|
||||
void Renderer::renderDeepSkyObjects(const DeepSkyCatalog& catalog,
|
||||
const Observer& observer)
|
||||
class DSORenderer : public ObjectRenderer<DeepSkyObject*, double>
|
||||
{
|
||||
Point3d observerPos = (Point3d) observer.getPosition();
|
||||
observerPos.x *= 1e-6;
|
||||
observerPos.y *= 1e-6;
|
||||
observerPos.z *= 1e-6;
|
||||
public:
|
||||
DSORenderer();
|
||||
|
||||
Frustum frustum(degToRad(fov),
|
||||
(float) windowWidth / (float) windowHeight,
|
||||
MinNearPlaneDistance);
|
||||
void process(DeepSkyObject* const &, double, float);
|
||||
|
||||
Mat3f viewMat = observer.getOrientation().toMatrix3();
|
||||
Vec3f v0 = Vec3f(-1, -1, 0) * viewMat;
|
||||
Vec3f v1 = Vec3f( 1, -1, 0) * viewMat;
|
||||
Vec3f v2 = Vec3f( 1, 1, 0) * viewMat;
|
||||
Vec3f v3 = Vec3f(-1, 1, 0) * viewMat;
|
||||
public:
|
||||
Point3d obsPos;
|
||||
DSODatabase* dsoDB;
|
||||
Frustum frustum;
|
||||
|
||||
// Kludgy way to diminish brightness of galaxies based on faintest
|
||||
// magnitude. I need to rethink how galaxies are rendered.
|
||||
float brightness = min((faintestMag - 2.0f) / 4.0f, 1.0f);
|
||||
if (brightness < 0.0f)
|
||||
Mat3f orientationMatrix;
|
||||
|
||||
int wWidth;
|
||||
int wHeight;
|
||||
|
||||
double avgAbsMag;
|
||||
};
|
||||
|
||||
|
||||
DSORenderer::DSORenderer() :
|
||||
ObjectRenderer<DeepSkyObject*, double>(DSO_DISTANCE_LIMIT),
|
||||
frustum(degToRad(45.0f), 1.0f, 1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void DSORenderer::process(DeepSkyObject* const & dso,
|
||||
double distanceToDSO,
|
||||
float absMag)
|
||||
{
|
||||
if (distanceToDSO > distanceLimit)
|
||||
return;
|
||||
|
||||
// Render any line primitives with smooth lines (mostly to make
|
||||
// graticules look good.)
|
||||
if ((renderFlags & ShowSmoothLines) != 0)
|
||||
enableSmoothLines();
|
||||
Point3d dsoPos = dso->getPosition();
|
||||
Vec3f relPos = Vec3f((float)(dsoPos.x - obsPos.x),
|
||||
(float)(dsoPos.y - obsPos.y),
|
||||
(float)(dsoPos.z - obsPos.z));
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
|
||||
Point3d center = Point3d(0.0f, 0.0f, 0.0f) + relPos * orientationMatrix;
|
||||
|
||||
for (DeepSkyCatalog::const_iterator iter = catalog.begin();
|
||||
iter != catalog.end(); iter++)
|
||||
// Test the object's bounding sphere against the view frustum. If we
|
||||
// avoid this stage, overcrowded octree cells may hit performance badly:
|
||||
// each object (even if it's not visible) would be sent to the OpenGL
|
||||
// pipeline.
|
||||
|
||||
if (renderFlags & dso->getRenderMask())
|
||||
{
|
||||
DeepSkyObject* obj = *iter;
|
||||
|
||||
if ((renderFlags & obj->getRenderMask()) == 0)
|
||||
continue;
|
||||
|
||||
Point3d pos = obj->getPosition();
|
||||
float radius = obj->getRadius();
|
||||
Vec3f offset = Vec3f((float) (pos.x - observerPos.x),
|
||||
(float) (pos.y - observerPos.y),
|
||||
(float) (pos.z - observerPos.z));
|
||||
Point3f center = Point3f(0.0f, 0.0f, 0.0f) + offset *
|
||||
conjugate(observer.getOrientation()).toMatrix3();
|
||||
|
||||
// Test the object's bounding sphere against the view frustum
|
||||
if (frustum.testSphere(center, radius) != Frustum::Outside)
|
||||
double dsoRadius = dso->getRadius();
|
||||
if (frustum.testSphere(center, dsoRadius) != Frustum::Outside)
|
||||
{
|
||||
float distanceToObject = offset.length() - radius;
|
||||
if (distanceToObject < 0)
|
||||
distanceToObject = 0;
|
||||
float minimumFeatureSize = pixelSize * 0.5f * distanceToObject;
|
||||
if (distanceToDSO < 0)
|
||||
distanceToDSO = 0;
|
||||
|
||||
if (radius < 10.0)
|
||||
// display looks satisfactory for 0.2 < brightness < O(1.0)
|
||||
// Ansatz: brightness = a - b*appMag(distanceToDSO), emulates
|
||||
// eye sensitivity...
|
||||
// determine a,b such that
|
||||
// a-b*absMag = absMag/avgAbsMag ~ 1; a-b*faintestMag = 0.2
|
||||
// the 2nd eqn guarantees that the faintest galaxies are still
|
||||
// visible.
|
||||
// the parameters in the 'close' correction are fixed by matching
|
||||
// the gradients at 10 pc and requiring brightness = r + ri at distanceToDSO = 0
|
||||
|
||||
double ri = 0.25, pc10 = 32.6167;
|
||||
double r = absMag/avgAbsMag;
|
||||
double num = 5*(absMag - faintestMag);
|
||||
double a = r*(avgAbsMag - 5*faintestMag)/num;
|
||||
double b = (1.0 - 5*r)/num;
|
||||
double c = 0.4605170186*ri/b-1.0;
|
||||
double close = ri*(pc10 - distanceToDSO)/(pc10 + distanceToDSO*c);
|
||||
double brightness = (distanceToDSO >= pc10) ?
|
||||
a - b * astro::absToAppMag(absMag, (float) distanceToDSO): r + close;
|
||||
brightness = 1.5*brightness*(faintestMag-3.0)/renderer->getFaintestAM45deg();
|
||||
if (brightness < 0.0)
|
||||
brightness = 0.0;
|
||||
|
||||
if (dsoRadius < 1000.0)
|
||||
{
|
||||
// Small objects may be prone to clipping; give them special
|
||||
// handling. We don't want to always set the projection
|
||||
// matrix, since that could be expensive with large galaxy
|
||||
// catalogs.
|
||||
float nearZ = distanceToObject;
|
||||
float farZ = offset.length() + radius * 2;
|
||||
if (nearZ < radius * 0.001f)
|
||||
float nearZ = (float) distanceToDSO;
|
||||
float farZ = (float) (relPos.length() + dsoRadius * 2);
|
||||
if (nearZ < dsoRadius * 0.001f)
|
||||
{
|
||||
nearZ = radius * 0.001f;
|
||||
farZ = nearZ * 10000.0f;
|
||||
nearZ = (float) (dsoRadius * 0.001);
|
||||
farZ = nearZ * 10000.0f;
|
||||
}
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
gluPerspective(fov,
|
||||
(float) windowWidth / (float) windowHeight,
|
||||
nearZ, farZ);
|
||||
(float) wWidth / (float) wHeight,
|
||||
nearZ,
|
||||
farZ);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslate(offset);
|
||||
obj->render(*context,
|
||||
offset,
|
||||
observer.getOrientation(),
|
||||
brightness,
|
||||
glTranslate(relPos);
|
||||
|
||||
dso->render(*context,
|
||||
relPos,
|
||||
observer->getOrientation(),
|
||||
(float) brightness,
|
||||
pixelSize);
|
||||
glPopMatrix();
|
||||
|
||||
if (radius < 10.0)
|
||||
#if 1
|
||||
if (dsoRadius < 1000.0)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // frustum test
|
||||
} // renderFlags check
|
||||
|
||||
// avoid label overlap by FOV/fov-weighted distance cut-off!
|
||||
// only render those labels that are in front of the camera:
|
||||
if ((dso->getLabelMask() & labelMode) &&
|
||||
distanceToDSO < LABELLED_DSO_DISTANCE_LIMIT * FOV/fov &&
|
||||
dot(relPos, viewNormal) > 0)
|
||||
{
|
||||
renderer->addLabel(dsoDB->getDSOName(dso),
|
||||
Color(0.1f, 0.85f, 0.85f, 1.0f),
|
||||
Point3f(relPos.x, relPos.y, relPos.z));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::renderDeepSkyObjects(const Universe& universe,
|
||||
const Observer& observer,
|
||||
const float faintestMagNight)
|
||||
{
|
||||
DSORenderer dsoRenderer;
|
||||
|
||||
Point3d obsPos = (Point3d) observer.getPosition();
|
||||
obsPos.x *= 1e-6;
|
||||
obsPos.y *= 1e-6;
|
||||
obsPos.z *= 1e-6;
|
||||
|
||||
DSODatabase* dsoDB = universe.getDSOCatalog();
|
||||
|
||||
dsoRenderer.context = context;
|
||||
dsoRenderer.renderer = this;
|
||||
dsoRenderer.dsoDB = dsoDB;
|
||||
dsoRenderer.orientationMatrix = conjugate(observer.getOrientation()).toMatrix3();
|
||||
|
||||
dsoRenderer.observer = &observer;
|
||||
dsoRenderer.obsPos = obsPos;
|
||||
dsoRenderer.viewNormal = Vec3f(0, 0, -1) * observer.getOrientation().toMatrix3();
|
||||
dsoRenderer.fov = fov;
|
||||
// size/pixelSize =0.86 at 120deg, 1.43 at 45deg and 1.6 at 0deg.
|
||||
dsoRenderer.size = pixelSize * 1.6f / corrFac;
|
||||
dsoRenderer.pixelSize = pixelSize;
|
||||
dsoRenderer.brightnessScale = brightnessScale * corrFac;
|
||||
dsoRenderer.brightnessBias = brightnessBias;
|
||||
|
||||
dsoRenderer.avgAbsMag = dsoDB->getAverageAbsoluteMagnitude();
|
||||
dsoRenderer.faintestMag = faintestMag;
|
||||
dsoRenderer.faintestMagNight = faintestMagNight;
|
||||
dsoRenderer.saturationMag = saturationMag;
|
||||
dsoRenderer.renderFlags = renderFlags;
|
||||
dsoRenderer.labelMode = labelMode;
|
||||
//cout<<"dsoRenderer: "<<faintestMag<<" "<<saturationMag<<endl;
|
||||
dsoRenderer.wWidth = windowWidth;
|
||||
dsoRenderer.wHeight = windowHeight;
|
||||
|
||||
dsoRenderer.frustum = Frustum(degToRad(fov),
|
||||
(float) windowWidth / (float) windowHeight,
|
||||
MinNearPlaneDistance);
|
||||
|
||||
// Render any line primitives with smooth lines
|
||||
// (mostly to make graticules look good.)
|
||||
if ((renderFlags & ShowSmoothLines) != 0)
|
||||
enableSmoothLines();
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
dsoDB->findVisibleDSOs(dsoRenderer,
|
||||
obsPos,
|
||||
observer.getOrientation(),
|
||||
degToRad(fov),
|
||||
(float) windowWidth / (float) windowHeight,
|
||||
2*faintestMagNight);
|
||||
|
||||
if ((renderFlags & ShowSmoothLines) != 0)
|
||||
disableSmoothLines();
|
||||
|
@ -6578,44 +6715,18 @@ void Renderer::renderCelestialSphere(const Observer& observer)
|
|||
}
|
||||
|
||||
|
||||
void Renderer::labelDeepSkyObjects(const DeepSkyCatalog& catalog,
|
||||
const Observer& observer)
|
||||
{
|
||||
Point3f observerPos_ly = (Point3f) observer.getPosition() * ((float)1e-6);
|
||||
|
||||
for (DeepSkyCatalog::const_iterator iter = catalog.begin();
|
||||
iter != catalog.end(); iter++)
|
||||
{
|
||||
DeepSkyObject* obj = *iter;
|
||||
|
||||
if ((obj->getLabelMask() & labelMode) != 0)
|
||||
{
|
||||
Point3d posd = obj->getPosition();
|
||||
Point3f pos((float) posd.x, (float) posd.y, (float) posd.z);
|
||||
|
||||
Vec3f rpos = pos - observerPos_ly;
|
||||
if ((rpos * conjugate(observer.getOrientation()).toMatrix3()).z < 0)
|
||||
{
|
||||
addLabel(obj->getName(), Color(0.7f, 0.7f, 0.0f),
|
||||
Point3f(rpos.x, rpos.y, rpos.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::labelStars(const vector<StarLabel>& stars,
|
||||
void Renderer::labelStars(const vector<StarLabel>& labelledStars,
|
||||
const StarDatabase& starDB,
|
||||
const Observer& observer)
|
||||
{
|
||||
Point3f observerPos_ly = (Point3f) observer.getPosition() * ((float)1e-6);
|
||||
Point3f observerPos_ly = (Point3f) observer.getPosition() * 1e-6f;
|
||||
|
||||
for (vector<StarLabel>::const_iterator iter = stars.begin(); iter != stars.end(); iter++)
|
||||
for (vector<StarLabel>::const_iterator iter = labelledStars.begin(); iter != labelledStars.end(); ++iter)
|
||||
{
|
||||
Star* star = iter->star;
|
||||
Point3f pos = star->getPosition();
|
||||
Star* star = iter->obj;
|
||||
Point3f pos = star->getPosition();
|
||||
float distance = pos.distanceTo(observerPos_ly);
|
||||
float appMag = (distance > 0.0f) ?
|
||||
float appMag = (distance > 0.0f) ?
|
||||
astro::absToAppMag(star->getAbsoluteMagnitude(), distance) : -100.0f;
|
||||
|
||||
if (appMag < faintestMag && distance <= distanceLimit)
|
||||
|
@ -6669,7 +6780,8 @@ void Renderer::labelConstellations(const AsterismList& asterisms,
|
|||
avg = avg / (float) chain.size();
|
||||
avg = avg * 1e6f;
|
||||
Vec3f rpos = Point3f(avg.x, avg.y, avg.z) - observerPos;
|
||||
if ((rpos * conjugate(observer.getOrientation()).toMatrix3()).z < 0) {
|
||||
if ((rpos * conjugate(observer.getOrientation()).toMatrix3()).z < 0)
|
||||
{
|
||||
addLabel(ast->getName(labelMode & I18nConstellationLabels),
|
||||
Color(0.5f, 0.0f, 1.0f, 1.0f),
|
||||
Point3f(rpos.x, rpos.y, rpos.z));
|
||||
|
|
|
@ -253,30 +253,45 @@ class Renderer
|
|||
float cosSkyCapAltitude;
|
||||
};
|
||||
|
||||
struct StarLabel
|
||||
template <class OBJ> struct ObjectLabel
|
||||
{
|
||||
Star* star;
|
||||
string label;
|
||||
OBJ* obj;
|
||||
std::string label;
|
||||
|
||||
StarLabel() : star(NULL), label("") {};
|
||||
StarLabel(Star* _star, const std::string& _label) :
|
||||
star(_star), label(_label) {};
|
||||
StarLabel(const StarLabel& sl) : star(sl.star), label(sl.label) {};
|
||||
StarLabel& operator=(const StarLabel& sl)
|
||||
ObjectLabel() :
|
||||
obj (NULL),
|
||||
label("")
|
||||
{};
|
||||
|
||||
ObjectLabel(OBJ* _obj, const std::string& _label) :
|
||||
obj (_obj),
|
||||
label(_label)
|
||||
{};
|
||||
|
||||
ObjectLabel(const ObjectLabel& objLbl) :
|
||||
obj (objLbl.obj),
|
||||
label(objLbl.label)
|
||||
{};
|
||||
|
||||
ObjectLabel& operator = (const ObjectLabel& objLbl)
|
||||
{
|
||||
star = sl.star;
|
||||
label = sl.label;
|
||||
obj = objLbl.obj;
|
||||
label = objLbl.label;
|
||||
return *this;
|
||||
};
|
||||
};
|
||||
|
||||
typedef ObjectLabel<Star> StarLabel;
|
||||
typedef ObjectLabel<DeepSkyObject> DSOLabel; // currently not used
|
||||
|
||||
private:
|
||||
void setFieldOfView(float);
|
||||
void renderStars(const StarDatabase& starDB,
|
||||
float faintestVisible,
|
||||
const Observer& observer);
|
||||
void renderDeepSkyObjects(const DeepSkyCatalog& catalog,
|
||||
const Observer& observer);
|
||||
void renderDeepSkyObjects(const Universe&,
|
||||
const Observer&,
|
||||
float faintestMagNight);
|
||||
void renderCelestialSphere(const Observer& observer);
|
||||
void renderPlanetarySystem(const Star& sun,
|
||||
const PlanetarySystem& solSystem,
|
||||
|
@ -349,11 +364,9 @@ class Renderer
|
|||
double now,
|
||||
vector<EclipseShadow>& shadows);
|
||||
|
||||
void labelDeepSkyObjects(const DeepSkyCatalog& catalog,
|
||||
const Observer& observer);
|
||||
void labelStars(const std::vector<StarLabel>& stars,
|
||||
const StarDatabase& starDB,
|
||||
const Observer& observer);
|
||||
void labelStars(const std::vector<StarLabel>& labelledStars,
|
||||
const StarDatabase&,
|
||||
const Observer&);
|
||||
void labelConstellations(const AsterismList& asterisms,
|
||||
const Observer& observer);
|
||||
void renderParticles(const std::vector<Particle>& particles,
|
||||
|
@ -417,6 +430,7 @@ class Renderer
|
|||
std::vector<LightSource> lightSourceLists[MaxSolarSystems];
|
||||
|
||||
std::vector<StarLabel> labelledStars;
|
||||
std::vector<DSOLabel> labelledDSOs;
|
||||
|
||||
double modelMatrix[16];
|
||||
double projMatrix[16];
|
||||
|
|
|
@ -88,12 +88,18 @@ string Selection::getName() const
|
|||
switch (type)
|
||||
{
|
||||
case Type_Star:
|
||||
char buf[20];
|
||||
sprintf(buf, "#%d", star()->getCatalogNumber());
|
||||
return string(buf);
|
||||
{
|
||||
char buf[20];
|
||||
sprintf(buf, "#%d", star()->getCatalogNumber());
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
case Type_DeepSky:
|
||||
return deepsky()->getName();
|
||||
{
|
||||
char buf[20];
|
||||
sprintf(buf, "#%d", deepsky()->getCatalogNumber());
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
case Type_Body:
|
||||
{
|
||||
|
|
|
@ -449,7 +449,7 @@ Selection Simulation::findObjectFromPath(string s, bool i18n)
|
|||
}
|
||||
|
||||
|
||||
std::vector<std::string> Simulation::getObjectCompletion(string s, bool withLocations)
|
||||
vector<std::string> Simulation::getObjectCompletion(string s, bool withLocations)
|
||||
{
|
||||
Selection path[2];
|
||||
int nPathEntries = 0;
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#include <celmath/plane.h>
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/bytes.h>
|
||||
#include <celengine/stardb.h>
|
||||
#include "celestia.h"
|
||||
#include "astro.h"
|
||||
#include "stardb.h"
|
||||
#include "parser.h"
|
||||
#include "parseobject.h"
|
||||
#include "multitexture.h"
|
||||
|
@ -36,40 +36,12 @@ static string LacailleCatalogPrefix("Lacaille ");
|
|||
static string TychoCatalogPrefix("TYC ");
|
||||
static string SAOCatalogPrefix("SAO ");
|
||||
|
||||
static const float OctreeRootSize = 15000.0f;
|
||||
static const float OctreeMagnitude = 6.0f;
|
||||
static const float ExtraRoom = 0.01f; // Reserve 1% capacity for extra stars
|
||||
static const float STAR_OCTREE_ROOT_SIZE = 15000.0f;
|
||||
static const float STAR_OCTREE_MAGNITUDE = 6.0f;
|
||||
static const float STAR_EXTRA_ROOM = 0.01f; // Reserve 1% capacity for extra stars
|
||||
|
||||
const char* StarDatabase::FileHeader = "CELSTARS";
|
||||
const char* StarDatabase::CrossIndexFileHeader = "CELINDEX";
|
||||
|
||||
|
||||
StarDatabase::StarDatabase() : nStars(0),
|
||||
capacity(0),
|
||||
stars(NULL),
|
||||
names(NULL),
|
||||
octreeRoot(NULL),
|
||||
nextAutoCatalogNumber(0xfffffffe)
|
||||
{
|
||||
crossIndexes.resize(MaxCatalog);
|
||||
}
|
||||
|
||||
|
||||
StarDatabase::~StarDatabase()
|
||||
{
|
||||
if (stars != NULL)
|
||||
delete [] stars;
|
||||
|
||||
if (catalogNumberIndex != NULL)
|
||||
delete [] catalogNumberIndex;
|
||||
|
||||
for (vector<CrossIndex*>::iterator iter = crossIndexes.begin();
|
||||
iter != crossIndexes.end(); iter++)
|
||||
{
|
||||
if (*iter != NULL)
|
||||
delete *iter;
|
||||
}
|
||||
}
|
||||
const char* StarDatabase::FILE_HEADER = "CELSTARS";
|
||||
const char* StarDatabase::CROSSINDEX_FILE_HEADER = "CELINDEX";
|
||||
|
||||
|
||||
// Used to sort stars by catalog number
|
||||
|
@ -113,47 +85,6 @@ struct PtrCatalogNumberOrderingPredicate
|
|||
};
|
||||
|
||||
|
||||
Star* StarDatabase::find(uint32 catalogNumber) const
|
||||
{
|
||||
Star refStar;
|
||||
refStar.setCatalogNumber(catalogNumber);
|
||||
|
||||
Star** star = lower_bound(catalogNumberIndex,
|
||||
catalogNumberIndex + nStars,
|
||||
&refStar,
|
||||
PtrCatalogNumberOrderingPredicate());
|
||||
|
||||
if (star != catalogNumberIndex + nStars &&
|
||||
(*star)->getCatalogNumber() == catalogNumber)
|
||||
return *star;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
StarDatabase::crossIndex(Catalog catalog, uint32 celCatalogNumber) const
|
||||
{
|
||||
if (static_cast<uint32>(catalog) >= crossIndexes.size())
|
||||
return Star::InvalidCatalogNumber;
|
||||
|
||||
CrossIndex* xindex = crossIndexes[catalog];
|
||||
if (xindex == NULL)
|
||||
return Star::InvalidCatalogNumber;
|
||||
|
||||
// A simple linear search. We could store cross indices sorted by
|
||||
// both catalog numbers and trade memory for speed
|
||||
for (CrossIndex::const_iterator iter = xindex->begin();
|
||||
iter != xindex->end(); iter++)
|
||||
{
|
||||
if (celCatalogNumber == iter->celCatalogNumber)
|
||||
return iter->catalogNumber;
|
||||
}
|
||||
|
||||
return Star::InvalidCatalogNumber;
|
||||
}
|
||||
|
||||
|
||||
static bool parseSimpleCatalogNumber(const string& name,
|
||||
const string& prefix,
|
||||
uint32* catalogNumber)
|
||||
|
@ -179,7 +110,8 @@ static bool parseSimpleCatalogNumber(const string& name,
|
|||
static bool parseHIPPARCOSCatalogNumber(const string& name,
|
||||
uint32* catalogNumber)
|
||||
{
|
||||
return parseSimpleCatalogNumber(name, HIPPARCOSCatalogPrefix,
|
||||
return parseSimpleCatalogNumber(name,
|
||||
HIPPARCOSCatalogPrefix,
|
||||
catalogNumber);
|
||||
}
|
||||
|
||||
|
@ -187,7 +119,8 @@ static bool parseHIPPARCOSCatalogNumber(const string& name,
|
|||
static bool parseHDCatalogNumber(const string& name,
|
||||
uint32* catalogNumber)
|
||||
{
|
||||
return parseSimpleCatalogNumber(name, HDCatalogPrefix,
|
||||
return parseSimpleCatalogNumber(name,
|
||||
HDCatalogPrefix,
|
||||
catalogNumber);
|
||||
}
|
||||
|
||||
|
@ -198,7 +131,9 @@ static bool parseTychoCatalogNumber(const string& name,
|
|||
if (compareIgnoringCase(name, TychoCatalogPrefix, TychoCatalogPrefix.length()) == 0)
|
||||
{
|
||||
unsigned int tyc1 = 0, tyc2 = 0, tyc3 = 0;
|
||||
if (sscanf(string(name, TychoCatalogPrefix.length(), string::npos).c_str(), " %u-%u-%u", &tyc1, &tyc2, &tyc3) == 3)
|
||||
if (sscanf(string(name, TychoCatalogPrefix.length(),
|
||||
string::npos).c_str(),
|
||||
" %u-%u-%u", &tyc1, &tyc2, &tyc3) == 3)
|
||||
{
|
||||
*catalogNumber = (uint32) (tyc3 * 1000000000 + tyc2 * 10000 + tyc1);
|
||||
return true;
|
||||
|
@ -235,25 +170,48 @@ bool operator< (const StarDatabase::CrossIndexEntry& a,
|
|||
}
|
||||
|
||||
|
||||
Star*
|
||||
StarDatabase::searchCrossIndex(Catalog catalog, uint32 number) const
|
||||
StarDatabase::StarDatabase():
|
||||
nStars (0),
|
||||
capacity (0),
|
||||
stars (NULL),
|
||||
namesDB (NULL),
|
||||
octreeRoot (NULL),
|
||||
nextAutoCatalogNumber(0xfffffffe)
|
||||
{
|
||||
if (static_cast<unsigned int>(catalog) >= crossIndexes.size())
|
||||
return NULL;
|
||||
crossIndexes.resize(MaxCatalog);
|
||||
}
|
||||
|
||||
CrossIndex* xindex = crossIndexes[catalog];
|
||||
if (xindex == NULL)
|
||||
return NULL;
|
||||
|
||||
CrossIndexEntry xindexEnt;
|
||||
xindexEnt.catalogNumber = number;
|
||||
StarDatabase::~StarDatabase()
|
||||
{
|
||||
if (stars != NULL)
|
||||
delete [] stars;
|
||||
|
||||
CrossIndex::iterator iter = lower_bound(xindex->begin(), xindex->end(),
|
||||
xindexEnt);
|
||||
if (iter == xindex->end() || iter->catalogNumber != number)
|
||||
return NULL;
|
||||
if (catalogNumberIndex != NULL)
|
||||
delete [] catalogNumberIndex;
|
||||
|
||||
for (vector<CrossIndex*>::iterator iter = crossIndexes.begin(); iter != crossIndexes.end(); ++iter)
|
||||
{
|
||||
if (*iter != NULL)
|
||||
delete *iter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Star* StarDatabase::find(const uint32 catalogNumber) const
|
||||
{
|
||||
Star refStar;
|
||||
refStar.setCatalogNumber(catalogNumber);
|
||||
|
||||
Star** star = lower_bound(catalogNumberIndex,
|
||||
catalogNumberIndex + nStars,
|
||||
&refStar,
|
||||
PtrCatalogNumberOrderingPredicate());
|
||||
|
||||
if (star != catalogNumberIndex + nStars && (*star)->getCatalogNumber() == catalogNumber)
|
||||
return *star;
|
||||
else
|
||||
return find(iter->celCatalogNumber);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -287,9 +245,9 @@ Star* StarDatabase::find(const string& name) const
|
|||
}
|
||||
else
|
||||
{
|
||||
if (names != NULL)
|
||||
if (namesDB != NULL)
|
||||
{
|
||||
uint32 catalogNumber = names->findName(name);
|
||||
uint32 catalogNumber = namesDB->findCatalogNumberByName(name);
|
||||
if (catalogNumber != Star::InvalidCatalogNumber)
|
||||
return find(catalogNumber);
|
||||
}
|
||||
|
@ -298,13 +256,56 @@ Star* StarDatabase::find(const string& name) const
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> StarDatabase::getCompletion(const string& name) const
|
||||
|
||||
uint32 StarDatabase::crossIndex(const Catalog catalog, const uint32 celCatalogNumber) const
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
if (static_cast<uint32>(catalog) >= crossIndexes.size())
|
||||
return Star::InvalidCatalogNumber;
|
||||
|
||||
CrossIndex* xindex = crossIndexes[catalog];
|
||||
if (xindex == NULL)
|
||||
return Star::InvalidCatalogNumber;
|
||||
|
||||
// A simple linear search. We could store cross indices sorted by
|
||||
// both catalog numbers and trade memory for speed
|
||||
for (CrossIndex::const_iterator iter = xindex->begin(); iter != xindex->end(); iter++)
|
||||
{
|
||||
if (celCatalogNumber == iter->celCatalogNumber)
|
||||
return iter->catalogNumber;
|
||||
}
|
||||
|
||||
return Star::InvalidCatalogNumber;
|
||||
}
|
||||
|
||||
|
||||
Star* StarDatabase::searchCrossIndex(const Catalog catalog, const uint32 number) const
|
||||
{
|
||||
if (static_cast<unsigned int>(catalog) >= crossIndexes.size())
|
||||
return NULL;
|
||||
|
||||
CrossIndex* xindex = crossIndexes[catalog];
|
||||
if (xindex == NULL)
|
||||
return NULL;
|
||||
|
||||
CrossIndexEntry xindexEnt;
|
||||
xindexEnt.catalogNumber = number;
|
||||
|
||||
CrossIndex::iterator iter = lower_bound(xindex->begin(), xindex->end(),
|
||||
xindexEnt);
|
||||
if (iter == xindex->end() || iter->catalogNumber != number)
|
||||
return NULL;
|
||||
else
|
||||
return find(iter->celCatalogNumber);
|
||||
}
|
||||
|
||||
|
||||
vector<string> StarDatabase::getCompletion(const string& name) const
|
||||
{
|
||||
vector<string> completion;
|
||||
|
||||
// only named stars are supported by completion.
|
||||
if (!name.empty() && names != NULL)
|
||||
return names->getCompletion(name);
|
||||
if (!name.empty() && namesDB != NULL)
|
||||
return namesDB->getCompletion(name);
|
||||
else
|
||||
return completion;
|
||||
}
|
||||
|
@ -327,10 +328,10 @@ string StarDatabase::getStarName(const Star& star) const
|
|||
{
|
||||
uint32 catalogNumber = star.getCatalogNumber();
|
||||
|
||||
if (names != NULL)
|
||||
if (namesDB != NULL)
|
||||
{
|
||||
StarNameDatabase::NumberIndex::const_iterator iter = getStarNames(catalogNumber);
|
||||
if (iter != finalName() && iter->first == catalogNumber)
|
||||
StarNameDatabase::NumberIndex::const_iterator iter = namesDB->getFirstNameIter(catalogNumber);
|
||||
if (iter != namesDB->getFinalNameIter() && iter->first == catalogNumber)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
@ -362,23 +363,77 @@ string StarDatabase::getStarName(const Star& star) const
|
|||
}
|
||||
|
||||
|
||||
StarNameDatabase::NumberIndex::const_iterator
|
||||
StarDatabase::getStarNames(uint32 catalogNumber) const
|
||||
string StarDatabase::getStarNameList(const Star& star, const unsigned int maxNames) const
|
||||
{
|
||||
// assert(names != NULL);
|
||||
return names->findFirstName(catalogNumber);
|
||||
string starNames;
|
||||
char numString[32];
|
||||
|
||||
unsigned int catalogNumber = star.getCatalogNumber();
|
||||
|
||||
StarNameDatabase::NumberIndex::const_iterator iter = namesDB->getFirstNameIter(catalogNumber);
|
||||
|
||||
unsigned int count = 0;
|
||||
while (iter != namesDB->getFinalNameIter() && iter->first == catalogNumber && count < maxNames)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
|
||||
starNames += ReplaceGreekLetterAbbr(_(iter->second.c_str()));
|
||||
++iter;
|
||||
++count;
|
||||
}
|
||||
|
||||
uint32 hip = catalogNumber;
|
||||
if (hip != Star::InvalidCatalogNumber && hip != 0 && count < maxNames)
|
||||
{
|
||||
if (hip <= Star::MaxTychoCatalogNumber)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
if (hip >= 1000000)
|
||||
{
|
||||
uint32 h = hip;
|
||||
uint32 tyc3 = h / 1000000000;
|
||||
h -= tyc3 * 1000000000;
|
||||
uint32 tyc2 = h / 10000;
|
||||
h -= tyc2 * 10000;
|
||||
uint32 tyc1 = h;
|
||||
|
||||
sprintf(numString, "TYC %u-%u-%u", tyc1, tyc2, tyc3);
|
||||
starNames += numString;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(numString, "HIP %u", hip);
|
||||
starNames += numString;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 hd = crossIndex(StarDatabase::HenryDraper, hip);
|
||||
if (count < maxNames && hd != Star::InvalidCatalogNumber)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
sprintf(numString, "HD %u", hd);
|
||||
starNames += numString;
|
||||
}
|
||||
|
||||
uint32 sao = crossIndex(StarDatabase::SAO, hip);
|
||||
if (count < maxNames && sao != Star::InvalidCatalogNumber)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
sprintf(numString, "SAO %u", sao);
|
||||
starNames += numString;
|
||||
}
|
||||
|
||||
return starNames;
|
||||
}
|
||||
|
||||
|
||||
StarNameDatabase::NumberIndex::const_iterator
|
||||
StarDatabase::finalName() const
|
||||
{
|
||||
// assert(names != NULL);
|
||||
return names->finalName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void StarDatabase::findVisibleStars(StarHandler& starHandler,
|
||||
const Point3f& position,
|
||||
const Quatf& orientation,
|
||||
|
@ -404,8 +459,11 @@ void StarDatabase::findVisibleStars(StarHandler& starHandler,
|
|||
frustumPlanes[i] = Planef(planeNormals[i], position);
|
||||
}
|
||||
|
||||
octreeRoot->findVisibleStars(starHandler, position, frustumPlanes,
|
||||
limitingMag, OctreeRootSize);
|
||||
octreeRoot->processVisibleObjects(starHandler,
|
||||
position,
|
||||
frustumPlanes,
|
||||
limitingMag,
|
||||
STAR_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -413,22 +471,26 @@ void StarDatabase::findCloseStars(StarHandler& starHandler,
|
|||
const Point3f& position,
|
||||
float radius) const
|
||||
{
|
||||
octreeRoot->findCloseStars(starHandler, position, radius, OctreeRootSize);
|
||||
octreeRoot->processCloseObjects(starHandler,
|
||||
position,
|
||||
radius,
|
||||
STAR_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
|
||||
|
||||
StarNameDatabase* StarDatabase::getNameDatabase() const
|
||||
{
|
||||
return names;
|
||||
return namesDB;
|
||||
}
|
||||
|
||||
void StarDatabase::setNameDatabase(StarNameDatabase* _names)
|
||||
|
||||
void StarDatabase::setNameDatabase(StarNameDatabase* _namesDB)
|
||||
{
|
||||
names = _names;
|
||||
namesDB = _namesDB;
|
||||
}
|
||||
|
||||
|
||||
bool StarDatabase::loadCrossIndex(Catalog catalog, istream& in)
|
||||
bool StarDatabase::loadCrossIndex(const Catalog catalog, istream& in)
|
||||
{
|
||||
if (static_cast<unsigned int>(catalog) >= crossIndexes.size())
|
||||
return false;
|
||||
|
@ -438,10 +500,10 @@ bool StarDatabase::loadCrossIndex(Catalog catalog, istream& in)
|
|||
|
||||
// Verify that the star database file has a correct header
|
||||
{
|
||||
int headerLength = strlen(CrossIndexFileHeader);
|
||||
int headerLength = strlen(CROSSINDEX_FILE_HEADER);
|
||||
char* header = new char[headerLength];
|
||||
in.read(header, headerLength);
|
||||
if (strncmp(header, CrossIndexFileHeader, headerLength))
|
||||
if (strncmp(header, CROSSINDEX_FILE_HEADER, headerLength))
|
||||
{
|
||||
cerr << _("Bad header for cross index\n");
|
||||
return false;
|
||||
|
@ -504,7 +566,7 @@ bool StarDatabase::loadOldFormatBinary(istream& in)
|
|||
if (!in.good())
|
||||
return false;
|
||||
|
||||
int requiredCapacity = (int) ((nStars + nStarsInFile) * (1.0 + ExtraRoom));
|
||||
int requiredCapacity = (int) ((nStars + nStarsInFile) * (1.0 + STAR_EXTRA_ROOM));
|
||||
if (capacity < requiredCapacity)
|
||||
{
|
||||
Star* newStars = new Star[requiredCapacity];
|
||||
|
@ -615,10 +677,10 @@ bool StarDatabase::loadBinary(istream& in)
|
|||
|
||||
// Verify that the star database file has a correct header
|
||||
{
|
||||
int headerLength = strlen(FileHeader);
|
||||
int headerLength = strlen(FILE_HEADER);
|
||||
char* header = new char[headerLength];
|
||||
in.read(header, headerLength);
|
||||
if (strncmp(header, FileHeader, headerLength))
|
||||
if (strncmp(header, FILE_HEADER, headerLength))
|
||||
return false;
|
||||
delete[] header;
|
||||
}
|
||||
|
@ -638,7 +700,7 @@ bool StarDatabase::loadBinary(istream& in)
|
|||
if (!in.good())
|
||||
return false;
|
||||
|
||||
int requiredCapacity = (int) ((nStars + nStarsInFile) * (1.0 + ExtraRoom));
|
||||
int requiredCapacity = (int) ((nStars + nStarsInFile) * (1.0 + STAR_EXTRA_ROOM));
|
||||
if (capacity < requiredCapacity)
|
||||
{
|
||||
Star* newStars = new Star[requiredCapacity];
|
||||
|
@ -749,53 +811,6 @@ void StarDatabase::finish()
|
|||
}
|
||||
|
||||
|
||||
void StarDatabase::buildOctree()
|
||||
{
|
||||
// This should only be called once for the database
|
||||
// ASSERT(octreeRoot == NULL);
|
||||
|
||||
DPRINTF(1, "Sorting stars into octree . . .\n");
|
||||
float absMag = astro::appToAbsMag(OctreeMagnitude,
|
||||
OctreeRootSize * (float) sqrt(3.0));
|
||||
DynamicStarOctree* root = new DynamicStarOctree(Point3f(1000, 1000, 1000),
|
||||
absMag);
|
||||
for (int i = 0; i < nStars; i++)
|
||||
root->insertStar(stars[i], OctreeRootSize);
|
||||
|
||||
DPRINTF(1, "Spatially sorting stars for improved locality of reference . . .\n");
|
||||
Star* sortedStars = new Star[nStars];
|
||||
Star* firstStar = sortedStars;
|
||||
root->rebuildAndSort(octreeRoot, firstStar);
|
||||
|
||||
// ASSERT((int) (firstStar - sortedStars) == nStars);
|
||||
DPRINTF(1, "%d stars total\n", (int) (firstStar - sortedStars));
|
||||
DPRINTF(1, "Octree has %d nodes and %d stars.\n",
|
||||
1 + octreeRoot->countChildren(), octreeRoot->countStars());
|
||||
|
||||
// Clean up . . .
|
||||
delete[] stars;
|
||||
delete root;
|
||||
|
||||
stars = sortedStars;
|
||||
}
|
||||
|
||||
|
||||
void StarDatabase::buildIndexes()
|
||||
{
|
||||
// This should only be called once for the database
|
||||
// assert(catalogNumberIndexes[0] == NULL);
|
||||
|
||||
DPRINTF(1, "Building catalog number indexes . . .\n");
|
||||
|
||||
catalogNumberIndex = new Star*[nStars];
|
||||
for (int i = 0; i < nStars; i++)
|
||||
catalogNumberIndex[i] = &stars[i];
|
||||
|
||||
sort(catalogNumberIndex, catalogNumberIndex + nStars,
|
||||
PtrCatalogNumberOrderingPredicate());
|
||||
}
|
||||
|
||||
|
||||
static void errorMessagePrelude(const Tokenizer& tok)
|
||||
{
|
||||
cerr << _("Error in .stc file (line ") << tok.getLineNumber() << "): ";
|
||||
|
@ -809,8 +824,7 @@ static void stcError(const Tokenizer& tok,
|
|||
}
|
||||
|
||||
|
||||
Star*
|
||||
StarDatabase::createStar(uint32 catalogNumber,
|
||||
Star* StarDatabase::createStar(const uint32 catalogNumber,
|
||||
Hash* starData,
|
||||
const string& path,
|
||||
bool isBarycenter)
|
||||
|
@ -906,7 +920,7 @@ StarDatabase::createStar(uint32 catalogNumber,
|
|||
string barycenterName;
|
||||
if (starData->getString("OrbitBarycenter", barycenterName))
|
||||
{
|
||||
uint32 barycenterCatNo = names->findCatalogNumber(barycenterName);
|
||||
uint32 barycenterCatNo = namesDB->findCatalogNumberByName(barycenterName);
|
||||
if (barycenterCatNo != Star::InvalidCatalogNumber)
|
||||
{
|
||||
// We can't actually resolve the barycenter catalog number
|
||||
|
@ -1069,11 +1083,11 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
catalogNumber = nextAutoCatalogNumber--;
|
||||
}
|
||||
|
||||
string name;
|
||||
string objName;
|
||||
if (tokenizer.getTokenType() == Tokenizer::TokenString)
|
||||
{
|
||||
// A star name (or names) is present
|
||||
name = tokenizer.getStringValue();
|
||||
objName = tokenizer.getStringValue();
|
||||
tokenizer.nextToken();
|
||||
}
|
||||
|
||||
|
@ -1093,8 +1107,7 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
}
|
||||
Hash* starData = starDataValue->getHash();
|
||||
|
||||
Star* star = createStar(catalogNumber, starData, resourcePath,
|
||||
!isStar);
|
||||
Star* star = createStar(catalogNumber, starData, resourcePath, !isStar);
|
||||
if (star != NULL)
|
||||
{
|
||||
// Ensure that the star array is large enough
|
||||
|
@ -1126,26 +1139,26 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
}
|
||||
stars[nStars++] = *star;
|
||||
|
||||
if (names != NULL && !name.empty())
|
||||
if (namesDB != NULL && !objName.empty())
|
||||
{
|
||||
// List of names will replace any that already exist for
|
||||
// List of namesDB will replace any that already exist for
|
||||
// this star.
|
||||
names->erase(catalogNumber);
|
||||
namesDB->erase(catalogNumber);
|
||||
|
||||
// Iterate through the string for names delimited
|
||||
// by ':', and insert them into the star database.
|
||||
// Note that db->add() will skip empty names.
|
||||
// Note that db->add() will skip empty namesDB.
|
||||
string::size_type startPos = 0;
|
||||
while (startPos != string::npos)
|
||||
{
|
||||
string::size_type next = name.find(':', startPos);
|
||||
string::size_type next = objName.find(':', startPos);
|
||||
string::size_type length = string::npos;
|
||||
if (next != string::npos)
|
||||
{
|
||||
length = next - startPos;
|
||||
next++;
|
||||
++next;
|
||||
}
|
||||
names->add(catalogNumber, name.substr(startPos, length));
|
||||
namesDB->add(catalogNumber, objName.substr(startPos, length));
|
||||
startPos = next;
|
||||
}
|
||||
}
|
||||
|
@ -1159,3 +1172,49 @@ bool StarDatabase::load(istream& in, const string& resourcePath)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
void StarDatabase::buildOctree()
|
||||
{
|
||||
// This should only be called once for the database
|
||||
// ASSERT(octreeRoot == NULL);
|
||||
|
||||
DPRINTF(1, "Sorting stars into octree . . .\n");
|
||||
float absMag = astro::appToAbsMag(STAR_OCTREE_MAGNITUDE,
|
||||
STAR_OCTREE_ROOT_SIZE * (float) sqrt(3.0));
|
||||
DynamicStarOctree* root = new DynamicStarOctree(Point3f(1000, 1000, 1000),
|
||||
absMag);
|
||||
for (int i=0; i<nStars; ++i)
|
||||
{
|
||||
root->insertObject(stars[i], STAR_OCTREE_ROOT_SIZE);
|
||||
}
|
||||
DPRINTF(1, "Spatially sorting stars for improved locality of reference . . .\n");
|
||||
Star* sortedStars = new Star[nStars];
|
||||
Star* firstStar = sortedStars;
|
||||
root->rebuildAndSort(octreeRoot, firstStar);
|
||||
|
||||
// ASSERT((int) (firstStar - sortedStars) == nStars);
|
||||
DPRINTF(1, "%d stars total\n", (int) (firstStar - sortedStars));
|
||||
DPRINTF(1, "Octree has %d nodes and %d stars.\n",
|
||||
1 + octreeRoot->countChildren(), octreeRoot->countObjects());
|
||||
|
||||
// Clean up . . .
|
||||
delete[] stars;
|
||||
delete root;
|
||||
|
||||
stars = sortedStars;
|
||||
}
|
||||
|
||||
|
||||
void StarDatabase::buildIndexes()
|
||||
{
|
||||
// This should only be called once for the database
|
||||
// assert(catalogNumberIndexes[0] == NULL);
|
||||
|
||||
DPRINTF(1, "Building catalog number indexes . . .\n");
|
||||
|
||||
catalogNumberIndex = new Star*[nStars];
|
||||
for (int i = 0; i < nStars; ++i)
|
||||
catalogNumberIndex[i] = &stars[i];
|
||||
|
||||
sort(catalogNumberIndex, catalogNumberIndex + nStars, PtrCatalogNumberOrderingPredicate());
|
||||
}
|
||||
|
|
|
@ -15,36 +15,41 @@
|
|||
#include <celengine/constellation.h>
|
||||
#include <celengine/starname.h>
|
||||
#include <celengine/star.h>
|
||||
#include <celengine/octree.h>
|
||||
#include <celengine/staroctree.h>
|
||||
#include <celengine/parser.h>
|
||||
|
||||
|
||||
static const unsigned int MAX_STAR_NAMES = 10;
|
||||
|
||||
|
||||
class StarDatabase
|
||||
{
|
||||
public:
|
||||
StarDatabase();
|
||||
~StarDatabase();
|
||||
|
||||
inline Star* getStar(uint32) const;
|
||||
|
||||
inline Star* getStar(const uint32) const;
|
||||
inline uint32 size() const;
|
||||
Star* find(uint32 catalogNumber) const;
|
||||
|
||||
Star* find(const uint32 catalogNumber) const;
|
||||
Star* find(const std::string&) const;
|
||||
|
||||
std::vector<std::string> getCompletion(const std::string&) const;
|
||||
|
||||
void findVisibleStars(StarHandler& starHandler,
|
||||
const Point3f& position,
|
||||
const Quatf& orientation,
|
||||
const Point3f& obsPosition,
|
||||
const Quatf& obsOrientation,
|
||||
float fovY,
|
||||
float aspectRatio,
|
||||
float limitingMag) const;
|
||||
|
||||
void findCloseStars(StarHandler& starHandler,
|
||||
const Point3f& position,
|
||||
const Point3f& obsPosition,
|
||||
float radius) const;
|
||||
|
||||
std::string getStarName(const Star&) const;
|
||||
StarNameDatabase::NumberIndex::const_iterator
|
||||
getStarNames(uint32 catalogNumber) const;
|
||||
StarNameDatabase::NumberIndex::const_iterator finalName() const;
|
||||
std::string getStarName (const Star&) const;
|
||||
std::string getStarNameList(const Star&, const unsigned int maxNames = MAX_STAR_NAMES) const;
|
||||
|
||||
StarNameDatabase* getNameDatabase() const;
|
||||
void setNameDatabase(StarNameDatabase*);
|
||||
|
@ -53,10 +58,10 @@ class StarDatabase
|
|||
bool loadBinary(std::istream&);
|
||||
bool loadOldFormatBinary(std::istream&);
|
||||
|
||||
Star* createStar(uint32 catalogNumber,
|
||||
Star* createStar(const uint32 catalogNumber,
|
||||
Hash* starData,
|
||||
const std::string& path,
|
||||
bool isBarycenter);
|
||||
const bool isBarycenter);
|
||||
|
||||
enum Catalog
|
||||
{
|
||||
|
@ -73,16 +78,17 @@ class StarDatabase
|
|||
};
|
||||
|
||||
typedef std::vector<CrossIndexEntry> CrossIndex;
|
||||
bool loadCrossIndex(Catalog, std::istream&);
|
||||
Star* searchCrossIndex(Catalog catalog, uint32 number) const;
|
||||
uint32 crossIndex(Catalog catalog, uint32 number) const;
|
||||
|
||||
bool loadCrossIndex (const Catalog, std::istream&);
|
||||
Star* searchCrossIndex(const Catalog, const uint32 number) const;
|
||||
uint32 crossIndex (const Catalog, const uint32 number) const;
|
||||
|
||||
void finish();
|
||||
|
||||
static StarDatabase* read(std::istream&);
|
||||
|
||||
static const char* FileHeader;
|
||||
static const char* CrossIndexFileHeader;
|
||||
static const char* FILE_HEADER;
|
||||
static const char* CROSSINDEX_FILE_HEADER;
|
||||
|
||||
private:
|
||||
void buildOctree();
|
||||
|
@ -91,13 +97,13 @@ class StarDatabase
|
|||
int nStars;
|
||||
int capacity;
|
||||
Star* stars;
|
||||
StarNameDatabase* names;
|
||||
StarNameDatabase* namesDB;
|
||||
Star** catalogNumberIndex;
|
||||
StarOctree* octreeRoot;
|
||||
uint32 nextAutoCatalogNumber;
|
||||
|
||||
std::vector<CrossIndex*> crossIndexes;
|
||||
|
||||
uint32 nextAutoCatalogNumber;
|
||||
|
||||
struct BarycenterUsage
|
||||
{
|
||||
|
@ -108,7 +114,7 @@ class StarDatabase
|
|||
};
|
||||
|
||||
|
||||
Star* StarDatabase::getStar(uint32 n) const
|
||||
Star* StarDatabase::getStar(const uint32 n) const
|
||||
{
|
||||
return stars + n;
|
||||
}
|
||||
|
|
|
@ -1,105 +1,96 @@
|
|||
// starname.cpp
|
||||
//
|
||||
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
|
||||
// C++ Implementation: starname
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
// 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 <string>
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef MACOSX
|
||||
#include <config.h>
|
||||
#endif /* ! MACOSX */
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
#include <celutil/util.h>
|
||||
#include <celutil/debug.h>
|
||||
#include <celutil/utf8.h>
|
||||
#include "celestia.h"
|
||||
#include "star.h"
|
||||
#include "starname.h"
|
||||
#include <celengine/constellation.h>
|
||||
#include <celengine/starname.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
StarNameDatabase::StarNameDatabase()
|
||||
{
|
||||
}
|
||||
|
||||
void StarNameDatabase::add(uint32 catalogNumber, const string& name)
|
||||
uint32 StarNameDatabase::findCatalogNumberByName(const string& name) const
|
||||
{
|
||||
if(name.length() != 0)
|
||||
string priName = name;
|
||||
string altName;
|
||||
|
||||
// See if the name is a Bayer or Flamsteed designation
|
||||
string::size_type pos = name.find(' ');
|
||||
if (pos != 0 && pos != string::npos && pos < name.length() - 1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
uint32 tmp;
|
||||
if((tmp=findName(name))!=Star::InvalidCatalogNumber)
|
||||
DPRINTF(2,"Duplicated name '%s' on HIP %d and %d\n", name.c_str(),
|
||||
tmp, catalogNumber);
|
||||
#endif
|
||||
// Add the new name
|
||||
//nameIndex.insert(NameIndex::value_type(name, catalogNumber));
|
||||
string prefix(name, 0, pos);
|
||||
string conName(name, pos + 1, string::npos);
|
||||
Constellation* con = Constellation::getConstellation(conName);
|
||||
if (con != NULL)
|
||||
{
|
||||
char digit = ' ';
|
||||
int len = prefix.length();
|
||||
|
||||
nameIndex[name] = catalogNumber;
|
||||
numberIndex.insert(NumberIndex::value_type(catalogNumber, name));
|
||||
// If the first character of the prefix is a letter
|
||||
// and the last character is a digit, we may have
|
||||
// something like 'Alpha2 Cen' . . . Extract the digit
|
||||
// before trying to match a Greek letter.
|
||||
if (len > 2 && isalpha(prefix[0]) && isdigit(prefix[len - 1]))
|
||||
{
|
||||
--len;
|
||||
digit = prefix[len];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StarNameDatabase::erase(uint32 catalogNumber)
|
||||
{
|
||||
numberIndex.erase(catalogNumber);
|
||||
}
|
||||
|
||||
|
||||
uint32 StarNameDatabase::findCatalogNumber(const string& name) const
|
||||
{
|
||||
NameIndex::const_iterator iter = nameIndex.find(name);
|
||||
if (iter == nameIndex.end())
|
||||
return Star::InvalidCatalogNumber;
|
||||
// We have a valid constellation as the last part
|
||||
// of the name. Next, we see if the first part of
|
||||
// the name is a greek letter.
|
||||
const string& letter = Greek::canonicalAbbreviation(string(prefix, 0, len));
|
||||
if (letter != "")
|
||||
{
|
||||
// Matched . . . this is a Bayer designation
|
||||
if (digit == ' ')
|
||||
{
|
||||
priName = letter + ' ' + con->getAbbreviation();
|
||||
// If 'let con' doesn't match, try using
|
||||
// 'let1 con' instead.
|
||||
altName = letter + '1' + ' ' + con->getAbbreviation();
|
||||
}
|
||||
else
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
std::vector<std::string> StarNameDatabase::getCompletion(const std::string& name) const
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
for (NameIndex::const_iterator iter = nameIndex.begin();
|
||||
iter != nameIndex.end() ; iter++)
|
||||
{
|
||||
if (!UTF8StringCompare(iter->first, name, name.length()))
|
||||
priName = letter + digit + ' ' + con->getAbbreviation();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
completion.push_back(iter->first);
|
||||
// Something other than a Bayer designation
|
||||
priName = prefix + ' ' + con->getAbbreviation();
|
||||
}
|
||||
}
|
||||
}
|
||||
return completion;
|
||||
}
|
||||
|
||||
uint32 catalogNumber = getCatalogNumberByName(priName);
|
||||
if (catalogNumber != Star::InvalidCatalogNumber)
|
||||
return catalogNumber;
|
||||
|
||||
// Return the first name matching the catalog number or finalName()
|
||||
// if there are no matching names. The first name *should* be the
|
||||
// proper name of the star, if one exists. This requires that the
|
||||
// star name database file to have the proper names listed before
|
||||
// Bayer and other designations. Also, the STL implementation must
|
||||
// preserve this order when inserting the names into the multimap
|
||||
// (not certain whether or not this is behavior is in the STL spec.,
|
||||
// but it works on the implementations I've tried so far.)
|
||||
StarNameDatabase::NumberIndex::const_iterator
|
||||
StarNameDatabase::findFirstName(uint32 catalogNumber) const
|
||||
{
|
||||
NumberIndex::const_iterator iter = numberIndex.lower_bound(catalogNumber);
|
||||
if (iter == numberIndex.end() || iter->first != catalogNumber)
|
||||
return finalName();
|
||||
else
|
||||
return iter;
|
||||
}
|
||||
priName += " A"; // try by appending an A
|
||||
catalogNumber = getCatalogNumberByName(priName);
|
||||
if (catalogNumber != Star::InvalidCatalogNumber)
|
||||
return catalogNumber;
|
||||
|
||||
// If the first search failed, try using the alternate name
|
||||
if (altName.length() != 0)
|
||||
{
|
||||
catalogNumber = getCatalogNumberByName(altName);
|
||||
if (catalogNumber == Star::InvalidCatalogNumber)
|
||||
{
|
||||
altName += " A";
|
||||
catalogNumber = getCatalogNumberByName(altName);
|
||||
} // Intentional fallthrough.
|
||||
}
|
||||
|
||||
StarNameDatabase::NumberIndex::const_iterator
|
||||
StarNameDatabase::finalName() const
|
||||
{
|
||||
return numberIndex.end();
|
||||
return catalogNumber;
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,11 +129,13 @@ StarNameDatabase* StarNameDatabase::readNames(istream& in)
|
|||
string::size_type startPos = 0;
|
||||
while (startPos != string::npos)
|
||||
{
|
||||
startPos++;
|
||||
++startPos;
|
||||
string::size_type next = name.find(':', startPos);
|
||||
string::size_type length = string::npos;
|
||||
|
||||
if (next != string::npos)
|
||||
length = next - startPos;
|
||||
|
||||
db->add(catalogNumber, name.substr(startPos, length));
|
||||
startPos = next;
|
||||
}
|
||||
|
@ -158,81 +151,3 @@ StarNameDatabase* StarNameDatabase::readNames(istream& in)
|
|||
return db;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32 StarNameDatabase::findName(string name) const
|
||||
{
|
||||
string priName = name;
|
||||
string altName;
|
||||
// See if the name is a Bayer or Flamsteed designation
|
||||
string::size_type pos = name.find(' ');
|
||||
if (pos != 0 && pos != string::npos && pos < name.length() - 1)
|
||||
{
|
||||
string prefix(name, 0, pos);
|
||||
string conName(name, pos + 1, string::npos);
|
||||
Constellation* con = Constellation::getConstellation(conName);
|
||||
if (con != NULL)
|
||||
{
|
||||
char digit = ' ';
|
||||
int len = prefix.length();
|
||||
|
||||
// If the first character of the prefix is a letter
|
||||
// and the last character is a digit, we may have
|
||||
// something like 'Alpha2 Cen' . . . Extract the digit
|
||||
// before trying to match a Greek letter.
|
||||
if (len > 2 &&
|
||||
isalpha(prefix[0]) && isdigit(prefix[len - 1]))
|
||||
{
|
||||
len--;
|
||||
digit = prefix[len];
|
||||
}
|
||||
|
||||
// We have a valid constellation as the last part
|
||||
// of the name. Next, we see if the first part of
|
||||
// the name is a greek letter.
|
||||
const string& letter = Greek::canonicalAbbreviation(string(prefix, 0, len));
|
||||
if (letter != "")
|
||||
{
|
||||
// Matched . . . this is a Bayer designation
|
||||
if (digit == ' ')
|
||||
{
|
||||
priName = letter + ' ' + con->getAbbreviation();
|
||||
// If 'let con' doesn't match, try using
|
||||
// 'let1 con' instead.
|
||||
altName = letter + '1' + ' ' + con->getAbbreviation();
|
||||
}
|
||||
else
|
||||
{
|
||||
priName = letter + digit + ' ' + con->getAbbreviation();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something other than a Bayer designation
|
||||
priName = prefix + ' ' + con->getAbbreviation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 catalogNumber = findCatalogNumber(priName);
|
||||
if (catalogNumber != Star::InvalidCatalogNumber)
|
||||
return catalogNumber;
|
||||
priName += " A"; // try by appending an A
|
||||
catalogNumber = findCatalogNumber(priName);
|
||||
if (catalogNumber != Star::InvalidCatalogNumber)
|
||||
return catalogNumber;
|
||||
|
||||
// If the first search failed, try using the alternate name
|
||||
if (altName.length() != 0)
|
||||
{
|
||||
catalogNumber = findCatalogNumber(altName);
|
||||
if (catalogNumber == Star::InvalidCatalogNumber)
|
||||
{
|
||||
altName += " A";
|
||||
catalogNumber = findCatalogNumber(altName);
|
||||
} // Intentional fallthrough.
|
||||
}
|
||||
return catalogNumber;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,48 +1,31 @@
|
|||
// starname.h
|
||||
//
|
||||
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
|
||||
// C++ Interface: starname
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef _STARNAME_H_
|
||||
#define _STARNAME_H_
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <celutil/basictypes.h>
|
||||
#include <celutil/util.h>
|
||||
#include <celengine/constellation.h>
|
||||
#include <celengine/name.h>
|
||||
#include <celengine/star.h>
|
||||
|
||||
|
||||
class StarNameDatabase
|
||||
class StarNameDatabase: public NameDatabase<Star>
|
||||
{
|
||||
public:
|
||||
StarNameDatabase();
|
||||
StarNameDatabase() {};
|
||||
|
||||
typedef std::map<std::string, uint32, CompareIgnoringCasePredicate> NameIndex;
|
||||
typedef std::multimap<uint32, std::string> NumberIndex;
|
||||
|
||||
void add(uint32, const std::string&);
|
||||
|
||||
// Delete all names associated with the specified catalog number
|
||||
void erase(uint32);
|
||||
|
||||
uint32 findCatalogNumber(const std::string& name) const;
|
||||
uint32 findName(std::string name) const;
|
||||
std::vector<std::string> getCompletion(const std::string& name) const;
|
||||
NumberIndex::const_iterator findFirstName(uint32 catalogNumber) const;
|
||||
NumberIndex::const_iterator finalName() const;
|
||||
uint32 findCatalogNumberByName(const std::string&) const;
|
||||
|
||||
static StarNameDatabase* readNames(std::istream&);
|
||||
|
||||
private:
|
||||
NameIndex nameIndex;
|
||||
NumberIndex numberIndex;
|
||||
};
|
||||
|
||||
#endif // _STARNAME_H_
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
//
|
||||
// C++ Implementation: staroctree
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#include <celengine/staroctree.h>
|
||||
|
||||
|
||||
// The octree node into which a star is placed is dependent on two properties:
|
||||
// its obsPosition and its luminosity--the fainter the star, the deeper the node
|
||||
// in which it will reside. Each node stores an absolute magnitude; no child
|
||||
// of the node is allowed contain a star brighter than this value, making it
|
||||
// possible to determine quickly whether or not to cull subtrees.
|
||||
|
||||
bool starAbsoluteMagnitudePredicate(const Star& star, const float absMag)
|
||||
{
|
||||
return star.getAbsoluteMagnitude() <= absMag;
|
||||
}
|
||||
|
||||
|
||||
bool starOrbitStraddlesNodesPredicate(const Point3f& cellCenterPos, const Star& star, const float absMag)
|
||||
{
|
||||
//checks if this star's orbit straddles child nodes
|
||||
float orbitalRadius = star.getOrbitalRadius();
|
||||
if (orbitalRadius == 0.0f)
|
||||
return false;
|
||||
|
||||
Point3f starPos = star.getPosition();
|
||||
|
||||
return abs(starPos.x - cellCenterPos.x) < orbitalRadius ||
|
||||
abs(starPos.y - cellCenterPos.y) < orbitalRadius ||
|
||||
abs(starPos.z - cellCenterPos.z) < orbitalRadius;
|
||||
}
|
||||
|
||||
|
||||
float starAbsoluteMagnitudeDecayFunction(const float excludingFactor)
|
||||
{
|
||||
return astro::lumToAbsMag(astro::absMagToLum(excludingFactor) / 4.0f);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
DynamicStarOctree* DynamicStarOctree::getChild(const Star& obj,
|
||||
const Point3f& cellCenterPos)
|
||||
{
|
||||
Point3f objPos = obj.getPosition();
|
||||
|
||||
int child = 0;
|
||||
child |= objPos.x < cellCenterPos.x ? 0 : XPos;
|
||||
child |= objPos.y < cellCenterPos.y ? 0 : YPos;
|
||||
child |= objPos.z < cellCenterPos.z ? 0 : ZPos;
|
||||
|
||||
return _children[child];
|
||||
}
|
||||
|
||||
|
||||
// In testing, changing SPLIT_THRESHOLD from 100 to 50 nearly
|
||||
// doubled the number of nodes in the tree, but provided only between a
|
||||
// 0 to 5 percent frame rate improvement.
|
||||
template<> unsigned int DynamicStarOctree::SPLIT_THRESHOLD = 75;
|
||||
template<> DynamicStarOctree::LimitingFactorPredicate*
|
||||
DynamicStarOctree::limitingFactorPredicate = starAbsoluteMagnitudePredicate;
|
||||
template<> DynamicStarOctree::StraddlingPredicate*
|
||||
DynamicStarOctree::straddlingPredicate = starOrbitStraddlesNodesPredicate;
|
||||
template<> DynamicStarOctree::ExclusionFactorDecayFunction*
|
||||
DynamicStarOctree::decayFunction = starAbsoluteMagnitudeDecayFunction;
|
||||
|
||||
|
||||
// total specialization of the StaticOctree template process*() methods for stars:
|
||||
template<>
|
||||
void StarOctree::processVisibleObjects(StarHandler& processor,
|
||||
const Point3f& obsPosition,
|
||||
const Planef* frustumPlanes,
|
||||
float limitingFactor,
|
||||
float scale) const
|
||||
{
|
||||
// See if this node lies within the view frustum
|
||||
|
||||
// Test the cubic octree node against each one of the five
|
||||
// planes that define the infinite view frustum.
|
||||
for (int i=0; i<5; ++i)
|
||||
{
|
||||
const Planef* plane = frustumPlanes + i;
|
||||
float r = scale * (abs(plane->normal.x) +
|
||||
abs(plane->normal.y) +
|
||||
abs(plane->normal.z));
|
||||
|
||||
if (plane->normal * Vec3f(cellCenterPos.x, cellCenterPos.y, cellCenterPos.z) - plane->d < -r)
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the distance to node; this is equal to the distance to
|
||||
// the cellCenterPos of the node minus the boundingRadius of the node, scale * SQRT3.
|
||||
float minDistance = (obsPosition - cellCenterPos).length() - scale * StarOctree::SQRT3;
|
||||
|
||||
// Process the objects in this node
|
||||
float dimmest = minDistance > 0 ? astro::appToAbsMag(limitingFactor, minDistance) : 1000;
|
||||
|
||||
for (unsigned int i=0; i<nObjects; ++i)
|
||||
{
|
||||
Star& obj = _firstObject[i];
|
||||
|
||||
if (obj.getAbsoluteMagnitude() < dimmest)
|
||||
{
|
||||
float distance = obsPosition.distanceTo(obj.getPosition());
|
||||
float appMag = astro::absToAppMag(obj.getAbsoluteMagnitude(), distance);
|
||||
|
||||
if (appMag < limitingFactor)
|
||||
processor.process(obj, distance, appMag);
|
||||
}
|
||||
}
|
||||
|
||||
// See if any of the objects in child nodes are potentially included
|
||||
// that we need to recurse deeper.
|
||||
if (minDistance <= 0 || astro::absToAppMag(exclusionFactor, minDistance) <= limitingFactor)
|
||||
// Recurse into the child nodes
|
||||
if (_children != NULL)
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
_children[i]->processVisibleObjects(processor,
|
||||
obsPosition,
|
||||
frustumPlanes,
|
||||
limitingFactor,
|
||||
scale * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void StarOctree::processCloseObjects(StarHandler& processor,
|
||||
const Point3f& obsPosition,
|
||||
float boundingRadius,
|
||||
float scale) const
|
||||
{
|
||||
// Compute the distance to node; this is equal to the distance to
|
||||
// the cellCenterPos of the node minus the boundingRadius of the node, scale * SQRT3.
|
||||
float nodeDistance = (obsPosition - cellCenterPos).length() - scale * StarOctree::SQRT3;
|
||||
|
||||
if (nodeDistance > boundingRadius)
|
||||
return;
|
||||
|
||||
// At this point, we've determined that the cellCenterPos of the node is
|
||||
// close enough that we must check individual objects for proximity.
|
||||
|
||||
// Compute distance squared to avoid having to sqrt for distance
|
||||
// comparison.
|
||||
float radiusSquared = boundingRadius * boundingRadius;
|
||||
|
||||
// Check all the objects in the node.
|
||||
for (unsigned int i = 0; i < nObjects; ++i)
|
||||
{
|
||||
Star& obj = _firstObject[i];
|
||||
|
||||
if (obsPosition.distanceToSquared(obj.getPosition()) < radiusSquared)
|
||||
{
|
||||
float distance = obsPosition.distanceTo(obj.getPosition());
|
||||
float appMag = astro::absToAppMag(obj.getAbsoluteMagnitude(), distance);
|
||||
|
||||
processor.process(obj, distance, appMag);
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into the child nodes
|
||||
if (_children != NULL)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
_children[i]->processCloseObjects(processor,
|
||||
obsPosition,
|
||||
boundingRadius,
|
||||
scale * 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// C++ Interface: staroctree
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
//
|
||||
// Author: Toti <root@totibox>, (C) 2005
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _STAROCTREE_H_
|
||||
#define _STAROCTREE_H_
|
||||
|
||||
#include <celengine/star.h>
|
||||
#include <celengine/octree.h>
|
||||
|
||||
|
||||
typedef DynamicOctree <Star, float> DynamicStarOctree;
|
||||
typedef StaticOctree <Star, float> StarOctree;
|
||||
typedef OctreeProcessor<Star, float> StarHandler;
|
||||
|
||||
#endif // _STAROCTREE_H_
|
|
@ -19,14 +19,15 @@
|
|||
#include "meshmanager.h"
|
||||
#include "universe.h"
|
||||
|
||||
#define ANGULAR_RES 3.5e-6
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define ANGULAR_RES 3.5e-6
|
||||
|
||||
Universe::Universe() :
|
||||
starCatalog(NULL),
|
||||
solarSystemCatalog(NULL),
|
||||
deepSkyCatalog(NULL),
|
||||
dsoCatalog(NULL),
|
||||
asterisms(NULL),
|
||||
/*boundaries(NULL),*/
|
||||
markers(NULL)
|
||||
|
@ -63,14 +64,14 @@ void Universe::setSolarSystemCatalog(SolarSystemCatalog* catalog)
|
|||
}
|
||||
|
||||
|
||||
DeepSkyCatalog* Universe::getDeepSkyCatalog() const
|
||||
DSODatabase* Universe::getDSOCatalog() const
|
||||
{
|
||||
return deepSkyCatalog;
|
||||
return dsoCatalog;
|
||||
}
|
||||
|
||||
void Universe::setDeepSkyCatalog(DeepSkyCatalog* catalog)
|
||||
void Universe::setDSOCatalog(DSODatabase* catalog)
|
||||
{
|
||||
deepSkyCatalog = catalog;
|
||||
dsoCatalog = catalog;
|
||||
}
|
||||
|
||||
|
||||
|
@ -319,7 +320,9 @@ static bool ApproxPlanetPickTraversal(Body* body, void* info)
|
|||
|
||||
if ((pickInfo->atanTolerance > ANGULAR_RES ? pickInfo->atanTolerance:
|
||||
ANGULAR_RES) > appOrbitRadius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bodyDir.normalize();
|
||||
Vec3d bodyMiss = bodyDir - pickInfo->pickRay.direction;
|
||||
|
@ -712,39 +715,172 @@ Selection Universe::pickStar(const UniversalCoord& origin,
|
|||
}
|
||||
|
||||
|
||||
class DSOPicker : public DSOHandler
|
||||
{
|
||||
public:
|
||||
DSOPicker(const Point3d&, const Vec3d&, float);
|
||||
~DSOPicker() {};
|
||||
|
||||
void process(DeepSkyObject* const &, double, float);
|
||||
|
||||
public:
|
||||
const DeepSkyObject* pickedDSO;
|
||||
Point3d pickOrigin;
|
||||
Vec3d pickDir;
|
||||
double sinAngle2Closest;
|
||||
};
|
||||
|
||||
|
||||
DSOPicker::DSOPicker(const Point3d& pickOrigin,
|
||||
const Vec3d& pickDir,
|
||||
float angle) :
|
||||
pickedDSO (NULL),
|
||||
pickOrigin (pickOrigin),
|
||||
pickDir (pickDir),
|
||||
sinAngle2Closest(sin(angle/2.0) > ANGULAR_RES ? sin(angle/2.0) :
|
||||
ANGULAR_RES )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void DSOPicker::process(DeepSkyObject* const & dso, double distance, float appMag)
|
||||
{
|
||||
Vec3d relativeDSOPos = dso->getPosition() - pickOrigin;
|
||||
Vec3d dsoDir = relativeDSOPos;
|
||||
dsoDir.normalize();
|
||||
|
||||
double sinAngle2 = 0.0;
|
||||
|
||||
double distance2;
|
||||
if (testIntersection(Ray3d(Point3d(0.0, 0.0, 0.0), pickDir),
|
||||
Sphered(Point3d(0.0, 0.0, 0.0) + relativeDSOPos, (double) dso->getRadius()), distance2))
|
||||
{
|
||||
Point3d dsoPos = dso->getPosition();
|
||||
dsoDir = Vec3d(dsoPos.x * 1.0e-6 - pickOrigin.x,
|
||||
dsoPos.y * 1.0e-6 - pickOrigin.y,
|
||||
dsoPos.z * 1.0e-6 - pickOrigin.z);
|
||||
dsoDir.normalize();
|
||||
}
|
||||
|
||||
Vec3d dsoMissd = dsoDir - Vec3d(pickDir.x, pickDir.y, pickDir.z);
|
||||
sinAngle2 = sqrt(dsoMissd * dsoMissd)/2.0;
|
||||
|
||||
if (sinAngle2 <= sinAngle2Closest)
|
||||
{
|
||||
sinAngle2Closest = sinAngle2 > ANGULAR_RES ? sinAngle2 : ANGULAR_RES;
|
||||
pickedDSO = dso;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CloseDSOPicker : public DSOHandler
|
||||
{
|
||||
public:
|
||||
CloseDSOPicker(const Point3d& pos,
|
||||
const Vec3d& dir,
|
||||
double maxDistance,
|
||||
float angle);
|
||||
~CloseDSOPicker() {};
|
||||
|
||||
void process(DeepSkyObject* const & dso, double distance, float appMag);
|
||||
|
||||
public:
|
||||
Point3d pickOrigin;
|
||||
Vec3d pickDir;
|
||||
double maxDistance;
|
||||
const DeepSkyObject* closestDSO;
|
||||
double closestDistance;
|
||||
};
|
||||
|
||||
|
||||
CloseDSOPicker::CloseDSOPicker(const Point3d& pos,
|
||||
const Vec3d& dir,
|
||||
double maxDistance,
|
||||
float angle) :
|
||||
pickOrigin (pos),
|
||||
pickDir (dir),
|
||||
maxDistance (maxDistance),
|
||||
closestDSO (NULL),
|
||||
closestDistance(1.0e32)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CloseDSOPicker::process(DeepSkyObject* const & dso,
|
||||
double distance,
|
||||
float appMag)
|
||||
{
|
||||
|
||||
if (distance > maxDistance)
|
||||
return;
|
||||
|
||||
double distance2 = 0.0;
|
||||
if (testIntersection(Ray3d(pickOrigin, pickDir),
|
||||
Sphered(dso->getPosition(), (double) dso->getRadius()),
|
||||
distance2))
|
||||
{
|
||||
// Don't select the object the observer is currently in:
|
||||
if (pickOrigin.distanceTo(dso->getPosition()) > dso->getRadius() &&
|
||||
distance2 < closestDistance)
|
||||
{
|
||||
closestDSO = dso;
|
||||
closestDistance = distance2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Selection Universe::pickDeepSkyObject(const UniversalCoord& origin,
|
||||
const Vec3f& direction,
|
||||
float faintestMag,
|
||||
float tolerance)
|
||||
{
|
||||
Selection sel;
|
||||
Point3d p = (Point3d) origin;
|
||||
Ray3d pickRay(Point3d(p.x * 1e-6, p.y * 1e-6, p.z * 1e-6),
|
||||
Vec3d(direction.x, direction.y, direction.z));
|
||||
double closestDistance = 1.0e30;
|
||||
Point3d orig = (Point3d) origin;
|
||||
orig.x *= 1e-6;
|
||||
orig.y *= 1e-6;
|
||||
orig.z *= 1e-6;
|
||||
|
||||
if (deepSkyCatalog != NULL)
|
||||
Vec3d dir = Vec3d(direction.x, direction.y, direction.z);
|
||||
|
||||
CloseDSOPicker closePicker(orig, dir, 1e9, tolerance);
|
||||
|
||||
dsoCatalog->findCloseDSOs(closePicker, orig, 1e9);
|
||||
if (closePicker.closestDSO != NULL)
|
||||
{
|
||||
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
|
||||
iter != deepSkyCatalog->end(); iter++)
|
||||
{
|
||||
double distance = 0.0;
|
||||
if (testIntersection(pickRay,
|
||||
Sphered((*iter)->getPosition(), (*iter)->getRadius()),
|
||||
distance))
|
||||
{
|
||||
// Don't select an object that contains the origin
|
||||
if (pickRay.origin.distanceTo((*iter)->getPosition()) > (*iter)->getRadius() &&
|
||||
distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
sel = Selection(*iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Selection(const_cast<DeepSkyObject*>(closePicker.closestDSO));
|
||||
}
|
||||
|
||||
return sel;
|
||||
Quatf rotation;
|
||||
Vec3d n(0, 0, -1);
|
||||
Vec3d Miss = n - dir;
|
||||
double sinAngle2 = sqrt(Miss * Miss)/2.0;
|
||||
|
||||
if (sinAngle2 <= ANGULAR_RES)
|
||||
{
|
||||
rotation.setAxisAngle(Vec3f(1, 0, 0), 0);
|
||||
}
|
||||
else if (sinAngle2 >= 1.0 - 0.5 * ANGULAR_RES * ANGULAR_RES)
|
||||
{
|
||||
rotation.setAxisAngle(Vec3f(1, 0, 0), (float) PI);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3f axis = direction ^ Vec3f((float)n.x, (float)n.y, (float)n.z);
|
||||
axis.normalize();
|
||||
rotation.setAxisAngle(axis, (float) (2.0 * asin(sinAngle2)));
|
||||
}
|
||||
|
||||
DSOPicker picker(orig, dir, tolerance);
|
||||
dsoCatalog->findVisibleDSOs(picker,
|
||||
orig,
|
||||
rotation,
|
||||
tolerance,
|
||||
1.0f,
|
||||
faintestMag);
|
||||
if (picker.pickedDSO != NULL)
|
||||
return Selection(const_cast<DeepSkyObject*>(picker.pickedDSO));
|
||||
else
|
||||
return Selection();
|
||||
}
|
||||
|
||||
|
||||
|
@ -909,21 +1045,21 @@ Selection Universe::find(const string& s,
|
|||
int nContexts,
|
||||
bool i18n)
|
||||
{
|
||||
if (deepSkyCatalog != NULL)
|
||||
if (starCatalog != NULL)
|
||||
{
|
||||
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
|
||||
iter != deepSkyCatalog->end(); iter++)
|
||||
{
|
||||
if (UTF8StringCompare((*iter)->getName(), s) == 0)
|
||||
return Selection(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
Star* star = starCatalog->find(s);
|
||||
if (star != NULL)
|
||||
return Selection(star);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nContexts; i++)
|
||||
if (dsoCatalog != NULL)
|
||||
{
|
||||
DeepSkyObject* dso = dsoCatalog->find(s);
|
||||
if (dso != NULL)
|
||||
return Selection(dso);
|
||||
}
|
||||
|
||||
for (int i=0; i<nContexts; ++i)
|
||||
{
|
||||
Selection sel = findObjectInContext(contexts[i], s, i18n);
|
||||
if (!sel.empty())
|
||||
|
@ -975,19 +1111,19 @@ Selection Universe::findPath(const string& s,
|
|||
}
|
||||
|
||||
|
||||
std::vector<std::string> Universe::getCompletion(const string& s,
|
||||
vector<string> Universe::getCompletion(const string& s,
|
||||
Selection* contexts,
|
||||
int nContexts,
|
||||
bool withLocations)
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
vector<string> completion;
|
||||
|
||||
// Solar bodies first
|
||||
// Solar bodies first:
|
||||
for (int i = 0; i < nContexts; i++)
|
||||
{
|
||||
if (withLocations && contexts[i].getType() == Selection::Type_Body)
|
||||
{
|
||||
std::vector<Location*>* locations = contexts[i].body()->getLocations();
|
||||
vector<Location*>* locations = contexts[i].body()->getLocations();
|
||||
if (locations != NULL)
|
||||
{
|
||||
for (vector<Location*>::const_iterator iter = locations->begin();
|
||||
|
@ -1005,38 +1141,38 @@ std::vector<std::string> Universe::getCompletion(const string& s,
|
|||
PlanetarySystem* planets = sys->getPlanets();
|
||||
if (planets != NULL)
|
||||
{
|
||||
std::vector<std::string> bodies = planets->getCompletion(s);
|
||||
vector<string> bodies = planets->getCompletion(s);
|
||||
completion.insert(completion.end(),
|
||||
bodies.begin(), bodies.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deep sky object
|
||||
if (deepSkyCatalog != NULL)
|
||||
{
|
||||
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
|
||||
iter != deepSkyCatalog->end(); iter++)
|
||||
// Deep sky objects:
|
||||
if (dsoCatalog != NULL)
|
||||
{
|
||||
if (UTF8StringCompare((*iter)->getName(), s, s.length()) == 0)
|
||||
completion.push_back(Selection(*iter).getName());
|
||||
}
|
||||
vector<string> dsos = dsoCatalog->getCompletion(s);
|
||||
completion.insert(completion.end(), dsos.begin(), dsos.end());
|
||||
}
|
||||
|
||||
// finally stars;
|
||||
std::vector<std::string> stars = starCatalog->getCompletion(s);
|
||||
// and finally stars;
|
||||
if (starCatalog != NULL)
|
||||
{
|
||||
vector<string> stars = starCatalog->getCompletion(s);
|
||||
completion.insert(completion.end(), stars.begin(), stars.end());
|
||||
}
|
||||
|
||||
return completion;
|
||||
}
|
||||
|
||||
std::vector<std::string> Universe::getCompletionPath(const string& s,
|
||||
|
||||
vector<string> Universe::getCompletionPath(const string& s,
|
||||
Selection* contexts,
|
||||
int nContexts,
|
||||
bool withLocations)
|
||||
{
|
||||
std::vector<std::string> completion;
|
||||
std::vector<std::string> locationCompletion;
|
||||
vector<string> completion;
|
||||
vector<string> locationCompletion;
|
||||
string::size_type pos = s.rfind('/', s.length());
|
||||
|
||||
if (pos == string::npos)
|
||||
|
@ -1045,20 +1181,23 @@ std::vector<std::string> Universe::getCompletionPath(const string& s,
|
|||
string base(s, 0, pos);
|
||||
Selection sel = findPath(base, contexts, nContexts, true);
|
||||
|
||||
if (sel.empty()){ std::cerr << "nothing found" << std::endl;
|
||||
if (sel.empty())
|
||||
{
|
||||
cerr << "nothing found" << endl;
|
||||
return completion;
|
||||
}
|
||||
}
|
||||
|
||||
if (sel.getType() == Selection::Type_DeepSky)
|
||||
{
|
||||
completion.push_back(sel.deepsky()->getName());
|
||||
completion.push_back(dsoCatalog->getDSOName(sel.deepsky()));
|
||||
return completion;
|
||||
}
|
||||
|
||||
PlanetarySystem* worlds = NULL;
|
||||
if (sel.getType() == Selection::Type_Body)
|
||||
{std::cerr << "body found" << std::endl;
|
||||
{cerr << "body found" << endl;
|
||||
worlds = sel.body()->getSatellites();
|
||||
std::vector<Location*>* locations = sel.body()->getLocations();
|
||||
vector<Location*>* locations = sel.body()->getLocations();
|
||||
if (locations != NULL && withLocations)
|
||||
{
|
||||
string search = s.substr(pos + 1);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <celmath/quaternion.h>
|
||||
#include <celengine/univcoord.h>
|
||||
#include <celengine/stardb.h>
|
||||
#include <celengine/dsodb.h>
|
||||
#include <celengine/solarsys.h>
|
||||
#include <celengine/deepskyobj.h>
|
||||
#include <celengine/asterism.h>
|
||||
|
@ -31,12 +32,16 @@ class Universe
|
|||
|
||||
StarDatabase* getStarCatalog() const;
|
||||
void setStarCatalog(StarDatabase*);
|
||||
|
||||
SolarSystemCatalog* getSolarSystemCatalog() const;
|
||||
void setSolarSystemCatalog(SolarSystemCatalog*);
|
||||
DeepSkyCatalog* getDeepSkyCatalog() const;
|
||||
void setDeepSkyCatalog(DeepSkyCatalog*);
|
||||
|
||||
DSODatabase* getDSOCatalog() const;
|
||||
void setDSOCatalog(DSODatabase*);
|
||||
|
||||
AsterismList* getAsterisms() const;
|
||||
void setAsterisms(AsterismList*);
|
||||
|
||||
ConstellationBoundaries* getBoundaries() const;
|
||||
void setBoundaries(ConstellationBoundaries*);
|
||||
|
||||
|
@ -45,13 +50,18 @@ class Universe
|
|||
double when,
|
||||
float faintestMag,
|
||||
float tolerance = 0.0f);
|
||||
Selection pickStar(const UniversalCoord&, const Vec3f&,
|
||||
|
||||
Selection pickStar(const UniversalCoord&,
|
||||
const Vec3f&,
|
||||
double when,
|
||||
float faintest,
|
||||
float tolerance = 0.0f);
|
||||
|
||||
Selection pickDeepSkyObject(const UniversalCoord&,
|
||||
const Vec3f&, float faintest,
|
||||
const Vec3f&,
|
||||
float faintest,
|
||||
float tolerance = 0.0f);
|
||||
|
||||
Selection find(const std::string& s,
|
||||
Selection* contexts = NULL,
|
||||
int nContexts = 0,
|
||||
|
@ -106,8 +116,8 @@ class Universe
|
|||
|
||||
private:
|
||||
StarDatabase* starCatalog;
|
||||
DSODatabase* dsoCatalog;
|
||||
SolarSystemCatalog* solarSystemCatalog;
|
||||
DeepSkyCatalog* deepSkyCatalog;
|
||||
AsterismList* asterisms;
|
||||
ConstellationBoundaries* boundaries;
|
||||
MarkerList* markers;
|
||||
|
|
|
@ -612,7 +612,7 @@ void CelestiaCore::mouseButtonDown(float x, float y, int button)
|
|||
if (views.size() > 1 && button == LeftButton) // look if click is near a view border
|
||||
{
|
||||
View *v1 = 0, *v2 = 0;
|
||||
for(std::vector<View*>::iterator i = views.begin(); i != views.end(); i++)
|
||||
for (vector<View*>::iterator i = views.begin(); i != views.end(); i++)
|
||||
{
|
||||
View* v = *i;
|
||||
float vx, vy, vxp, vyp;
|
||||
|
@ -752,7 +752,7 @@ void CelestiaCore::mouseMove(float x, float y)
|
|||
View* v1 = 0;
|
||||
View* v2 = 0;
|
||||
|
||||
for (std::vector<View*>::iterator i = views.begin(); i != views.end(); i++)
|
||||
for (vector<View*>::iterator i = views.begin(); i != views.end(); i++)
|
||||
{
|
||||
View* v = *i;
|
||||
float vx, vy, vxp, vyp;
|
||||
|
@ -924,7 +924,7 @@ void CelestiaCore::pickView(float x, float y)
|
|||
if (x+2 < views[activeView]->x * width || x-2 > (views[activeView]->x + views[activeView]->width) * width
|
||||
|| (height - y)+2 < views[activeView]->y * height || (height - y)-2 > (views[activeView]->y + views[activeView]->height) * height)
|
||||
{
|
||||
std::vector<View*>::iterator i = views.begin();
|
||||
vector<View*>::iterator i = views.begin();
|
||||
int n = 0;
|
||||
while (i < views.end() && (x+2 < (*i)->x * width || x-2 > ((*i)->x + (*i)->width) * width
|
||||
|| (height - y)+2 < (*i)->y * height || (height - y)-2 > ((*i)->y + (*i)->height) * height))
|
||||
|
@ -1113,14 +1113,14 @@ void CelestiaCore::charEntered(const char *c_p, int modifiers)
|
|||
if ( wc && (iswalpha(wc) || iswdigit(wc) || iswpunct(c) || c == ' ') )
|
||||
#endif
|
||||
{
|
||||
typedText += std::string(c_p);
|
||||
typedText += string(c_p);
|
||||
typedTextCompletion = sim->getObjectCompletion(typedText, (renderer->getLabelMode() & Renderer::LocationLabels) != 0);
|
||||
typedTextCompletionIdx = -1;
|
||||
#ifdef AUTO_COMPLETION
|
||||
if (typedTextCompletion.size() == 1)
|
||||
{
|
||||
std::string::size_type pos = typedText.rfind('/', typedText.length());
|
||||
if (pos != std::string::npos)
|
||||
string::size_type pos = typedText.rfind('/', typedText.length());
|
||||
if (pos != string::npos)
|
||||
typedText = typedText.substr(0, pos + 1) + typedTextCompletion[0];
|
||||
else
|
||||
typedText = typedTextCompletion[0];
|
||||
|
@ -1161,8 +1161,8 @@ void CelestiaCore::charEntered(const char *c_p, int modifiers)
|
|||
else if ((int) typedTextCompletion.size() > 0 && typedTextCompletionIdx + 1 == (int) typedTextCompletion.size())
|
||||
typedTextCompletionIdx = 0;
|
||||
if (typedTextCompletionIdx >= 0) {
|
||||
std::string::size_type pos = typedText.rfind('/', typedText.length());
|
||||
if (pos != std::string::npos)
|
||||
string::size_type pos = typedText.rfind('/', typedText.length());
|
||||
if (pos != string::npos)
|
||||
typedText = typedText.substr(0, pos + 1) + typedTextCompletion[typedTextCompletionIdx];
|
||||
else
|
||||
typedText = typedTextCompletion[typedTextCompletionIdx];
|
||||
|
@ -1177,8 +1177,8 @@ void CelestiaCore::charEntered(const char *c_p, int modifiers)
|
|||
else if (typedTextCompletion.size() > 0)
|
||||
typedTextCompletionIdx = typedTextCompletion.size() - 1;
|
||||
if (typedTextCompletionIdx >= 0) {
|
||||
std::string::size_type pos = typedText.rfind('/', typedText.length());
|
||||
if (pos != std::string::npos)
|
||||
string::size_type pos = typedText.rfind('/', typedText.length());
|
||||
if (pos != string::npos)
|
||||
typedText = typedText.substr(0, pos + 1) + typedTextCompletion[typedTextCompletionIdx];
|
||||
else
|
||||
typedText = typedTextCompletion[typedTextCompletionIdx];
|
||||
|
@ -1898,11 +1898,21 @@ void CelestiaCore::charEntered(const char *c_p, int modifiers)
|
|||
break;
|
||||
|
||||
case '(':
|
||||
Galaxy::decreaseLightGain();
|
||||
{
|
||||
char buf[128];
|
||||
Galaxy::decreaseLightGain();
|
||||
sprintf(buf, "%s: %3.2f %%", _("Light gain"), Galaxy::getLightGain() * 100.0f);
|
||||
flash(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case ')':
|
||||
Galaxy::increaseLightGain();
|
||||
{
|
||||
char buf[128];
|
||||
Galaxy::increaseLightGain();
|
||||
sprintf(buf, "%s: %3.2f %%", _("Light gain"), Galaxy::getLightGain() * 100.0f);
|
||||
flash(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case '~':
|
||||
|
@ -1957,7 +1967,7 @@ void CelestiaCore::start(double t)
|
|||
goToUrl(startURL);
|
||||
}
|
||||
|
||||
void CelestiaCore::setStartURL(std::string url)
|
||||
void CelestiaCore::setStartURL(string url)
|
||||
{
|
||||
if (!url.substr(0,4).compare("cel:"))
|
||||
{
|
||||
|
@ -2344,7 +2354,7 @@ void CelestiaCore::splitView(View::Type type, View* av, float splitPos)
|
|||
|
||||
void CelestiaCore::setFOVFromZoom()
|
||||
{
|
||||
for (std::vector<View*>::iterator i = views.begin(); i < views.end(); i++)
|
||||
for (vector<View*>::iterator i = views.begin(); i < views.end(); i++)
|
||||
if ((*i)->type == View::ViewWindow)
|
||||
{
|
||||
double fov = 2 * atan(height * (*i)->height / (screenDpi / 25.4) / 2. / distanceToScreen) / (*i)->zoom;
|
||||
|
@ -2354,7 +2364,7 @@ void CelestiaCore::setFOVFromZoom()
|
|||
|
||||
void CelestiaCore::setZoomFromFOV()
|
||||
{
|
||||
for (std::vector<View*>::iterator i = views.begin(); i < views.end(); i++)
|
||||
for (vector<View*>::iterator i = views.begin(); i < views.end(); i++)
|
||||
if ((*i)->type == View::ViewWindow)
|
||||
{
|
||||
(*i)->zoom = (float) (2 * atan(height * (*i)->height / (screenDpi / 25.4) / 2. / distanceToScreen) / (*i)->observer->getFOV());
|
||||
|
@ -2396,7 +2406,7 @@ void CelestiaCore::deleteView(View* v)
|
|||
|
||||
if (v->parent == 0) return;
|
||||
|
||||
for(std::vector<View*>::iterator i = views.begin(); i < views.end() ; i++)
|
||||
for(vector<View*>::iterator i = views.begin(); i < views.end() ; i++)
|
||||
{
|
||||
if (*i == v)
|
||||
{
|
||||
|
@ -2506,7 +2516,7 @@ static FormattedNumber SigDigitNum(double v, int digits)
|
|||
|
||||
static void displayDistance(Overlay& overlay, double distance)
|
||||
{
|
||||
char* units = "";
|
||||
const char* units = "";
|
||||
|
||||
if (abs(distance) >= astro::parsecsToLightYears(1e+6))
|
||||
{
|
||||
|
@ -2578,7 +2588,8 @@ static void displayAngle(Overlay& overlay, double angle)
|
|||
|
||||
|
||||
static void displayApparentDiameter(Overlay& overlay,
|
||||
double radius, double distance)
|
||||
double radius,
|
||||
double distance)
|
||||
{
|
||||
if (distance > radius)
|
||||
{
|
||||
|
@ -2595,13 +2606,29 @@ static void displayApparentDiameter(Overlay& overlay,
|
|||
}
|
||||
}
|
||||
|
||||
static void displayApparentMagnitude(Overlay& overlay,
|
||||
float absMag,
|
||||
double distance)
|
||||
{
|
||||
float appMag = absMag;
|
||||
if (distance > 32.6167)
|
||||
{
|
||||
appMag = astro::absToAppMag(absMag, (float) distance);
|
||||
overlay << _("Apparent magnitude: ");
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay << _("Absolute magnitude: ");
|
||||
}
|
||||
|
||||
overlay.printf("%.1f\n", appMag);
|
||||
}
|
||||
|
||||
static void displayAcronym(Overlay& overlay, char* s)
|
||||
{
|
||||
if (strchr(s, ' ') != NULL)
|
||||
{
|
||||
int length = strlen(s);
|
||||
int n = 0;
|
||||
char lastChar = ' ';
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
|
@ -2618,114 +2645,6 @@ static void displayAcronym(Overlay& overlay, char* s)
|
|||
}
|
||||
|
||||
|
||||
static void displayStarName(Overlay& overlay,
|
||||
Star& star,
|
||||
StarDatabase& starDB)
|
||||
{
|
||||
StarNameDatabase::NumberIndex::const_iterator iter =
|
||||
starDB.getStarNames(star.getCatalogNumber());
|
||||
|
||||
if (iter != starDB.finalName() &&
|
||||
iter->first == star.getCatalogNumber())
|
||||
{
|
||||
overlay << ReplaceGreekLetterAbbr(iter->second.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 hip = star.getCatalogNumber();
|
||||
if (hip != Star::InvalidCatalogNumber && hip != 0)
|
||||
{
|
||||
if (hip >= 1000000)
|
||||
{
|
||||
uint32 tyc3 = hip / 1000000000;
|
||||
hip -= tyc3 * 1000000000;
|
||||
uint32 tyc2 = hip / 10000;
|
||||
hip -= tyc2 * 10000;
|
||||
uint32 tyc1 = hip;
|
||||
overlay << "TYC " << tyc1 << '-' << tyc2 << '-' << tyc3;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay << "HIP " << hip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static string starNameList(Star& star,
|
||||
StarDatabase& starDB,
|
||||
int maxNames = 10)
|
||||
{
|
||||
string starNames;
|
||||
char numString[32];
|
||||
|
||||
StarNameDatabase::NumberIndex::const_iterator iter =
|
||||
starDB.getStarNames(star.getCatalogNumber());
|
||||
|
||||
int count = 0;
|
||||
while (iter != starDB.finalName() &&
|
||||
iter->first == star.getCatalogNumber() &&
|
||||
count < maxNames)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
|
||||
starNames += ReplaceGreekLetterAbbr(_(iter->second.c_str()));
|
||||
iter++;
|
||||
count++;
|
||||
}
|
||||
|
||||
uint32 hip = star.getCatalogNumber();
|
||||
if (hip != Star::InvalidCatalogNumber && hip != 0 && count < maxNames)
|
||||
{
|
||||
if (hip <= Star::MaxTychoCatalogNumber)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
if (hip >= 1000000)
|
||||
{
|
||||
uint32 h = hip;
|
||||
uint32 tyc3 = h / 1000000000;
|
||||
h -= tyc3 * 1000000000;
|
||||
uint32 tyc2 = h / 10000;
|
||||
h -= tyc2 * 10000;
|
||||
uint32 tyc1 = h;
|
||||
sprintf(numString, "TYC %u-%u-%u", tyc1, tyc2, tyc3);
|
||||
starNames += numString;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(numString, "HIP %u", hip);
|
||||
starNames += numString;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 hd = starDB.crossIndex(StarDatabase::HenryDraper, hip);
|
||||
if (count < maxNames && hd != Star::InvalidCatalogNumber)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
sprintf(numString, "HD %u", hd);
|
||||
starNames += numString;
|
||||
}
|
||||
|
||||
uint32 sao = starDB.crossIndex(StarDatabase::SAO, hip);
|
||||
if (count < maxNames && sao != Star::InvalidCatalogNumber)
|
||||
{
|
||||
if (count != 0)
|
||||
starNames += " / ";
|
||||
sprintf(numString, "SAO %u", sao);
|
||||
starNames += numString;
|
||||
}
|
||||
|
||||
|
||||
return starNames;
|
||||
}
|
||||
|
||||
|
||||
static void displayStarInfo(Overlay& overlay,
|
||||
int detail,
|
||||
Star& star,
|
||||
|
@ -2778,6 +2697,30 @@ static void displayStarInfo(Overlay& overlay,
|
|||
}
|
||||
|
||||
|
||||
static void displayDSOinfo(Overlay& overlay,
|
||||
int detail,
|
||||
const DeepSkyObject& dso,
|
||||
const Universe& universe,
|
||||
double distance)
|
||||
{
|
||||
overlay << dso.getType() << '\n';
|
||||
overlay << _("Distance: ");
|
||||
displayDistance(overlay, distance);
|
||||
overlay << '\n';
|
||||
overlay << _("Radius: ");
|
||||
displayDistance(overlay, dso.getRadius());
|
||||
overlay << '\n';
|
||||
|
||||
displayApparentDiameter(overlay, dso.getRadius(), distance);
|
||||
if (dso.getAbsoluteMagnitude() > DSO_DEFAULT_ABS_MAGNITUDE)
|
||||
{
|
||||
displayApparentMagnitude(overlay,
|
||||
dso.getAbsoluteMagnitude(),
|
||||
distance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void displayPlanetInfo(Overlay& overlay,
|
||||
int detail,
|
||||
Body& body,
|
||||
|
@ -2834,18 +2777,6 @@ static void displayPlanetInfo(Overlay& overlay,
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// TODO: Need to display some sort of information for galaxies and other
|
||||
// deep sky objects.
|
||||
static void displayGalaxyInfo(Overlay& overlay,
|
||||
Galaxy& galaxy,
|
||||
double distance)
|
||||
{
|
||||
overlay << _("Type: ") << galaxy.getType() << '\n';
|
||||
overlay << _("Radius: ") << galaxy.getRadius() << _(" ly\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void displayLocationInfo(Overlay& overlay,
|
||||
Location& location,
|
||||
|
@ -2921,10 +2852,11 @@ static void displaySelectionName(Overlay& overlay,
|
|||
overlay << sel.body()->getName(true).c_str();
|
||||
break;
|
||||
case Selection::Type_DeepSky:
|
||||
overlay << sel.deepsky()->getName().c_str();
|
||||
overlay << univ.getDSOCatalog()->getDSOName(sel.deepsky());
|
||||
break;
|
||||
case Selection::Type_Star:
|
||||
displayStarName(overlay, *(sel.star()), *univ.getStarCatalog());
|
||||
//displayStarName(overlay, *(sel.star()), *univ.getStarCatalog());
|
||||
overlay << univ.getStarCatalog()->getStarName(*sel.star());
|
||||
break;
|
||||
case Selection::Type_Location:
|
||||
overlay << sel.location()->getName(true).c_str();
|
||||
|
@ -2948,13 +2880,13 @@ static void showViewFrame(const View* v, int width, int height)
|
|||
|
||||
void CelestiaCore::renderOverlay()
|
||||
{
|
||||
static std::locale currentLocale;
|
||||
static std::locale cLocale;
|
||||
static locale currentLocale;
|
||||
static locale cLocale;
|
||||
static bool localeSet = false;
|
||||
|
||||
if (!localeSet) {
|
||||
cLocale = overlay->getloc();
|
||||
currentLocale = std::locale(cLocale, "", std::locale::numeric);
|
||||
currentLocale = locale(cLocale, "", std::locale::numeric);
|
||||
localeSet = true;
|
||||
}
|
||||
|
||||
|
@ -2977,7 +2909,7 @@ void CelestiaCore::renderOverlay()
|
|||
glLineWidth(1.0f);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
for(std::vector<View*>::iterator i = views.begin(); i != views.end(); i++)
|
||||
for(vector<View*>::iterator i = views.begin(); i != views.end(); i++)
|
||||
{
|
||||
showViewFrame(*i, width, height);
|
||||
}
|
||||
|
@ -3239,12 +3171,11 @@ void CelestiaCore::renderOverlay()
|
|||
if (sel != lastSelection)
|
||||
{
|
||||
lastSelection = sel;
|
||||
selectionNames = starNameList(*(sel.star()),
|
||||
*(sim->getUniverse()->getStarCatalog()));
|
||||
selectionNames = sim->getUniverse()->getStarCatalog()->getStarNameList(*sel.star());
|
||||
}
|
||||
|
||||
overlay->setFont(titleFont);
|
||||
*overlay << selectionNames.c_str();
|
||||
*overlay << selectionNames;
|
||||
overlay->setFont(font);
|
||||
*overlay << '\n';
|
||||
displayStarInfo(*overlay,
|
||||
|
@ -3255,6 +3186,27 @@ void CelestiaCore::renderOverlay()
|
|||
}
|
||||
break;
|
||||
|
||||
case Selection::Type_DeepSky:
|
||||
{
|
||||
if (sel != lastSelection)
|
||||
{
|
||||
lastSelection = sel;
|
||||
selectionNames = sim->getUniverse()->getDSOCatalog()->getDSONameList(sel.deepsky());
|
||||
}
|
||||
|
||||
overlay->setFont(titleFont);
|
||||
//*overlay << sel.deepsky()->getName().c_str();
|
||||
*overlay << selectionNames;
|
||||
overlay->setFont(font);
|
||||
*overlay << '\n';
|
||||
displayDSOinfo(*overlay,
|
||||
hudDetail,
|
||||
*sel.deepsky(),
|
||||
*sim->getUniverse(),
|
||||
v.length() * 1e-6 - sel.deepsky()->getRadius());
|
||||
}
|
||||
break;
|
||||
|
||||
case Selection::Type_Body:
|
||||
{
|
||||
overlay->setFont(titleFont);
|
||||
|
@ -3270,24 +3222,6 @@ void CelestiaCore::renderOverlay()
|
|||
}
|
||||
break;
|
||||
|
||||
case Selection::Type_DeepSky:
|
||||
{
|
||||
overlay->setFont(titleFont);
|
||||
*overlay << sel.deepsky()->getName().c_str();
|
||||
overlay->setFont(font);
|
||||
*overlay << '\n';
|
||||
*overlay << _("Distance: ");
|
||||
displayDistance(*overlay, v.length() * 1e-6);
|
||||
*overlay << '\n';
|
||||
displayApparentDiameter(*overlay, sel.deepsky()->getRadius(),
|
||||
v.length() * 1e-6);
|
||||
#if 0
|
||||
displayGalaxyInfo(*overlay, *sel.galaxy,
|
||||
v.length() * 1e-6);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case Selection::Type_Location:
|
||||
overlay->setFont(titleFont);
|
||||
*overlay << sel.location()->getName(true).c_str();
|
||||
|
@ -3326,7 +3260,7 @@ void CelestiaCore::renderOverlay()
|
|||
int nb_lines = 3;
|
||||
int start = 0;
|
||||
glTranslatef(3.0f, -font->getHeight() - 3.0f, 0.0f);
|
||||
std::vector<std::string>::const_iterator iter = typedTextCompletion.begin();
|
||||
vector<std::string>::const_iterator iter = typedTextCompletion.begin();
|
||||
if (typedTextCompletionIdx >= nb_cols * nb_lines)
|
||||
{
|
||||
start = (typedTextCompletionIdx / nb_lines + 1 - nb_cols) * nb_lines;
|
||||
|
@ -3548,59 +3482,47 @@ class SolarSystemLoader : public EnumFilesHandler
|
|||
};
|
||||
};
|
||||
|
||||
class DeepSkyLoader : public EnumFilesHandler
|
||||
template <class OBJDB> class CatalogLoader : public EnumFilesHandler
|
||||
{
|
||||
public:
|
||||
DeepSkyCatalog* catalog;
|
||||
DeepSkyLoader(DeepSkyCatalog* c) : catalog(c) {};
|
||||
OBJDB* objDB;
|
||||
string typeDesc;
|
||||
ContentType contentType;
|
||||
|
||||
CatalogLoader(OBJDB* db,
|
||||
const std::string& typeDesc,
|
||||
const ContentType& contentType) :
|
||||
objDB (db),
|
||||
typeDesc (typeDesc),
|
||||
contentType(contentType)
|
||||
{
|
||||
}
|
||||
|
||||
bool process(const string& filename)
|
||||
{
|
||||
if (DetermineFileType(filename) == Content_CelestiaDeepSkyCatalog)
|
||||
if (DetermineFileType(filename) == contentType)
|
||||
{
|
||||
string fullname = getPath() + '/' + filename;
|
||||
clog << _("Loading deep sky catalog: ") << fullname << '\n';
|
||||
ifstream deepSkyFile(fullname.c_str(), ios::in);
|
||||
if (deepSkyFile.good())
|
||||
clog << _("Loading ") << typeDesc << " catalog: " << fullname << '\n';
|
||||
ifstream catalogFile(fullname.c_str(), ios::in);
|
||||
if (catalogFile.good())
|
||||
{
|
||||
LoadDeepSkyObjects(*catalog, deepSkyFile, getPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log the failure
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
class StarLoader : public EnumFilesHandler
|
||||
{
|
||||
public:
|
||||
StarDatabase* starDB;
|
||||
StarLoader(StarDatabase* s) : starDB(s) {};
|
||||
|
||||
bool process(const string& filename)
|
||||
{
|
||||
if (DetermineFileType(filename) == Content_CelestiaStarCatalog)
|
||||
{
|
||||
string fullname = getPath() + '/' + filename;
|
||||
clog << _("Loading star catalog: ") << fullname << '\n';
|
||||
ifstream starFile(fullname.c_str(), ios::in);
|
||||
if (starFile.good())
|
||||
{
|
||||
bool success = starDB->load(starFile, getPath());
|
||||
bool success = objDB->load(catalogFile, getPath());
|
||||
if (!success)
|
||||
{
|
||||
DPRINTF(0, _("Error reading star file: %s\n"),
|
||||
fullname.c_str());
|
||||
}
|
||||
DPRINTF(0, "Error reading %s catalog file: %s\n", typeDesc.c_str(), fullname.c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
typedef CatalogLoader<StarDatabase> StarLoader;
|
||||
typedef CatalogLoader<DSODatabase> DeepSkyLoader;
|
||||
|
||||
|
||||
bool CelestiaCore::initSimulation(const string* configFileName,
|
||||
const vector<string>* extrasDirs)
|
||||
|
@ -3627,7 +3549,7 @@ bool CelestiaCore::initSimulation(const string* configFileName,
|
|||
{
|
||||
config = ReadCelestiaConfig("celestia.cfg");
|
||||
|
||||
std::string localConfigFile = WordExp("~/.celestia.cfg");
|
||||
string localConfigFile = WordExp("~/.celestia.cfg");
|
||||
if (localConfigFile != "")
|
||||
ReadCelestiaConfig(localConfigFile.c_str(), config);
|
||||
}
|
||||
|
@ -3726,19 +3648,36 @@ bool CelestiaCore::initSimulation(const string* configFileName,
|
|||
}
|
||||
}
|
||||
|
||||
DeepSkyCatalog* deepSkyCatalog = new DeepSkyCatalog();
|
||||
DSONameDatabase* dsoNameDB = new DSONameDatabase;
|
||||
DSODatabase* dsoDB = new DSODatabase;
|
||||
dsoDB->setNameDatabase(dsoNameDB);
|
||||
|
||||
// We'll first read a very large DSO catalog from a bundled file:
|
||||
if (config->deepSkyCatalog != "")
|
||||
{
|
||||
ifstream deepSkyFile(config->deepSkyCatalog.c_str(), ios::in);
|
||||
if (!deepSkyFile.good())
|
||||
ifstream dsoFile(config->deepSkyCatalog.c_str(), ios::in);
|
||||
#if 0 //TODO: define a binary file format for DSOs !!
|
||||
if (!dsoDB->loadBinary(deepSkyFile))
|
||||
{
|
||||
warning(_("Error opening deep sky file.\n"));
|
||||
cerr << _("Error reading deep sky file\n");
|
||||
delete dsoDB;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!dsoFile.good())
|
||||
{
|
||||
LoadDeepSkyObjects(*deepSkyCatalog, deepSkyFile, "");
|
||||
cerr << _("Error opening ") << config->deepSkyCatalog << '\n';
|
||||
delete dsoDB;
|
||||
return false;
|
||||
}
|
||||
else if (!dsoDB->load(dsoFile, ""))
|
||||
{
|
||||
cerr << "Cannot read Deep Sky Objects database." << config->deepSkyCatalog << '\n';
|
||||
delete dsoDB;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// TODO:add support for additional catalogs declared in the config file.
|
||||
|
||||
// Next, read all the deep sky files in the extras directories
|
||||
{
|
||||
|
@ -3749,7 +3688,9 @@ bool CelestiaCore::initSimulation(const string* configFileName,
|
|||
{
|
||||
Directory* dir = OpenDirectory(*iter);
|
||||
|
||||
DeepSkyLoader loader(deepSkyCatalog);
|
||||
DeepSkyLoader loader(dsoDB,
|
||||
"deep sky object",
|
||||
Content_CelestiaDeepSkyCatalog);
|
||||
loader.pushDir(*iter);
|
||||
dir->enumFiles(loader, true);
|
||||
|
||||
|
@ -3758,8 +3699,10 @@ bool CelestiaCore::initSimulation(const string* configFileName,
|
|||
}
|
||||
}
|
||||
|
||||
universe->setDeepSkyCatalog(deepSkyCatalog);
|
||||
dsoDB->finish();
|
||||
universe->setDSOCatalog(dsoDB);
|
||||
|
||||
// Load asterisms:
|
||||
if (config->asterismsFile != "")
|
||||
{
|
||||
ifstream asterismsFile(config->asterismsFile.c_str(), ios::in);
|
||||
|
@ -4021,7 +3964,7 @@ bool CelestiaCore::readStars(const CelestiaConfig& cfg)
|
|||
{
|
||||
Directory* dir = OpenDirectory(*iter);
|
||||
|
||||
StarLoader loader(starDB);
|
||||
StarLoader loader(starDB, "star", Content_CelestiaStarCatalog);
|
||||
loader.pushDir(*iter);
|
||||
dir->enumFiles(loader, true);
|
||||
|
||||
|
@ -4215,7 +4158,7 @@ bool CelestiaCore::isRecording()
|
|||
return recording;
|
||||
}
|
||||
|
||||
void CelestiaCore::flash(const std::string& s, double duration)
|
||||
void CelestiaCore::flash(const string& s, double duration)
|
||||
{
|
||||
if (hudDetail > 0)
|
||||
showText(s, -1, -1, 0, 5, duration);
|
||||
|
@ -4252,7 +4195,7 @@ void CelestiaCore::notifyWatchers(int property)
|
|||
}
|
||||
|
||||
|
||||
void CelestiaCore::goToUrl(const std::string& urlStr)
|
||||
void CelestiaCore::goToUrl(const string& urlStr)
|
||||
{
|
||||
Url url(urlStr, this);
|
||||
url.goTo();
|
||||
|
@ -4303,17 +4246,17 @@ void CelestiaCore::forward()
|
|||
}
|
||||
|
||||
|
||||
const std::vector<Url>& CelestiaCore::getHistory() const
|
||||
const vector<Url>& CelestiaCore::getHistory() const
|
||||
{
|
||||
return history;
|
||||
}
|
||||
|
||||
std::vector<Url>::size_type CelestiaCore::getHistoryCurrent() const
|
||||
vector<Url>::size_type CelestiaCore::getHistoryCurrent() const
|
||||
{
|
||||
return historyCurrent;
|
||||
}
|
||||
|
||||
void CelestiaCore::setHistoryCurrent(std::vector<Url>::size_type curr)
|
||||
void CelestiaCore::setHistoryCurrent(vector<Url>::size_type curr)
|
||||
{
|
||||
if (curr >= history.size()) return;
|
||||
if (historyCurrent == history.size()) {
|
||||
|
|
|
@ -964,7 +964,7 @@ View* getViewByObserver(CelestiaCore* appCore, Observer* obs)
|
|||
}
|
||||
|
||||
// Fill list with all Observers
|
||||
void getObservers(CelestiaCore* appCore, std::vector<Observer*>& list)
|
||||
void getObservers(CelestiaCore* appCore, vector<Observer*>& list)
|
||||
{
|
||||
for (unsigned int i = 0; i < appCore->views.size(); i++)
|
||||
{
|
||||
|
@ -2121,7 +2121,8 @@ static int object_name(lua_State* l)
|
|||
lua_pushstring(l, sel->body()->getName().c_str());
|
||||
break;
|
||||
case Selection::Type_DeepSky:
|
||||
lua_pushstring(l, sel->deepsky()->getName().c_str());
|
||||
lua_pushstring(l, getAppCore(l, AllErrors)->getSimulation()->getUniverse()
|
||||
->getDSOCatalog()->getDSOName(sel->deepsky()).c_str());
|
||||
break;
|
||||
case Selection::Type_Star:
|
||||
lua_pushstring(l, getAppCore(l, AllErrors)->getSimulation()->getUniverse()
|
||||
|
@ -2247,7 +2248,8 @@ static int object_getinfo(lua_State* l)
|
|||
{
|
||||
setTable(l, "type", "deepsky");
|
||||
DeepSkyObject* deepsky = sel->deepsky();
|
||||
setTable(l, "name", deepsky->getName().c_str());
|
||||
setTable(l, "name", getAppCore(l, AllErrors)->getSimulation()->getUniverse()
|
||||
->getDSOCatalog()->getDSOName(sel->deepsky()).c_str());
|
||||
setTable(l, "radius", (lua_Number)deepsky->getRadius());
|
||||
}
|
||||
else if (sel->location() != NULL)
|
||||
|
@ -3833,7 +3835,7 @@ static int celestia_getobservers(lua_State* l)
|
|||
checkArgs(l, 1, 1, "No arguments expected for celestia:getobservers()");
|
||||
CelestiaCore* appCore = this_celestia(l);
|
||||
|
||||
std::vector<Observer*> observer_list;
|
||||
vector<Observer*> observer_list;
|
||||
getObservers(appCore, observer_list);
|
||||
lua_newtable(l);
|
||||
for (unsigned int i = 0; i < observer_list.size(); i++)
|
||||
|
|
|
@ -194,7 +194,8 @@ Url::Url(const std::string& str, CelestiaCore *core)
|
|||
evalName();
|
||||
}
|
||||
|
||||
Url::Url(CelestiaCore* core, UrlType type) {
|
||||
Url::Url(CelestiaCore* core, UrlType type)
|
||||
{
|
||||
appCore = core;
|
||||
Simulation *sim = appCore->getSimulation();
|
||||
Renderer *renderer = appCore->getRenderer();
|
||||
|
@ -380,8 +381,7 @@ std::string Url::getSelectionName(const Selection& selection) const
|
|||
}
|
||||
if (selection.body()->getSystem()->getStar() != NULL)
|
||||
{
|
||||
name=universe->getStarCatalog()->getStarName(*(selection.body()->getSystem()->getStar()))
|
||||
+ ":" + name;
|
||||
name = universe->getStarCatalog()->getStarName(*(selection.body()->getSystem()->getStar())) + ":" + name;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
|
@ -391,7 +391,7 @@ std::string Url::getSelectionName(const Selection& selection) const
|
|||
return universe->getStarCatalog()->getStarName(*selection.star());
|
||||
|
||||
case Selection::Type_DeepSky:
|
||||
return selection.deepsky()->getName();
|
||||
return universe->getDSOCatalog()->getDSOName(selection.deepsky());
|
||||
|
||||
case Selection::Type_Location:
|
||||
return "";
|
||||
|
|
|
@ -1706,8 +1706,9 @@ VOID APIENTRY handlePopupMenu(HWND hwnd,
|
|||
|
||||
case Selection::Type_DeepSky:
|
||||
{
|
||||
AppendMenu(hMenu, MF_STRING, ID_NAVIGATION_CENTER,
|
||||
sel.deepsky()->getName().c_str());
|
||||
Simulation* sim = appCore->getSimulation();
|
||||
name = sim->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky());
|
||||
AppendMenu(hMenu, MF_STRING, ID_NAVIGATION_CENTER, name.c_str());
|
||||
AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
|
||||
AppendMenu(hMenu, MF_STRING, ID_NAVIGATION_GOTO, "&Goto");
|
||||
AppendMenu(hMenu, MF_STRING, ID_NAVIGATION_FOLLOW, "&Follow");
|
||||
|
@ -3020,7 +3021,7 @@ static bool parseCommandLine(int argc, char* argv[])
|
|||
if (isLastArg)
|
||||
{
|
||||
MessageBox(NULL,
|
||||
"Configuration file name expected after --config",
|
||||
"Configuration file name expected after --conf",
|
||||
"Celestia Command Line Error",
|
||||
MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue