00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "altvstime.h"
00019
00020 #include <QVBoxLayout>
00021 #include <QPainter>
00022 #include <QMouseEvent>
00023 #include <QPixmap>
00024 #include <QFrame>
00025 #include <QPaintEvent>
00026 #include <QPointF>
00027
00028 #include <klocale.h>
00029 #include <klineedit.h>
00030 #include <kpushbutton.h>
00031 #include <kdialog.h>
00032 #include <kplotobject.h>
00033 #include <kplotaxis.h>
00034 #include <kplotwidget.h>
00035
00036 #include "ui_altvstime.h"
00037 #include "dms.h"
00038 #include "kstars.h"
00039 #include "kstarsdata.h"
00040 #include "skypoint.h"
00041 #include "skyobject.h"
00042 #include "ksnumbers.h"
00043 #include "simclock.h"
00044 #include "finddialog.h"
00045 #include "locationdialog.h"
00046 #include "widgets/dmsbox.h"
00047 #include "avtplotwidget.h"
00048
00049 #include "kstarsdatetime.h"
00050
00051 AltVsTimeUI::AltVsTimeUI( QWidget *p ) : QFrame( p ) {
00052 setupUi( this );
00053 }
00054
00055 AltVsTime::AltVsTime( QWidget* parent) :
00056 KDialog( parent )
00057 {
00058 ks = (KStars*) parent;
00059
00060 QFrame *page = new QFrame( this );
00061 setMainWidget(page);
00062 setCaption( i18n( "Altitude vs. Time" ) );
00063 setButtons( KDialog::Close );
00064 setModal( false );
00065
00066 topLayout = new QVBoxLayout( page );
00067 topLayout->setMargin( 0 );
00068 topLayout->setSpacing( spacingHint() );
00069
00070 avtUI = new AltVsTimeUI( page );
00071
00072 avtUI->View->setLimits( -12.0, 12.0, -90.0, 90.0 );
00073 avtUI->View->setShowGrid( false );
00074 avtUI->View->axis(KPlotWidget::BottomAxis)->setTickLabelFormat( 't' );
00075 avtUI->View->axis(KPlotWidget::BottomAxis)->setLabel( i18n( "Local Time" ) );
00076 avtUI->View->axis(KPlotWidget::TopAxis)->setTickLabelFormat( 't' );
00077 avtUI->View->axis(KPlotWidget::TopAxis)->setTickLabelsShown( true );
00078 avtUI->View->axis(KPlotWidget::TopAxis)->setLabel( i18n( "Local Sidereal Time" ) );
00079 avtUI->View->axis(KPlotWidget::LeftAxis)->setLabel( i18nc( "the angle of an object above (or below) the horizon", "Altitude" ) );
00080
00081 avtUI->raBox->setDegType( false );
00082 avtUI->decBox->setDegType( true );
00083
00084
00085
00086 avtUI->longBox->setReadOnly( true );
00087 avtUI->latBox->setReadOnly( true );
00088
00089 topLayout->addWidget( avtUI );
00090
00091 geo = ks->geo();
00092
00093 DayOffset = 0;
00094 showCurrentDate();
00095 if ( getDate().time().hour() > 12 ) DayOffset = 1;
00096
00097 avtUI->longBox->show( geo->lng() );
00098 avtUI->latBox->show( geo->lat() );
00099
00100 computeSunRiseSetTimes();
00101
00102 setLSTLimits();
00103
00104 connect( avtUI->browseButton, SIGNAL( clicked() ), this, SLOT( slotBrowseObject() ) );
00105 connect( avtUI->cityButton, SIGNAL( clicked() ), this, SLOT( slotChooseCity() ) );
00106 connect( avtUI->updateButton, SIGNAL( clicked() ), this, SLOT( slotUpdateDateLoc() ) );
00107 connect( avtUI->clearButton, SIGNAL( clicked() ), this, SLOT( slotClear() ) );
00108 connect( avtUI->addButton, SIGNAL( clicked() ), this, SLOT( slotAddSource() ) );
00109 connect( avtUI->nameBox, SIGNAL( returnPressed() ), this, SLOT( slotAddSource() ) );
00110 connect( avtUI->raBox, SIGNAL( returnPressed() ), this, SLOT( slotAddSource() ) );
00111 connect( avtUI->decBox, SIGNAL( returnPressed() ), this, SLOT( slotAddSource() ) );
00112 connect( avtUI->clearFieldsButton, SIGNAL( clicked() ), this, SLOT( slotClearBoxes() ) );
00113 connect( avtUI->longBox, SIGNAL( returnPressed() ), this, SLOT( slotAdvanceFocus() ) );
00114 connect( avtUI->latBox, SIGNAL( returnPressed() ), this, SLOT( slotAdvanceFocus() ) );
00115 connect( avtUI->PlotList, SIGNAL( currentRowChanged(int) ), this, SLOT( slotHighlight(int) ) );
00116
00117
00118 avtUI->nameBox->setTrapReturnKey( true );
00119 avtUI->raBox->setTrapReturnKey( true );
00120 avtUI->decBox->setTrapReturnKey( true );
00121
00122 setMouseTracking( true );
00123 }
00124
00125 AltVsTime::~AltVsTime()
00126 {
00127
00128 }
00129
00130 void AltVsTime::slotAddSource(void) {
00131 SkyObject *obj = ks->data()->objectNamed( avtUI->nameBox->text() );
00132
00133 if ( obj ) {
00134
00135
00136 bool found(false);
00137 foreach ( SkyObject *o, pList ) {
00138 if ( o->name() == obj->name() ) { found = true; break; }
00139 }
00140
00141 if ( found )
00142 kDebug() << i18n("An object named %1 is already displayed; I will not duplicate it.", obj->name());
00143
00144 else
00145 processObject( obj );
00146
00147 } else {
00148
00149
00150
00151
00152 if ( ! avtUI->nameBox->text().isEmpty() &&
00153 ! avtUI->raBox->text().isEmpty() &&
00154 ! avtUI->decBox->text().isEmpty() ) {
00155 bool ok( true );
00156 dms newRA( 0.0 ), newDec( 0.0 );
00157 newRA = avtUI->raBox->createDms( false, &ok );
00158 if ( ok ) newDec = avtUI->decBox->createDms( true, &ok );
00159 if ( !ok ) return;
00160
00161
00162
00163 KStarsDateTime dt;
00164 dt.setFromEpoch( getEpoch( avtUI->epochName->text() ) );
00165 long double jd = dt.djd();
00166 if ( jd != J2000 ) {
00167 SkyPoint ptest( newRA, newDec );
00168 ptest.precessFromAnyEpoch( jd, J2000 );
00169 newRA.setH( ptest.ra()->Hours() );
00170 newDec.setD( ptest.dec()->Degrees() );
00171 }
00172
00173
00174 bool found(false);
00175 foreach ( SkyObject *p, pList ) {
00176
00177 if ( fabs( newRA.Degrees() - p->ra()->Degrees() ) < 0.0003 && fabs( newDec.Degrees() - p->dec()->Degrees() ) < 0.0003 ) {
00178 found = true;
00179 break;
00180 }
00181 }
00182 if ( found ) {
00183 kDebug() << "This point is already displayed; I will not duplicate it.";
00184 ok = false;
00185 }
00186
00187 if ( ok ) {
00188 SkyObject *obj = new SkyObject( 8, newRA, newDec, 1.0, avtUI->nameBox->text() );
00189 deleteList.append( obj );
00190 processObject( obj );
00191 }
00192 }
00193
00194
00195
00196
00197 if ( avtUI->nameBox->text().isEmpty() )
00198 avtUI->nameBox->QWidget::setFocus();
00199 if ( avtUI->raBox->text().isEmpty() )
00200 avtUI->raBox->QWidget::setFocus();
00201 else if ( avtUI->decBox->text().isEmpty() )
00202 avtUI->decBox->QWidget::setFocus();
00203 }
00204
00205 avtUI->View->update();
00206 }
00207
00208
00209 void AltVsTime::slotBrowseObject(void) {
00210 FindDialog fd(ks);
00211 if ( fd.exec() == QDialog::Accepted ) {
00212 SkyObject *o = fd.selectedObject();
00213 processObject( o );
00214 }
00215
00216 avtUI->View->update();
00217 }
00218
00219 void AltVsTime::processObject( SkyObject *o, bool forceAdd ) {
00220 if ( !o ) return;
00221
00222 KSNumbers *num = new KSNumbers( getDate().djd() );
00223 KSNumbers *oldNum = 0;
00224
00225
00226 if ( o->isSolarSystem() ) {
00227 oldNum = new KSNumbers( ks->data()->ut().djd() );
00228 o->updateCoords( num, true, geo->lat(), ks->LST() );
00229 }
00230
00231
00232 o->updateCoords( num );
00233
00234
00235 bool found(false);
00236 foreach ( SkyObject *p, pList ) {
00237 if ( o->ra()->Degrees() == p->ra()->Degrees() && o->dec()->Degrees() == p->dec()->Degrees() ) {
00238 found = true;
00239 break;
00240 }
00241 }
00242 if ( found && !forceAdd ) kDebug() << "This point is already displayed; I will not duplicate it.";
00243 else {
00244 pList.append( o );
00245
00246
00247 QList< KPlotObject* > objects = avtUI->View->plotObjects();
00248 for ( int i=0; i < objects.count(); ++i ) {
00249 KPlotObject *obj = objects.at( i );
00250 if ( obj->size() == 2 ) {
00251 obj->setLinePen( QPen( Qt::red, 1 ) );
00252 }
00253 }
00254
00255
00256 KPlotObject *po = new KPlotObject( Qt::white, KPlotObject::Lines, 2.0 );
00257 for ( double h=-12.0; h<=12.0; h+=0.5 ) {
00258 po->addPoint( h, findAltitude( o, h ) );
00259 }
00260 avtUI->View->addPlotObject( po );
00261
00262 avtUI->PlotList->addItem( o->translatedName() );
00263 avtUI->PlotList->setCurrentRow( avtUI->PlotList->count() - 1 );
00264 avtUI->raBox->showInHours(o->ra() );
00265 avtUI->decBox->showInDegrees(o->dec() );
00266 avtUI->nameBox->setText(o->translatedName() );
00267
00268
00269 avtUI->epochName->setText( QString().setNum( getDate().epoch() ) );
00270 }
00271 kDebug() << "Currently, there are " << avtUI->View->plotObjects().count() << " objects displayed.";
00272
00273
00274 if ( o->isSolarSystem() ) {
00275 o->updateCoords( oldNum, true, ks->geo()->lat(), ks->LST() );
00276 delete oldNum;
00277 }
00278 o->EquatorialToHorizontal( ks->LST(), ks->geo()->lat() );
00279 delete num;
00280 }
00281
00282 double AltVsTime::findAltitude( SkyPoint *p, double hour ) {
00283 hour += 24.0*(double)DayOffset;
00284
00285
00286 KStarsDateTime ut = getDate().addSecs( hour*3600.0 );
00287
00288 dms LST = geo->GSTtoLST( ut.gst() );
00289 p->EquatorialToHorizontal( &LST, geo->lat() );
00290 return p->alt()->Degrees();
00291 }
00292
00293 void AltVsTime::slotHighlight( int row ) {
00294
00295 QList< KPlotObject* > objects = avtUI->View->plotObjects();
00296 for ( int i=0; i<objects.count(); ++i ) {
00297 KPlotObject *obj = objects.at( i );
00298
00299 if ( i == row ) {
00300 obj->setLinePen( QPen( Qt::white, 2 ) );
00301 } else {
00302 obj->setLinePen( QPen( Qt::red, 1 ) );
00303 }
00304 }
00305
00306 avtUI->View->update();
00307
00308 for ( int i=0; i < pList.size(); ++i ) {
00309 if ( i == row ) {
00310 SkyObject *p = pList.at(i);
00311 avtUI->raBox->showInHours( p->ra() );
00312 avtUI->decBox->showInDegrees( p->dec() );
00313 avtUI->nameBox->setText( avtUI->PlotList->currentItem()->text() );
00314 }
00315 }
00316 }
00317
00318
00319 void AltVsTime::slotAdvanceFocus(void) {
00320 if ( sender()->objectName() == QString( "nameBox" ) ) avtUI->addButton->setFocus();
00321 if ( sender()->objectName() == QString( "raBox" ) ) avtUI->decBox->setFocus();
00322 if ( sender()->objectName() == QString( "decbox" ) ) avtUI->addButton->setFocus();
00323 if ( sender()->objectName() == QString( "longBox" ) ) avtUI->latBox->setFocus();
00324 if ( sender()->objectName() == QString( "latBox" ) ) avtUI->updateButton->setFocus();
00325 }
00326
00327 void AltVsTime::slotClear(void) {
00328 if ( pList.count() ) pList.clear();
00329
00330 while ( ! deleteList.isEmpty() )
00331 delete deleteList.takeFirst();
00332 avtUI->PlotList->clear();
00333 avtUI->nameBox->clear();
00334 avtUI->raBox->clear();
00335 avtUI->decBox->clear();
00336 avtUI->epochName->clear();
00337 avtUI->View->removeAllPlotObjects();
00338 avtUI->View->update();
00339 }
00340
00341 void AltVsTime::slotClearBoxes(void) {
00342 avtUI->nameBox->clear();
00343 avtUI->raBox->clear() ;
00344 avtUI->decBox->clear();
00345 avtUI->epochName->clear();
00346 }
00347
00348 void AltVsTime::computeSunRiseSetTimes() {
00349
00350
00351 KStarsDateTime today = getDate();
00352
00353 SkyObject *oSun = ks->data()->objectNamed( "Sun" );
00354 double sunRise = -1.0 * oSun->riseSetTime( today.djd() + 1.0, geo, true ).secsTo(QTime()) / 86400.0;
00355 double sunSet = -1.0 * oSun->riseSetTime( today.djd(), geo, false ).secsTo(QTime()) / 86400.0;
00356
00357
00358
00359 KSNumbers *num = new KSNumbers( today.djd() );
00360 KSNumbers *oldNum = new KSNumbers( ks->data()->ut().djd() );
00361 dms LST = geo->GSTtoLST( getDate().gst() );
00362 oSun->updateCoords( num, true, geo->lat(), &LST );
00363 if ( oSun->checkCircumpolar( geo->lat() ) ) {
00364 if ( oSun->alt()->Degrees() > 0.0 ) {
00365
00366 sunRise = 0.0;
00367 sunSet = 1.0;
00368 } else {
00369
00370 sunRise = 0.0;
00371 sunSet = -1.0;
00372 }
00373 }
00374
00375
00376 avtUI->View->setSunRiseSetTimes( sunRise, sunSet );
00377
00378
00379 oSun->updateCoords( oldNum, true, ks->geo()->lat(), ks->LST() );
00380 oSun->EquatorialToHorizontal( ks->LST(), ks->geo()->lat() );
00381
00382 delete num;
00383 delete oldNum;
00384 }
00385
00386 void AltVsTime::slotUpdateDateLoc(void) {
00387 KStarsDateTime today = getDate();
00388 KSNumbers *num = new KSNumbers( today.djd() );
00389 KSNumbers *oldNum = 0;
00390 dms LST = geo->GSTtoLST( today.gst() );
00391
00392
00393 computeSunRiseSetTimes();
00394
00395 for ( int i = 0; i < avtUI->PlotList->count(); ++i ) {
00396 QString oName = avtUI->PlotList->item( i )->text().toLower();
00397
00398 SkyObject *o = ks->data()->objectNamed( oName );
00399 if ( o ) {
00400
00401 if ( o->isSolarSystem() ) {
00402 oldNum = new KSNumbers( ks->data()->ut().djd() );
00403 o->updateCoords( num, true, geo->lat(), &LST );
00404 }
00405
00406
00407 o->updateCoords( num );
00408
00409
00410 pList.replace( i, o );
00411
00412 KPlotObject *po = new KPlotObject( Qt::white, KPlotObject::Lines, 1 );
00413 for ( double h=-12.0; h<=12.0; h+=0.5 ) {
00414 po->addPoint( h, findAltitude( o, h ) );
00415 }
00416 avtUI->View->replacePlotObject( i, po );
00417
00418
00419 if ( o->isSolarSystem() ) {
00420 o->updateCoords( oldNum, true, ks->data()->geo()->lat(), ks->LST() );
00421 delete oldNum;
00422 oldNum = 0;
00423 }
00424 o->EquatorialToHorizontal( ks->LST(), ks->geo()->lat() );
00425 } else {
00426 pList.at(i)->updateCoords( num );
00427
00428 KPlotObject *po = new KPlotObject( Qt::white, KPlotObject::Lines, 1 );
00429 for ( double h=-12.0; h<=12.0; h+=0.5 ) {
00430 po->addPoint( h, findAltitude( pList.at(i), h ) );
00431 }
00432 avtUI->View->replacePlotObject( i, po );
00433 }
00434 }
00435
00436 if ( getDate().time().hour() > 12 ) DayOffset = 1;
00437 else DayOffset = 0;
00438
00439 setLSTLimits();
00440 slotHighlight( avtUI->PlotList->currentRow() );
00441 avtUI->View->update();
00442
00443 delete num;
00444 }
00445
00446 void AltVsTime::slotChooseCity(void) {
00447 LocationDialog ld(ks);
00448 if ( ld.exec() == QDialog::Accepted ) {
00449 GeoLocation *newGeo = ld.selectedCity();
00450 if ( newGeo ) {
00451 geo = newGeo;
00452 avtUI->latBox->showInDegrees( geo->lat() );
00453 avtUI->longBox->showInDegrees( geo->lng() );
00454 }
00455 }
00456 }
00457
00458 int AltVsTime::currentPlotListItem() const {
00459 return avtUI->PlotList->currentRow();
00460 }
00461
00462 void AltVsTime::setLSTLimits(void) {
00463
00464 KStarsDateTime ut = getDate().addSecs( ((double)DayOffset + 0.5)*86400. );
00465
00466 dms lst = geo->GSTtoLST( ut.gst() );
00467 double h1 = lst.Hours();
00468 if ( h1 > 12.0 ) h1 -= 24.0;
00469 double h2 = h1 + 24.0;
00470 avtUI->View->setSecondaryLimits( h1, h2, -90.0, 90.0 );
00471 }
00472
00473 void AltVsTime::showCurrentDate (void)
00474 {
00475 KStarsDateTime dt = KStarsDateTime::currentDateTime();
00476 if ( dt.time() > QTime( 12, 0, 0 ) ) dt = dt.addDays( 1 );
00477 avtUI->DateWidget->setDate( dt.date() );
00478 }
00479
00480 KStarsDateTime AltVsTime::getDate (void)
00481 {
00482
00483 KStarsDateTime dt( avtUI->DateWidget->date(), QTime() );
00484 dt = geo->LTtoUT( dt );
00485 return dt;
00486 }
00487
00488 double AltVsTime::getEpoch(const QString &eName)
00489 {
00490
00491 bool ok(false);
00492 double epoch = eName.toDouble(&ok);
00493
00494 if ( !ok ) {
00495 kDebug() << "Invalid Epoch. Assuming 2000.0.";
00496 return 2000.0;
00497 }
00498
00499 return epoch;
00500 }
00501
00502 #include "altvstime.moc"