Kstars

hipsfinder.cpp
1/*
2 SPDX-FileCopyrightText: 2021 Jasem Mutlaq
3
4 Static version of the HIPS Renderer for a single point in the sky.
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "hipsfinder.h"
10
11#include "kstars_debug.h"
12#include "Options.h"
13#include "kspaths.h"
14#include "projections/projector.h"
15#include "projections/lambertprojector.h"
16
17///////////////////////////////////////////////////////////////////////////////////////////
18///
19///////////////////////////////////////////////////////////////////////////////////////////
20HIPSFinder * HIPSFinder::m_Instance = nullptr;
21
22///////////////////////////////////////////////////////////////////////////////////////////
23///
24///////////////////////////////////////////////////////////////////////////////////////////
25HIPSFinder *HIPSFinder::Instance()
26{
27 if (m_Instance == nullptr)
28 {
29 m_Instance = new HIPSFinder();
30 }
31
32 return m_Instance;
33}
34
35///////////////////////////////////////////////////////////////////////////////////////////
36///
37///////////////////////////////////////////////////////////////////////////////////////////
38HIPSFinder::HIPSFinder()
39{
40 m_ScanRender.reset(new ScanRender());
41 m_HEALpix.reset(new HEALPix());
42}
43
44///////////////////////////////////////////////////////////////////////////////////////////
45/// Static
46///////////////////////////////////////////////////////////////////////////////////////////
47bool HIPSFinder::render(SkyPoint *center, uint8_t level, double zoom, QImage *destinationImage, double &fov_w,
48 double &fov_h)
49{
50 double ra = center->ra0().radians();
51 double de = center->dec0().radians();
52 // do we need this? or updateCoords?
53 //center.catalogueCoord(KStarsData::Instance()->updateNum()->julianDay());
54
55 if (std::isnan(ra) || std::isnan(de))
56 {
57 qCWarning(KSTARS) << "NAN Center, HiPS rendering failed.";
58 return false;
59 }
60
61 m_RenderedMap.clear();
62
63 // Setup sample projector
64 ViewParams viewParams;
65 viewParams.width = destinationImage->width();
66 viewParams.height = destinationImage->height();
67 viewParams.fillGround = false;
68 viewParams.useAltAz = false;
69 viewParams.zoomFactor = zoom;
70 viewParams.focus = center;
71
72 m_Projector.reset(new LambertProjector(viewParams));
73
74 // Get the ID of the face at this level containing the coordinates.
75 int centerPix = m_HEALpix->getPix(level, ra, de);
76
77 SkyPoint cornerSkyCoords[4];
78 QPointF tileLine[2];
79
80 // Get corners for this face
81 m_HEALpix->getCornerPoints(level, centerPix, cornerSkyCoords);
82
83 fov_w = cornerSkyCoords[0].angularDistanceTo(&cornerSkyCoords[1]).Degrees();
84 fov_h = cornerSkyCoords[1].angularDistanceTo(&cornerSkyCoords[2]).Degrees();
85
86 // Map the tile lines to the corners
87 for (int i = 0; i < 2; i++)
88 tileLine[i] = m_Projector->toScreen(&cornerSkyCoords[i]);
89
90 int size = std::sqrt(std::pow(tileLine[0].x() - tileLine[1].x(), 2) + std::pow(tileLine[0].y() - tileLine[1].y(), 2));
91 if (size < 0)
92 size = HIPSManager::Instance()->getCurrentTileWidth();
93
94 m_ScanRender->setBilinearInterpolationEnabled(size >= HIPSManager::Instance()->getCurrentTileWidth());
95
96 renderRec(level, centerPix, destinationImage);
97
98 return !m_RenderedMap.isEmpty();
99}
100
101///////////////////////////////////////////////////////////////////////////////////////////
102/// Static
103///////////////////////////////////////////////////////////////////////////////////////////
104bool HIPSFinder::renderFOV(SkyPoint *center, double fov_radius, double rotation, QImage *destinationImage)
105{
106 double ra = center->ra0().radians();
107 double de = center->dec0().radians();
108 // do we need this? or updateCoords?
109 //center.catalogueCoord(KStarsData::Instance()->updateNum()->julianDay());
110
111 if (std::isnan(ra) || std::isnan(de))
112 {
113 qCWarning(KSTARS) << "NAN Center, HiPS rendering failed.";
114 return false;
115 }
116
117 m_RenderedMap.clear();
118
119 auto width = destinationImage->width();
120 auto height = destinationImage->height();
121 auto zoom = sqrt(width * width + height * height) / (fov_radius * 2 * M_PI / 180.0);
122
123 // Setup sample projector
124 ViewParams viewParams;
125 viewParams.width = width;
126 viewParams.height = height;
127 viewParams.fillGround = false;
128 viewParams.useAltAz = false;
129 viewParams.zoomFactor = zoom;
130 viewParams.rotationAngle = dms(rotation);
131 viewParams.focus = center;
132
133 m_Projector.reset(new LambertProjector(viewParams));
134
135 uint8_t level = 1;
136
137 // Min FOV in Degrees
138 double minfov = 58.5;
139 double fov = m_Projector->fov() * width / height;
140
141 // Find suitable level for current FOV
142 while(fov < minfov)
143 {
144 minfov /= 2;
145 level++;
146 }
147
148 // We need this in case of offline storage missing a few levels.
149 level = HIPSManager::Instance()->getUsableOfflineLevel(level);
150
151 // Get the ID of the face at this level containing the coordinates.
152 int centerPix = m_HEALpix->getPix(level, ra, de);
153
154 m_ScanRender->setBilinearInterpolationEnabled(Options::hIPSBiLinearInterpolation());
155
156 renderRec(level, centerPix, destinationImage);
157
158 return !m_RenderedMap.isEmpty();
159}
160
161
162///////////////////////////////////////////////////////////////////////////////////////////
163/// Static
164///////////////////////////////////////////////////////////////////////////////////////////
165void HIPSFinder::renderRec(uint8_t level, int pix, QImage *destinationImage)
166{
167 if (m_RenderedMap.contains(pix))
168 return;
169
170 if (renderPix(level, pix, destinationImage))
171 {
172 m_RenderedMap.insert(pix);
173 int dirs[8];
174 int nside = 1 << level;
175
176 m_HEALpix->neighbours(nside, pix, dirs);
177
178 renderRec(level, dirs[0], destinationImage);
179 renderRec(level, dirs[2], destinationImage);
180 renderRec(level, dirs[4], destinationImage);
181 renderRec(level, dirs[6], destinationImage);
182 }
183}
184
185///////////////////////////////////////////////////////////////////////////////////////////
186///
187///////////////////////////////////////////////////////////////////////////////////////////
188bool HIPSFinder::renderPix(int level, int pix, QImage *destinationImage)
189{
190 SkyPoint cornerSkyCoords[4];
191 QPointF cornerScreenCoords[4];
192 bool isVisible = false;
193
194 m_HEALpix->getCornerPoints(level, pix, cornerSkyCoords);
195
196 for (int i = 0; i < 4; i++)
197 {
198 cornerScreenCoords[i] = m_Projector->toScreen(&cornerSkyCoords[i]);
199 isVisible |= m_Projector->checkVisibility(&cornerSkyCoords[i]);
200 }
201
202 if (isVisible)
203 {
204 int dir = (pix / 10000) * 10000;
206 QString("/HIPS/Norder%1/Dir%2/Npix%3.jpg").arg(level).arg(dir).arg(pix));
207 QImage sourceImage(path);
208
209 if (!sourceImage.isNull())
210 {
211 QPointF uv[16][4] = {{QPointF(.25, .25), QPointF(0.25, 0), QPointF(0, .0), QPointF(0, .25)},
212 {QPointF(.25, .5), QPointF(0.25, 0.25), QPointF(0, .25), QPointF(0, .5)},
213 {QPointF(.5, .25), QPointF(0.5, 0), QPointF(.25, .0), QPointF(.25, .25)},
214 {QPointF(.5, .5), QPointF(0.5, 0.25), QPointF(.25, .25), QPointF(.25, .5)},
215
216 {QPointF(.25, .75), QPointF(0.25, 0.5), QPointF(0, 0.5), QPointF(0, .75)},
217 {QPointF(.25, 1), QPointF(0.25, 0.75), QPointF(0, .75), QPointF(0, 1)},
218 {QPointF(.5, .75), QPointF(0.5, 0.5), QPointF(.25, .5), QPointF(.25, .75)},
219 {QPointF(.5, 1), QPointF(0.5, 0.75), QPointF(.25, .75), QPointF(.25, 1)},
220
221 {QPointF(.75, .25), QPointF(0.75, 0), QPointF(0.5, .0), QPointF(0.5, .25)},
222 {QPointF(.75, .5), QPointF(0.75, 0.25), QPointF(0.5, .25), QPointF(0.5, .5)},
223 {QPointF(1, .25), QPointF(1, 0), QPointF(.75, .0), QPointF(.75, .25)},
224 {QPointF(1, .5), QPointF(1, 0.25), QPointF(.75, .25), QPointF(.75, .5)},
225
226 {QPointF(.75, .75), QPointF(0.75, 0.5), QPointF(0.5, .5), QPointF(0.5, .75)},
227 {QPointF(.75, 1), QPointF(0.75, 0.75), QPointF(0.5, .75), QPointF(0.5, 1)},
228 {QPointF(1, .75), QPointF(1, 0.5), QPointF(.75, .5), QPointF(.75, .75)},
229 {QPointF(1, 1), QPointF(1, 0.75), QPointF(.75, .75), QPointF(.75, 1)},
230 };
231
232 int childPixelID[4];
233
234 // Find all the 4 children of the current pixel
235 m_HEALpix->getPixChilds(pix, childPixelID);
236
237 int j = 0;
238 for (int id : childPixelID)
239 {
240 int grandChildPixelID[4];
241 // Find the children of this child (i.e. grand child)
242 // Then we have 4x4 pixels under the primary pixel
243 // The image is interpolated and rendered over these pixels
244 // coordinate to minimize any distortions due to the projection
245 // system.
246 m_HEALpix->getPixChilds(id, grandChildPixelID);
247
248 QPointF fineScreenCoords[4];
249
250 for (int id2 : grandChildPixelID)
251 {
252 SkyPoint fineSkyPoints[4];
253 m_HEALpix->getCornerPoints(level + 2, id2, fineSkyPoints);
254
255 for (int i = 0; i < 4; i++)
256 fineScreenCoords[i] = m_Projector->toScreen(&fineSkyPoints[i]);
257
258 m_ScanRender->renderPolygon(3, fineScreenCoords, destinationImage, &sourceImage, uv[j]);
259 j++;
260 }
261 }
262
263 return true;
264 }
265 }
266
267 return false;
268}
Implememntation of Lambert azimuthal equal-area projection
The sky coordinates of a point in the sky.
Definition skypoint.h:45
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
Definition skypoint.cpp:899
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
QString path(const QString &relativePath)
QStringView level(QStringView ifopt)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
int height() const const
int width() const const
void reset(T *other)
void clear()
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
bool isEmpty() const const
QTextStream & center(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.