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 }