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 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
313 float h, s, v, a;
314 #else
315 qreal h, s, v, a;
316 #endif
318 QColor starColor = ColorMap[color];
319 starColor.getHsvF(&h, &s, &v, &a);
320 for (int i = 0; i < 8; i++)
321 {
322 for (int j = 0; j < 8; j++)
323 {
324 qreal x = i - 7;
325 qreal y = j - 7;
326 qreal dist = sqrt(x * x + y * y) / 7.0;
327 starColor.setHsvF(
328 h,
329 qMin(qreal(1),
330 dist < (10 - starColorIntensity) / 10.0 ? 0 : dist),
331 v,
332 qMax(qreal(0),
333 dist < (10 - starColorIntensity) / 20.0 ? 1 : 1 - dist));
334 p.setPen(starColor);
335 p.drawPoint(i, j);
336 p.drawPoint(14 - i, j);
337 p.drawPoint(i, 14 - j);
338 p.drawPoint(14 - i, 14 - j);
339 }
340 }
341 }
342 else
343 {
345 p.setPen(QPen(ColorMap[color], 2.0));
346 p.setBrush(p.pen().color());
347 p.drawEllipse(QRectF(2, 2, 10, 10));
348 }
349 p.end();
350
351 // Cache array slice
352 QPixmap **pmap = imageCache[harvardToIndex(color)];
353
354 for (int size = 1; size < nStarSizes; size++)
355 {
356 if (!pmap[size])
357 pmap[size] = new QPixmap();
358 *pmap[size] = BigImage.scaled(size, size, Qt::KeepAspectRatio,
360 }
361 }
362 starColorMode = Options::starColorMode();
363
364 if (!visibleSatPixmap.get())
365 visibleSatPixmap.reset(new QPixmap(":/icons/kstars_satellites_visible.svg"));
366 if (!invisibleSatPixmap.get())
367 invisibleSatPixmap.reset(new QPixmap(":/icons/kstars_satellites_invisible.svg"));
368}
369
371{
372 bool aVisible, bVisible;
373 QPointF aScreen = m_proj->toScreen(a, true, &aVisible);
374 QPointF bScreen = m_proj->toScreen(b, true, &bVisible);
375
376 drawLine(aScreen, bScreen);
377
378 //THREE CASES:
379 // if (aVisible && bVisible)
380 // {
381 // //Both a,b visible, so paint the line normally:
382 // drawLine(aScreen, bScreen);
383 // }
384 // else if (aVisible)
385 // {
386 // //a is visible but b isn't:
387 // drawLine(aScreen, m_proj->clipLine(a, b));
388 // }
389 // else if (bVisible)
390 // {
391 // //b is visible but a isn't:
392 // drawLine(bScreen, m_proj->clipLine(b, a));
393 // } //FIXME: what if both are offscreen but the line isn't?
394}
395
396void SkyQPainter::drawSkyPolyline(LineList * list, SkipHashList * skipList,
397 LineListLabel * label)
398{
399 SkyList *points = list->points();
400 bool isVisible, isVisibleLast;
401
402 if (points->size() == 0)
403 return;
404 QPointF oLast = m_proj->toScreen(points->first().get(), true, &isVisibleLast);
405 // & with the result of checkVisibility to clip away things below horizon
406 isVisibleLast &= m_proj->checkVisibility(points->first().get());
407 QPointF oThis, oThis2;
408
409 for (int j = 1; j < points->size(); j++)
410 {
411 SkyPoint *pThis = points->at(j).get();
412
413 oThis2 = oThis = m_proj->toScreen(pThis, true, &isVisible);
414 // & with the result of checkVisibility to clip away things below horizon
415 isVisible &= m_proj->checkVisibility(pThis);
416 bool doSkip = false;
417 if (skipList)
418 {
419 doSkip = skipList->skip(j);
420 }
421
422 bool pointsVisible = false;
423 //Temporary solution to avoid random lines in Gnomonic projection and draw lines up to horizon
424 if (SkyMap::Instance()->projector()->type() == Projector::Gnomonic)
425 {
426 if (isVisible && isVisibleLast)
427 pointsVisible = true;
428 }
429 else
430 {
431 if (isVisible || isVisibleLast)
432 pointsVisible = true;
433 }
434
435 if (!doSkip)
436 {
437 if (pointsVisible)
438 {
439 drawLine(oLast, oThis);
440 if (label)
441 label->updateLabelCandidates(oThis.x(), oThis.y(), list, j);
442 }
443 }
444
445 oLast = oThis2;
446 isVisibleLast = isVisible;
447 }
448}
449
450void SkyQPainter::drawSkyPolygon(LineList * list, bool forceClip)
451{
452 bool isVisible = false, isVisibleLast;
453 SkyList *points = list->points();
454 QPolygonF polygon;
455
456 if (forceClip == false)
457 {
458 for (const auto &point : *points)
459 {
460 polygon << m_proj->toScreen(point.get(), false, &isVisibleLast);
461 isVisible |= isVisibleLast;
462 }
463
464 // If 1+ points are visible, draw it
465 if (polygon.size() && isVisible)
466 drawPolygon(polygon);
467
468 return;
469 }
470
471 SkyPoint *pLast = points->last().get();
472 QPointF oLast = m_proj->toScreen(pLast, true, &isVisibleLast);
473 // & with the result of checkVisibility to clip away things below horizon
474 isVisibleLast &= m_proj->checkVisibility(pLast);
475
476 for (const auto &point : *points)
477 {
478 SkyPoint *pThis = point.get();
479 QPointF oThis = m_proj->toScreen(pThis, true, &isVisible);
480 // & with the result of checkVisibility to clip away things below horizon
481 isVisible &= m_proj->checkVisibility(pThis);
482
483 if (isVisible && isVisibleLast)
484 {
485 polygon << oThis;
486 }
487 else if (isVisibleLast)
488 {
489 QPointF oMid = m_proj->clipLine(pLast, pThis);
490 polygon << oMid;
491 }
492 else if (isVisible)
493 {
494 QPointF oMid = m_proj->clipLine(pThis, pLast);
495 polygon << oMid;
496 polygon << oThis;
497 }
498
499 pLast = pThis;
500 oLast = oThis;
501 isVisibleLast = isVisible;
502 }
503
504 if (polygon.size())
505 drawPolygon(polygon);
506}
507
509{
510 if (!m_proj->checkVisibility(planet))
511 return false;
512
513 bool visible = false;
514 QPointF pos = m_proj->toScreen(planet, true, &visible);
515 if (!visible || !m_proj->onScreen(pos))
516 return false;
517
518 float fakeStarSize = (10.0 + log10(Options::zoomFactor()) - log10(MINZOOM)) *
519 (10 - planet->mag()) / 10;
520 if (fakeStarSize > 15.0)
521 fakeStarSize = 15.0;
522
523 double size = planet->angSize() * dms::PI * Options::zoomFactor() / 10800.0;
524 if (size < fakeStarSize && planet->name() != i18n("Sun") &&
525 planet->name() != i18n("Moon"))
526 {
527 // Draw them as bright stars of appropriate color instead of images
528 char spType;
529 //FIXME: do these need i18n?
530 if (planet->name() == i18n("Mars"))
531 {
532 spType = 'K';
533 }
534 else if (planet->name() == i18n("Jupiter") || planet->name() == i18n("Mercury") ||
535 planet->name() == i18n("Saturn"))
536 {
537 spType = 'F';
538 }
539 else
540 {
541 spType = 'B';
542 }
543 drawPointSource(pos, fakeStarSize, spType);
544 }
545 else
546 {
547 float sizemin = 1.0;
548 if (planet->name() == i18n("Sun") || planet->name() == i18n("Moon"))
549 sizemin = 8.0;
550 if (planet->name() == i18n("Sun")) size = size * Options::sunScale();
551 if (planet->name() == i18n("Moon")) size = size * Options::moonScale();
552
553 if (size < sizemin)
554 size = sizemin;
555
556 if (Options::showPlanetImages() && !planet->image().isNull())
557 {
558 //Because Saturn has rings, we inflate its image size by a factor 2.5
559 if (planet->name() == "Saturn")
560 size = int(2.5 * size);
561 // Scale size exponentially so it is visible at large zooms
562 else if (planet->name() == "Pluto")
563 size = int(size * exp(1.5 * size));
564
565 save();
566 translate(pos);
567 rotate(m_proj->findPA(planet, pos.x(), pos.y()));
568
570 // Use the Screen composition mode for the Moon to make it look nicer, especially the non-full
571 // phases. When doing this, though, stars would shine through, so need to paint in the skycolor
572 // behind it.
573 if (planet->name() == i18n("Moon"))
574 {
575 auto keepBrush = brush();
576 auto keepPen = pen();
577 setBrush(skyColor());
578 setPen(skyColor());
580 drawEllipse(QRectF(-0.5 * size, -0.5 * size, size, size));
581 setBrush(keepBrush);
582 setPen(keepPen);
584 }
585 drawImage(QRectF(-0.5 * size, -0.5 * size, size, size), planet->image());
586 setCompositionMode(mode);
587
588 restore();
589 }
590 else //Otherwise, draw a simple circle.
591 {
592 drawEllipse(pos, size * .5, size * .5);
593 }
594 }
595 return true;
596}
597
599{
600 if (!m_proj->checkVisibility(shadow))
601 return false;
602
603 bool visible = false;
604 QPointF pos = m_proj->toScreen(shadow, true, &visible);
605
606 if (!visible)
607 return false;
608
609 double umbra_size =
610 shadow->getUmbraAngSize() * dms::PI * Options::zoomFactor() / 10800.0;
611 double penumbra_size =
612 shadow->getPenumbraAngSize() * dms::PI * Options::zoomFactor() / 10800.0;
613
614 save();
615 setBrush(QBrush(QColor(255, 96, 38, 128)));
616 drawEllipse(pos, umbra_size, umbra_size);
617 setBrush(QBrush(QColor(255, 96, 38, 90)));
618 drawEllipse(pos, penumbra_size, penumbra_size);
619 restore();
620
621 return true;
622}
623
625{
626 if (!m_proj->checkVisibility(com))
627 return false;
628
629 double size =
630 com->angSize() * dms::PI * Options::zoomFactor() / 10800.0 / 2; // Radius
631 if (size < 1)
632 size = 1;
633
634 bool visible = false;
635 QPointF pos = m_proj->toScreen(com, true, &visible);
636
637 // Draw the coma. FIXME: Another Check??
638 if (visible && m_proj->onScreen(pos))
639 {
640 // Draw the comet.
641 drawEllipse(pos, size, size);
642
643 double comaLength =
644 (com->getComaAngSize().arcmin() * dms::PI * Options::zoomFactor() / 10800.0);
645
646 // If coma is visible and long enough.
647 if (Options::showCometComas() && comaLength > size)
648 {
649 KSSun *sun =
650 KStarsData::Instance()->skyComposite()->solarSystemComposite()->sun();
651
652 // Find the angle to the sun.
653 double comaAngle = m_proj->findPA(sun, pos.x(), pos.y());
654
655 const QVector<QPoint> coma = { QPoint(pos.x() - size, pos.y()),
656 QPoint(pos.x() + size, pos.y()),
657 QPoint(pos.x(), pos.y() + comaLength)
658 };
659
660 QPolygon comaPoly(coma);
661
662 comaPoly =
663 QTransform()
664 .translate(pos.x(), pos.y())
665 .rotate(
666 comaAngle) // Already + 180 Deg, because rotated from south, not north.
667 .translate(-pos.x(), -pos.y())
668 .map(comaPoly);
669
670 save();
671
672 // Nice fade for the Coma.
673 QLinearGradient linearGrad(pos, comaPoly.point(2));
674 linearGrad.setColorAt(0, QColor("white"));
675 linearGrad.setColorAt(size / comaLength, QColor("white"));
676 linearGrad.setColorAt(0.9, QColor("transparent"));
677 setBrush(linearGrad);
678
679 // Render Coma.
680 drawConvexPolygon(comaPoly);
681 restore();
682 }
683
684 return true;
685 }
686 else
687 {
688 return false;
689 }
690}
691
693{
694 if (!m_proj->checkVisibility(ast))
695 {
696 return false;
697 }
698
699 bool visible = false;
700 QPointF pos = m_proj->toScreen(ast, true, &visible);
701
702 if (visible && m_proj->onScreen(pos))
703 {
704 KStarsData *data = KStarsData::Instance();
705
706 setPen(data->colorScheme()->colorNamed("AsteroidColor"));
707 drawLine(QPoint(pos.x() - 1.0, pos.y()), QPoint(pos.x() + 1.0, pos.y()));
708 drawLine(QPoint(pos.x(), pos.y() - 1.0), QPoint(pos.x(), pos.y() + 1.0));
709
710 return true;
711 }
712
713 return false;
714}
715
716bool SkyQPainter::drawPointSource(const SkyPoint * loc, float mag, char sp)
717{
718 //Check if it's even visible before doing anything
719 if (!m_proj->checkVisibility(loc))
720 return false;
721
722 bool visible = false;
723 QPointF pos = m_proj->toScreen(loc, true, &visible);
724 // FIXME: onScreen here should use canvas size rather than SkyMap size, especially while printing in portrait mode!
725 if (visible && m_proj->onScreen(pos))
726 {
727 drawPointSource(pos, starWidth(mag), sp);
728 return true;
729 }
730 else
731 {
732 return false;
733 }
734}
735
736void SkyQPainter::drawPointSource(const QPointF &pos, float size, char sp)
737{
738 int isize = qMin(static_cast<int>(size), 14);
739 if (!m_vectorStars || starColorMode == 0)
740 {
741 // Draw stars as bitmaps, either because we were asked to, or because we're painting real colors
742 QPixmap *im = imageCache[harvardToIndex(sp)][isize];
743 float offset = 0.5 * im->width();
744 drawPixmap(QPointF(pos.x() - offset, pos.y() - offset), *im);
745 }
746 else
747 {
748 // Draw stars as vectors, for better printing / SVG export etc.
749 if (starColorMode != 4)
750 {
751 setPen(m_starColor);
752 setBrush(m_starColor);
753 }
754 else
755 {
756 // 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.
757 QColor c = ColorMap.value(sp, Qt::white);
758 setPen(c);
759 setBrush(c);
760 }
761
762 // Be consistent with old raster representation
763 if (size > 14)
764 size = 14;
765 if (size >= 2)
766 drawEllipse(pos.x() - 0.5 * size, pos.y() - 0.5 * size, int(size), int(size));
767 else if (size >= 1)
768 drawPoint(pos.x(), pos.y());
769 }
770}
771
773{
774 double zoom = Options::zoomFactor();
775
776 bool visible = false;
777 obj->EquatorialToHorizontal(KStarsData::Instance()->lst(),
778 KStarsData::Instance()->geo()->lat());
779 QPointF constellationmidpoint = m_proj->toScreen(obj, true, &visible);
780
781 if (!visible || !m_proj->onScreen(constellationmidpoint))
782 return false;
783
784 //qDebug() << Q_FUNC_INFO << "o->pa() " << obj->pa();
785 float positionangle =
786 m_proj->findPA(obj, constellationmidpoint.x(), constellationmidpoint.y());
787 //qDebug() << Q_FUNC_INFO << " final PA " << positionangle;
788
789 float w = obj->getWidth() * 60 * dms::PI * zoom / 10800;
790 float h = obj->getHeight() * 60 * dms::PI * zoom / 10800;
791
792 save();
793
795
796 translate(constellationmidpoint);
797 rotate(positionangle);
798 if (m_proj->viewParams().mirror)
799 {
800 scale(-1., 1.);
801 }
802 setOpacity(0.7);
803 drawImage(QRectF(-0.5 * w, -0.5 * h, w, h), obj->image());
804 setOpacity(1);
805
807 restore();
808 return true;
809}
810
811#ifdef HAVE_INDI
812bool SkyQPainter::drawMosaicPanel(MosaicTiles * obj)
813{
814 bool visible = false;
815 obj->EquatorialToHorizontal(KStarsData::Instance()->lst(),
816 KStarsData::Instance()->geo()->lat());
817 QPointF tileMid = m_proj->toScreen(obj, true, &visible);
818
819 if (!visible || !m_proj->onScreen(tileMid) || !obj->isValid())
820 return false;
821
822 //double northRotation = m_proj->findNorthPA(obj, tileMid.x(), tileMid.y())
823
824 // convert 0 to +180 EAST, and 0 to -180 WEST to 0 to 360 CCW
825 const auto mirror = m_proj->viewParams().mirror;
826 auto PA = (obj->positionAngle() < 0) ? obj->positionAngle() + 360 : obj->positionAngle();
827 auto finalPA = m_proj->findNorthPA(obj, tileMid.x(), tileMid.y()) - (mirror ? -PA : PA);
828
829 save();
830 translate(tileMid.toPoint());
831 rotate(finalPA);
832 obj->draw(this);
833 restore();
834
835 return true;
836}
837#endif
838
839bool SkyQPainter::drawHips(bool useCache)
840{
841 int w = viewport().width();
842 int h = viewport().height();
843
844 if (useCache && m_HiPSImage)
845 {
846 drawImage(viewport(), *m_HiPSImage.data());
847 return true;
848 }
849 else
850 {
851 m_HiPSImage.reset(new QImage(w, h, QImage::Format_ARGB32_Premultiplied));
852 bool rendered = m_hipsRender->render(w, h, m_HiPSImage.data(), m_proj);
853 if (rendered)
854 drawImage(viewport(), *m_HiPSImage.data());
855 return rendered;
856 }
857}
858
859bool SkyQPainter::drawTerrain(bool useCache)
860{
861 // TODO
862 Q_UNUSED(useCache);
863 int w = viewport().width();
864 int h = viewport().height();
865 QImage *terrainImage = new QImage(w, h, QImage::Format_ARGB32_Premultiplied);
866 TerrainRenderer *renderer = TerrainRenderer::Instance();
867 bool rendered = renderer->render(w, h, terrainImage, m_proj);
868 if (rendered)
869 drawImage(viewport(), *terrainImage);
870
871 delete (terrainImage);
872 return rendered;
873}
874
875bool SkyQPainter::drawImageOverlay(const QList<ImageOverlay> *imageOverlays, bool useCache)
876{
877 Q_UNUSED(useCache);
878 if (!Options::showImageOverlays())
879 return false;
880
881 constexpr int minDisplayDimension = 5;
882
883 // Convert the RA/DEC from j2000 to jNow and add in az/alt computations.
884 auto localTime = KStarsData::Instance()->geo()->UTtoLT(KStarsData::Instance()->clock()->utc());
885
886 const ViewParams view = m_proj->viewParams();
887 const double vw = view.width, vh = view.height;
888 RectangleOverlap overlap(QPointF(vw / 2.0, vh / 2.0), vw, vh);
889
890 // QElapsedTimer drawTimer;
891 // drawTimer.restart();
892 int numDrawn = 0;
893 for (const ImageOverlay &o : *imageOverlays)
894 {
895 if (o.m_Status != ImageOverlay::AVAILABLE || o.m_Img.get() == nullptr)
896 continue;
897
898 double orientation = o.m_Orientation, ra = o.m_RA, dec = o.m_DEC, scale = o.m_ArcsecPerPixel;
899 const int origWidth = o.m_Width, origHeight = o.m_Height;
900
901 // Not sure why I have to do this, suspect it's related to the East-to-the-right thing.
902 // Note that I have mirrored the image above, so east-to-the-right=false is now east-to-the-right=true
903 // BTW, solver gave me -66, but astrometry.net gave me 246.1 East of North
904 orientation += 180;
905
906 const dms raDms(ra), decDms(dec);
907 SkyPoint coord(raDms, decDms);
908 coord.apparentCoord(static_cast<long double>(J2000), KStars::Instance()->data()->ut().djd());
909 coord.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
910
911 // Find if the object is not visible, or if it is very small.
912 const double a = origWidth * scale / 60.0; // This is the width of the image in arcmin--not the major axis
913 const double zoom = Options::zoomFactor();
914 // W & h are the actual pixel width and height (as doubles) though
915 // the projection size might be smaller.
916 const double w = a * dms::PI * zoom / 10800.0;
917 const double h = w * origHeight / origWidth;
918 const double maxDimension = std::max(w, h);
919 if (maxDimension < minDisplayDimension)
920 continue;
921
922 bool visible;
923 QPointF pos = m_proj->toScreen(&coord, true, &visible);
924 if (!visible || isnan(pos.x()) || isnan(pos.y()))
925 continue;
926
927 const auto PA = (orientation < 0) ? orientation + 360 : orientation;
928 const auto mirror = m_proj->viewParams().mirror;
929 const auto finalPA = m_proj->findNorthPA(&coord, pos.x(), pos.y()) - (mirror ? -PA : PA);
930 if (!overlap.intersects(pos, w, h, finalPA))
931 continue;
932
933 save();
934 translate(pos);
935 rotate(finalPA);
936 if (mirror)
937 {
938 this->scale(-1., 1.);
939 }
940 drawImage(QRectF(-0.5 * w, -0.5 * h, w, h), *(o.m_Img.get()));
941 numDrawn++;
942 restore();
943 }
944 // fprintf(stderr, "DrawTimer: %lldms for %d images\n", drawTimer.elapsed(), numDrawn);
945 return true;
946}
947
948void SkyQPainter::drawCatalogObjectImage(const QPointF &pos, const CatalogObject &obj,
949 float positionAngle)
950{
951 const auto &image = obj.image();
952
953 if (!image.first)
954 return;
955
956 double zoom = Options::zoomFactor();
957 double w = obj.a() * dms::PI * zoom / 10800.0;
958 double h = obj.e() * w;
959
960 save();
961 translate(pos);
962 rotate(positionAngle);
963 drawImage(QRectF(-0.5 * w, -0.5 * h, w, h), image.second);
964 restore();
965}
966
968{
969 if (!m_proj->checkVisibility(&obj))
970 return false;
971
972 bool visible = false;
973 QPointF pos = m_proj->toScreen(&obj, true, &visible);
974 if (!visible || !m_proj->onScreen(pos))
975 return false;
976
977 // if size is 0.0 set it to 1.0, this are normally stars (type 0 and 1)
978 // if we use size 0.0 the star wouldn't be drawn
979 float majorAxis = obj.a();
980 if (majorAxis == 0.0)
981 {
982 majorAxis = 1.0;
983 }
984
985 float size = majorAxis * dms::PI * Options::zoomFactor() / 10800.0;
986
987 const auto mirror = m_proj->viewParams().mirror;
988 const auto positionAngle = m_proj->findNorthPA(&obj, pos.x(), pos.y())
989 - (mirror ? -obj.pa() : obj.pa()) // FIXME: We seem to have two different conventions for PA sign in KStars!
990 + 90.;
991
992 // Draw image
993 if (Options::showInlineImages() && Options::zoomFactor() > 5. * MINZOOM &&
994 !Options::showHIPS())
995 drawCatalogObjectImage(pos, obj, positionAngle);
996
997 // Draw Symbol
998 drawDeepSkySymbol(pos, obj.type(), size, obj.e(), positionAngle);
999
1000 return true;
1001}
1002
1003void SkyQPainter::drawDeepSkySymbol(const QPointF &pos, int type, float size, float e,
1004 float positionAngle)
1005{
1006 float x = pos.x();
1007 float y = pos.y();
1008 float zoom = Options::zoomFactor();
1009
1010 int isize = int(size);
1011
1012 float dx1 = -0.5 * size;
1013 float dx2 = 0.5 * size;
1014 float dy1 = -1.0 * e * size / 2.;
1015 float dy2 = e * size / 2.;
1016 float x1 = x + dx1;
1017 float x2 = x + dx2;
1018 float y1 = y + dy1;
1019 float y2 = y + dy2;
1020
1021 float dxa = -size / 4.;
1022 float dxb = size / 4.;
1023 float dya = -1.0 * e * size / 4.;
1024 float dyb = e * size / 4.;
1025 float xa = x + dxa;
1026 float xb = x + dxb;
1027 float ya = y + dya;
1028 float yb = y + dyb;
1029
1030 QString color;
1031
1032 float psize;
1033
1034 QBrush tempBrush;
1035
1036 std::function<void(float, float, float, float)> lambdaDrawEllipse;
1037 std::function<void(float, float, float, float)> lambdaDrawLine;
1038 std::function<void(float, float, float, float)> lambdaDrawCross;
1039
1040 if (Options::useAntialias())
1041 {
1042 lambdaDrawEllipse = [this](float x, float y, float width, float height)
1043 {
1044 drawEllipse(QRectF(x, y, width, height));
1045 };
1046 lambdaDrawLine = [this](float x1, float y1, float x2, float y2)
1047 {
1048 drawLine(QLineF(x1, y1, x2, y2));
1049 };
1050 lambdaDrawCross = [this](float centerX, float centerY, float sizeX, float sizeY)
1051 {
1052 drawLine(
1053 QLineF(centerX - sizeX / 2., centerY, centerX + sizeX / 2., centerY));
1054 drawLine(
1055 QLineF(centerX, centerY - sizeY / 2., centerX, centerY + sizeY / 2.));
1056 };
1057 }
1058 else
1059 {
1060 lambdaDrawEllipse = [this](float x, float y, float width, float height)
1061 {
1062 drawEllipse(QRect(x, y, width, height));
1063 };
1064 lambdaDrawLine = [this](float x1, float y1, float x2, float y2)
1065 {
1066 drawLine(QLine(x1, y1, x2, y2));
1067 };
1068 lambdaDrawCross = [this](float centerX, float centerY, float sizeX, float sizeY)
1069 {
1070 drawLine(QLine(centerX - sizeX / 2., centerY, centerX + sizeX / 2., centerY));
1071 drawLine(QLine(centerX, centerY - sizeY / 2., centerX, centerY + sizeY / 2.));
1072 };
1073 }
1074
1075 switch ((SkyObject::TYPE)type)
1076 {
1077 case SkyObject::STAR:
1078 case SkyObject::CATALOG_STAR: //catalog star
1079 //Some NGC/IC objects are stars...changed their type to 1 (was double star)
1080 if (size < 2.)
1081 size = 2.;
1082 lambdaDrawEllipse(x - size / 2., y - size / 2., size, size);
1083 break;
1084 case SkyObject::PLANET: //Planet
1085 break;
1086 case SkyObject::OPEN_CLUSTER: //Open cluster; draw circle of points
1087 case SkyObject::ASTERISM: // Asterism
1088 {
1089 tempBrush = brush();
1090 color = pen().color().name();
1091 setBrush(pen().color());
1092 psize = 2.;
1093 if (size > 50.)
1094 psize *= 2.;
1095 if (size > 100.)
1096 psize *= 2.;
1097 auto putDot = [psize, &lambdaDrawEllipse](float x, float y)
1098 {
1099 lambdaDrawEllipse(x - psize / 2., y - psize / 2., psize, psize);
1100 };
1101 putDot(xa, y1);
1102 putDot(xb, y1);
1103 putDot(xa, y2);
1104 putDot(xb, y2);
1105 putDot(x1, ya);
1106 putDot(x1, yb);
1107 putDot(x2, ya);
1108 putDot(x2, yb);
1109 setBrush(tempBrush);
1110 break;
1111 }
1112 case SkyObject::GLOBULAR_CLUSTER: //Globular Cluster
1113 if (size < 2.)
1114 size = 2.;
1115 save();
1116 translate(x, y);
1117 color = pen().color().name();
1118 rotate(positionAngle); //rotate the coordinate system
1119 lambdaDrawEllipse(dx1, dy1, size, e * size);
1120 lambdaDrawCross(0, 0, size, e * size);
1121 restore(); //reset coordinate system
1122 break;
1123
1124 case SkyObject::GASEOUS_NEBULA: //Gaseous Nebula
1125 case SkyObject::DARK_NEBULA: // Dark Nebula
1126 save();
1127 translate(x, y);
1128 rotate(positionAngle); //rotate the coordinate system
1129 color = pen().color().name();
1130 lambdaDrawLine(dx1, dy1, dx2, dy1);
1131 lambdaDrawLine(dx2, dy1, dx2, dy2);
1132 lambdaDrawLine(dx2, dy2, dx1, dy2);
1133 lambdaDrawLine(dx1, dy2, dx1, dy1);
1134 restore(); //reset coordinate system
1135 break;
1136 case SkyObject::PLANETARY_NEBULA: //Planetary Nebula
1137 if (size < 2.)
1138 size = 2.;
1139 save();
1140 translate(x, y);
1141 rotate(positionAngle); //rotate the coordinate system
1142 color = pen().color().name();
1143 lambdaDrawEllipse(dx1, dy1, size, e * size);
1144 lambdaDrawLine(0., dy1, 0., dy1 - e * size / 2.);
1145 lambdaDrawLine(0., dy2, 0., dy2 + e * size / 2.);
1146 lambdaDrawLine(dx1, 0., dx1 - size / 2., 0.);
1147 lambdaDrawLine(dx2, 0., dx2 + size / 2., 0.);
1148 restore(); //reset coordinate system
1149 break;
1150 case SkyObject::SUPERNOVA_REMNANT: //Supernova remnant // FIXME: Why is SNR drawn different from a gaseous nebula?
1151 save();
1152 translate(x, y);
1153 rotate(positionAngle); //rotate the coordinate system
1154 color = pen().color().name();
1155 lambdaDrawLine(0., dy1, dx2, 0.);
1156 lambdaDrawLine(dx2, 0., 0., dy2);
1157 lambdaDrawLine(0., dy2, dx1, 0.);
1158 lambdaDrawLine(dx1, 0., 0., dy1);
1159 restore(); //reset coordinate system
1160 break;
1161 case SkyObject::GALAXY: //Galaxy
1162 case SkyObject::QUASAR: // Quasar
1163 color = pen().color().name();
1164 if (size < 1. && zoom > 20 * MINZOOM)
1165 size = 3.; //force ellipse above zoomFactor 20
1166 if (size < 1. && zoom > 5 * MINZOOM)
1167 size = 1.; //force points above zoomFactor 5
1168 if (size > 2.)
1169 {
1170 save();
1171 translate(x, y);
1172 rotate(positionAngle); //rotate the coordinate system
1173 lambdaDrawEllipse(dx1, dy1, size, e * size);
1174 restore(); //reset coordinate system
1175 }
1176 else if (size > 0.)
1177 {
1178 drawPoint(QPointF(x, y));
1179 }
1180 break;
1181 case SkyObject::GALAXY_CLUSTER: // Galaxy cluster - draw a dashed circle
1182 {
1183 tempBrush = brush();
1184 setBrush(QBrush());
1185 color = pen().color().name();
1186 save();
1187 translate(x, y);
1188 rotate(positionAngle); //rotate the coordinate system
1189 QPen newPen = pen();
1190 newPen.setStyle(Qt::DashLine);
1191 setPen(newPen);
1192 lambdaDrawEllipse(dx1, dy1, size, e * size);
1193 restore();
1194 setBrush(tempBrush);
1195 break;
1196 }
1197 default
1198: // Unknown object or something we don't know how to draw. Just draw an ellipse with a ?-mark
1199 color = pen().color().name();
1200 if (size < 1. && zoom > 20 * MINZOOM)
1201 size = 3.; //force ellipse above zoomFactor 20
1202 if (size < 1. && zoom > 5 * MINZOOM)
1203 size = 1.; //force points above zoomFactor 5
1204 if (size > 2.)
1205 {
1206 save();
1207 QFont f = font();
1208 const QString qMark = " ? ";
1209
1210#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1211 double scaleFactor = 0.8 * size / fontMetrics().horizontalAdvance(qMark);
1212#else
1213 double scaleFactor = 0.8 * size / fontMetrics().width(qMark);
1214#endif
1215
1216 f.setPointSizeF(f.pointSizeF() * scaleFactor);
1217 setFont(f);
1218 translate(x, y);
1219 rotate(positionAngle); //rotate the coordinate system
1220 lambdaDrawEllipse(dx1, dy1, size, e * size);
1221 if (Options::useAntialias())
1222 drawText(QRectF(dx1, dy1, size, e * size), Qt::AlignCenter, qMark);
1223 else
1224 {
1225 int idx1 = int(dx1);
1226 int idy1 = int(dy1);
1227 drawText(QRect(idx1, idy1, isize, int(e * size)), Qt::AlignCenter,
1228 qMark);
1229 }
1230 restore(); //reset coordinate system (and font?)
1231 }
1232 else if (size > 0.)
1233 {
1234 if (Options::useAntialias())
1235 drawPoint(QPointF(x, y));
1236 else
1237 drawPoint(QPoint(x, y));
1238 }
1239 }
1240}
1241
1243{
1244 foreach (SkyObject *obj, obs)
1245 {
1246 bool visible = false;
1247 QPointF o = m_proj->toScreen(obj, true, &visible);
1248 if (!visible || !m_proj->onScreen(o))
1249 continue;
1250
1251 float size = 20.;
1252 float x1 = o.x() - 0.5 * size;
1253 float y1 = o.y() - 0.5 * size;
1254 drawArc(QRectF(x1, y1, size, size), -60 * 16, 120 * 16);
1255 drawArc(QRectF(x1, y1, size, size), 120 * 16, 120 * 16);
1256 }
1257}
1258
1260{
1261 KStarsData *data = KStarsData::Instance();
1262 std::shared_ptr<SkyPoint> point;
1263 QImage image;
1264 bool visible = false;
1265 QPointF pos;
1266
1267 for (int i = 0; i < data->skyComposite()->flags()->size(); i++)
1268 {
1269 point = data->skyComposite()->flags()->pointList().at(i);
1270 image = data->skyComposite()->flags()->image(i);
1271
1272 // Set Horizontal coordinates
1273 point->EquatorialToHorizontal(data->lst(), data->geo()->lat());
1274
1275 // Get flag position on screen
1276 pos = m_proj->toScreen(point.get(), true, &visible);
1277
1278 // Return if flag is not visible
1279 if (!visible || !m_proj->onScreen(pos))
1280 continue;
1281
1282 // Draw flag image
1283 drawImage(pos.x() - 0.5 * image.width(), pos.y() - 0.5 * image.height(), image);
1284
1285 // Draw flag label
1286 setPen(data->skyComposite()->flags()->labelColor(i));
1287 setFont(QFont("Helvetica", 10, QFont::Bold));
1288 drawText(pos.x() + 10, pos.y() - 10, data->skyComposite()->flags()->label(i));
1289 }
1290}
1291
1292void SkyQPainter::drawHorizon(bool filled, SkyPoint * labelPoint, bool * drawLabel)
1293{
1294 QVector<Eigen::Vector2f> ground = m_proj->groundPoly(labelPoint, drawLabel);
1295 if (ground.size())
1296 {
1297 QPolygonF groundPoly(ground.size());
1298 for (int i = 0; i < ground.size(); ++i)
1299 groundPoly[i] = KSUtils::vecToPoint(ground[i]);
1300 if (filled)
1301 drawPolygon(groundPoly);
1302 else
1303 {
1304 groundPoly.append(groundPoly.first());
1305 drawPolyline(groundPoly);
1306 }
1307 }
1308}
1309
1311{
1312 if (!m_proj->checkVisibility(sat))
1313 return false;
1314
1315 QPointF pos;
1316 bool visible = false;
1317
1318 //sat->HorizontalToEquatorial( data->lst(), data->geo()->lat() );
1319
1320 pos = m_proj->toScreen(sat, true, &visible);
1321
1322 if (!visible || !m_proj->onScreen(pos))
1323 return false;
1324
1325 if (Options::drawSatellitesLikeStars())
1326 {
1327 drawPointSource(pos, 3.5, 'B');
1328 }
1329 else
1330 {
1331 if (sat->isVisible())
1332 drawPixmap(QPoint(pos.x() - 15, pos.y() - 11), *visibleSatPixmap);
1333 else
1334 drawPixmap(QPoint(pos.x() - 15, pos.y() - 11), *invisibleSatPixmap);
1335
1336 //drawPixmap(pos, *genericSatPixmap);
1337 /*drawLine( QPoint( pos.x() - 0.5, pos.y() - 0.5 ), QPoint( pos.x() + 0.5, pos.y() - 0.5 ) );
1338 drawLine( QPoint( pos.x() + 0.5, pos.y() - 0.5 ), QPoint( pos.x() + 0.5, pos.y() + 0.5 ) );
1339 drawLine( QPoint( pos.x() + 0.5, pos.y() + 0.5 ), QPoint( pos.x() - 0.5, pos.y() + 0.5 ) );
1340 drawLine( QPoint( pos.x() - 0.5, pos.y() + 0.5 ), QPoint( pos.x() - 0.5, pos.y() - 0.5 ) );*/
1341 }
1342
1343 return true;
1344
1345 //if ( Options::showSatellitesLabels() )
1346 //data->skyComposite()->satellites()->drawLabel( sat, pos );
1347}
1348
1350{
1351 KStarsData *data = KStarsData::Instance();
1352 if (!m_proj->checkVisibility(sup))
1353 {
1354 return false;
1355 }
1356
1357 bool visible = false;
1358 QPointF pos = m_proj->toScreen(sup, true, &visible);
1359 //qDebug()<<"sup->ra() = "<<(sup->ra()).toHMSString()<<"sup->dec() = "<<sup->dec().toDMSString();
1360 //qDebug()<<"pos = "<<pos<<"m_proj->onScreen(pos) = "<<m_proj->onScreen(pos);
1361 if (!visible || !m_proj->onScreen(pos))
1362 return false;
1363
1364 setPen(data->colorScheme()->colorNamed("SupernovaColor"));
1365 //qDebug()<<"Here";
1366 drawLine(QPoint(pos.x() - 2.0, pos.y()), QPoint(pos.x() + 2.0, pos.y()));
1367 drawLine(QPoint(pos.x(), pos.y() - 2.0), QPoint(pos.x(), pos.y() + 2.0));
1368 return true;
1369}
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:121
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
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 Mon Nov 4 2024 16:38:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.