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 
18 HIPSRenderer::HIPSRenderer()
19 {
20  m_scanRender.reset(new ScanRender());
21  m_HEALpix.reset(new HEALPix());
22 }
23 
24 bool 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() && (size >= HIPSManager::Instance()->getCurrentTileWidth() || allSky));
97 
98  renderRec(allSky, level, centerPix, hipsImage);
99 
100  m_scanRender->setBilinearInterpolationEnabled(old);
101 
102  return true;
103 }
104 
105 void HIPSRenderer::renderRec(bool allsky, int level, int pix, QImage *pDest)
106 {
107  if (m_renderedMap.contains(pix))
108  {
109  return;
110  }
111 
112  if (renderPix(allsky, level, pix, pDest))
113  {
114  m_renderedMap.insert(pix);
115  int dirs[8];
116  int nside = 1 << level;
117 
118  m_HEALpix->neighbours(nside, pix, dirs);
119 
120  renderRec(allsky, level, dirs[0], pDest);
121  renderRec(allsky, level, dirs[2], pDest);
122  renderRec(allsky, level, dirs[4], pDest);
123  renderRec(allsky, level, dirs[6], pDest);
124  }
125 }
126 
127 bool HIPSRenderer::renderPix(bool allsky, int level, int pix, QImage *pDest)
128 {
129  SkyPoint cornerSkyCoords[4];
130  QPointF cornerScreenCoords[4];
131  bool freeImage = false;
132 
133  m_HEALpix->getCornerPoints(level, pix, cornerSkyCoords);
134  bool isVisible = false;
135 
136  for (int i = 0; i < 4; i++)
137  {
138  cornerScreenCoords[i] = m_projector->toScreen(&cornerSkyCoords[i]);
139  isVisible |= m_projector->checkVisibility(&cornerSkyCoords[i]);
140  }
141 
142  //if (SKPLANECheckFrustumToPolygon(trfGetFrustum(), pts, 4))
143  // Is the right way to do this?
144 
145  if (isVisible)
146  {
147  m_blocks++;
148 
149  /*for (int i = 0; i < 4; i++)
150  {
151  trfProjectPointNoCheck(&pts[i]);
152  } */
153 
154  QImage *image = HIPSManager::Instance()->getPix(allsky, level, pix, freeImage);
155 
156  if (image)
157  {
158  m_rendered++;
159 
160 #if QT_VERSION >= QT_VERSION_CHECK(5,10,0)
161  m_size += image->sizeInBytes();
162 #else
163  m_size += image->byteCount();
164 #endif
165 
166  // UV Mapping to apply image unto the destination image
167  // 4x4 = 16 points are mapped from the source image unto the destination image.
168  // Starting from each grandchild pixel, each pix polygon is mapped accordingly.
169  // For example, pixel 357 will have 4 child pixels, each of them will have 4 childs pixels and so
170  // on. Each healpix pixel appears roughly as a diamond on the sky map.
171  // The corners points for HealPIX moves from NORTH -> EAST -> SOUTH -> WEST
172  // Hence first point is 0.25, 0.25 in UV coordinate system.
173  // Depending on the selected algorithm, the mapping will either utilize nearest neighbour
174  // or bilinear interpolation.
175  QPointF uv[16][4] = {{QPointF(.25, .25), QPointF(0.25, 0), QPointF(0, .0), QPointF(0, .25)},
176  {QPointF(.25, .5), QPointF(0.25, 0.25), QPointF(0, .25), QPointF(0, .5)},
177  {QPointF(.5, .25), QPointF(0.5, 0), QPointF(.25, .0), QPointF(.25, .25)},
178  {QPointF(.5, .5), QPointF(0.5, 0.25), QPointF(.25, .25), QPointF(.25, .5)},
179 
180  {QPointF(.25, .75), QPointF(0.25, 0.5), QPointF(0, 0.5), QPointF(0, .75)},
181  {QPointF(.25, 1), QPointF(0.25, 0.75), QPointF(0, .75), QPointF(0, 1)},
182  {QPointF(.5, .75), QPointF(0.5, 0.5), QPointF(.25, .5), QPointF(.25, .75)},
183  {QPointF(.5, 1), QPointF(0.5, 0.75), QPointF(.25, .75), QPointF(.25, 1)},
184 
185  {QPointF(.75, .25), QPointF(0.75, 0), QPointF(0.5, .0), QPointF(0.5, .25)},
186  {QPointF(.75, .5), QPointF(0.75, 0.25), QPointF(0.5, .25), QPointF(0.5, .5)},
187  {QPointF(1, .25), QPointF(1, 0), QPointF(.75, .0), QPointF(.75, .25)},
188  {QPointF(1, .5), QPointF(1, 0.25), QPointF(.75, .25), QPointF(.75, .5)},
189 
190  {QPointF(.75, .75), QPointF(0.75, 0.5), QPointF(0.5, .5), QPointF(0.5, .75)},
191  {QPointF(.75, 1), QPointF(0.75, 0.75), QPointF(0.5, .75), QPointF(0.5, 1)},
192  {QPointF(1, .75), QPointF(1, 0.5), QPointF(.75, .5), QPointF(.75, .75)},
193  {QPointF(1, 1), QPointF(1, 0.75), QPointF(.75, .75), QPointF(.75, 1)},
194  };
195 
196  int childPixelID[4];
197 
198  // Find all the 4 children of the current pixel
199  m_HEALpix->getPixChilds(pix, childPixelID);
200 
201  int j = 0;
202  for (int id : childPixelID)
203  {
204  int grandChildPixelID[4];
205  // Find the children of this child (i.e. grand child)
206  // Then we have 4x4 pixels under the primary pixel
207  // The image is interpolated and rendered over these pixels
208  // coordinate to minimize any distortions due to the projection
209  // system.
210  m_HEALpix->getPixChilds(id, grandChildPixelID);
211 
212  QPointF fineScreenCoords[4];
213 
214  for (int id2 : grandChildPixelID)
215  {
216  SkyPoint fineSkyPoints[4];
217  m_HEALpix->getCornerPoints(level + 2, id2, fineSkyPoints);
218 
219  for (int i = 0; i < 4; i++)
220  fineScreenCoords[i] = m_projector->toScreen(&fineSkyPoints[i]);
221  m_scanRender->renderPolygon(3, fineScreenCoords, pDest, image, uv[j]);
222  j++;
223  }
224  }
225 
226  if (freeImage)
227  {
228  delete image;
229  }
230  }
231 
232  if (Options::hIPSShowGrid())
233  {
234  QPainter p(pDest);
235  p.setRenderHint(QPainter::Antialiasing);
236  p.setPen(gridColor);
237 
238  p.drawLine(cornerScreenCoords[0].x(), cornerScreenCoords[0].y(), cornerScreenCoords[1].x(), cornerScreenCoords[1].y());
239  p.drawLine(cornerScreenCoords[1].x(), cornerScreenCoords[1].y(), cornerScreenCoords[2].x(), cornerScreenCoords[2].y());
240  p.drawLine(cornerScreenCoords[2].x(), cornerScreenCoords[2].y(), cornerScreenCoords[3].x(), cornerScreenCoords[3].y());
241  p.drawLine(cornerScreenCoords[3].x(), cornerScreenCoords[3].y(), cornerScreenCoords[0].x(), cornerScreenCoords[0].y());
242  p.drawText((cornerScreenCoords[0].x() + cornerScreenCoords[1].x() + cornerScreenCoords[2].x() + cornerScreenCoords[3].x()) / 4,
243  (cornerScreenCoords[0].y() + cornerScreenCoords[1].y() + cornerScreenCoords[2].y() + cornerScreenCoords[3].y()) / 4, QString::number(pix) + " / " + QString::number(level));
244  }
245 
246  return true;
247  }
248 
249  return false;
250 }
qsizetype sizeInBytes() const const
QString number(int n, int base)
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
QString name() const const
QStringView level(QStringView ifopt)
ColorScheme * colorScheme()
Definition: kstarsdata.h:171
double fov() const
Return the FOV of this projection.
Definition: projector.cpp:88
KStandardDirs * dirs()
QTextStream & center(QTextStream &stream)
int byteCount() const const
QColor colorNamed(const QString &name) const
Retrieve a color by name.
Definition: colorscheme.cpp:86
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Aug 11 2022 03:59:59 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.