Kstars

planetviewer.cpp
1/*
2 SPDX-FileCopyrightText: 2003 Jason Harris <jharris@30doradus.org>
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 <kplotaxis.h>
19#include <kplotobject.h>
20#include <kplotpoint.h>
21#include <kplotwidget.h>
22
23#include <QFile>
24#include <QKeyEvent>
25#include <QVBoxLayout>
26
27#include <cmath>
28
29// Qt version calming
30#include <qtskipemptyparts.h>
31
32PlanetViewerUI::PlanetViewerUI(QWidget *p) : QFrame(p)
33{
34 setupUi(this);
35}
36
37PlanetViewer::PlanetViewer(QWidget *parent) : QDialog(parent), scale(1.0), isClockRunning(false), tmr(this)
38{
39#ifdef Q_OS_MACOS
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
118QString PlanetViewer::planetName(uint i) const
119{
120 return PlanetList[i]->name();
121}
122
123void 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
132void PlanetViewer::setTimeScale(float f)
133{
134 scale = f / 86400.; //convert seconds to days
135}
136
137void 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
156void PlanetViewer::slotChangeDate()
157{
158 ut.setDate(pw->DateBox->date());
159 updatePlanets();
160}
161
162void 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
173void 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
212void PlanetViewer::slotToday()
213{
214 pw->DateBox->setDate(KStarsData::Instance()->lt().date());
215}
216
217void PlanetViewer::paintEvent(QPaintEvent *)
218{
219 pw->map->update();
220}
221
222void 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
273void PlanetViewer::keyPressEvent(QKeyEvent *e)
274{
275 if (e->key() == Qt::Key_Escape)
276 close();
277 else
278 e->ignore();
279}
void addPoint(const QPointF &p, const QString &label=QString(), double barWidth=0.0)
QList< KPlotPoint * > points() const
I totally rewrote this because the earlier scheme of reading all the lines of a file into a buffer be...
There are several time-dependent values used in position calculations, that are not specific to an ob...
Definition ksnumbers.h:43
A subclass of TrailObject that provides additional information needed for most solar system objects.
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.
const dms & helEcLat() const
const dms & helEcLong() const
QColor & color()
double rsun() const
bool isMajorPlanet() const
A subclass of KSPlanetBase for seven of the major planets in the solar system (Earth and Pluto have t...
Definition ksplanet.h:33
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
const KStarsDateTime & lt() const
Definition kstarsdata.h:151
const KStarsDateTime & ut() const
Definition kstarsdata.h:157
void setDJD(long double jd)
Assign the static_cast<long double> Julian Day value, which includes the time of day encoded in the f...
void setDate(const QDate &d)
Assign the Date according to a QDate object.
long double djd() const
QString translatedName() const
Definition skyobject.h:148
virtual QString name(void) const
Definition skyobject.h:145
void SinCos(double &s, double &c) const
Compute Sine and Cosine of the angle simultaneously.
Definition dms.h:447
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
qint64 toJulianDay() const const
QDate date() const const
void ignore()
QIcon fromTheme(const QString &name)
int key() const const
const_reference at(qsizetype i) const const
qsizetype count() const const
qreal bottom() const const
qreal left() const const
qreal right() const const
qreal top() const const
qreal x() const const
qreal y() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString toLower() const const
Key_Escape
SkipEmptyParts
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void start()
void stop()
bool close()
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.