Kstars

projector.h
1 /*
2  SPDX-FileCopyrightText: 2010 Henry de Valence <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #ifdef KSTARS_LITE
10 #include "skymaplite.h"
11 #else
12 #include "skymap.h"
13 #endif
14 #include "skyobjects/skypoint.h"
15 
16 #if __GNUC__ > 5
17 #pragma GCC diagnostic push
18 #pragma GCC diagnostic ignored "-Wignored-attributes"
19 #endif
20 #if __GNUC__ > 6
21 #pragma GCC diagnostic ignored "-Wint-in-bool-context"
22 #endif
23 #include <Eigen/Core>
24 #if __GNUC__ > 5
25 #pragma GCC diagnostic pop
26 #endif
27 
28 #include <QPointF>
29 
30 #include <cstddef>
31 #include <cmath>
32 
33 class KStarsData;
34 
35 /** This is just a container that holds information needed to do projections. */
37 {
38  public:
39  float width, height;
40  float zoomFactor;
41  CachingDms rotationAngle;
42  bool useRefraction;
43  bool useAltAz;
44  bool fillGround; ///<If the ground is filled, then points below horizon are invisible
45  SkyPoint *focus;
46  ViewParams() : width(0), height(0), zoomFactor(0), rotationAngle(0),
47  useRefraction(false), useAltAz(false), fillGround(false),
48  focus(nullptr) {}
49 };
50 
51 /**
52  * @class Projector
53  *
54  * The Projector class is the primary class that serves as an interface to handle projections.
55  */
56 class Projector
57 {
58  Q_GADGET
59  public:
60  /**
61  * Constructor.
62  *
63  * @param p the ViewParams for this projection
64  */
65  explicit Projector(const ViewParams &p);
66 
67  virtual ~Projector() = default;
68 
69  /** Update cached values for projector */
70  void setViewParams(const ViewParams &p);
71  ViewParams viewParams() const
72  {
73  return m_vp;
74  }
75 
76  enum Projection
77  {
78  Lambert,
79  AzimuthalEquidistant,
80  Orthographic,
81  Equirectangular,
82  Stereographic,
83  Gnomonic,
84  UnknownProjection
85  };
86  Q_ENUM(Projection)
87 
88  /** Return the type of this projection */
89  Q_INVOKABLE virtual Projection type() const = 0;
90 
91  /** Return the FOV of this projection */
92  double fov() const;
93 
94  /**
95  * Check if the current point on screen is a valid point on the sky. This is needed
96  * to avoid a crash of the program if the user clicks on a point outside the sky (the
97  * corners of the sky map at the lowest zoom level are the invalid points).
98  * @param p the screen pixel position
99  */
100  virtual bool unusablePoint(const QPointF &p) const;
101 
102  /**
103  * Given the coordinates of the SkyPoint argument, determine the
104  * pixel coordinates in the SkyMap.
105  *
106  * Since most of the projections used by KStars are very similar,
107  * if this function were to be reimplemented in each projection subclass
108  * we would end up changing maybe 5 or 6 lines out of 150.
109  * Instead, we have a default implementation that uses the projectionK
110  * and projectionL functions to take care of the differences between
111  * e.g. Orthographic and Stereographic. There is also the cosMaxFieldAngle
112  * function, which is used for testing whether a point is on the visible
113  * part of the projection, and the radius function which gives the radius of
114  * the projection in screen coordinates.
115  *
116  * While this seems ugly, it is less ugly than duplicating 150 loc to change 5.
117  *
118  * @return Eigen::Vector2f containing screen pixel x, y coordinates of SkyPoint.
119  * @param o pointer to the SkyPoint for which to calculate x, y coordinates.
120  * @param oRefract true = use Options::useRefraction() value.
121  * false = do not use refraction. This argument is only needed
122  * for the Horizon, which should never be refracted.
123  * @param onVisibleHemisphere pointer to a bool to indicate whether the point is
124  * on the visible part of the Celestial Sphere.
125  */
126  virtual Eigen::Vector2f toScreenVec(const SkyPoint *o, bool oRefract = true,
127  bool *onVisibleHemisphere = nullptr) const;
128 
129  /**
130  * This is exactly the same as toScreenVec but it returns a QPointF.
131  * It just calls toScreenVec and converts the result.
132  * @see toScreenVec()
133  */
134  QPointF toScreen(const SkyPoint *o, bool oRefract = true, bool *onVisibleHemisphere = nullptr) const;
135 
136  /**
137  * @short Determine RA, Dec coordinates of the pixel at (dx, dy), which are the
138  * screen pixel coordinate offsets from the center of the Sky pixmap.
139  * @param p the screen pixel position to convert
140  * @param LST pointer to the local sidereal time, as a dms object.
141  * @param lat pointer to the current geographic laitude, as a dms object
142  * @param onlyAltAz the returned SkyPoint's RA & DEC are not computed, only Alt/Az.
143  */
144  virtual SkyPoint fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz = false) const;
145 
146  /**
147  * ASSUMES *p1 did not clip but *p2 did. Returns the QPointF on the line
148  * between *p1 and *p2 that just clips.
149  */
150  QPointF clipLine(SkyPoint *p1, SkyPoint *p2) const;
151 
152  /**
153  * ASSUMES *p1 did not clip but *p2 did. Returns the Eigen::Vector2f on the line
154  * between *p1 and *p2 that just clips.
155  */
156  Eigen::Vector2f clipLineVec(SkyPoint *p1, SkyPoint *p2) const;
157 
158  /** Check whether the projected point is on-screen */
159  bool onScreen(const QPointF &p) const;
160  bool onScreen(const Eigen::Vector2f &p) const;
161 
162  /**
163  * @short Determine if the skypoint p is likely to be visible in the display window.
164  *
165  * checkVisibility() is an optimization function. It determines whether an object
166  * appears within the bounds of the skymap window, and therefore should be drawn.
167  * The idea is to save time by skipping objects which are off-screen, so it is
168  * absolutely essential that checkVisibility() is significantly faster than
169  * the computations required to draw the object to the screen.
170  *
171  * If the ground is to be filled, the function first checks whether the point is
172  * below the horizon, because they will be covered by the ground anyways.
173  * Importantly, it does not call the expensive EquatorialToHorizontal function.
174  * This means that the horizontal coordinates MUST BE CORRECT! The vast majority
175  * of points are already synchronized, so recomputing the horizontal coordinates is
176  * a waste.
177  *
178  * The function then checks the difference between the Declination/Altitude
179  * coordinate of the Focus position, and that of the point p. If the absolute
180  * value of this difference is larger than fov, then the function returns false.
181  * For most configurations of the sky map window, this simple check is enough to
182  * exclude a large number of objects.
183  *
184  * Next, it determines if one of the poles of the current Coordinate System
185  * (Equatorial or Horizontal) is currently inside the sky map window. This is
186  * stored in the member variable 'bool SkyMap::isPoleVisible, and is set by the
187  * function SkyMap::setMapGeometry(), which is called by SkyMap::paintEvent().
188  * If a Pole is visible, then it will return true immediately. The idea is that
189  * when a pole is on-screen it is computationally expensive to determine whether
190  * a particular position is on-screen or not: for many valid Dec/Alt values, *all*
191  * values of RA/Az will indeed be onscreen, but for other valid Dec/Alt values,
192  * only *most* RA/Az values are onscreen. It is cheaper to simply accept all
193  * "horizontal" RA/Az values, since we have already determined that they are
194  * on-screen in the "vertical" Dec/Alt coordinate.
195  *
196  * Finally, if no Pole is onscreen, it checks the difference between the Focus
197  * position's RA/Az coordinate and that of the point p. If the absolute value of
198  * this difference is larger than XMax, the function returns false. Otherwise,
199  * it returns true.
200  *
201  * @param p pointer to the skypoint to be checked.
202  * @return true if the point p was found to be inside the Sky map window.
203  * @see SkyMap::setMapGeometry()
204  * @see SkyMap::fov()
205  * @note If you are creating skypoints using equatorial coordinates, then
206  * YOU MUST CALL EQUATORIALTOHORIZONTAL BEFORE THIS FUNCTION!
207  */
208  bool checkVisibility(const SkyPoint *p) const;
209 
210  /**
211  * Determine the on-screen position angle of a SkyPont with recept with NCP.
212  * This is the object's sky position angle (w.r.t. North).
213  * of "North" at the position of the object (w.r.t. the screen Y-axis).
214  * The latter is determined by constructing a test point with the same RA but
215  * a slightly increased Dec as the object, and calculating the angle w.r.t. the
216  * Y-axis of the line connecting the object to its test point.
217  */
218  double findNorthPA(const SkyPoint *o, float x, float y) const;
219 
220  /**
221  * Determine the on-screen position angle of a SkyObject. This is the sum
222  * of the object's sky position angle (w.r.t. North), and the position angle
223  * of "North" at the position of the object (w.r.t. the screen Y-axis).
224  * The latter is determined by constructing a test point with the same RA but
225  * a slightly increased Dec as the object, and calculating the angle w.r.t. the
226  * Y-axis of the line connecting the object to its test point.
227  */
228  double findPA(const SkyObject *o, float x, float y) const;
229 
230  /**
231  * Determine the on-screen angle of a SkyPoint with respect to Zenith.
232  *
233  * @note Similar to @see findNorthPA
234  * @note It is assumed that EquatorialToHorizontal has been called on @p o
235  *
236  * @description This is determined by constructing a test
237  * point with the same Azimuth but a slightly increased
238  * Altitude, and calculating the angle w.r.t. the Y-axis of
239  * the line connecting the object to its test point.
240  */
241  double findZenithPA(const SkyPoint *o, float x, float y) const;
242 
243  /**
244  * Get the ground polygon
245  * @param labelpoint This point will be set to something suitable for attaching a label
246  * @param drawLabel this tells whether to draw a label.
247  * @return the ground polygon
248  */
249  virtual QVector<Eigen::Vector2f> groundPoly(SkyPoint *labelpoint = nullptr, bool *drawLabel = nullptr) const;
250 
251  /**
252  * @brief updateClipPoly calculate the clipping polygen given the current FOV.
253  */
254  virtual void updateClipPoly();
255 
256  /**
257  * @return the clipping polygen covering the visible sky area. Anything outside this polygon is
258  * clipped by QPainter.
259  */
260  virtual QPolygonF clipPoly() const;
261 
262  protected:
263  /**
264  * Get the radius of this projection's sky circle.
265  * @return the radius in radians
266  */
267  virtual double radius() const
268  {
269  return 2 * M_PI;
270  }
271 
272  /**
273  * This function handles some of the projection-specific code.
274  * @see toScreen()
275  */
276  virtual double projectionK(double x) const
277  {
278  return x;
279  }
280 
281  /**
282  * This function handles some of the projection-specific code.
283  * @see toScreen()
284  */
285  virtual double projectionL(double x) const
286  {
287  return x;
288  }
289 
290  /**
291  * This function returns the cosine of the maximum field angle, i.e., the maximum angular
292  * distance from the focus for which a point should be projected. Default is 0, i.e.,
293  * 90 degrees.
294  */
295  virtual double cosMaxFieldAngle() const
296  {
297  return 0;
298  }
299 
300  /**
301  * Transform proj (x, y) to screen (x, y) accounting for scale and rotation
302  *
303  * Transforms the Cartesian position given by the projector
304  * algorithm into the screen coordinate by applying the scale
305  * factor, rotation and shift from SkyMap origin
306  *
307  * rst stands for rotate-scale-translate
308  *
309  */
310  inline Eigen::Vector2f rst(double x, double y) const
311  {
312  return
313  {
314  m_vp.width / 2 - m_vp.zoomFactor * (x * m_vp.rotationAngle.cos() - y * m_vp.rotationAngle.sin()),
315  m_vp.height / 2 - m_vp.zoomFactor * (x * m_vp.rotationAngle.sin() + y * m_vp.rotationAngle.cos())
316  };
317  }
318 
319  /**
320  * Transform screen (x, y) to projector (x, y) accounting for scale, rotation
321  *
322  * Transforms the Cartesian position on the screen to the
323  * Cartesian position accepted by the projector algorithm by
324  * applying th escale factor, rotation and shift from SkyMap
325  * origin
326  *
327  * rst stands for rotate-scale-translate
328  *
329  * @see rst
330  */
331  inline Eigen::Vector2f derst(double x, double y) const
332  {
333  const double X = (m_vp.width / 2 - x) / m_vp.zoomFactor;
334  const double Y = (m_vp.height / 2 - y) / m_vp.zoomFactor;
335  return
336  {
337  m_vp.rotationAngle.cos() * X + m_vp.rotationAngle.sin() * Y,
338  -m_vp.rotationAngle.sin() * X + m_vp.rotationAngle.cos() * Y
339  };
340  }
341 
342  /**
343  * Helper function for drawing ground.
344  * @return the point with Alt = 0, az = @p az
345  */
346  static SkyPoint pointAt(double az);
347 
348  KStarsData *m_data { nullptr };
349  ViewParams m_vp;
350  double m_sinY0 { 0 };
351  double m_cosY0 { 0 };
352  double m_fov { 0 };
353  QPolygonF m_clipPolygon;
354 
355  private:
356  //Used by CheckVisibility
357  double m_xrange { 0 };
358  bool m_isPoleVisible { false };
359 };
double sin() const
Get the sine of this angle.
Definition: cachingdms.h:190
virtual void updateClipPoly()
updateClipPoly calculate the clipping polygen given the current FOV.
Definition: projector.cpp:406
double findPA(const SkyObject *o, float x, float y) const
Determine the on-screen position angle of a SkyObject.
Definition: projector.cpp:267
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
a dms subclass that caches its sine and cosine values every time the angle is changed.
Definition: cachingdms.h:18
virtual double projectionK(double x) const
This function handles some of the projection-specific code.
Definition: projector.h:276
Projector(const ViewParams &p)
Constructor.
Definition: projector.cpp:38
virtual Eigen::Vector2f toScreenVec(const SkyPoint *o, bool oRefract=true, bool *onVisibleHemisphere=nullptr) const
Given the coordinates of the SkyPoint argument, determine the pixel coordinates in the SkyMap.
Definition: projector.cpp:506
virtual double cosMaxFieldAngle() const
This function returns the cosine of the maximum field angle, i.e., the maximum angular distance from ...
Definition: projector.h:295
QPointF clipLine(SkyPoint *p1, SkyPoint *p2) const
ASSUMES *p1 did not clip but *p2 did.
Definition: projector.cpp:108
Eigen::Vector2f clipLineVec(SkyPoint *p1, SkyPoint *p2) const
ASSUMES *p1 did not clip but *p2 did.
Definition: projector.cpp:113
virtual Q_INVOKABLE Projection type() const =0
Return the type of this projection.
bool onScreen(const QPointF &p) const
Check whether the projected point is on-screen.
Definition: projector.cpp:98
Eigen::Vector2f derst(double x, double y) const
Transform screen (x, y) to projector (x, y) accounting for scale, rotation.
Definition: projector.h:331
virtual bool unusablePoint(const QPointF &p) const
Check if the current point on screen is a valid point on the sky.
Definition: projector.cpp:429
Eigen::Vector2f rst(double x, double y) const
Transform proj (x, y) to screen (x, y) accounting for scale and rotation.
Definition: projector.h:310
This is just a container that holds information needed to do projections.
Definition: projector.h:36
double cos() const
Get the cosine of this angle.
Definition: cachingdms.h:204
double findNorthPA(const SkyPoint *o, float x, float y) const
Determine the on-screen position angle of a SkyPont with recept with NCP.
Definition: projector.cpp:237
bool fillGround
If the ground is filled, then points below horizon are invisible.
Definition: projector.h:44
void setViewParams(const ViewParams &p)
Update cached values for projector.
Definition: projector.cpp:46
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
virtual QVector< Eigen::Vector2f > groundPoly(SkyPoint *labelpoint=nullptr, bool *drawLabel=nullptr) const
Get the ground polygon.
Definition: projector.cpp:305
double findZenithPA(const SkyPoint *o, float x, float y) const
Determine the on-screen angle of a SkyPoint with respect to Zenith.
Definition: projector.cpp:273
virtual SkyPoint fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz=false) const
Determine RA, Dec coordinates of the pixel at (dx, dy), which are the screen pixel coordinate offsets...
Definition: projector.cpp:449
double fov() const
Return the FOV of this projection.
Definition: projector.cpp:88
virtual QPolygonF clipPoly() const
Definition: projector.cpp:424
QPointF toScreen(const SkyPoint *o, bool oRefract=true, bool *onVisibleHemisphere=nullptr) const
This is exactly the same as toScreenVec but it returns a QPointF.
Definition: projector.cpp:93
virtual double projectionL(double x) const
This function handles some of the projection-specific code.
Definition: projector.h:285
static SkyPoint pointAt(double az)
Helper function for drawing ground.
Definition: projector.cpp:29
Information about an object in the sky.
Definition: skyobject.h:41
bool checkVisibility(const SkyPoint *p) const
Determine if the skypoint p is likely to be visible in the display window.
Definition: projector.cpp:183
virtual double radius() const
Get the radius of this projection's sky circle.
Definition: projector.h:267
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 04:02:42 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.