1 /*
2 SPDX-FileCopyrightText: 2009 Jerome SONRIER <jsid@emor3j.fr.eu.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "satellitescomponent.h"
8
9 #include "ksfilereader.h"
10 #include "ksnotification.h"
11 #include "kstarsdata.h"
12 #include "Options.h"
13 #include "skylabeler.h"
14 #include "skymap.h"
15 #include "skypainter.h"
16 #include "skyobjects/satellite.h"
17
18 #include <QNetworkAccessManager>
19 #include <QNetworkReply>
20 #include <QProgressDialog>
21 #include <QtConcurrent>
22
SatellitesComponent(SkyComposite * parent)23 SatellitesComponent::SatellitesComponent(SkyComposite *parent) : SkyComponent(parent)
24 {
25 QtConcurrent::run(this, &SatellitesComponent::loadData);
26 }
27
~SatellitesComponent()28 SatellitesComponent::~SatellitesComponent()
29 {
30 qDeleteAll(m_groups);
31 m_groups.clear();
32 }
33
loadData()34 void SatellitesComponent::loadData()
35 {
36 KSFileReader fileReader;
37 QString line;
38 QStringList group_infos;
39
40 if (!fileReader.open("satellites.dat"))
41 return;
42
43 emitProgressText(i18n("Loading satellites"));
44
45 while (fileReader.hasMoreLines())
46 {
47 line = fileReader.readLine();
48 if (line.trimmed().isEmpty() || line.at(0) == '#')
49 continue;
50 group_infos = line.split(';');
51 m_groups.append(new SatelliteGroup(group_infos.at(0), group_infos.at(1), QUrl(group_infos.at(2))));
52 }
53
54 objectNames(SkyObject::SATELLITE).clear();
55 objectLists(SkyObject::SATELLITE).clear();
56
57 foreach (SatelliteGroup *group, m_groups)
58 {
59 for (int i = 0; i < group->size(); i++)
60 {
61 Satellite *sat = group->at(i);
62
63 if (sat->selected() && nameHash.contains(sat->name().toLower()) == false)
64 {
65 objectNames(SkyObject::SATELLITE).append(sat->name());
66 objectLists(SkyObject::SATELLITE).append(QPair<QString, const SkyObject *>(sat->name(), sat));
67 nameHash[sat->name().toLower()] = sat;
68 }
69 }
70 }
71 }
72
selected()73 bool SatellitesComponent::selected()
74 {
75 return Options::showSatellites();
76 }
77
update(KSNumbers *)78 void SatellitesComponent::update(KSNumbers *)
79 {
80 // Return if satellites must not be draw
81 if (!selected())
82 return;
83
84 foreach (SatelliteGroup *group, m_groups)
85 {
86 group->updateSatellitesPos();
87 }
88 }
89
draw(SkyPainter * skyp)90 void SatellitesComponent::draw(SkyPainter *skyp)
91 {
92 #ifndef KSTARS_LITE
93 // Return if satellites must not be draw
94 if (!selected())
95 return;
96
97 bool hideLabels = (!Options::showSatellitesLabels() || (SkyMap::Instance()->isSlewing() && Options::hideLabels()));
98
99 foreach (SatelliteGroup *group, m_groups)
100 {
101 for (int i = 0; i < group->size(); i++)
102 {
103 Satellite *sat = group->at(i);
104
105 if (sat->selected())
106 {
107 bool drawn = false;
108 if (Options::showVisibleSatellites())
109 {
110 if (sat->isVisible())
111 drawn = skyp->drawSatellite(sat);
112 }
113 else
114 {
115 drawn = skyp->drawSatellite(sat);
116 }
117
118 if (drawn && !hideLabels)
119 SkyLabeler::AddLabel(sat, SkyLabeler::SATELLITE_LABEL);
120 }
121 }
122 }
123 #else
124 Q_UNUSED(skyp);
125 #endif
126 }
127
drawLabel(Satellite * sat,const QPointF & pos)128 void SatellitesComponent::drawLabel(Satellite *sat, const QPointF& pos)
129 {
130 SkyLabeler *labeler = SkyLabeler::Instance();
131 labeler->setPen(KStarsData::Instance()->colorScheme()->colorNamed("SatLabelColor"));
132 labeler->drawNameLabel(sat, pos);
133 }
134
drawTrails(SkyPainter * skyp)135 void SatellitesComponent::drawTrails(SkyPainter *skyp)
136 {
137 Q_UNUSED(skyp);
138 }
139
updateTLEs()140 void SatellitesComponent::updateTLEs()
141 {
142 int i = 0;
143 QProgressDialog progressDlg(i18n("Update TLEs..."), i18n("Abort"), 0, m_groups.count());
144 progressDlg.setWindowModality(Qt::WindowModal);
145 progressDlg.setValue(0);
146
147 foreach (SatelliteGroup *group, m_groups)
148 {
149 if (progressDlg.wasCanceled())
150 return;
151
152 if (group->tleUrl().isEmpty())
153 continue;
154
155 progressDlg.setLabelText(i18n("Update %1 satellites", group->name()));
156 progressDlg.setWindowTitle(i18nc("@title:window", "Satellite Orbital Elements Update"));
157
158 QNetworkAccessManager manager;
159 QNetworkReply *response = manager.get(QNetworkRequest(group->tleUrl()));
160
161 // Wait synchronously
162 QEventLoop event;
163 QObject::connect(response, SIGNAL(finished()), &event, SLOT(quit()));
164 event.exec();
165
166 if (response->error() == QNetworkReply::NoError)
167 {
168 QFile file(group->tleFilename().toLocalFile());
169 if (file.open(QFile::WriteOnly))
170 {
171 file.write(response->readAll());
172 file.close();
173 group->readTLE();
174 group->updateSatellitesPos();
175 progressDlg.setValue(++i);
176 }
177 else
178 {
179 KSNotification::error(file.errorString());
180 return;
181 }
182 }
183 else
184 {
185 KSNotification::error(response->errorString());
186 return;
187 }
188 }
189 }
190
groups()191 QList<SatelliteGroup *> SatellitesComponent::groups()
192 {
193 return m_groups;
194 }
195
findSatellite(QString name)196 Satellite *SatellitesComponent::findSatellite(QString name)
197 {
198 foreach (SatelliteGroup *group, m_groups)
199 {
200 for (int i = 0; i < group->size(); i++)
201 {
202 Satellite *sat = group->at(i);
203 if (sat->name() == name)
204 return sat;
205 }
206 }
207
208 return nullptr;
209 }
210
objectNearest(SkyPoint * p,double & maxrad)211 SkyObject *SatellitesComponent::objectNearest(SkyPoint *p, double &maxrad)
212 {
213 if (!selected())
214 return nullptr;
215
216 //KStarsData* data = KStarsData::Instance();
217
218 SkyObject *oBest = nullptr;
219 double rBest = maxrad;
220 double r;
221
222 foreach (SatelliteGroup *group, m_groups)
223 {
224 for (int i = 0; i < group->size(); i++)
225 {
226 Satellite *sat = group->at(i);
227 if (!sat->selected())
228 continue;
229
230 r = sat->angularDistanceTo(p).Degrees();
231 //qDebug() << sat->name();
232 //qDebug() << "r = " << r << " - max = " << rBest;
233 //qDebug() << "ra2=" << sat->ra().Degrees() << " - dec2=" << sat->dec().Degrees();
234 if (r < rBest)
235 {
236 rBest = r;
237 oBest = sat;
238 }
239 }
240 }
241
242 maxrad = rBest;
243 return oBest;
244 }
245
findByName(const QString & name)246 SkyObject *SatellitesComponent::findByName(const QString &name)
247 {
248 return nameHash[name.toLower()];
249 }
250