1 /***************************************************************************
2 planetviewer.cpp - Display overhead view of the solar system
4 begin : Sun May 25 2003
5 copyright : (C) 2003 by Jason Harris
6 email : jharris@30doradus.org
7 ***************************************************************************/
8 /***************************************************************************
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. *
15 ***************************************************************************/
17 #include <stdlib.h> //needed for abs() on some platforms
24 #include <kiconloader.h>
26 #include "planetviewer.h"
28 #include "kstarsdata.h"
30 #include "ksnumbers.h"
31 #include "ksplanetbase.h"
33 #include "timestepbox.h"
34 #include "libkdeedu/extdate/extdatetimeedit.h"
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
);
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";
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() );
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
) );
117 // pw->dateBox->setEnabled( false );
119 pw
->RunButton
->setPixmap( KGlobal::iconLoader()->loadIcon( "1rightarrow", KIcon::Toolbar
) );
121 // pw->dateBox->setEnabled( true );
125 void PlanetViewer::slotChangeDate( const ExtDate
&d
) {
126 ut
.setDate( pw
->dateBox
->date() );
130 void PlanetViewer::updatePlanets() {
131 KSNumbers
num( ut
.djd() );
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
);
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());
165 if ( changed
) pw
->map
->update();
168 void PlanetViewer::paintEvent( QPaintEvent
* ) {
172 void PlanetViewer::initPlotObjects() {
174 KPlotObject
*orbit
[9];
176 //mean orbital radii, in AU
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
);
198 if ( KSUtils::openDataFile( orbitFile
, pName
[i
].lower() + ".orbit" ) ) {
199 QTextStream
orbitStream( &orbitFile
);
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
);
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
] );
227 void PlanetViewer::keyPressEvent( QKeyEvent
*e
) {
228 switch ( e
->key() ) {
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() ) {
266 if ( xc
- xstep
> -AUMAX
) {
267 setLimits( x() - xstep
, x2() - xstep
, y(), y2() );
268 pv
->setCenterPlanet("");
274 if ( xc
+ xstep
< AUMAX
) {
275 setLimits( x() + xstep
, x2() + xstep
, y(), y2() );
276 pv
->setCenterPlanet("");
282 if ( yc
- ystep
> -AUMAX
) {
283 setLimits( x(), x2(), y() - ystep
, y2() - ystep
);
284 pv
->setCenterPlanet("");
290 if ( yc
+ ystep
< AUMAX
) {
291 setLimits( x(), x2(), y() + ystep
, y2() + ystep
);
292 pv
->setCenterPlanet("");
308 setLimits( -dx
, dx
, -dy
, dy
);
309 pv
->setCenterPlanet( "Sun" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
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" );
400 void PVPlotWidget::mousePressEvent( QMouseEvent
*e
) {
401 mouseButtonDown
= true;
406 void PVPlotWidget::mouseReleaseEvent( QMouseEvent
* ) {
407 mouseButtonDown
= false;
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() );
426 kapp
->processEvents(20);
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() );
447 pv
->setCenterPlanet( "" );
448 for ( unsigned int i
=0; i
<9; ++i
) {
449 double dx
= ( pv
->planetObject(i
)->point(0)->x() - xc
)/xscale
;
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();
464 void PVPlotWidget::slotZoomIn() {
465 double size( x2() - x() );
467 setLimits( x() + 0.02*size
, x2() - 0.02*size
, y() + 0.02*size
, y2() - 0.02*size
);
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
);
480 #include "planetviewer.moc"