Integrated changes from Fridger and Toti's Celestia FT 1.2

pull/3/head
Chris Laurel 2005-11-18 09:00:39 +00:00
parent 48849e4b32
commit 974213f905
34 changed files with 2832 additions and 1139 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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_

View File

@ -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);
}

View File

@ -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_

View File

@ -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);
}
}
}

View File

@ -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_

View File

@ -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 \

View File

@ -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;
}

View File

@ -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_

View File

@ -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_

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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_

View File

@ -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;
}

View File

@ -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

View File

@ -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));

View File

@ -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];

View File

@ -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:
{

View File

@ -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;

View File

@ -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());
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_

View File

@ -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);
}
}
}

View File

@ -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_

View File

@ -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);

View File

@ -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;

View File

@ -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()) {

View File

@ -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++)

View File

@ -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 "";

View File

@ -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;