Kstars

equirectangularprojector.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Henry de Valence <hdevalence@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "equirectangularprojector.h"
8
9#include "ksutils.h"
10#include "kstarsdata.h"
11#include "skycomponents/skylabeler.h"
12
13EquirectangularProjector::EquirectangularProjector(const ViewParams &p) : Projector(p)
14{
15 updateClipPoly();
16}
17
18Projector::Projection EquirectangularProjector::type() const
19{
20 return Equirectangular;
21}
22
24{
25 return 1.0;
26}
27
28Eigen::Vector2f EquirectangularProjector::toScreenVec(const SkyPoint *o, bool oRefract, bool *onVisibleHemisphere) const
29{
30 double Y, dX;
31 Eigen::Vector2f p;
32 double x, y;
33
34 oRefract &= m_vp.useRefraction;
35 if (m_vp.useAltAz)
36 {
37 double Y0;
38 Y = SkyPoint::refract(o->alt(), oRefract).radians(); //account for atmospheric refraction
39 Y0 = SkyPoint::refract(m_vp.focus->alt(), oRefract).radians();
40 dX = m_vp.focus->az().reduce().radians() - o->az().reduce().radians();
41
42 y = (Y - Y0);
43 }
44 else
45 {
46 dX = o->ra().reduce().radians() - m_vp.focus->ra().reduce().radians();
47 Y = o->dec().radians();
48 y = (Y - m_vp.focus->dec().radians());
49 }
50
51 dX = KSUtils::reduceAngle(dX, -dms::PI, dms::PI);
52
53 x = dX;
54
55 p = rst(x, y);
56
57 if (onVisibleHemisphere)
58 *onVisibleHemisphere = (p[0] > 0 && p[0] < m_vp.width);
59
60 return p;
61}
62
63SkyPoint EquirectangularProjector::fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz) const
64{
65 SkyPoint result;
66
67 //Convert pixel position to x and y offsets in radians
68 auto p_ = derst(p.x(), p.y());
69 double dx = p_[0];
70 double dy = p_[1];
71
72 if (m_vp.useAltAz)
73 {
74 dms az, alt;
75 dx = -1.0 * dx; //Azimuth goes in opposite direction compared to RA
76 az.setRadians(dx + m_vp.focus->az().radians());
77 alt.setRadians(dy + SkyPoint::refract(m_vp.focus->alt(), m_vp.useRefraction).radians());
78 result.setAz(az.reduce());
79 if (m_vp.useRefraction)
80 alt = SkyPoint::unrefract(alt);
81 result.setAlt(alt);
82 if (!onlyAltAz)
83 result.HorizontalToEquatorial(LST, lat);
84 return result;
85 }
86 else
87 {
88 dms ra, dec;
89 ra.setRadians(dx + m_vp.focus->ra().radians());
90 dec.setRadians(dy + m_vp.focus->dec().radians());
91 result.set(ra.reduce(), dec);
92 result.EquatorialToHorizontal(LST, lat);
93 return result;
94 }
95}
96
98{
99 auto p_ = derst(p.x(), p.y());
100 double dx = p_[0];
101 double dy = p_[1];
102 return (dx * dx > M_PI * M_PI / 4.0) || (dy * dy > M_PI * M_PI / 4.0);
103}
104
106{
107 float x0 = m_vp.width / 2.;
108 if (m_vp.useAltAz)
109 {
110 float dX = M_PI;
111
112 // N.B. alt ranges from -π/2 to π/2, but the focus can be at
113 // either extreme, so the Y-range of the map is actually -π to
114 // π -- asimha
115 float dY = M_PI;
116
117 SkyPoint belowFocus;
118 belowFocus.setAz(m_vp.focus->az().Degrees());
119 belowFocus.setAlt(0.0);
120
121 // Compute the ends of the horizon line
122 Eigen::Vector2f obf = toScreenVec(&belowFocus, false);
123 auto obf_derst = derst(obf.x(), obf.y());
124 auto corner1 = rst(obf_derst[0] - dX,
125 obf_derst[1]);
126 auto corner2 = rst(obf_derst[0] + dX,
127 obf_derst[1]);
128
129 auto corner3 = rst(obf_derst[0] + dX,
130 -dY);
131 auto corner4 = rst(obf_derst[0] - dX,
132 -dY);
133
135 //Construct the ground polygon, which is a simple rectangle in this case
136 ground << corner1
137 << corner2;
138 if (m_vp.fillGround) {
139 ground << corner3
140 << corner4;
141 }
142
143 if (labelpoint)
144 {
145 auto pLabel_ = corner2 - 50. * (corner1 - corner2).normalized();
146 QPointF pLabel(pLabel_[0], pLabel_[1]);
147 KStarsData *data = KStarsData::Instance();
148 *labelpoint = fromScreen(pLabel, data->lst(), data->geo()->lat());
149 }
150 if (drawLabel)
151 *drawLabel = true;
152
153 return ground;
154 }
155 else
156 {
157 float dX = m_vp.zoomFactor * M_PI; // RA ranges from 0 to 2π, so half-length is π
158 float dY = m_vp.zoomFactor * M_PI;
160
161 static const QString horizonLabel = i18n("Horizon");
162 float marginLeft, marginRight, marginTop, marginBot;
163 SkyLabeler::Instance()->getMargins(horizonLabel, &marginLeft, &marginRight, &marginTop, &marginBot);
164
165 double daz = 180.;
166 double faz = m_vp.focus->az().Degrees();
167 double az1 = faz - daz;
168 double az2 = faz + daz;
169
170 bool inverted = ((m_vp.rotationAngle + 90.0_deg).reduce().Degrees() > 180.);
171 bool allGround = true;
172 bool allSky = true;
173
174 double inc = 1.0;
175 //Add points along horizon
176 std::vector<Eigen::Vector2f> groundPoints;
177 for (double az = az1; az <= az2 + inc; az += inc)
178 {
179 SkyPoint p = pointAt(az);
180 bool visible = false;
181 Eigen::Vector2f o = toScreenVec(&p, false, &visible);
182 if (visible)
183 {
184 groundPoints.push_back(o);
185 //Set the label point if this point is onscreen
186 if (labelpoint && o.x() < marginRight && o.y() > marginTop && o.y() < marginBot)
187 *labelpoint = p;
188
189 if (o.y() > 0.)
190 allGround = false;
191 if (o.y() < m_vp.height)
192 allSky = false;
193 }
194 }
195
196 if (inverted)
197 std::swap(allGround, allSky);
198
199 if (allSky)
200 {
201 if (drawLabel)
202 *drawLabel = false;
204 }
205
206 const Eigen::Vector2f slope {m_vp.rotationAngle.cos(), m_vp.rotationAngle.sin()};
207 std::sort(groundPoints.begin(), groundPoints.end(), [&](const Eigen::Vector2f & a,
208 const Eigen::Vector2f & b)
209 {
210 return a.dot(slope) < b.dot(slope);
211 });
212
213 for (auto point : groundPoints)
214 {
215 ground.append(point);
216 }
217
218 // if (allGround)
219 // {
220 // ground.clear();
221 // ground.append(Eigen::Vector2f(x0 - dX, y0 - dY));
222 // ground.append(Eigen::Vector2f(x0 + dX, y0 - dY));
223 // ground.append(Eigen::Vector2f(x0 + dX, y0 + dY));
224 // ground.append(Eigen::Vector2f(x0 - dX, y0 + dY));
225 // if (drawLabel)
226 // *drawLabel = false;
227 // return ground;
228 // }
229
230 if (labelpoint)
231 {
232 QPointF pLabel(x0 - dX - 50., ground.last().y());
233 KStarsData *data = KStarsData::Instance();
234 *labelpoint = fromScreen(pLabel, data->lst(), data->geo()->lat());
235 }
236 if (drawLabel)
237 *drawLabel = true;
238
239 const auto lat = KStarsData::Instance()->geo()->lat();
240 const Eigen::Vector2f perpendicular {-m_vp.rotationAngle.sin(), m_vp.rotationAngle.cos()};
241 const double sgn = (lat->Degrees() > 0 ? 1. : -1.);
242 if (m_vp.fillGround)
243 {
244 ground.append(groundPoints.back() + perpendicular * sgn * dY);
245 ground.append(groundPoints.front() + perpendicular * sgn * dY);
246 }
247 return ground;
248 }
249}
250
252{
253 m_clipPolygon.clear();
254
255 m_clipPolygon << QPointF(0, 0) << QPointF(m_vp.width, 0) << QPointF(m_vp.width, m_vp.height)
256 << QPointF(0, m_vp.height);
257}
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
SkyPoint fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz=false) const override
Determine RA, Dec coordinates of the pixel at (dx, dy), which are the screen pixel coordinate offsets...
void updateClipPoly() override
updateClipPoly calculate the clipping polygen given the current FOV.
Projection type() const override
Return the type of this projection.
double radius() const override
Get the radius of this projection's sky circle.
Eigen::Vector2f toScreenVec(const SkyPoint *o, bool oRefract=true, bool *onVisibleHemisphere=nullptr) const override
Given the coordinates of the SkyPoint argument, determine the pixel coordinates in the SkyMap.
bool unusablePoint(const QPointF &p) const override
Check if the current point on screen is a valid point on the sky.
QVector< Eigen::Vector2f > groundPoly(SkyPoint *labelpoint=nullptr, bool *drawLabel=nullptr) const override
Get the ground polygon.
const CachingDms * lat() const
Definition geolocation.h:70
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
CachingDms * lst()
Definition kstarsdata.h:224
GeoLocation * geo()
Definition kstarsdata.h:230
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
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
static SkyPoint pointAt(double az)
Helper function for drawing ground.
Definition projector.cpp:29
void getMargins(const QString &text, float *left, float *right, float *top, float *bot)
sets four margins for help in keeping labels entirely on the screen.
The sky coordinates of a point in the sky.
Definition skypoint.h:45
static double refract(const double alt, bool conditional=true)
Apply refraction correction to altitude, depending on conditional.
const CachingDms & dec() const
Definition skypoint.h:269
const CachingDms & ra() const
Definition skypoint.h:263
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
Definition skypoint.cpp:77
static double unrefract(const double alt, bool conditional=true)
Remove refraction correction, depending on conditional.
const dms & az() const
Definition skypoint.h:275
void set(const dms &r, const dms &d)
Sets RA, Dec and RA0, Dec0 according to arguments.
Definition skypoint.cpp:63
void setAlt(dms alt)
Sets Alt, the Altitude.
Definition skypoint.h:194
const dms & alt() const
Definition skypoint.h:281
void HorizontalToEquatorial(const dms *LST, const dms *lat)
Determine the (RA, Dec) coordinates of the SkyPoint from its (Altitude, Azimuth) coordinates,...
Definition skypoint.cpp:143
void setAz(dms az)
Sets Az, the Azimuth.
Definition skypoint.h:230
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
const dms reduce() const
return the equivalent angle between 0 and 360 degrees.
Definition dms.cpp:251
static constexpr double PI
PI is a const static member; it's public so that it can be used anywhere, as long as dms....
Definition dms.h:385
double radians() const
Express the angle in radians.
Definition dms.h:325
virtual void setRadians(const double &Rad)
Set angle according to the argument, in radians.
Definition dms.h:333
const double & Degrees() const
Definition dms.h:141
QString i18n(const char *text, const TYPE &arg...)
void append(QList< T > &&value)
void clear()
T & last()
qreal x() const const
qreal y() const const
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.