Kstars

fov.cpp
1/*
2 SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "fov.h"
8
9#include "geolocation.h"
10#include "kspaths.h"
11#ifndef KSTARS_LITE
12#include "kstars.h"
13#endif
14#include "kstarsdata.h"
15#include "Options.h"
16#include "skymap.h"
17#include "projections/projector.h"
18#include "fovadaptor.h"
19
20#include <QPainter>
21#include <QTextStream>
22#include <QFile>
23#include <QDebug>
24#include <QStandardPaths>
25
26#include <algorithm>
27
28QList<FOV *> FOVManager::m_FOVs;
29int FOV::m_ID = 1;
30
31FOVManager::~FOVManager()
32{
33 qDeleteAll(m_FOVs);
34}
35
36QList<FOV *> FOVManager::defaults()
37{
38 QList<FOV *> fovs;
39 fovs << new FOV(i18nc("use field-of-view for binoculars", "7x35 Binoculars"), 558, 558, 0, 0, 0, FOV::CIRCLE,
40 "#AAAAAA")
41 << new FOV(i18nc("use a Telrad field-of-view indicator", "Telrad"), 30, 30, 0, 0, 0, FOV::BULLSEYE, "#AA0000")
42 << new FOV(i18nc("use 1-degree field-of-view indicator", "One Degree"), 60, 60, 0, 0, 0, FOV::CIRCLE,
43 "#AAAAAA")
44 << new FOV(i18nc("use HST field-of-view indicator", "HST WFPC2"), 2.4, 2.4, 0, 0, 0, FOV::SQUARE, "#AAAAAA")
45 << new FOV(i18nc("use Radiotelescope HPBW", "30m at 1.3cm"), 1.79, 1.79, 0, 0, 0, FOV::SQUARE, "#AAAAAA");
46 return fovs;
47}
48
50{
51 QFile f;
52
53 // TODO: Move FOVs to user database instead of file!!
54 f.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("fov.dat"));
55
56 if (!f.open(QIODevice::WriteOnly))
57 {
58 qDebug() << Q_FUNC_INFO << "Could not open fov.dat.";
59 return false;
60 }
61
62 QTextStream ostream(&f);
63 foreach (FOV *fov, m_FOVs)
64 {
65 ostream << fov->name() << ':' << fov->sizeX() << ':' << fov->sizeY() << ':' << fov->offsetX() << ':'
66 << fov->offsetY() << ':' << fov->PA() << ':' << QString::number(fov->shape())
67 << ':' << fov->color()
68 << ':' << (fov->lockCelestialPole() ? 1 : 0)
69 << '\n';
70 }
71 f.close();
72
73 return true;
74}
75
77{
78 qDeleteAll(m_FOVs);
79 m_FOVs.clear();
80
81 QFile f;
82 f.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("fov.dat"));
83
84 if (!f.exists())
85 {
86 m_FOVs = defaults();
87 save();
88 return m_FOVs;
89 }
90
91 if (f.open(QIODevice::ReadOnly))
92 {
93 QTextStream istream(&f);
94 while (!istream.atEnd())
95 {
96 QStringList fields = istream.readLine().split(':');
97 bool ok;
98 QString name, color;
99 float sizeX, sizeY, xoffset, yoffset, rot;
100 bool lockedCP = false;
101 FOV::Shape shape;
102 if (fields.count() >= 8)
103 {
104 name = fields[0];
105 sizeX = fields[1].toFloat(&ok);
106 if (!ok)
107 {
108 return m_FOVs;
109 }
110 sizeY = fields[2].toFloat(&ok);
111 if (!ok)
112 {
113 return m_FOVs;
114 }
115 xoffset = fields[3].toFloat(&ok);
116 if (!ok)
117 {
118 return m_FOVs;
119 }
120
121 yoffset = fields[4].toFloat(&ok);
122 if (!ok)
123 {
124 return m_FOVs;
125 }
126
127 rot = fields[5].toFloat(&ok);
128 if (!ok)
129 {
130 return m_FOVs;
131 }
132
133 shape = static_cast<FOV::Shape>(fields[6].toInt(&ok));
134 if (!ok)
135 {
136 return m_FOVs;
137 }
138 color = fields[7];
139
140 if (fields.count() == 9)
141 lockedCP = (fields[8].toInt(&ok) == 1);
142 }
143 else
144 {
145 continue;
146 }
147
148 m_FOVs.append(new FOV(name, sizeX, sizeY, xoffset, yoffset, rot, shape, color, lockedCP));
149 }
150 }
151 return m_FOVs;
152}
153
155{
156 qDeleteAll(m_FOVs);
157 m_FOVs.clear();
158}
159
160FOV::FOV(const QString &n, float a, float b, float xoffset, float yoffset, float rot, Shape sh, const QString &col,
161 bool useLockedCP) : QObject()
162{
163 qRegisterMetaType<FOV::Shape>("FOV::Shape");
164 qDBusRegisterMetaType<FOV::Shape>();
165
166 new FovAdaptor(this);
167 QDBusConnection::sessionBus().registerObject(QString("/KStars/FOV/%1").arg(getID()), this);
168
169 m_name = n;
170 m_sizeX = a;
171 m_sizeY = (b < 0.0) ? a : b;
172
173 m_offsetX = xoffset;
174 m_offsetY = yoffset;
175 m_PA = rot;
176 m_shape = sh;
177 m_color = col;
178 m_northPA = 0;
179 m_center.setRA(0);
180 m_center.setDec(0);
181 m_imageDisplay = false;
182 m_lockCelestialPole = useLockedCP;
183}
184
186{
187 qRegisterMetaType<FOV::Shape>("FOV::Shape");
188 qDBusRegisterMetaType<FOV::Shape>();
189
190 new FovAdaptor(this);
191 QDBusConnection::sessionBus().registerObject(QString("/KStars/FOV/%1").arg(getID()), this);
192
193 m_name = i18n("No FOV");
194 m_color = "#FFFFFF";
195
196 m_sizeX = m_sizeY = 0;
197 m_shape = SQUARE;
198 m_imageDisplay = false;
199 m_lockCelestialPole = false;
200}
201
202FOV::FOV(const FOV &other) : QObject()
203{
204 m_name = other.m_name;
205 m_color = other.m_color;
206 m_sizeX = other.m_sizeX;
207 m_sizeY = other.m_sizeY;
208 m_shape = other.m_shape;
209 m_offsetX = other.m_offsetX;
210 m_offsetY = other.m_offsetY;
211 m_PA = other.m_PA;
212 m_imageDisplay = other.m_imageDisplay;
213 m_lockCelestialPole = other.m_lockCelestialPole;
214}
215
216void FOV::sync(const FOV &other)
217{
218 m_name = other.m_name;
219 m_color = other.m_color;
220 m_sizeX = other.m_sizeX;
221 m_sizeY = other.m_sizeY;
222 m_shape = other.m_shape;
223 m_offsetX = other.m_offsetX;
224 m_offsetY = other.m_offsetY;
225 m_PA = other.m_PA;
226 m_imageDisplay = other.m_imageDisplay;
227 m_lockCelestialPole = other.m_lockCelestialPole;
228}
229
230void FOV::draw(QPainter &p, float zoomFactor)
231{
232 // Do not draw empty FOVs
233 if (m_sizeX == 0 || m_sizeY == 0)
234 return;
235
236 p.setPen(QColor(color()));
238
239 p.setRenderHint(QPainter::Antialiasing, Options::useAntialias());
240
241 float pixelSizeX = sizeX() * zoomFactor / 57.3 / 60.0;
242 float pixelSizeY = sizeY() * zoomFactor / 57.3 / 60.0;
243
244 float offsetXPixelSize = offsetX() * zoomFactor / 57.3 / 60.0;
245 float offsetYPixelSize = offsetY() * zoomFactor / 57.3 / 60.0;
246
247 p.save();
248
249 if (m_center.ra().Degrees() > 0)
250 {
251 m_center.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
252 QPointF skypoint_center = KStars::Instance()->map()->projector()->toScreen(&m_center);
253 p.translate(skypoint_center.toPoint());
254 }
255 else
256 p.translate(p.viewport().center());
257
258 p.translate(offsetXPixelSize, offsetYPixelSize);
259 p.rotate( (m_PA - m_northPA) * -1);
260
261 QPointF center(0, 0);
262
263 auto setNameFont = [&]() -> bool
264 {
265 int fontSize = pixelSizeX / 15;
266 fontSize *= 14.0 / name().count();
267
268 // Don't let the font size get larger than the vertical space allotted.
269 const int maxYPixelSize = (14.0 / 15.0) * (pixelSizeY / 8);
270 fontSize = std::min(maxYPixelSize, fontSize);
271
272 if (fontSize <= 4)
273 return false;
274
275 QFont font = p.font();
276 font.setPixelSize(fontSize);
277 p.setFont(font);
278 return true;
279 };
280
281 auto setSizeFont = [&](const QString & fovString)
282 {
283 int fontSize = pixelSizeX / 15;
284 fontSize *= 14.0 / name().count();
285 // Maybe make the font size smaller for the field-of-view dimensions.
286 const int maxYPixelSize = (14.0 / 15.0) * (pixelSizeY / 8);
287 int fovFontSize = (pixelSizeX / 15) * (14.0 / fovString.count());
288 fovFontSize = std::min(maxYPixelSize, fovFontSize);
289 fontSize = std::min(fovFontSize, fontSize);
290
291 if (fontSize > 4)
292 {
293 QFont font = p.font();
294 font.setPixelSize(fontSize);
295 p.setFont(font);
296 }
297 };
298
299 auto drawNameForCircularFov = [&]()
300 {
301 if (name().count() > 0)
302 {
303 if (!setNameFont()) // Too small
304 {
305 return;
306 }
307 QRect nameRect(center.x() - pixelSizeX / 2., center.y() + pixelSizeY / 2. + 1.05 * pixelSizeX / 10, pixelSizeY / 2,
308 pixelSizeX / 10);
309 p.drawText(nameRect, Qt::AlignCenter, name());
310
311 QString fovString = QString("%1'").arg(QString::number(m_sizeX, 'f', 1));
312 setSizeFont(fovString);
313
314 QRect sizeRect(center.x(), center.y() + pixelSizeY / 2. + 1.05 * pixelSizeX / 10, pixelSizeY / 2,
315 pixelSizeX / 10);
316 p.drawText(sizeRect, Qt::AlignCenter, fovString);
317 }
318 };
319
320 switch (shape())
321 {
322 case SQUARE:
323 {
324 QRect targetRect(center.x() - pixelSizeX / 2, center.y() - pixelSizeY / 2, pixelSizeX, pixelSizeY);
325 if (m_imageDisplay)
326 p.drawImage(targetRect, m_image);
327
328 p.drawRect(targetRect);
329 p.drawRect(center.x(), center.y() - (3 * pixelSizeY / 5), pixelSizeX / 40, pixelSizeX / 10);
330 p.drawLine(center.x() - pixelSizeX / 30, center.y() - (3 * pixelSizeY / 5), center.x() + pixelSizeX / 20,
331 center.y() - (3 * pixelSizeY / 5));
332 p.drawLine(center.x() - pixelSizeX / 30, center.y() - (3 * pixelSizeY / 5), center.x() + pixelSizeX / 70,
333 center.y() - (0.7 * pixelSizeY));
334 p.drawLine(center.x() + pixelSizeX / 20, center.y() - (3 * pixelSizeY / 5), center.x() + pixelSizeX / 70,
335 center.y() - (0.7 * pixelSizeY));
336
337 if (name().count() > 0)
338 {
339 setNameFont();
340 QRect nameRect(targetRect.topLeft().x(), targetRect.topLeft().y() - (pixelSizeY / 8), targetRect.width() / 2,
341 pixelSizeX / 10);
342 p.drawText(nameRect, Qt::AlignCenter, name());
343
344 QString fovString = QString("%1'x%2'").arg(QString::number(m_sizeX, 'f', 1), QString::number(m_sizeY, 'f', 1));
345 setSizeFont(fovString);
346
347 QRect sizeRect(targetRect.center().x(), targetRect.topLeft().y() - (pixelSizeY / 8), targetRect.width() / 2,
348 pixelSizeX / 10);
349 p.drawText(sizeRect, Qt::AlignCenter, QString("%1'x%2'").arg(QString::number(m_sizeX, 'f', 1), QString::number(m_sizeY, 'f',
350 1)));
351 }
352 }
353 break;
354 case CIRCLE:
355 p.drawEllipse(center, pixelSizeX / 2, pixelSizeY / 2);
356 drawNameForCircularFov();
357 break;
358 case CROSSHAIRS:
359 //Draw radial lines
360 p.drawLine(center.x() + 0.5 * pixelSizeX, center.y(), center.x() + 1.5 * pixelSizeX, center.y());
361 p.drawLine(center.x() - 0.5 * pixelSizeX, center.y(), center.x() - 1.5 * pixelSizeX, center.y());
362 p.drawLine(center.x(), center.y() + 0.5 * pixelSizeY, center.x(), center.y() + 1.5 * pixelSizeY);
363 p.drawLine(center.x(), center.y() - 0.5 * pixelSizeY, center.x(), center.y() - 1.5 * pixelSizeY);
364 //Draw circles at 0.5 & 1 degrees
365 p.drawEllipse(center, 0.5 * pixelSizeX, 0.5 * pixelSizeY);
366 p.drawEllipse(center, pixelSizeX, pixelSizeY);
367 drawNameForCircularFov();
368 break;
369 case BULLSEYE:
370 p.drawEllipse(center, 0.5 * pixelSizeX, 0.5 * pixelSizeY);
371 p.drawEllipse(center, 2.0 * pixelSizeX, 2.0 * pixelSizeY);
372 p.drawEllipse(center, 4.0 * pixelSizeX, 4.0 * pixelSizeY);
373 drawNameForCircularFov();
374 break;
375 case SOLIDCIRCLE:
376 {
377 QColor colorAlpha = color();
378 colorAlpha.setAlpha(127);
379 p.setBrush(QBrush(colorAlpha));
380 p.drawEllipse(center, pixelSizeX / 2, pixelSizeY / 2);
382 drawNameForCircularFov();
383 break;
384 }
385 default:
386 ;
387 }
388
389 p.restore();
390}
391
392void FOV::draw(QPainter &p, float x, float y)
393{
394 float xfactor = x / sizeX() * 57.3 * 60.0;
395 float yfactor = y / sizeY() * 57.3 * 60.0;
396 float zoomFactor = std::min(xfactor, yfactor);
397 switch (shape())
398 {
399 case CROSSHAIRS:
400 zoomFactor /= 3;
401 break;
402 case BULLSEYE:
403 zoomFactor /= 8;
404 break;
405 default:
406 ;
407 }
408 draw(p, zoomFactor);
409}
410
411SkyPoint FOV::center() const
412{
413 return m_center;
414}
415
416void FOV::setCenter(const SkyPoint &center)
417{
418 m_center = center;
419}
420
421float FOV::northPA() const
422{
423 return m_northPA;
424}
425
426void FOV::setNorthPA(float northPA)
427{
428 m_northPA = northPA;
429}
430
431void FOV::setImage(const QImage &image)
432{
433 m_image = image;
434}
435
436void FOV::setImageDisplay(bool value)
437{
438 m_imageDisplay = value;
439}
440
441bool FOV::lockCelestialPole() const
442{
443 return m_lockCelestialPole;
444}
445
446void FOV::setLockCelestialPole(bool lockCelestialPole)
447{
448 m_lockCelestialPole = lockCelestialPole;
449}
450
451QDBusArgument &operator<<(QDBusArgument &argument, const FOV::Shape &source)
452{
453 argument.beginStructure();
454 argument << static_cast<int>(source);
455 argument.endStructure();
456 return argument;
457}
458
459const QDBusArgument &operator>>(const QDBusArgument &argument, FOV::Shape &dest)
460{
461 int a;
462 argument.beginStructure();
463 argument >> a;
464 argument.endStructure();
465 dest = static_cast<FOV::Shape>(a);
466 return argument;
467}
static const QList< FOV * > & readFOVs()
Read list of FOVs from "fov.dat".
Definition fov.cpp:76
static bool save()
Write list of FOVs to "fov.dat".
Definition fov.cpp:49
static void releaseCache()
Release the FOV cache.
Definition fov.cpp:154
A simple class encapsulating a Field-of-View symbol.
Definition fov.h:28
FOV()
Default constructor.
Definition fov.cpp:185
void draw(QPainter &p, float zoomFactor)
draw the FOV symbol on a QPainter
Definition fov.cpp:230
SkyMap * map() const
Definition kstars.h:141
static KStars * Instance()
Definition kstars.h:123
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
const Projector * projector() const
Get the current projector.
Definition skymap.h:300
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
const double & Degrees() const
Definition dms.h:141
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
void setAlpha(int alpha)
void beginStructure()
void endStructure()
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
void setPixelSize(int pixelSize)
void append(QList< T > &&value)
void clear()
void drawEllipse(const QPoint &center, int rx, int ry)
void drawImage(const QPoint &point, const QImage &image)
void drawLine(const QLine &line)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
const QFont & font() const const
void restore()
void rotate(qreal angle)
void save()
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void translate(const QPoint &offset)
QRect viewport() const const
int x() const const
int y() const const
QPoint toPoint() const const
QPoint center() const const
QPoint topLeft() const const
int width() const const
qsizetype count() const const
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
AlignCenter
QTextStream & center(QTextStream &stream)
bool atEnd() const const
QString readLine(qint64 maxlen)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:50 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.