Warning, file /education/kstars/kstars/dialogs/fovdialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "fovdialog.h"
0008 
0009 #include <QFile>
0010 #include <QFrame>
0011 #include <QPainter>
0012 #include <QTextStream>
0013 #include <QPaintEvent>
0014 #include <QDebug>
0015 #include <QPushButton>
0016 #include <QComboBox>
0017 #include <QDoubleSpinBox>
0018 #include <QLineEdit>
0019 
0020 #include <KActionCollection>
0021 #include <KLocalizedString>
0022 #include <kcolorbutton.h>
0023 #include <KMessageBox>
0024 
0025 #include "kstars.h"
0026 #include "kstarsdata.h"
0027 #include "widgets/fovwidget.h"
0028 #include "Options.h"
0029 
0030 // This is needed to make FOV work with QVariant
0031 Q_DECLARE_METATYPE(FOV *)
0032 
0033 int FOVDialog::fovID = -1;
0034 
0035 namespace
0036 {
0037 // Try to convert text in KLine edit to double
0038 inline double textToDouble(const QLineEdit *edit, bool *ok = nullptr)
0039 {
0040     return edit->text().replace(QLocale().decimalPoint(), ".").toDouble(ok);
0041 }
0042 
0043 // Extract FOV from QListWidget. No checking is done
0044 FOV *getFOV(QListWidgetItem *item)
0045 {
0046     return item->data(Qt::UserRole).value<FOV *>();
0047 }
0048 
0049 // Convert double to QString
0050 QString toString(double x, int precision = 2)
0051 {
0052     return QString::number(x, 'f', precision).replace('.', QLocale().decimalPoint());
0053 }
0054 }
0055 
0056 FOVDialogUI::FOVDialogUI(QWidget *parent) : QFrame(parent)
0057 {
0058     setupUi(this);
0059 }
0060 
0061 NewFOVUI::NewFOVUI(QWidget *parent) : QFrame(parent)
0062 {
0063     setupUi(this);
0064 }
0065 
0066 //---------FOVDialog---------------//
0067 FOVDialog::FOVDialog(QWidget *p) : QDialog(p)
0068 {
0069 #ifdef Q_OS_OSX
0070     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0071 #endif
0072     // Register FOV* data type
0073     if (fovID == -1)
0074         fovID = qRegisterMetaType<FOV *>("FOV*");
0075     fov = new FOVDialogUI(this);
0076 
0077     setWindowTitle(i18nc("@title:window", "Set FOV Indicator"));
0078 
0079     QVBoxLayout *mainLayout = new QVBoxLayout;
0080     mainLayout->addWidget(fov);
0081     setLayout(mainLayout);
0082 
0083     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close);
0084     mainLayout->addWidget(buttonBox);
0085     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0086     connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
0087 
0088     connect(fov->FOVListBox, SIGNAL(currentRowChanged(int)), SLOT(slotSelect(int)));
0089     connect(fov->NewButton, SIGNAL(clicked()), SLOT(slotNewFOV()));
0090     connect(fov->EditButton, SIGNAL(clicked()), SLOT(slotEditFOV()));
0091     connect(fov->RemoveButton, SIGNAL(clicked()), SLOT(slotRemoveFOV()));
0092 
0093     // Read list of FOVs and for each FOV create listbox entry, which stores it.
0094     foreach (FOV *f, FOVManager::getFOVs())
0095     {
0096         addListWidget(f);
0097     }
0098 }
0099 
0100 FOVDialog::~FOVDialog()
0101 {
0102     // Delete FOVs
0103     //for(int i = 0; i < fov->FOVListBox->count(); i++) {
0104     //delete getFOV( fov->FOVListBox->item(i) );
0105     //}
0106 }
0107 
0108 QListWidgetItem *FOVDialog::addListWidget(FOV *f)
0109 {
0110     QListWidgetItem *item = new QListWidgetItem(f->name(), fov->FOVListBox);
0111     item->setData(Qt::UserRole, QVariant::fromValue<FOV *>(f));
0112     return item;
0113 }
0114 
0115 void FOVDialog::slotSelect(int irow)
0116 {
0117     bool enable = irow >= 0;
0118     fov->RemoveButton->setEnabled(enable);
0119     fov->EditButton->setEnabled(enable);
0120     if (enable)
0121     {
0122         //paint dialog with selected FOV symbol
0123         fov->ViewBox->setFOV(getFOV(fov->FOVListBox->currentItem()));
0124         fov->ViewBox->update();
0125     }
0126 }
0127 
0128 void FOVDialog::slotNewFOV()
0129 {
0130     QPointer<NewFOV> newfdlg = new NewFOV(this);
0131     if (newfdlg->exec() == QDialog::Accepted)
0132     {
0133         FOV *newfov = new FOV(newfdlg->getFOV());
0134         FOVManager::addFOV(newfov);
0135         addListWidget(newfov);
0136         fov->FOVListBox->setCurrentRow(fov->FOVListBox->count() - 1);
0137     }
0138     delete newfdlg;
0139 }
0140 
0141 void FOVDialog::slotEditFOV()
0142 {
0143     //Preload current values
0144     QListWidgetItem *item = fov->FOVListBox->currentItem();
0145     if (item == nullptr)
0146         return;
0147     FOV *f = item->data(Qt::UserRole).value<FOV *>();
0148 
0149     // Create dialog
0150     QPointer<NewFOV> newfdlg = new NewFOV(this, f);
0151     if (newfdlg->exec() == QDialog::Accepted)
0152     {
0153         // Overwrite FOV
0154         f->sync(newfdlg->getFOV());
0155         fov->ViewBox->update();
0156     }
0157     delete newfdlg;
0158 }
0159 
0160 void FOVDialog::slotRemoveFOV()
0161 {
0162     int i = fov->FOVListBox->currentRow();
0163     if (i >= 0)
0164     {
0165         QListWidgetItem *item = fov->FOVListBox->takeItem(i);
0166         FOVManager::removeFOV(getFOV(item));
0167         delete item;
0168     }
0169 }
0170 
0171 //-------------NewFOV------------------//
0172 
0173 NewFOV::NewFOV(QWidget *parent, const FOV *fov) : QDialog(parent), f()
0174 {
0175     ui = new NewFOVUI(this);
0176 
0177     setWindowTitle(i18nc("@title:window", "New FOV Indicator"));
0178 
0179     QVBoxLayout *mainLayout = new QVBoxLayout;
0180     mainLayout->addWidget(ui);
0181     setLayout(mainLayout);
0182 
0183     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0184     mainLayout->addWidget(buttonBox);
0185     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0186     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0187 
0188     okB = buttonBox->button(QDialogButtonBox::Ok);
0189 
0190     // Initialize FOV if required
0191     if (fov != nullptr)
0192     {
0193         f.sync(*fov);
0194         ui->FOVName->setText(f.name());
0195         ui->FOVEditX->setText(toString(f.sizeX()));
0196         ui->FOVEditY->setText(toString(f.sizeY()));
0197         ui->FOVEditOffsetX->setText(toString(f.offsetX()));
0198         ui->FOVEditOffsetY->setText(toString(f.offsetY()));
0199         ui->FOVEditRotation->setText(toString(f.PA()));
0200         ui->ColorButton->setColor(QColor(f.color()));
0201         ui->ShapeBox->setCurrentIndex(f.shape());
0202         ui->FOVLockCP->setChecked(f.lockCelestialPole());
0203 
0204         ui->TLength2->setValue(Options::telescopeFocalLength());
0205         ui->cameraWidth->setValue(Options::cameraWidth());
0206         ui->cameraHeight->setValue(Options::cameraHeight());
0207         ui->cameraPixelSizeW->setValue(Options::cameraPixelWidth());
0208         ui->cameraPixelSizeH->setValue(Options::cameraPixelHeight());
0209 
0210         ui->ViewBox->setFOV(&f);
0211         ui->ViewBox->update();
0212     }
0213 
0214     connect(ui->FOVName, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
0215     connect(ui->FOVEditX, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
0216     connect(ui->FOVEditY, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
0217     connect(ui->FOVEditOffsetX, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
0218     connect(ui->FOVEditOffsetY, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
0219     connect(ui->FOVEditRotation, SIGNAL(textChanged(QString)), SLOT(slotUpdateFOV()));
0220     connect(ui->FOVLockCP, SIGNAL(toggled(bool)), SLOT(slotUpdateFOV()));
0221     connect(ui->ColorButton, SIGNAL(changed(QColor)), SLOT(slotUpdateFOV()));
0222     connect(ui->ShapeBox, SIGNAL(activated(int)), SLOT(slotUpdateFOV()));
0223     connect(ui->ComputeEyeFOV, SIGNAL(clicked()), SLOT(slotComputeFOV()));
0224     connect(ui->ComputeCameraFOV, SIGNAL(clicked()), SLOT(slotComputeFOV()));
0225     connect(ui->ComputeHPBW, SIGNAL(clicked()), SLOT(slotComputeFOV()));
0226     connect(ui->ComputeBinocularFOV, SIGNAL(clicked()), SLOT(slotComputeFOV()));
0227     connect(ui->ComputeTLengthFromFNum1, SIGNAL(clicked()), SLOT(slotComputeTelescopeFL()));
0228     connect(ui->DetectFromINDI, SIGNAL(clicked()), SLOT(slotDetectFromINDI()));
0229 
0230 #ifndef HAVE_INDI
0231     ui->DetectFromINDI->setEnabled(false);
0232 #endif
0233 
0234     // Populate eyepiece AFOV options. The userData field contains the apparent FOV associated with that option
0235     ui->EyepieceAFOV->insertItem(0, i18nc("Specify the apparent field of view (AFOV) manually", "Specify AFOV"), -1);
0236     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Ramsden (Typical)"), 30);
0237     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Orthoscopic (Typical)"), 45);
0238     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Ploessl (Typical)"), 50);
0239     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Erfle (Typical)"), 60);
0240     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Radian"), 60);
0241     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Baader Hyperion"), 68);
0242     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Panoptic"), 68);
0243     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Delos"), 72);
0244     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Meade UWA"), 82);
0245     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Nagler"), 82);
0246     ui->EyepieceAFOV->addItem(i18nc("Eyepiece Design / Brand / Name; Optional", "Tele Vue Ethos (Typical)"), 100);
0247 
0248     connect(ui->EyepieceAFOV, SIGNAL(currentIndexChanged(int)), SLOT(slotEyepieceAFOVChanged(int)));
0249 
0250     ui->LinearFOVDistance->insertItem(0, i18n("1000 yards"));
0251     ui->LinearFOVDistance->insertItem(1, i18n("1000 meters"));
0252     connect(ui->LinearFOVDistance, SIGNAL(currentIndexChanged(int)), SLOT(slotBinocularFOVDistanceChanged(int)));
0253 
0254     slotUpdateFOV();
0255 }
0256 
0257 void NewFOV::slotBinocularFOVDistanceChanged(int index)
0258 {
0259     QString text = (index == 0 ? i18n("feet") : i18n("meters"));
0260     ui->LabelUnits->setText(text);
0261 }
0262 
0263 void NewFOV::slotUpdateFOV()
0264 {
0265     bool okX, okY;
0266     f.setName(ui->FOVName->text());
0267     float sizeX = textToDouble(ui->FOVEditX, &okX);
0268     float sizeY = textToDouble(ui->FOVEditY, &okY);
0269     if (okX && okY)
0270         f.setSize(sizeX, sizeY);
0271 
0272     float xoffset = textToDouble(ui->FOVEditOffsetX, &okX);
0273     float yoffset = textToDouble(ui->FOVEditOffsetY, &okY);
0274     if (okX && okY)
0275         f.setOffset(xoffset, yoffset);
0276 
0277     float rot = textToDouble(ui->FOVEditRotation, &okX);
0278     if (okX)
0279         f.setPA(rot);
0280 
0281     f.setShape(static_cast<FOV::Shape>(ui->ShapeBox->currentIndex()));
0282     f.setColor(ui->ColorButton->color().name());
0283     f.setLockCelestialPole(ui->FOVLockCP->isChecked());
0284 
0285     okB->setEnabled(!f.name().isEmpty() && okX && okY);
0286 
0287     ui->ViewBox->setFOV(&f);
0288     ui->ViewBox->update();
0289 }
0290 
0291 void NewFOV::slotComputeFOV()
0292 {
0293     if (sender() == ui->ComputeEyeFOV && ui->TLength1->value() > 0.0)
0294     {
0295         ui->FOVEditX->setText(toString(60.0 * ui->EyeFOV->value() * ui->EyeLength->value() / ui->TLength1->value()));
0296         ui->FOVEditY->setText(ui->FOVEditX->text());
0297     }
0298     else if (sender() == ui->ComputeCameraFOV && ui->TLength2->value() > 0.0)
0299     {
0300         /*double sx = (double)ui->ChipWidth->value() * 3438.0 / ui->TLength2->value();
0301         double sy = (double)ui->ChipHeight->value() * 3438.0 / ui->TLength2->value();
0302         //const double aspectratio = 3.0/2.0; // Use the default aspect ratio for DSLRs / Film (i.e. 3:2)*/
0303 
0304         // FOV in arcmins
0305         double fov_x = 206264.8062470963552 * ui->cameraWidth->value() * ui->cameraPixelSizeW->value() / 60000.0 / ui->TLength2->value();
0306         double fov_y = 206264.8062470963552 * ui->cameraHeight->value() * ui->cameraPixelSizeH->value() / 60000.0 / ui->TLength2->value();
0307 
0308         ui->FOVEditX->setText(toString(fov_x));
0309         ui->FOVEditY->setText(toString(fov_y));
0310     }
0311     else if (sender() == ui->ComputeHPBW && ui->RTDiameter->value() > 0.0 && ui->WaveLength->value() > 0.0)
0312     {
0313         ui->FOVEditX->setText(toString(34.34 * 1.2 * ui->WaveLength->value() / ui->RTDiameter->value()));
0314         // Beam width for an antenna is usually a circle on the sky.
0315         ui->ShapeBox->setCurrentIndex(4);
0316         ui->FOVEditY->setText(ui->FOVEditX->text());
0317         slotUpdateFOV();
0318     }
0319     else if (sender() == ui->ComputeBinocularFOV && ui->LinearFOV->value() > 0.0 &&
0320              ui->LinearFOVDistance->currentIndex() >= 0)
0321     {
0322         double sx =
0323             atan((double)ui->LinearFOV->value() / ((ui->LinearFOVDistance->currentIndex() == 0) ? 3000.0 : 1000.0)) *
0324             180.0 * 60.0 / dms::PI;
0325         ui->FOVEditX->setText(toString(sx));
0326         ui->FOVEditY->setText(ui->FOVEditX->text());
0327     }
0328 }
0329 
0330 void NewFOV::slotEyepieceAFOVChanged(int index)
0331 {
0332     if (index == 0)
0333     {
0334         ui->EyeFOV->setEnabled(true);
0335     }
0336     else
0337     {
0338         bool ok;
0339         ui->EyeFOV->setEnabled(false);
0340         ui->EyeFOV->setValue(ui->EyepieceAFOV->itemData(index).toFloat(&ok));
0341         Q_ASSERT(ok);
0342     }
0343 }
0344 
0345 void NewFOV::slotComputeTelescopeFL()
0346 {
0347     TelescopeFL *telescopeFLDialog = new TelescopeFL(this);
0348     if (telescopeFLDialog->exec() == QDialog::Accepted)
0349     {
0350         ui->TLength1->setValue(telescopeFLDialog->computeFL());
0351     }
0352     delete telescopeFLDialog;
0353 }
0354 
0355 void NewFOV::slotDetectFromINDI()
0356 {
0357     QDBusInterface alignInterface("org.kde.kstars",
0358                                   "/KStars/Ekos/Align",
0359                                   "org.kde.kstars.Ekos.Align",
0360                                   QDBusConnection::sessionBus());
0361 
0362     QDBusReply<QList<double>> cameraReply = alignInterface.call("cameraInfo");
0363     if (cameraReply.isValid())
0364     {
0365         QList<double> values = cameraReply.value();
0366 
0367         ui->cameraWidth->setValue(values[0]);
0368         ui->cameraHeight->setValue(values[1]);
0369         ui->cameraPixelSizeW->setValue(values[2]);
0370         ui->cameraPixelSizeH->setValue(values[3]);
0371     }
0372 
0373     QDBusReply<QList<double>> telescopeReply = alignInterface.call("telescopeInfo");
0374     if (telescopeReply.isValid())
0375     {
0376         QList<double> values = telescopeReply.value();
0377         ui->TLength2->setValue(values[0]);
0378     }
0379 
0380     QDBusReply<QList<double>> solutionReply = alignInterface.call("getSolutionResult");
0381     if (solutionReply.isValid())
0382     {
0383         QList<double> values = solutionReply.value();
0384         if (values[0] > -1e6)
0385             ui->FOVEditRotation->setText(QString::number(values[0]));
0386     }
0387 }
0388 
0389 
0390 //-------------TelescopeFL------------------//
0391 
0392 TelescopeFL::TelescopeFL(QWidget *parent) : QDialog(parent), aperture(nullptr), fNumber(nullptr), apertureUnit(nullptr)
0393 {
0394     setWindowTitle(i18nc("@title:window", "Telescope Focal Length Calculator"));
0395 
0396     //QWidget *mainWidget = new QWidget( this );
0397     QGridLayout *mainLayout = new QGridLayout(this);
0398     setLayout(mainLayout);
0399 
0400     aperture = new QDoubleSpinBox();
0401     aperture->setRange(0.0, 100000.0);
0402     aperture->setDecimals(2);
0403     aperture->setSingleStep(0.1);
0404 
0405     fNumber = new QDoubleSpinBox();
0406     fNumber->setRange(0.0, 99.9);
0407     fNumber->setDecimals(2);
0408     fNumber->setSingleStep(0.1);
0409 
0410     apertureUnit = new QComboBox(this);
0411     apertureUnit->insertItem(0, i18nc("millimeters", "mm"));
0412     apertureUnit->insertItem(1, i18n("inch"));
0413 
0414     mainLayout->addWidget(new QLabel(i18n("Aperture diameter: "), this), 0, 0);
0415     mainLayout->addWidget(aperture, 0, 1);
0416     mainLayout->addWidget(apertureUnit, 0, 2);
0417     mainLayout->addWidget(new QLabel(i18nc("F-Number or F-Ratio of optical system", "F-Number: "), this), 1, 0);
0418     mainLayout->addWidget(fNumber, 1, 1);
0419 
0420     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0421     mainLayout->addWidget(buttonBox);
0422     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0423     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0424 
0425     show();
0426 }
0427 
0428 double TelescopeFL::computeFL() const
0429 {
0430     const double inch_to_mm = 25.4; // 1 inch, by definition, is 25.4 mm
0431     return (aperture->value() * fNumber->value() *
0432             ((apertureUnit->currentIndex() == 1) ?
0433              inch_to_mm :
0434              1.0)); // Focal Length = Aperture * F-Number, by definition of F-Number
0435 }
0436 
0437 unsigned int FOVDialog::currentItem() const
0438 {
0439     return fov->FOVListBox->currentRow();
0440 }