moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kstars / kstars / tools / planetviewer.cpp
blob5f910c5efc7665927dc5c068fc4c24e5f816eeef
1 /***************************************************************************
2 planetviewer.cpp - Display overhead view of the solar system
3 -------------------
4 begin : Sun May 25 2003
5 copyright : (C) 2003 by Jason Harris
6 email : jharris@30doradus.org
7 ***************************************************************************/
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
17 #include <stdlib.h> //needed for abs() on some platforms
19 #include <qfile.h>
20 #include <qlayout.h>
21 #include <kdebug.h>
22 #include <klocale.h>
23 #include <kglobal.h>
24 #include <kiconloader.h>
26 #include "planetviewer.h"
27 #include "kstars.h"
28 #include "kstarsdata.h"
29 #include "ksutils.h"
30 #include "ksnumbers.h"
31 #include "ksplanetbase.h"
32 #include "dms.h"
33 #include "timestepbox.h"
34 #include "libkdeedu/extdate/extdatetimeedit.h"
36 #define AUMAX 48
38 PlanetViewer::PlanetViewer(QWidget *parent, const char *name)
39 : KDialogBase( KDialogBase::Plain, i18n("Solar System Viewer"), Close, Close, parent, name ), PCat( ((KStars*)parent)->data() ), scale(1.0), isClockRunning(false), tmr(this)
41 QFrame *page = plainPage();
42 QVBoxLayout *vlay = new QVBoxLayout( page, 0, spacingHint() );
43 pw = new PlanetViewerUI( page );
44 pw->map->setLimits( -48.0, 48.0, -48.0, 48.0 );
45 pw->map->setXAxisLabel( i18n( "axis label for x-coordinate of solar system viewer. AU means astronomical unit.", "X-position (AU)" ) );
46 pw->map->setYAxisLabel( i18n( "axis label for y-coordinate of solar system viewer. AU means astronomical unit.", "Y-position (AU)" ) );
48 pw->timeStep->tsbox()->setMinValue( 21 );
49 pw->timeStep->tsbox()->setValue( 21 );
50 pw->RunButton->setPixmap( KGlobal::iconLoader()->loadIcon( "1rightarrow", KIcon::Toolbar ) );
51 pw->dateBox->setDate( ExtDate::currentDate() );
53 vlay->addWidget( pw );
54 resize( 500, 500 );
55 pw->map->QWidget::setFocus(); //give keyboard focus to the plot widget for key and mouse events
57 pName[0] = "Mercury"; pColor[0] = "SlateBlue1";
58 pName[1] = "Venus"; pColor[1] = "LightGreen";
59 pName[2] = "Earth"; pColor[2] = "Blue";
60 pName[3] = "Mars"; pColor[3] = "Red";
61 pName[4] = "Jupiter"; pColor[4] = "Goldenrod";
62 pName[5] = "Saturn"; pColor[5] = "LightYellow2";
63 pName[6] = "Uranus"; pColor[6] = "LightSeaGreen";
64 pName[7] = "Neptune"; pColor[7] = "SkyBlue";
65 pName[8] = "Pluto"; pColor[8] = "gray";
66 setCenterPlanet("");
68 PCat.initialize();
69 ut = ((KStars*)parent)->data()->ut();
70 KSNumbers num( ut.djd() );
71 PCat.findPosition( &num, 0, 0 ); //NULL args: don't need geocent. coords.
73 for ( uint i=0; i<9; ++i )
74 LastUpdate[i] = int( ut.date().jd() );
76 //The planets' update intervals are 0.5% of one period:
77 UpdateInterval[0] = 0;
78 UpdateInterval[1] = 0;
79 UpdateInterval[2] = 1;
80 UpdateInterval[3] = 2;
81 UpdateInterval[4] = 11;
82 UpdateInterval[5] = 27;
83 UpdateInterval[6] = 76;
84 UpdateInterval[7] = 150;
85 UpdateInterval[8] = 227;
87 QTimer::singleShot( 0, this, SLOT( initPlotObjects() ) );
89 connect( &tmr, SIGNAL( timeout() ), SLOT( tick() ) );
90 connect( pw->timeStep, SIGNAL( scaleChanged(float) ), SLOT( setTimeScale(float) ) );
91 connect( pw->RunButton, SIGNAL( clicked() ), SLOT( slotRunClock() ) );
92 connect( pw->dateBox, SIGNAL( valueChanged( const ExtDate & ) ), SLOT( slotChangeDate( const ExtDate & ) ) );
95 PlanetViewer::~PlanetViewer()
99 void PlanetViewer::tick() {
100 //Update the time/date
101 ut.setDJD( ut.djd() + scale*0.1 );
102 pw->dateBox->setDate( ut.date() );
104 updatePlanets();
107 void PlanetViewer::setTimeScale(float f) {
108 scale = f/86400.; //convert seconds to days
111 void PlanetViewer::slotRunClock() {
112 isClockRunning = !isClockRunning;
114 if ( isClockRunning ) {
115 pw->RunButton->setPixmap( KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Toolbar ) );
116 tmr.start( 100 );
117 // pw->dateBox->setEnabled( false );
118 } else {
119 pw->RunButton->setPixmap( KGlobal::iconLoader()->loadIcon( "1rightarrow", KIcon::Toolbar ) );
120 tmr.stop();
121 // pw->dateBox->setEnabled( true );
125 void PlanetViewer::slotChangeDate( const ExtDate &d ) {
126 ut.setDate( pw->dateBox->date() );
127 updatePlanets();
130 void PlanetViewer::updatePlanets() {
131 KSNumbers num( ut.djd() );
132 bool changed(false);
134 //Check each planet to see if it needs to be updated
135 for ( unsigned int i=0; i<9; ++i ) {
136 if ( abs( int(ut.date().jd()) - LastUpdate[i] ) > UpdateInterval[i] ) {
137 KSPlanetBase *p = PCat.findByName( pName[i] );
139 //Call findPosition w/o Earth pointer to skip geocentric coords calculation
140 //(however, this is not possible for Pluto)
141 if ( pName[i] == "Pluto" ) p->findPosition( &num, 0, 0, PCat.findByName( "Earth" ) );
142 else p->findPosition( &num );
144 double s, c;
145 p->helEcLong()->SinCos( s, c );
146 planet[i]->point(0)->setX( p->rsun()*c );
147 planet[i]->point(0)->setY( p->rsun()*s );
148 planetLabel[i]->point(0)->setX( p->rsun()*c );
149 planetLabel[i]->point(0)->setY( p->rsun()*s );
151 if ( centerPlanet() == pName[i] ) {
152 double xc = (pw->map->x2() + pw->map->x())*0.5;
153 double yc = (pw->map->y2() + pw->map->y())*0.5;
154 double dx = planet[i]->point(0)->x() - xc;
155 double dy = planet[i]->point(0)->y() - yc;
156 pw->map->setLimits( pw->map->x() + dx, pw->map->x2() + dx,
157 pw->map->y() + dy, pw->map->y2() + dy );
160 LastUpdate[i] = int(ut.date().jd());
161 changed = true;
165 if ( changed ) pw->map->update();
168 void PlanetViewer::paintEvent( QPaintEvent* ) {
169 pw->map->update();
172 void PlanetViewer::initPlotObjects() {
173 //**Orbits**//
174 KPlotObject *orbit[9];
176 //mean orbital radii, in AU
177 double rad[9];
178 rad[0] = 0.4;
179 rad[1] = 0.7;
180 rad[2] = 1.0;
181 rad[3] = 1.5;
182 rad[4] = 5.2;
183 rad[5] = 9.5;
184 rad[6] = 19.2;
185 rad[7] = 30.1;
186 rad[8] = 39.5;
188 // Planets
189 ksun = new KPlotObject( "Sun", "yellow", KPlotObject::POINTS, 12, KPlotObject::CIRCLE );
190 ksun->addPoint( new DPoint( 0.0, 0.0 ) );
191 pw->map->addObject( ksun );
193 //Read in the orbit curves.
194 for ( unsigned int i=0; i<9; ++i ) {
195 orbit[i] = new KPlotObject( "", "white", KPlotObject::CURVE, 1, KPlotObject::SOLID );
197 QFile orbitFile;
198 if ( KSUtils::openDataFile( orbitFile, pName[i].lower() + ".orbit" ) ) {
199 QTextStream orbitStream( &orbitFile );
200 double x, y, z;
201 while ( !orbitStream.eof() ) {
202 orbitStream >> x >> y >> z;
203 orbit[i]->addPoint( new DPoint( x, y ) );
207 pw->map->addObject( orbit[i] );
210 for ( unsigned int i=0; i<9; ++i ) {
211 planet[i] = new KPlotObject( pName[i], pColor[i], KPlotObject::POINTS, 6, KPlotObject::CIRCLE );
212 planetLabel[i] = new KPlotObject( i18n(pName[i].local8Bit()), pColor[i], KPlotObject::LABEL );
214 double s, c;
215 KSPlanetBase *p = PCat.findByName( pName[i] );
216 p->helEcLong()->SinCos( s, c );
218 planet[i]->addPoint( new DPoint( p->rsun()*c, p->rsun()*s ) );
219 planetLabel[i]->addPoint( new DPoint( p->rsun()*c, p->rsun()*s ) );
220 pw->map->addObject( planet[i] );
221 pw->map->addObject( planetLabel[i] );
224 update();
227 void PlanetViewer::keyPressEvent( QKeyEvent *e ) {
228 switch ( e->key() ) {
229 case Key_Escape:
230 close();
231 break;
232 default:
233 e->ignore();
234 break;
238 PVPlotWidget::PVPlotWidget( double x1, double x2, double y1, double y2, QWidget *par, const char *name ) :
239 KStarsPlotWidget( x1, x2, y1, y2, par, name ),
240 mouseButtonDown(false), oldx(0), oldy(0) {
241 setFocusPolicy( QWidget::StrongFocus );
242 setMouseTracking (true);
243 pv = (PlanetViewer*)topLevelWidget();
246 PVPlotWidget::PVPlotWidget( QWidget *parent, const char *name ) :
247 KStarsPlotWidget( 0.0, 1.0, 0.0, 1.0, parent, name ),
248 mouseButtonDown(false), oldx(0), oldy(0) {
249 setFocusPolicy( QWidget::StrongFocus );
250 setMouseTracking (true);
251 pv = (PlanetViewer*)topLevelWidget();
254 PVPlotWidget::~ PVPlotWidget() {}
256 void PVPlotWidget::keyPressEvent( QKeyEvent *e ) {
257 double xc = (x2() + x())*0.5;
258 double yc = (y2() + y())*0.5;
259 double xstep = 0.01*(x2() - x());
260 double ystep = 0.01*(y2() - y());
261 double dx = 0.5*dataWidth();
262 double dy = 0.5*dataHeight();
264 switch ( e->key() ) {
265 case Key_Left:
266 if ( xc - xstep > -AUMAX ) {
267 setLimits( x() - xstep, x2() - xstep, y(), y2() );
268 pv->setCenterPlanet("");
269 update();
271 break;
273 case Key_Right:
274 if ( xc + xstep < AUMAX ) {
275 setLimits( x() + xstep, x2() + xstep, y(), y2() );
276 pv->setCenterPlanet("");
277 update();
279 break;
281 case Key_Down:
282 if ( yc - ystep > -AUMAX ) {
283 setLimits( x(), x2(), y() - ystep, y2() - ystep );
284 pv->setCenterPlanet("");
285 update();
287 break;
289 case Key_Up:
290 if ( yc + ystep < AUMAX ) {
291 setLimits( x(), x2(), y() + ystep, y2() + ystep );
292 pv->setCenterPlanet("");
293 update();
295 break;
297 case Key_Plus:
298 case Key_Equal:
299 slotZoomIn();
300 break;
302 case Key_Minus:
303 case Key_Underscore:
304 slotZoomOut();
305 break;
307 case Key_0: //Sun
308 setLimits( -dx, dx, -dy, dy );
309 pv->setCenterPlanet( "Sun" );
310 update();
311 break;
313 case Key_1: //Mercury
315 DPoint *p = object(10)->point(0);
316 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
317 pv->setCenterPlanet( "Mercury" );
318 update();
319 break;
322 case Key_2: //Venus
324 DPoint *p = object(12)->point(0);
325 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
326 pv->setCenterPlanet( "Venus" );
327 update();
328 break;
331 case Key_3: //Earth
333 DPoint *p = object(14)->point(0);
334 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
335 pv->setCenterPlanet( "Earth" );
336 update();
337 break;
340 case Key_4: //Mars
342 DPoint *p = object(16)->point(0);
343 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
344 pv->setCenterPlanet( "Mars" );
345 update();
346 break;
349 case Key_5: //Jupiter
351 DPoint *p = object(18)->point(0);
352 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
353 pv->setCenterPlanet( "Jupiter" );
354 update();
355 break;
358 case Key_6: //Saturn
360 DPoint *p = object(20)->point(0);
361 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
362 pv->setCenterPlanet( "Saturn" );
363 update();
364 break;
367 case Key_7: //Uranus
369 DPoint *p = object(22)->point(0);
370 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
371 pv->setCenterPlanet( "Uranus" );
372 update();
373 break;
376 case Key_8: //Neptune
378 DPoint *p = object(24)->point(0);
379 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
380 pv->setCenterPlanet( "Neptune" );
381 update();
382 break;
385 case Key_9: //Pluto
387 DPoint *p = object(26)->point(0);
388 setLimits( p->x() - dx, p->x() + dx, p->y() - dy, p->y() + dy );
389 pv->setCenterPlanet( "Pluto" );
390 update();
391 break;
394 default:
395 e->ignore();
396 break;
400 void PVPlotWidget::mousePressEvent( QMouseEvent *e ) {
401 mouseButtonDown = true;
402 oldx = e->x();
403 oldy = e->y();
406 void PVPlotWidget::mouseReleaseEvent( QMouseEvent * ) {
407 mouseButtonDown = false;
408 update();
411 void PVPlotWidget::mouseMoveEvent( QMouseEvent *e ) {
412 if ( mouseButtonDown ) {
413 //Determine how far we've moved
414 double xc = (x2() + x())*0.5;
415 double yc = (y2() + y())*0.5;
416 double xscale = dataWidth()/( width() - leftPadding() - rightPadding() );
417 double yscale = dataHeight()/( height() - topPadding() - bottomPadding() );
419 xc += ( oldx - e->x() )*xscale;
420 yc -= ( oldy - e->y() )*yscale; //Y data axis is reversed...
422 if ( xc > -AUMAX && xc < AUMAX && yc > -AUMAX && yc < AUMAX ) {
423 setLimits( xc - 0.5*dataWidth(), xc + 0.5*dataWidth(),
424 yc - 0.5*dataHeight(), yc + 0.5*dataHeight() );
425 update();
426 kapp->processEvents(20);
429 oldx = e->x();
430 oldy = e->y();
434 void PVPlotWidget::mouseDoubleClickEvent( QMouseEvent *e ) {
435 double xscale = dataWidth()/( width() - leftPadding() - rightPadding() );
436 double yscale = dataHeight()/( height() - topPadding() - bottomPadding() );
438 double xc = x() + xscale*( e->x() - leftPadding() );
439 double yc = y2() - yscale*( e->y() - topPadding() );
441 if ( xc > -AUMAX && xc < AUMAX && yc > -AUMAX && yc < AUMAX ) {
442 setLimits( xc - 0.5*dataWidth(), xc + 0.5*dataWidth(),
443 yc - 0.5*dataHeight(), yc + 0.5*dataHeight() );
444 update();
447 pv->setCenterPlanet( "" );
448 for ( unsigned int i=0; i<9; ++i ) {
449 double dx = ( pv->planetObject(i)->point(0)->x() - xc )/xscale;
450 if ( dx < 4.0 ) {
451 double dy = ( pv->planetObject(i)->point(0)->y() - yc )/yscale;
452 if ( sqrt( dx*dx + dy*dy ) < 4.0 ) {
453 pv->setCenterPlanet( pv->planetName(i) );
459 void PVPlotWidget::wheelEvent( QWheelEvent *e ) {
460 if ( e->delta() > 0 ) slotZoomIn();
461 else slotZoomOut();
464 void PVPlotWidget::slotZoomIn() {
465 double size( x2() - x() );
466 if ( size > 0.8 ) {
467 setLimits( x() + 0.02*size, x2() - 0.02*size, y() + 0.02*size, y2() - 0.02*size );
468 update();
472 void PVPlotWidget::slotZoomOut() {
473 double size( x2() - x() );
474 if ( (x2() - x()) < 100.0 ) {
475 setLimits( x() - 0.02*size, x2() + 0.02*size, y() - 0.02*size, y2() + 0.02*size );
476 update();
480 #include "planetviewer.moc"