Kstars

hipsrenderer.cpp
1/*
2 SPDX-FileCopyrightText: 2015-2017 Pavel Mraz
3
4 SPDX-FileCopyrightText: 2017 Jasem Mutlaq
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "hipsrenderer.h"
10
11#include "colorscheme.h"
12#include "kstars_debug.h"
13#include "Options.h"
14#include "skymap.h"
15#include "skyqpainter.h"
16#include "projections/projector.h"
17
18HIPSRenderer::HIPSRenderer()
19{
20 m_scanRender.reset(new ScanRender());
21 m_HEALpix.reset(new HEALPix());
22}
23
24bool HIPSRenderer::render(uint16_t w, uint16_t h, QImage *hipsImage, const Projector *m_proj)
25{
26 gridColor = KStarsData::Instance()->colorScheme()->colorNamed("HIPSGridColor").name();
27
28 m_projector = m_proj;
29
30 int level = 1;
31
32 // Min FOV in Degrees
33 double minfov = 58.5;
34 double fov = m_proj->fov() * w / h;
35
36 // Find suitable level for current FOV
37 while( level < HIPSManager::Instance()->getCurrentOrder() && fov < minfov)
38 {
39 minfov /= 2;
40 level++;
41 }
42
43 // We need this in case of offline storage missing a few levels.
44 level = HIPSManager::Instance()->getUsableLevel(level);
45
46 m_renderedMap.clear();
47 m_rendered = 0;
48 m_blocks = 0;
49 m_size = 0;
50
51 SkyPoint center = SkyMap::Instance()->getCenterPoint();
52 //center.deprecess(KStarsData::Instance()->updateNum());
53 center.catalogueCoord(KStarsData::Instance()->updateNum()->julianDay());
54
55 double ra = center.ra0().radians();
56 double de = center.dec0().radians();
57
58 if (std::isnan(ra) || std::isnan(de))
59 {
60 qCWarning(KSTARS) << "NAN Center, HiPS draw canceled.";
61 return false;
62 }
63
64 bool allSky;
65
66 if (level < 3)
67 {
68 allSky = true;
69 level = 3;
70 }
71 else
72 {
73 allSky = false;
74 }
75
76 int centerPix = m_HEALpix->getPix(level, ra, de);
77
78 SkyPoint cornerSkyCoords[4];
79 QPointF tileLine[2];
80 m_HEALpix->getCornerPoints(level, centerPix, cornerSkyCoords);
81
82 //qCDebug(KSTARS) << "#" << i+1 << "RA0" << cornerSkyCoords[i].ra0().toHMSString();
83 //qCDebug(KSTARS) << "#" << i+1 << "DE0" << cornerSkyCoords[i].dec0().toHMSString();
84
85 //qCDebug(KSTARS) << "#" << i+1 << "X" << tileLine[i].x();
86 //qCDebug(KSTARS) << "#" << i+1 << "Y" << tileLine[i].y();
87
88 for (int i = 0; i < 2; i++)
89 tileLine[i] = m_projector->toScreen(&cornerSkyCoords[i]);
90
91 int size = std::sqrt(std::pow(tileLine[0].x() - tileLine[1].x(), 2) + std::pow(tileLine[0].y() - tileLine[1].y(), 2));
92 if (size < 0)
93 size = HIPSManager::Instance()->getCurrentTileWidth();
94
95 bool old = m_scanRender->isBilinearInterpolationEnabled();
96 m_scanRender->setBilinearInterpolationEnabled(Options::hIPSBiLinearInterpolation()
97 && (size >= HIPSManager::Instance()->getCurrentTileWidth() || allSky));
98
99 renderRec(allSky, level, centerPix, hipsImage);
100
101 m_scanRender->setBilinearInterpolationEnabled(old);
102
103 return true;
104}
105
106void HIPSRenderer::renderRec(bool allsky, int level, int pix, QImage *pDest)
107{
108 if (m_renderedMap.contains(pix))
109 {
110 return;
111 }
112
113 if (renderPix(allsky, level, pix, pDest))
114 {
115 m_renderedMap.insert(pix);
116 int dirs[8];
117 int nside = 1 << level;
118
119 m_HEALpix->neighbours(nside, pix, dirs);
120
121 renderRec(allsky, level, dirs[0], pDest);
122 renderRec(allsky, level, dirs[2], pDest);
123 renderRec(allsky, level, dirs[4], pDest);
124 renderRec(allsky, level, dirs[6], pDest);
125 }
126}
127
128bool HIPSRenderer::renderPix(bool allsky, int level, int pix, QImage *pDest)
129{
130 SkyPoint cornerSkyCoords[4];
131 QPointF cornerScreenCoords[4];
132 bool freeImage = false;
133
134 m_HEALpix->getCornerPoints(level, pix, cornerSkyCoords);
135 bool isVisible = false;
136
137 for (int i = 0; i < 4; i++)
138 {
139 cornerScreenCoords[i] = m_projector->toScreen(&cornerSkyCoords[i]);
140 isVisible |= m_projector->checkVisibility(&cornerSkyCoords[i]);
141 }
142
143 //if (SKPLANECheckFrustumToPolygon(trfGetFrustum(), pts, 4))
144 // Is the right way to do this?
145
146 if (isVisible)
147 {
148 m_blocks++;
149
150 /*for (int i = 0; i < 4; i++)
151 {
152 trfProjectPointNoCheck(&pts[i]);
153 } */
154
155 QImage *image = HIPSManager::Instance()->getPix(allsky, level, pix, freeImage);
156
157 if (image)
158 {
159 m_rendered++;
160
161 m_size += image->sizeInBytes();
162
163 // UV Mapping to apply image unto the destination image
164 // 4x4 = 16 points are mapped from the source image unto the destination image.
165 // Starting from each grandchild pixel, each pix polygon is mapped accordingly.
166 // For example, pixel 357 will have 4 child pixels, each of them will have 4 childs pixels and so
167 // on. Each healpix pixel appears roughly as a diamond on the sky map.
168 // The corners points for HealPIX moves from NORTH -> EAST -> SOUTH -> WEST
169 // Hence first point is 0.25, 0.25 in UV coordinate system.
170 // Depending on the selected algorithm, the mapping will either utilize nearest neighbour
171 // or bilinear interpolation.
172 QPointF uv[16][4] = {{QPointF(.25, .25), QPointF(0.25, 0), QPointF(0, .0), QPointF(0, .25)},
173 {QPointF(.25, .5), QPointF(0.25, 0.25), QPointF(0, .25), QPointF(0, .5)},
174 {QPointF(.5, .25), QPointF(0.5, 0), QPointF(.25, .0), QPointF(.25, .25)},
175 {QPointF(.5, .5), QPointF(0.5, 0.25), QPointF(.25, .25), QPointF(.25, .5)},
176
177 {QPointF(.25, .75), QPointF(0.25, 0.5), QPointF(0, 0.5), QPointF(0, .75)},
178 {QPointF(.25, 1), QPointF(0.25, 0.75), QPointF(0, .75), QPointF(0, 1)},
179 {QPointF(.5, .75), QPointF(0.5, 0.5), QPointF(.25, .5), QPointF(.25, .75)},
180 {QPointF(.5, 1), QPointF(0.5, 0.75), QPointF(.25, .75), QPointF(.25, 1)},
181
182 {QPointF(.75, .25), QPointF(0.75, 0), QPointF(0.5, .0), QPointF(0.5, .25)},
183 {QPointF(.75, .5), QPointF(0.75, 0.25), QPointF(0.5, .25), QPointF(0.5, .5)},
184 {QPointF(1, .25), QPointF(1, 0), QPointF(.75, .0), QPointF(.75, .25)},
185 {QPointF(1, .5), QPointF(1, 0.25), QPointF(.75, .25), QPointF(.75, .5)},
186
187 {QPointF(.75, .75), QPointF(0.75, 0.5), QPointF(0.5, .5), QPointF(0.5, .75)},
188 {QPointF(.75, 1), QPointF(0.75, 0.75), QPointF(0.5, .75), QPointF(0.5, 1)},
189 {QPointF(1, .75), QPointF(1, 0.5), QPointF(.75, .5), QPointF(.75, .75)},
190 {QPointF(1, 1), QPointF(1, 0.75), QPointF(.75, .75), QPointF(.75, 1)},
191 };
192
193 int childPixelID[4];
194
195 // Find all the 4 children of the current pixel
196 m_HEALpix->getPixChilds(pix, childPixelID);
197
198 int j = 0;
199 for (int id : childPixelID)
200 {
201 int grandChildPixelID[4];
202 // Find the children of this child (i.e. grand child)
203 // Then we have 4x4 pixels under the primary pixel
204 // The image is interpolated and rendered over these pixels
205 // coordinate to minimize any distortions due to the projection
206 // system.
207 m_HEALpix->getPixChilds(id, grandChildPixelID);
208
209 QPointF fineScreenCoords[4];
210
211 for (int id2 : grandChildPixelID)
212 {
213 SkyPoint fineSkyPoints[4];
214 m_HEALpix->getCornerPoints(level + 2, id2, fineSkyPoints);
215
216 for (int i = 0; i < 4; i++)
217 fineScreenCoords[i] = m_projector->toScreen(&fineSkyPoints[i]);
218 m_scanRender->renderPolygon(3, fineScreenCoords, pDest, image, uv[j]);
219 j++;
220 }
221 }
222
223 if (freeImage)
224 {
225 delete image;
226 }
227 }
228
229 if (Options::hIPSShowGrid())
230 {
231 QPainter p(pDest);
232 p.setRenderHint(QPainter::Antialiasing);
233 p.setPen(gridColor);
234
235 p.drawLine(cornerScreenCoords[0].x(), cornerScreenCoords[0].y(), cornerScreenCoords[1].x(), cornerScreenCoords[1].y());
236 p.drawLine(cornerScreenCoords[1].x(), cornerScreenCoords[1].y(), cornerScreenCoords[2].x(), cornerScreenCoords[2].y());
237 p.drawLine(cornerScreenCoords[2].x(), cornerScreenCoords[2].y(), cornerScreenCoords[3].x(), cornerScreenCoords[3].y());
238 p.drawLine(cornerScreenCoords[3].x(), cornerScreenCoords[3].y(), cornerScreenCoords[0].x(), cornerScreenCoords[0].y());
239 p.drawText((cornerScreenCoords[0].x() + cornerScreenCoords[1].x() + cornerScreenCoords[2].x() + cornerScreenCoords[3].x()) /
240 4,
241 (cornerScreenCoords[0].y() + cornerScreenCoords[1].y() + cornerScreenCoords[2].y() + cornerScreenCoords[3].y()) / 4,
242 QString::number(pix) + " / " + QString::number(level));
243 }
244
245 return true;
246 }
247
248 return false;
249}
QColor colorNamed(const QString &name) const
Retrieve a color by name.
ColorScheme * colorScheme()
Definition kstarsdata.h:174
The Projector class is the primary class that serves as an interface to handle projections.
Definition projector.h:58
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
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.
The sky coordinates of a point in the sky.
Definition skypoint.h:45
QStringView level(QStringView ifopt)
QString name(NameFormat format) const const
qsizetype sizeInBytes() const const
void clear()
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
QString number(double n, char format, int precision)
QTextStream & center(QTextStream &stream)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:04:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.