File indexing completed on 2024-03-24 15:17:48

0001 /*
0002     SPDX-FileCopyrightText: 2005 Thomas Kabelmann <thomas.kabelmann@gmx.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "skypoint.h"
0010 #include "typedef.h"
0011 
0012 class QString;
0013 
0014 class SkyObject;
0015 class SkyPoint;
0016 class SkyComposite;
0017 class SkyPainter;
0018 
0019 /**
0020  * @class SkyComponent
0021  * SkyComponent represents an object on the sky map. This may be a star, a planet or an imaginary
0022  * line like the equator.
0023  * The SkyComponent uses the composite design pattern. So if a new object type is needed, it has to
0024  * be derived from this class and must be added into the hierarchy of components.
0025  *
0026  * \section Overview Overview
0027  * KStars utilizes the Composite/Component design pattern to store all elements that must be
0028  * drawn on the SkyMap.  In this design pattern, elements to be drawn in the map are called
0029  * "Components", and they are hierarchically organized into groups called "Composites".
0030  * A Composite can contain other Composites, as well as Components. From an organizational
0031  * point of view, you can think of Composites and Components as being analogous to
0032  * "Directories" and "Files" in a computer filesystem.
0033  *
0034  * The advantage of this design pattern is that it minimizes code duplication and maximizes
0035  * modularity. There is a set of operations which all Components must perform periodically
0036  * (such as drawing on screen, or updating position), but each Component may perform its task
0037  * slightly differently. Thus, each Component can implement its own version of the functions,
0038  * and each Composite calls on its child Components to execute the desired function. For
0039  * example, if we wanted to draw all Components in the SkyMap, we would simply need to call
0040  * "skyComposite()->draw()". SkyComposite is the "top-level" Composite; its "draw()" function
0041  * simply calls draw() on each of its children. Its child Components will draw themselves,
0042  * while its child Composites will call "draw()" for each of *their* children.  Note that
0043  * we don't need to know *any* implementation details; when we need to draw the
0044  * elements, we just tell the top-level Composite to spread the word.
0045  *
0046  * \section ClassInheritance Class Inheritance
0047  * The base class in this directory is SkyComponent; all other classes are derived from it
0048  * (directly or indirectly). Its most important derivative is SkyComposite, the base classes
0049  * for all Composites.
0050  *
0051  * FIXME: There is no SingleComponent
0052  * From SkyComponent, we derive three important subclasses: SingleComponent, ListComponent,
0053  * and PointListComponent. SingleComponent represents a sky element consisting of a single
0054  * SkyObject, such as the Sun.  ListComponent represents a list of SkyObjects, such as the
0055  * Asteroids.  PointListComponent represents a list of SkyPoints (not SkyObjects), such as
0056  * the Ecliptic. Almost all other Components are derived from one of these three classes
0057  * (two Components are derived directly from SkyComponent).
0058  *
0059  * The Solar System bodies require some special treatment. For example, only solar system
0060  * bodies may have attached trails, and they move across the sky, so their positions must
0061  * be updated frequently. To handle these features, we derive SolarSystemComposite from
0062  * SkyComposite to be the container for all solar system Components. In addition, we derive
0063  * SolarSystemSingleComponent from SingleComponent, and SolarSystemListComponent from
0064  * ListComponent. These classes simply add functions to handle Trails, and to update the
0065  * positions of the bodies. Also, they contain KSPlanetBase objects, instead of SkyObjects.
0066  *
0067  * The Sun, Moon and Pluto each get a unique Component class, derived from
0068  * SolarSystemSingleComponent (this is needed because each of these bodies uses a unique
0069  * class derived from KSPlanetBase: KSSun, KSMoon, and KSPluto). The remaining major
0070  * planets are each represented with a PlanetComponent object, which is also derived from
0071  * SolarSystemSingleComponent. Finally, we have AsteroidsComponent and CometsComponent,
0072  * each of which is derived from SolarSystemListComponent.
0073  *
0074  * Next, we have the Components derived from PointListComponent. These Components represent
0075  * imaginary guide lines in the sky, such as constellation boundaries or the coordinate grid.
0076  * They are listed above, and most of them don't require further comment. The GuidesComposite
0077  * contains two sub-Composites: CoordinateGridComposite, and ConstellationLinesComposite.
0078  * Both of these contain a number of PointListComponents: CoordinateGridComposite contains one
0079  * PointsListComponent for each circle in the grid, and ConstellationLineComposite contains
0080  * one PointsListComponent for each constellation (representing the "stick figure" of the
0081  * constellation).
0082  *
0083  * Finally, we have the Components which don't inherit from either SingleComponent,
0084  * ListComponent, or PointListComponent: PlanetMoonsComponent inherits from SkyComponent
0085  * directly, because the planet moons have their own class (PlanetMoons) not derived
0086  * directly from a SkyPoint.
0087  *
0088  * \section StarComponent DeepStarComponent and StarComponent
0089  * StarComponent and DeepStarComponent manage stars in KStars. StarComponent maintains a
0090  * QVector of instances of DeepStarComponents and takes care of calling their draw routines
0091  * etc. The machinery for handling stars is documented in great detail in \ref Stars
0092  *
0093  * @author Thomas Kabelmann
0094  */
0095 class SkyComponent
0096 {
0097     public:
0098         /**
0099          * @short Constructor
0100          * @p parent pointer to the parent SkyComposite
0101          */
0102         explicit SkyComponent(SkyComposite *parent = nullptr);
0103 
0104         virtual ~SkyComponent() = default;
0105 
0106         /**
0107          * @short Draw the object on the SkyMap
0108          * @p skyp a pointer to the SkyPainter to use
0109          */
0110         virtual void draw(SkyPainter *skyp) = 0;
0111 
0112         /** @short Draw trails for objects. */
0113         virtual void drawTrails(SkyPainter *skyp);
0114 
0115         /**
0116          * @short Update the sky position(s) of this component.
0117          *
0118          * This function usually just updates the Horizontal (Azimuth/Altitude)
0119          * coordinates of its member object(s).  However, the precession and
0120          * nutation must also be recomputed periodically.
0121          * @p num Pointer to the KSNumbers object
0122          * @sa SingleComponent::update()
0123          * @sa ListComponent::update()
0124          * @sa ConstellationBoundaryComponent::update()
0125          */
0126         virtual void update(KSNumbers *) {}
0127         virtual void updateSolarSystemBodies(KSNumbers *) {}
0128         virtual void updateMoons(KSNumbers *) {}
0129 
0130         /** @return true if component is to be drawn on the map. */
0131         virtual bool selected()
0132         {
0133             return true;
0134         }
0135 
0136         /** @return Parent of component. If there is no parent returns nullptr. */
0137         SkyComposite *parent()
0138         {
0139             return m_parent;
0140         }
0141 
0142         /**
0143          * @short Search the children of this SkyComponent for
0144          * a SkyObject whose name matches the argument
0145          * @p name the name to be matched
0146          * @p exact If true, it will return an exact match, otherwise it can return
0147          * a partial match.
0148          * @return a pointer to the SkyObject whose name matches
0149          * the argument, or a nullptr pointer if no match was found.
0150          * @note This function simply returns the nullptr pointer; it
0151          * is reimplemented in various sub-classes
0152          */
0153         virtual SkyObject *findByName(const QString &name, bool exact = true);
0154 
0155         /**
0156          * @short Searches the region(s) and appends the SkyObjects found to the list of sky objects
0157          *
0158          * Look for a SkyObject that is in one of the regions
0159          * If found, then append to the list of sky objects
0160          * @p list list of SkyObject to which matching list has to be appended to
0161          * @p region defines the regions in which the search for SkyObject should be done within
0162          * @return void
0163          * @note This function simply returns; it is
0164          * reimplemented in various sub-classes.
0165          */
0166         virtual void objectsInArea(QList<SkyObject *> &list, const SkyRegion &region);
0167 
0168         /**
0169          * @short Find the SkyObject nearest the given SkyPoint
0170          *
0171          * Look for a SkyObject that is nearer to point p than maxrad.
0172          * If one is found, then maxrad is reset to the separation of the new nearest object.
0173          * @p p pointer to the SkyPoint to search around
0174          * @p maxrad reference to current search radius in degrees
0175          * @return a pointer to the nearest SkyObject
0176          * @note This function simply returns a nullptr pointer; it is
0177          * reimplemented in various sub-classes.
0178          */
0179         virtual SkyObject *objectNearest(SkyPoint *p, double &maxrad);
0180 
0181         /**
0182          * @short Emit signal about progress.
0183          *
0184          * @sa SkyMapComposite::emitProgressText
0185          */
0186         virtual void emitProgressText(const QString &message);
0187 
0188         inline QHash<int, QStringList> &objectNames()
0189         {
0190             return getObjectNames();
0191         }
0192 
0193         inline QStringList &objectNames(int type)
0194         {
0195             return getObjectNames()[type];
0196         }
0197 
0198         inline QHash<int, QVector<QPair<QString, const SkyObject *>>> &objectLists()
0199         {
0200             return getObjectLists();
0201         }
0202 
0203         inline QVector<QPair<QString, const SkyObject *>> &objectLists(int type)
0204         {
0205             return getObjectLists()[type];
0206         }
0207 
0208         void removeFromNames(const SkyObject *obj);
0209         void removeFromLists(const SkyObject *obj);
0210 
0211     private:
0212         virtual QHash<int, QStringList> &getObjectNames();
0213         virtual QHash<int, QVector<QPair<QString, const SkyObject *>>> &getObjectLists();
0214 
0215         // Disallow copying and assignment
0216         SkyComponent(const SkyComponent &);
0217         SkyComponent &operator=(const SkyComponent &);
0218 
0219         /// Parent of sky component.
0220         SkyComposite *m_parent;
0221 };