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

KDE's Doxygen guidelines are available online.