Kstars

planetviewer.cpp
1 /*
2  SPDX-FileCopyrightText: 2003 Jason Harris <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "planetviewer.h"
8 
9 #include "ksfilereader.h"
10 #include "ksnumbers.h"
11 #include "kstarsdata.h"
12 #include "ksutils.h"
13 #include "skyobjects/ksplanet.h"
14 #include "skyobjects/ksplanetbase.h"
15 #include "widgets/timespinbox.h"
16 
17 #include <KLocalizedString>
18 #include <KPlotting/KPlotAxis>
19 #include <KPlotting/KPlotObject>
20 #include <KPlotting/KPlotPoint>
21 #include <KPlotting/KPlotWidget>
22 
23 #include <QFile>
24 #include <QKeyEvent>
25 #include <QVBoxLayout>
26 
27 #include <cmath>
28 
29 // Qt version calming
30 #include <qtskipemptyparts.h>
31 
32 PlanetViewerUI::PlanetViewerUI(QWidget *p) : QFrame(p)
33 {
34  setupUi(this);
35 }
36 
37 PlanetViewer::PlanetViewer(QWidget *parent) : QDialog(parent), scale(1.0), isClockRunning(false), tmr(this)
38 {
39 #ifdef Q_OS_OSX
40  setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
41 #endif
42  KStarsData *data = KStarsData::Instance();
43  pw = new PlanetViewerUI(this);
44 
45  QVBoxLayout *mainLayout = new QVBoxLayout;
46 
47  mainLayout->addWidget(pw);
48  setLayout(mainLayout);
49 
50  setWindowTitle(i18nc("@title:window", "Solar System Viewer"));
51  //setMainWidget( pw );
52  //setButtons( QDialog::Close );
53  setModal(false);
54 
55  pw->map->setLimits(-48.0, 48.0, -48.0, 48.0);
56  pw->map->axis(KPlotWidget::BottomAxis)
57  ->setLabel(i18nc("axis label for x-coordinate of solar system viewer. AU means astronomical unit.",
58  "X-position (AU)"));
59  pw->map->axis(KPlotWidget::LeftAxis)
60  ->setLabel(i18nc("axis label for y-coordinate of solar system viewer. AU means astronomical unit.",
61  "Y-position (AU)"));
62 
63  pw->TimeStep->setDaysOnly(true);
64  pw->TimeStep->tsbox()->setValue(1); //start with 1-day timestep
65 
66  pw->RunButton->setIcon(QIcon::fromTheme("arrow-right"));
67  pw->ZoomInButton->setIcon(QIcon::fromTheme("zoom-in"));
68  pw->ZoomOutButton->setIcon(QIcon::fromTheme("zoom-out"));
69  pw->DateBox->setDate(data->lt().date());
70 
71  resize(500, 500);
72  pw->map->QWidget::setFocus(); //give keyboard focus to the plot widget for key and mouse events
73 
74  setCenterPlanet(QString());
75 
76  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::MERCURY));
77  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::VENUS));
78  PlanetList.append(new KSPlanet(i18n("Earth")));
79  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::MARS));
80  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::JUPITER));
81  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::SATURN));
82  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::URANUS));
83  PlanetList.append(KSPlanetBase::createPlanet(KSPlanetBase::NEPTUNE));
84  //PlanetList.append( KSPlanetBase::createPlanet( KSPlanetBase::PLUTO ) );
85 
86  ut = data->ut();
87  KSNumbers num(ut.djd());
88 
89  for (int i = 0; i < PlanetList.count(); ++i)
90  {
91  PlanetList[i]->findPosition(&num, nullptr, nullptr); // nullptr args: don't need geocent. coords.
92  LastUpdate[i] = int(ut.date().toJulianDay());
93  }
94 
95  //The planets' update intervals are 0.25% of one period:
96  UpdateInterval[0] = 0;
97  UpdateInterval[1] = 0;
98  UpdateInterval[2] = 0;
99  UpdateInterval[3] = 1;
100  UpdateInterval[4] = 5;
101  UpdateInterval[5] = 13;
102  UpdateInterval[6] = 38;
103  UpdateInterval[7] = 75;
104  //UpdateInterval[8] = 113;
105 
106  QTimer::singleShot(0, this, SLOT(initPlotObjects()));
107 
108  connect(&tmr, SIGNAL(timeout()), SLOT(tick()));
109  connect(pw->TimeStep, SIGNAL(scaleChanged(float)), SLOT(setTimeScale(float)));
110  connect(pw->RunButton, SIGNAL(clicked()), SLOT(slotRunClock()));
111  connect(pw->ZoomInButton, SIGNAL(clicked()), pw->map, SLOT(slotZoomIn()));
112  connect(pw->ZoomOutButton, SIGNAL(clicked()), pw->map, SLOT(slotZoomOut()));
113  connect(pw->DateBox, SIGNAL(dateChanged(QDate)), SLOT(slotChangeDate()));
114  connect(pw->TodayButton, SIGNAL(clicked()), SLOT(slotToday()));
115  connect(this, SIGNAL(closeClicked()), SLOT(slotCloseWindow()));
116 }
117 
118 QString PlanetViewer::planetName(uint i) const
119 {
120  return PlanetList[i]->name();
121 }
122 
123 void PlanetViewer::tick()
124 {
125  //Update the time/date
126  ut.setDJD(ut.djd() + scale * 0.1);
127  pw->DateBox->setDate(ut.date());
128 
129  updatePlanets();
130 }
131 
132 void PlanetViewer::setTimeScale(float f)
133 {
134  scale = f / 86400.; //convert seconds to days
135 }
136 
137 void PlanetViewer::slotRunClock()
138 {
139  isClockRunning = !isClockRunning;
140 
141  if (isClockRunning)
142  {
143  pw->RunButton->setIcon(
144  QIcon::fromTheme("media-playback-pause"));
145  tmr.start(100);
146  // pw->DateBox->setEnabled( false );
147  }
148  else
149  {
150  pw->RunButton->setIcon(QIcon::fromTheme("arrow-right"));
151  tmr.stop();
152  // pw->DateBox->setEnabled( true );
153  }
154 }
155 
156 void PlanetViewer::slotChangeDate()
157 {
158  ut.setDate(pw->DateBox->date());
159  updatePlanets();
160 }
161 
162 void PlanetViewer::slotCloseWindow()
163 {
164  //Stop the clock if it's running
165  if (isClockRunning)
166  {
167  tmr.stop();
168  isClockRunning = false;
169  pw->RunButton->setIcon(QIcon::fromTheme("arrow-right"));
170  }
171 }
172 
173 void PlanetViewer::updatePlanets()
174 {
175  KSNumbers num(ut.djd());
176  bool changed(false);
177 
178  //Check each planet to see if it needs to be updated
179  for (int i = 0; i < PlanetList.count(); ++i)
180  {
181  if (abs(int(ut.date().toJulianDay()) - LastUpdate[i]) > UpdateInterval[i])
182  {
183  KSPlanetBase *p = PlanetList[i];
184  p->findPosition(&num);
185 
186  double s, c, s2, c2;
187  p->helEcLong().SinCos(s, c);
188  p->helEcLat().SinCos(s2, c2);
189  QList<KPlotPoint *> points = planet[i]->points();
190  points.at(0)->setX(p->rsun() * c * c2);
191  points.at(0)->setY(p->rsun() * s * c2);
192 
193  if (centerPlanet() == p->name())
194  {
195  QRectF dataRect = pw->map->dataRect();
196  double xc = (dataRect.right() + dataRect.left()) * 0.5;
197  double yc = (dataRect.bottom() + dataRect.top()) * 0.5;
198  double dx = points.at(0)->x() - xc;
199  double dy = points.at(0)->y() - yc;
200  pw->map->setLimits(dataRect.x() + dx, dataRect.right() + dx, dataRect.y() + dy, dataRect.bottom() + dy);
201  }
202 
203  LastUpdate[i] = int(ut.date().toJulianDay());
204  changed = true;
205  }
206  }
207 
208  if (changed)
209  pw->map->update();
210 }
211 
212 void PlanetViewer::slotToday()
213 {
214  pw->DateBox->setDate(KStarsData::Instance()->lt().date());
215 }
216 
217 void PlanetViewer::paintEvent(QPaintEvent *)
218 {
219  pw->map->update();
220 }
221 
222 void PlanetViewer::initPlotObjects()
223 {
224  // Planets
225  ksun = new KPlotObject(Qt::yellow, KPlotObject::Points, 12, KPlotObject::Circle);
226  ksun->addPoint(0.0, 0.0);
227  pw->map->addPlotObject(ksun);
228 
229  //Read in the orbit curves
230  for (int i = 0; i < PlanetList.count(); ++i)
231  {
232  KSPlanetBase *p = PlanetList[i];
234 
235  QFile orbitFile;
236  QString orbitFileName =
237  (p->isMajorPlanet() ? (dynamic_cast<KSPlanet *>(p))->untranslatedName().toLower() : p->name().toLower()) + ".orbit";
238  if (KSUtils::openDataFile(orbitFile, orbitFileName))
239  {
240  KSFileReader fileReader(orbitFile); // close file is included
241  double x, y;
242  while (fileReader.hasMoreLines())
243  {
244  QString line = fileReader.readLine();
245  QStringList fields = line.split(' ', Qt::SkipEmptyParts);
246  if (fields.size() == 3)
247  {
248  x = fields[0].toDouble();
249  y = fields[1].toDouble();
250  orbit->addPoint(x, y);
251  }
252  }
253  }
254 
255  pw->map->addPlotObject(orbit);
256  }
257 
258  for (int i = 0; i < PlanetList.count(); ++i)
259  {
260  KSPlanetBase *p = PlanetList[i];
261  planet[i] = new KPlotObject(p->color(), KPlotObject::Points, 6, KPlotObject::Circle);
262 
263  double s, c;
264  p->helEcLong().SinCos(s, c);
265 
266  planet[i]->addPoint(p->rsun() * c, p->rsun() * s, p->translatedName());
267  pw->map->addPlotObject(planet[i]);
268  }
269 
270  update();
271 }
272 
273 void PlanetViewer::keyPressEvent(QKeyEvent *e)
274 {
275  if (e->key() == Qt::Key_Escape)
276  close();
277  else
278  e->ignore();
279 }
qreal left() const const
const dms & helEcLong() const
Definition: ksplanetbase.h:109
const KStarsDateTime & lt() const
Definition: kstarsdata.h:150
QColor & color()
Definition: ksplanetbase.h:203
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
qreal x() const const
qreal y() const const
void findPosition(const KSNumbers *num, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, const KSPlanetBase *Earth=nullptr)
Find position, including correction for Figure-of-the-Earth.
void SinCos(double &s, double &c) const
Compute Sine and Cosine of the angle simultaneously.
Definition: dms.h:439
QIcon fromTheme(const QString &name)
virtual QString name(void) const
Definition: skyobject.h:145
double rsun() const
Definition: ksplanetbase.h:130
QString translatedName() const
Definition: skyobject.h:148
const dms & helEcLat() const
Definition: ksplanetbase.h:112
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QString i18n(const char *text, const TYPE &arg...)
Store several time-dependent astronomical quantities.
Definition: ksnumbers.h:42
SkipEmptyParts
const T & at(int i) const const
QAction * close(const QObject *recvr, const char *slot, QObject *parent)
qreal bottom() const const
Key_Escape
Provides necessary information about objects in the solar system.
Definition: ksplanet.h:32
qreal top() const const
qreal right() const const
const KStarsDateTime & ut() const
Definition: kstarsdata.h:156
QString toLower() const const
void addPoint(const QPointF &p, const QString &label=QString(), double barWidth=0.0)
int key() const const
void ignore()
void update(Part *part, const QByteArray &data, qint64 dataSize)
QDate date() const const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
bool isMajorPlanet() const
Provides necessary information about objects in the solar system.
Definition: ksplanetbase.h:49
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue Aug 16 2022 04:00:57 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.