1 /* 2 SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #pragma once 8 9 #include "dms.h" 10 #include "skypoint.h" 11 12 #include <KLocalizedString> 13 14 #include <QSharedDataPointer> 15 #include <QString> 16 #include <QStringList> 17 18 class QPoint; 19 class GeoLocation; 20 class KSPopupMenu; 21 22 /** 23 * @class SkyObject 24 * Provides all necessary information about an object in the sky: 25 * its coordinates, name(s), type, magnitude, and QStringLists of 26 * URLs for images and webpages regarding the object. 27 * @short Information about an object in the sky. 28 * @author Jason Harris 29 * @version 1.0 30 */ 31 class SkyObject : public SkyPoint 32 { 33 public: 34 /** 35 * @short Type for Unique object IDenticator. 36 * 37 * Each object has unique ID (UID). For different objects UIDs must be different. 38 */ 39 typedef qint64 UID; 40 41 /** @short Kind of UID */ 42 static const UID UID_STAR; 43 static const UID UID_GALAXY; 44 static const UID UID_DEEPSKY; 45 static const UID UID_SOLARSYS; 46 47 /** Invalid UID. Real sky object could not have such UID */ 48 static const UID invalidUID; 49 50 /** 51 * Constructor. Set SkyObject data according to arguments. 52 * @param t Type of object 53 * @param r catalog Right Ascension 54 * @param d catalog Declination 55 * @param m magnitude (brightness) 56 * @param n Primary name 57 * @param n2 Secondary name 58 * @param lname Long name (common name) 59 */ 60 explicit SkyObject(int t = TYPE_UNKNOWN, dms r = dms(0.0), dms d = dms(0.0), float m = 0.0, 61 const QString &n = QString(), const QString &n2 = QString(), const QString &lname = QString()); 62 /** 63 * Constructor. Set SkyObject data according to arguments. Differs from 64 * above function only in data type of RA and Dec. 65 * @param t Type of object 66 * @param r catalog Right Ascension 67 * @param d catalog Declination 68 * @param m magnitude (brightness) 69 * @param n Primary name 70 * @param n2 Secondary name 71 * @param lname Long name (common name) 72 */ 73 SkyObject(int t, double r, double d, float m = 0.0, const QString &n = QString(), const QString &n2 = QString(), 74 const QString &lname = QString()); 75 76 /** Destructor (empty) */ 77 virtual ~SkyObject() override = default; 78 79 /** 80 * @short Create copy of object. 81 * This method is virtual copy constructor. It allows for safe 82 * copying of objects. In other words, KSPlanet object stored in 83 * SkyObject pointer will be copied as KSPlanet. 84 * 85 * Each subclass of SkyObject MUST implement clone method. There 86 * is no checking to ensure this, though. 87 * 88 * @return pointer to newly allocated object. Caller takes full responsibility 89 * for deallocating it. 90 */ 91 virtual SkyObject *clone() const; 92 93 /** 94 * @enum TYPE 95 * The type classification of the SkyObject. 96 * @note Keep TYPE_UNKNOWN at 255. To find out how many known 97 * types exist, keep the NUMBER_OF_KNOWN_TYPES at the highest 98 * non-Unknown value. This is a fake type that can be used in 99 * comparisons and for loops. 100 */ 101 enum TYPE 102 { 103 STAR = 0, 104 CATALOG_STAR = 1, 105 PLANET = 2, 106 OPEN_CLUSTER = 3, 107 GLOBULAR_CLUSTER = 4, 108 GASEOUS_NEBULA = 5, 109 PLANETARY_NEBULA = 6, 110 SUPERNOVA_REMNANT = 7, 111 GALAXY = 8, 112 COMET = 9, 113 ASTEROID = 10, 114 CONSTELLATION = 11, 115 MOON = 12, 116 ASTERISM = 13, 117 GALAXY_CLUSTER = 14, 118 DARK_NEBULA = 15, 119 QUASAR = 16, 120 MULT_STAR = 17, 121 RADIO_SOURCE = 18, 122 SATELLITE = 19, 123 SUPERNOVA = 20, 124 NUMBER_OF_KNOWN_TYPES = 21, 125 TYPE_UNKNOWN = 255 126 }; 127 /** 128 * @return A translated string indicating the type name for a given type number 129 * @param t The type number 130 * @note Note the existence of a SkyObject::typeName( void ) method that is not static and returns the type of this object. 131 */ 132 static QString typeName(const int t); 133 134 /** @return object's primary name. */ name(void)135 inline virtual QString name(void) const { return hasName() ? Name : unnamedString; } 136 137 /** @return object's primary name, translated to local language. */ translatedName()138 inline QString translatedName() const 139 { 140 return i18n( 141 name() 142 .toUtf8()); // FIXME: Hmm... that's funny. How does the string extraction work, if we are UTF8-ing the name first? Does the string extraction change to UTF8? 143 } 144 145 /** @return object's secondary name */ name2(void)146 inline QString name2(void) const { return (hasName2() ? Name2 : emptyString); } 147 148 /** @return object's secondary name, translated to local language. */ translatedName2()149 inline QString translatedName2() const { return (hasName2() ? i18n(Name2.toUtf8()) : emptyString); } 150 151 /** 152 * @return object's common (long) name 153 */ longname(void)154 virtual QString longname(void) const { return hasLongName() ? LongName : unnamedObjectString; } 155 156 /** 157 * @return object's common (long) name, translated to local language. 158 */ translatedLongName()159 QString translatedLongName() const { return i18n(longname().toUtf8()); } 160 161 /** 162 * Set the object's long name. 163 * @param longname the object's long name. 164 */ 165 void setLongName(const QString &longname = QString()); 166 167 /** 168 * @return the string used to label the object on the map 169 * In the default implementation, this just returns translatedName() 170 * Overridden by StarObject. 171 */ 172 virtual QString labelString() const; 173 174 /** 175 * @return object's type identifier (int) 176 * @see enum TYPE 177 */ type(void)178 inline int type(void) const { return (int)Type; } 179 180 /** 181 * Set the object's type identifier to the argument. 182 * @param t the object's type identifier (e.g., "SkyObject::PLANETARY_NEBULA") 183 * @see enum TYPE 184 */ setType(int t)185 inline void setType(int t) { Type = (unsigned char)t; } 186 187 /** 188 * @return the type name for this object 189 * @note This just calls the static method by the same name, with the appropriate type number. See SkyObject::typeName( const int ) 190 */ 191 QString typeName() const; 192 193 /** 194 * @return object's magnitude 195 */ mag()196 inline float mag() const { return sortMagnitude; } 197 198 /** 199 * @return the object's position angle. This is overridden in KSPlanetBase 200 * and DeepSkyObject; for all other SkyObjects, this returns 0.0. 201 */ pa()202 inline virtual double pa() const { return 0.0; } 203 204 /** 205 * @return true if the object is a solar system body. 206 */ isSolarSystem()207 inline bool isSolarSystem() const { return (type() == 2 || type() == 9 || type() == 10 || type() == 12); } 208 209 /** 210 * Initialize the popup menut. This function should call correct 211 * initialization function in KSPopupMenu. By overloading the 212 * function, we don't have to check the object type when we need 213 * the menu. 214 */ 215 virtual void initPopupMenu(KSPopupMenu *pmenu); 216 217 /** Show Type-specific popup menu. Overloading is done in the function initPopupMenu */ 218 void showPopupMenu(KSPopupMenu *pmenu, const QPoint &pos); 219 220 /** 221 * Determine the time at which the point will rise or set. Because solar system 222 * objects move across the sky, it is necessary to iterate on the solution. 223 * We compute the rise/set time for the object's current position, then 224 * compute the object's position at that time. Finally, we recompute then 225 * rise/set time for the new coordinates. Further iteration is not necessary, 226 * even for the most swiftly-moving object (the Moon). 227 * @return the local time that the object will rise 228 * @param dt current UT date/time 229 * @param geo current geographic location 230 * @param rst If true, compute rise time. If false, compute set time. 231 * @param exact If true, use a second iteration for more accurate time 232 */ 233 QTime riseSetTime(const KStarsDateTime &dt, const GeoLocation *geo, bool rst, bool exact = true) const; 234 235 /** 236 * @return the UT time when the object will rise or set 237 * @param dt target date/time 238 * @param geo pointer to Geographic location 239 * @param rst Boolean. If true will compute rise time. If false 240 * will compute set time. 241 * @param exact If true, use a second iteration for more accurate time 242 */ 243 QTime riseSetTimeUT(const KStarsDateTime &dt, const GeoLocation *geo, bool rst, bool exact = true) const; 244 245 /** 246 * @return the Azimuth time when the object will rise or set. This function 247 * recomputes set or rise UT times. 248 * @param dt target date/time 249 * @param geo GeoLocation object 250 * @param rst Boolen. If true will compute rise time. If false 251 * will compute set time. 252 */ 253 dms riseSetTimeAz(const KStarsDateTime &dt, const GeoLocation *geo, bool rst) const; 254 255 /** 256 * The same iteration technique described in riseSetTime() is used here. 257 * @return the local time that the object will transit the meridian. 258 * @param dt target date/time 259 * @param geo pointer to the geographic location 260 */ 261 QTime transitTime(const KStarsDateTime &dt, const GeoLocation *geo) const; 262 263 /** 264 * @return the universal time that the object will transit the meridian. 265 * @param dt target date/time 266 * @param geo pointer to the geographic location 267 */ 268 QTime transitTimeUT(const KStarsDateTime &dt, const GeoLocation *geo) const; 269 270 /** 271 * @return the altitude of the object at the moment it transits the meridian. 272 * @param dt target date/time 273 * @param geo pointer to the geographic location 274 */ 275 dms transitAltitude(const KStarsDateTime &dt, const GeoLocation *geo) const; 276 277 /** 278 * The equatorial coordinates for the object on date dt are computed and returned, 279 * but the object's internal coordinates are not modified. 280 * @return the coordinates of the selected object for the time given by jd 281 * @param dt date/time for which the coords will be computed. 282 * @param geo pointer to geographic location (used for solar system only) 283 * @note Does not update the horizontal coordinates. Call EquatorialToHorizontal for that. 284 */ 285 SkyPoint recomputeCoords(const KStarsDateTime &dt, const GeoLocation *geo = nullptr) const; 286 287 /** 288 * @short Like recomputeCoords, but also calls EquatorialToHorizontal before returning 289 */ 290 SkyPoint recomputeHorizontalCoords(const KStarsDateTime &dt, const GeoLocation *geo) const; 291 hasName()292 inline bool hasName() const { return !Name.isEmpty(); } 293 hasName2()294 inline bool hasName2() const { return !Name2.isEmpty(); } 295 hasLongName()296 inline bool hasLongName() const { return !LongName.isEmpty(); } 297 298 /** 299 * @short Given the Image title from a URL file, try to convert it to an image credit string. 300 */ 301 QString messageFromTitle(const QString &imageTitle) const; 302 303 /** 304 * @return the pixel distance for offseting the object's name label 305 * @note overridden in StarObject, DeepSkyObject, KSPlanetBase 306 */ 307 virtual double labelOffset() const; 308 309 /** 310 * @short Return UID for object. 311 * This method should be reimplemented in all concrete 312 * subclasses. Implementation for SkyObject just returns 313 * invalidUID. It's required SkyObject is not an abstract class. 314 */ 315 virtual UID getUID() const; 316 317 // TODO: (Valentin) have another think about onFocus handlers :) 318 319 /** 320 * @brief hashBeenUpdated 321 * @return whether the coordinates of the object have been updated 322 * 323 * This is used for faster filtering. 324 */ hashBeenUpdated()325 bool hashBeenUpdated() { return has_been_updated; } 326 327 private: 328 /** 329 * Compute the UT time when the object will rise or set. It is an auxiliary 330 * procedure because it does not use the RA and DEC of the object but values 331 * given as parameters. You may want to use riseSetTimeUT() which is 332 * public. riseSetTimeUT() calls this function iteratively. 333 * @param dt target date/time 334 * @param geo pointer to Geographic location 335 * @param righta pointer to Right ascention of the object 336 * @param decl pointer to Declination of the object 337 * @param rst Boolean. If true will compute rise time. If false 338 * will compute set time. 339 * @return the time at which the given position will rise or set. 340 */ 341 QTime auxRiseSetTimeUT(const KStarsDateTime &dt, const GeoLocation *geo, const dms *righta, const dms *decl, 342 bool riseT) const; 343 344 /** 345 * Compute the LST time when the object will rise or set. It is an auxiliary 346 * procedure because it does not use the RA and DEC of the object but values 347 * given as parameters. You may want to use riseSetTimeLST() which is 348 * public. riseSetTimeLST() calls this function iteratively. 349 * @param gLt Geographic latitude 350 * @param rga Right ascention of the object 351 * @param decl Declination of the object 352 * @param rst Boolean. If true will compute rise time. If false 353 * will compute set time. 354 */ 355 dms auxRiseSetTimeLST(const dms *gLt, const dms *rga, const dms *decl, bool rst) const; 356 357 /** 358 * Compute the approximate hour angle that an object with declination d will have 359 * when its altitude is h (as seen from geographic latitude gLat). 360 * This function is only used by auxRiseSetTimeLST(). 361 * @param h pointer to the altitude of the object 362 * @param gLat pointer to the geographic latitude 363 * @param d pointer to the declination of the object. 364 * @return the Hour Angle, in degrees. 365 */ 366 double approxHourAngle(const dms *h, const dms *gLat, const dms *d) const; 367 368 /** 369 * Correct for the geometric altitude of the center of the body at the 370 * time of rising or setting. This is due to refraction at the horizon 371 * and to the size of the body. The moon correction has also to take into 372 * account parallax. The value we use here is a rough approximation 373 * suggested by J. Meeus. 374 * 375 * Weather status (temperature and pressure basically) is not taken 376 * into account although change of conditions between summer and 377 * winter could shift the times of sunrise and sunset by 20 seconds. 378 * 379 * This function is only used by auxRiseSetTimeLST(). 380 * @return dms object with the correction. 381 */ 382 dms elevationCorrection(void) const; 383 384 unsigned char Type; 385 float 386 sortMagnitude; // This magnitude is used for sorting / making decisions about the visibility of an object. Should not be NaN. 387 388 protected: 389 /** 390 * Set the object's sorting magnitude. 391 * @param m the object's magnitude. 392 */ setMag(float m)393 inline void setMag(float m) 394 { 395 sortMagnitude = 396 m < 36.0 ? 397 m : 398 NaN:: 399 f; // Updating faintest sane magnitude to 36.0 (faintest visual magnitude visible with E-ELT, acc. to Wikipedia on Apparent Magnitude.) 400 } 401 // FIXME: We claim sortMagnitude should not be NaN, but we are setting it to NaN above!! ^ 402 403 /** 404 * Set the object's primary name. 405 * @param name the object's primary name 406 */ setName(const QString & name)407 inline void setName(const QString &name) { Name = name; } 408 409 /** 410 * Set the object's secondary name. 411 * @param name2 the object's secondary name. 412 */ 413 inline void setName2(const QString &name2 = QString()) { Name2 = name2; } 414 415 QString Name, Name2, LongName; 416 417 // store often used name strings in static variables 418 static QString emptyString; 419 static QString unnamedString; 420 static QString unnamedObjectString; 421 static QString starString; 422 423 // Whether the coordinates of the object have been updated. 424 // The default value is chose for compatibility reasons. 425 // It primarily matters for objects which are filtered. 426 // See `KSAsteroid` for an example. 427 bool has_been_updated = true; 428 }; 429