Kstars

skyobject.cpp
1 /*
2  SPDX-FileCopyrightText: 2001 Jason Harris <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "skyobject.h"
8 
9 #include "geolocation.h"
10 #include "ksnumbers.h"
11 #include "kspaths.h"
12 #ifdef KSTARS_LITE
13 #include "skymaplite.h"
14 #else
15 #include "kspopupmenu.h"
16 #include "skymap.h"
17 #endif
18 #include "kstarsdata.h"
19 #include "Options.h"
20 #include "starobject.h"
21 #include "skycomponents/skylabeler.h"
22 
23 
26 const SkyObject::UID SkyObject::UID_GALAXY = 1;
27 const SkyObject::UID SkyObject::UID_DEEPSKY = 2;
28 const SkyObject::UID SkyObject::UID_SOLARSYS = 3;
29 
30 SkyObject::SkyObject(int t, dms r, dms d, float m, const QString &n, const QString &n2, const QString &lname)
31  : SkyPoint(r, d)
32 {
33  setType(t);
34  sortMagnitude = m;
35  setName(n);
36  setName2(n2);
37  setLongName(lname);
38 }
39 
40 SkyObject::SkyObject(int t, double r, double d, float m, const QString &n, const QString &n2, const QString &lname)
41  : SkyPoint(r, d)
42 {
43  setType(t);
44  sortMagnitude = m;
45  setName(n);
46  setName2(n2);
47  setLongName(lname);
48 }
49 
51 {
52  Q_ASSERT(typeid(this) == typeid(static_cast<const SkyObject *>(this))); // Ensure we are not slicing a derived class
53  return new SkyObject(*this);
54 }
55 
57 {
58 #if defined(KSTARS_LITE)
59  Q_UNUSED(pos)
60  Q_UNUSED(pmenu);
61 #else
62  initPopupMenu(pmenu);
63  pmenu->popup(pos);
64 #endif
65 }
66 
68 {
69 #ifdef KSTARS_LITE
70  Q_UNUSED(pmenu)
71 #else
72  pmenu->createEmptyMenu(this);
73 #endif
74 }
75 
76 void SkyObject::setLongName(const QString &longname)
77 {
78  if (longname.isEmpty())
79  {
80  if (hasName())
81  LongName = name();
82  else if (hasName2())
83  LongName = name2();
84  else
85  LongName.clear();
86  }
87  else
88  {
89  LongName = longname;
90  }
91 }
92 
93 QTime SkyObject::riseSetTime(const KStarsDateTime &dt, const GeoLocation *geo, bool rst, bool exact) const
94 {
95  // If this object does not rise or set, return an invalid time
96  SkyPoint p = recomputeCoords(dt, geo);
97  if (p.checkCircumpolar(geo->lat()))
98  return QTime();
99 
100  //First of all, if the object is below the horizon at date/time dt, adjust the time
101  //to bring it above the horizon
102  KStarsDateTime dt2 = dt;
103  dms lst(geo->GSTtoLST(dt.gst()));
104  p.EquatorialToHorizontal(&lst, geo->lat());
105  if (p.alt().Degrees() < 0.0)
106  {
107  if (p.az().Degrees() < 180.0) //object has not risen yet
108  {
109  dt2 = dt.addSecs(12. * 3600.); // Move forward 12 hours, to a time when it has already risen
110  }
111  else //object has already set
112  {
113  dt2 = dt.addSecs(-12. * 3600.); // Move backward 12 hours, to a time when it has not yet set
114  }
115  }
116  // The addition / subtraction of 12 hours ensures that we always
117  // compute the _closest_ rise time and the _closest_ set time to
118  // the current time.
119 
120  QTime rstUt = riseSetTimeUT(dt2, geo, rst, exact);
121  if (!rstUt.isValid())
122  return QTime();
123 
124  return geo->UTtoLT(KStarsDateTime(dt2.date(), rstUt)).time();
125 }
126 
127 QTime SkyObject::riseSetTimeUT(const KStarsDateTime &dt, const GeoLocation *geo, bool riseT, bool exact) const
128 {
129  // First trial to calculate UT
130  QTime UT = auxRiseSetTimeUT(dt, geo, &ra(), &dec(), riseT);
131 
132  // We iterate once more using the calculated UT to compute again
133  // the ra and dec for that time and hence the rise/set time.
134  // Also, adjust the date by +/- 1 day, if necessary
135 
136  // By adding this +/- 1 day, we are double-checking that the
137  // reported rise-time is the _already_ (last) risen time, and that
138  // the reported set-time is the _future_ (next) set time
139  //
140  // However, issues with this are taken care of in
141  // SkyObject::riseSetTime()
142 
143  KStarsDateTime dt0 = dt;
144  dt0.setTime(UT);
145  if (riseT && dt0 > dt)
146  {
147  dt0 = dt0.addDays(-1);
148  }
149  else if (!riseT && dt0 < dt)
150  {
151  dt0 = dt0.addDays(1);
152  }
153 
154  SkyPoint sp = recomputeCoords(dt0, geo);
155  UT = auxRiseSetTimeUT(dt0, geo, &sp.ra(), &sp.dec(), riseT);
156 
157  if (exact)
158  {
159  // We iterate a second time (For the Moon the second iteration changes
160  // aprox. 1.5 arcmin the coordinates).
161  dt0.setTime(UT);
162  sp = recomputeCoords(dt0, geo);
163  UT = auxRiseSetTimeUT(dt0, geo, &sp.ra(), &sp.dec(), riseT);
164  }
165 
166  return UT;
167 }
168 
169 QTime SkyObject::auxRiseSetTimeUT(const KStarsDateTime &dt, const GeoLocation *geo, const dms *righta, const dms *decl,
170  bool riseT) const
171 {
172  dms LST = auxRiseSetTimeLST(geo->lat(), righta, decl, riseT);
173  return dt.GSTtoUT(geo->LSTtoGST(LST));
174 }
175 
176 dms SkyObject::auxRiseSetTimeLST(const dms *gLat, const dms *righta, const dms *decl, bool riseT) const
177 {
178  dms h0 = elevationCorrection();
179  double H = approxHourAngle(&h0, gLat, decl);
180  dms LST;
181 
182  if (riseT)
183  LST.setH(24.0 + righta->Hours() - H / 15.0);
184  else
185  LST.setH(righta->Hours() + H / 15.0);
186 
187  return LST.reduce();
188 }
189 
190 dms SkyObject::riseSetTimeAz(const KStarsDateTime &dt, const GeoLocation *geo, bool riseT) const
191 {
192  dms Azimuth;
193  double AltRad, AzRad;
194  double sindec, cosdec, sinlat, coslat, sinHA, cosHA;
195  double sinAlt, cosAlt;
196 
197  QTime UT = riseSetTimeUT(dt, geo, riseT);
198  KStarsDateTime dt0 = dt;
199  dt0.setTime(UT);
200  SkyPoint sp = recomputeCoords(dt0, geo);
201 
202  dms LST = auxRiseSetTimeLST(geo->lat(), &sp.ra0(), &sp.dec0(), riseT);
203  dms HourAngle = dms(LST.Degrees() - sp.ra0().Degrees());
204 
205  geo->lat()->SinCos(sinlat, coslat);
206  dec().SinCos(sindec, cosdec);
207  HourAngle.SinCos(sinHA, cosHA);
208 
209  sinAlt = sindec * sinlat + cosdec * coslat * cosHA;
210  AltRad = asin(sinAlt);
211  cosAlt = cos(AltRad);
212 
213  AzRad = acos((sindec - sinlat * sinAlt) / (coslat * cosAlt));
214  if (sinHA > 0.0)
215  AzRad = 2.0 * dms::PI - AzRad; // resolve acos() ambiguity
216  Azimuth.setRadians(AzRad);
217 
218  return Azimuth;
219 }
220 
222 {
223  dms LST = geo->GSTtoLST(dt.gst());
224 
225  //dSec is the number of seconds until the object transits.
226  dms HourAngle = dms(LST.Degrees() - ra().Degrees());
227  int dSec = static_cast<int>(-3600. * HourAngle.Degrees() / 15.0);
228 
229  //dt0 is the first guess at the transit time.
230  KStarsDateTime dt0 = dt.addSecs(dSec);
231  //recompute object's position at UT0 and then find transit time of this refined position
232  SkyPoint sp = recomputeCoords(dt0, geo);
233  HourAngle = dms(LST.Degrees() - sp.ra().Degrees());
234  dSec = static_cast<int>(-3600. * HourAngle.Degrees() / 15.0);
235 
236  return dt.addSecs(dSec).time();
237 }
238 
240 {
241  return geo->UTtoLT(KStarsDateTime(dt.date(), transitTimeUT(dt, geo))).time();
242 }
243 
245 {
246  KStarsDateTime dt0 = dt;
247  dt0.setTime(transitTimeUT(dt, geo));
248  SkyPoint sp = recomputeCoords(dt0, geo);
249 
250  double delta = 90 - geo->lat()->Degrees() + sp.dec().Degrees();
251  if (delta > 90)
252  delta = 180 - delta;
253  return dms(delta);
254 }
255 
256 double SkyObject::approxHourAngle(const dms *h0, const dms *gLat, const dms *dec) const
257 {
258  double sh0 = sin(h0->radians());
259  double r = (sh0 - sin(gLat->radians()) * sin(dec->radians())) / (cos(gLat->radians()) * cos(dec->radians()));
260 
261  double H = acos(r) / dms::DegToRad;
262 
263  return H;
264 }
265 
266 dms SkyObject::elevationCorrection(void) const
267 {
268  /* The atmospheric refraction at the horizon shifts altitude by
269  * - 34 arcmin = 0.5667 degrees. This value changes if the observer
270  * is above the horizon, or if the weather conditions change much.
271  *
272  * For the sun we have to add half the angular sie of the body, since
273  * the sunset is the time the upper limb of the sun disappears below
274  * the horizon, and dawn, when the upper part of the limb appears
275  * over the horizon. The angular size of the sun = angular size of the
276  * moon = 31' 59''.
277  *
278  * So for the sun the correction is = -34 - 16 = 50 arcmin = -0.8333
279  *
280  * This same correction should be applied to the moon however parallax
281  * is important here. Meeus states that the correction should be
282  * 0.7275 P - 34 arcmin, where P is the moon's horizontal parallax.
283  * He proposes a mean value of 0.125 degrees if no great accuracy
284  * is needed.
285  */
286 
287  if (name() == i18n("Sun") || name() == i18n("Moon") || name() == i18n("Earth Shadow"))
288  return dms(-0.8333);
289  // else if ( name() == "Moon" )
290  // return dms(0.125);
291  else // All sources point-like.
292  return dms(-0.5667);
293 }
294 
296 {
297  // Create a clone
298  SkyObject *c = this->clone();
299 
300  // compute coords of the copy for new time jd
301  KSNumbers num(dt.djd());
302 
303  // Note: isSolarSystem() below should give the same result on this
304  // and c. The only very minor reason to prefer this is so that we
305  // have an additional layer of warnings about subclasses of
306  // KSPlanetBase that do not implement SkyObject::clone() due to
307  // the passing of lat and LST
308 
309  if (isSolarSystem() && geo)
310  {
311  CachingDms LST = geo->GSTtoLST(dt.gst());
312  c->updateCoords(&num, true, geo->lat(), &LST);
313  }
314  else
315  {
316  c->updateCoords(&num);
317  }
318 
319  // Transfer the coordinates into a SkyPoint
320  SkyPoint p = *c;
321 
322  // Delete the clone
323  delete c;
324 
325  // Return the SkyPoint
326  return p;
327 }
328 
330 {
331  Q_ASSERT(geo);
332  SkyPoint ret = recomputeCoords(dt, geo);
333  CachingDms LST = geo->GSTtoLST(dt.gst());
334  ret.EquatorialToHorizontal(&LST, geo->lat());
335  return ret;
336 }
337 
339 {
340  switch (t)
341  {
342  case STAR:
343  return i18n("Star");
344  case CATALOG_STAR:
345  return i18n("Catalog Star");
346  case PLANET:
347  return i18n("Planet");
348  case OPEN_CLUSTER:
349  return i18n("Open Cluster");
350  case GLOBULAR_CLUSTER:
351  return i18n("Globular Cluster");
352  case GASEOUS_NEBULA:
353  return i18n("Gaseous Nebula");
354  case PLANETARY_NEBULA:
355  return i18n("Planetary Nebula");
356  case SUPERNOVA_REMNANT:
357  return i18n("Supernova Remnant");
358  case GALAXY:
359  return i18n("Galaxy");
360  case COMET:
361  return i18n("Comet");
362  case ASTEROID:
363  return i18n("Asteroid");
364  case CONSTELLATION:
365  return i18n("Constellation");
366  case MOON:
367  return i18n("Moon");
368  case GALAXY_CLUSTER:
369  return i18n("Galaxy Cluster");
370  case SATELLITE:
371  return i18n("Satellite");
372  case SUPERNOVA:
373  return i18n("Supernova");
374  case RADIO_SOURCE:
375  return i18n("Radio Source");
376  case ASTERISM:
377  return i18n("Asterism");
378  case DARK_NEBULA:
379  return i18n("Dark Nebula");
380  case QUASAR:
381  return i18n("Quasar");
382  case MULT_STAR:
383  return i18n("Multiple Star");
384  default:
385  return i18n("Unknown Type");
386  }
387 }
388 
390 {
391  return typeName(Type);
392 }
393 
395 {
396  QString message = imageTitle;
397 
398  //HST Image
399  if (imageTitle == i18n("Show HST Image") || imageTitle.contains("HST"))
400  {
401  message = i18n("%1: Hubble Space Telescope, operated by STScI for NASA [public domain]", longname());
402 
403  //Spitzer Image
404  }
405  else if (imageTitle.contains(i18n("Show Spitzer Image")))
406  {
407  message = i18n("%1: Spitzer Space Telescope, courtesy NASA/JPL-Caltech [public domain]", longname());
408 
409  //SEDS Image
410  }
411  else if (imageTitle == i18n("Show SEDS Image"))
412  {
413  message = i18n("%1: SEDS, http://www.seds.org [free for non-commercial use]", longname());
414 
415  //Kitt Peak AOP Image
416  }
417  else if (imageTitle == i18n("Show KPNO AOP Image"))
418  {
419  message = i18n("%1: Advanced Observing Program at Kitt Peak National Observatory [free for non-commercial use; "
420  "no physical reproductions]",
421  longname());
422 
423  //NOAO Image
424  }
425  else if (imageTitle.contains(i18n("Show NOAO Image")))
426  {
427  message =
428  i18n("%1: National Optical Astronomy Observatories and AURA [free for non-commercial use]", longname());
429 
430  //VLT Image
431  }
432  else if (imageTitle.contains("VLT"))
433  {
434  message = i18n("%1: Very Large Telescope, operated by the European Southern Observatory [free for "
435  "non-commercial use; no reproductions]",
436  longname());
437 
438  //All others
439  }
440  else if (imageTitle.startsWith(i18n("Show")))
441  {
442  message = imageTitle.mid(imageTitle.indexOf(" ") + 1); //eat first word, "Show"
443  message = longname() + ": " + message;
444  }
445 
446  return message;
447 }
448 
450 {
451  return translatedName();
452 }
453 
455 {
456  return SkyLabeler::ZoomOffset();
457 }
458 
460 {
461  return invalidUID;
462 }
const dms & alt() const
Definition: skypoint.h:281
SkyObject(int t=TYPE_UNKNOWN, dms r=dms(0.0), dms d=dms(0.0), float m=0.0, const QString &n=QString(), const QString &n2=QString(), const QString &lname=QString())
Constructor.
Definition: skyobject.cpp:30
static const UID UID_STAR
Kind of UID.
Definition: skyobject.h:52
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
QTime riseSetTimeUT(const KStarsDateTime &dt, const GeoLocation *geo, bool rst, bool exact=true) const
Definition: skyobject.cpp:127
bool checkCircumpolar(const dms *gLat) const
Check if this point is circumpolar at the given geographic latitude.
Definition: skypoint.cpp:1045
virtual UID getUID() const
Return UID for object.
Definition: skyobject.cpp:459
static constexpr double PI
PI is a const static member; it's public so that it can be used anywhere, as long as dms....
Definition: dms.h:385
SkyPoint recomputeHorizontalCoords(const KStarsDateTime &dt, const GeoLocation *geo) const
Like recomputeCoords, but also calls EquatorialToHorizontal before returning.
Definition: skyobject.cpp:329
KStarsDateTime addDays(int nd) const
Modify the Date/Time by adding a number of days.
long double djd() const
void createEmptyMenu(SkyPoint *nullObj)
Create a popup menu for empty sky.
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
a dms subclass that caches its sine and cosine values every time the angle is changed.
Definition: cachingdms.h:18
static constexpr double DegToRad
DegToRad is a const static member equal to the number of radians in one degree (dms::PI/180....
Definition: dms.h:390
QTime time() const const
void clear()
void SinCos(double &s, double &c) const
Get the sine and cosine together.
Definition: cachingdms.h:175
void SinCos(double &s, double &c) const
Compute Sine and Cosine of the angle simultaneously.
Definition: dms.h:444
virtual QString name(void) const
Definition: skyobject.h:145
QString translatedName() const
Definition: skyobject.h:148
bool isValid() const const
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
Definition: skypoint.cpp:77
KStarsDateTime addSecs(double s) const
qint64 UID
Type for Unique object IDenticator.
Definition: skyobject.h:49
void showPopupMenu(KSPopupMenu *pmenu, const QPoint &pos)
Show Type-specific popup menu.
Definition: skyobject.cpp:56
virtual SkyObject * clone() const
Create copy of object.
Definition: skyobject.cpp:50
void setTime(const QTime &t)
Assign the Time according to a QTime object.
virtual void setH(const double &x)
Sets floating-point value of angle, in hours.
Definition: dms.h:210
virtual void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false)
Determine the current coordinates (RA, Dec) from the catalog coordinates (RA0, Dec0),...
Definition: skypoint.cpp:582
static const UID invalidUID
Invalid UID.
Definition: skyobject.h:58
QString i18n(const char *text, const TYPE &arg...)
Store several time-dependent astronomical quantities.
Definition: ksnumbers.h:42
const CachingDms & dec() const
Definition: skypoint.h:269
dms riseSetTimeAz(const KStarsDateTime &dt, const GeoLocation *geo, bool rst) const
Definition: skyobject.cpp:190
QTime riseSetTime(const KStarsDateTime &dt, const GeoLocation *geo, bool rst, bool exact=true) const
Determine the time at which the point will rise or set.
Definition: skyobject.cpp:93
bool isEmpty() const const
virtual double labelOffset() const
Definition: skyobject.cpp:454
QString messageFromTitle(const QString &imageTitle) const
Given the Image title from a URL file, try to convert it to an image credit string.
Definition: skyobject.cpp:394
void setName(const QString &name)
Set the object's primary name.
Definition: skyobject.h:417
SkyPoint recomputeCoords(const KStarsDateTime &dt, const GeoLocation *geo=nullptr) const
The equatorial coordinates for the object on date dt are computed and returned, but the object's inte...
Definition: skyobject.cpp:295
virtual void initPopupMenu(KSPopupMenu *pmenu)
Initialize the popup menut.
Definition: skyobject.cpp:67
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QTime transitTimeUT(const KStarsDateTime &dt, const GeoLocation *geo) const
Definition: skyobject.cpp:221
virtual QString labelString() const
Definition: skyobject.cpp:449
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
dms transitAltitude(const KStarsDateTime &dt, const GeoLocation *geo) const
Definition: skyobject.cpp:244
virtual void setRadians(const double &Rad)
Set angle according to the argument, in radians.
Definition: dms.h:333
void popup(const QPoint &p, QAction *atAction)
const CachingDms & ra() const
Definition: skypoint.h:263
double radians() const
Express the angle in radians.
Definition: dms.h:325
const CachingDms & dec0() const
Definition: skypoint.h:257
static double ZoomOffset()
returns the zoom dependent label offset.
Definition: skylabeler.cpp:75
const double & Degrees() const
Definition: dms.h:141
QDate date() const const
const CachingDms & ra0() const
Definition: skypoint.h:251
bool isSolarSystem() const
Definition: skyobject.h:217
virtual QString longname(void) const
Definition: skyobject.h:164
QTime transitTime(const KStarsDateTime &dt, const GeoLocation *geo) const
The same iteration technique described in riseSetTime() is used here.
Definition: skyobject.cpp:239
const dms reduce() const
return the equivalent angle between 0 and 360 degrees.
Definition: dms.cpp:251
QString name2(void) const
Definition: skyobject.h:156
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QTime GSTtoUT(dms GST) const
Convert a given Greenwich Sidereal Time to Universal Time (=Greenwich Mean Time).
QString mid(int position, int n) const const
void setName2(const QString &name2=QString())
Set the object's secondary name.
Definition: skyobject.h:423
Information about an object in the sky.
Definition: skyobject.h:41
void setType(int t)
Set the object's type identifier to the argument.
Definition: skyobject.h:195
QString message
double Hours() const
Definition: dms.h:168
QString typeName() const
Definition: skyobject.cpp:389
void setLongName(const QString &longname=QString())
Set the object's long name.
Definition: skyobject.cpp:76
Relevant data about an observing location on Earth.
Definition: geolocation.h:27
const dms & az() const
Definition: skypoint.h:275
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 04:02:44 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.