Added solar system browser to Qt4 front-end.

ver1_5_1
Chris Laurel 2008-01-15 01:22:55 +00:00
parent 7a5c9ed95c
commit 1fd6c7c76f
3 changed files with 290 additions and 27 deletions

View File

@ -23,6 +23,7 @@
#include "qtappwin.h"
#include "qtglwidget.h"
#include "qtpreferencesdialog.h"
#include "qtsolarsystembrowser.h"
#include "qtcelestialbrowser.h"
#include "qtdeepskybrowser.h"
#include "qtselectionpopup.h"
@ -39,7 +40,7 @@ const QPoint DEFAULT_MAIN_WINDOW_POSITION(200, 200);
// Used when saving and restoring main window state; increment whenever
// new dockables or toolbars are added.
static const int CELESTIA_MAIN_WINDOW_VERSION = 2;
static const int CELESTIA_MAIN_WINDOW_VERSION = 3;
// Terrible hack required because context menu callback doesn't retain
@ -105,6 +106,10 @@ CelestiaAppWindow::CelestiaAppWindow(const QString& qConfigFileName,
QWidget* deepSkyBrowser = new DeepSkyBrowser(appCore, NULL);
deepSkyBrowser->setObjectName("deepsky-browser");
SolarSystemBrowser* solarSystemBrowser = new SolarSystemBrowser(appCore, NULL);
solarSystemBrowser->setObjectName("ssys-browser");
tabWidget->addTab(solarSystemBrowser, tr("Solar System"));
tabWidget->addTab(celestialBrowser, tr("Stars"));
tabWidget->addTab(deepSkyBrowser, tr("Deep Sky Objects"));

View File

@ -18,6 +18,7 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QCheckBox>
#include <QLabel>
#include <celestia/celestiacore.h>
#include <vector>
@ -50,7 +51,7 @@ public:
TypeColumn = 1,
};
void buildModel(Star& star);
void buildModel(Star* star, bool _groupByClass);
private:
class TreeItem
@ -64,20 +65,36 @@ private:
TreeItem** children;
int nChildren;
int childIndex;
int classification;
};
TreeItem* createTreeItem(Selection sel, TreeItem* parent, int childIndex);
void addTreeItemChildren(TreeItem* item,
PlanetarySystem* sys,
const vector<Star*>* orbitingStars);
void addTreeItemChildrenGrouped(TreeItem* item,
PlanetarySystem* sys,
const vector<Star*>* orbitingStars,
Selection parent);
TreeItem* createGroupTreeItem(int classification,
const vector<Body*>& objects,
TreeItem* parent,
int childIndex);
TreeItem* itemAtIndex(const QModelIndex& index) const;
private:
const Universe* universe;
TreeItem* rootItem;
bool groupByClass;
};
SolarSystemTreeModel::TreeItem::TreeItem() :
parent(NULL),
children(NULL),
nChildren(0)
nChildren(0),
classification(0)
{
}
@ -95,8 +112,11 @@ SolarSystemTreeModel::TreeItem::~TreeItem()
SolarSystemTreeModel::SolarSystemTreeModel(const Universe* _universe) :
universe(_universe),
rootItem(NULL)
rootItem(NULL),
groupByClass(false)
{
// Initialize an empty model
buildModel(NULL, false);
}
@ -105,6 +125,28 @@ SolarSystemTreeModel::~SolarSystemTreeModel()
}
// Call createTreeItem() to build the parallel tree structure
void SolarSystemTreeModel::buildModel(Star* star, bool _groupByClass)
{
groupByClass = _groupByClass;
if (rootItem != NULL)
delete rootItem;
rootItem = new TreeItem();
rootItem->obj = Selection();
if (star != NULL)
{
rootItem->nChildren = 1;
rootItem->children = new TreeItem*[1];
rootItem->children[0] = createTreeItem(Selection(star), rootItem, 0);
}
reset();
}
// Rather than directly use Celestia's solar system data structure for
// the tree model, we'll build a parallel structure out of TreeItems.
// The additional memory used for this structure is negligible, and
@ -144,6 +186,20 @@ SolarSystemTreeModel::createTreeItem(Selection sel,
orbitingStars = sel.star()->getOrbitingStars();
}
if (groupByClass && sys != NULL)
addTreeItemChildrenGrouped(item, sys, orbitingStars, sel);
else
addTreeItemChildren(item, sys, orbitingStars);
return item;
}
void
SolarSystemTreeModel::addTreeItemChildren(TreeItem* item,
PlanetarySystem* sys,
const vector<Star*>* orbitingStars)
{
// Calculate the number of children: the number of orbiting stars plus
// the number of orbiting solar system bodies.
item->nChildren = 0;
@ -179,34 +235,193 @@ SolarSystemTreeModel::createTreeItem(Selection sel,
}
}
}
}
// Add children to item, but group objects of certain classes
// into subtrees to avoid clutter. Stars, planets, and moons
// are shown as direct children of the parent. Small moons,
// asteroids, and spacecraft a grouped together, as there tend to be
// large collections of such objects.
void
SolarSystemTreeModel::addTreeItemChildrenGrouped(TreeItem* item,
PlanetarySystem* sys,
const vector<Star*>* orbitingStars,
Selection parent)
{
vector<Body*> asteroids;
vector<Body*> spacecraft;
vector<Body*> minorMoons;
vector<Body*> other;
vector<Body*> normal;
float minorMoonCutoffRadius = 0.0f;
bool groupAsteroids = true;
bool groupSpacecraft = true;
if (parent.body())
{
// TODO: we should define a class for minor moons. Until then,
// we'll call a moon 'minor' if its radius is less than 1/1000
// times the radius of the planet it orbits.
minorMoonCutoffRadius = parent.body()->getRadius() / 1000.0f;
// Don't put asteroid moons in the asteroid group; make them
// immediate children of the parent.
if (parent.body()->getClassification() == Body::Asteroid)
groupAsteroids = false;
if (parent.body()->getClassification() == Body::Spacecraft)
groupSpacecraft = false;
}
for (int i = 0; i < sys->getSystemSize(); i++)
{
Body* body = sys->getBody(i);
switch (body->getClassification())
{
case Body::Planet:
case Body::Invisible:
normal.push_back(body);
break;
case Body::Moon:
if (body->getRadius() < minorMoonCutoffRadius)
minorMoons.push_back(body);
else
normal.push_back(body);
break;
case Body::Asteroid:
case Body::Comet:
if (groupAsteroids)
asteroids.push_back(body);
else
normal.push_back(body);
break;
case Body::Spacecraft:
if (groupSpacecraft)
spacecraft.push_back(body);
else
normal.push_back(body);
break;
default:
other.push_back(body);
break;
}
}
// Calculate the total number of children
item->nChildren = 0;
if (orbitingStars != NULL)
item->nChildren += orbitingStars->size();
item->nChildren += normal.size();
if (!asteroids.empty())
item->nChildren++;
if (!spacecraft.empty())
item->nChildren++;
if (!minorMoons.empty())
item->nChildren++;
if (!other.empty())
item->nChildren++;
if (item->nChildren != 0)
{
int childIndex = 0;
item->children = new TreeItem*[item->nChildren];
{
// Add the stars
if (orbitingStars != NULL)
{
for (unsigned int i = 0; i < orbitingStars->size(); i++)
{
Selection child(orbitingStars->at(i));
item->children[i] = createTreeItem(child, item, childIndex);
childIndex++;
}
}
// Add the direct children
for (int i = 0; i < (int) normal.size(); i++)
{
item->children[childIndex] = createTreeItem(normal[i], item, childIndex);
childIndex++;
}
// Add the groups
if (!minorMoons.empty())
{
item->children[childIndex] = createGroupTreeItem(Body::SmallBody,
minorMoons,
item, childIndex);
childIndex++;
}
if (!asteroids.empty())
{
item->children[childIndex] = createGroupTreeItem(Body::Asteroid,
asteroids,
item, childIndex);
childIndex++;
}
if (!spacecraft.empty())
{
item->children[childIndex] = createGroupTreeItem(Body::Spacecraft,
spacecraft,
item, childIndex);
childIndex++;
}
if (!other.empty())
{
item->children[childIndex] = createGroupTreeItem(Body::Unknown,
other,
item, childIndex);
childIndex++;
}
}
}
}
SolarSystemTreeModel::TreeItem*
SolarSystemTreeModel::createGroupTreeItem(int classification,
const vector<Body*>& objects,
TreeItem* parent,
int childIndex)
{
TreeItem* item = new TreeItem();
item->parent = parent;
item->childIndex = childIndex;
item->classification = classification;
if (!objects.empty())
{
item->nChildren = (int) objects.size();
item->children = new TreeItem*[item->nChildren];
for (int i = 0; i < item->nChildren; i++)
{
item->children[i] = createTreeItem(Selection(objects[i]), item, i);
}
}
return item;
}
// Call createTreeItem() to build the parallel tree structure
void SolarSystemTreeModel::buildModel(Star& star)
SolarSystemTreeModel::TreeItem*
SolarSystemTreeModel::itemAtIndex(const QModelIndex& index) const
{
if (rootItem != NULL)
delete rootItem;
rootItem = new TreeItem();
rootItem->nChildren = 1;
rootItem->children = new TreeItem*[1];
rootItem->obj = Selection();
rootItem->children[0] = createTreeItem(Selection(&star), rootItem, 0);
reset();
if (!index.isValid())
return rootItem;
else
return static_cast<TreeItem*>(index.internalPointer());
}
Selection SolarSystemTreeModel::objectAtIndex(const QModelIndex& index) const
Selection
SolarSystemTreeModel::objectAtIndex(const QModelIndex& index) const
{
if (!index.isValid())
return rootItem->obj;
else
return static_cast<TreeItem*>(index.internalPointer())->obj;
return itemAtIndex(index)->obj;
}
@ -284,14 +499,46 @@ static QString objectTypeName(const Selection& sel)
}
static QString classificationName(int classification)
{
if (classification == Body::Planet)
return QObject::tr("Planets");
else if (classification == Body::Moon)
return QObject::tr("Moons");
else if (classification == Body::Spacecraft)
return QObject::tr("Spacecraft");
else if (classification == Body::Asteroid)
return QObject::tr("Asteroids & comets");
else if (classification == Body::Invisible)
return QObject::tr("Reference points");
else if (classification == Body::SmallBody) // TODO: should have a separate
return QObject::tr("Minor moons"); // category for this.
else
return QObject::tr("Other objects");
}
// Override QAbstractTableModel::data()
QVariant SolarSystemTreeModel::data(const QModelIndex& index, int role) const
{
Selection sel = objectAtIndex(index);
if (role != Qt::DisplayRole)
return QVariant();
TreeItem* item = itemAtIndex(index);
// See if the tree item is a group
if (item->classification != 0)
{
if (index.column() == NameColumn)
return classificationName(item->classification);
else
return QVariant();
}
// Tree item is an object, not a group
Selection sel = item->obj;
switch (index.column())
{
case NameColumn:
@ -388,6 +635,10 @@ SolarSystemBrowser::SolarSystemBrowser(CelestiaCore* _appCore, QWidget* parent)
connect(refreshButton, SIGNAL(clicked()), this, SLOT(slotRefreshTree()));
layout->addWidget(refreshButton);
groupCheckBox = new QCheckBox(tr("Group objects by class"));
connect(groupCheckBox, SIGNAL(clicked()), this, SLOT(slotRefreshTree()));
layout->addWidget(groupCheckBox);
slotRefreshTree();
setLayout(layout);
@ -412,16 +663,20 @@ void SolarSystemBrowser::slotRefreshTree()
if (!solarSys)
return;
//Selection sun = appCore->getSimulation()->getUniverse()->find("Sol");
Star* rootStar = solarSys->getStar();
// We want to show all gravitationally associated stars in the
// browser; follow the chain up the parent star or barycenter.
while (rootStar->getOrbitBarycenter() != NULL)
{
rootStar = rootStar->getOrbitBarycenter();
}
solarSystemModel->buildModel(*rootStar);
bool groupByClass = groupCheckBox->checkState() == Qt::Checked;
solarSystemModel->buildModel(rootStar, groupByClass);
treeView->resizeColumnToContents(SolarSystemTreeModel::NameColumn);
treeView->clearSelection();
}

View File

@ -17,6 +17,7 @@
class QAbstractItemModel;
class QTreeView;
class QCheckBox;
class CelestiaCore;
class SolarSystemTreeModel;
@ -43,6 +44,8 @@ Q_OBJECT
SolarSystemTreeModel* solarSystemModel;
QTreeView* treeView;
QCheckBox* groupCheckBox;
};
#endif // _QTSOLARSYSTEMBROWSER_H_