Added a rudimentary info panel to the Qt4 interface.
parent
a97bc06603
commit
d7520a1880
|
@ -0,0 +1,318 @@
|
|||
// qtcelestiaactions.h
|
||||
//
|
||||
// Copyright (C) 2008, Celestia Development Team
|
||||
// celestia-developers@lists.sourceforge.net
|
||||
//
|
||||
// Information panel for Qt4 UI.
|
||||
//
|
||||
// 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 "celengine/astro.h"
|
||||
#include "celutil/utf8.h"
|
||||
#include <QTextBrowser>
|
||||
#include "qtinfopanel.h"
|
||||
|
||||
|
||||
// TODO: This should be moved to astro.cpp
|
||||
struct OrbitalElements
|
||||
{
|
||||
double semimajorAxis;
|
||||
double eccentricity;
|
||||
double inclination;
|
||||
double longAscendingNode;
|
||||
double argPericenter;
|
||||
double meanAnomaly;
|
||||
};
|
||||
|
||||
static void CalculateOsculatingElements(const Orbit& orbit,
|
||||
double t,
|
||||
double dt,
|
||||
OrbitalElements* elements);
|
||||
|
||||
|
||||
InfoPanel::InfoPanel(const QString& title, QWidget* parent) :
|
||||
QDockWidget(title, parent),
|
||||
textBrowser(NULL)
|
||||
{
|
||||
textBrowser = new QTextBrowser(this);
|
||||
textBrowser->setOpenExternalLinks(true);
|
||||
setWidget(textBrowser);
|
||||
}
|
||||
|
||||
|
||||
InfoPanel::~InfoPanel()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void InfoPanel::buildInfoPage(Selection sel, double t)
|
||||
{
|
||||
QString pageText;
|
||||
QTextStream stream(&pageText, QIODevice::WriteOnly);
|
||||
|
||||
pageHeader(stream);
|
||||
|
||||
if (sel.body() != NULL)
|
||||
{
|
||||
buildSolarSystemBodyPage(sel.body(), t, stream);
|
||||
}
|
||||
else if (sel.star() != NULL)
|
||||
{
|
||||
buildStarPage(sel.star(), stream);
|
||||
}
|
||||
else if (sel.deepsky() != NULL)
|
||||
{
|
||||
buildDSOPage(sel.deepsky(), stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream << "Error: no object selected!\n";
|
||||
}
|
||||
|
||||
pageFooter(stream);
|
||||
|
||||
textBrowser->setHtml(pageText);
|
||||
}
|
||||
|
||||
|
||||
void InfoPanel::pageHeader(QTextStream& stream)
|
||||
{
|
||||
stream << "<html><head><title>Info</title></head>\n";
|
||||
stream << "<body>\n";
|
||||
}
|
||||
|
||||
|
||||
void InfoPanel::pageFooter(QTextStream& stream)
|
||||
{
|
||||
stream << "</body></html>\n";
|
||||
}
|
||||
|
||||
|
||||
static QString boldText(const QString& s)
|
||||
{
|
||||
return QString("<b>") + s + QString("</b>");
|
||||
}
|
||||
|
||||
|
||||
static QString anchor(const QString& href, const QString& text)
|
||||
{
|
||||
return QString("<a href=\"") + href + QString("\">") + text + QString("</a>");
|
||||
}
|
||||
|
||||
|
||||
void InfoPanel::buildSolarSystemBodyPage(const Body* body,
|
||||
double t,
|
||||
QTextStream& stream)
|
||||
{
|
||||
stream << "<h1>" << body->getName().c_str() << "</h1><br>\n";
|
||||
|
||||
if (!body->getInfoURL().empty())
|
||||
{
|
||||
const char* infoURL = body->getInfoURL().c_str();
|
||||
stream << tr("Web info: ") << anchor(infoURL, infoURL) << "<br>\n";
|
||||
}
|
||||
|
||||
stream << "<br>\n";
|
||||
|
||||
bool isArtificial = body->getClassification() == Body::Spacecraft;
|
||||
|
||||
QString units(tr("km"));
|
||||
double radius = body->getRadius();
|
||||
if (radius < 1.0)
|
||||
{
|
||||
units = tr("m");
|
||||
radius *= 1000.0;
|
||||
}
|
||||
|
||||
//if (body->isEllipsoid())
|
||||
if (body->getModel() == InvalidResource)
|
||||
stream << boldText(tr("Equatorial radius: "));
|
||||
else
|
||||
stream << boldText(tr("Size: "));
|
||||
|
||||
stream << radius << " " << units << "<br>";
|
||||
|
||||
#if 0
|
||||
if (body->getOblateness() != 0.0f && body->isEllipsoid())
|
||||
{
|
||||
stream << boldText(tr("Oblateness: ")) << body->getOblateness() << "<br>\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
double orbitalPeriod = 0.0;
|
||||
if (body->getOrbit()->isPeriodic())
|
||||
orbitalPeriod = body->getOrbit()->getPeriod();
|
||||
|
||||
// Show rotation information for natural, periodic rotators
|
||||
if (body->getRotationModel()->isPeriodic() && !isArtificial)
|
||||
{
|
||||
double rotPeriod = body->getRotationModel()->getPeriod();
|
||||
|
||||
double dayLength = 0.0;
|
||||
if (body->getOrbit()->isPeriodic())
|
||||
{
|
||||
double siderealDaysPerYear = orbitalPeriod / rotPeriod;
|
||||
double solarDaysPerYear = siderealDaysPerYear - 1.0;
|
||||
if (solarDaysPerYear > 0.0001)
|
||||
{
|
||||
dayLength = orbitalPeriod / (siderealDaysPerYear - 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rotPeriod < 2.0)
|
||||
{
|
||||
rotPeriod *= 24.0;
|
||||
dayLength *= 24.0;
|
||||
units = tr("hours");
|
||||
}
|
||||
else
|
||||
{
|
||||
units = tr("days");
|
||||
}
|
||||
|
||||
stream << boldText(tr("Sidereal rotation period: ")) << rotPeriod << " " << units << "<br>\n";
|
||||
if (dayLength != 0.0)
|
||||
{
|
||||
stream << boldText(tr("Length of day: ")) << dayLength << " " << units << "<br>\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Orbit information
|
||||
if (orbitalPeriod != 0.0)
|
||||
{
|
||||
OrbitalElements elements;
|
||||
CalculateOsculatingElements(*body->getOrbit(),
|
||||
t,
|
||||
orbitalPeriod * 1.0e-6,
|
||||
&elements);
|
||||
|
||||
if (orbitalPeriod < 365.25 * 2.0)
|
||||
{
|
||||
units = tr("days");
|
||||
}
|
||||
else
|
||||
{
|
||||
units = tr("years");
|
||||
orbitalPeriod /= 365.25;
|
||||
}
|
||||
|
||||
stream << "<br><big><b>" << tr("Orbit information") << "</b></big><br>\n";
|
||||
stream << tr("Osculating elements for") << " " << astro::TDBtoUTC(t).toCStr() << "<br>\n";
|
||||
stream << "<i>[ Orbit reference plane info goes here ]</i><br>\n";
|
||||
stream << boldText(tr("Period: ")) << orbitalPeriod << " " << units << "<br>\n";
|
||||
|
||||
double sma = elements.semimajorAxis;
|
||||
if (sma > 2.5e7)
|
||||
{
|
||||
units = tr("AU");
|
||||
sma = astro::kilometersToAU(sma);
|
||||
}
|
||||
else
|
||||
{
|
||||
units = tr("km");
|
||||
}
|
||||
|
||||
stream << boldText(tr("Semi-major axis: ")) << sma << " " << units << "<br>\n";
|
||||
stream << boldText(tr("Eccentricity: ")) << elements.eccentricity << "<br>\n";
|
||||
stream << boldText(tr("Inclination: ")) << radToDeg(elements.inclination) << QString::fromUtf8(UTF8_DEGREE_SIGN) << "<br>\n";
|
||||
stream << boldText(tr("Pericenter distance: ")) << sma * (1 - elements.eccentricity) << " " << units << "<br>\n";
|
||||
stream << boldText(tr("Apocenter distance: ")) << sma * (1 + elements.eccentricity) << " " << units << "<br>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InfoPanel::buildStarPage(const Star* star, QTextStream& stream)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void InfoPanel::buildDSOPage(const DeepSkyObject* dso, QTextStream& stream)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void StateVectorToElements(const Point3d& position,
|
||||
const Vec3d& v,
|
||||
double GM,
|
||||
OrbitalElements* elements)
|
||||
{
|
||||
Vec3d R = position - Point3d(0.0, 0.0, 0.0);
|
||||
Vec3d L = R ^ v;
|
||||
double magR = R.length();
|
||||
double magL = L.length();
|
||||
double magV = v.length();
|
||||
L *= (1.0 / magL);
|
||||
|
||||
Vec3d W = L ^ (R / magR);
|
||||
|
||||
// Compute the semimajor axis
|
||||
double a = 1.0 / (2.0 / magR - square(magV) / GM);
|
||||
|
||||
// Compute the eccentricity
|
||||
double p = square(magL) / GM;
|
||||
double q = R * v;
|
||||
double ex = 1.0 - magR / a;
|
||||
double ey = q / sqrt(a * GM);
|
||||
double e = sqrt(ex * ex + ey * ey);
|
||||
|
||||
// Compute the mean anomaly
|
||||
double E = atan2(ey, ex);
|
||||
double M = E - e * sin(E);
|
||||
|
||||
// Compute the inclination
|
||||
double cosi = L * Vec3d(0, 1.0, 0);
|
||||
double i = 0.0;
|
||||
if (cosi < 1.0)
|
||||
i = acos(cosi);
|
||||
|
||||
// Compute the longitude of ascending node
|
||||
double Om = atan2(L.x, L.z);
|
||||
|
||||
// Compute the argument of pericenter
|
||||
Vec3d U = R / magR;
|
||||
double s_nu = (v * U) * sqrt(p / GM);
|
||||
double c_nu = (v * W) * sqrt(p / GM) - 1;
|
||||
s_nu /= e;
|
||||
c_nu /= e;
|
||||
Vec3d P = U * c_nu - W * s_nu;
|
||||
Vec3d Q = U * s_nu + W * c_nu;
|
||||
double om = atan2(P.y, Q.y);
|
||||
|
||||
// Compute the period
|
||||
double T = 2 * PI * sqrt(cube(a) / GM);
|
||||
T = T / 86400.0; // Convert from seconds to days
|
||||
|
||||
elements->semimajorAxis = a;
|
||||
elements->eccentricity = e;
|
||||
elements->inclination = i;
|
||||
elements->longAscendingNode = Om;
|
||||
elements->argPericenter = om;
|
||||
elements->meanAnomaly = M;
|
||||
}
|
||||
|
||||
|
||||
static void CalculateOsculatingElements(const Orbit& orbit,
|
||||
double t,
|
||||
double dt,
|
||||
OrbitalElements* elements)
|
||||
{
|
||||
Point3d p0 = orbit.positionAtTime(t - dt);
|
||||
Point3d p1 = orbit.positionAtTime(t);
|
||||
Point3d p2 = orbit.positionAtTime(t + dt);
|
||||
|
||||
Vec3d v0 = (p1 - p0) / dt;
|
||||
Vec3d v1 = (p2 - p1) / dt;
|
||||
Vec3d v = (p2 - p0) / (dt * 2);
|
||||
|
||||
double accel = ((v1 - v0) / dt).length();
|
||||
Vec3d r = p1 - Point3d(0.0, 0.0, 0.0);
|
||||
double GM = accel * (r * r);
|
||||
|
||||
StateVectorToElements(p1, v, GM, elements);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// qtcelestiaactions.h
|
||||
//
|
||||
// Copyright (C) 2008, Celestia Development Team
|
||||
// celestia-developers@lists.sourceforge.net
|
||||
//
|
||||
// Dockable information panel for Qt4 UI.
|
||||
//
|
||||
// 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 _INFOPANEL_H_
|
||||
#define _INFOPANEL_H_
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QTextStream>
|
||||
#include "celengine/selection.h"
|
||||
|
||||
class QTextBrowser;
|
||||
|
||||
class InfoPanel : public QDockWidget
|
||||
{
|
||||
public:
|
||||
InfoPanel(const QString& title, QWidget* parent);
|
||||
~InfoPanel();
|
||||
|
||||
void buildInfoPage(Selection sel, double t);
|
||||
|
||||
private:
|
||||
void pageHeader(QTextStream&);
|
||||
void pageFooter(QTextStream&);
|
||||
void buildSolarSystemBodyPage(const Body* body, double t, QTextStream&);
|
||||
void buildStarPage(const Star* star, QTextStream&);
|
||||
void buildDSOPage(const DeepSkyObject* dso, QTextStream&);
|
||||
|
||||
public:
|
||||
QTextBrowser* textBrowser;
|
||||
};
|
||||
|
||||
#endif // _INFOPANEL_H_
|
Loading…
Reference in New Issue