Kstars

asteroidscomponent.cpp
1/*
2 SPDX-FileCopyrightText: 2005 Thomas Kabelmann <thomas.kabelmann@gmx.de>
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
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 */
81void AsteroidsComponent::loadDataFromText()
82{
83 clear();
84 objectNames(SkyObject::ASTEROID).clear();
85 objectLists(SkyObject::ASTEROID).clear();
86
87 QString name, full_name, orbit_id, orbit_class, dimensions;
88 int mJD;
89 double q, a, e, dble_i, dble_w, dble_N, dble_M, H, G, earth_moid;
90 long double JD;
91 float diameter, albedo, rot_period, period;
92 bool neo;
93
94 emitProgressText(i18n("Loading asteroids"));
95 qCInfo(KSTARS) << "Loading asteroids";
96
97 try
98 {
99 KSUtils::JPLParser ast_parser(filepath_txt);
100 auto fieldMap = ast_parser.fieldMap();
101 bool isString = fieldMap.count("epoch_mjd") == 1;
102
103 ast_parser.for_each(
104 [&](const auto & get)
105 {
106 full_name = get("full_name").toString();
107 full_name = full_name.trimmed();
108 int catN = full_name.section(' ', 0, 0).toInt();
109 name = full_name.section(' ', 1, -1);
110
111 //JM temporary hack to avoid Europa,Io, and Asterope duplication
112 if (name == i18nc("Asteroid name (optional)", "Europa") ||
113 name == i18nc("Asteroid name (optional)", "Io") ||
114 name == i18nc("Asteroid name (optional)", "Asterope"))
115 name += i18n(" (Asteroid)");
116
117 // JM 2022.08.26: Try to check if the file is in the new format
118 // where epoch_mjd field is a string
119 if (isString)
120 {
121 mJD = get("epoch_mjd").toString().toInt();
122 period = get("per_y").toString().toDouble();
123 }
124 // If not fall back to old behavior
125 else
126 {
127 mJD = get("epoch.mjd").toInt();
128 period = get("per.y").toDouble();
129 }
130
131 q = get("q").toString().toDouble();
132 a = get("a").toString().toDouble();
133 e = get("e").toString().toDouble();
134 dble_i = get("i").toString().toDouble();
135 dble_w = get("w").toString().toDouble();
136 dble_N = get("om").toString().toDouble();
137 dble_M = get("ma").toString().toDouble();
138 orbit_id = get("orbit_id").toString();
139 H = get("H").toString().toDouble();
140 G = get("G").toString().toDouble();
141 neo = get("neo").toString() == "Y";
142 diameter = get("diameter").toString().toFloat();
143 dimensions = get("extent").toString();
144 albedo = get("albedo").toString().toFloat();
145 rot_period = get("rot_per").toString().toFloat();
146 earth_moid = get("moid").toString().toDouble();
147 orbit_class = get("class").toString();
148
149 JD = static_cast<double>(mJD) + 2400000.5;
150
151 KSAsteroid *new_asteroid = nullptr;
152
153 // Diameter is missing from JPL data
154 if (name == i18nc("Asteroid name (optional)", "Pluto"))
155 diameter = 2390;
156
157 new_asteroid =
158 new KSAsteroid(catN, name, QString(), JD, a, e, dms(dble_i),
159 dms(dble_w), dms(dble_N), dms(dble_M), H, G);
160
161 new_asteroid->setPerihelion(q);
162 new_asteroid->setOrbitID(orbit_id);
163 new_asteroid->setNEO(neo);
164 new_asteroid->setDiameter(diameter);
165 new_asteroid->setDimensions(dimensions);
166 new_asteroid->setAlbedo(albedo);
167 new_asteroid->setRotationPeriod(rot_period);
168 new_asteroid->setPeriod(period);
169 new_asteroid->setEarthMOID(earth_moid);
170 new_asteroid->setOrbitClass(orbit_class);
171 new_asteroid->setPhysicalSize(diameter);
172 //new_asteroid->setAngularSize(0.005);
173
174 appendListObject(new_asteroid);
175
176 // Add name to the list of object names
177 objectNames(SkyObject::ASTEROID).append(name);
178 objectLists(SkyObject::ASTEROID)
179 .append(QPair<QString, const SkyObject *>(name, new_asteroid));
180 });
181 }
182 catch (const std::runtime_error &e)
183 {
184 qCInfo(KSTARS) << "Loading asteroid objects failed.";
185 qCInfo(KSTARS) << " -> was trying to read " + filepath_txt;
186 return;
187 }
188}
189
191{
192 Q_UNUSED(skyp)
193#ifndef KSTARS_LITE
194 if (!selected())
195 return;
196
197 bool hideLabels = !Options::showAsteroidNames() || (SkyMap::Instance()->isSlewing() && Options::hideLabels());
198
199 double labelMagLimit = Options::asteroidLabelDensity(); // Slider min value 0, max value 20.
200 const double showMagLimit = Options::magLimitAsteroid();
201 const double lgmin = log10(MINZOOM);
202 const double lgmax = log10(MAXZOOM);
203 const double lgz = log10(Options::zoomFactor());
204 const double densityLabelFactor = 10.0; // Value of 10.0 influences the slider mag value [0, 2],
205 // where a value 5.0 influences the slider mag value [0, 4].
206 const double zoomLimit = (lgz - lgmin) / (lgmax - lgmin); // Min-max normalize into [lgmin, lgmax].
207
208 // Map labelMagLimit into interval [0, 20.0 / densityLabelFactor]
209 labelMagLimit = std::max(1e-3, labelMagLimit) / densityLabelFactor;
210 // If zooming closer, then the labelMagLimit gets closer to showMagLimit value.
211 // If sliding density value to the right, then the labelMagLimit gets closer to showMagLimit value.
212 // It is however assured that labelMagLimit <= showMagLimit.
213 labelMagLimit = showMagLimit - 20.0 / densityLabelFactor + std::max(zoomLimit, labelMagLimit);
214
215 foreach (SkyObject *so, m_ObjectList)
216 {
217 KSAsteroid *ast = dynamic_cast<KSAsteroid *>(so);
218
219 if (!ast->toDraw() || std::isnan(ast->mag()) || ast->mag() > showMagLimit)
220 continue;
221
222 bool drawn = false;
223
224 if (ast->image().isNull() == false)
225 drawn = skyp->drawPlanet(ast);
226 else
227 drawn = skyp->drawAsteroid(ast);
228
229 if (drawn && !hideLabels && ast->mag() <= labelMagLimit)
230 SkyLabeler::AddLabel(ast, SkyLabeler::ASTEROID_LABEL);
231 }
232#endif
233}
234
235SkyObject *AsteroidsComponent::objectNearest(SkyPoint *p, double &maxrad)
236{
237 SkyObject *oBest = nullptr;
238
239 if (!selected())
240 return nullptr;
241
242 for (auto o : m_ObjectList)
243 {
244 if (!((dynamic_cast<KSAsteroid*>(o)->toDraw())))
245 continue;
246
247 double r = o->angularDistanceTo(p).Degrees();
248 if (r < maxrad)
249 {
250 oBest = o;
251 maxrad = r;
252 }
253 }
254
255 return oBest;
256}
257
258void AsteroidsComponent::updateDataFile(bool isAutoUpdate)
259{
260 delete (downloadJob);
261 downloadJob = new FileDownloader();
262
263 if (isAutoUpdate == false)
264 downloadJob->setProgressDialogEnabled(true, i18n("Asteroid Update"),
265 i18n("Downloading asteroids updates..."));
266 downloadJob->registerDataVerification([&](const QByteArray & data)
267 {
268 return data.startsWith("{\"signature\"");
269 });
270
271 QObject::connect(downloadJob, SIGNAL(downloaded()), this, SLOT(downloadReady()));
272 if (isAutoUpdate == false)
273 QObject::connect(downloadJob, SIGNAL(error(QString)), this,
274 SLOT(downloadError(QString)));
275
276 QUrl url = QUrl("https://ssd-api.jpl.nasa.gov/sbdb_query.api");
277
278 QByteArray mag = QString::number(Options::magLimitAsteroidDownload()).toUtf8();
279 QByteArray post_data =
280 KSUtils::getJPLQueryString("a",
281 "full_name,neo,H,G,diameter,extent,albedo,rot_per,"
282 "orbit_id,epoch_mjd,e,a,q,i,om,w,ma,per_y,moid,class",
283 QVector<KSUtils::JPLFilter> { { "H", "LT", mag } });
284 downloadJob->post(url, post_data);
285}
286
287void AsteroidsComponent::downloadReady()
288{
289 // Comment the first line
290 QByteArray data = downloadJob->downloadedData();
291
292 // Write data to asteroids.dat
293 QFile file(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
294 .filePath("asteroids.dat"));
296 {
297 file.write(data);
298 file.close();
299 }
300 else
301 qCWarning(KSTARS) << "Failed writing asteroid data to" << file.fileName();
302
303 QString focusedAstroid;
304
305#ifdef KSTARS_LITE
307 if (foc && foc->type() == SkyObject::ASTEROID)
308 {
309 focusedAstroid = foc->name();
311 }
312#else
314 if (foc && foc->type() == SkyObject::ASTEROID)
315 {
316 focusedAstroid = foc->name();
317 KStars::Instance()->map()->setFocusObject(nullptr);
318 }
319
320#endif
321 // Reload asteroids
322 loadData(true);
323
324#ifdef KSTARS_LITE
326 if (!focusedAstroid.isEmpty())
328 KStarsLite::Instance()->data()->objectNamed(focusedAstroid));
329#else
330 if (!focusedAstroid.isEmpty())
332 KStars::Instance()->data()->objectNamed(focusedAstroid));
334#endif
335 downloadJob->deleteLater();
336}
337
338void AsteroidsComponent::downloadError(const QString &errorString)
339{
340 KSNotification::error(i18n("Error downloading asteroids data: %1", errorString));
341 qDebug() << Q_FUNC_INFO << i18n("Error downloading asteroids data: %1", errorString);
342 downloadJob->deleteLater();
343}
AsteroidsComponent(SolarSystemComposite *parent)
Default constructor.
void draw(SkyPainter *skyp) override
Draw the object on the SkyMap skyp a pointer to the SkyPainter to use.
SkyObject * objectNearest(SkyPoint *p, double &maxrad) override
Find the SkyObject nearest the given SkyPoint.
provides functionality for loading the component data from Binary
A subclass of KSPlanetBase that implements asteroids.
Definition ksasteroid.h:42
void setPerihelion(double perihelion)
Sets the asteroid's perihelion distance.
bool toDraw()
toDraw
Definition ksasteroid.h:188
void setPeriod(float per)
Sets the asteroid's period.
void setDiameter(float diam)
Sets the asteroid's diameter.
void setDimensions(QString dim)
Sets the asteroid's dimensions.
void setEarthMOID(double earth_moid)
Sets the asteroid's earth minimum orbit intersection distance.
void setNEO(bool neo)
Sets if the comet is a near earth object.
void setOrbitID(QString orbit_id)
Sets the asteroid's orbit solution ID.
void setAlbedo(float albedo)
Sets the asteroid's albedo.
void setRotationPeriod(float rot_per)
Sets the asteroid's rotation period.
void setOrbitClass(QString orbit_class)
Sets the asteroid's orbit class.
void setPhysicalSize(double size)
set the planet's physical size, in km.
const QImage & image() const
void setFullTimeUpdate()
The Sky is updated more frequently than the moon, which is updated more frequently than the planets.
SkyMapLite * map() const
Definition kstarslite.h:80
static KStarsLite * Instance()
Definition kstarslite.h:77
KStarsData * data() const
Definition kstarslite.h:86
SkyMap * map() const
Definition kstars.h:139
static KStars * Instance()
Definition kstars.h:121
KStarsData * data() const
Definition kstars.h:133
void appendListObject(SkyObject *object)
Add an object to the Object list.
virtual void emitProgressText(const QString &message)
Emit signal about progress.
static void AddLabel(SkyObject *obj, label_t type)
static version of addLabel() below.
Definition skylabeler.h:135
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition skymaplite.h:252
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
Definition skymap.cpp:371
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition skymap.h:262
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual QString name(void) const
Definition skyobject.h:146
int type(void) const
Definition skyobject.h:189
float mag() const
Definition skyobject.h:207
Draws things on the sky, without regard to backend.
Definition skypainter.h:40
virtual bool drawPlanet(KSPlanetBase *planet)=0
Draw a planet.
virtual bool drawAsteroid(KSAsteroid *ast)=0
Draw an asteroid in the sky.
The solar system composite manages all planets, asteroids and comets.
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
bool startsWith(QByteArrayView bv) const const
void clear()
bool isNull() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool isEmpty() const const
QString number(double n, char format, int precision)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
int toInt(bool *ok, int base) const const
QByteArray toUtf8() const const
QString trimmed() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.