Kstars

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

KDE's Doxygen guidelines are available online.