Kstars

cometscomponent.cpp
1 /*
2  SPDX-FileCopyrightText: 2005 Jason Harris <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "cometscomponent.h"
8 
9 #ifndef KSTARS_LITE
10 #include "kstars.h"
11 #endif
12 #include "ksfilereader.h"
13 #include "kspaths.h"
14 #include "kstarsdata.h"
15 #include "ksutils.h"
16 #include "ksnotification.h"
17 #include "kstars_debug.h"
18 #ifndef KSTARS_LITE
19 #include "skymap.h"
20 #else
21 #include "kstarslite.h"
22 #endif
23 #include "Options.h"
24 #include "skylabeler.h"
25 #include "skypainter.h"
26 #include "solarsystemcomposite.h"
27 #include "auxiliary/filedownloader.h"
28 #include "auxiliary/kspaths.h"
29 #include "projections/projector.h"
30 #include "skyobjects/kscomet.h"
31 
32 #include <QFile>
33 #include <QHttpMultiPart>
34 #include <QPen>
35 #include <QStandardPaths>
36 
37 #include <cmath>
38 
40  : SolarSystemListComponent(parent)
41 {
42  loadData();
43 }
44 
46 {
47  return Options::showComets();
48 }
49 
50 /*
51  * @short Initialize the comets list.
52  * Reads in the comets data from the comets.dat file.
53  *
54  * Populate the list of Comets from the data file.
55  * The data file is a CSV file with the following columns :
56  * @li 1 full name [string]
57  * @li 2 modified julian day of orbital elements [int]
58  * @li 3 perihelion distance in AU [double]
59  * @li 4 eccentricity of orbit [double]
60  * @li 5 inclination angle of orbit in degrees [double]
61  * @li 6 argument of perihelion in degrees [double]
62  * @li 7 longitude of the ascending node in degrees [double]
63  * @li 8 time of perihelion passage (YYYYMMDD.DDD) [double]
64  * @li 9 orbit solution ID [string]
65  * @li 10 Near-Earth Object (NEO) flag [bool]
66  * @li 11 comet total magnitude parameter [float]
67  * @li 12 comet nuclear magnitude parameter [float]
68  * @li 13 object diameter (from equivalent sphere) [float]
69  * @li 14 object bi/tri-axial ellipsoid dimensions [string]
70  * @li 15 geometric albedo [float]
71  * @li 16 rotation period [float]
72  * @li 17 orbital period [float]
73  * @li 18 earth minimum orbit intersection distance [double]
74  * @li 19 orbit classification [string]
75  * @li 20 comet total magnitude slope parameter
76  * @li 21 comet nuclear magnitude slope parameter
77  * @note See KSComet constructor for more details.
78  */
79 void CometsComponent::loadData()
80 {
81  QString name, orbit_class;
82 
83  emitProgressText(i18n("Loading comets"));
84  qCInfo(KSTARS) << "Loading comets";
85 
86  qDeleteAll(m_ObjectList);
87  m_ObjectList.clear();
88 
89  objectNames(SkyObject::COMET).clear();
90  objectLists(SkyObject::COMET).clear();
91 
92  QString file_name = KSPaths::locate(QStandardPaths::AppLocalDataLocation, QString("cometels.json.gz"));
93 
94  try
95  {
96  KSUtils::MPCParser com_parser(file_name);
97  com_parser.for_each(
98  [&](const auto & get)
99  {
100  KSComet *com = nullptr;
101  name = get("Designation_and_name").toString();
102 
103  int perihelion_year, perihelion_month, perihelion_day, perihelion_hour, perihelion_minute, perihelion_second;
104 
105  // Perihelion Distance in AU
106  double perihelion_distance = get("Perihelion_dist").toDouble();
107  // Orbital Eccentricity
108  double eccentricity = get("e").toDouble();
109  // Argument of perihelion, J2000.0 (degrees)
110  double perihelion_argument = get("Peri").toDouble();
111  // Longitude of the ascending node, J2000.0 (degrees)
112  double ascending_node = get("Node").toDouble();
113  // Inclination in degrees, J2000.0 (degrees)
114  double inclination = get("i").toDouble();
115 
116  // Perihelion Date
117  perihelion_year = get("Year_of_perihelion").toInt();
118  perihelion_month = get("Month_of_perihelion").toInt();
119  // Stored as double in MPC
120  double peri_day = get("Day_of_perihelion").toDouble();
121  perihelion_day = static_cast<int>(peri_day);
122  double peri_hour = (peri_day - perihelion_day) * 24;
123  perihelion_hour = static_cast<int>(peri_hour);
124  perihelion_minute = static_cast<int>((peri_hour - perihelion_hour) * 60);
125  perihelion_second = ( (( peri_hour - perihelion_hour) * 60) - perihelion_minute) * 60;
126 
127  long double Tp = KStarsDateTime(QDate(perihelion_year, perihelion_month, perihelion_day),
128  QTime(perihelion_hour, perihelion_minute, perihelion_second)).djd();
129 
130  // Orbit type
131  orbit_class = get("Orbit_type").toString();
132  double absolute_magnitude = get("H").toDouble();
133  double slope_parameter = get("G").toDouble();
134 
135  com = new KSComet(name,
136  QString(),
137  perihelion_distance,
138  eccentricity,
139  dms(inclination),
140  dms(perihelion_argument),
141  dms(ascending_node),
142  Tp,
143  absolute_magnitude,
144  101.0,
145  slope_parameter,
146  101.0);
147 
148  com->setOrbitClass(orbit_class);
149  com->setAngularSize(0.005);
150  appendListObject(com);
151 
152  // Add *short* name to the list of object names
153  objectNames(SkyObject::COMET).append(com->name());
154  objectLists(SkyObject::COMET).append(QPair<QString, const SkyObject *>(com->name(), com));
155  });
156  }
157  catch (const std::runtime_error&)
158  {
159  qCInfo(KSTARS) << "Loading comets failed.";
160  qCInfo(KSTARS) << " -> was trying to read " + file_name;
161  return;
162  }
163 }
164 
165 // Used for JPL Data
166 // DO NOT REMOVE, we can revert to JPL at any time.
167 //void CometsComponent::loadData()
168 //{
169 // QString name, orbit_id, orbit_class, dimensions;
170 
171 // emitProgressText(i18n("Loading comets"));
172 // qCInfo(KSTARS) << "Loading comets";
173 
174 // qDeleteAll(m_ObjectList);
175 // m_ObjectList.clear();
176 
177 // objectNames(SkyObject::COMET).clear();
178 // objectLists(SkyObject::COMET).clear();
179 
180 // QString file_name =
181 // KSPaths::locate(QStandardPaths::AppLocalDataLocation, QString("comets.dat"));
182 
183 // try
184 // {
185 // KSUtils::JPLParser com_parser(file_name);
186 // com_parser.for_each(
187 // [&](const auto &get)
188 // {
189 // KSComet *com = nullptr;
190 // name = get("full_name").toString();
191 // name = name.trimmed();
192 // bool neo;
193 // double q, e, dble_i, dble_w, dble_N, Tp, earth_moid;
194 // float M1, M2, K1, K2, diameter, albedo, rot_period, period;
195 // q = get("q").toString().toDouble();
196 // e = get("e").toString().toDouble();
197 // dble_i = get("i").toString().toDouble();
198 // dble_w = get("w").toString().toDouble();
199 // dble_N = get("om").toString().toDouble();
200 // Tp = get("tp").toString().toDouble();
201 // orbit_id = get("orbit_id").toString();
202 // neo = get("neo").toString() == "Y";
203 
204 // if (get("M1").toString().toFloat() == 0.0)
205 // M1 = 101.0;
206 // else
207 // M1 = get("M1").toString().toFloat();
208 
209 // if (get("M2").toString().toFloat() == 0.0)
210 // M2 = 101.0;
211 // else
212 // M2 = get("M2").toString().toFloat();
213 
214 // diameter = get("diameter").toString().toFloat();
215 // dimensions = get("extent").toString();
216 // albedo = get("albedo").toString().toFloat();
217 // rot_period = get("rot_per").toString().toFloat();
218 // period = get("per.y").toDouble();
219 // earth_moid = get("moid").toString().toDouble();
220 // orbit_class = get("class").toString();
221 // K1 = get("H").toString().toFloat();
222 // K2 = get("G").toString().toFloat();
223 
224 // com = new KSComet(name, QString(), q, e, dms(dble_i), dms(dble_w),
225 // dms(dble_N), Tp, M1, M2, K1, K2);
226 // com->setOrbitID(orbit_id);
227 // com->setNEO(neo);
228 // com->setDiameter(diameter);
229 // com->setDimensions(dimensions);
230 // com->setAlbedo(albedo);
231 // com->setRotationPeriod(rot_period);
232 // com->setPeriod(period);
233 // com->setEarthMOID(earth_moid);
234 // com->setOrbitClass(orbit_class);
235 // com->setAngularSize(0.005);
236 // appendListObject(com);
237 
238 // // Add *short* name to the list of object names
239 // objectNames(SkyObject::COMET).append(com->name());
240 // objectLists(SkyObject::COMET)
241 // .append(QPair<QString, const SkyObject *>(com->name(), com));
242 // });
243 // }
244 // catch (const std::runtime_error &e)
245 // {
246 // qCInfo(KSTARS) << "Loading comets failed.";
247 // qCInfo(KSTARS) << " -> was trying to read " + file_name;
248 // return;
249 // }
250 //}
251 
253 {
254  Q_UNUSED(skyp)
255 #ifndef KSTARS_LITE
256  if (!selected() || Options::zoomFactor() < 1 * MINZOOM)
257  return;
258 
259  bool hideLabels = !Options::showCometNames() || (SkyMap::Instance()->isSlewing() && Options::hideLabels());
260  double rsunLabelLimit = Options::maxRadCometName();
261 
262  //FIXME: Should these be config'able?
263  skyp->setPen(QPen(QColor("transparent")));
264  skyp->setBrush(QBrush(QColor("white")));
265 
266  for (auto so : m_ObjectList)
267  {
268  KSComet *com = dynamic_cast<KSComet *>(so);
269  double mag = com->mag();
270  if (std::isnan(mag) == 0)
271  {
272  bool drawn = skyp->drawComet(com);
273  if (drawn && !(hideLabels || com->rsun() >= rsunLabelLimit))
274  SkyLabeler::AddLabel(com, SkyLabeler::COMET_LABEL);
275  }
276  }
277 #endif
278 }
279 
280 // DO NOT REMOVE
281 //void CometsComponent::updateDataFile(bool isAutoUpdate)
282 //{
283 // delete (downloadJob);
284 // downloadJob = new FileDownloader();
285 
286 // if (isAutoUpdate == false)
287 // downloadJob->setProgressDialogEnabled(true, i18n("Comets Update"),
288 // i18n("Downloading comets updates..."));
289 // downloadJob->registerDataVerification([&](const QByteArray &data)
290 // { return data.startsWith("{\"signature\""); });
291 
292 // connect(downloadJob, SIGNAL(downloaded()), this, SLOT(downloadReady()));
293 
294 // // For auto-update, we ignore errors
295 // if (isAutoUpdate == false)
296 // connect(downloadJob, SIGNAL(error(QString)), this, SLOT(downloadError(QString)));
297 
298 // QUrl url = QUrl("https://ssd-api.jpl.nasa.gov/sbdb_query.api");
299 // QByteArray post_data = KSUtils::getJPLQueryString(
300 // "c",
301 // "full_name,epoch.mjd,q,e,i,w,om,tp,orbit_id,neo,"
302 // "M1,M2,diameter,extent,albedo,rot_per,per.y,moid,H,G,class",
303 // QVector<KSUtils::JPLFilter>{});
304 // // FIXME: find out what { "Af", "!=", "D" } used to mean
305 
306 // downloadJob->post(url, post_data);
307 //}
308 
309 void CometsComponent::updateDataFile(bool isAutoUpdate)
310 {
311  delete (downloadJob);
312  downloadJob = new FileDownloader();
313 
314  if (isAutoUpdate == false)
315  downloadJob->setProgressDialogEnabled(true, i18n("Comets Update"),
316  i18n("Downloading comets updates..."));
317 
318  connect(downloadJob, SIGNAL(downloaded()), this, SLOT(downloadReady()));
319 
320  // For auto-update, we ignore errors
321  if (isAutoUpdate == false)
322  connect(downloadJob, SIGNAL(error(QString)), this, SLOT(downloadError(QString)));
323 
324  QUrl url = QUrl("https://www.minorplanetcenter.net/Extended_Files/cometels.json.gz");
325  downloadJob->get(url);
326 }
327 
328 void CometsComponent::downloadReady()
329 {
330  // Comment the first line
331  QByteArray data = downloadJob->downloadedData();
332 
333  // Write data to cometels.json.gz
334  QFile file(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
335  .filePath("cometels.json.gz"));
336  if (file.open(QIODevice::WriteOnly))
337  {
338  file.write(data);
339  file.close();
340  }
341  else
342  qCWarning(KSTARS) << "Failed writing comet data to" << file.fileName();
343 
344  QString focusedComet;
345 
346 #ifdef KSTARS_LITE
348  if (foc && foc->type() == SkyObject::COMET)
349  {
350  focusedComet = foc->name();
351  KStarsLite::Instance()->map()->setFocusObject(nullptr);
352  }
353 #else
354  SkyObject *foc = KStars::Instance()->map()->focusObject();
355  if (foc && foc->type() == SkyObject::COMET)
356  {
357  focusedComet = foc->name();
358  KStars::Instance()->map()->setFocusObject(nullptr);
359  }
360 #endif
361 
362  // Reload comets
363  loadData();
364 
365 #ifdef KSTARS_LITE
367  if (!focusedComet.isEmpty())
369  KStarsLite::Instance()->data()->objectNamed(focusedComet));
370 #else
371  if (!focusedComet.isEmpty())
373  KStars::Instance()->data()->objectNamed(focusedComet));
375 #endif
376 
377  downloadJob->deleteLater();
378 }
379 
380 // DO NOT REMOVE
381 //void CometsComponent::downloadReady()
382 //{
383 // // Comment the first line
384 // QByteArray data = downloadJob->downloadedData();
385 
386 // // Write data to comets.dat
387 // QFile file(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
388 // .filePath("comets.dat"));
389 // if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
390 // {
391 // file.write(data);
392 // file.close();
393 // }
394 // else
395 // qCWarning(KSTARS) << "Failed writing comet data to" << file.fileName();
396 
397 // QString focusedComet;
398 
399 //#ifdef KSTARS_LITE
400 // SkyObject *foc = KStarsLite::Instance()->map()->focusObject();
401 // if (foc && foc->type() == SkyObject::COMET)
402 // {
403 // focusedComet = foc->name();
404 // KStarsLite::Instance()->map()->setFocusObject(nullptr);
405 // }
406 //#else
407 // SkyObject *foc = KStars::Instance()->map()->focusObject();
408 // if (foc && foc->type() == SkyObject::COMET)
409 // {
410 // focusedComet = foc->name();
411 // KStars::Instance()->map()->setFocusObject(nullptr);
412 // }
413 //#endif
414 
415 // // Reload comets
416 // loadData();
417 
418 //#ifdef KSTARS_LITE
419 // KStarsLite::Instance()->data()->setFullTimeUpdate();
420 // if (!focusedComet.isEmpty())
421 // KStarsLite::Instance()->map()->setFocusObject(
422 // KStarsLite::Instance()->data()->objectNamed(focusedComet));
423 //#else
424 // if (!focusedComet.isEmpty())
425 // KStars::Instance()->map()->setFocusObject(
426 // KStars::Instance()->data()->objectNamed(focusedComet));
427 // KStars::Instance()->data()->setFullTimeUpdate();
428 //#endif
429 
430 // downloadJob->deleteLater();
431 //}
432 
433 void CometsComponent::downloadError(const QString &errorString)
434 {
435  KSNotification::error(i18n("Error downloading asteroids data: %1", errorString));
436  qCCritical(KSTARS) << errorString;
437  downloadJob->deleteLater();
438 }
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
long double djd() const
static void AddLabel(SkyObject *obj, label_t type)
static version of addLabel() below.
Definition: skylabeler.h:135
KStarsData * data() const
Definition: kstarslite.h:86
void clear()
virtual void setPen(const QPen &pen)=0
Set the pen of the painter.
A subclass of KSPlanetBase that implements comets.
Definition: kscomet.h:43
virtual QString name(void) const
Definition: skyobject.h:145
static KStarsLite * Instance()
Definition: kstarslite.h:77
double rsun() const
Definition: ksplanetbase.h:130
float mag() const
Definition: skyobject.h:206
SkyMap * map() const
Definition: kstars.h:141
void setFullTimeUpdate()
The Sky is updated more frequently than the moon, which is updated more frequently than the planets.
Definition: kstarsdata.cpp:313
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
Definition: skymap.cpp:368
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
SkyMapLite * map() const
Definition: kstarslite.h:80
static KStars * Instance()
Definition: kstars.h:123
int type(void) const
Definition: skyobject.h:188
virtual void emitProgressText(const QString &message)
Emit signal about progress.
bool selected() override
double toDouble(bool *ok) const const
QString i18n(const char *text, const TYPE &arg...)
bool isEmpty() const const
void appendListObject(SkyObject *object)
Add an object to the Object list.
virtual void setBrush(const QBrush &brush)=0
Set the brush of the painter.
int toInt(bool *ok) const const
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition: skymaplite.h:252
Draws things on the sky, without regard to backend.
Definition: skypainter.h:39
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
Definition: skymaplite.cpp:318
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
void setOrbitClass(QString orbit_class)
Sets the comet's orbit class.
Definition: kscomet.cpp:326
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition: skymap.h:262
void setAngularSize(double size)
set the planet's angular size, in km.
Definition: ksplanetbase.h:189
virtual bool drawComet(KSComet *com)=0
Draw a comet in the sky.
void clear()
KStarsData * data() const
Definition: kstars.h:135
Information about an object in the sky.
Definition: skyobject.h:41
void draw(SkyPainter *skyp) override
Draw the object on the SkyMap skyp a pointer to the SkyPainter to use.
CometsComponent(SolarSystemComposite *parent)
Default constructor.
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Sep 22 2023 03:57:53 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.