Kstars

skyqpainter.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 "skyqpainter.h"
8
9#include <QPointer>
10
11#include "kstarsdata.h"
12#include "kstars.h"
13#include "Options.h"
14#include "skymap.h"
15#include "projections/projector.h"
16#include "skycomponents/flagcomponent.h"
17#include "skycomponents/linelist.h"
18#include "skycomponents/linelistlabel.h"
19#include "skycomponents/satellitescomponent.h"
20#include "skycomponents/skiphashlist.h"
21#include "skycomponents/skymapcomposite.h"
22#include "skycomponents/solarsystemcomposite.h"
23#include "skycomponents/earthshadowcomponent.h"
24#include "skycomponents/imageoverlaycomponent.h"
25#include "skyobjects/skyobject.h"
26#include "skyobjects/constellationsart.h"
27#include "skyobjects/catalogobject.h"
28#include "skyobjects/ksasteroid.h"
29#include "skyobjects/kscomet.h"
30#include "skyobjects/kssun.h"
31#include "skyobjects/ksmoon.h"
32#include "skyobjects/satellite.h"
33#include "skyobjects/supernova.h"
34#include "skyobjects/ksearthshadow.h"
35#ifdef HAVE_INDI
36#include "skyobjects/mosaictiles.h"
37#endif
38#include "hips/hipsrenderer.h"
39#include "terrain/terrainrenderer.h"
40#include <QElapsedTimer>
41#include "auxiliary/rectangleoverlap.h"
42
43namespace
44{
45// Convert spectral class to numerical index.
46// If spectral class is invalid return index for white star (A class)
47int harvardToIndex(char c)
48{
49 switch (c)
50 {
51 case 'o':
52 case 'O':
53 return 0;
54 case 'b':
55 case 'B':
56 return 1;
57 case 'a':
58 case 'A':
59 return 2;
60 case 'f':
61 case 'F':
62 return 3;
63 case 'g':
64 case 'G':
65 return 4;
66 case 'k':
67 case 'K':
68 return 5;
69 case 'm':
70 case 'M':
71 return 6;
72 // For unknown spectral class assume A class (white star)
73 default:
74 return 2;
75 }
76}
77
78// Total number of sizes of stars.
79const int nStarSizes = 15;
80// Total number of spectral classes
81// N.B. Must be in sync with harvardToIndex
82const int nSPclasses = 7;
83
84// Cache for star images.
85//
86// These pixmaps are never deallocated. Not really good...
87QPixmap *imageCache[nSPclasses][nStarSizes] = { { nullptr } };
88
89std::unique_ptr<QPixmap> visibleSatPixmap, invisibleSatPixmap;
90} // namespace
91
92int SkyQPainter::starColorMode = 0;
93QColor SkyQPainter::m_starColor = QColor();
94QMap<char, QColor> SkyQPainter::ColorMap = QMap<char, QColor>();
95
97{
98 for (char &color : ColorMap.keys())
99 {
100 QPixmap **pmap = imageCache[harvardToIndex(color)];
101
102 for (int size = 1; size < nStarSizes; size++)
103 {
104 if (pmap[size])
105 delete pmap[size];
106
107 pmap[size] = nullptr;
108 }
109 }
110}
111
113{
114 Q_ASSERT(pd);
115 m_pd = pd;
116 m_size = QSize(pd->width(), pd->height());
117 m_hipsRender = new HIPSRenderer();
118}
119
121{
122 Q_ASSERT(pd);
123 m_pd = pd;
124 m_size = size;
125 m_hipsRender = new HIPSRenderer();
126}
127
129{
130 Q_ASSERT(widget);
131 // Set paint device pointer to pd or to the widget if pd = 0
132 m_pd = (pd ? pd : widget);
133 m_size = widget->size();
134 m_hipsRender = new HIPSRenderer();
135}
136
137SkyQPainter::~SkyQPainter()
138{
139 delete (m_hipsRender);
140}
141
142void SkyQPainter::setSize(int width, int height)
143{
144 m_size.setWidth(width);
145 m_size.setHeight(height);
146}
147
149{
150 QPainter::begin(m_pd);
151 bool aa = !SkyMap::Instance()->isSlewing() && Options::useAntialias();
154 m_proj = SkyMap::Instance()->projector();
155}
156
158{
160}
161
162namespace
163{
164// Circle intersection formula from https://dassencio.org/102
165double circleOverlap(double d, double radius1, double radius2)
166{
167 // r1 is the radius of the larger circle.
168 const double r1 = (radius1 >= radius2) ? radius1 : radius2;
169 // r2 is the radius of the smaller circle.
170 const double r2 = (radius1 >= radius2) ? radius2 : radius1;
171
172 // No overlap.
173 if (d > r1 + r2)
174 return 0.0;
175
176 // The smaller circle (with radius r2) is fully contained in larger circle.
177 if (d == 0 || r2 + d <= r1)
178 return M_PI * r2 * r2;
179
180 // Some bounds checking.
181 if (r1 <= 0 || r2 <= 0 || d < 0)
182 return 0.0;
183
184 // They partially overlap.
185 const double d1 = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
186 const double d2 = d - d1;
187 const double intersection =
188 r1 * r1 * acos(d1 / r1) - d1 * sqrt(r1 * r1 - d1 * d1) +
189 r2 * r2 * acos(d2 / r2) - d2 * sqrt(r2 * r2 - d2 * d2);
190
191 return intersection;
192}
193} // namespace
194
195QColor SkyQPainter::skyColor() const
196{
197 const QColor nightSky = KStarsData::Instance()->colorScheme()->colorNamed("SkyColor");
198 QColor sky = nightSky;
199 if (Options::simulateDaytime())
200 {
201 KSSun *sun = KStarsData::Instance()->skyComposite()->solarSystemComposite()->sun();
202 if (sun)
203 {
204 const double nightFraction = sun->nightFraction();
205 const double dayFraction = 1 - nightFraction;
206 const QColor daySky = KStarsData::Instance()->colorScheme()->colorNamed("SkyColorDaytime");
207 sky = QColor(nightFraction * nightSky.red() + dayFraction * daySky.red(),
208 nightFraction * nightSky.green() + dayFraction * daySky.green(),
209 nightFraction * nightSky.blue() + dayFraction * daySky.blue());
210
211 // Just for kicks, check if sun is eclipsed!
212 const KSMoon *moon = KStarsData::Instance()->skyComposite()->solarSystemComposite()->moon();
213 if (moon)
214 {
215 const double separation = sun->angularDistanceTo(moon).Degrees();
216 const double sunRadius = sun->angSize() * 0.5 / 60.0;
217 const double moonRadius = moon->angSize() * 0.5 / 60.0;
218 if (separation < sunRadius + moonRadius)
219 {
220 // Ongoing eclipse!
221
222 if (moonRadius >= separation + sunRadius)
223 sky = nightSky; // Totality!
224 else
225 {
226 // We (arbitrarily) dim the sun when it is more than 95% obscured.
227 // It is changed linearly from 100% day color at 5% visible, to 100% night color at 0% visible.
228 const double sunArea = M_PI * sunRadius * sunRadius;
229 const double overlapArea = circleOverlap(separation, moonRadius, sunRadius);
230 const double sunFraction = (sunArea - overlapArea) / sunArea;
231 if (sunFraction <= .05)
232 {
233 const double dayFraction = sunFraction / .05;
234 const double nightFraction = 1 - dayFraction;
235 sky = QColor(dayFraction * sky.red() + nightFraction * nightSky.red(),
236 dayFraction * sky.green() + nightFraction * nightSky.green(),
237 dayFraction * sky.blue() + nightFraction * nightSky.blue());
238
239 }
240 }
241 }
242 }
243 }
244 }
245 return sky;
246}
247
249{
250 fillRect(0, 0, m_size.width(), m_size.height(), skyColor());
251}
252
253void SkyQPainter::setPen(const QPen &pen)
254{
256}
257
259{
261}
262
264{
265 const int starColorIntensity = Options::starColorIntensity();
266
267 ColorMap.clear();
268 switch (Options::starColorMode())
269 {
270 case 1: // Red stars.
271 m_starColor = Qt::red;
272 break;
273 case 2: // Black stars.
274 m_starColor = Qt::black;
275 break;
276 case 3: // White stars
277 m_starColor = Qt::white;
278 break;
279 case 0: // Real color
280 default: // And use real color for everything else
281 m_starColor = QColor();
282 ColorMap.insert('O', QColor::fromRgb(0, 0, 255));
283 ColorMap.insert('B', QColor::fromRgb(0, 200, 255));
284 ColorMap.insert('A', QColor::fromRgb(0, 255, 255));
285 ColorMap.insert('F', QColor::fromRgb(200, 255, 100));
286 ColorMap.insert('G', QColor::fromRgb(255, 255, 0));
287 ColorMap.insert('K', QColor::fromRgb(255, 100, 0));
288 ColorMap.insert('M', QColor::fromRgb(255, 0, 0));
289 break;
290 }
291 if (ColorMap.isEmpty())
292 {
293 ColorMap.insert('O', m_starColor);
294 ColorMap.insert('B', m_starColor);
295 ColorMap.insert('A', m_starColor);
296 ColorMap.insert('F', m_starColor);
297 ColorMap.insert('G', m_starColor);
298 ColorMap.insert('K', m_starColor);
299 ColorMap.insert('M', m_starColor);
300 }
301
302 for (char &color : ColorMap.keys())
303 {
304 QPixmap BigImage(15, 15);
305 BigImage.fill(Qt::transparent);
306
307 QPainter p;
308 p.begin(&BigImage);
309
310 if (Options::starColorMode() == 0)
311 {
312 qreal h, s, v, a;
314 QColor starColor = ColorMap[color];
315 starColor.getHsvF(&h, &s, &v, &a);
316 for (int i = 0; i < 8; i++)
317 {
318 for (int j = 0; j < 8; j++)
319 {
320 qreal x = i - 7;
321 qreal y = j - 7;
322 qreal dist = sqrt(x * x + y * y) / 7.0;
323 starColor.setHsvF(
324 h,
325 qMin(qreal(1),
326 dist < (10 - starColorIntensity) / 10.0 ? 0 : dist),
327 v,
328 qMax(qreal(0),
329 dist < (10 - starColorIntensity) / 20.0 ? 1 : 1 - dist));
330 p.setPen(starColor);
331 p.drawPoint(i, j);
332 p.drawPoint(14 - i, j);
333 p.drawPoint(i, 14 - j);
334 p.drawPoint(14 - i, 14 - j);
335 }
336 }
337 }
338 else
339 {
341 p.setPen(QPen(ColorMap[color], 2.0));
342 p.setBrush(p.pen().color());
343 p.drawEllipse(QRectF(2, 2, 10, 10));
344 }
345 p.end();
346
347 // Cache array slice
348 QPixmap **pmap = imageCache[harvardToIndex(color)];
349
350 for (int size = 1; size < nStarSizes; size++)
351 {
352 if (!pmap[size])
353 pmap[size] = new QPixmap();
354 *pmap[size] = BigImage.scaled(size, size, Qt::KeepAspectRatio,
356 }
357 }
358 starColorMode = Options::starColorMode();
359
360 if (!visibleSatPixmap.get())
361 visibleSatPixmap.reset(new QPixmap(":/icons/kstars_satellites_visible.svg"));
362 if (!invisibleSatPixmap.get())
363 invisibleSatPixmap.reset(new QPixmap(":/icons/kstars_satellites_invisible.svg"));
364}
365
367{
368 bool aVisible, bVisible;
369 QPointF aScreen = m_proj->toScreen(a, true, &aVisible);
370 QPointF bScreen = m_proj->toScreen(b, true, &bVisible);
371
372 drawLine(aScreen, bScreen);
373
374 //THREE CASES:
375 // if (aVisible && bVisible)
376 // {
377 // //Both a,b visible, so paint the line normally:
378 // drawLine(aScreen, bScreen);
379 // }
380 // else if (aVisible)
381 // {
382 // //a is visible but b isn't:
383 // drawLine(aScreen, m_proj->clipLine(a, b));
384 // }
385 // else if (bVisible)
386 // {
387 // //b is visible but a isn't:
388 // drawLine(bScreen, m_proj->clipLine(b, a));
389 // } //FIXME: what if both are offscreen but the line isn't?
390}
391
392void SkyQPainter::drawSkyPolyline(LineList * list, SkipHashList * skipList,
393 LineListLabel * label)
394{
395 SkyList *points = list->points();
396 bool isVisible, isVisibleLast;
397
398 if (points->size() == 0)
399 return;
400 QPointF oLast = m_proj->toScreen(points->first().get(), true, &isVisibleLast);
401 // & with the result of checkVisibility to clip away things below horizon
402 isVisibleLast &= m_proj->checkVisibility(points->first().get());
403 QPointF oThis, oThis2;
404
405 for (int j = 1; j < points->size(); j++)
406 {
407 SkyPoint *pThis = points->at(j).get();
408
409 oThis2 = oThis = m_proj->toScreen(pThis, true, &isVisible);
410 // & with the result of checkVisibility to clip away things below horizon
411 isVisible &= m_proj->checkVisibility(pThis);
412 bool doSkip = false;
413 if (skipList)
414 {
415 doSkip = skipList->skip(j);
416 }
417
418 bool pointsVisible = false;
419 //Temporary solution to avoid random lines in Gnomonic projection and draw lines up to horizon
420 if (SkyMap::Instance()->projector()->type() == Projector::Gnomonic)
421 {
422 if (isVisible && isVisibleLast)
423 pointsVisible = true;
424 }
425 else
426 {
427 if (isVisible || isVisibleLast)
428 pointsVisible = true;
429 }
430
431 if (!doSkip)
432 {
433 if (pointsVisible)
434 {
435 drawLine(oLast, oThis);
436 if (label)
437 label->updateLabelCandidates(oThis.x(), oThis.y(), list, j);
438 }
439 }
440
441 oLast = oThis2;
442 isVisibleLast = isVisible;
443 }
444}
445
446void SkyQPainter::drawSkyPolygon(LineList * list, bool forceClip)
447{
448 bool isVisible = false, isVisibleLast;
449 SkyList *points = list->points();
450 QPolygonF polygon;
451
452 if (forceClip == false)
453 {
454 for (const auto &point : *points)
455 {
456 polygon << m_proj->toScreen(point.get(), false, &isVisibleLast);
457 isVisible |= isVisibleLast;
458 }
459
460 // If 1+ points are visible, draw it
461 if (polygon.size() && isVisible)
462 drawPolygon(polygon);
463
464 return;
465 }
466
467 SkyPoint *pLast = points->last().get();
468 QPointF oLast = m_proj->toScreen(pLast, true, &isVisibleLast);
469 // & with the result of checkVisibility to clip away things below horizon
470 isVisibleLast &= m_proj->checkVisibility(pLast);
471
472 for (const auto &point : *points)
473 {
474 SkyPoint *pThis = point.get();
475 QPointF oThis = m_proj->toScreen(pThis, true, &isVisible);
476 // & with the result of checkVisibility to clip away things below horizon
477 isVisible &= m_proj->checkVisibility(pThis);
478
479 if (isVisible && isVisibleLast)
480 {
481 polygon << oThis;
482 }
483 else if (isVisibleLast)
484 {
485 QPointF oMid = m_proj->clipLine(pLast, pThis);
486 polygon << oMid;
487 }
488 else if (isVisible)
489 {
490 QPointF oMid = m_proj->clipLine(pThis, pLast);
491 polygon << oMid;
492 polygon << oThis;
493 }
494
495 pLast = pThis;
496 oLast = oThis;
497 isVisibleLast = isVisible;
498 }
499
500 if (polygon.size())
501 drawPolygon(polygon);
502}
503
505{
506 if (!m_proj->checkVisibility(planet))
507 return false;
508
509 bool visible = false;
510 QPointF pos = m_proj->toScreen(planet, true, &visible);
511 if (!visible || !m_proj->onScreen(pos))
512 return false;
513
514 float fakeStarSize = (10.0 + log10(Options::zoomFactor()) - log10(MINZOOM)) *
515 (10 - planet->mag()) / 10;
516 if (fakeStarSize > 15.0)
517 fakeStarSize = 15.0;
518
519 double size = planet->angSize() * dms::PI * Options::zoomFactor() / 10800.0;
520 if (size < fakeStarSize && planet->name() != i18n("Sun") &&
521 planet->name() != i18n("Moon"))
522 {
523 // Draw them as bright stars of appropriate color instead of images
524 char spType;
525 //FIXME: do these need i18n?
526 if (planet->name() == i18n("Mars"))
527 {
528 spType = 'K';
529 }
530 else if (planet->name() == i18n("Jupiter") || planet->name() == i18n("Mercury") ||
531 planet->name() == i18n("Saturn"))
532 {
533 spType = 'F';
534 }
535 else
536 {
537 spType = 'B';
538 }
539 drawPointSource(pos, fakeStarSize, spType);
540 }
541 else
542 {
543 float sizemin = 1.0;
544 if (planet->name() == i18n("Sun") || planet->name() == i18n("Moon"))
545 sizemin = 8.0;
546 if (planet->name() == i18n("Sun")) size = size * Options::sunScale();
547 if (planet->name() == i18n("Moon")) size = size * Options::moonScale();
548
549 if (size < sizemin)
550 size = sizemin;
551
552 if (Options::showPlanetImages() && !planet->image().isNull())
553 {
554 //Because Saturn has rings, we inflate its image size by a factor 2.5
555 if (planet->name() == "Saturn")
556 size = int(2.5 * size);
557 // Scale size exponentially so it is visible at large zooms
558 else if (planet->name() == "Pluto")
559 size = int(size * exp(1.5 * size));
560
561 save();
562 translate(pos);
563 rotate(m_proj->findPA(planet, pos.x(), pos.y()));
564
566 // Use the Screen composition mode for the Moon to make it look nicer, especially the non-full
567 // phases. When doing this, though, stars would shine through, so need to paint in the skycolor
568 // behind it.
569 if (planet->name() == i18n("Moon"))
570 {
571 auto keepBrush = brush();
572 auto keepPen = pen();
573 setBrush(skyColor());
574 setPen(skyColor());
576 drawEllipse(QRectF(-0.5 * size, -0.5 * size, size, size));
577 setBrush(keepBrush);
578 setPen(keepPen);
580 }
581 drawImage(QRectF(-0.5 * size, -0.5 * size, size, size), planet->image());
582 setCompositionMode(mode);
583
584 restore();
585 }
586 else //Otherwise, draw a simple circle.
587 {
588 drawEllipse(pos, size * .5, size * .5);
589 }
590 }
591 return true;
592}
593
595{
596 if (!m_proj->checkVisibility(shadow))
597 return false;
598
599 bool visible = false;
600 QPointF pos = m_proj->toScreen(shadow, true, &visible);
601
602 if (!visible)
603 return false;
604
605 double umbra_size =
606 shadow->getUmbraAngSize() * dms::PI * Options::zoomFactor() / 10800.0;
607 double penumbra_size =
608 shadow->getPenumbraAngSize() * dms::PI * Options::zoomFactor() / 10800.0;
609
610 save();
611 setBrush(QBrush(QColor(255, 96, 38, 128)));
612 drawEllipse(pos, umbra_size, umbra_size);
613 setBrush(QBrush(QColor(255, 96, 38, 90)));
614 drawEllipse(pos, penumbra_size, penumbra_size);
615 restore();
616
617 return true;
618}
619
621{
622 if (!m_proj->checkVisibility(com))
623 return false;
624
625 double size =
626 com->angSize() * dms::PI * Options::zoomFactor() / 10800.0 / 2; // Radius
627 if (size < 1)
628 size = 1;
629
630 bool visible = false;
631 QPointF pos = m_proj->toScreen(com, true, &visible);
632
633 // Draw the coma. FIXME: Another Check??
634 if (visible && m_proj->onScreen(pos))
635 {
636 // Draw the comet.
637 drawEllipse(pos, size, size);
638
639 double comaLength =
640 (com->getComaAngSize().arcmin() * dms::PI * Options::zoomFactor() / 10800.0);
641
642 // If coma is visible and long enough.
643 if (Options::showCometComas() && comaLength > size)
644 {
645 KSSun *sun =
646 KStarsData::Instance()->skyComposite()->solarSystemComposite()->sun();
647
648 // Find the angle to the sun.
649 double comaAngle = m_proj->findPA(sun, pos.x(), pos.y());
650
651 const QVector<QPoint> coma = { QPoint(pos.x() - size, pos.y()),
652 QPoint(pos.x() + size, pos.y()),
653 QPoint(pos.x(), pos.y() + comaLength)
654 };
655
656 QPolygon comaPoly(coma);
657
658 comaPoly =
659 QTransform()
660 .translate(pos.x(), pos.y())
661 .rotate(
662 comaAngle) // Already + 180 Deg, because rotated from south, not north.
663 .translate(-pos.x(), -pos.y())
664 .map(comaPoly);
665
666 save();
667
668 // Nice fade for the Coma.
669 QLinearGradient linearGrad(pos, comaPoly.point(2));
670 linearGrad.setColorAt(0, QColor("white"));
671 linearGrad.setColorAt(size / comaLength, QColor("white"));
672 linearGrad.setColorAt(0.9, QColor("transparent"));
673 setBrush(linearGrad);
674
675 // Render Coma.
676 drawConvexPolygon(comaPoly);
677 restore();
678 }
679
680 return true;
681 }
682 else
683 {
684 return false;
685 }
686}
687
689{
690 if (!m_proj->checkVisibility(ast))
691 {
692 return false;
693 }
694
695 bool visible = false;
696 QPointF pos = m_proj->toScreen(ast, true, &visible);
697
698 if (visible && m_proj->onScreen(pos))
699 {
700 KStarsData *data = KStarsData::Instance();
701
702 setPen(data->colorScheme()->colorNamed("AsteroidColor"));
703 drawLine(QPoint(pos.x() - 1.0, pos.y()), QPoint(pos.x() + 1.0, pos.y()));
704 drawLine(QPoint(pos.x(), pos.y() - 1.0), QPoint(pos.x(), pos.y() + 1.0));
705
706 return true;
707 }
708
709 return false;
710}
711
712bool SkyQPainter::drawPointSource(const SkyPoint * loc, float mag, char sp)
713{
714 //Check if it's even visible before doing anything
715 if (!m_proj->checkVisibility(loc))
716 return false;
717
718 bool visible = false;
719 QPointF pos = m_proj->toScreen(loc, true, &visible);
720 // FIXME: onScreen here should use canvas size rather than SkyMap size, especially while printing in portrait mode!
721 if (visible && m_proj->onScreen(pos))
722 {
723 drawPointSource(pos, starWidth(mag), sp);
724 return true;
725 }
726 else
727 {
728 return false;
729 }
730}
731
732void SkyQPainter::drawPointSource(const QPointF &pos, float size, char sp)
733{
734 int isize = qMin(static_cast<int>(size), 14);
735 if (!m_vectorStars || starColorMode == 0)
736 {
737 // Draw stars as bitmaps, either because we were asked to, or because we're painting real colors
738 QPixmap *im = imageCache[harvardToIndex(sp)][isize];
739 float offset = 0.5 * im->width();
740 drawPixmap(QPointF(pos.x() - offset, pos.y() - offset), *im);
741 }
742 else
743 {
744 // Draw stars as vectors, for better printing / SVG export etc.
745 if (starColorMode != 4)
746 {
747 setPen(m_starColor);
748 setBrush(m_starColor);
749 }
750 else
751 {
752 // Note: This is not efficient, but we use vector stars only when plotting SVG, not when drawing the skymap, so speed is not very important.
753 QColor c = ColorMap.value(sp, Qt::white);
754 setPen(c);
755 setBrush(c);
756 }
757
758 // Be consistent with old raster representation
759 if (size > 14)
760 size = 14;
761 if (size >= 2)
762 drawEllipse(pos.x() - 0.5 * size, pos.y() - 0.5 * size, int(size), int(size));
763 else if (size >= 1)
764 drawPoint(pos.x(), pos.y());
765 }
766}
767
769{
770 double zoom = Options::zoomFactor();
771
772 bool visible = false;
773 obj->EquatorialToHorizontal(KStarsData::Instance()->lst(),
774 KStarsData::Instance()->geo()->lat());
775 QPointF constellationmidpoint = m_proj->toScreen(obj, true, &visible);
776
777 if (!visible || !m_proj->onScreen(constellationmidpoint))
778 return false;
779
780 //qDebug() << Q_FUNC_INFO << "o->pa() " << obj->pa();
781 float positionangle =
782 m_proj->findPA(obj, constellationmidpoint.x(), constellationmidpoint.y());
783 //qDebug() << Q_FUNC_INFO << " final PA " << positionangle;
784
785 float w = obj->getWidth() * 60 * dms::PI * zoom / 10800;
786 float h = obj->getHeight() * 60 * dms::PI * zoom / 10800;
787
788 save();
789
791
792 translate(constellationmidpoint);
793 rotate(positionangle);
794 if (m_proj->viewParams().mirror)
795 {
796 scale(-1., 1.);
797 }
798 setOpacity(0.7);
799 drawImage(QRectF(-0.5 * w, -0.5 * h, w, h), obj->image());
800 setOpacity(1);
801
803 restore();
804 return true;
805}
806
807#ifdef HAVE_INDI
808bool SkyQPainter::drawMosaicPanel(MosaicTiles * obj)
809{
810 bool visible = false;
811 obj->EquatorialToHorizontal(KStarsData::Instance()->lst(),
812 KStarsData::Instance()->geo()->lat());
813 QPointF tileMid = m_proj->toScreen(obj, true, &visible);
814
815 if (!visible || !m_proj->onScreen(tileMid) || !obj->isValid())
816 return false;
817
818 //double northRotation = m_proj->findNorthPA(obj, tileMid.x(), tileMid.y())
819
820 // convert 0 to +180 EAST, and 0 to -180 WEST to 0 to 360 CCW
821 const auto mirror = m_proj->viewParams().mirror;
822 auto PA = (obj->positionAngle() < 0) ? obj->positionAngle() + 360 : obj->positionAngle();
823 auto finalPA = m_proj->findNorthPA(obj, tileMid.x(), tileMid.y()) - (mirror ? -PA : PA);
824
825 save();
826 translate(tileMid.toPoint());
827 rotate(finalPA);
828 obj->draw(this);
829 restore();
830
831 return true;
832}
833#endif
834
835bool SkyQPainter::drawHips(bool useCache)
836{
837 int w = viewport().width();
838 int h = viewport().height();
839
840 if (useCache && m_HiPSImage)
841 {
842 drawImage(viewport(), *m_HiPSImage.data());
843 return true;
844 }
845 else
846 {
847 m_HiPSImage.reset(new QImage(w, h, QImage::Format_ARGB32_Premultiplied));
848 bool rendered = m_hipsRender->render(w, h, m_HiPSImage.data(), m_proj);
849 if (rendered)
850 drawImage(viewport(), *m_HiPSImage.data());
851 return rendered;
852 }
853}
854
855bool SkyQPainter::drawTerrain(bool useCache)
856{
857 // TODO
858 Q_UNUSED(useCache);
859 int w = viewport().width();
860 int h = viewport().height();
861 QImage *terrainImage = new QImage(w, h, QImage::Format_ARGB32_Premultiplied);
862 TerrainRenderer *renderer = TerrainRenderer::Instance();
863 bool rendered = renderer->render(w, h, terrainImage, m_proj);
864 if (rendered)
865 drawImage(viewport(), *terrainImage);
866
867 delete (terrainImage);
868 return rendered;
869}
870
871bool SkyQPainter::drawImageOverlay(const QList<ImageOverlay> *imageOverlays, bool useCache)
872{
873 Q_UNUSED(useCache);
874 if (!Options::showImageOverlays())
875 return false;
876
877 constexpr int minDisplayDimension = 5;
878
879 // Convert the RA/DEC from j2000 to jNow and add in az/alt computations.
880 auto localTime = KStarsData::Instance()->geo()->UTtoLT(KStarsData::Instance()->clock()->utc());
881
882 const ViewParams view = m_proj->viewParams();
883 const double vw = view.width, vh = view.height;
884 RectangleOverlap overlap(QPointF(vw / 2.0, vh / 2.0), vw, vh);
885
886 // QElapsedTimer drawTimer;
887 // drawTimer.restart();
888 int numDrawn = 0;
889 for (const ImageOverlay &o : *imageOverlays)
890 {
891 if (o.m_Status != ImageOverlay::AVAILABLE || o.m_Img.get() == nullptr)
892 continue;
893
894 double orientation = o.m_Orientation, ra = o.m_RA, dec = o.m_DEC, scale = o.m_ArcsecPerPixel;
895 const int origWidth = o.m_Width, origHeight = o.m_Height;
896
897 // Not sure why I have to do this, suspect it's related to the East-to-the-right thing.
898 // Note that I have mirrored the image above, so east-to-the-right=false is now east-to-the-right=true
899 // BTW, solver gave me -66, but astrometry.net gave me 246.1 East of North
900 orientation += 180;
901
902 const dms raDms(ra), decDms(dec);
903 SkyPoint coord(raDms, decDms);
904 coord.apparentCoord(static_cast<long double>(J2000), KStars::Instance()->data()->ut().djd());
905 coord.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
906
907 // Find if the object is not visible, or if it is very small.
908 const double a = origWidth * scale / 60.0; // This is the width of the image in arcmin--not the major axis
909 const double zoom = Options::zoomFactor();
910 // W & h are the actual pixel width and height (as doubles) though
911 // the projection size might be smaller.
912 const double w = a * dms::PI * zoom / 10800.0;
913 const double h = w * origHeight / origWidth;
914 const double maxDimension = std::max(w, h);
915 if (maxDimension < minDisplayDimension)
916 continue;
917
918 bool visible;
919 QPointF pos = m_proj->toScreen(&coord, true, &visible);
920 if (!visible || isnan(pos.x()) || isnan(pos.y()))
921 continue;
922
923 const auto PA = (orientation < 0) ? orientation + 360 : orientation;
924 const auto mirror = m_proj->viewParams().mirror;
925 const auto finalPA = m_proj->findNorthPA(&coord, pos.x(), pos.y()) - (mirror ? -PA : PA);
926 if (!overlap.intersects(pos, w, h, finalPA))
927 continue;
928
929 save();
930 translate(pos);
931 rotate(finalPA);
932 if (mirror)
933 {
934 this->scale(-1., 1.);
935 }
936 drawImage(QRectF(-0.5 * w, -0.5 * h, w, h), *(o.m_Img.get()));
937 numDrawn++;
938 restore();
939 }
940 // fprintf(stderr, "DrawTimer: %lldms for %d images\n", drawTimer.elapsed(), numDrawn);
941 return true;
942}
943
944void SkyQPainter::drawCatalogObjectImage(const QPointF &pos, const CatalogObject &obj,
945 float positionAngle)
946{
947 const auto &image = obj.image();
948
949 if (!image.first)
950 return;
951
952 double zoom = Options::zoomFactor();
953 double w = obj.a() * dms::PI * zoom / 10800.0;
954 double h = obj.e() * w;
955
956 save();
957 translate(pos);
958 rotate(positionAngle);
959 drawImage(QRectF(-0.5 * w, -0.5 * h, w, h), image.second);
960 restore();
961}
962
964{
965 if (!m_proj->checkVisibility(&obj))
966 return false;
967
968 bool visible = false;
969 QPointF pos = m_proj->toScreen(&obj, true, &visible);
970 if (!visible || !m_proj->onScreen(pos))
971 return false;
972
973 // if size is 0.0 set it to 1.0, this are normally stars (type 0 and 1)
974 // if we use size 0.0 the star wouldn't be drawn
975 float majorAxis = obj.a();
976 if (majorAxis == 0.0)
977 {
978 majorAxis = 1.0;
979 }
980
981 float size = majorAxis * dms::PI * Options::zoomFactor() / 10800.0;
982
983 const auto mirror = m_proj->viewParams().mirror;
984 const auto positionAngle = m_proj->findNorthPA(&obj, pos.x(), pos.y())
985 - (mirror ? -obj.pa() : obj.pa()) // FIXME: We seem to have two different conventions for PA sign in KStars!
986 + 90.;
987
988 // Draw image
989 if (Options::showInlineImages() && Options::zoomFactor() > 5. * MINZOOM &&
990 !Options::showHIPS())
991 drawCatalogObjectImage(pos, obj, positionAngle);
992
993 // Draw Symbol
994 drawDeepSkySymbol(pos, obj.type(), size, obj.e(), positionAngle);
995
996 return true;
997}
998
999void SkyQPainter::drawDeepSkySymbol(const QPointF &pos, int type, float size, float e,
1000 float positionAngle)
1001{
1002 float x = pos.x();
1003 float y = pos.y();
1004 float zoom = Options::zoomFactor();
1005
1006 int isize = int(size);
1007
1008 float dx1 = -0.5 * size;
1009 float dx2 = 0.5 * size;
1010 float dy1 = -1.0 * e * size / 2.;
1011 float dy2 = e * size / 2.;
1012 float x1 = x + dx1;
1013 float x2 = x + dx2;
1014 float y1 = y + dy1;
1015 float y2 = y + dy2;
1016
1017 float dxa = -size / 4.;
1018 float dxb = size / 4.;
1019 float dya = -1.0 * e * size / 4.;
1020 float dyb = e * size / 4.;
1021 float xa = x + dxa;
1022 float xb = x + dxb;
1023 float ya = y + dya;
1024 float yb = y + dyb;
1025
1026 QString color;
1027
1028 float psize;
1029
1030 QBrush tempBrush;
1031
1032 std::function<void(float, float, float, float)> lambdaDrawEllipse;
1033 std::function<void(float, float, float, float)> lambdaDrawLine;
1034 std::function<void(float, float, float, float)> lambdaDrawCross;
1035
1036 if (Options::useAntialias())
1037 {
1038 lambdaDrawEllipse = [this](float x, float y, float width, float height)
1039 {
1040 drawEllipse(QRectF(x, y, width, height));
1041 };
1042 lambdaDrawLine = [this](float x1, float y1, float x2, float y2)
1043 {
1044 drawLine(QLineF(x1, y1, x2, y2));
1045 };
1046 lambdaDrawCross = [this](float centerX, float centerY, float sizeX, float sizeY)
1047 {
1048 drawLine(
1049 QLineF(centerX - sizeX / 2., centerY, centerX + sizeX / 2., centerY));
1050 drawLine(
1051 QLineF(centerX, centerY - sizeY / 2., centerX, centerY + sizeY / 2.));
1052 };
1053 }
1054 else
1055 {
1056 lambdaDrawEllipse = [this](float x, float y, float width, float height)
1057 {
1058 drawEllipse(QRect(x, y, width, height));
1059 };
1060 lambdaDrawLine = [this](float x1, float y1, float x2, float y2)
1061 {
1062 drawLine(QLine(x1, y1, x2, y2));
1063 };
1064 lambdaDrawCross = [this](float centerX, float centerY, float sizeX, float sizeY)
1065 {
1066 drawLine(QLine(centerX - sizeX / 2., centerY, centerX + sizeX / 2., centerY));
1067 drawLine(QLine(centerX, centerY - sizeY / 2., centerX, centerY + sizeY / 2.));
1068 };
1069 }
1070
1071 switch ((SkyObject::TYPE)type)
1072 {
1073 case SkyObject::STAR:
1074 case SkyObject::CATALOG_STAR: //catalog star
1075 //Some NGC/IC objects are stars...changed their type to 1 (was double star)
1076 if (size < 2.)
1077 size = 2.;
1078 lambdaDrawEllipse(x - size / 2., y - size / 2., size, size);
1079 break;
1080 case SkyObject::PLANET: //Planet
1081 break;
1082 case SkyObject::OPEN_CLUSTER: //Open cluster; draw circle of points
1083 case SkyObject::ASTERISM: // Asterism
1084 {
1085 tempBrush = brush();
1086 color = pen().color().name();
1087 setBrush(pen().color());
1088 psize = 2.;
1089 if (size > 50.)
1090 psize *= 2.;
1091 if (size > 100.)
1092 psize *= 2.;
1093 auto putDot = [psize, &lambdaDrawEllipse](float x, float y)
1094 {
1095 lambdaDrawEllipse(x - psize / 2., y - psize / 2., psize, psize);
1096 };
1097 putDot(xa, y1);
1098 putDot(xb, y1);
1099 putDot(xa, y2);
1100 putDot(xb, y2);
1101 putDot(x1, ya);
1102 putDot(x1, yb);
1103 putDot(x2, ya);
1104 putDot(x2, yb);
1105 setBrush(tempBrush);
1106 break;
1107 }
1108 case SkyObject::GLOBULAR_CLUSTER: //Globular Cluster
1109 if (size < 2.)
1110 size = 2.;
1111 save();
1112 translate(x, y);
1113 color = pen().color().name();
1114 rotate(positionAngle); //rotate the coordinate system
1115 lambdaDrawEllipse(dx1, dy1, size, e * size);
1116 lambdaDrawCross(0, 0, size, e * size);
1117 restore(); //reset coordinate system
1118 break;
1119
1120 case SkyObject::GASEOUS_NEBULA: //Gaseous Nebula
1121 case SkyObject::DARK_NEBULA: // Dark Nebula
1122 save();
1123 translate(x, y);
1124 rotate(positionAngle); //rotate the coordinate system
1125 color = pen().color().name();
1126 lambdaDrawLine(dx1, dy1, dx2, dy1);
1127 lambdaDrawLine(dx2, dy1, dx2, dy2);
1128 lambdaDrawLine(dx2, dy2, dx1, dy2);
1129 lambdaDrawLine(dx1, dy2, dx1, dy1);
1130 restore(); //reset coordinate system
1131 break;
1132 case SkyObject::PLANETARY_NEBULA: //Planetary Nebula
1133 if (size < 2.)
1134 size = 2.;
1135 save();
1136 translate(x, y);
1137 rotate(positionAngle); //rotate the coordinate system
1138 color = pen().color().name();
1139 lambdaDrawEllipse(dx1, dy1, size, e * size);
1140 lambdaDrawLine(0., dy1, 0., dy1 - e * size / 2.);
1141 lambdaDrawLine(0., dy2, 0., dy2 + e * size / 2.);
1142 lambdaDrawLine(dx1, 0., dx1 - size / 2., 0.);
1143 lambdaDrawLine(dx2, 0., dx2 + size / 2., 0.);
1144 restore(); //reset coordinate system
1145 break;
1146 case SkyObject::SUPERNOVA_REMNANT: //Supernova remnant // FIXME: Why is SNR drawn different from a gaseous nebula?
1147 save();
1148 translate(x, y);
1149 rotate(positionAngle); //rotate the coordinate system
1150 color = pen().color().name();
1151 lambdaDrawLine(0., dy1, dx2, 0.);
1152 lambdaDrawLine(dx2, 0., 0., dy2);
1153 lambdaDrawLine(0., dy2, dx1, 0.);
1154 lambdaDrawLine(dx1, 0., 0., dy1);
1155 restore(); //reset coordinate system
1156 break;
1157 case SkyObject::GALAXY: //Galaxy
1158 case SkyObject::QUASAR: // Quasar
1159 color = pen().color().name();
1160 if (size < 1. && zoom > 20 * MINZOOM)
1161 size = 3.; //force ellipse above zoomFactor 20
1162 if (size < 1. && zoom > 5 * MINZOOM)
1163 size = 1.; //force points above zoomFactor 5
1164 if (size > 2.)
1165 {
1166 save();
1167 translate(x, y);
1168 rotate(positionAngle); //rotate the coordinate system
1169 lambdaDrawEllipse(dx1, dy1, size, e * size);
1170 restore(); //reset coordinate system
1171 }
1172 else if (size > 0.)
1173 {
1174 drawPoint(QPointF(x, y));
1175 }
1176 break;
1177 case SkyObject::GALAXY_CLUSTER: // Galaxy cluster - draw a dashed circle
1178 {
1179 tempBrush = brush();
1180 setBrush(QBrush());
1181 color = pen().color().name();
1182 save();
1183 translate(x, y);
1184 rotate(positionAngle); //rotate the coordinate system
1185 QPen newPen = pen();
1186 newPen.setStyle(Qt::DashLine);
1187 setPen(newPen);
1188 lambdaDrawEllipse(dx1, dy1, size, e * size);
1189 restore();
1190 setBrush(tempBrush);
1191 break;
1192 }
1193 default
1194: // Unknown object or something we don't know how to draw. Just draw an ellipse with a ?-mark
1195 color = pen().color().name();
1196 if (size < 1. && zoom > 20 * MINZOOM)
1197 size = 3.; //force ellipse above zoomFactor 20
1198 if (size < 1. && zoom > 5 * MINZOOM)
1199 size = 1.; //force points above zoomFactor 5
1200 if (size > 2.)
1201 {
1202 save();
1203 QFont f = font();
1204 const QString qMark = " ? ";
1205
1206#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1207 double scaleFactor = 0.8 * size / fontMetrics().horizontalAdvance(qMark);
1208#else
1209 double scaleFactor = 0.8 * size / fontMetrics().width(qMark);
1210#endif
1211
1212 f.setPointSizeF(f.pointSizeF() * scaleFactor);
1213 setFont(f);
1214 translate(x, y);
1215 rotate(positionAngle); //rotate the coordinate system
1216 lambdaDrawEllipse(dx1, dy1, size, e * size);
1217 if (Options::useAntialias())
1218 drawText(QRectF(dx1, dy1, size, e * size), Qt::AlignCenter, qMark);
1219 else
1220 {
1221 int idx1 = int(dx1);
1222 int idy1 = int(dy1);
1223 drawText(QRect(idx1, idy1, isize, int(e * size)), Qt::AlignCenter,
1224 qMark);
1225 }
1226 restore(); //reset coordinate system (and font?)
1227 }
1228 else if (size > 0.)
1229 {
1230 if (Options::useAntialias())
1231 drawPoint(QPointF(x, y));
1232 else
1233 drawPoint(QPoint(x, y));
1234 }
1235 }
1236}
1237
1239{
1240 foreach (SkyObject *obj, obs)
1241 {
1242 bool visible = false;
1243 QPointF o = m_proj->toScreen(obj, true, &visible);
1244 if (!visible || !m_proj->onScreen(o))
1245 continue;
1246
1247 float size = 20.;
1248 float x1 = o.x() - 0.5 * size;
1249 float y1 = o.y() - 0.5 * size;
1250 drawArc(QRectF(x1, y1, size, size), -60 * 16, 120 * 16);
1251 drawArc(QRectF(x1, y1, size, size), 120 * 16, 120 * 16);
1252 }
1253}
1254
1256{
1257 KStarsData *data = KStarsData::Instance();
1258 std::shared_ptr<SkyPoint> point;
1259 QImage image;
1260 bool visible = false;
1261 QPointF pos;
1262
1263 for (int i = 0; i < data->skyComposite()->flags()->size(); i++)
1264 {
1265 point = data->skyComposite()->flags()->pointList().at(i);
1266 image = data->skyComposite()->flags()->image(i);
1267
1268 // Set Horizontal coordinates
1269 point->EquatorialToHorizontal(data->lst(), data->geo()->lat());
1270
1271 // Get flag position on screen
1272 pos = m_proj->toScreen(point.get(), true, &visible);
1273
1274 // Return if flag is not visible
1275 if (!visible || !m_proj->onScreen(pos))
1276 continue;
1277
1278 // Draw flag image
1279 drawImage(pos.x() - 0.5 * image.width(), pos.y() - 0.5 * image.height(), image);
1280
1281 // Draw flag label
1282 setPen(data->skyComposite()->flags()->labelColor(i));
1283 setFont(QFont("Helvetica", 10, QFont::Bold));
1284 drawText(pos.x() + 10, pos.y() - 10, data->skyComposite()->flags()->label(i));
1285 }
1286}
1287
1288void SkyQPainter::drawHorizon(bool filled, SkyPoint * labelPoint, bool * drawLabel)
1289{
1290 QVector<Eigen::Vector2f> ground = m_proj->groundPoly(labelPoint, drawLabel);
1291 if (ground.size())
1292 {
1293 QPolygonF groundPoly(ground.size());
1294 for (int i = 0; i < ground.size(); ++i)
1295 groundPoly[i] = KSUtils::vecToPoint(ground[i]);
1296 if (filled)
1297 drawPolygon(groundPoly);
1298 else
1299 {
1300 groundPoly.append(groundPoly.first());
1301 drawPolyline(groundPoly);
1302 }
1303 }
1304}
1305
1307{
1308 if (!m_proj->checkVisibility(sat))
1309 return false;
1310
1311 QPointF pos;
1312 bool visible = false;
1313
1314 //sat->HorizontalToEquatorial( data->lst(), data->geo()->lat() );
1315
1316 pos = m_proj->toScreen(sat, true, &visible);
1317
1318 if (!visible || !m_proj->onScreen(pos))
1319 return false;
1320
1321 if (Options::drawSatellitesLikeStars())
1322 {
1323 drawPointSource(pos, 3.5, 'B');
1324 }
1325 else
1326 {
1327 if (sat->isVisible())
1328 drawPixmap(QPoint(pos.x() - 15, pos.y() - 11), *visibleSatPixmap);
1329 else
1330 drawPixmap(QPoint(pos.x() - 15, pos.y() - 11), *invisibleSatPixmap);
1331
1332 //drawPixmap(pos, *genericSatPixmap);
1333 /*drawLine( QPoint( pos.x() - 0.5, pos.y() - 0.5 ), QPoint( pos.x() + 0.5, pos.y() - 0.5 ) );
1334 drawLine( QPoint( pos.x() + 0.5, pos.y() - 0.5 ), QPoint( pos.x() + 0.5, pos.y() + 0.5 ) );
1335 drawLine( QPoint( pos.x() + 0.5, pos.y() + 0.5 ), QPoint( pos.x() - 0.5, pos.y() + 0.5 ) );
1336 drawLine( QPoint( pos.x() - 0.5, pos.y() + 0.5 ), QPoint( pos.x() - 0.5, pos.y() - 0.5 ) );*/
1337 }
1338
1339 return true;
1340
1341 //if ( Options::showSatellitesLabels() )
1342 //data->skyComposite()->satellites()->drawLabel( sat, pos );
1343}
1344
1346{
1347 KStarsData *data = KStarsData::Instance();
1348 if (!m_proj->checkVisibility(sup))
1349 {
1350 return false;
1351 }
1352
1353 bool visible = false;
1354 QPointF pos = m_proj->toScreen(sup, true, &visible);
1355 //qDebug()<<"sup->ra() = "<<(sup->ra()).toHMSString()<<"sup->dec() = "<<sup->dec().toDMSString();
1356 //qDebug()<<"pos = "<<pos<<"m_proj->onScreen(pos) = "<<m_proj->onScreen(pos);
1357 if (!visible || !m_proj->onScreen(pos))
1358 return false;
1359
1360 setPen(data->colorScheme()->colorNamed("SupernovaColor"));
1361 //qDebug()<<"Here";
1362 drawLine(QPoint(pos.x() - 2.0, pos.y()), QPoint(pos.x() + 2.0, pos.y()));
1363 drawLine(QPoint(pos.x(), pos.y() - 2.0), QPoint(pos.x(), pos.y() + 2.0));
1364 return true;
1365}
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
float e() const
std::pair< bool, const QImage & > image() const
Get the image for this object.
float a() const
double pa() const override
QColor colorNamed(const QString &name) const
Retrieve a color by name.
Information about a ConstellationsArt object.
const QImage & image()
QColor labelColor(int index)
Get label color.
QString label(int index)
Get label.
QImage image(int index)
Get image.
const CachingDms * lat() const
Definition geolocation.h:70
A subclass of KSPlanetBase that implements asteroids.
Definition ksasteroid.h:42
A subclass of KSPlanetBase that implements comets.
Definition kscomet.h:44
dms getComaAngSize()
Definition kscomet.h:109
A class that manages the calculation of the earths shadow (in moon distance) as a 'virtual' skyobject...
double getPenumbraAngSize() const
double getUmbraAngSize() const
Provides necessary information about the Moon.
Definition ksmoon.h:26
A subclass of TrailObject that provides additional information needed for most solar system objects.
const QImage & image() const
double angSize() const
Child class of KSPlanetBase; encapsulates information about the Sun.
Definition kssun.h:24
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
CachingDms * lst()
Definition kstarsdata.h:224
ColorScheme * colorScheme()
Definition kstarsdata.h:172
GeoLocation * geo()
Definition kstarsdata.h:230
SkyMapComposite * skyComposite()
Definition kstarsdata.h:166
static KStars * Instance()
Definition kstars.h:123
A simple data container used by LineListIndex.
Definition linelist.h:25
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 findPA(const SkyObject *o, float x, float y) const
Determine the on-screen position angle of a SkyObject.
bool onScreen(const QPointF &p) const
Check whether the projected point is on-screen.
Definition projector.cpp:98
double findNorthPA(const SkyPoint *o, float x, float y) const
Determine the on-screen position angle of a SkyPont with recept with NCP.
bool checkVisibility(const SkyPoint *p) const
Determine if the skypoint p is likely to be visible in the display window.
virtual QVector< Eigen::Vector2f > groundPoly(SkyPoint *labelpoint=nullptr, bool *drawLabel=nullptr) const
Get the ground polygon.
QPointF clipLine(SkyPoint *p1, SkyPoint *p2) const
ASSUMES *p1 did not clip but *p2 did.
This class checks if two rectangles overlap.
bool intersects(const QPointF &center, int width, int height, double rotationDegrees=0.0) const
Check if the input rectangle overlaps the reference rectangle.
Represents an artificial satellites.
Definition satellite.h:23
bool isVisible()
const Projector * projector() const
Get the current projector.
Definition skymap.h:300
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual QString name(void) const
Definition skyobject.h:145
int type(void) const
Definition skyobject.h:188
float mag() const
Definition skyobject.h:206
TYPE
The type classification of the SkyObject.
Definition skyobject.h:112
Draws things on the sky, without regard to backend.
Definition skypainter.h:40
float starWidth(float mag) const
Get the width of a star of magnitude mag.
The sky coordinates of a point in the sky.
Definition skypoint.h:45
void apparentCoord(long double jd0, long double jdf)
Computes the apparent coordinates for this SkyPoint for any epoch, accounting for the effects of prec...
Definition skypoint.cpp:700
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
Definition skypoint.cpp:899
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
bool drawAsteroid(KSAsteroid *ast) override
Draw an asteroid in the sky.
bool drawComet(KSComet *com) override
Draw a comet in the sky.
void end() override
End and finalize painting.
SkyQPainter(QPaintDevice *pd, const QSize &canvasSize)
Creates a SkyQPainter with the given QPaintDevice and uses the dimensions of the paint device as canv...
bool drawPlanet(KSPlanetBase *planet) override
Draw a planet.
bool drawPointSource(const SkyPoint *loc, float mag, char sp='A') override
Draw a point source (e.g., a star).
void drawSkyLine(SkyPoint *a, SkyPoint *b) override
Draw a line between points in the sky.
bool drawImageOverlay(const QList< ImageOverlay > *imageOverlays, bool useCache=false) override
drawImageOverlay Draws a user-supplied image onto the skymap
void setBrush(const QBrush &brush) override
Set the brush of the painter.
void drawSkyPolyline(LineList *list, SkipHashList *skipList=nullptr, LineListLabel *label=nullptr) override
Draw a polyline in the sky.
bool drawTerrain(bool useCache=false) override
drawTerrain Draw the Terrain
void drawSkyPolygon(LineList *list, bool forceClip=true) override
Draw a polygon in the sky.
void drawSkyBackground() override
Draw the sky background.
bool drawCatalogObject(const CatalogObject &obj) override
Draw a deep sky object (loaded from the new implementation)
void drawObservingList(const QList< SkyObject * > &obs) override
Draw the symbols for the observing list.
static void initStarImages()
Recalculates the star pixmaps.
static void releaseImageCache()
Release the image cache.
void setPen(const QPen &pen) override
Set the pen of the painter.
bool drawEarthShadow(KSEarthShadow *shadow) override
Draw the earths shadow on the moon (red-ish)
bool drawConstellationArtImage(ConstellationsArt *obj) override
Draw a ConstellationsArt object.
void drawFlags() override
Draw flags.
bool drawSupernova(Supernova *sup) override
Draw a Supernova.
bool drawHips(bool useCache=false) override
drawMosaicPanel Draws mosaic panel in planning or operation mode.
bool drawSatellite(Satellite *sat) override
Draw a satellite.
void begin() override
Begin painting.
Represents the supernova object.
Definition supernova.h:34
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
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
int arcmin() const
Definition dms.cpp:180
const double & Degrees() const
Definition dms.h:141
QString i18n(const char *text, const TYPE &arg...)
int blue() const const
QColor fromRgb(QRgb rgb)
void getHsvF(float *h, float *s, float *v, float *a) const const
int green() const const
QString name(NameFormat format) const const
int red() const const
void setHsvF(float h, float s, float v, float a)
int horizontalAdvance(QChar ch) const const
void setColorAt(qreal position, const QColor &color)
Format_ARGB32_Premultiplied
int height() const const
bool isNull() const const
int width() const const
const_reference at(qsizetype i) const const
qsizetype size() const const
void clear()
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
QList< Key > keys() const const
T value(const Key &key, const T &defaultValue) const const
int height() const const
int width() const const
bool begin(QPaintDevice *device)
const QBrush & brush() const const
CompositionMode compositionMode() const const
void drawArc(const QRect &rectangle, int startAngle, int spanAngle)
void drawConvexPolygon(const QPoint *points, int pointCount)
void drawEllipse(const QPoint &center, int rx, int ry)
void drawImage(const QPoint &point, const QImage &image)
void drawLine(const QLine &line)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawPoint(const QPoint &position)
void drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
void drawPolyline(const QPoint *points, int pointCount)
void drawText(const QPoint &position, const QString &text)
bool end()
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
QFontMetrics fontMetrics() const const
const QPen & pen() const const
void restore()
void rotate(qreal angle)
void save()
void scale(qreal sx, qreal sy)
void setBrush(Qt::BrushStyle style)
void setCompositionMode(CompositionMode mode)
void setFont(const QFont &font)
void setOpacity(qreal opacity)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void setRenderHints(RenderHints hints, bool on)
void translate(const QPoint &offset)
QRect viewport() const const
QColor color() const const
void setStyle(Qt::PenStyle style)
void fill(const QColor &color)
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
int width() const const
QPoint toPoint() const const
qreal x() const const
qreal y() const const
QPoint point(int index) const const
int height() const const
int width() const const
T * data() const const
void reset(T *other)
int height() const const
void setHeight(int height)
void setWidth(int width)
int width() const const
AlignCenter
KeepAspectRatio
DashLine
SmoothTransformation
QLine map(const QLine &l) const const
QTransform & rotate(qreal a, Qt::Axis axis)
QTransform & translate(qreal dx, qreal dy)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:52 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.