Kstars

skymapdrawabstract.cpp
1/*
2 SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7// This file implements the class SkyMapDrawAbstract, and is almost
8// identical to the older skymapdraw.cpp file, written by Jason
9// Harris. Essentially, skymapdraw.cpp was renamed and modified.
10// -- asimha (2011)
11
12#include <QPainter>
13#include <QPixmap>
14#include <QPainterPath>
15
16#include "skymapdrawabstract.h"
17#include "skymap.h"
18#include "Options.h"
19#include "fov.h"
20#include "kstars.h"
21#include "kstarsdata.h"
22#include "ksnumbers.h"
23#include "ksutils.h"
24#include "skyobjects/skyobject.h"
25#include "skyobjects/catalogobject.h"
26#include "catalogsdb.h"
27#include "skyobjects/starobject.h"
28#include "skyobjects/ksplanetbase.h"
29#include "simclock.h"
30#include "observinglist.h"
31#include "skycomponents/constellationboundarylines.h"
32#include "skycomponents/skylabeler.h"
33#include "skycomponents/skymapcomposite.h"
34#include "skyqpainter.h"
35#include "projections/projector.h"
36#include "projections/lambertprojector.h"
37
38#include <config-kstars.h>
39
40#ifdef HAVE_INDI
41#include <basedevice.h>
42#include "indi/indilistener.h"
43#include "indi/driverinfo.h"
44#include "indi/indistd.h"
45#include "indi/indimount.h"
46#endif
47
48bool SkyMapDrawAbstract::m_DrawLock = false;
49
50SkyMapDrawAbstract::SkyMapDrawAbstract(SkyMap *sm) : m_KStarsData(KStarsData::Instance()), m_SkyMap(sm)
51{
52 //m_fpstime.start();
53 //m_framecount = 0;
54}
55
57{
58 if (!KStars::Instance())
59 return;
60
61 //draw labels
62 SkyLabeler::Instance()->draw(p);
63
64 if (drawFov)
65 {
66 //draw FOV symbol
67 foreach (FOV *fov, m_KStarsData->getVisibleFOVs())
68 {
69 if (fov->lockCelestialPole())
70 {
71 SkyPoint centerSkyPoint = SkyMap::Instance()->projector()->fromScreen(p.viewport().center(), KStarsData::Instance()->lst(),
72 KStarsData::Instance()->geo()->lat());
74 double northRotation = SkyMap::Instance()->projector()->findNorthPA(&centerSkyPoint, screenSkyPoint.x(),
75 screenSkyPoint.y());
76 fov->setCenter(centerSkyPoint);
77 fov->setNorthPA(northRotation);
78 }
79 fov->draw(p, Options::zoomFactor());
80 }
81 }
82
84
86
87 drawZoomBox(p);
88
89 if (m_SkyMap->rotationStart.x() > 0 && m_SkyMap->rotationStart.y() > 0)
90 {
92 }
93
94 // FIXME: Maybe we should take care of this differently. Maybe
95 // drawOverlays should remain in SkyMap, since it just calls
96 // certain drawing functions which are implemented in
97 // SkyMapDrawAbstract. Really, it doesn't draw anything on its
98 // own.
99 if (m_SkyMap->rulerMode)
100 {
101 m_SkyMap->updateAngleRuler();
103 }
104}
105
107{
108 //FIXME use sky painter.
109 p.setPen(QPen(m_KStarsData->colorScheme()->colorNamed("AngularRuler"), 3.0, Qt::DotLine));
110 p.drawLine(
111 m_SkyMap->m_proj->toScreen(m_SkyMap->AngularRuler.point(
112 0)), // FIXME: More ugliness. m_proj should probably be a single-instance class, or we should have our own instance etc.
113 m_SkyMap->m_proj->toScreen(m_SkyMap->AngularRuler.point(
114 1))); // FIXME: Again, AngularRuler should be something better -- maybe a class in itself. After all it's used for more than one thing after we integrate the StarHop feature.
115}
116
118{
119 auto* data = m_KStarsData;
120 const SkyPoint centerSkyPoint = m_SkyMap->m_proj->fromScreen(
121 p.viewport().center(),
122 data->lst(), data->geo()->lat());
123
125 double northRotation = m_SkyMap->m_proj->findNorthPA(
127 double zenithRotation = m_SkyMap->m_proj->findZenithPA(
129
130 QColor overlayColor(data->colorScheme()->colorNamed("CompassColor"));
131 p.setPen(Qt::NoPen);
132 auto drawArrow = [&](double angle, const QString & marker, const float labelRadius, const bool primary)
133 {
134 constexpr float radius = 150.0f; // In pixels
135 const auto fontMetrics = QFontMetricsF(QFont());
136 QTransform transform;
137 QColor color = overlayColor;
138 color.setAlphaF(primary ? 1.0 : 0.75);
139 QPen pen(color, 1.0, primary ? Qt::SolidLine : Qt::DotLine);
140 QBrush brush(color);
141
143 arrowstem.moveTo(0.f, 0.f);
144 arrowstem.lineTo(0.f, -radius + radius / 7.5f);
145 transform.reset();
146 transform.translate(centerScreenPoint.x(), centerScreenPoint.y());
147 transform.rotate(angle);
148 arrowstem = transform.map(arrowstem);
149 p.strokePath(arrowstem, pen);
150
152 arrowhead.moveTo(0.f, 0.f);
153 arrowhead.lineTo(-radius / 30.f, radius / 7.5f);
154 arrowhead.lineTo(radius / 30.f, radius / 7.5f);
155 arrowhead.lineTo(0.f, 0.f);
156 arrowhead.addText(QPointF(-1.1 * fontMetrics.width(marker), radius / 7.5f + 1.2f * fontMetrics.ascent()),
157 QFont(), marker);
158 transform.translate(0, -radius);
159 arrowhead = transform.map(arrowhead);
160 p.fillPath(arrowhead, brush);
161
162 if (labelRadius > 0.f)
163 {
165 2.f * labelRadius, 2.f * labelRadius);
166 p.setPen(pen);
167 if (abs(angle) < 0.01)
168 {
169 angle = 0.;
170 }
171 double arcAngle = angle <= 0. ? -angle : 360. - angle;
172 p.drawArc(angleMarkerRect, 90 * 16, int(arcAngle * 16.));
173
175 QString angleLabelText = QString::number(int(round(arcAngle))) + "°";
176 angleLabel.addText(QPointF(-fontMetrics.width(angleLabelText) / 2.f, 1.2f * fontMetrics.ascent()),
178 transform.reset();
179 transform.translate(centerScreenPoint.x(), centerScreenPoint.y());
180 transform.rotate(angle);
181 transform.translate(0, -labelRadius);
182 transform.rotate(90);
183 angleLabel = transform.map(angleLabel);
184 p.fillPath(angleLabel, brush);
185 }
186
187 };
188 auto eastRotation = northRotation + (m_SkyMap->m_proj->viewParams().mirror ? 90 : -90);
189 drawArrow(northRotation, i18nc("North", "N"), 80.f, !Options::useAltAz());
190 drawArrow(eastRotation, i18nc("East", "E"), -1.f, !Options::useAltAz());
191 drawArrow(zenithRotation, i18nc("Zenith", "Z"), 40.f, Options::useAltAz());
192}
193
195{
196 //draw the manual zoom-box, if it exists
197 if (m_SkyMap->ZoomRect.isValid())
198 {
200 p.drawRect(m_SkyMap->ZoomRect.x(), m_SkyMap->ZoomRect.y(), m_SkyMap->ZoomRect.width(),
201 m_SkyMap->ZoomRect.height());
202 }
203}
204
206{
207 bool checkSlewing =
208 (m_SkyMap->slewing || (m_SkyMap->clockSlewing && m_KStarsData->clock()->isActive())) && Options::hideOnSlew();
209 if (checkSlewing && Options::hideLabels())
210 return;
211
212 SkyLabeler *skyLabeler = SkyLabeler::Instance();
213 skyLabeler->resetFont(); // use the zoom dependent font
214
215 skyLabeler->setPen(m_KStarsData->colorScheme()->colorNamed("UserLabelColor"));
216
217 bool drawPlanets = Options::showSolarSystem() && !(checkSlewing && Options::hidePlanets());
218 bool drawComets = drawPlanets && Options::showComets();
219 bool drawAsteroids = drawPlanets && Options::showAsteroids();
220 bool drawOther = Options::showDeepSky() && Options::showOther() && !(checkSlewing && Options::hideOther());
221 bool drawStars = Options::showStars();
222 bool hideFaintStars = checkSlewing && Options::hideStars();
223
224 //Attach a label to the centered object
225 if (m_SkyMap->focusObject() != nullptr && Options::useAutoLabel())
226 {
227 QPointF o =
228 m_SkyMap->m_proj->toScreen(m_SkyMap->focusObject()); // FIXME: Same thing. m_proj should be accessible here.
229 skyLabeler->drawNameLabel(m_SkyMap->focusObject(), o);
230 }
231
232 foreach (SkyObject *obj, labelObjects)
233 {
234 //Only draw an attached label if the object is being drawn to the map
235 //reproducing logic from other draw funcs here...not an optimal solution
236 if (obj->type() == SkyObject::STAR || obj->type() == SkyObject::CATALOG_STAR ||
237 obj->type() == SkyObject::MULT_STAR)
238 {
239 if (!drawStars)
240 continue;
241 // if ( obj->mag() > Options::magLimitDrawStar() ) continue;
242 if (hideFaintStars && obj->mag() > Options::magLimitHideStar())
243 continue;
244 }
245 if (obj->type() == SkyObject::PLANET)
246 {
247 if (!drawPlanets)
248 continue;
249 if (obj->name() == i18n("Sun") && !Options::showSun())
250 continue;
251 if (obj->name() == i18n("Mercury") && !Options::showMercury())
252 continue;
253 if (obj->name() == i18n("Venus") && !Options::showVenus())
254 continue;
255 if (obj->name() == i18n("Moon") && !Options::showMoon())
256 continue;
257 if (obj->name() == i18n("Mars") && !Options::showMars())
258 continue;
259 if (obj->name() == i18n("Jupiter") && !Options::showJupiter())
260 continue;
261 if (obj->name() == i18n("Saturn") && !Options::showSaturn())
262 continue;
263 if (obj->name() == i18n("Uranus") && !Options::showUranus())
264 continue;
265 if (obj->name() == i18n("Neptune") && !Options::showNeptune())
266 continue;
267 //if ( obj->name() == i18n( "Pluto" ) && ! Options::showPluto() ) continue;
268 }
269 if ((obj->type() >= SkyObject::OPEN_CLUSTER && obj->type() <= SkyObject::GALAXY) ||
270 (obj->type() >= SkyObject::ASTERISM && obj->type() <= SkyObject::QUASAR) ||
271 (obj->type() == SkyObject::RADIO_SOURCE))
272 {
273 if (((CatalogObject *)obj)->getCatalog().id == -1 && !drawOther)
274 continue;
275 }
276 if (obj->type() == SkyObject::COMET && !drawComets)
277 continue;
278 if (obj->type() == SkyObject::ASTEROID && !drawAsteroids)
279 continue;
280
281 if (!m_SkyMap->m_proj->checkVisibility(obj))
282 continue; // FIXME: m_proj should be a member of this class.
283 QPointF o = m_SkyMap->m_proj->toScreen(obj);
284 if (!m_SkyMap->m_proj->onScreen(o))
285 continue;
286
287 skyLabeler->drawNameLabel(obj, o);
288 }
289
290 skyLabeler->useStdFont(); // use the StdFont for the guides.
291}
292
294{
296
297#ifdef HAVE_INDI
298
299 for (auto oneFOV : KStarsData::Instance()->getTransientFOVs())
300 {
301 QVariant visible = oneFOV->property("visible");
302 if (visible.isNull() || visible.toBool() == false)
303 continue;
304
305 if (oneFOV->objectName() == "sensor_fov")
306 {
307 oneFOV->setColor(KStars::Instance()->data()->colorScheme()->colorNamed("SensorFOVColor").name());
308 SkyPoint centerSkyPoint = SkyMap::Instance()->projector()->fromScreen(psky.viewport().center(),
309 KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
310 QPointF screenSkyPoint = psky.viewport().center();
311 double northRotation = SkyMap::Instance()->projector()->findNorthPA(&centerSkyPoint, screenSkyPoint.x(),
312 screenSkyPoint.y());
313 oneFOV->setCenter(centerSkyPoint);
314 oneFOV->setNorthPA(northRotation);
315 oneFOV->draw(psky, Options::zoomFactor());
316 }
317 else if (oneFOV->objectName() == "solver_fov")
318 {
319 bool isVisible = false;
320 SkyPoint p = oneFOV->center();
321 if (std::isnan(p.ra().Degrees()))
322 continue;
323
324 p.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
325 QPointF point = SkyMap::Instance()->projector()->toScreen(&p, true, &isVisible);
326 double northRotation = SkyMap::Instance()->projector()->findNorthPA(&p, point.x(), point.y());
327 oneFOV->setNorthPA(northRotation);
328 oneFOV->draw(psky, Options::zoomFactor());
329 }
330 }
331#endif
332}
333
335{
337
338#ifdef HAVE_INDI
339 if (!Options::showTargetCrosshair())
340 return;
341
342 if (INDIListener::Instance()->size() == 0)
343 return;
345
346 psky.setPen(QPen(QColor(m_KStarsData->colorScheme()->colorNamed("TargetColor"))));
347 psky.setBrush(Qt::NoBrush);
348 float pxperdegree = Options::zoomFactor() / 57.3;
349
350 for (auto &oneDevice : INDIListener::devices())
351 {
352 if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE) || oneDevice->isConnected() == false)
353 continue;
354
355 auto mount = oneDevice->getMount();
356 if (!mount)
357 continue;
358
359 auto coordNP = mount->currentCoordinates();
360
361 QPointF P = m_SkyMap->m_proj->toScreen(&coordNP);
362 if (Options::useAntialias())
363 {
364 float s1 = 0.5 * pxperdegree;
365 float s2 = pxperdegree;
366 float s3 = 2.0 * pxperdegree;
367
368 float x0 = P.x();
369 float y0 = P.y();
370 float x1 = x0 - 0.5 * s1;
371 float y1 = y0 - 0.5 * s1;
372 float x2 = x0 - 0.5 * s2;
373 float y2 = y0 - 0.5 * s2;
374 float x3 = x0 - 0.5 * s3;
375 float y3 = y0 - 0.5 * s3;
376
377 //Draw radial lines
378 psky.drawLine(QPointF(x1, y0), QPointF(x3, y0));
379 psky.drawLine(QPointF(x0 + s2, y0), QPointF(x0 + 0.5 * s1, y0));
380 psky.drawLine(QPointF(x0, y1), QPointF(x0, y3));
381 psky.drawLine(QPointF(x0, y0 + 0.5 * s1), QPointF(x0, y0 + s2));
382 //Draw circles at 0.5 & 1 degrees
383 psky.drawEllipse(QRectF(x1, y1, s1, s1));
384 psky.drawEllipse(QRectF(x2, y2, s2, s2));
385
386 psky.drawText(QPointF(x0 + s2 + 2., y0), mount->getDeviceName());
387 }
388 else
389 {
390 int s1 = int(0.5 * pxperdegree);
391 int s2 = int(pxperdegree);
392 int s3 = int(2.0 * pxperdegree);
393
394 int x0 = int(P.x());
395 int y0 = int(P.y());
396 int x1 = x0 - s1 / 2;
397 int y1 = y0 - s1 / 2;
398 int x2 = x0 - s2 / 2;
399 int y2 = y0 - s2 / 2;
400 int x3 = x0 - s3 / 2;
401 int y3 = y0 - s3 / 2;
402
403 //Draw radial lines
404 psky.drawLine(QPoint(x1, y0), QPoint(x3, y0));
405 psky.drawLine(QPoint(x0 + s2, y0), QPoint(x0 + s1 / 2, y0));
406 psky.drawLine(QPoint(x0, y1), QPoint(x0, y3));
407 psky.drawLine(QPoint(x0, y0 + s1 / 2), QPoint(x0, y0 + s2));
408 //Draw circles at 0.5 & 1 degrees
409 psky.drawEllipse(QRect(x1, y1, s1, s1));
410 psky.drawEllipse(QRect(x2, y2, s2, s2));
411
412 psky.drawText(QPoint(x0 + s2 + 2, y0), mount->getDeviceName());
413 }
414 }
415#endif
416}
417
419{
420 SkyQPainter p(m_SkyMap, pd);
421 p.begin();
423
424 exportSkyImage(&p, scale);
425
426 p.end();
427}
428
430{
431 bool vectorStarState;
432 vectorStarState = painter->getVectorStars();
433 painter->setVectorStars(
434 true); // Since we are exporting an image, we may use vector stars without worrying about time
435 painter->setRenderHint(QPainter::Antialiasing, Options::useAntialias());
436
437 if (scale)
438 {
439 //scale sky image to fit paint device
440 qDebug() << Q_FUNC_INFO << "Scaling true while exporting Sky Image";
441 double xscale = double(painter->device()->width()) / double(m_SkyMap->width());
442 double yscale = double(painter->device()->height()) / double(m_SkyMap->height());
443 double scale = qMin(xscale, yscale);
444 qDebug() << Q_FUNC_INFO << "xscale: " << xscale << "yscale: " << yscale << "chosen scale: " << scale;
445 painter->scale(scale, scale);
446 }
447
448 painter->drawSkyBackground();
449 m_KStarsData->skyComposite()->draw(painter);
450 drawOverlays(*painter);
451 painter->setVectorStars(vectorStarState); // Restore the state of the painter
452}
453
454/* JM 2016-05-03: Not needed since we're not using OpenGL for now
455 * void SkyMapDrawAbstract::calculateFPS()
456{
457 if(m_framecount == 25) {
458 //float sec = m_fpstime.elapsed()/1000.;
459 // qDebug() << Q_FUNC_INFO << "FPS " << m_framecount/sec;
460 m_framecount = 0;
461 m_fpstime.restart();
462 }
463 ++m_framecount;
464}*/
465
467{
468 m_DrawLock = state;
469}
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
QColor colorNamed(const QString &name) const
Retrieve a color by name.
A simple class encapsulating a Field-of-View symbol.
Definition fov.h:28
void draw(QPainter &p, float zoomFactor)
draw the FOV symbol on a QPainter
Definition fov.cpp:230
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
ColorScheme * colorScheme()
Definition kstarsdata.h:172
Q_INVOKABLE SimClock * clock()
Definition kstarsdata.h:218
SkyMapComposite * skyComposite()
Definition kstarsdata.h:166
const QList< FOV * > getVisibleFOVs() const
Definition kstarsdata.h:306
static KStars * Instance()
Definition kstars.h:123
virtual SkyPoint fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz=false) const
Determine RA, Dec coordinates of the pixel at (dx, dy), which are the screen pixel coordinate offsets...
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 findZenithPA(const SkyPoint *o, float x, float y) const
Determine the on-screen angle of a SkyPoint with respect to Zenith.
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.
Q_INVOKABLE bool isActive()
Whether the clock is active or not is a bit complicated by the introduction of "manual mode".
Definition simclock.cpp:96
The purpose of this class is to prevent labels from overlapping.
Definition skylabeler.h:99
void resetFont()
sets the font in SkyLabeler and in psky back to the zoom dependent value that was set in reset().
void setPen(const QPen &pen)
sets the pen used for drawing labels on the sky.
void useStdFont()
sets the font in SkyLabeler and in psky to the font psky had originally when reset() was called.
bool drawNameLabel(SkyObject *obj, const QPointF &_p, const qreal padding_factor=1)
Tries to draw a label for an object.
SkyPoint * point(int i) const
Definition skyline.h:44
void draw(SkyPainter *skyp) override
Delegate draw requests to all sub components psky Reference to the QPainter on which to paint.
static void setDrawLock(bool state)
Acquire / release a draw lock.
void drawOrientationArrows(QPainter &p)
Draw north and zenith arrows to show the orientation while rotating the sky map.
void drawZoomBox(QPainter &psky)
Draw a dotted-line rectangle which traces the potential new field-of-view in ZoomBox mode.
void drawTelescopeSymbols(QPainter &psky)
Draw symbols at the position of each Telescope currently being controlled by KStars.
void drawAngleRuler(QPainter &psky)
Draw a dashed line from the Angular-Ruler start point to the current mouse cursor,...
void drawSolverFOV(QPainter &psky)
Draw FOV of solved image in Ekos Alignment Module.
void drawObjectLabels(QList< SkyObject * > &labelObjects)
Draw "user labels".
void exportSkyImage(QPaintDevice *pd, bool scale=false)
Draw the current Sky map to a pixmap which is to be printed or exported to a file.
void drawOverlays(QPainter &p, bool drawFov=true)
Draw the overlays on top of the sky map.
SkyMapDrawAbstract(SkyMap *sm)
Constructor that sets data and m_SkyMap, and initializes the FPS counters.
This is the canvas on which the sky is painted.
Definition skymap.h:54
void updateAngleRuler()
update the geometry of the angle ruler.
Definition skymap.cpp:1357
SkyObject * focusObject() const
Retrieve the object which is centered in the sky map.
Definition skymap.h:262
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
The sky coordinates of a point in the sky.
Definition skypoint.h:45
const CachingDms & ra() const
Definition skypoint.h:263
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
The QPainter-based painting backend.
Definition skyqpainter.h:31
void end() override
End and finalize painting.
void drawSkyBackground() override
Draw the sky background.
void setVectorStars(bool vectorStars)
Definition skyqpainter.h:69
void begin() override
Begin painting.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void setAlphaF(float alpha)
int height() const const
int width() const const
SmoothPixmapTransform
QPaintDevice * device() const const
void drawArc(const QRect &rectangle, int startAngle, int spanAngle)
void drawLine(const QLine &line)
void drawRect(const QRect &rectangle)
void fillPath(const QPainterPath &path, const QBrush &brush)
void scale(qreal sx, qreal sy)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void strokePath(const QPainterPath &path, const QPen &pen)
QRect viewport() const const
int x() const const
int y() const const
qreal x() const const
qreal y() const const
QPoint center() const const
int height() const const
bool isValid() const const
int width() const const
int x() const const
int y() const const
QString number(double n, char format, int precision)
bool isNull() const const
bool toBool() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 24 2024 11:49:23 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.