1 /*
2 SPDX-FileCopyrightText: 2016 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 Based on Samikshan Bairagya GSoC work.
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "supernovaecomponent.h"
10
11 #ifndef KSTARS_LITE
12 #include "kstars.h"
13 #include "skymap.h"
14 #else
15 #include "kstarslite.h"
16 #endif
17 #include "dms.h"
18 #include "kstars_debug.h"
19 #include "ksnotification.h"
20 #include "kstarsdata.h"
21 #include "Options.h"
22 #include "skylabeler.h"
23 #include "skymesh.h"
24 #include "skypainter.h"
25 #include "auxiliary/filedownloader.h"
26 #include "projections/projector.h"
27 #include "auxiliary/kspaths.h"
28
29 #include <QtConcurrent>
30 #include <QJsonDocument>
31 #include <QJsonValue>
32
SupernovaeComponent(SkyComposite * parent)33 SupernovaeComponent::SupernovaeComponent(SkyComposite *parent) : ListComponent(parent)
34 {
35 //QtConcurrent::run(this, &SupernovaeComponent::loadData);
36 //loadData();
37 }
38
update(KSNumbers * num)39 void SupernovaeComponent::update(KSNumbers *num)
40 {
41 if (!selected() || !m_DataLoaded)
42 return;
43
44 KStarsData *data = KStarsData::Instance();
45 for (auto so : m_ObjectList)
46 {
47 if (num)
48 so->updateCoords(num);
49 so->EquatorialToHorizontal(data->lst(), data->geo()->lat());
50 }
51 }
52
selected()53 bool SupernovaeComponent::selected()
54 {
55 return Options::showSupernovae();
56 }
57
loadData()58 void SupernovaeComponent::loadData()
59 {
60 qDeleteAll(m_ObjectList);
61 m_ObjectList.clear();
62
63 objectNames(SkyObject::SUPERNOVA).clear();
64 objectLists(SkyObject::SUPERNOVA).clear();
65
66 QString name, type, host, date, ra, de;
67 float z, mag;
68
69 QString sFileName = KSPaths::locate(QStandardPaths::AppDataLocation, QString("catalog.min.json"));
70
71 QFile sNovaFile(sFileName);
72
73 if (sNovaFile.open(QIODevice::ReadOnly) == false)
74 {
75 qCritical() << "Unable to open supernova file" << sFileName;
76 return;
77 }
78
79 QJsonParseError pError;
80 QJsonDocument sNova = QJsonDocument::fromJson(sNovaFile.readAll(), &pError);
81
82 if (pError.error != QJsonParseError::NoError)
83 {
84 qCritical() << "Error parsing json document" << pError.errorString();
85 return;
86 }
87
88 if (sNova.isArray() == false)
89 {
90 qCCritical(KSTARS) << "Invalid document format! No JSON array.";
91 return;
92 }
93
94 QJsonArray sArray = sNova.array();
95 bool ok = false;
96
97 for (const auto snValue : sArray)
98 {
99 const QJsonObject propObject = snValue.toObject();
100 mag = 99.9;
101 z = 0;
102 name.clear();
103 type.clear();
104 host.clear();
105 date.clear();
106
107 if (propObject.contains("ra") == false || propObject.contains("dec") == false)
108 continue;
109 ra = ((propObject["ra"].toArray()[0]).toObject()["value"]).toString();
110 de = ((propObject["dec"].toArray()[0]).toObject()["value"]).toString();
111
112 name = propObject["name"].toString();
113 if (propObject.contains("claimedtype"))
114 type = ((propObject["claimedtype"].toArray()[0]).toObject()["value"]).toString();
115 if (propObject.contains("host"))
116 host = ((propObject["host"].toArray()[0]).toObject()["value"]).toString();
117 if (propObject.contains("discoverdate"))
118 date = ((propObject["discoverdate"].toArray()[0]).toObject()["value"]).toString();
119 if (propObject.contains("redshift"))
120 z = ((propObject["redshift"].toArray()[0]).toObject()["value"]).toString().toDouble(&ok);
121 if (ok == false)
122 z = 99.9;
123 if (propObject.contains("maxappmag"))
124 mag = ((propObject["maxappmag"].toArray()[0]).toObject()["value"]).toString().toDouble(&ok);
125 if (ok == false)
126 mag = 99.9;
127
128 Supernova *sup =
129 new Supernova(name, dms::fromString(ra, false), dms::fromString(de, true), type, host, date, z, mag);
130
131 objectNames(SkyObject::SUPERNOVA).append(name);
132
133 appendListObject(sup);
134 objectLists(SkyObject::SUPERNOVA).append(QPair<QString, const SkyObject *>(name, sup));
135 }
136
137 m_DataLoading = false;
138 m_DataLoaded = true;
139 }
140
objectNearest(SkyPoint * p,double & maxrad)141 SkyObject *SupernovaeComponent::objectNearest(SkyPoint *p, double &maxrad)
142 {
143 if (!selected() || !m_DataLoaded)
144 return nullptr;
145
146 SkyObject *oBest = nullptr;
147 double rBest = maxrad;
148
149 for (auto so : m_ObjectList)
150 {
151 double r = so->angularDistanceTo(p).Degrees();
152 //qDebug()<<r;
153 if (r < rBest)
154 {
155 oBest = so;
156 rBest = r;
157 }
158 }
159 maxrad = rBest;
160 return oBest;
161 }
162
zoomMagnitudeLimit()163 float SupernovaeComponent::zoomMagnitudeLimit()
164 {
165 //adjust maglimit for ZoomLevel
166 double lgmin = log10(MINZOOM);
167 double lgz = log10(Options::zoomFactor());
168
169 return 14.0 + 2.222 * (lgz - lgmin) + 2.222 * log10(static_cast<double>(Options::starDensity()));
170 }
171
draw(SkyPainter * skyp)172 void SupernovaeComponent::draw(SkyPainter *skyp)
173 {
174 //qDebug()<<"selected()="<<selected();
175 if (!selected())
176 return;
177 else if (!m_DataLoaded)
178 {
179 if (!m_DataLoading)
180 {
181 m_DataLoading = true;
182 QtConcurrent::run(this, &SupernovaeComponent::loadData);
183 }
184 return;
185 }
186
187 double maglim = zoomMagnitudeLimit();
188
189 for (auto so : m_ObjectList)
190 {
191 Supernova *sup = dynamic_cast<Supernova *>(so);
192 float mag = sup->mag();
193
194 if (mag > float(Options::magnitudeLimitShowSupernovae()))
195 continue;
196
197 //Do not draw if mag>maglim
198 if (mag > maglim)
199 continue;
200 skyp->drawSupernova(sup);
201 }
202 }
203
204 #if 0
205 void SupernovaeComponent::notifyNewSupernovae()
206 {
207 #ifndef KSTARS_LITE
208 //qDebug()<<"New Supernovae discovered";
209 QList<SkyObject *> latestList;
210 foreach (SkyObject * so, latest)
211 {
212 Supernova * sup = (Supernova *)so;
213
214 if (sup->getMagnitude() > float(Options::magnitudeLimitAlertSupernovae()))
215 {
216 //qDebug()<<"Not Bright enough to be notified";
217 continue;
218 }
219
220 //qDebug()<<"Bright enough to be notified";
221 latestList.append(so);
222 }
223 if (!latestList.empty())
224 {
225 NotifyUpdatesUI * ui = new NotifyUpdatesUI(0);
226 ui->addItems(latestList);
227 ui->show();
228 }
229 // if (!latest.empty())
230 // KMessageBox::informationList(0, i18n("New Supernovae discovered!"), latestList, i18n("New Supernovae discovered!"));
231 #endif
232 }
233 #endif
234
slotTriggerDataFileUpdate()235 void SupernovaeComponent::slotTriggerDataFileUpdate()
236 {
237 delete(downloadJob);
238 downloadJob = new FileDownloader();
239
240 downloadJob->setProgressDialogEnabled(true, i18n("Supernovae Update"), i18n("Downloading Supernovae updates..."));
241
242 QObject::connect(downloadJob, SIGNAL(downloaded()), this, SLOT(downloadReady()));
243 QObject::connect(downloadJob, SIGNAL(error(QString)), this, SLOT(downloadError(QString)));
244
245 QString output = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("catalog.min.json");
246
247 downloadJob->setDownloadedFileURL(QUrl::fromLocalFile(output));
248
249 downloadJob->get(QUrl("https://sne.space/astrocats/astrocats/supernovae/output/catalog.min.json"));
250 }
251
downloadReady()252 void SupernovaeComponent::downloadReady()
253 {
254 // Reload Supernova
255 loadData();
256 #ifdef KSTARS_LITE
257 KStarsLite::Instance()->data()->setFullTimeUpdate();
258 #else
259 KStars::Instance()->data()->setFullTimeUpdate();
260 #endif
261 downloadJob->deleteLater();
262 }
263
downloadError(const QString & errorString)264 void SupernovaeComponent::downloadError(const QString &errorString)
265 {
266 KSNotification::error(i18n("Error downloading supernova data: %1", errorString));
267 downloadJob->deleteLater();
268 }
269