Kstars

asteroidscomponent.cpp
1 /*
2  SPDX-FileCopyrightText: 2005 Thomas Kabelmann <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "asteroidscomponent.h"
8 #include "ksutils.h"
9 
10 #ifndef KSTARS_LITE
11 #include "kstars.h"
12 #endif
13 #include "ksfilereader.h"
14 #include "kstarsdata.h"
15 #include "kstars_debug.h"
16 #include "Options.h"
17 #include "solarsystemcomposite.h"
18 #include "skycomponent.h"
19 #include "skylabeler.h"
20 #ifndef KSTARS_LITE
21 #include "skymap.h"
22 #else
23 #include "kstarslite.h"
24 #endif
25 #include "skypainter.h"
26 #include "auxiliary/kspaths.h"
27 #include "auxiliary/ksnotification.h"
28 #include "auxiliary/filedownloader.h"
29 #include "projections/projector.h"
30 
31 #include <KLocalizedString>
32 
33 #include <QDebug>
34 #include <QStandardPaths>
35 #include <QHttpMultiPart>
36 #include <QPen>
37 
38 #include <cmath>
39 
41  : BinaryListComponent(this, "asteroids"), SolarSystemListComponent(parent)
42 {
43  loadData();
44 }
45 
47 {
48  return Options::showAsteroids();
49 }
50 
51 /*
52  * @short Initialize the asteroids list.
53  * Reads in the asteroids data from the asteroids.dat file
54  * and writes it into the Binary File;
55  *
56  * The data file is a CSV file with the following columns :
57  * @li 1 full name [string]
58  * @li 2 Modified Julian Day of orbital elements [int]
59  * @li 3 perihelion distance in AU [double]
60  * @li 4 semi-major axis
61  * @li 5 eccentricity of orbit [double]
62  * @li 6 inclination angle of orbit in degrees [double]
63  * @li 7 argument of perihelion in degrees [double]
64  * @li 8 longitude of the ascending node in degrees [double]
65  * @li 9 mean anomaly
66  * @li 10 time of perihelion passage (YYYYMMDD.DDD) [double]
67  * @li 11 orbit solution ID [string]
68  * @li 12 absolute magnitude [float]
69  * @li 13 slope parameter [float]
70  * @li 14 Near-Earth Object (NEO) flag [bool]
71  * @li 15 comet total magnitude parameter [float] (we should remove this column)
72  * @li 16 comet nuclear magnitude parameter [float] (we should remove this column)
73  * @li 17 object diameter (from equivalent sphere) [float]
74  * @li 18 object bi/tri-axial ellipsoid dimensions [string]
75  * @li 19 geometric albedo [float]
76  * @li 20 rotation period [float]
77  * @li 21 orbital period [float]
78  * @li 22 earth minimum orbit intersection distance [double]
79  * @li 23 orbit classification [string]
80  */
81 void AsteroidsComponent::loadDataFromText()
82 {
83  QString name, full_name, orbit_id, orbit_class, dimensions;
84  int mJD;
85  double q, a, e, dble_i, dble_w, dble_N, dble_M, H, G, earth_moid;
86  long double JD;
87  float diameter, albedo, rot_period, period;
88  bool neo;
89 
90  emitProgressText(i18n("Loading asteroids"));
91  qCInfo(KSTARS) << "Loading asteroids";
92 
93  try
94  {
95  KSUtils::JPLParser ast_parser(filepath_txt);
96 
97  ast_parser.for_each(
98  [&](const auto & get)
99  {
100  full_name = get("full_name").toString();
101  full_name = full_name.trimmed();
102  int catN = full_name.section(' ', 0, 0).toInt();
103  name = full_name.section(' ', 1, -1);
104 
105  //JM temporary hack to avoid Europa,Io, and Asterope duplication
106  if (name == i18nc("Asteroid name (optional)", "Europa") ||
107  name == i18nc("Asteroid name (optional)", "Io") ||
108  name == i18nc("Asteroid name (optional)", "Asterope"))
109  name += i18n(" (Asteroid)");
110 
111  mJD = get("epoch_mjd").toString().toInt();
112  q = get("q").toString().toDouble();
113  a = get("a").toString().toDouble();
114  e = get("e").toString().toDouble();
115  dble_i = get("i").toString().toDouble();
116  dble_w = get("w").toString().toDouble();
117  dble_N = get("om").toString().toDouble();
118  dble_M = get("ma").toString().toDouble();
119  orbit_id = get("orbit_id").toString();
120  H = get("H").toString().toDouble();
121  G = get("G").toString().toDouble();
122  neo = get("neo").toString() == "Y";
123  diameter = get("diameter").toString().toFloat();
124  dimensions = get("extent").toString();
125  albedo = get("albedo").toString().toFloat();
126  rot_period = get("rot_per").toString().toFloat();
127  period = get("per_y").toString().toDouble();
128  earth_moid = get("moid").toString().toDouble();
129  orbit_class = get("class").toString();
130 
131  JD = static_cast<double>(mJD) + 2400000.5;
132 
133  KSAsteroid *new_asteroid = nullptr;
134 
135  // Diameter is missing from JPL data
136  if (name == i18nc("Asteroid name (optional)", "Pluto"))
137  diameter = 2390;
138 
139  new_asteroid =
140  new KSAsteroid(catN, name, QString(), JD, a, e, dms(dble_i),
141  dms(dble_w), dms(dble_N), dms(dble_M), H, G);
142 
143  new_asteroid->setPerihelion(q);
144  new_asteroid->setOrbitID(orbit_id);
145  new_asteroid->setNEO(neo);
146  new_asteroid->setDiameter(diameter);
147  new_asteroid->setDimensions(dimensions);
148  new_asteroid->setAlbedo(albedo);
149  new_asteroid->setRotationPeriod(rot_period);
150  new_asteroid->setPeriod(period);
151  new_asteroid->setEarthMOID(earth_moid);
152  new_asteroid->setOrbitClass(orbit_class);
153  new_asteroid->setPhysicalSize(diameter);
154  //new_asteroid->setAngularSize(0.005);
155 
156  appendListObject(new_asteroid);
157 
158  // Add name to the list of object names
159  objectNames(SkyObject::ASTEROID).append(name);
160  objectLists(SkyObject::ASTEROID)
161  .append(QPair<QString, const SkyObject *>(name, new_asteroid));
162  });
163  }
164  catch (const std::runtime_error &e)
165  {
166  qCInfo(KSTARS) << "Loading asteroid objects failed.";
167  qCInfo(KSTARS) << " -> was trying to read " + filepath_txt;
168  return;
169  }
170 }
171 
173 {
174  Q_UNUSED(skyp)
175 #ifndef KSTARS_LITE
176  if (!selected())
177  return;
178 
179  bool hideLabels = !Options::showAsteroidNames() || (SkyMap::Instance()->isSlewing() && Options::hideLabels());
180 
181  double showLimit = Options::magLimitAsteroid();
182  double lgmin = log10(MINZOOM);
183  double lgmax = log10(MAXZOOM);
184  double lgz = log10(Options::zoomFactor());
185  double labelMagLimit = 2.5 + Options::asteroidLabelDensity() / 5.0;
186  labelMagLimit += (15.0 - labelMagLimit) * (lgz - lgmin) / (lgmax - lgmin);
187  if (labelMagLimit > 10.0)
188  labelMagLimit = 10.0;
189  //printf("labelMagLim = %.1f\n", labelMagLimit );
190 
191  skyp->setBrush(QBrush(QColor("gray")));
192 
193  foreach (SkyObject *so, m_ObjectList)
194  {
195  KSAsteroid *ast = dynamic_cast<KSAsteroid *>(so);
196 
197  if (!ast->toDraw() || std::isnan(ast->mag()) || ast->mag() > showLimit)
198  continue;
199 
200  bool drawn = false;
201 
202  if (ast->image().isNull() == false)
203  drawn = skyp->drawPlanet(ast);
204  else
205  drawn = skyp->drawPointSource(ast, ast->mag());
206 
207  if (drawn && !(hideLabels || ast->mag() >= labelMagLimit))
208  SkyLabeler::AddLabel(ast, SkyLabeler::ASTEROID_LABEL);
209  }
210 #endif
211 }
212 
214 {
215  SkyObject *oBest = nullptr;
216 
217  if (!selected())
218  return nullptr;
219 
220  for (auto o : m_ObjectList)
221  {
222  if (!((dynamic_cast<KSAsteroid*>(o)->toDraw())))
223  continue;
224 
225  double r = o->angularDistanceTo(p).Degrees();
226  if (r < maxrad)
227  {
228  oBest = o;
229  maxrad = r;
230  }
231  }
232 
233  return oBest;
234 }
235 
236 void AsteroidsComponent::updateDataFile(bool isAutoUpdate)
237 {
238  delete (downloadJob);
239  downloadJob = new FileDownloader();
240 
241  if (isAutoUpdate == false)
242  downloadJob->setProgressDialogEnabled(true, i18n("Asteroid Update"),
243  i18n("Downloading asteroids updates..."));
244  downloadJob->registerDataVerification([&](const QByteArray & data)
245  {
246  return data.startsWith("{\"signature\"");
247  });
248 
249  QObject::connect(downloadJob, SIGNAL(downloaded()), this, SLOT(downloadReady()));
250  if (isAutoUpdate == false)
251  QObject::connect(downloadJob, SIGNAL(error(QString)), this,
252  SLOT(downloadError(QString)));
253 
254  QUrl url = QUrl("https://ssd-api.jpl.nasa.gov/sbdb_query.api");
255 
256  QByteArray mag = QString::number(Options::magLimitAsteroidDownload()).toUtf8();
257  QByteArray post_data =
258  KSUtils::getJPLQueryString("a",
259  "full_name,neo,H,G,diameter,extent,albedo,rot_per,"
260  "orbit_id,epoch_mjd,e,a,q,i,om,w,ma,per_y,moid,class",
261  QVector<KSUtils::JPLFilter> { { "H", "LT", mag } });
262  downloadJob->post(url, post_data);
263 }
264 
265 void AsteroidsComponent::downloadReady()
266 {
267  // Comment the first line
268  QByteArray data = downloadJob->downloadedData();
269 
270  // Write data to asteroids.dat
271  QFile file(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
272  .filePath("asteroids.dat"));
274  {
275  file.write(data);
276  file.close();
277  }
278  else
279  qCWarning(KSTARS) << "Failed writing asteroid data to" << file.fileName();
280 
281  QString focusedAstroid;
282 
283 #ifdef KSTARS_LITE
285  if (foc && foc->type() == SkyObject::ASTEROID)
286  {
287  focusedAstroid = foc->name();
288  KStarsLite::Instance()->map()->setFocusObject(nullptr);
289  }
290 #else
291  SkyObject *foc = KStars::Instance()->map()->focusObject();
292  if (foc && foc->type() == SkyObject::ASTEROID)
293  {
294  focusedAstroid = foc->name();
295  KStars::Instance()->map()->setFocusObject(nullptr);
296  }
297 
298 #endif
299  // Reload asteroids
300  loadData(true);
301 
302 #ifdef KSTARS_LITE
304  if (!focusedAstroid.isEmpty())
306  KStarsLite::Instance()->data()->objectNamed(focusedAstroid));
307 #else
308  if (!focusedAstroid.isEmpty())
310  KStars::Instance()->data()->objectNamed(focusedAstroid));
312 #endif
313  downloadJob->deleteLater();
314 }
315 
316 void AsteroidsComponent::downloadError(const QString &errorString)
317 {
318  KSNotification::error(i18n("Error downloading asteroids data: %1", errorString));
319  qDebug() << Q_FUNC_INFO << i18n("Error downloading asteroids data: %1", errorString);
320  downloadJob->deleteLater();
321 }
QString section(QChar sep, int start, int end, QString::SectionFlags flags) const const
void setOrbitID(QString orbit_id)
Sets the asteroid's orbit solution ID.
Definition: ksasteroid.cpp:195
QString number(int n, int base)
void setDimensions(QString dim)
Sets the asteroid's dimensions.
Definition: ksasteroid.cpp:180
void setOrbitClass(QString orbit_class)
Sets the asteroid's orbit class.
Definition: ksasteroid.cpp:190
static void AddLabel(SkyObject *obj, label_t type)
static version of addLabel() below.
Definition: skylabeler.h:135
provides functionality for loading the component data from Binary
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
KStarsData * data() const
Definition: kstarslite.h:86
QString trimmed() const const
void setAlbedo(float albedo)
Sets the asteroid's albedo.
Definition: ksasteroid.cpp:170
A subclass of KSPlanetBase that implements asteroids.
Definition: ksasteroid.h:41
virtual QString name(void) const
Definition: skyobject.h:145
static KStarsLite * Instance()
Definition: kstarslite.h:77
void draw(SkyPainter *skyp) override
Draw the object on the SkyMap skyp a pointer to the SkyPainter to use.
float mag() const
Definition: skyobject.h:206
SkyMap * map() const
Definition: kstars.h:143
void setFullTimeUpdate()
The Sky is updated more frequently than the moon, which is updated more frequently than the planets.
Definition: kstarsdata.cpp:313
void setEarthMOID(double earth_moid)
Sets the asteroid's earth minimum orbit intersection distance.
Definition: ksasteroid.cpp:165
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
Definition: skymap.cpp:336
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setDiameter(float diam)
Sets the asteroid's diameter.
Definition: ksasteroid.cpp:175
SkyMapLite * map() const
Definition: kstarslite.h:80
static KStars * Instance()
Definition: kstars.h:125
int type(void) const
Definition: skyobject.h:188
virtual void emitProgressText(const QString &message)
Emit signal about progress.
SkyObject * objectNearest(SkyPoint *p, double &maxrad) override
Find the SkyObject nearest the given SkyPoint.
QString i18n(const char *text, const TYPE &arg...)
const QImage & image() const
Definition: ksplanetbase.h:127
bool isEmpty() const const
void appendListObject(SkyObject *object)
Add an object to the Object list.
virtual bool drawPointSource(const SkyPoint *loc, float mag, char sp='A')=0
Draw a point source (e.g., a star).
QByteArray toUtf8() const const
bool isNull() const const
virtual void setBrush(const QBrush &brush)=0
Set the brush of the painter.
bool startsWith(const QByteArray &ba) const const
int toInt(bool *ok, int base) const const
bool selected() override
float toFloat(bool *ok) const const
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition: skymaplite.h:252
void setNEO(bool neo)
Sets if the comet is a near earth object.
Definition: ksasteroid.cpp:185
Draws things on the sky, without regard to backend.
Definition: skypainter.h:37
void setRotationPeriod(float rot_per)
Sets the asteroid's rotation period.
Definition: ksasteroid.cpp:263
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
Definition: skypoint.cpp:899
double toDouble(bool *ok) const const
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
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
bool toDraw()
toDraw
Definition: ksasteroid.h:188
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition: skymap.h:261
const double & Degrees() const
Definition: dms.h:141
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setPerihelion(double perihelion)
Sets the asteroid's perihelion distance.
Definition: ksasteroid.cpp:160
KStarsData * data() const
Definition: kstars.h:137
void setPhysicalSize(double size)
set the planet's physical size, in km.
Definition: ksplanetbase.h:197
Information about an object in the sky.
Definition: skyobject.h:41
AsteroidsComponent(SolarSystemComposite *parent)
Default constructor.
virtual bool drawPlanet(KSPlanetBase *planet)=0
Draw a planet.
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
QString toString() const const
void setPeriod(float per)
Sets the asteroid's period.
Definition: ksasteroid.cpp:200
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Aug 11 2022 03:59:56 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.