Added a rudimentary info panel to the Qt4 interface.

ver1_5_1
Chris Laurel 2008-01-22 10:35:49 +00:00
parent a97bc06603
commit d7520a1880
2 changed files with 359 additions and 0 deletions

View File

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

View File

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