File indexing completed on 2024-07-14 07:17:23

0001 /*
0002     SPDX-FileCopyrightText: 2009 Jerome SONRIER <jsid@emor3j.fr.eu.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "satellitescomponent.h"
0008 
0009 #include "ksfilereader.h"
0010 #include "ksnotification.h"
0011 #include "kstarsdata.h"
0012 #include "Options.h"
0013 #include "skylabeler.h"
0014 #include "skymap.h"
0015 #include "skypainter.h"
0016 #include "skyobjects/satellite.h"
0017 
0018 #include <QNetworkAccessManager>
0019 #include <QNetworkReply>
0020 #include <QProgressDialog>
0021 #include <QtConcurrent>
0022 
0023 SatellitesComponent::SatellitesComponent(SkyComposite *parent) : SkyComponent(parent)
0024 {
0025     QtConcurrent::run(this, &SatellitesComponent::loadData);
0026 }
0027 
0028 SatellitesComponent::~SatellitesComponent()
0029 {
0030     qDeleteAll(m_groups);
0031     m_groups.clear();
0032 }
0033 
0034 void SatellitesComponent::loadData()
0035 {
0036     KSFileReader fileReader;
0037     QString line;
0038     QStringList group_infos;
0039 
0040     if (!fileReader.open("satellites.dat"))
0041         return;
0042 
0043     emitProgressText(i18n("Loading satellites"));
0044 
0045     while (fileReader.hasMoreLines())
0046     {
0047         line = fileReader.readLine();
0048         if (line.trimmed().isEmpty() || line.at(0) == '#')
0049             continue;
0050         group_infos = line.split(';');
0051         m_groups.append(new SatelliteGroup(group_infos.at(0), group_infos.at(1), QUrl(group_infos.at(2))));
0052     }
0053 
0054     objectNames(SkyObject::SATELLITE).clear();
0055     objectLists(SkyObject::SATELLITE).clear();
0056 
0057     foreach (SatelliteGroup *group, m_groups)
0058     {
0059         for (int i = 0; i < group->size(); i++)
0060         {
0061             Satellite *sat = group->at(i);
0062 
0063             if (sat->selected() && nameHash.contains(sat->name().toLower()) == false)
0064             {
0065                 objectNames(SkyObject::SATELLITE).append(sat->name());
0066                 objectLists(SkyObject::SATELLITE).append(QPair<QString, const SkyObject *>(sat->name(), sat));
0067                 nameHash[sat->name().toLower()] = sat;
0068             }
0069         }
0070     }
0071 }
0072 
0073 bool SatellitesComponent::selected()
0074 {
0075     return Options::showSatellites();
0076 }
0077 
0078 void SatellitesComponent::update(KSNumbers *)
0079 {
0080     // Return if satellites must not be draw
0081     if (!selected())
0082         return;
0083 
0084     foreach (SatelliteGroup *group, m_groups)
0085     {
0086         group->updateSatellitesPos();
0087     }
0088 }
0089 
0090 void SatellitesComponent::draw(SkyPainter *skyp)
0091 {
0092 #ifndef KSTARS_LITE
0093     // Return if satellites must not be draw
0094     if (!selected())
0095         return;
0096 
0097     bool hideLabels = (!Options::showSatellitesLabels() || (SkyMap::Instance()->isSlewing() && Options::hideLabels()));
0098 
0099     foreach (SatelliteGroup *group, m_groups)
0100     {
0101         for (int i = 0; i < group->size(); i++)
0102         {
0103             Satellite *sat = group->at(i);
0104 
0105             if (sat->selected())
0106             {
0107                 bool drawn = false;
0108                 if (Options::showVisibleSatellites())
0109                 {
0110                     if (sat->isVisible())
0111                         drawn = skyp->drawSatellite(sat);
0112                 }
0113                 else
0114                 {
0115                     drawn = skyp->drawSatellite(sat);
0116                 }
0117 
0118                 if (drawn && !hideLabels)
0119                     SkyLabeler::AddLabel(sat, SkyLabeler::SATELLITE_LABEL);
0120             }
0121         }
0122     }
0123 #else
0124     Q_UNUSED(skyp);
0125 #endif
0126 }
0127 
0128 void SatellitesComponent::drawLabel(Satellite *sat, const QPointF &pos)
0129 {
0130     SkyLabeler *labeler = SkyLabeler::Instance();
0131     labeler->setPen(KStarsData::Instance()->colorScheme()->colorNamed("SatLabelColor"));
0132     labeler->drawNameLabel(sat, pos);
0133 }
0134 
0135 void SatellitesComponent::drawTrails(SkyPainter *skyp)
0136 {
0137     Q_UNUSED(skyp);
0138 }
0139 
0140 void SatellitesComponent::updateTLEs()
0141 {
0142     int i = 0;
0143     QProgressDialog progressDlg(i18n("Update TLEs..."), i18n("Abort"), 0, m_groups.count());
0144     progressDlg.setWindowModality(Qt::WindowModal);
0145     progressDlg.setValue(0);
0146 
0147     foreach (SatelliteGroup *group, m_groups)
0148     {
0149         if (progressDlg.wasCanceled())
0150             return;
0151 
0152         if (group->tleUrl().isEmpty())
0153             continue;
0154 
0155         progressDlg.setLabelText(i18n("Update %1 satellites", group->name()));
0156         progressDlg.setWindowTitle(i18nc("@title:window", "Satellite Orbital Elements Update"));
0157 
0158         QNetworkAccessManager manager;
0159         QNetworkReply *response = manager.get(QNetworkRequest(group->tleUrl()));
0160 
0161         // Wait synchronously
0162         QEventLoop event;
0163         QObject::connect(response, SIGNAL(finished()), &event, SLOT(quit()));
0164         event.exec();
0165 
0166         if (response->error() == QNetworkReply::NoError)
0167         {
0168             QFile file(group->tleFilename().toLocalFile());
0169             if (file.open(QFile::WriteOnly))
0170             {
0171                 file.write(response->readAll());
0172                 file.close();
0173                 group->readTLE();
0174                 group->updateSatellitesPos();
0175                 progressDlg.setValue(++i);
0176             }
0177             else
0178             {
0179                 KSNotification::error(file.errorString());
0180                 return;
0181             }
0182         }
0183         else
0184         {
0185             KSNotification::error(response->errorString());
0186             return;
0187         }
0188     }
0189 }
0190 
0191 QList<SatelliteGroup *> SatellitesComponent::groups()
0192 {
0193     return m_groups;
0194 }
0195 
0196 Satellite *SatellitesComponent::findSatellite(QString name)
0197 {
0198     foreach (SatelliteGroup *group, m_groups)
0199     {
0200         for (int i = 0; i < group->size(); i++)
0201         {
0202             Satellite *sat = group->at(i);
0203             if (sat->name() == name)
0204                 return sat;
0205         }
0206     }
0207 
0208     return nullptr;
0209 }
0210 
0211 SkyObject *SatellitesComponent::objectNearest(SkyPoint *p, double &maxrad)
0212 {
0213     if (!selected())
0214         return nullptr;
0215 
0216     //KStarsData* data = KStarsData::Instance();
0217 
0218     SkyObject *oBest = nullptr;
0219     double rBest     = maxrad;
0220     double r;
0221 
0222     foreach (SatelliteGroup *group, m_groups)
0223     {
0224         for (int i = 0; i < group->size(); i++)
0225         {
0226             Satellite *sat = group->at(i);
0227             if (!sat->selected())
0228                 continue;
0229 
0230             r = sat->angularDistanceTo(p).Degrees();
0231             //qDebug() << Q_FUNC_INFO << sat->name();
0232             //qDebug() << Q_FUNC_INFO << "r = " << r << " - max = " << rBest;
0233             //qDebug() << Q_FUNC_INFO << "ra2=" << sat->ra().Degrees() << " - dec2=" << sat->dec().Degrees();
0234             if (r < rBest)
0235             {
0236                 rBest = r;
0237                 oBest = sat;
0238             }
0239         }
0240     }
0241 
0242     maxrad = rBest;
0243     return oBest;
0244 }
0245 
0246 SkyObject *SatellitesComponent::findByName(const QString &name, bool exact)
0247 {
0248     Q_UNUSED(exact)
0249     return nameHash[name.toLower()];
0250 }