File indexing completed on 2024-07-14 07:17:24

0001 /*
0002     SPDX-FileCopyrightText: 2007 James B. Bowlin <bowlin@mindspring.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "ksnumbers.h"
0010 #include "typedef.h"
0011 #include "htmesh/HTMesh.h"
0012 
0013 #include <QMap>
0014 
0015 class QPainter;
0016 class QPointF;
0017 class QPolygonF;
0018 
0019 class KSNumbers;
0020 class SkyPoint;
0021 class StarObject;
0022 
0023 // These enums control the trixel storage.  Separate buffers are available for
0024 // indexing and intersecting.  Currently only one buffer is required.  Multiple
0025 // buffers could be used for intermingling drawing and searching or to have a
0026 // non-precessed aperture for objects that don't precess.  If a buffer number
0027 // is greater than or equal to NUM_BUF a brief error message will be printed
0028 // and then KStars will crash.  This is a feature, not a bug.
0029 
0030 enum MeshBufNum_t
0031 {
0032     DRAW_BUF        = 0,
0033     NO_PRECESS_BUF  = 1,
0034     OBJ_NEAREST_BUF = 2,
0035     IN_CONSTELL_BUF = 3,
0036     NUM_MESH_BUF
0037 };
0038 
0039 /** @class SkyMesh
0040  * Provides an interface to the Hierarchical Triangular Mesh (HTM) library
0041  * written by A. Szalay, John Doug Reynolds, Jim Gray, and Peter Z. Kunszt.
0042  *
0043  * HTM divides the celestial sphere up into little triangles (trixels) and
0044  * gives each triangle a unique integer id.  We index objects by putting a
0045  * pointer to the object in a data structure accessible by the id number, for
0046  * example QList<QList<StarObject*> or QHash<int, QList<LineListComponent*>.
0047  *
0048  * Use aperture(centerPoint, radius) to get a list of trixels visible in the
0049  * circle.  Then use a MeshIterator to iterate over the indices of the visible
0050  * trixels.  Look up each index in the top level QHash or QList data structure
0051  * and the union of all the elements of the QList's returned will contain all
0052  * the objects visible in the circle in the sky specified in the aperture()
0053  * call.
0054  *
0055  * The drawID is used for extended objects that may be covered by more than
0056  * one trixel.  Every time aperture() is called, drawID is incremented by one.
0057  * Extended objects should each contain their own drawID.  If an object's
0058  * drawID is the same as the current drawID then it shouldn't be drawn again
0059  * because it was already drawn in this draw cycle.  If the drawID is
0060  * different then it should be drawn and then the drawID should be set to the
0061  * current drawID() so it doesn't get drawn again this cycle.
0062  *
0063  * The list of visible trixels found from an aperture() call or one of the
0064  * primitive index() by creating a new MeshIterator instance:
0065  *
0066  *      MeshIterator( HTMesh *mesh )
0067  *
0068  * The MeshIterator has its own bool hasNext(), int next(), and int size()
0069  * methods for iterating through the integer indices of the found trixels or
0070  * for just getting the total number of found trixels.
0071  */
0072 
0073 class SkyMesh : public HTMesh
0074 {
0075   protected:
0076     SkyMesh(int level);
0077     // FIXME: check copy ctor
0078     SkyMesh(SkyMesh &skyMesh);
0079 
0080   public:
0081     /** @short creates the single instance of SkyMesh.  The level indicates
0082          * how fine a mesh we will use. The number of triangles (trixels) in the
0083          * mesh will be 8 * 4^level so a mesh of level 5 will have 8 * 4^5 = 8 *
0084          * 2^10 = 8192 trixels.  The size of the triangles are roughly pi / *
0085          * 2^(level + 1) so a level 5 mesh will have triangles size roughly of
0086          * .05 radians or 2.8 degrees.
0087                */
0088     static SkyMesh *Create(int level);
0089 
0090     /** @short returns the default instance of SkyMesh or null if it has not
0091          * yet been created.
0092          */
0093     static SkyMesh *Instance();
0094 
0095     /**
0096          *@short returns the instance of SkyMesh corresponding to the given level
0097          *@return the instance of SkyMesh at the given level, or nullptr if it has not
0098          *yet been created.
0099          */
0100     static SkyMesh *Instance(int level);
0101 
0102     /**
0103          *@short finds the set of trixels that cover the circular aperture
0104          * specified after first performing a reverse precession correction on
0105          * the center so we don't have to re-index objects simply due to
0106          * precession.  The drawID also gets incremented which is useful for
0107          * drawing extended objects.  Typically a safety factor of about one
0108          * degree is added to the radius to account for proper motion,
0109          * refraction and other imperfections.
0110          *@param center Center of the aperture
0111          *@param radius Radius of the aperture in degrees
0112          *@param bufNum Buffer to use
0113          *@note See HTMesh.h for more
0114          */
0115     void aperture(SkyPoint *center, double radius, MeshBufNum_t bufNum = DRAW_BUF);
0116 
0117     /** @short returns the index of the trixel containing p.
0118          */
0119     Trixel index(const SkyPoint *p);
0120 
0121     /**
0122          * @short returns the sky region needed to cover the rectangle defined by two
0123          * SkyPoints p1 and p2
0124          * @param p1 top-left SkyPoint of the rectangle
0125          * @param p2 bottom-right SkyPoint of the rectangle
0126          */
0127     const SkyRegion &skyRegion(const SkyPoint &p1, const SkyPoint &p2);
0128 
0129     /** @name Stars and CLines
0130         Routines used for indexing stars and CLines.
0131         The following four routines are used for indexing stars and CLines.
0132         They differ from the normal routines because they take proper motion
0133         into account while the normal routines always index the J2000
0134         position.
0135 
0136         Since the proper motion depends on time, it is essential to call
0137         setKSNumbers to set the time before doing the indexing.  The default
0138         value is J2000.
0139         */
0140 
0141     /** @{*/
0142 
0143     /** @short sets the time for indexing StarObjects and CLines.
0144          */
0145     void setKSNumbers(KSNumbers *num) { m_KSNumbers = KSNumbers(*num); }
0146 
0147     /** @short returns the trixel that contains the star at the set
0148          * time with proper motion taken into account but not precession.
0149          * This is a feature not a bug.
0150          */
0151     Trixel indexStar(StarObject *star);
0152 
0153     /** @short fills the default buffer with all the trixels needed to cover
0154          * the line connecting the two stars.
0155          */
0156     void indexStar(StarObject *star1, StarObject *star2);
0157 
0158     /** @short Fills a hash with all the trixels needed to cover all the line
0159          * segments in the SkyList where each SkyPoint is assumed to be a star
0160          * and proper motion is taken into account.  Used only by
0161          * ConstellationsLines.
0162          */
0163     const IndexHash &indexStarLine(SkyList *points);
0164 
0165     /** @}*/
0166 
0167     //----- Here come index routines for various shapes -----
0168 
0169     /** @name Multi Shape Index Routines
0170          * The first two routines use QPoint and the rest use SkyPoint
0171         */
0172 
0173     /** @{*/
0174 
0175     /** @short finds the indices of the trixels that cover the triangle
0176          * specified by the three QPointF's.
0177          */
0178     void index(const QPointF &p1, const QPointF &p2, const QPointF &p3);
0179 
0180     /** @short Finds the trixels needed to cover the quadrilateral specified
0181          * by the four QPointF's.
0182          */
0183     void index(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4);
0184 
0185     /** @short finds the indices of the trixels covering the circle specified
0186          * by center and radius.
0187          */
0188     void index(const SkyPoint *center, double radius, MeshBufNum_t bufNum = DRAW_BUF);
0189 
0190     /** @short finds the indices of the trixels covering the line segment
0191          * connecting p1 and p2.
0192          */
0193     void index(const SkyPoint *p1, const SkyPoint *p2);
0194 
0195     /** @short finds the indices of the trixels covering the triangle
0196          * specified by vertices: p1, p2, and p3.
0197          */
0198     void index(const SkyPoint *p1, const SkyPoint *p2, const SkyPoint *p3);
0199 
0200     /** @short finds the indices of the trixels covering the quadralateral
0201          * specified by the vertices: p1, p2, p3, and p4.
0202          */
0203     void index(const SkyPoint *p1, const SkyPoint *p2, const SkyPoint *p3, const SkyPoint *p4);
0204 
0205     /** @}*/
0206 
0207     /** @name IndexHash Routines
0208 
0209         The follow routines are used to index SkyList data structures.  They
0210         fill a QHash with the indices of the trixels that cover the data
0211         structure.  These are all used as callbacks in the LineListIndex
0212         subclasses so they can use the same indexing code to index different
0213         data structures.  See also indexStarLine() above.
0214         */
0215 
0216     /** @{*/
0217 
0218     /** @short fills a QHash with the trixel indices needed to cover all the
0219          * line segments specified in the QVector<SkyPoints*> points.
0220          *
0221          * @param points the points of the line segment. The debug mode causes extra
0222          * info to be printed.
0223          */
0224     const IndexHash &indexLine(SkyList *points);
0225 
0226     /** @short as above but allows for skipping the indexing of some of
0227          * the points.
0228          *
0229          * @param points the line segment to be indexed.
0230          * @param skip a hash indicating which points to skip
0231          * debugging info.
0232          */
0233     const IndexHash &indexLine(SkyList *points, IndexHash *skip);
0234 
0235     /** @short fills a QHash with the trixel indices needed to cover the
0236          * polygon specified in the QList<SkyPoints*> points.  There is no
0237          * version with a skip parameter because it does not make sense to
0238          * skip some of the edges of a filled polygon.
0239          *
0240          * @param points the points of the line segment.
0241          * The debug mode causes extra info to be printed.
0242          */
0243     const IndexHash &indexPoly(SkyList *points);
0244 
0245     /** @short does the same as above but with a QPolygonF as the
0246          * container for the points.
0247          */
0248     const IndexHash &indexPoly(const QPolygonF *points);
0249 
0250     /** @}*/
0251 
0252     /** @short Returns the debug level.  This is used as a global debug level
0253          * for LineListIndex and its subclasses.
0254          */
0255     int debug() const { return m_debug; }
0256 
0257     /** @short Sets the debug level.
0258          */
0259     void debug(int debug) { m_debug = debug; }
0260 
0261     /** @return the current drawID which gets incremented each time aperture()
0262          * is called.
0263          */
0264     DrawID drawID() const { return m_drawID; }
0265 
0266     /** @short increments the drawID and returns the new value.  This is
0267          * useful when you want to use the drawID to ensure you are not
0268          * repeating yourself when iterating over the elements of an IndexHash.
0269          * It is currently used in LineListIndex::reindex().
0270          */
0271     int incDrawID() { return ++m_drawID; }
0272 
0273     /** @short Draws the outline of all the trixels in the specified buffer.
0274          * This was very useful during debugging.  I don't precess the points
0275          * because I mainly use it with the IN_CONSTELL_BUF which is not
0276          * precessed.  We will probably have buffers serve double and triple
0277          * duty in the production code to save space in which case this function
0278          * may become less useful.
0279          */
0280     void draw(QPainter &psky, MeshBufNum_t bufNum = DRAW_BUF);
0281 
0282     bool inDraw() const { return m_inDraw; }
0283     void inDraw(bool inDraw) { m_inDraw = inDraw; }
0284 
0285   private:
0286     DrawID m_drawID;
0287     int errLimit { 0 };
0288     int m_debug { 0 };
0289 
0290     IndexHash indexHash;
0291     KSNumbers m_KSNumbers;
0292 
0293     bool m_inDraw { false };
0294     static int defaultLevel;
0295     static QMap<int, SkyMesh *> pinstances;
0296 };