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
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 const auto LST = data->lst();
73 const auto lat = data->geo()->lat();
74 const auto jdf = data->djd();
75
76 if (m_vp.useAltAz)
77 {
78 dms az, alt;
79 dx = -1.0 * dx; //Azimuth goes in opposite direction compared to RA
80 az.setRadians(dx + m_vp.focus->az().radians());
81 alt.setRadians(dy + SkyPoint::refract(m_vp.focus->alt(), m_vp.useRefraction).radians());
82 result.setAz(az.reduce());
83 if (m_vp.useRefraction)
84 alt = SkyPoint::unrefract(alt);
85 result.setAlt(alt);
86 if (onlyAltAz)
87 return result;
88 result.HorizontalToEquatorialICRS(LST, lat, jdf);
89 return result;
90 }
91 else
92 {
93 dms ra, dec;
94 ra.setRadians(dx + m_vp.focus->ra().radians());
95 dec.setRadians(dy + m_vp.focus->dec().radians());
96 result.set(ra.reduce(), dec);
97 SkyPoint p(ra, dec);
98 p.catalogueCoord(jdf);
99 result.setRA0(p.ra0());
100 result.setDec0(p.dec0());
101 result.EquatorialToHorizontal(LST, lat);
102 return result;
103 }
104}
105
107{
108 auto p_ = derst(p.x(), p.y());
109 double dx = p_[0];
110 double dy = p_[1];
111 return (dx * dx > M_PI * M_PI / 4.0) || (dy * dy > M_PI * M_PI / 4.0);
112}
113
115{
116 float x0 = m_vp.width / 2.;
117 if (m_vp.useAltAz)
118 {
119 float dX = M_PI;
120
121 // N.B. alt ranges from -π/2 to π/2, but the focus can be at
122 // either extreme, so the Y-range of the map is actually -π to
123 // π -- asimha
124 float dY = M_PI;
125
126 SkyPoint belowFocus;
127 belowFocus.setAz(m_vp.focus->az().Degrees());
128 belowFocus.setAlt(0.0);
129
130 // Compute the ends of the horizon line
131 Eigen::Vector2f obf = toScreenVec(&belowFocus, false);
132 auto obf_derst = derst(obf.x(), obf.y());
133 auto corner1 = rst(obf_derst[0] - dX,
134 obf_derst[1]);
135 auto corner2 = rst(obf_derst[0] + dX,
136 obf_derst[1]);
137
138 auto corner3 = rst(obf_derst[0] + dX,
139 -dY);
140 auto corner4 = rst(obf_derst[0] - dX,
141 -dY);
142
144 //Construct the ground polygon, which is a simple rectangle in this case
145 ground << corner1
146 << corner2;
147 if (m_vp.fillGround) {
148 ground << corner3
149 << corner4;
150 }
151
152 if (labelpoint)
153 {
154 auto pLabel_ = corner2 - 50. * (corner1 - corner2).normalized();
155 QPointF pLabel(pLabel_[0], pLabel_[1]);
156 KStarsData *data = KStarsData::Instance();
157 *labelpoint = fromScreen(pLabel, data);
158 }
159 if (drawLabel)
160 *drawLabel = true;
161
162 return ground;
163 }
164 else
165 {
166 float dX = m_vp.zoomFactor * M_PI; // RA ranges from 0 to 2π, so half-length is π
167 float dY = m_vp.zoomFactor * M_PI;
169
170 static const QString horizonLabel = i18n("Horizon");
171 float marginLeft, marginRight, marginTop, marginBot;
172 SkyLabeler::Instance()->getMargins(horizonLabel, &marginLeft, &marginRight, &marginTop, &marginBot);
173
174 double daz = 180.;
175 double faz = m_vp.focus->az().Degrees();
176 double az1 = faz - daz;
177 double az2 = faz + daz;
178
179 bool inverted = ((m_vp.rotationAngle + 90.0_deg).reduce().Degrees() > 180.);
180 bool allGround = true;
181 bool allSky = true;
182
183 double inc = 1.0;
184 //Add points along horizon
185 std::vector<Eigen::Vector2f> groundPoints;
186 for (double az = az1; az <= az2 + inc; az += inc)
187 {
188 SkyPoint p = pointAt(az);
189 bool visible = false;
190 Eigen::Vector2f o = toScreenVec(&p, false, &visible);
191 if (visible)
192 {
193 groundPoints.push_back(o);
194 //Set the label point if this point is onscreen
195 if (labelpoint && o.x() < marginRight && o.y() > marginTop && o.y() < marginBot)
196 *labelpoint = p;
197
198 if (o.y() > 0.)
199 allGround = false;
200 if (o.y() < m_vp.height)
201 allSky = false;
202 }
203 }
204
205 if (inverted)
206 std::swap(allGround, allSky);
207
208 if (allSky)
209 {
210 if (drawLabel)
211 *drawLabel = false;
213 }
214
215 const Eigen::Vector2f slope {m_vp.rotationAngle.cos(), m_vp.rotationAngle.sin()};
216 std::sort(groundPoints.begin(), groundPoints.end(), [&](const Eigen::Vector2f & a,
217 const Eigen::Vector2f & b)
218 {
219 return a.dot(slope) < b.dot(slope);
220 });
221
222 for (auto point : groundPoints)
223 {
224 ground.append(point);
225 }
226
227 // if (allGround)
228 // {
229 // ground.clear();
230 // ground.append(Eigen::Vector2f(x0 - dX, y0 - dY));
231 // ground.append(Eigen::Vector2f(x0 + dX, y0 - dY));
232 // ground.append(Eigen::Vector2f(x0 + dX, y0 + dY));
233 // ground.append(Eigen::Vector2f(x0 - dX, y0 + dY));
234 // if (drawLabel)
235 // *drawLabel = false;
236 // return ground;
237 // }
238
239 if (labelpoint)
240 {
241 QPointF pLabel(x0 - dX - 50., ground.last().y());
242 KStarsData *data = KStarsData::Instance();
243 *labelpoint = fromScreen(pLabel, data);
244 }
245 if (drawLabel)
246 *drawLabel = true;
247
248 const auto lat = KStarsData::Instance()->geo()->lat();
249 const Eigen::Vector2f perpendicular {-m_vp.rotationAngle.sin(), m_vp.rotationAngle.cos()};
250 const double sgn = (lat->Degrees() > 0 ? 1. : -1.);
251 if (m_vp.fillGround)
252 {
253 ground.append(groundPoints.back() + perpendicular * sgn * dY);
254 ground.append(groundPoints.front() + perpendicular * sgn * dY);
255 }
256 return ground;
257 }
258}
259
261{
262 m_clipPolygon.clear();
263
264 m_clipPolygon << QPointF(0, 0) << QPointF(m_vp.width, 0) << QPointF(m_vp.width, m_vp.height)
265 << QPointF(0, m_vp.height);
266}
SkyPoint fromScreen(const QPointF &p, KStarsData *data, 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:74
CachingDms * lst()
Definition kstarsdata.h:232
long double djd() const
Definition kstarsdata.h:165
GeoLocation * geo()
Definition kstarsdata.h:238
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:335
Eigen::Vector2f rst(double x, double y) const
Transform proj (x, y) to screen (x, y) accounting for scale and rotation.
Definition projector.h:313
static SkyPoint pointAt(double az)
Helper function for drawing ground.
Definition projector.cpp:29
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 & ra0() const
Definition skypoint.h:251
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
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
Definition skypoint.h:94
static double unrefract(const double alt, bool conditional=true)
Remove refraction correction, depending on conditional.
void HorizontalToEquatorialICRS(const dms *LST, const dms *lat, const long double jdf)
Determine the (RA, Dec) coordinates of the SkyPoint from its (Altitude, Azimuth) coordinates,...
Definition skypoint.cpp:187
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 setAz(dms az)
Sets Az, the Azimuth.
Definition skypoint.h:230
const CachingDms & dec0() const
Definition skypoint.h:257
void setDec0(dms d)
Sets Dec0, the catalog Declination.
Definition skypoint.h:119
SkyPoint catalogueCoord(long double jdf)
Computes the J2000.0 catalogue coordinates for this SkyPoint using the epoch removing aberration,...
Definition skypoint.cpp:730
This is just a container that holds information needed to do projections.
Definition projector.h:37
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
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-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:53:02 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.