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().size();
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().size();
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.size());
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().size() > 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().size() > 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:139
static KStars * Instance()
Definition kstars.h:121
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
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 &)
QDebug operator<<(QDebug dbg, const PerceptualColor::MultiSpinBoxSection &value)
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
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
qsizetype size() const const
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 Dec 6 2024 12:09:51 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.