00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <qlayout.h>
00019 #include <qpainter.h>
00020 #include <klocale.h>
00021 #include <klineedit.h>
00022 #include <klistbox.h>
00023 #include <kpushbutton.h>
00024 #include <kdialogbase.h>
00025
00026 #include "altvstime.h"
00027 #include "altvstimeui.h"
00028 #include "dms.h"
00029 #include "dmsbox.h"
00030 #include "kstars.h"
00031 #include "kstarsdata.h"
00032 #include "skypoint.h"
00033 #include "skyobject.h"
00034 #include "skyobjectname.h"
00035 #include "ksnumbers.h"
00036 #include "objectnamelist.h"
00037 #include "simclock.h"
00038 #include "finddialog.h"
00039 #include "locationdialog.h"
00040
00041 #include "kstarsdatetime.h"
00042 #include "libkdeedu/extdate/extdatetimeedit.h"
00043
00044 AltVsTime::AltVsTime( QWidget* parent) :
00045 KDialogBase( KDialogBase::Plain, i18n( "Altitude vs. Time" ), Close, Close, parent )
00046 {
00047 ks = (KStars*) parent;
00048
00049 QFrame *page = plainPage();
00050
00051 setMainWidget(page);
00052 topLayout = new QVBoxLayout( page, 0, spacingHint() );
00053
00054 View = new AVTPlotWidget( -12.0, 12.0, -90.0, 90.0, page );
00055 View->setMinimumSize( 400, 400 );
00056 View->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
00057 View->setXAxisType( KStarsPlotWidget::TIME );
00058 View->setYAxisType( KStarsPlotWidget::ANGLE );
00059 View->setShowGrid( false );
00060 View->setXAxisLabel( i18n( "Local Time" ) );
00061 View->setXAxisLabel2( i18n( "Local Sidereal Time" ) );
00062 View->setYAxisLabel( i18n( "the angle of an object above (or below) the horizon", "Altitude" ) );
00063
00064 avtUI = new AltVsTimeUI( page );
00065 avtUI->raBox->setDegType( false );
00066 avtUI->decBox->setDegType( true );
00067
00068
00069
00070 avtUI->longBox->setReadOnly( true );
00071 avtUI->latBox->setReadOnly( true );
00072
00073 topLayout->addWidget( View );
00074 topLayout->addWidget( avtUI );
00075
00076 geo = ks->geo();
00077
00078 DayOffset = 0;
00079 showCurrentDate();
00080 if ( getDate().time().hour() > 12 ) DayOffset = 1;
00081
00082 avtUI->longBox->show( geo->lng() );
00083 avtUI->latBox->show( geo->lat() );
00084
00085 computeSunRiseSetTimes();
00086
00087 setLSTLimits();
00088 View->updateTickmarks();
00089
00090 connect( avtUI->browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseObject() ) );
00091 connect( avtUI->cityButton, SIGNAL( clicked() ), this, SLOT( slotChooseCity() ) );
00092 connect( avtUI->updateButton, SIGNAL( clicked() ), this, SLOT( slotUpdateDateLoc() ) );
00093 connect( avtUI->clearButton, SIGNAL( clicked() ), this, SLOT( slotClear() ) );
00094 connect( avtUI->addButton, SIGNAL( clicked() ), this, SLOT( slotAddSource() ) );
00095 connect( avtUI->nameBox, SIGNAL( returnPressed() ), this, SLOT( slotAddSource() ) );
00096 connect( avtUI->raBox, SIGNAL( returnPressed() ), this, SLOT( slotAddSource() ) );
00097 connect( avtUI->decBox, SIGNAL( returnPressed() ), this, SLOT( slotAddSource() ) );
00098 connect( avtUI->clearFieldsButton, SIGNAL( clicked() ), this, SLOT( slotClearBoxes() ) );
00099 connect( avtUI->longBox, SIGNAL( returnPressed() ), this, SLOT( slotAdvanceFocus() ) );
00100 connect( avtUI->latBox, SIGNAL( returnPressed() ), this, SLOT( slotAdvanceFocus() ) );
00101 connect( avtUI->PlotList, SIGNAL( highlighted(int) ), this, SLOT( slotHighlight() ) );
00102
00103 pList.setAutoDelete(FALSE);
00104 deleteList.setAutoDelete(TRUE);
00105
00106
00107 avtUI->nameBox->setTrapReturnKey( true );
00108 avtUI->raBox->setTrapReturnKey( true );
00109 avtUI->decBox->setTrapReturnKey( true );
00110
00111 setMouseTracking( true );
00112 }
00113
00114 AltVsTime::~AltVsTime()
00115 {
00116
00117 }
00118
00119 void AltVsTime::slotAddSource(void) {
00120 bool objFound( false );
00121
00122
00123 if ( ! avtUI->nameBox->text().isEmpty() ) {
00124 ObjectNameList &ObjNames = ks->data()->ObjNames;
00125 QString text = avtUI->nameBox->text().lower();
00126
00127 for( SkyObjectName *name = ObjNames.first( text ); name; name = ObjNames.next() ) {
00128 if ( name->text().lower() == text ) {
00129
00130 SkyObject *o = name->skyObject();
00131 processObject( o );
00132
00133 objFound = true;
00134 break;
00135 }
00136 }
00137
00138 if ( !objFound ) kdDebug() << "No object named " << avtUI->nameBox->text() << " found." << endl;
00139 }
00140
00141
00142
00143 if ( !objFound && ! avtUI->nameBox->text().isEmpty() && ! avtUI->raBox->text().isEmpty() && ! avtUI->decBox->text().isEmpty() ) {
00144 bool ok( true );
00145 dms newRA( 0.0 ), newDec( 0.0 );
00146 newRA = avtUI->raBox->createDms( false, &ok );
00147 if ( ok ) newDec = avtUI->decBox->createDms( true, &ok );
00148
00149
00150
00151 KStarsDateTime dt;
00152 dt.setFromEpoch( getEpoch( avtUI->epochName->text() ) );
00153 long double jd = dt.djd();
00154 if ( jd != J2000 ) {
00155 SkyPoint ptest( newRA, newDec );
00156 ptest.precessFromAnyEpoch( jd, J2000 );
00157 newRA.setH( ptest.ra()->Hours() );
00158 newDec.setD( ptest.dec()->Degrees() );
00159 }
00160
00161
00162 bool found(false);
00163 for ( SkyPoint *p = pList.first(); p; p = pList.next() ) {
00164
00165 if ( fabs( newRA.Degrees() - p->ra()->Degrees() ) < 0.0003 && fabs( newDec.Degrees() - p->dec()->Degrees() ) < 0.0003 ) {
00166 found = true;
00167 break;
00168 }
00169 }
00170 if ( found ) {
00171 kdDebug() << "This point is already displayed; I will not duplicate it." << endl;
00172 ok = false;
00173 }
00174
00175 if ( ok ) {
00176 SkyObject *obj = new SkyObject( 8, newRA, newDec, 1.0, avtUI->nameBox->text() );
00177 deleteList.append( obj );
00178 processObject( obj );
00179 }
00180
00181
00182
00183 } else if ( avtUI->nameBox->text().isEmpty() && ! avtUI->raBox->text().isEmpty() && ! avtUI->decBox->text().isEmpty() ) {
00184 avtUI->nameBox->QWidget::setFocus();
00185
00186
00187 } else if ( avtUI->raBox->text().isEmpty() ) {
00188 avtUI->raBox->QWidget::setFocus();
00189 } else if ( avtUI->decBox->text().isEmpty() ) {
00190 avtUI->decBox->QWidget::setFocus();
00191 }
00192
00193 View->repaint(false);
00194 }
00195
00196
00197 void AltVsTime::slotBrowseObject(void) {
00198 FindDialog fd(ks);
00199 if ( fd.exec() == QDialog::Accepted ) {
00200 SkyObject *o = fd.currentItem()->objName()->skyObject();
00201 processObject( o );
00202 }
00203
00204 View->repaint();
00205 }
00206
00207 void AltVsTime::processObject( SkyObject *o, bool forceAdd ) {
00208 KSNumbers *num = new KSNumbers( getDate().djd() );
00209 KSNumbers *oldNum = 0;
00210
00211
00212 if ( o && o->isSolarSystem() ) {
00213 oldNum = new KSNumbers( ks->data()->ut().djd() );
00214 o->updateCoords( num, true, geo->lat(), ks->LST() );
00215 }
00216
00217
00218 o->updateCoords( num );
00219
00220
00221 bool found(false);
00222 for ( SkyPoint *p = pList.first(); p; p = pList.next() ) {
00223 if ( o->ra()->Degrees() == p->ra()->Degrees() && o->dec()->Degrees() == p->dec()->Degrees() ) {
00224 found = true;
00225 break;
00226 }
00227 }
00228 if ( found && !forceAdd ) kdDebug() << "This point is already displayed; I will not duplicate it." << endl;
00229 else {
00230 pList.append( (SkyPoint*)o );
00231
00232
00233 for ( int i=0; i < View->objectCount(); ++i ) {
00234 KPlotObject *obj = View->object( i );
00235 if ( obj->size() == 2 ) {
00236 obj->setColor( "red" );
00237 obj->setSize( 1 );
00238 }
00239 }
00240
00241
00242 KPlotObject *po = new KPlotObject( "", "white", KPlotObject::CURVE, 2, KPlotObject::SOLID );
00243 for ( double h=-12.0; h<=12.0; h+=0.5 ) {
00244 po->addPoint( new DPoint( h, findAltitude( o, h ) ) );
00245 }
00246 View->addObject( po );
00247
00248 avtUI->PlotList->insertItem( o->translatedName() );
00249 avtUI->PlotList->setCurrentItem( avtUI->PlotList->count() - 1 );
00250 avtUI->raBox->showInHours(o->ra() );
00251 avtUI->decBox->showInDegrees(o->dec() );
00252 avtUI->nameBox->setText(o->translatedName() );
00253
00254
00255 avtUI->epochName->setText( QString().setNum( getDate().epoch() ) );
00256 }
00257 kdDebug() << "Currently, there are " << View->objectCount() << " objects displayed." << endl;
00258
00259
00260 if ( o->isSolarSystem() ) {
00261 o->updateCoords( oldNum, true, ks->geo()->lat(), ks->LST() );
00262 delete oldNum;
00263 }
00264 o->EquatorialToHorizontal( ks->LST(), ks->geo()->lat() );
00265 delete num;
00266 }
00267
00268 double AltVsTime::findAltitude( SkyPoint *p, double hour ) {
00269 hour += 24.0*(double)DayOffset;
00270
00271
00272 KStarsDateTime ut = getDate().addSecs( hour*3600.0 );
00273
00274 dms LST = geo->GSTtoLST( ut.gst() );
00275 p->EquatorialToHorizontal( &LST, geo->lat() );
00276 return p->alt()->Degrees();
00277 }
00278
00279 void AltVsTime::slotHighlight(void) {
00280 int iPlotList = avtUI->PlotList->currentItem();
00281
00282
00283 for ( int i=0; i<View->objectCount(); ++i ) {
00284 KPlotObject *obj = View->object( i );
00285
00286 if ( i == iPlotList ) {
00287 obj->setSize( 2 );
00288 obj->setColor( "white" );
00289 } else {
00290 obj->setSize( 1 );
00291 obj->setColor( "red" );
00292 }
00293 }
00294
00295 View->update();
00296
00297 int index = 0;
00298 for ( SkyPoint *p = pList.first(); p; p = pList.next() ) {
00299 if ( index == iPlotList ) {
00300 avtUI->raBox->showInHours(p->ra() );
00301 avtUI->decBox->showInDegrees(p->dec() );
00302 avtUI->nameBox->setText(avtUI->PlotList->currentText() );
00303 }
00304 ++index;
00305 }
00306 }
00307
00308
00309 void AltVsTime::slotAdvanceFocus(void) {
00310 if ( sender()->name() == QString( "nameBox" ) ) avtUI->addButton->setFocus();
00311 if ( sender()->name() == QString( "raBox" ) ) avtUI->decBox->setFocus();
00312 if ( sender()->name() == QString( "decbox" ) ) avtUI->addButton->setFocus();
00313 if ( sender()->name() == QString( "longBox" ) ) avtUI->latBox->setFocus();
00314 if ( sender()->name() == QString( "latBox" ) ) avtUI->updateButton->setFocus();
00315 }
00316
00317 void AltVsTime::slotClear(void) {
00318 if ( pList.count() ) pList.clear();
00319 if ( deleteList.count() ) deleteList.clear();
00320 avtUI->PlotList->clear();
00321 avtUI->nameBox->clear();
00322 avtUI->raBox->clear();
00323 avtUI->decBox->clear();
00324 avtUI->epochName->clear();
00325 View->clearObjectList();
00326 View->repaint();
00327 }
00328
00329 void AltVsTime::slotClearBoxes(void) {
00330 avtUI->nameBox->clear();
00331 avtUI->raBox->clear() ;
00332 avtUI->decBox->clear();
00333 avtUI->epochName->clear();
00334 }
00335
00336 void AltVsTime::computeSunRiseSetTimes() {
00337
00338
00339 KStarsDateTime today = getDate();
00340
00341 SkyObject *oSun = (SkyObject*) ks->data()->PCat->planetSun();
00342 double sunRise = -1.0 * oSun->riseSetTime( today.djd() + 1.0, geo, true ).secsTo(QTime()) / 86400.0;
00343 double sunSet = -1.0 * oSun->riseSetTime( today.djd(), geo, false ).secsTo(QTime()) / 86400.0;
00344
00345
00346
00347 KSNumbers *num = new KSNumbers( today.djd() );
00348 KSNumbers *oldNum = new KSNumbers( ks->data()->ut().djd() );
00349 dms LST = geo->GSTtoLST( getDate().gst() );
00350 oSun->updateCoords( num, true, geo->lat(), &LST );
00351 if ( oSun->checkCircumpolar( geo->lat() ) ) {
00352 if ( oSun->alt()->Degrees() > 0.0 ) {
00353
00354 sunRise = 0.0;
00355 sunSet = 1.0;
00356 } else {
00357
00358 sunRise = 0.0;
00359 sunSet = -1.0;
00360 }
00361 }
00362
00363
00364 View->setSunRiseSetTimes( sunRise, sunSet );
00365
00366
00367 oSun->updateCoords( oldNum, true, ks->geo()->lat(), ks->LST() );
00368 oSun->EquatorialToHorizontal( ks->LST(), ks->geo()->lat() );
00369
00370 delete num;
00371 delete oldNum;
00372 }
00373
00374 void AltVsTime::slotUpdateDateLoc(void) {
00375 KStarsDateTime today = getDate();
00376 KSNumbers *num = new KSNumbers( today.djd() );
00377 KSNumbers *oldNum = 0;
00378 dms LST = geo->GSTtoLST( today.gst() );
00379
00380
00381 computeSunRiseSetTimes();
00382
00383 for ( unsigned int i = 0; i < avtUI->PlotList->count(); ++i ) {
00384 QString oName = avtUI->PlotList->text( i ).lower();
00385 ObjectNameList &ObjNames = ks->data()->ObjNames;
00386 bool objFound(false);
00387
00388 for( SkyObjectName *name = ObjNames.first( oName ); name; name = ObjNames.next() ) {
00389 if ( name->text().lower() == oName ) {
00390
00391 SkyObject *o = name->skyObject();
00392
00393
00394 if ( o->isSolarSystem() ) {
00395 oldNum = new KSNumbers( ks->data()->ut().djd() );
00396 o->updateCoords( num, true, geo->lat(), &LST );
00397 }
00398
00399
00400 o->updateCoords( num );
00401
00402
00403 pList.replace( i, (SkyPoint*)o );
00404
00405 KPlotObject *po = new KPlotObject( "", "white", KPlotObject::CURVE, 1, KPlotObject::SOLID );
00406 for ( double h=-12.0; h<=12.0; h+=0.5 ) {
00407 po->addPoint( new DPoint( h, findAltitude( o, h ) ) );
00408 }
00409 View->replaceObject( i, po );
00410
00411
00412 if ( o->isSolarSystem() ) {
00413 o->updateCoords( oldNum, true, ks->data()->geo()->lat(), ks->LST() );
00414 delete oldNum;
00415 oldNum = 0;
00416 }
00417 o->EquatorialToHorizontal( ks->LST(), ks->data()->geo()->lat() );
00418
00419 objFound = true;
00420 break;
00421 }
00422 }
00423
00424 if ( ! objFound ) {
00425 pList.at(i)->updateCoords( num );
00426
00427 KPlotObject *po = new KPlotObject( "", "white", KPlotObject::CURVE, 1, KPlotObject::SOLID );
00428 for ( double h=-12.0; h<=12.0; h+=0.5 ) {
00429 po->addPoint( new DPoint( h, findAltitude( pList.at(i), h ) ) );
00430 }
00431 View->replaceObject( i, po );
00432 }
00433 }
00434
00435 if ( getDate().time().hour() > 12 ) DayOffset = 1;
00436 else DayOffset = 0;
00437
00438 setLSTLimits();
00439 slotHighlight();
00440 View->repaint();
00441
00442 delete num;
00443 }
00444
00445 void AltVsTime::slotChooseCity(void) {
00446 LocationDialog ld(ks);
00447 if ( ld.exec() == QDialog::Accepted ) {
00448 GeoLocation *newGeo = ld.selectedCity();
00449 if ( newGeo ) {
00450 geo = newGeo;
00451 avtUI->latBox->showInDegrees( geo->lat() );
00452 avtUI->longBox->showInDegrees( geo->lng() );
00453 }
00454 }
00455 }
00456
00457 int AltVsTime::currentPlotListItem() const {
00458 return avtUI->PlotList->currentItem();
00459 }
00460
00461 void AltVsTime::setLSTLimits(void) {
00462
00463 KStarsDateTime ut = getDate().addSecs( ((double)DayOffset + 0.5)*86400. );
00464
00465 dms lst = geo->GSTtoLST( ut.gst() );
00466 View->setSecondaryLimits( lst.Hours(), lst.Hours() + 24.0, -90.0, 90.0 );
00467 }
00468
00469 void AltVsTime::showCurrentDate (void)
00470 {
00471 KStarsDateTime dt = KStarsDateTime::currentDateTime();
00472 if ( dt.time() > QTime( 12, 0, 0 ) ) dt = dt.addDays( 1 );
00473 avtUI->dateBox->setDate( dt.date() );
00474 }
00475
00476 KStarsDateTime AltVsTime::getDate (void)
00477 {
00478
00479 KStarsDateTime dt( avtUI->dateBox->date(), QTime() );
00480 dt = geo->LTtoUT( dt );
00481 return dt;
00482 }
00483
00484 double AltVsTime::getEpoch (QString eName)
00485 {
00486
00487 bool ok(false);
00488 double epoch = eName.toDouble(&ok);
00489
00490 if ( !ok ) {
00491 kdDebug() << "Invalid Epoch. Assuming 2000.0." << endl;
00492 return 2000.0;
00493 }
00494
00495 return epoch;
00496 }
00497
00498 AVTPlotWidget::AVTPlotWidget( double x1, double x2, double y1, double y2, QWidget *parent, const char* name )
00499 : KStarsPlotWidget( x1, x2, y1, y2, parent, name )
00500 {
00501
00502 SunRise = 0.25;
00503 SunSet = 0.75;
00504 }
00505
00506 void AVTPlotWidget::mousePressEvent( QMouseEvent *e ) {
00507 mouseMoveEvent( e );
00508 }
00509
00510 void AVTPlotWidget::mouseMoveEvent( QMouseEvent *e ) {
00511 QRect checkRect( leftPadding(), topPadding(), PixRect.width(), PixRect.height() );
00512 int Xcursor = e->x();
00513 int Ycursor = e->y();
00514
00515 if ( ! checkRect.contains( e->x(), e->y() ) ) {
00516 if ( e->x() < checkRect.left() ) Xcursor = checkRect.left();
00517 if ( e->x() > checkRect.right() ) Xcursor = checkRect.right();
00518 if ( e->y() < checkRect.top() ) Ycursor = checkRect.top();
00519 if ( e->y() > checkRect.bottom() ) Ycursor = checkRect.bottom();
00520 }
00521
00522 Xcursor -= leftPadding();
00523 Ycursor -= topPadding();
00524
00525 QPixmap buffer2( *buffer );
00526 QPainter p;
00527 p.begin( &buffer2 );
00528 p.translate( leftPadding(), topPadding() );
00529 p.setPen( QPen( "grey", 1, SolidLine ) );
00530 p.drawLine( Xcursor, 0, Xcursor, PixRect.height() );
00531 p.drawLine( 0, Ycursor, PixRect.width(), Ycursor );
00532 p.end();
00533 bitBlt( this, 0, 0, &buffer2 );
00534 }
00535
00536 void AVTPlotWidget::paintEvent( QPaintEvent * ) {
00537 QPainter p;
00538
00539 p.begin( buffer );
00540 p.fillRect( 0, 0, width(), height(), bgColor() );
00541
00542 p.translate( leftPadding(), topPadding() );
00543
00544 int pW = PixRect.width();
00545 int pH = PixRect.height();
00546
00547
00548
00549 if ( SunSet != -1.0 ) {
00550
00551 if ( SunSet == 1.0 ) {
00552 p.fillRect( 0, 0, pW, int(0.5*pH), QColor( 0, 100, 200 ) );
00553 } else {
00554
00555 int dawn = int(pW*(0.5 + SunRise));
00556 int dusk = int(pW*(SunSet - 0.5));
00557 p.fillRect( 0, 0, dusk, int(0.5*pH), QColor( 0, 100, 200 ) );
00558 p.fillRect( dawn, 0, pW - dawn, int(0.5*pH), QColor( 0, 100, 200 ) );
00559
00560
00561 unsigned short int W = 40;
00562 for ( unsigned short int i=0; i<W; ++i ) {
00563 p.setPen( QColor( 0, int(100*i/W), 200*i/W ) );
00564 p.drawLine( dusk - (i-20), 0, dusk - (i-20), pH );
00565 p.drawLine( dawn + (i-20), 0, dawn + (i-20), pH );
00566 }
00567 }
00568 }
00569
00570
00571 p.fillRect( 0, int(0.5*pH), pW, int(0.5*pH), QColor( "#002200" ) );
00572
00573 drawBox( &p );
00574 drawObjects( &p );
00575
00576
00577 QTime t = QTime::currentTime();
00578 double x = 12.0 + t.hour() + t.minute()/60.0 + t.second()/3600.0;
00579 while ( x > 24.0 ) x -= 24.0;
00580 int ix = int(x*pW/24.0);
00581 p.setPen( QPen( "white", 2, DotLine ) );
00582 p.drawLine( ix, 0, ix, pH );
00583
00584 p.end();
00585
00586 bitBlt( this, 0, 0, buffer );
00587 }
00588
00589 #include "altvstime.moc"