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();
153 setRenderHint(QPainter::HighQualityAntialiasing, aa);
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");
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;
219 {
220 // Ongoing eclipse!
221
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;
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);
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
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());
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 {
436 if (label)
437 label->updateLabelCandidates(oThis.x(), oThis.y(), list, j);
438 }
439 }
440
441 oLast = oThis2;
442 isVisibleLast = isVisible;
443 }
444}
445
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));
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)));
613 setBrush(QBrush(QColor(255, 96, 38, 90)));
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
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"));
674
675 // Render Coma.
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
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());
828 obj->draw(this);
829 restore();
830
831 return true;
832}
833#endif
834
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
856{
857 // TODO
859 int w = viewport().width();
860 int h = viewport().height();
862 TerrainRenderer *renderer = TerrainRenderer::Instance();
863 bool rendered = renderer->render(w, h, terrainImage, m_proj);
864 if (rendered)
866
867 delete (terrainImage);
868 return rendered;
869}
870
872{
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);
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);
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);
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
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);
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();
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
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
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()
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
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...)
QColor fromRgb(QRgb rgb)
int horizontalAdvance(QChar ch) const const
Format_ARGB32_Premultiplied
int height() const const
int width() const const
const_reference at(qsizetype i) const const
qsizetype size() 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 translate(const QPoint &offset)
QRect viewport() const const
qreal x() const const
qreal y() 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 May 17 2024 11:48:27 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.