1 /*
2     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
3     SPDX-FileCopyrightText: 2021 Valentin Boettcher <hiro at protagon.space; @hiro98:tchncs.de>
4 
5     SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #pragma once
9 
10 #include "dms.h"
11 #include "skyobject.h"
12 #include "nan.h"
13 #include "texturemanager.h"
14 #include <QString>
15 #include <QByteArray>
16 #include <QImage>
17 #include <array>
18 #include <utility>
19 
20 class KSPopupMenu;
21 class KStarsData;
22 class CatalogComponent;
23 class CatalogEntryData;
24 namespace CatalogsDB
25 {
26 struct Catalog;
27 }
28 
29 /**
30  * A simple container object to hold the minimum information for a Deeb
31  * Sky Object to be drawn on the skymap.  Detailed information about the
32  * object (like `Catalog` information) will be loaded from it's birthing
33  * database when needed. Based on the original DeepSkyObject by Jason
34  * Harris.
35  *
36  * You shouldn't create a CatalogObject manually!
37  *
38  * \todo maybe just turn the const members public
39  */
40 class CatalogObject : public SkyObject
41 {
42     friend class AddCatalogObject;
43 
44   public:
45     using oid = QByteArray;
46 
47     /**
48      * @param id oid (hash) of the object
49      * @param t Type of object
50      * @param r Right Ascension
51      * @param d Declination
52      * @param m magnitude (brightness)
53      * @param n Primary name
54      * @param lname Long name (common name)
55      * @param catalog_identifier a catalog specific identifier
56      * @param catalog_id catalog id
57      * @param a major axis (arcminutes)
58      * @param b minor axis (arcminutes)
59      * @param pa position angle (degrees)
60      * @param flux integrated flux (optional)
61      * @param database_path the path to the birthing database of this
62      * object, used to load additional information on-demand
63      */
64     CatalogObject(oid id = {}, const SkyObject::TYPE t = SkyObject::STAR,
65                   const dms &r = dms(0.0), const dms &d = dms(0.0),
66                   const float m = NaN::f, const QString &n = "unnamed",
67                   const QString &lname              = QString(),
68                   const QString &catalog_identifier = QString(),
69                   const int catalog_id = -1, const float a = 0.0, const float b = 0.0,
70                   const double pa = 0.0, const float flux = 0,
71                   const QString &database_path = "")
SkyObject(t,r,d,m,n,catalog_identifier,lname)72         : SkyObject(t, r, d, m, n, catalog_identifier, lname),
73           m_catalog_identifier{ catalog_identifier }, m_catalog_id{ catalog_id },
74           m_database_path{ database_path }, m_major_axis{ a }, m_minor_axis{ b },
75           m_position_angle{ pa }, m_flux{ flux }
76     {
77         if (id.length() == 0)
78             m_object_id = getId();
79         else
80             m_object_id = std::move(id);
81     };
82 
83     ~CatalogObject() override = default;
84 
85     /**
86      * @return the string for the skymap label of the object.
87      */
88     QString labelString() const override;
89 
90     /**
91      * Clones the object and returns a pointer to it. This is legacy
92      * code.
93      *
94      * @deprecated do not use in new code
95      */
96     CatalogObject *clone() const override;
97 
98     /**
99      * Generates a KStars internal UID from the object id.
100      */
101     SkyObject::UID getUID() const override;
102 
103     /**
104      * @return the object's integrated flux, unit value is stored in
105      * the custom catalog component.
106      */
flux()107     inline float flux() const { return m_flux; }
108 
109     /**
110      * @return the object's major axis length, in arcminutes.
111      */
a()112     inline float a() const { return m_major_axis; }
113 
114     /**
115      * @return the object's minor axis length, in arcminutes.
116      */
b()117     inline float b() const { return m_minor_axis; }
118 
119     /**
120      * @return the object's aspect ratio (MinorAxis/MajorAxis). Returns 1.0
121      * if the object's MinorAxis=0.0.
122      */
123     float e() const;
124 
125     /**
126      * @return the object's position angle in degrees, measured clockwise from North.
127      */
pa()128     inline double pa() const override { return m_position_angle; }
129 
130     /**
131      * Get information about the catalog that this objects stems from.
132      *
133      * The catalog information will be loaded from the catalog
134      * database on demand.
135      */
136     const CatalogsDB::Catalog getCatalog() const;
137 
138     /**
139      * Get the id of the catalog this object belongs to.
140      */
catalogId()141     int catalogId() const { return m_catalog_id; }
142 
143     /**
144      * @return the pixel distance for offseting the object's name label
145      */
146     double labelOffset() const override;
147 
148     /**
149      * Update the cooridnates and the horizontal coordinates if
150      * updateID or updateNumID have changed (global).
151      */
152     void JITupdate();
153 
154     /**
155      * Initialize the popup menu for a `CatalogObject`.
156      */
157     void initPopupMenu(KSPopupMenu *pmenu) override;
158 
159     /**
160      * \return the catalog specific identifier. (For example UGC ...)
161      */
162 
catalogIdentifier()163     const QString &catalogIdentifier() const { return m_catalog_identifier; };
164 
165     friend bool operator==(const CatalogObject &c1, const CatalogObject &c2)
166     {
167         return c1.m_object_id == c2.m_object_id;
168     }
169 
170     friend bool operator!=(const CatalogObject &c1, const CatalogObject &c2)
171     {
172         return !(c1 == c2);
173     }
174 
175     /**
176      * \returns the unique ID of this object (not the physical ID =
177      * m_object_id) by hashing unique properties of the object.
178      *
179      * This method provides the reference implementation for the oid hash.
180      */
181     const oid getId() const;
182     static const oid getId(const SkyObject::TYPE type, const double ra, const double dec,
183                            const QString &name, const QString &catalog_identifier);
184 
185     /**
186      * \returns the physical object id of the catalogobject
187      */
getObjectId()188     const oid getObjectId() const { return m_object_id; };
189 
190     /**
191      * Set the catalog identifier to \p `cat_ident`.
192      */
setCatalogIdentifier(const QString & cat_ident)193     void setCatalogIdentifier(const QString &cat_ident)
194     {
195         m_catalog_identifier = cat_ident;
196     }
197 
198     /**
199      * Set the major axis to \p `a`.
200      */
setMaj(const float a)201     void setMaj(const float a) { m_major_axis = a; }
202 
203     /**
204      * Set the minor axis to \p `b`.
205      */
setMin(const float b)206     void setMin(const float b) { m_minor_axis = b; }
207 
208     /**
209      * Set the flux to \p `flux`.
210      */
setFlux(const float flux)211     void setFlux(const float flux) { m_flux = flux; }
212 
213     /**
214      * Set the position angle to \p `pa`.
215      */
setPA(const double pa)216     void setPA(const double pa) { m_position_angle = pa; }
217 
218     /**
219      * Set the magnitude of the object.
220      */
setMag(const double mag)221     void setMag(const double mag) { SkyObject::setMag(mag); };
222 
223     /**
224      * Load the image for this object.
225      */
226     void load_image();
227 
228     /**
229      * Get the image for this object.
230      *
231      * @returns [has image?, the image]
232      */
image()233     inline std::pair<bool, const QImage &> image() const
234     {
235         return { !m_image.isNull(), m_image };
236     }
237 
238   private:
239     /**
240      * The unique physical object identifier (hash).
241      */
242     oid m_object_id;
243 
244     /**
245      * A catalog specific identifier.
246      */
247     QString m_catalog_identifier;
248 
249     /**
250      * The id of the catalog, the object is originating from.
251      *
252      * A value of -1 means that the catalog is unknown. This member is
253      * not exposed publicly because it is only useful along with
254      * `m_database_path`.
255      */
256     int m_catalog_id;
257 
258     /**
259      * The database path which this object was loaded from.
260      */
261     std::reference_wrapper<const QString> m_database_path;
262 
263     /**
264      * Whether the image for this catalog object has been loaded.
265      */
266     bool m_image_loaded{ false };
267 
268     /**
269      * The image for this object (if any).
270      *
271      * @todo use std::optional
272      */
273     QImage m_image;
274 
275     //@{
276     /**
277      * Astronical metadata.
278      *
279      * Those values may make sense depending on the type of the
280      * object. A value of `-1` always means: "it doesn't make sense
281      * here".
282      */
283     float m_major_axis;
284     float m_minor_axis;
285 
286     double m_position_angle;
287     float m_flux;
288     //@}
289 
290     //@{
291     /**
292      * Update id counters.
293      */
294     quint64 m_updateID{ 0 };
295     quint64 m_updateNumID{ 0 };
296     //@}
297 };
298