You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/kstars/kstars/tools/planetviewer.cpp

474 lines
13 KiB

/***************************************************************************
planetviewer.cpp - Display overhead view of the solar system
-------------------
begin : Sun May 25 2003
copyright : (C) 2003 by Jason Harris
email : jharris@30doradus.org
***************************************************************************/
/***************************************************************************
* *
* 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 <stdlib.h> //needed for abs() on some platforms
#include <tqfile.h>
#include <tqlayout.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <kiconloader.h>
#include "planetviewer.h"
#include "kstars.h"
#include "kstarsdata.h"
#include "ksutils.h"
#include "ksnumbers.h"
#include "ksplanetbase.h"
#include "dms.h"
#include "timestepbox.h"
#include "libtdeedu/extdate/extdatetimeedit.h"
#define AUMAX 48
PlanetViewer::PlanetViewer(TQWidget *parent, const char *name)
: KDialogBase( KDialogBase::Plain, i18n("Solar System Viewer"), Close, Close, parent, name ), PCat( ((KStars*)parent)->data() ), scale(1.0), isClockRunning(false), tmr(this)
{
TQFrame *page = plainPage();
TQVBoxLayout *vlay = new TQVBoxLayout( page, 0, spacingHint() );
pw = new PlanetViewerUI( page );
pw->map->setLimits( -48.0, 48.0, -48.0, 48.0 );
pw->map->setXAxisLabel( i18n( "axis label for x-coordinate of solar system viewer. AU means astronomical unit.", "X-position (AU)" ) );
pw->map->setYAxisLabel( i18n( "axis label for y-coordinate of solar system viewer. AU means astronomical unit.", "Y-position (AU)" ) );
pw->timeStep->setDaysOnly( true );
pw->timeStep->tsbox()->setValue( 1 ); //start with 1-day timestep
pw->RunButton->setPixmap( TDEGlobal::iconLoader()->loadIcon( "1rightarrow", TDEIcon::Toolbar ) );
pw->dateBox->setDate( ((KStars*)parent)->data()->lt().date() );
vlay->addWidget( pw );
resize( 500, 500 );
pw->map->TQWidget::setFocus(); //give keyboard focus to the plot widget for key and mouse events
pName[0] = "Mercury"; pColor[0] = "SlateBlue1";
pName[1] = "Venus"; pColor[1] = "LightGreen";
pName[2] = "Earth"; pColor[2] = "Blue";
pName[3] = "Mars"; pColor[3] = "Red";
pName[4] = "Jupiter"; pColor[4] = "Goldenrod";
pName[5] = "Saturn"; pColor[5] = "LightYellow2";
pName[6] = "Uranus"; pColor[6] = "LightSeaGreen";
pName[7] = "Neptune"; pColor[7] = "SkyBlue";
pName[8] = "Pluto"; pColor[8] = "gray";
setCenterPlanet("");
PCat.initialize();
ut = ((KStars*)parent)->data()->ut();
KSNumbers num( ut.djd() );
PCat.findPosition( &num, 0, 0 ); //NULL args: don't need geocent. coords.
for ( uint i=0; i<9; ++i )
LastUpdate[i] = int( ut.date().jd() );
//The planets' update intervals are 0.25% of one period:
UpdateInterval[0] = 0;
UpdateInterval[1] = 0;
UpdateInterval[2] = 0;
UpdateInterval[3] = 1;
UpdateInterval[4] = 5;
UpdateInterval[5] = 13;
UpdateInterval[6] = 38;
UpdateInterval[7] = 75;
UpdateInterval[8] = 113;
TQTimer::singleShot( 0, this, TQT_SLOT( initPlotObjects() ) );
connect( &tmr, TQT_SIGNAL( timeout() ), TQT_SLOT( tick() ) );
connect( pw->timeStep, TQT_SIGNAL( scaleChanged(float) ), TQT_SLOT( setTimeScale(float) ) );
connect( pw->RunButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotRunClock() ) );
connect( pw->dateBox, TQT_SIGNAL( valueChanged( const ExtDate & ) ), TQT_SLOT( slotChangeDate( const ExtDate & ) ) );
connect( pw->TodayButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotToday() ) );
}
PlanetViewer::~PlanetViewer()
{
}
void PlanetViewer::tick() {
//Update the time/date
ut.setDJD( ut.djd() + scale*0.1 );
pw->dateBox->setDate( ut.date() );
updatePlanets();
}
void PlanetViewer::setTimeScale(float f) {
scale = f/86400.; //convert seconds to days
}
void PlanetViewer::slotRunClock() {
isClockRunning = !isClockRunning;
if ( isClockRunning ) {
pw->RunButton->setPixmap( TDEGlobal::iconLoader()->loadIcon( "media-playback-pause", TDEIcon::Toolbar ) );
tmr.start( 100 );
// pw->dateBox->setEnabled( false );
} else {
pw->RunButton->setPixmap( TDEGlobal::iconLoader()->loadIcon( "1rightarrow", TDEIcon::Toolbar ) );
tmr.stop();
// pw->dateBox->setEnabled( true );
}
}
void PlanetViewer::slotChangeDate( const ExtDate & ) {
if ( pw->dateBox->date().isValid() ) {
ut.setDate( pw->dateBox->date() );
updatePlanets();
}
}
void PlanetViewer::updatePlanets() {
KSNumbers num( ut.djd() );
bool changed(false);
//Check each planet to see if it needs to be updated
for ( unsigned int i=0; i<9; ++i ) {
if ( abs( int(ut.date().jd()) - LastUpdate[i] ) > UpdateInterval[i] ) {
KSPlanetBase *p = PCat.findByName( pName[i] );
p->findPosition( &num );
double s, c, s2, c2;
p->helEcLong()->SinCos( s, c );
p->helEcLat()->SinCos( s2, c2 );
planet[i]->point(0)->setX( p->rsun()*c*c2 );
planet[i]->point(0)->setY( p->rsun()*s*c2 );
planetLabel[i]->point(0)->setX( p->rsun()*c*c2 );
planetLabel[i]->point(0)->setY( p->rsun()*s*c2 );
if ( centerPlanet() == pName[i] ) {
double xc = (pw->map->x2() + pw->map->x())*0.5;
double yc = (pw->map->y2() + pw->map->y())*0.5;
double dx = planet[i]->point(0)->x() - xc;
double dy = planet[i]->point(0)->y() - yc;
pw->map->setLimits( pw->map->x() + dx, pw->map->x2() + dx,
pw->map->y() + dy, pw->map->y2() + dy );
}
LastUpdate[i] = int(ut.date().jd());
changed = true;
}
}
if ( changed ) pw->map->update();
}
void PlanetViewer::slotToday() {
KStars *ks = (KStars*)parent();
pw->dateBox->setDate( ks->data()->lt().date() );
}
void PlanetViewer::paintEvent( TQPaintEvent* ) {
pw->map->update();
}
void PlanetViewer::initPlotObjects() {
// Planets
ksun = new KPlotObject( "Sun", "yellow", KPlotObject::POINTS, 12, KPlotObject::CIRCLE );
ksun->addPoint( new DPoint( 0.0, 0.0 ) );
pw->map->addObject( ksun );
//Read in the orbit curves
KPlotObject *orbit[9];
for ( unsigned int i=0; i<9; ++i ) {
orbit[i] = new KPlotObject( "", "white", KPlotObject::CURVE, 1, KPlotObject::SOLID );
TQFile orbitFile;
if ( KSUtils::openDataFile( orbitFile, pName[i].lower() + ".orbit" ) ) {
TQTextStream orbitStream( &orbitFile );
double x, y, z;
while ( !orbitStream.eof() ) {
orbitStream >> x >> y >> z;
orbit[i]->addPoint( new DPoint( x, y ) );
}
}
pw->map->addObject( orbit[i] );
}
for ( unsigned int i=0; i<9; ++i ) {
planet[i] = new KPlotObject( pName[i], pColor[i], KPlotObject::POINTS, 6, KPlotObject::CIRCLE );
planetLabel[i] = new KPlotObject( i18n(pName[i].local8Bit()), pColor[i], KPlotObject::LABEL );
double s, c;
KSPlanetBase *p = PCat.findByName( pName[i] );
p->helEcLong()->SinCos( s, c );
planet[i]->addPoint( new DPoint( p->rsun()*c, p->rsun()*s ) );
planetLabel[i]->addPoint( new DPoint( p->rsun()*c, p->rsun()*s ) );
pw->map->addObject( planet[i] );
pw->map->addObject( planetLabel[i] );
}
update();
}
void PlanetViewer::keyPressEvent( TQKeyEvent *e ) {
switch ( e->key() ) {
case Key_Escape:
close();
break;
default:
e->ignore();
break;
}
}
PVPlotWidget::PVPlotWidget( double x1, double x2, double y1, double y2, TQWidget *par, const char *name ) :
KStarsPlotWidget( x1, x2, y1, y2, par, name ),
mouseButtonDown(false), oldx(0), oldy(0) {
setFocusPolicy( TQ_StrongFocus );
setMouseTracking (true);
pv = (PlanetViewer*)topLevelWidget();
}
PVPlotWidget::PVPlotWidget( TQWidget *parent, const char *name ) :
KStarsPlotWidget( 0.0, 1.0, 0.0, 1.0, parent, name ),
mouseButtonDown(false), oldx(0), oldy(0) {
setFocusPolicy( TQ_StrongFocus );
setMouseTracking (true);
pv = (PlanetViewer*)topLevelWidget();
}
PVPlotWidget::~ PVPlotWidget() {}
void PVPlotWidget::keyPressEvent( TQKeyEvent *e ) {
double xc = (x2() + x())*0.5;
double yc = (y2() + y())*0.5;
double xstep = 0.01*(x2() - x());
double ystep = 0.01*(y2() - y());
double dx = 0.5*dataWidth();
double dy = 0.5*dataHeight();
switch ( e->key() ) {
case Key_Left:
if ( xc - xstep > -AUMAX ) {
setLimits( x() - xstep, x2() - xstep, y(), y2() );
pv->setCenterPlanet("");
update();
}
break;
case Key_Right:
if ( xc + xstep < AUMAX ) {
setLimits( x() + xstep, x2() + xstep, y(), y2() );
pv->setCenterPlanet("");
update();
}
break;
case Key_Down:
if ( yc - ystep > -AUMAX ) {
setLimits( x(), x2(), y() - ystep, y2() - ystep );
pv->setCenterPlanet("");
update();
}
break;
case Key_Up:
if ( yc + ystep < AUMAX ) {
setLimits( x(), x2(), y() + ystep, y2() + ystep );
pv->setCenterPlanet("");
update();
}
break;
case Key_Plus:
case Key_Equal:
slotZoomIn();
break;
case Key_Minus:
case Key_Underscore:
slotZoomOut();
break;
case Key_0: //Sun
setLimits( -dx, dx, -dy, dy );
pv->setCenterPlanet( "Sun" );
update();
break;
case Key_1: //Mercury
{
DPoint *p = object(10)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Mercury" );
update();
break;
}
case Key_2: //Venus
{
DPoint *p = object(12)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Venus" );
update();
break;
}
case Key_3: //Earth
{
DPoint *p = object(14)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Earth" );
update();
break;
}
case Key_4: //Mars
{
DPoint *p = object(16)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Mars" );
update();
break;
}
case Key_5: //Jupiter
{
DPoint *p = object(18)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Jupiter" );
update();
break;
}
case Key_6: //Saturn
{
DPoint *p = object(20)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Saturn" );
update();
break;
}
case Key_7: //Uranus
{
DPoint *p = object(22)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Uranus" );
update();
break;
}
case Key_8: //Neptune
{
DPoint *p = object(24)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Neptune" );
update();
break;
}
case Key_9: //Pluto
{
DPoint *p = object(26)->point(0);
setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
pv->setCenterPlanet( "Pluto" );
update();
break;
}
default:
e->ignore();
break;
}
}
void PVPlotWidget::mousePressEvent( TQMouseEvent *e ) {
mouseButtonDown = true;
oldx = e->x();
oldy = e->y();
}
void PVPlotWidget::mouseReleaseEvent( TQMouseEvent * ) {
mouseButtonDown = false;
update();
}
void PVPlotWidget::mouseMoveEvent( TQMouseEvent *e ) {
if ( mouseButtonDown ) {
//Determine how far we've moved
double xc = (x2() + x())*0.5;
double yc = (y2() + y())*0.5;
double xscale = dataWidth()/( width() - leftPadding() - rightPadding() );
double yscale = dataHeight()/( height() - topPadding() - bottomPadding() );
xc += ( oldx - e->x() )*xscale;
yc -= ( oldy - e->y() )*yscale; //Y data axis is reversed...
if ( xc > -AUMAX && xc < AUMAX && yc > -AUMAX && yc < AUMAX ) {
setLimits( xc - 0.5*dataWidth(), xc + 0.5*dataWidth(),
yc - 0.5*dataHeight(), yc + 0.5*dataHeight() );
update();
kapp->processEvents(20);
}
oldx = e->x();
oldy = e->y();
}
}
void PVPlotWidget::mouseDoubleClickEvent( TQMouseEvent *e ) {
double xscale = dataWidth()/( width() - leftPadding() - rightPadding() );
double yscale = dataHeight()/( height() - topPadding() - bottomPadding() );
double xc = x() + xscale*( e->x() - leftPadding() );
double yc = y2() - yscale*( e->y() - topPadding() );
if ( xc > -AUMAX && xc < AUMAX && yc > -AUMAX && yc < AUMAX ) {
setLimits( xc - 0.5*dataWidth(), xc + 0.5*dataWidth(),
yc - 0.5*dataHeight(), yc + 0.5*dataHeight() );
update();
}
pv->setCenterPlanet( "" );
for ( unsigned int i=0; i<9; ++i ) {
double dx = ( pv->planetObject(i)->point(0)->x() - xc )/xscale;
if ( dx < 4.0 ) {
double dy = ( pv->planetObject(i)->point(0)->y() - yc )/yscale;
if ( sqrt( dx*dx + dy*dy ) < 4.0 ) {
pv->setCenterPlanet( pv->planetName(i) );
}
}
}
}
void PVPlotWidget::wheelEvent( TQWheelEvent *e ) {
if ( e->delta() > 0 ) slotZoomIn();
else slotZoomOut();
}
void PVPlotWidget::slotZoomIn() {
double size( x2() - x() );
if ( size > 0.8 ) {
setLimits( x() + 0.02*size, x2() - 0.02*size, y() + 0.02*size, y2() - 0.02*size );
update();
}
}
void PVPlotWidget::slotZoomOut() {
double size( x2() - x() );
if ( (x2() - x()) < 100.0 ) {
setLimits( x() - 0.02*size, x2() + 0.02*size, y() - 0.02*size, y2() + 0.02*size );
update();
}
}
#include "planetviewer.moc"