Kstars

fovdialog.cpp
1 /*
2  SPDX-FileCopyrightText: 2003 Jason Harris <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "fovdialog.h"
8 
9 #include <QFile>
10 #include <QFrame>
11 #include <QPainter>
12 #include <QTextStream>
13 #include <QPaintEvent>
14 #include <QDebug>
15 #include <QPushButton>
16 #include <QComboBox>
17 #include <QDoubleSpinBox>
18 #include <QLineEdit>
19 
20 #include <KActionCollection>
21 #include <KLocalizedString>
22 #include <kcolorbutton.h>
23 #include <KMessageBox>
24 
25 #include "kstars.h"
26 #include "kstarsdata.h"
27 #include "widgets/fovwidget.h"
28 #include "Options.h"
29 
30 // This is needed to make FOV work with QVariant
31 Q_DECLARE_METATYPE(FOV *)
32 
33 int FOVDialog::fovID = -1;
34 
35 namespace
36 {
37 // Try to convert text in KLine edit to double
38 inline double textToDouble(const QLineEdit *edit, bool *ok = nullptr)
39 {
40  return edit->text().replace(QLocale().decimalPoint(), ".").toDouble(ok);
41 }
42 
43 // Extract FOV from QListWidget. No checking is done
44 FOV *getFOV(QListWidgetItem *item)
45 {
46  return item->data(Qt::UserRole).value<FOV *>();
47 }
48 
49 // Convert double to QString
50 QString toString(double x, int precision = 2)
51 {
52  return QString::number(x, 'f', precision).replace('.', QLocale().decimalPoint());
53 }
54 }
55 
56 FOVDialogUI::FOVDialogUI(QWidget *parent) : QFrame(parent)
57 {
58  setupUi(this);
59 }
60 
61 NewFOVUI::NewFOVUI(QWidget *parent) : QFrame(parent)
62 {
63  setupUi(this);
64 }
65 
66 //---------FOVDialog---------------//
67 FOVDialog::FOVDialog(QWidget *p) : QDialog(p)
68 {
69 #ifdef Q_OS_OSX
70  setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
71 #endif
72  // Register FOV* data type
73  if (fovID == -1)
74  fovID = qRegisterMetaType<FOV *>("FOV*");
75  fov = new FOVDialogUI(this);
76 
77  setWindowTitle(i18nc("@title:window", "Set FOV Indicator"));
78 
79  QVBoxLayout *mainLayout = new QVBoxLayout;
80  mainLayout->addWidget(fov);
81  setLayout(mainLayout);
82 
84  mainLayout->addWidget(buttonBox);
85  connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
86  connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
87 
88  connect(fov->FOVListBox, SIGNAL(currentRowChanged(int)), SLOT(slotSelect(int)));
89  connect(fov->NewButton, SIGNAL(clicked()), SLOT(slotNewFOV()));
90  connect(fov->EditButton, SIGNAL(clicked()), SLOT(slotEditFOV()));
91  connect(fov->RemoveButton, SIGNAL(clicked()), SLOT(slotRemoveFOV()));
92 
93  // Read list of FOVs and for each FOV create listbox entry, which stores it.
94  foreach (FOV *f, FOVManager::getFOVs())
95  {
96  addListWidget(f);
97  }
98 }
99 
100 FOVDialog::~FOVDialog()
101 {
102  // Delete FOVs
103  //for(int i = 0; i < fov->FOVListBox->count(); i++) {
104  //delete getFOV( fov->FOVListBox->item(i) );
105  //}
106 }
107 
108 QListWidgetItem *FOVDialog::addListWidget(FOV *f)
109 {
110  QListWidgetItem *item = new QListWidgetItem(f->name(), fov->FOVListBox);
111  item->setData(Qt::UserRole, QVariant::fromValue<FOV *>(f));
112  return item;
113 }
114 
115 void FOVDialog::slotSelect(int irow)
116 {
117  bool enable = irow >= 0;
118  fov->RemoveButton->setEnabled(enable);
119  fov->EditButton->setEnabled(enable);
120  if (enable)
121  {
122  //paint dialog with selected FOV symbol
123  fov->ViewBox->setFOV(getFOV(fov->FOVListBox->currentItem()));
124  fov->ViewBox->update();
125  }
126 }
127 
128 void FOVDialog::slotNewFOV()
129 {
130  QPointer<NewFOV> newfdlg = new NewFOV(this);
131  if (newfdlg->exec() == QDialog::Accepted)
132  {
133  FOV *newfov = new FOV(newfdlg->getFOV());
134  FOVManager::addFOV(newfov);
135  addListWidget(newfov);
136  fov->FOVListBox->setCurrentRow(fov->FOVListBox->count() - 1);
137  }
138  delete newfdlg;
139 }
140 
141 void FOVDialog::slotEditFOV()
142 {
143  //Preload current values
144  QListWidgetItem *item = fov->FOVListBox->currentItem();
145  if (item == nullptr)
146  return;
147  FOV *f = item->data(Qt::UserRole).value<FOV *>();
148 
149  // Create dialog
150  QPointer<NewFOV> newfdlg = new NewFOV(this, f);
151  if (newfdlg->exec() == QDialog::Accepted)
152  {
153  // Overwrite FOV
154  f->sync(newfdlg->getFOV());
155  fov->ViewBox->update();
156  }
157  delete newfdlg;
158 }
159 
160 void FOVDialog::slotRemoveFOV()
161 {
162  int i = fov->FOVListBox->currentRow();
163  if (i >= 0)
164  {
165  QListWidgetItem *item = fov->FOVListBox->takeItem(i);
166  FOVManager::removeFOV(getFOV(item));
167  delete item;
168  }
169 }
170 
171 //-------------NewFOV------------------//
172 
173 NewFOV::NewFOV(QWidget *parent, const FOV *fov) : QDialog(parent), f()
174 {
175  ui = new NewFOVUI(this);
176 
177  setWindowTitle(i18nc("@title:window", "New FOV Indicator"));
178 
179  QVBoxLayout *mainLayout = new QVBoxLayout;
180  mainLayout->addWidget(ui);
181  setLayout(mainLayout);
182 
184  mainLayout->addWidget(buttonBox);
185  connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
186  connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
187 
188  okB = buttonBox->button(QDialogButtonBox::Ok);
189 
190  // Initialize FOV if required
191  if (fov != nullptr)
192  {
193  f.sync(*fov);
194  ui->FOVName->setText(f.name());
195  ui->FOVEditX->setText(toString(f.sizeX()));
196  ui->FOVEditY->setText(toString(f.sizeY()));
197  ui->FOVEditOffsetX->setText(toString(f.offsetX()));
198  ui->FOVEditOffsetY->setText(toString(f.offsetY()));
199  ui->FOVEditRotation->setText(toString(f.PA()));
200  ui->ColorButton->setColor(QColor(f.color()));
201  ui->ShapeBox->setCurrentIndex(f.shape());
202  ui->FOVLockCP->setChecked(f.lockCelestialPole());
203 
204  ui->TLength2->setValue(Options::telescopeFocalLength());
205  ui->cameraWidth->setValue(Options::cameraWidth());
206  ui->cameraHeight->setValue(Options::cameraHeight());
207  ui->cameraPixelSizeW->setValue(Options::cameraPixelWidth());
208  ui->cameraPixelSizeH->setValue(Options::cameraPixelHeight());
209 
210  ui->ViewBox->setFOV(&f);
211  ui->ViewBox->update();
212  }
213 
214  connect(ui->FOVName, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
215  connect(ui->FOVEditX, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
216  connect(ui->FOVEditY, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
217  connect(ui->FOVEditOffsetX, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
218  connect(ui->FOVEditOffsetY, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
219  connect(ui->FOVEditRotation, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
220  connect(ui->FOVLockCP, SIGNAL(toggled(bool)), SLOT(slotUpdateFOV()));
221  connect(ui->ColorButton, SIGNAL(changed(QColor)), SLOT(slotUpdateFOV()));
222  connect(ui->ShapeBox, SIGNAL(activated(int)), SLOT(slotUpdateFOV()));
223  connect(ui->ComputeEyeFOV, SIGNAL(clicked()), SLOT(slotComputeFOV()));
224  connect(ui->ComputeCameraFOV, SIGNAL(clicked()), SLOT(slotComputeFOV()));
225  connect(ui->ComputeHPBW, SIGNAL(clicked()), SLOT(slotComputeFOV()));
226  connect(ui->ComputeBinocularFOV, SIGNAL(clicked()), SLOT(slotComputeFOV()));
227  connect(ui->ComputeTLengthFromFNum1, SIGNAL(clicked()), SLOT(slotComputeTelescopeFL()));
228  connect(ui->DetectFromINDI, SIGNAL(clicked()), SLOT(slotDetectFromINDI()));
229 
230 #ifndef HAVE_INDI
231  ui->DetectFromINDI->setEnabled(false);
232 #endif
233 
234  // Populate eyepiece AFOV options. The userData field contains the apparent FOV associated with that option
235  ui->EyepieceAFOV->insertItem(0, i18nc("Specify the apparent field of view (AFOV) manually", "Specify AFOV"), -1);
236  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Ramsden (Typical)"), 30);
237  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Orthoscopic (Typical)"), 45);
238  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Ploessl (Typical)"), 50);
239  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Erfle (Typical)"), 60);
240  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Radian"), 60);
241  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Baader Hyperion"), 68);
242  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Panoptic"), 68);
243  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Delos"), 72);
244  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Meade UWA"), 82);
245  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Nagler"), 82);
246  ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Ethos (Typical)"), 100);
247 
248  connect(ui->EyepieceAFOV, SIGNAL(currentIndexChanged(int)), SLOT(slotEyepieceAFOVChanged(int)));
249 
250  ui->LinearFOVDistance->insertItem(0, i18n("1000 yards"));
251  ui->LinearFOVDistance->insertItem(1, i18n("1000 meters"));
252  connect(ui->LinearFOVDistance, SIGNAL(currentIndexChanged(int)), SLOT(slotBinocularFOVDistanceChanged(int)));
253 
254  slotUpdateFOV();
255 }
256 
257 void NewFOV::slotBinocularFOVDistanceChanged(int index)
258 {
259  QString text = (index == 0 ? i18n("feet") : i18n("meters"));
260  ui->LabelUnits->setText(text);
261 }
262 
263 void NewFOV::slotUpdateFOV()
264 {
265  bool okX, okY;
266  f.setName(ui->FOVName->text());
267  float sizeX = textToDouble(ui->FOVEditX, &okX);
268  float sizeY = textToDouble(ui->FOVEditY, &okY);
269  if (okX && okY)
270  f.setSize(sizeX, sizeY);
271 
272  float xoffset = textToDouble(ui->FOVEditOffsetX, &okX);
273  float yoffset = textToDouble(ui->FOVEditOffsetY, &okY);
274  if (okX && okY)
275  f.setOffset(xoffset, yoffset);
276 
277  float rot = textToDouble(ui->FOVEditRotation, &okX);
278  if (okX)
279  f.setPA(rot);
280 
281  f.setShape(static_cast<FOV::Shape>(ui->ShapeBox->currentIndex()));
282  f.setColor(ui->ColorButton->color().name());
283  f.setLockCelestialPole(ui->FOVLockCP->isChecked());
284 
285  okB->setEnabled(!f.name().isEmpty() && okX && okY);
286 
287  ui->ViewBox->setFOV(&f);
288  ui->ViewBox->update();
289 }
290 
291 void NewFOV::slotComputeFOV()
292 {
293  if (sender() == ui->ComputeEyeFOV && ui->TLength1->value() > 0.0)
294  {
295  ui->FOVEditX->setText(toString(60.0 * ui->EyeFOV->value() * ui->EyeLength->value() / ui->TLength1->value()));
296  ui->FOVEditY->setText(ui->FOVEditX->text());
297  }
298  else if (sender() == ui->ComputeCameraFOV && ui->TLength2->value() > 0.0)
299  {
300  /*double sx = (double)ui->ChipWidth->value() * 3438.0 / ui->TLength2->value();
301  double sy = (double)ui->ChipHeight->value() * 3438.0 / ui->TLength2->value();
302  //const double aspectratio = 3.0/2.0; // Use the default aspect ratio for DSLRs / Film (i.e. 3:2)*/
303 
304  // FOV in arcmins
305  double fov_x = 206264.8062470963552 * ui->cameraWidth->value() * ui->cameraPixelSizeW->value() / 60000.0 / ui->TLength2->value();
306  double fov_y = 206264.8062470963552 * ui->cameraHeight->value() * ui->cameraPixelSizeH->value() / 60000.0 / ui->TLength2->value();
307 
308  ui->FOVEditX->setText(toString(fov_x));
309  ui->FOVEditY->setText(toString(fov_y));
310  }
311  else if (sender() == ui->ComputeHPBW && ui->RTDiameter->value() > 0.0 && ui->WaveLength->value() > 0.0)
312  {
313  ui->FOVEditX->setText(toString(34.34 * 1.2 * ui->WaveLength->value() / ui->RTDiameter->value()));
314  // Beam width for an antenna is usually a circle on the sky.
315  ui->ShapeBox->setCurrentIndex(4);
316  ui->FOVEditY->setText(ui->FOVEditX->text());
317  slotUpdateFOV();
318  }
319  else if (sender() == ui->ComputeBinocularFOV && ui->LinearFOV->value() > 0.0 &&
320  ui->LinearFOVDistance->currentIndex() >= 0)
321  {
322  double sx =
323  atan((double)ui->LinearFOV->value() / ((ui->LinearFOVDistance->currentIndex() == 0) ? 3000.0 : 1000.0)) *
324  180.0 * 60.0 / dms::PI;
325  ui->FOVEditX->setText(toString(sx));
326  ui->FOVEditY->setText(ui->FOVEditX->text());
327  }
328 }
329 
330 void NewFOV::slotEyepieceAFOVChanged(int index)
331 {
332  if (index == 0)
333  {
334  ui->EyeFOV->setEnabled(true);
335  }
336  else
337  {
338  bool ok;
339  ui->EyeFOV->setEnabled(false);
340  ui->EyeFOV->setValue(ui->EyepieceAFOV->itemData(index).toFloat(&ok));
341  Q_ASSERT(ok);
342  }
343 }
344 
345 void NewFOV::slotComputeTelescopeFL()
346 {
347  TelescopeFL *telescopeFLDialog = new TelescopeFL(this);
348  if (telescopeFLDialog->exec() == QDialog::Accepted)
349  {
350  ui->TLength1->setValue(telescopeFLDialog->computeFL());
351  }
352  delete telescopeFLDialog;
353 }
354 
355 void NewFOV::slotDetectFromINDI()
356 {
357  QDBusInterface alignInterface("org.kde.kstars",
358  "/KStars/Ekos/Align",
359  "org.kde.kstars.Ekos.Align",
361 
362  QDBusReply<QList<double>> cameraReply = alignInterface.call("cameraInfo");
363  if (cameraReply.isValid())
364  {
365  QList<double> values = cameraReply.value();
366 
367  ui->cameraWidth->setValue(values[0]);
368  ui->cameraHeight->setValue(values[1]);
369  ui->cameraPixelSizeW->setValue(values[2]);
370  ui->cameraPixelSizeH->setValue(values[3]);
371  }
372 
373  QDBusReply<QList<double>> telescopeReply = alignInterface.call("telescopeInfo");
374  if (telescopeReply.isValid())
375  {
376  QList<double> values = telescopeReply.value();
377  ui->TLength2->setValue(values[0]);
378  }
379 
380  QDBusReply<QList<double>> solutionReply = alignInterface.call("getSolutionResult");
381  if (solutionReply.isValid())
382  {
383  QList<double> values = solutionReply.value();
384  if (values[0] > -1e6)
385  ui->FOVEditRotation->setText(QString::number(values[0]));
386  }
387 }
388 
389 
390 //-------------TelescopeFL------------------//
391 
392 TelescopeFL::TelescopeFL(QWidget *parent) : QDialog(parent), aperture(nullptr), fNumber(nullptr), apertureUnit(nullptr)
393 {
394  setWindowTitle(i18nc("@title:window", "Telescope Focal Length Calculator"));
395 
396  //QWidget *mainWidget = new QWidget( this );
397  QGridLayout *mainLayout = new QGridLayout(this);
398  setLayout(mainLayout);
399 
400  aperture = new QDoubleSpinBox();
401  aperture->setRange(0.0, 100000.0);
402  aperture->setDecimals(2);
403  aperture->setSingleStep(0.1);
404 
405  fNumber = new QDoubleSpinBox();
406  fNumber->setRange(0.0, 99.9);
407  fNumber->setDecimals(2);
408  fNumber->setSingleStep(0.1);
409 
410  apertureUnit = new QComboBox(this);
411  apertureUnit->insertItem(0, i18nc("millimeters", "mm"));
412  apertureUnit->insertItem(1, i18n("inch"));
413 
414  mainLayout->addWidget(new QLabel(i18n("Aperture diameter: "), this), 0, 0);
415  mainLayout->addWidget(aperture, 0, 1);
416  mainLayout->addWidget(apertureUnit, 0, 2);
417  mainLayout->addWidget(new QLabel(i18nc("F-Number or F-Ratio of optical system", "F-Number: "), this), 1, 0);
418  mainLayout->addWidget(fNumber, 1, 1);
419 
421  mainLayout->addWidget(buttonBox);
422  connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
423  connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
424 
425  show();
426 }
427 
429 {
430  const double inch_to_mm = 25.4; // 1 inch, by definition, is 25.4 mm
431  return (aperture->value() * fNumber->value() *
432  ((apertureUnit->currentIndex() == 1) ?
433  inch_to_mm :
434  1.0)); // Focal Length = Aperture * F-Number, by definition of F-Number
435 }
436 
437 unsigned int FOVDialog::currentItem() const
438 {
439  return fov->FOVListBox->currentRow();
440 }
Definition: fov.h:27
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:380
UserRole
QString number(int n, int base)
virtual void reject()
T value() const const
bool isValid() const const
void setDecimals(int prec)
double computeFL() const
Compute and return the focal length in mm.
Definition: fovdialog.cpp:428
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual QVariant data(int role) const const
void setEnabled(bool enable)
void rejected()
QString i18n(const char *text, const TYPE &arg...)
QDBusConnection sessionBus()
virtual void setData(int role, const QVariant &value)
char * toString(const T &value)
void insertItem(int index, const QString &text, const QVariant &userData)
void setWindowTitle(const QString &)
QAction * close(const QObject *recvr, const char *slot, QObject *parent)
virtual void accept()
virtual int exec()
NewFOV(QWidget *parent=nullptr, const FOV *fov=nullptr)
Create new dialog.
Definition: fovdialog.cpp:173
QString & replace(int position, int n, QChar after)
void show()
QPushButton * button(QDialogButtonBox::StandardButton which) const const
void setRange(double minimum, double maximum)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment)
TelescopeFL(QWidget *parent=nullptr)
Create a telescope focal length dialog.
Definition: fovdialog.cpp:392
void setLayout(QLayout *layout)
void setSingleStep(double val)
QVector< V > values(const QMultiHash< K, V > &c)
QDBusReply::Type value() const const
void accepted()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue Aug 16 2022 04:00:55 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.