Warning, file /education/kstars/kstars/projections/projector.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2010 Henry de Valence <hdevalence@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #ifdef KSTARS_LITE
0010 #include "skymaplite.h"
0011 #else
0012 #include "skymap.h"
0013 #endif
0014 #include "skyobjects/skypoint.h"
0015 
0016 #if __GNUC__ > 5
0017 #pragma GCC diagnostic push
0018 #pragma GCC diagnostic ignored "-Wignored-attributes"
0019 #endif
0020 #if __GNUC__ > 6
0021 #pragma GCC diagnostic ignored "-Wint-in-bool-context"
0022 #endif
0023 #include <Eigen/Core>
0024 #if __GNUC__ > 5
0025 #pragma GCC diagnostic pop
0026 #endif
0027 
0028 #include <QPointF>
0029 
0030 #include <cstddef>
0031 #include <cmath>
0032 
0033 class KStarsData;
0034 
0035 /** This is just a container that holds information needed to do projections. */
0036 class ViewParams
0037 {
0038     public:
0039         float width, height;
0040         float zoomFactor;
0041         bool useRefraction;
0042         bool useAltAz;
0043         bool fillGround; ///<If the ground is filled, then points below horizon are invisible
0044         SkyPoint *focus;
0045         ViewParams() : width(0), height(0), zoomFactor(0),
0046             useRefraction(false), useAltAz(false), fillGround(false),
0047             focus(nullptr) {}
0048 };
0049 
0050 /**
0051  * @class Projector
0052  *
0053  * The Projector class is the primary class that serves as an interface to handle projections.
0054  */
0055 class Projector
0056 {
0057         Q_GADGET
0058     public:
0059         /**
0060          * Constructor.
0061          *
0062          * @param p the ViewParams for this projection
0063          */
0064         explicit Projector(const ViewParams &p);
0065 
0066         virtual ~Projector() = default;
0067 
0068         /** Update cached values for projector */
0069         void setViewParams(const ViewParams &p);
0070         ViewParams viewParams() const
0071         {
0072             return m_vp;
0073         }
0074 
0075         enum Projection
0076         {
0077             Lambert,
0078             AzimuthalEquidistant,
0079             Orthographic,
0080             Equirectangular,
0081             Stereographic,
0082             Gnomonic,
0083             UnknownProjection
0084         };
0085         Q_ENUM(Projection)
0086 
0087         /** Return the type of this projection */
0088         Q_INVOKABLE virtual Projection type() const = 0;
0089 
0090         /** Return the FOV of this projection */
0091         double fov() const;
0092 
0093         /**
0094          * Check if the current point on screen is a valid point on the sky. This is needed
0095          * to avoid a crash of the program if the user clicks on a point outside the sky (the
0096          * corners of the sky map at the lowest zoom level are the invalid points).
0097          * @param p the screen pixel position
0098          */
0099         virtual bool unusablePoint(const QPointF &p) const;
0100 
0101         /**
0102          * Given the coordinates of the SkyPoint argument, determine the
0103          * pixel coordinates in the SkyMap.
0104          *
0105          * Since most of the projections used by KStars are very similar,
0106          * if this function were to be reimplemented in each projection subclass
0107          * we would end up changing maybe 5 or 6 lines out of 150.
0108          * Instead, we have a default implementation that uses the projectionK
0109          * and projectionL functions to take care of the differences between
0110          * e.g. Orthographic and Stereographic. There is also the cosMaxFieldAngle
0111          * function, which is used for testing whether a point is on the visible
0112          * part of the projection, and the radius function which gives the radius of
0113          * the projection in screen coordinates.
0114          *
0115          * While this seems ugly, it is less ugly than duplicating 150 loc to change 5.
0116          *
0117          * @return Eigen::Vector2f containing screen pixel x, y coordinates of SkyPoint.
0118          * @param o pointer to the SkyPoint for which to calculate x, y coordinates.
0119          * @param oRefract true = use Options::useRefraction() value.
0120          *   false = do not use refraction.  This argument is only needed
0121          *   for the Horizon, which should never be refracted.
0122          * @param onVisibleHemisphere pointer to a bool to indicate whether the point is
0123          *   on the visible part of the Celestial Sphere.
0124          */
0125         virtual Eigen::Vector2f toScreenVec(const SkyPoint *o, bool oRefract = true,
0126                                             bool *onVisibleHemisphere = nullptr) const;
0127 
0128         /**
0129          * This is exactly the same as toScreenVec but it returns a QPointF.
0130          * It just calls toScreenVec and converts the result.
0131          * @see toScreenVec()
0132          */
0133         QPointF toScreen(const SkyPoint *o, bool oRefract = true, bool *onVisibleHemisphere = nullptr) const;
0134 
0135         /**
0136          * @short Determine RA, Dec coordinates of the pixel at (dx, dy), which are the
0137          * screen pixel coordinate offsets from the center of the Sky pixmap.
0138          * @param p the screen pixel position to convert
0139          * @param LST pointer to the local sidereal time, as a dms object.
0140          * @param lat pointer to the current geographic laitude, as a dms object
0141          * @param onlyAltAz the returned SkyPoint's RA & DEC are not computed, only Alt/Az.
0142          */
0143         virtual SkyPoint fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz = false) const;
0144 
0145         /**
0146          * ASSUMES *p1 did not clip but *p2 did.  Returns the QPointF on the line
0147          * between *p1 and *p2 that just clips.
0148          */
0149         QPointF clipLine(SkyPoint *p1, SkyPoint *p2) const;
0150 
0151         /**
0152          * ASSUMES *p1 did not clip but *p2 did.  Returns the Eigen::Vector2f on the line
0153          * between *p1 and *p2 that just clips.
0154          */
0155         Eigen::Vector2f clipLineVec(SkyPoint *p1, SkyPoint *p2) const;
0156 
0157         /** Check whether the projected point is on-screen */
0158         bool onScreen(const QPointF &p) const;
0159         bool onScreen(const Eigen::Vector2f &p) const;
0160 
0161         /**
0162          * @short Determine if the skypoint p is likely to be visible in the display window.
0163          *
0164          * checkVisibility() is an optimization function.  It determines whether an object
0165          * appears within the bounds of the skymap window, and therefore should be drawn.
0166          * The idea is to save time by skipping objects which are off-screen, so it is
0167          * absolutely essential that checkVisibility() is significantly faster than
0168          * the computations required to draw the object to the screen.
0169          *
0170          * If the ground is to be filled, the function first checks whether the point is
0171          * below the horizon, because they will be covered by the ground anyways.
0172          * Importantly, it does not call the expensive EquatorialToHorizontal function.
0173          * This means that the horizontal coordinates MUST BE CORRECT! The vast majority
0174          * of points are already synchronized, so recomputing the horizontal coordinates is
0175          * a waste.
0176          *
0177          * The function then checks the difference between the Declination/Altitude
0178          * coordinate of the Focus position, and that of the point p.  If the absolute
0179          * value of this difference is larger than fov, then the function returns false.
0180          * For most configurations of the sky map window, this simple check is enough to
0181          * exclude a large number of objects.
0182          *
0183          * Next, it determines if one of the poles of the current Coordinate System
0184          * (Equatorial or Horizontal) is currently inside the sky map window.  This is
0185          * stored in the member variable 'bool SkyMap::isPoleVisible, and is set by the
0186          * function SkyMap::setMapGeometry(), which is called by SkyMap::paintEvent().
0187          * If a Pole is visible, then it will return true immediately.  The idea is that
0188          * when a pole is on-screen it is computationally expensive to determine whether
0189          * a particular position is on-screen or not: for many valid Dec/Alt values, *all*
0190          * values of RA/Az will indeed be onscreen, but for other valid Dec/Alt values,
0191          * only *most* RA/Az values are onscreen.  It is cheaper to simply accept all
0192          * "horizontal" RA/Az values, since we have already determined that they are
0193          * on-screen in the "vertical" Dec/Alt coordinate.
0194          *
0195          * Finally, if no Pole is onscreen, it checks the difference between the Focus
0196          * position's RA/Az coordinate and that of the point p.  If the absolute value of
0197          * this difference is larger than XMax, the function returns false.  Otherwise,
0198          * it returns true.
0199          *
0200          * @param p pointer to the skypoint to be checked.
0201          * @return true if the point p was found to be inside the Sky map window.
0202          * @see SkyMap::setMapGeometry()
0203          * @see SkyMap::fov()
0204          * @note If you are creating skypoints using equatorial coordinates, then
0205          * YOU MUST CALL EQUATORIALTOHORIZONTAL BEFORE THIS FUNCTION!
0206          */
0207         bool checkVisibility(const SkyPoint *p) const;
0208 
0209         /**
0210          * Determine the on-screen position angle of a SkyPont with recept with NCP.
0211          * This is the object's sky position angle (w.r.t. North).
0212          * of "North" at the position of the object (w.r.t. the screen Y-axis).
0213          * The latter is determined by constructing a test point with the same RA but
0214          * a slightly increased Dec as the object, and calculating the angle w.r.t. the
0215          * Y-axis of the line connecting the object to its test point.
0216          */
0217         double findNorthPA(const SkyPoint *o, float x, float y) const;
0218 
0219         /**
0220          * Determine the on-screen position angle of a SkyObject.  This is the sum
0221          * of the object's sky position angle (w.r.t. North), and the position angle
0222          * of "North" at the position of the object (w.r.t. the screen Y-axis).
0223          * The latter is determined by constructing a test point with the same RA but
0224          * a slightly increased Dec as the object, and calculating the angle w.r.t. the
0225          * Y-axis of the line connecting the object to its test point.
0226          */
0227         double findPA(const SkyObject *o, float x, float y) const;
0228 
0229         /**
0230          * Get the ground polygon
0231          * @param labelpoint This point will be set to something suitable for attaching a label
0232          * @param drawLabel this tells whether to draw a label.
0233          * @return the ground polygon
0234          */
0235         virtual QVector<Eigen::Vector2f> groundPoly(SkyPoint *labelpoint = nullptr, bool *drawLabel = nullptr) const;
0236 
0237         /**
0238          * @brief updateClipPoly calculate the clipping polygen given the current FOV.
0239          */
0240         virtual void updateClipPoly();
0241 
0242         /**
0243          * @return the clipping polygen covering the visible sky area. Anything outside this polygon is
0244          * clipped by QPainter.
0245          */
0246         virtual QPolygonF clipPoly() const;
0247 
0248     protected:
0249         /**
0250          * Get the radius of this projection's sky circle.
0251          * @return the radius in radians
0252          */
0253         virtual double radius() const
0254         {
0255             return 2 * M_PI;
0256         }
0257 
0258         /**
0259          * This function handles some of the projection-specific code.
0260          * @see toScreen()
0261          */
0262         virtual double projectionK(double x) const
0263         {
0264             return x;
0265         }
0266 
0267         /**
0268          * This function handles some of the projection-specific code.
0269          * @see toScreen()
0270          */
0271         virtual double projectionL(double x) const
0272         {
0273             return x;
0274         }
0275 
0276         /**
0277          * This function returns the cosine of the maximum field angle, i.e., the maximum angular
0278          * distance from the focus for which a point should be projected. Default is 0, i.e.,
0279          * 90 degrees.
0280          */
0281         virtual double cosMaxFieldAngle() const
0282         {
0283             return 0;
0284         }
0285 
0286         /**
0287          * Helper function for drawing ground.
0288          * @return the point with Alt = 0, az = @p az
0289          */
0290         static SkyPoint pointAt(double az);
0291 
0292         KStarsData *m_data { nullptr };
0293         ViewParams m_vp;
0294         double m_sinY0 { 0 };
0295         double m_cosY0 { 0 };
0296         double m_fov { 0 };
0297         QPolygonF m_clipPolygon;
0298 
0299     private:
0300         //Used by CheckVisibility
0301         double m_xrange { 0 };
0302         bool m_isPoleVisible { false };
0303 };