2008-01-05 22:45:49 -07:00
|
|
|
// qtcelestialbrowser.cpp
|
|
|
|
//
|
|
|
|
// Copyright (C) 2007-2008, Celestia Development Team
|
|
|
|
// celestia-developers@lists.sourceforge.net
|
|
|
|
//
|
2008-01-14 01:12:50 -07:00
|
|
|
// Star browser widget for Qt4 front-end.
|
2008-01-05 22:45:49 -07:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2009-12-02 15:06:19 -07:00
|
|
|
#include <celestia/celestiacore.h>
|
2008-01-05 22:45:49 -07:00
|
|
|
#include "qtcelestialbrowser.h"
|
2008-01-14 01:12:50 -07:00
|
|
|
#include "qtcolorswatchwidget.h"
|
2008-01-08 18:30:10 -07:00
|
|
|
#include <QAbstractItemModel>
|
|
|
|
#include <QTreeView>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QRadioButton>
|
2008-01-08 21:06:15 -07:00
|
|
|
#include <QComboBox>
|
|
|
|
#include <QCheckBox>
|
2008-01-08 18:30:10 -07:00
|
|
|
#include <QVBoxLayout>
|
2008-01-08 21:06:15 -07:00
|
|
|
#include <QHBoxLayout>
|
|
|
|
#include <QGridLayout>
|
|
|
|
#include <QGroupBox>
|
2008-01-08 23:02:14 -07:00
|
|
|
#include <QLabel>
|
2008-01-11 18:38:09 -07:00
|
|
|
#include <QLineEdit>
|
|
|
|
#include <QRegExp>
|
2008-01-14 01:12:50 -07:00
|
|
|
#include <QFontMetrics>
|
2008-01-10 23:06:10 -07:00
|
|
|
#include <cstring>
|
2008-01-08 18:30:10 -07:00
|
|
|
#include <vector>
|
|
|
|
#include <set>
|
2008-01-11 13:48:41 -07:00
|
|
|
#include <algorithm>
|
2008-01-05 22:45:49 -07:00
|
|
|
|
2009-07-15 21:48:44 -06:00
|
|
|
using namespace Eigen;
|
2008-01-08 18:30:10 -07:00
|
|
|
using namespace std;
|
2008-01-05 22:45:49 -07:00
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
class StarFilterPredicate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
StarFilterPredicate();
|
|
|
|
bool operator()(const Star* star) const;
|
|
|
|
|
2018-09-22 07:13:49 -06:00
|
|
|
bool planetsFilterEnabled{false};
|
|
|
|
bool multipleFilterEnabled{false};
|
|
|
|
bool barycentersFilterEnabled{false};
|
|
|
|
bool omitBarycenters{true};
|
|
|
|
bool spectralTypeFilterEnabled{false};
|
2008-01-11 18:38:09 -07:00
|
|
|
QRegExp spectralTypeFilter;
|
2008-01-10 23:06:10 -07:00
|
|
|
SolarSystemCatalog* solarSystems;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
class StarPredicate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum Criterion
|
|
|
|
{
|
|
|
|
Distance,
|
|
|
|
Brightness,
|
2008-01-10 23:06:10 -07:00
|
|
|
IntrinsicBrightness,
|
|
|
|
Alphabetical,
|
|
|
|
SpectralType
|
2008-01-08 18:30:10 -07:00
|
|
|
};
|
|
|
|
|
2018-04-27 07:40:35 -06:00
|
|
|
StarPredicate(Criterion _criterion, const UniversalCoord& _observerPos, const Universe* _universe);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
bool operator()(const Star* star0, const Star* star1) const;
|
2018-03-11 07:12:58 -06:00
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
private:
|
|
|
|
Criterion criterion;
|
2009-07-15 21:48:44 -06:00
|
|
|
Vector3f pos;
|
2008-01-08 18:30:10 -07:00
|
|
|
UniversalCoord ucPos;
|
2018-04-27 07:40:35 -06:00
|
|
|
const Universe* universe;
|
2008-01-08 18:30:10 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class StarTableModel : public QAbstractTableModel
|
|
|
|
{
|
|
|
|
public:
|
2018-09-22 07:13:49 -06:00
|
|
|
StarTableModel(const Universe* _universe) : universe(_universe) {};
|
|
|
|
virtual ~StarTableModel() = default;
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
// Methods from QAbstractTableModel
|
|
|
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
|
|
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
|
|
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
|
|
|
int rowCount(const QModelIndex& index) const;
|
|
|
|
int columnCount(const QModelIndex& index) const;
|
2008-01-10 23:06:10 -07:00
|
|
|
void sort(int column, Qt::SortOrder order);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
enum Predicate
|
|
|
|
{
|
|
|
|
DistancePredicate,
|
|
|
|
BrightnessPredicate,
|
|
|
|
HasPlanetsPredicate
|
|
|
|
};
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
NameColumn = 0,
|
|
|
|
DistanceColumn = 1,
|
2008-01-10 23:06:10 -07:00
|
|
|
AppMagColumn = 2,
|
|
|
|
AbsMagColumn = 3,
|
2008-01-08 21:06:15 -07:00
|
|
|
SpectralTypeColumn = 4,
|
|
|
|
};
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
void populate(const UniversalCoord& _observerPos,
|
2008-04-04 12:11:37 -06:00
|
|
|
double _now,
|
2008-01-11 18:38:09 -07:00
|
|
|
StarFilterPredicate& filterPred,
|
2008-01-08 18:30:10 -07:00
|
|
|
StarPredicate::Criterion criterion,
|
|
|
|
unsigned int nStars);
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
Selection itemAtRow(unsigned int row);
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
private:
|
|
|
|
const Universe* universe;
|
2018-09-22 07:13:49 -06:00
|
|
|
UniversalCoord observerPos{ 0.0, 0.0, 0.0 };
|
|
|
|
double now{ astro::J2000 };
|
2008-01-08 21:06:15 -07:00
|
|
|
vector<Star*> stars;
|
2008-01-08 18:30:10 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
/****** Virtual methods from QAbstractTableModel *******/
|
|
|
|
|
|
|
|
// Override QAbstractTableModel::flags()
|
2018-09-22 07:13:49 -06:00
|
|
|
Qt::ItemFlags StarTableModel::flags(const QModelIndex& /*unused*/) const
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
|
|
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
// Override QAbstractTableModel::data()
|
2008-01-08 18:30:10 -07:00
|
|
|
QVariant StarTableModel::data(const QModelIndex& index, int role) const
|
|
|
|
{
|
|
|
|
int row = index.row();
|
|
|
|
if (row < 0 || row >= (int) stars.size())
|
|
|
|
{
|
|
|
|
// Out of range
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Star* star = stars[row];
|
|
|
|
|
2008-01-14 01:12:50 -07:00
|
|
|
if (role == Qt::DisplayRole)
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
2008-01-14 01:12:50 -07:00
|
|
|
switch (index.column())
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
2008-01-14 01:12:50 -07:00
|
|
|
case NameColumn:
|
|
|
|
{
|
|
|
|
string starNameString = ReplaceGreekLetterAbbr(universe->getStarCatalog()->getStarName(*star));
|
|
|
|
return QVariant(QString::fromUtf8(starNameString.c_str()));
|
|
|
|
}
|
|
|
|
case DistanceColumn:
|
|
|
|
{
|
2009-07-24 00:59:54 -06:00
|
|
|
double distance = star->getPosition(now).distanceFromLy(observerPos);
|
|
|
|
return QVariant(distance);
|
2008-01-14 01:12:50 -07:00
|
|
|
}
|
|
|
|
case AppMagColumn:
|
|
|
|
{
|
2009-07-24 00:59:54 -06:00
|
|
|
double distance = star->getPosition(now).distanceFromLy(observerPos);
|
2008-01-14 01:12:50 -07:00
|
|
|
return QString("%1").arg((double) star->getApparentMagnitude((float) distance), 0, 'f', 2);
|
|
|
|
}
|
|
|
|
case AbsMagColumn:
|
|
|
|
return QString("%1").arg(star->getAbsoluteMagnitude(), 0, 'f', 2);
|
|
|
|
case SpectralTypeColumn:
|
|
|
|
return QString(star->getSpectralType());
|
|
|
|
default:
|
|
|
|
return QVariant();
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
2008-01-14 01:12:50 -07:00
|
|
|
}
|
|
|
|
else if (role == Qt::ToolTipRole)
|
|
|
|
{
|
|
|
|
// Experimental feature: show the HD catalog number of a star as a tooltip
|
|
|
|
switch (index.column())
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
2008-01-14 01:12:50 -07:00
|
|
|
case NameColumn:
|
|
|
|
{
|
2018-07-03 10:52:34 -06:00
|
|
|
uint32_t hipCatNo = star->getCatalogNumber();
|
|
|
|
uint32_t hdCatNo = universe->getStarCatalog()->crossIndex(StarDatabase::HenryDraper, hipCatNo);
|
2008-01-14 01:12:50 -07:00
|
|
|
if (hdCatNo != Star::InvalidCatalogNumber)
|
|
|
|
return QString("HD %1").arg(hdCatNo);
|
|
|
|
else
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QVariant();
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
2008-01-14 01:12:50 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-01-08 18:30:10 -07:00
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
// Override QAbstractDataModel::headerData()
|
2008-04-04 12:11:37 -06:00
|
|
|
QVariant StarTableModel::headerData(int section, Qt::Orientation /* orientation */, int role) const
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
|
|
|
if (role != Qt::DisplayRole)
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
switch (section)
|
|
|
|
{
|
|
|
|
case 0:
|
2010-04-13 04:14:57 -06:00
|
|
|
return _("Name");
|
2008-01-08 18:30:10 -07:00
|
|
|
case 1:
|
2010-04-13 04:14:57 -06:00
|
|
|
return _("Distance (ly)");
|
2008-01-08 18:30:10 -07:00
|
|
|
case 2:
|
2010-04-13 04:14:57 -06:00
|
|
|
return _("App. mag");
|
2008-01-08 18:30:10 -07:00
|
|
|
case 3:
|
2010-04-13 04:14:57 -06:00
|
|
|
return _("Abs. mag");
|
2008-01-08 18:30:10 -07:00
|
|
|
case 4:
|
2010-04-13 04:14:57 -06:00
|
|
|
return _("Type");
|
2008-01-08 18:30:10 -07:00
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
// Override QAbstractDataModel::rowCount()
|
2018-09-22 07:13:49 -06:00
|
|
|
int StarTableModel::rowCount(const QModelIndex& /*unused*/) const
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
|
|
|
return (int) stars.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
// Override QAbstractDataModel::columnCount()
|
2018-09-22 07:13:49 -06:00
|
|
|
int StarTableModel::columnCount(const QModelIndex& /*unused*/) const
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
StarPredicate::StarPredicate(Criterion _criterion,
|
2018-04-27 07:40:35 -06:00
|
|
|
const UniversalCoord& _observerPos,
|
|
|
|
const Universe *_universe) :
|
2008-01-08 18:30:10 -07:00
|
|
|
criterion(_criterion),
|
2018-04-27 07:40:35 -06:00
|
|
|
ucPos(_observerPos),
|
|
|
|
universe(_universe)
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
2009-07-16 20:35:24 -06:00
|
|
|
pos = ucPos.toLy().cast<float>();
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool StarPredicate::operator()(const Star* star0, const Star* star1) const
|
|
|
|
{
|
|
|
|
switch (criterion)
|
|
|
|
{
|
|
|
|
case Distance:
|
2009-07-15 21:48:44 -06:00
|
|
|
return ((pos - star0->getPosition()).squaredNorm() <
|
|
|
|
(pos - star1->getPosition()).squaredNorm());
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
case Brightness:
|
|
|
|
{
|
2009-07-15 21:48:44 -06:00
|
|
|
float d0 = (pos - star0->getPosition()).norm();
|
|
|
|
float d1 = (pos - star1->getPosition()).norm();
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
// If the stars are closer than one light year, use
|
|
|
|
// a more precise distance estimate.
|
|
|
|
if (d0 < 1.0f)
|
2009-07-15 21:48:44 -06:00
|
|
|
d0 = ucPos.offsetFromLy(star0->getPosition()).norm();
|
2008-01-08 18:30:10 -07:00
|
|
|
if (d1 < 1.0f)
|
2009-07-15 21:48:44 -06:00
|
|
|
d1 = ucPos.offsetFromLy(star1->getPosition()).norm();
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
return (star0->getApparentMagnitude(d0) <
|
|
|
|
star1->getApparentMagnitude(d1));
|
|
|
|
}
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
case IntrinsicBrightness:
|
|
|
|
return star0->getAbsoluteMagnitude() < star1->getAbsoluteMagnitude();
|
|
|
|
|
|
|
|
case SpectralType:
|
|
|
|
return strcmp(star0->getSpectralType(), star1->getSpectralType()) < 0;
|
|
|
|
|
|
|
|
case Alphabetical:
|
2018-04-27 07:40:35 -06:00
|
|
|
return strcmp(universe->getStarCatalog()->getStarName(*star0, true).c_str(), universe->getStarCatalog()->getStarName(*star1, true).c_str()) < 0;
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
StarFilterPredicate::StarFilterPredicate() :
|
2018-09-22 07:13:49 -06:00
|
|
|
|
|
|
|
solarSystems(nullptr)
|
2008-01-10 23:06:10 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool StarFilterPredicate::operator()(const Star* star) const
|
|
|
|
{
|
2008-01-11 18:38:09 -07:00
|
|
|
if (omitBarycenters)
|
|
|
|
{
|
|
|
|
if (!star->getVisibility())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
if (planetsFilterEnabled)
|
|
|
|
{
|
2018-09-22 07:13:49 -06:00
|
|
|
if (solarSystems == nullptr)
|
2008-01-10 23:06:10 -07:00
|
|
|
return true;
|
|
|
|
|
|
|
|
SolarSystemCatalog::iterator iter = solarSystems->find(star->getCatalogNumber());
|
|
|
|
if (iter == solarSystems->end())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-11-16 15:47:17 -07:00
|
|
|
if (multipleFilterEnabled)
|
|
|
|
{
|
|
|
|
if (!star->getOrbitBarycenter() || star->getCatalogNumber() == 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-08 02:27:41 -07:00
|
|
|
if (barycentersFilterEnabled)
|
|
|
|
{
|
|
|
|
if (star->getVisibility())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-01-11 18:38:09 -07:00
|
|
|
if (spectralTypeFilterEnabled)
|
|
|
|
{
|
|
|
|
if (!spectralTypeFilter.exactMatch(star->getSpectralType()))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Override QAbstractDataMode::sort()
|
|
|
|
void StarTableModel::sort(int column, Qt::SortOrder order)
|
|
|
|
{
|
|
|
|
StarPredicate::Criterion criterion = StarPredicate::Alphabetical;
|
|
|
|
|
|
|
|
switch (column)
|
|
|
|
{
|
|
|
|
case NameColumn:
|
|
|
|
criterion = StarPredicate::Alphabetical;
|
|
|
|
break;
|
|
|
|
case DistanceColumn:
|
|
|
|
criterion = StarPredicate::Distance;
|
|
|
|
break;
|
|
|
|
case AbsMagColumn:
|
|
|
|
criterion = StarPredicate::IntrinsicBrightness;
|
|
|
|
break;
|
|
|
|
case AppMagColumn:
|
|
|
|
criterion = StarPredicate::Brightness;
|
|
|
|
break;
|
|
|
|
case SpectralTypeColumn:
|
|
|
|
criterion = StarPredicate::SpectralType;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-27 07:40:35 -06:00
|
|
|
StarPredicate pred(criterion, observerPos, universe);
|
2008-01-10 23:06:10 -07:00
|
|
|
|
|
|
|
std::sort(stars.begin(), stars.end(), pred);
|
|
|
|
|
|
|
|
if (order == Qt::DescendingOrder)
|
|
|
|
reverse(stars.begin(), stars.end());
|
|
|
|
|
|
|
|
dataChanged(index(0, 0), index(stars.size() - 1, 4));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
void StarTableModel::populate(const UniversalCoord& _observerPos,
|
2008-04-04 12:11:37 -06:00
|
|
|
double _now,
|
2008-01-11 18:38:09 -07:00
|
|
|
StarFilterPredicate& filterPred,
|
2008-01-08 18:30:10 -07:00
|
|
|
StarPredicate::Criterion criterion,
|
|
|
|
unsigned int nStars)
|
|
|
|
{
|
|
|
|
const StarDatabase& stardb = *universe->getStarCatalog();
|
2018-03-11 07:12:58 -06:00
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
observerPos = _observerPos;
|
2008-04-04 12:11:37 -06:00
|
|
|
now = _now;
|
2008-01-08 18:30:10 -07:00
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
typedef multiset<Star*, StarPredicate> StarSet;
|
2018-04-27 07:40:35 -06:00
|
|
|
StarPredicate pred(criterion, observerPos, universe);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
2008-01-11 18:38:09 -07:00
|
|
|
// Apply the filter
|
|
|
|
vector<Star*> filteredStars;
|
|
|
|
unsigned int totalStars = stardb.size();
|
|
|
|
unsigned int i = 0;
|
|
|
|
filteredStars.reserve(totalStars);
|
|
|
|
for (i = 0; i < totalStars; i++)
|
|
|
|
{
|
|
|
|
Star* star = stardb.getStar(i);
|
|
|
|
if (!filterPred(star))
|
|
|
|
filteredStars.push_back(star);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't try and show more stars than remain after the filter
|
|
|
|
if (filteredStars.size() < nStars)
|
|
|
|
nStars = filteredStars.size();
|
2008-01-08 21:06:15 -07:00
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
// Clear out the results of the previous populate() call
|
|
|
|
if (stars.size() != 0)
|
2008-01-08 21:06:15 -07:00
|
|
|
{
|
2017-08-08 15:52:55 -06:00
|
|
|
beginResetModel();
|
2008-01-10 23:06:10 -07:00
|
|
|
stars.clear();
|
2017-08-08 15:52:55 -06:00
|
|
|
endResetModel();
|
2008-01-08 21:06:15 -07:00
|
|
|
}
|
|
|
|
|
2008-01-11 18:38:09 -07:00
|
|
|
if (filteredStars.empty())
|
|
|
|
return;
|
2008-01-08 18:30:10 -07:00
|
|
|
|
2008-01-11 18:38:09 -07:00
|
|
|
StarSet firstStars(pred);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
// We'll need at least nStars in the set, so first fill
|
|
|
|
// up the list indiscriminately.
|
|
|
|
for (i = 0; i < nStars; i++)
|
|
|
|
{
|
2008-01-11 18:38:09 -07:00
|
|
|
firstStars.insert(filteredStars[i]);
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// From here on, only add a star to the set if it's
|
2008-01-10 23:06:10 -07:00
|
|
|
// A better match than the worst matching star already
|
2008-01-08 18:30:10 -07:00
|
|
|
// in the set.
|
|
|
|
const Star* lastStar = *--firstStars.end();
|
2008-01-11 18:38:09 -07:00
|
|
|
for (; i < filteredStars.size(); i++)
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
2008-01-11 18:38:09 -07:00
|
|
|
Star* star = filteredStars[i];
|
|
|
|
if (pred(star, lastStar))
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
|
|
|
firstStars.insert(star);
|
|
|
|
firstStars.erase(--firstStars.end());
|
|
|
|
lastStar = *--firstStars.end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move the best matching stars into the vector
|
|
|
|
stars.reserve(nStars);
|
2018-09-22 07:13:49 -06:00
|
|
|
for (const auto& star : firstStars)
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
2018-09-22 07:13:49 -06:00
|
|
|
stars.push_back(star);
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
beginInsertRows(QModelIndex(), 0, stars.size());
|
|
|
|
endInsertRows();
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
Selection StarTableModel::itemAtRow(unsigned int row)
|
|
|
|
{
|
|
|
|
if (row >= stars.size())
|
|
|
|
return Selection();
|
|
|
|
else
|
|
|
|
return Selection(stars[row]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
CelestialBrowser::CelestialBrowser(CelestiaCore* _appCore, QWidget* parent) :
|
|
|
|
QWidget(parent),
|
|
|
|
appCore(_appCore),
|
2018-09-22 07:13:49 -06:00
|
|
|
starModel(nullptr),
|
|
|
|
treeView(nullptr),
|
|
|
|
searchResultLabel(nullptr),
|
|
|
|
closestButton(nullptr),
|
|
|
|
brightestButton(nullptr)
|
2008-01-08 18:30:10 -07:00
|
|
|
{
|
|
|
|
treeView = new QTreeView();
|
|
|
|
treeView->setRootIsDecorated(false);
|
|
|
|
treeView->setAlternatingRowColors(true);
|
|
|
|
treeView->setItemsExpandable(false);
|
|
|
|
treeView->setUniformRowHeights(true);
|
2008-01-08 21:06:15 -07:00
|
|
|
treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
2008-01-10 23:06:10 -07:00
|
|
|
treeView->setSortingEnabled(true);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
starModel = new StarTableModel(appCore->getSimulation()->getUniverse());
|
|
|
|
treeView->setModel(starModel);
|
|
|
|
|
2008-01-14 01:12:50 -07:00
|
|
|
#if 0
|
|
|
|
QFontMetrics fm = fontMetrics();
|
|
|
|
treeView->setColumnWidth(StarTableModel::DistanceColumn, fm.width(starModel->headerData(StarTableModel::DistanceColumn)));
|
|
|
|
treeView->setColumnWidth(StarTableModel::AppMagColumn, 30);
|
|
|
|
treeView->setColumnWidth(StarTableModel::AbsMagColumn, 30);
|
|
|
|
#endif
|
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(treeView, SIGNAL(customContextMenuRequested(const QPoint&)),
|
|
|
|
this, SLOT(slotContextMenu(const QPoint&)));
|
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
QVBoxLayout* layout = new QVBoxLayout();
|
|
|
|
layout->addWidget(treeView);
|
|
|
|
|
2008-01-13 16:19:24 -07:00
|
|
|
searchResultLabel = new QLabel("");
|
|
|
|
layout->addWidget(searchResultLabel);
|
|
|
|
|
2008-11-15 11:43:13 -07:00
|
|
|
QGroupBox* starGroup = new QGroupBox();
|
|
|
|
QGridLayout* starGroupLayout = new QGridLayout();
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
// Buttons to select filtering criterion for stars
|
2010-04-13 04:14:57 -06:00
|
|
|
closestButton = new QRadioButton(_("Closest Stars"));
|
2008-01-08 18:30:10 -07:00
|
|
|
connect(closestButton, SIGNAL(clicked()), this, SLOT(slotRefreshTable()));
|
2008-11-15 11:43:13 -07:00
|
|
|
starGroupLayout->addWidget(closestButton, 0, 0);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
brightestButton = new QRadioButton(_("Brightest Stars"));
|
2008-01-08 18:30:10 -07:00
|
|
|
connect(brightestButton, SIGNAL(clicked()), this, SLOT(slotRefreshTable()));
|
2008-11-15 11:43:13 -07:00
|
|
|
starGroupLayout->addWidget(brightestButton, 0, 1);
|
|
|
|
|
|
|
|
starGroup->setLayout(starGroupLayout);
|
|
|
|
layout->addWidget(starGroup);
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
closestButton->setChecked(true);
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
// Additional filtering controls
|
2010-04-13 04:14:57 -06:00
|
|
|
QGroupBox* filterGroup = new QGroupBox(_("Filter"));
|
2008-11-16 15:47:17 -07:00
|
|
|
QGridLayout* filterGroupLayout = new QGridLayout();
|
2018-03-11 07:12:58 -06:00
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
withPlanetsFilterBox = new QCheckBox(_("With Planets"));
|
2008-01-10 23:06:10 -07:00
|
|
|
connect(withPlanetsFilterBox, SIGNAL(clicked()), this, SLOT(slotRefreshTable()));
|
2008-11-16 15:47:17 -07:00
|
|
|
filterGroupLayout->addWidget(withPlanetsFilterBox, 0, 0);
|
2008-01-10 23:06:10 -07:00
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
multipleFilterBox = new QCheckBox(_("Multiple Stars"));
|
2017-02-08 02:27:41 -07:00
|
|
|
connect(multipleFilterBox, SIGNAL(clicked()), this, SLOT(slotUncheckBarycentersFilterBox()));
|
|
|
|
|
|
|
|
barycentersFilterBox = new QCheckBox(_("Barycenters"));
|
|
|
|
connect(barycentersFilterBox, SIGNAL(clicked()), this, SLOT(slotUncheckMultipleFilterBox()));
|
|
|
|
|
2008-11-16 15:47:17 -07:00
|
|
|
filterGroupLayout->addWidget(multipleFilterBox, 1, 0);
|
2017-02-08 02:27:41 -07:00
|
|
|
filterGroupLayout->addWidget(barycentersFilterBox, 1, 1);
|
2008-01-11 18:38:09 -07:00
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
filterGroupLayout->addWidget(new QLabel(_("Spectral Type")), 0, 1);
|
2008-01-11 18:38:09 -07:00
|
|
|
spectralTypeFilterBox = new QLineEdit();
|
2008-01-12 19:40:25 -07:00
|
|
|
connect(spectralTypeFilterBox, SIGNAL(editingFinished()), this, SLOT(slotRefreshTable()));
|
2008-11-16 15:47:17 -07:00
|
|
|
filterGroupLayout->addWidget(spectralTypeFilterBox, 0, 2);
|
2008-01-11 18:38:09 -07:00
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
filterGroup->setLayout(filterGroupLayout);
|
|
|
|
layout->addWidget(filterGroup);
|
|
|
|
// End filtering controls
|
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
QPushButton* refreshButton = new QPushButton(_("Refresh"));
|
2008-01-08 18:30:10 -07:00
|
|
|
connect(refreshButton, SIGNAL(clicked()), this, SLOT(slotRefreshTable()));
|
|
|
|
layout->addWidget(refreshButton);
|
|
|
|
|
2008-01-10 23:06:10 -07:00
|
|
|
// Controls for marking selected objects
|
2010-04-13 04:14:57 -06:00
|
|
|
QGroupBox* markGroup = new QGroupBox(_("Markers"));
|
2008-01-08 21:06:15 -07:00
|
|
|
QGridLayout* markGroupLayout = new QGridLayout();
|
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
QPushButton* markSelectedButton = new QPushButton(_("Mark Selected"));
|
2008-01-08 21:06:15 -07:00
|
|
|
connect(markSelectedButton, SIGNAL(clicked()), this, SLOT(slotMarkSelected()));
|
2010-04-13 04:14:57 -06:00
|
|
|
markSelectedButton->setToolTip(_("Mark stars selected in list view"));
|
2008-11-15 11:43:13 -07:00
|
|
|
markGroupLayout->addWidget(markSelectedButton, 0, 0, 1, 2);
|
2008-01-08 21:06:15 -07:00
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
QPushButton* clearMarkersButton = new QPushButton(_("Clear Markers"));
|
2008-01-14 01:12:50 -07:00
|
|
|
connect(clearMarkersButton, SIGNAL(clicked()), this, SLOT(slotClearMarkers()));
|
2010-04-13 04:14:57 -06:00
|
|
|
clearMarkersButton->setToolTip(_("Remove all existing markers"));
|
2008-11-15 11:43:13 -07:00
|
|
|
markGroupLayout->addWidget(clearMarkersButton, 0, 2, 1, 2);
|
2008-01-14 01:12:50 -07:00
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
markerSymbolBox = new QComboBox();
|
|
|
|
markerSymbolBox->setEditable(false);
|
2010-04-13 04:14:57 -06:00
|
|
|
markerSymbolBox->addItem(_("None"));
|
|
|
|
markerSymbolBox->addItem(_("Diamond"), (int) MarkerRepresentation::Diamond);
|
|
|
|
markerSymbolBox->addItem(_("Triangle"), (int) MarkerRepresentation::Triangle);
|
|
|
|
markerSymbolBox->addItem(_("Square"), (int) MarkerRepresentation::Square);
|
|
|
|
markerSymbolBox->addItem(_("Plus"), (int) MarkerRepresentation::Plus);
|
|
|
|
markerSymbolBox->addItem(_("X"), (int) MarkerRepresentation::X);
|
|
|
|
markerSymbolBox->addItem(_("Circle"), (int) MarkerRepresentation::Circle);
|
|
|
|
markerSymbolBox->addItem(_("Left Arrow"), (int) MarkerRepresentation::LeftArrow);
|
|
|
|
markerSymbolBox->addItem(_("Right Arrow"), (int) MarkerRepresentation::RightArrow);
|
|
|
|
markerSymbolBox->addItem(_("Up Arrow"), (int) MarkerRepresentation::UpArrow);
|
|
|
|
markerSymbolBox->addItem(_("Down Arrow"), (int) MarkerRepresentation::DownArrow);
|
2008-01-08 21:06:15 -07:00
|
|
|
markerSymbolBox->setCurrentIndex(1);
|
2010-04-13 04:14:57 -06:00
|
|
|
markerSymbolBox->setToolTip(_("Select marker symbol"));
|
2008-01-14 01:12:50 -07:00
|
|
|
markGroupLayout->addWidget(markerSymbolBox, 1, 0);
|
2008-01-08 23:02:14 -07:00
|
|
|
|
2008-11-15 11:43:13 -07:00
|
|
|
markerSizeBox = new QComboBox();
|
|
|
|
markerSizeBox->setEditable(true);
|
2010-04-13 04:14:57 -06:00
|
|
|
markerSizeBox->addItem("3", 3.0);
|
|
|
|
markerSizeBox->addItem("5", 5.0);
|
|
|
|
markerSizeBox->addItem("10", 10.0);
|
|
|
|
markerSizeBox->addItem("20", 20.0);
|
|
|
|
markerSizeBox->addItem("50", 50.0);
|
|
|
|
markerSizeBox->addItem("100", 100.0);
|
|
|
|
markerSizeBox->addItem("200", 200.0);
|
2008-11-15 11:43:13 -07:00
|
|
|
markerSizeBox->setCurrentIndex(3);
|
2010-04-13 04:14:57 -06:00
|
|
|
markerSizeBox->setToolTip(_("Select marker size"));
|
2008-11-15 11:43:13 -07:00
|
|
|
markGroupLayout->addWidget(markerSizeBox, 1, 1);
|
|
|
|
|
2008-01-14 01:12:50 -07:00
|
|
|
colorSwatch = new ColorSwatchWidget(QColor("cyan"));
|
2010-04-13 04:14:57 -06:00
|
|
|
colorSwatch->setToolTip(_("Click to select marker color"));
|
2008-11-15 11:43:13 -07:00
|
|
|
markGroupLayout->addWidget(colorSwatch, 1, 2);
|
2018-03-11 07:12:58 -06:00
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
labelMarkerBox = new QCheckBox(_("Label"));
|
2008-11-15 11:43:13 -07:00
|
|
|
markGroupLayout->addWidget(labelMarkerBox, 1, 3);
|
2008-01-08 21:06:15 -07:00
|
|
|
|
|
|
|
markGroup->setLayout(markGroupLayout);
|
|
|
|
layout->addWidget(markGroup);
|
2008-01-10 23:06:10 -07:00
|
|
|
// End marking group
|
2008-01-08 21:06:15 -07:00
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
slotRefreshTable();
|
|
|
|
|
|
|
|
setLayout(layout);
|
2008-01-05 22:45:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-08 23:02:14 -07:00
|
|
|
/******* Slots ********/
|
2017-02-08 02:27:41 -07:00
|
|
|
void CelestialBrowser::slotUncheckMultipleFilterBox()
|
|
|
|
{
|
|
|
|
multipleFilterBox->setChecked(false);
|
|
|
|
slotRefreshTable();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CelestialBrowser::slotUncheckBarycentersFilterBox()
|
|
|
|
{
|
|
|
|
barycentersFilterBox->setChecked(false);
|
|
|
|
slotRefreshTable();
|
|
|
|
}
|
2008-01-08 23:02:14 -07:00
|
|
|
|
2008-01-08 18:30:10 -07:00
|
|
|
void CelestialBrowser::slotRefreshTable()
|
|
|
|
{
|
|
|
|
UniversalCoord observerPos = appCore->getSimulation()->getActiveObserver()->getPosition();
|
2008-04-04 12:11:37 -06:00
|
|
|
double now = appCore->getSimulation()->getTime();
|
2008-01-08 18:30:10 -07:00
|
|
|
|
|
|
|
StarPredicate::Criterion criterion = StarPredicate::Distance;
|
|
|
|
if (brightestButton->isChecked())
|
|
|
|
criterion = StarPredicate::Brightness;
|
2008-01-10 23:06:10 -07:00
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
treeView->clearSelection();
|
2008-01-11 18:38:09 -07:00
|
|
|
|
|
|
|
// Set up the filter
|
|
|
|
StarFilterPredicate filterPred;
|
|
|
|
filterPred.planetsFilterEnabled = withPlanetsFilterBox->checkState() == Qt::Checked;
|
2008-11-16 15:47:17 -07:00
|
|
|
filterPred.multipleFilterEnabled = multipleFilterBox->checkState() == Qt::Checked;
|
2017-02-08 02:27:41 -07:00
|
|
|
filterPred.barycentersFilterEnabled = barycentersFilterBox->checkState() == Qt::Checked;
|
|
|
|
filterPred.omitBarycenters = barycentersFilterBox->checkState() == Qt::Unchecked;
|
2008-01-11 18:38:09 -07:00
|
|
|
filterPred.solarSystems = appCore->getSimulation()->getUniverse()->getSolarSystemCatalog();
|
|
|
|
|
|
|
|
QRegExp re(spectralTypeFilterBox->text(),
|
|
|
|
Qt::CaseInsensitive,
|
|
|
|
QRegExp::Wildcard);
|
|
|
|
if (!re.isEmpty() && re.isValid())
|
|
|
|
{
|
|
|
|
filterPred.spectralTypeFilter = re;
|
|
|
|
filterPred.spectralTypeFilterEnabled = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
filterPred.spectralTypeFilterEnabled = false;
|
|
|
|
}
|
|
|
|
|
2008-04-04 12:11:37 -06:00
|
|
|
starModel->populate(observerPos, now, filterPred, criterion, 1000);
|
2008-01-13 16:19:24 -07:00
|
|
|
|
2008-01-14 01:12:50 -07:00
|
|
|
treeView->resizeColumnToContents(StarTableModel::DistanceColumn);
|
|
|
|
treeView->resizeColumnToContents(StarTableModel::AppMagColumn);
|
|
|
|
treeView->resizeColumnToContents(StarTableModel::AbsMagColumn);
|
|
|
|
|
2010-04-13 04:14:57 -06:00
|
|
|
searchResultLabel->setText(QString(_("%1 objects found")).arg(starModel->rowCount(QModelIndex())));
|
2008-01-08 21:06:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CelestialBrowser::slotContextMenu(const QPoint& pos)
|
|
|
|
{
|
|
|
|
QModelIndex index = treeView->indexAt(pos);
|
|
|
|
Selection sel = starModel->itemAtRow((unsigned int) index.row());
|
|
|
|
|
|
|
|
if (!sel.empty())
|
|
|
|
{
|
2008-01-22 03:35:08 -07:00
|
|
|
emit selectionContextMenuRequested(treeView->mapToGlobal(pos), sel);
|
2008-01-08 21:06:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CelestialBrowser::slotMarkSelected()
|
|
|
|
{
|
|
|
|
QItemSelectionModel* sm = treeView->selectionModel();
|
|
|
|
bool labelMarker = labelMarkerBox->checkState() == Qt::Checked;
|
|
|
|
bool convertOK = false;
|
|
|
|
QVariant markerData = markerSymbolBox->itemData(markerSymbolBox->currentIndex());
|
2008-05-22 14:30:45 -06:00
|
|
|
MarkerRepresentation::Symbol markerSymbol = (MarkerRepresentation::Symbol) markerData.toInt(&convertOK);
|
2008-11-15 11:43:13 -07:00
|
|
|
QVariant markerSize = markerSizeBox->itemData(markerSizeBox->currentIndex());
|
|
|
|
float size = (float) markerSize.toInt(&convertOK);
|
2008-01-14 01:12:50 -07:00
|
|
|
QColor markerColor = colorSwatch->color();
|
2008-01-08 23:02:14 -07:00
|
|
|
Color color((float) markerColor.redF(),
|
|
|
|
(float) markerColor.greenF(),
|
|
|
|
(float) markerColor.blueF());
|
2018-03-11 07:12:58 -06:00
|
|
|
|
2008-01-08 21:06:15 -07:00
|
|
|
Universe* universe = appCore->getSimulation()->getUniverse();
|
|
|
|
string label;
|
|
|
|
|
2008-04-13 17:25:47 -06:00
|
|
|
for (int row = 0; row < starModel->rowCount(QModelIndex()); row++)
|
2008-01-08 21:06:15 -07:00
|
|
|
{
|
2008-04-13 17:25:47 -06:00
|
|
|
if (sm->isRowSelected(row, QModelIndex()))
|
2008-01-08 21:06:15 -07:00
|
|
|
{
|
2008-04-13 17:25:47 -06:00
|
|
|
Selection sel = starModel->itemAtRow((unsigned int) row);
|
|
|
|
if (!sel.empty())
|
2008-01-08 21:06:15 -07:00
|
|
|
{
|
2008-04-13 17:25:47 -06:00
|
|
|
if (convertOK)
|
2008-01-08 21:06:15 -07:00
|
|
|
{
|
2008-04-13 17:25:47 -06:00
|
|
|
if (labelMarker)
|
|
|
|
{
|
2018-09-22 07:13:49 -06:00
|
|
|
if (sel.star() != nullptr)
|
2008-04-13 17:25:47 -06:00
|
|
|
label = universe->getStarCatalog()->getStarName(*sel.star());
|
|
|
|
label = ReplaceGreekLetterAbbr(label);
|
|
|
|
}
|
|
|
|
|
2008-05-22 14:30:45 -06:00
|
|
|
universe->markObject(sel,
|
2008-11-15 11:43:13 -07:00
|
|
|
MarkerRepresentation(markerSymbol, size, color, label),
|
2008-05-22 14:30:45 -06:00
|
|
|
1);
|
2008-04-13 17:25:47 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
universe->unmarkObject(sel, 1);
|
2008-01-08 21:06:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-08 18:30:10 -07:00
|
|
|
}
|
2008-01-08 23:02:14 -07:00
|
|
|
|
|
|
|
|
2008-01-14 01:12:50 -07:00
|
|
|
void CelestialBrowser::slotClearMarkers()
|
2008-01-08 23:02:14 -07:00
|
|
|
{
|
2008-01-14 01:12:50 -07:00
|
|
|
appCore->getSimulation()->getUniverse()->unmarkAll();
|
2008-01-08 23:02:14 -07:00
|
|
|
}
|