File indexing completed on 2024-04-28 11:25:35
0001 /* 0002 SPDX-FileCopyrightText: 2003 Jason Harris <jharris@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "planetviewer.h" 0008 0009 #include "ksfilereader.h" 0010 #include "ksnumbers.h" 0011 #include "kstarsdata.h" 0012 #include "ksutils.h" 0013 #include "skyobjects/ksplanet.h" 0014 #include "skyobjects/ksplanetbase.h" 0015 #include "widgets/timespinbox.h" 0016 0017 #include <KLocalizedString> 0018 #include <KPlotting/KPlotAxis> 0019 #include <KPlotting/KPlotObject> 0020 #include <KPlotting/KPlotPoint> 0021 #include <KPlotting/KPlotWidget> 0022 0023 #include <QFile> 0024 #include <QKeyEvent> 0025 #include <QVBoxLayout> 0026 0027 #include <cmath> 0028 0029 // Qt version calming 0030 #include <qtskipemptyparts.h> 0031 0032 PlanetViewerUI::PlanetViewerUI(QWidget *p) : QFrame(p) 0033 { 0034 setupUi(this); 0035 } 0036 0037 PlanetViewer::PlanetViewer(QWidget *parent) : QDialog(parent), scale(1.0), isClockRunning(false), tmr(this) 0038 { 0039 #ifdef Q_OS_OSX 0040 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0041 #endif 0042 KStarsData *data = KStarsData::Instance(); 0043 pw = new PlanetViewerUI(this); 0044 0045 QVBoxLayout *mainLayout = new QVBoxLayout; 0046 0047 mainLayout->addWidget(pw); 0048 setLayout(mainLayout); 0049 0050 setWindowTitle(i18nc("@title:window", "Solar System Viewer")); 0051 //setMainWidget( pw ); 0052 //setButtons( QDialog::Close ); 0053 setModal(false); 0054 0055 pw->map->setLimits(-48.0, 48.0, -48.0, 48.0); 0056 pw->map->axis(KPlotWidget::BottomAxis) 0057 ->setLabel(i18nc("axis label for x-coordinate of solar system viewer. AU means astronomical unit.", 0058 "X-position (AU)")); 0059 pw->map->axis(KPlotWidget::LeftAxis) 0060 ->setLabel(i18nc("axis label for y-coordinate of solar system viewer. AU means astronomical unit.", 0061 "Y-position (AU)")); 0062 0063 pw->TimeStep->setDaysOnly(true); 0064 pw->TimeStep->tsbox()->setValue(1); //start with 1-day timestep 0065 0066 pw->RunButton->setIcon(QIcon::fromTheme("arrow-right")); 0067 pw->ZoomInButton->setIcon(QIcon::fromTheme("zoom-in")); 0068 pw->ZoomOutButton->setIcon(QIcon::fromTheme("zoom-out")); 0069 pw->DateBox->setDate(data->lt().date()); 0070 0071 resize(500, 500); 0072 pw->map->QWidget::setFocus(); //give keyboard focus to the plot widget for key and mouse events 0073 0074 setCenterPlanet(QString()); 0075 0076 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::MERCURY)); 0077 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::VENUS)); 0078 PlanetList.append(new KSPlanet(i18n("Earth"))); 0079 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::MARS)); 0080 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::JUPITER)); 0081 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::SATURN)); 0082 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::URANUS)); 0083 PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::NEPTUNE)); 0084 //PlanetList.append( KSPlanetBase::createPlanet( KSPlanetBase::PLUTO ) ); 0085 0086 ut = data->ut(); 0087 KSNumbers num(ut.djd()); 0088 0089 for (int i = 0; i < PlanetList.count(); ++i) 0090 { 0091 PlanetList[i]->findPosition(&num, nullptr, nullptr); // nullptr args: don't need geocent. coords. 0092 LastUpdate[i] = int(ut.date().toJulianDay()); 0093 } 0094 0095 //The planets' update intervals are 0.25% of one period: 0096 UpdateInterval[0] = 0; 0097 UpdateInterval[1] = 0; 0098 UpdateInterval[2] = 0; 0099 UpdateInterval[3] = 1; 0100 UpdateInterval[4] = 5; 0101 UpdateInterval[5] = 13; 0102 UpdateInterval[6] = 38; 0103 UpdateInterval[7] = 75; 0104 //UpdateInterval[8] = 113; 0105 0106 QTimer::singleShot(0, this, SLOT(initPlotObjects())); 0107 0108 connect(&tmr, SIGNAL(timeout()), SLOT(tick())); 0109 connect(pw->TimeStep, SIGNAL(scaleChanged(float)), SLOT(setTimeScale(float))); 0110 connect(pw->RunButton, SIGNAL(clicked()), SLOT(slotRunClock())); 0111 connect(pw->ZoomInButton, SIGNAL(clicked()), pw->map, SLOT(slotZoomIn())); 0112 connect(pw->ZoomOutButton, SIGNAL(clicked()), pw->map, SLOT(slotZoomOut())); 0113 connect(pw->DateBox, SIGNAL(dateChanged(QDate)), SLOT(slotChangeDate())); 0114 connect(pw->TodayButton, SIGNAL(clicked()), SLOT(slotToday())); 0115 connect(this, SIGNAL(closeClicked()), SLOT(slotCloseWindow())); 0116 } 0117 0118 QString PlanetViewer::planetName(uint i) const 0119 { 0120 return PlanetList[i]->name(); 0121 } 0122 0123 void PlanetViewer::tick() 0124 { 0125 //Update the time/date 0126 ut.setDJD(ut.djd() + scale * 0.1); 0127 pw->DateBox->setDate(ut.date()); 0128 0129 updatePlanets(); 0130 } 0131 0132 void PlanetViewer::setTimeScale(float f) 0133 { 0134 scale = f / 86400.; //convert seconds to days 0135 } 0136 0137 void PlanetViewer::slotRunClock() 0138 { 0139 isClockRunning = !isClockRunning; 0140 0141 if (isClockRunning) 0142 { 0143 pw->RunButton->setIcon( 0144 QIcon::fromTheme("media-playback-pause")); 0145 tmr.start(100); 0146 // pw->DateBox->setEnabled( false ); 0147 } 0148 else 0149 { 0150 pw->RunButton->setIcon(QIcon::fromTheme("arrow-right")); 0151 tmr.stop(); 0152 // pw->DateBox->setEnabled( true ); 0153 } 0154 } 0155 0156 void PlanetViewer::slotChangeDate() 0157 { 0158 ut.setDate(pw->DateBox->date()); 0159 updatePlanets(); 0160 } 0161 0162 void PlanetViewer::slotCloseWindow() 0163 { 0164 //Stop the clock if it's running 0165 if (isClockRunning) 0166 { 0167 tmr.stop(); 0168 isClockRunning = false; 0169 pw->RunButton->setIcon(QIcon::fromTheme("arrow-right")); 0170 } 0171 } 0172 0173 void PlanetViewer::updatePlanets() 0174 { 0175 KSNumbers num(ut.djd()); 0176 bool changed(false); 0177 0178 //Check each planet to see if it needs to be updated 0179 for (int i = 0; i < PlanetList.count(); ++i) 0180 { 0181 if (abs(int(ut.date().toJulianDay()) - LastUpdate[i]) > UpdateInterval[i]) 0182 { 0183 KSPlanetBase *p = PlanetList[i]; 0184 p->findPosition(&num); 0185 0186 double s, c, s2, c2; 0187 p->helEcLong().SinCos(s, c); 0188 p->helEcLat().SinCos(s2, c2); 0189 QList<KPlotPoint *> points = planet[i]->points(); 0190 points.at(0)->setX(p->rsun() * c * c2); 0191 points.at(0)->setY(p->rsun() * s * c2); 0192 0193 if (centerPlanet() == p->name()) 0194 { 0195 QRectF dataRect = pw->map->dataRect(); 0196 double xc = (dataRect.right() + dataRect.left()) * 0.5; 0197 double yc = (dataRect.bottom() + dataRect.top()) * 0.5; 0198 double dx = points.at(0)->x() - xc; 0199 double dy = points.at(0)->y() - yc; 0200 pw->map->setLimits(dataRect.x() + dx, dataRect.right() + dx, dataRect.y() + dy, dataRect.bottom() + dy); 0201 } 0202 0203 LastUpdate[i] = int(ut.date().toJulianDay()); 0204 changed = true; 0205 } 0206 } 0207 0208 if (changed) 0209 pw->map->update(); 0210 } 0211 0212 void PlanetViewer::slotToday() 0213 { 0214 pw->DateBox->setDate(KStarsData::Instance()->lt().date()); 0215 } 0216 0217 void PlanetViewer::paintEvent(QPaintEvent *) 0218 { 0219 pw->map->update(); 0220 } 0221 0222 void PlanetViewer::initPlotObjects() 0223 { 0224 // Planets 0225 ksun = new KPlotObject(Qt::yellow, KPlotObject::Points, 12, KPlotObject::Circle); 0226 ksun->addPoint(0.0, 0.0); 0227 pw->map->addPlotObject(ksun); 0228 0229 //Read in the orbit curves 0230 for (int i = 0; i < PlanetList.count(); ++i) 0231 { 0232 KSPlanetBase *p = PlanetList[i]; 0233 KPlotObject *orbit = new KPlotObject(Qt::white, KPlotObject::Lines, 1.0); 0234 0235 QFile orbitFile; 0236 QString orbitFileName = 0237 (p->isMajorPlanet() ? (dynamic_cast<KSPlanet *>(p))->untranslatedName().toLower() : p->name().toLower()) + ".orbit"; 0238 if (KSUtils::openDataFile(orbitFile, orbitFileName)) 0239 { 0240 KSFileReader fileReader(orbitFile); // close file is included 0241 double x, y; 0242 while (fileReader.hasMoreLines()) 0243 { 0244 QString line = fileReader.readLine(); 0245 QStringList fields = line.split(' ', Qt::SkipEmptyParts); 0246 if (fields.size() == 3) 0247 { 0248 x = fields[0].toDouble(); 0249 y = fields[1].toDouble(); 0250 orbit->addPoint(x, y); 0251 } 0252 } 0253 } 0254 0255 pw->map->addPlotObject(orbit); 0256 } 0257 0258 for (int i = 0; i < PlanetList.count(); ++i) 0259 { 0260 KSPlanetBase *p = PlanetList[i]; 0261 planet[i] = new KPlotObject(p->color(), KPlotObject::Points, 6, KPlotObject::Circle); 0262 0263 double s, c; 0264 p->helEcLong().SinCos(s, c); 0265 0266 planet[i]->addPoint(p->rsun() * c, p->rsun() * s, p->translatedName()); 0267 pw->map->addPlotObject(planet[i]); 0268 } 0269 0270 update(); 0271 } 0272 0273 void PlanetViewer::keyPressEvent(QKeyEvent *e) 0274 { 0275 if (e->key() == Qt::Key_Escape) 0276 close(); 0277 else 0278 e->ignore(); 0279 }