File indexing completed on 2024-04-28 03:43:17
0001 /* 0002 SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 2022 Toni Schriber 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 /****************************************************************************************************** 0009 * In 'rotatorGauge' and 'paGauge' all angles are displayed in viewing direction and positiv CCW. 0010 *******************************************************************************************************/ 0011 0012 #include "rotatorsettings.h" 0013 #include "Options.h" 0014 #include "fov.h" 0015 #include "kstarsdata.h" 0016 #include "ekos/manager.h" 0017 #include "indi/indirotator.h" 0018 #include <indicom.h> 0019 #include <basedevice.h> 0020 #include <cmath> 0021 #include "capture.h" 0022 #include "ekos/align/align.h" 0023 #include "ekos/capture/capturedeviceadaptor.h" 0024 #include "ekos/align/opsalign.h" 0025 #include "ekos/auxiliary/rotatorutils.h" 0026 0027 #include "ekos_capture_debug.h" 0028 0029 RotatorSettings::RotatorSettings(QWidget *parent) : QDialog(parent) 0030 { 0031 setupUi(this); 0032 0033 connect(this, &RotatorSettings::newLog, Ekos::Manager::Instance()->captureModule(), &Ekos::Capture::appendLogText); 0034 connect(RotatorUtils::Instance(), &RotatorUtils::changedPierside, this, &RotatorSettings::updateGaugeZeroPos); 0035 connect(FlipPolicy, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &RotatorSettings::setFlipPolicy); 0036 connect(AlignOptions, &QPushButton::clicked, this, &RotatorSettings::showAlignOptions); 0037 0038 // -- Parameter -> ui file 0039 0040 // -- Camera position angle 0041 CameraPA->setKeyboardTracking(false); 0042 connect(CameraPA, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, [ = ](double PAngle) 0043 { 0044 double RAngle = RotatorUtils::Instance()->calcRotatorAngle(PAngle); 0045 RotatorAngle->setValue(RAngle); 0046 syncFOV(PAngle); 0047 activateRotator(RAngle); 0048 CameraPASlider->setSliderPosition(PAngle * 100); // Prevent rounding to integer 0049 }); 0050 connect(CameraPASlider, &QSlider::sliderReleased, this, [this]() 0051 { 0052 CameraPA->setValue(CameraPASlider->sliderPosition() / 100.0); // Set position angle 0053 }); 0054 connect(CameraPASlider, &QSlider::valueChanged, this, [this](int PAngle100) 0055 { 0056 double PAngle = PAngle100 / 100; 0057 paGauge->setValue(-(PAngle)); // Preview cameraPA in gauge 0058 syncFOV(PAngle); // Preview FOV 0059 }); 0060 0061 // -- Options 0062 // enforceJobPA -> header file 0063 connect(reverseDirection, &QCheckBox::toggled, this, [ = ](bool toggled) 0064 { 0065 commitRotatorDirection(toggled); 0066 }); 0067 0068 // Rotator Gauge 0069 rotatorGauge->setFormat("R"); // dummy format 0070 rotatorGauge->setMinimum(-360); // display in viewing direction 0071 rotatorGauge->setMaximum(0); 0072 0073 // Position Angle Gauge 0074 paGauge->setFormat("P"); // dummy format 0075 paGauge->setMinimum(-181); // display in viewing direction 0076 paGauge->setMaximum(181); 0077 0078 // Angle Ruler 0079 paRuler->plotLayout()->clear(); 0080 QCPPolarAxisAngular *angularAxis = new QCPPolarAxisAngular(paRuler); 0081 angularAxis->removeRadialAxis(angularAxis->radialAxis()); 0082 QColor TransparentBlack(0, 0, 0, 100); 0083 QPen Pen(TransparentBlack, 3); 0084 angularAxis->setBasePen(Pen); 0085 angularAxis->setTickPen(Pen); 0086 angularAxis->setSubTickPen(Pen); 0087 angularAxis->setTickLabels(false); 0088 angularAxis->setTickLength(10, 10); 0089 angularAxis->setSubTickLength(5, 5); 0090 paRuler->plotLayout()->addElement(0, 0, angularAxis); 0091 paRuler->setBackground(Qt::GlobalColor::transparent); // transparent background part 1 0092 paRuler->setAttribute(Qt::WA_OpaquePaintEvent, false); // transparent background part 2 0093 angularAxis->grid()->setAngularPen(QPen(Qt::GlobalColor::transparent)); // no grid 0094 paRuler->replot(); 0095 0096 // Parameter Interface 0097 CameraPA->setMaximum(180.00); // uniqueness of angle (-180 = 180) 0098 CameraPA->setMinimum(-179.99); 0099 RotatorAngle->setButtonSymbols(QAbstractSpinBox::NoButtons); 0100 CameraOffset->setValue(Options::pAOffset()); 0101 CameraOffset->setButtonSymbols(QAbstractSpinBox::NoButtons); 0102 MountPierside->setCurrentIndex(ISD::Mount::PIER_UNKNOWN); 0103 MountPierside->setDisabled(true); // only show pierside for information 0104 } 0105 0106 void RotatorSettings::initRotator(const QString &train, Ekos::CaptureDeviceAdaptor *CaptureDA, ISD::Rotator *device) 0107 { 0108 m_CaptureDA = CaptureDA; 0109 RotatorUtils::Instance()->initRotatorUtils(train); 0110 0111 m_Rotator = device; 0112 RotatorName->setText(m_Rotator->getDeviceName()); 0113 updateFlipPolicy(Options::astrometryFlipRotationAllowed()); 0114 // Give getState() a second 0115 QTimer::singleShot(1000, [ = ] 0116 { 0117 if (m_CaptureDA->getRotatorAngleState() == IPS_OK) 0118 { 0119 double RAngle = m_CaptureDA->getRotatorAngle(); 0120 updateRotator(RAngle); 0121 updateGaugeZeroPos(RotatorUtils::Instance()->getMountPierside()); 0122 qCInfo(KSTARS_EKOS_CAPTURE()) << "Rotator Settings: Initial raw angle is" << RAngle << "."; 0123 emit newLog(i18n("Initial rotator angle %1° is read in successfully.", RAngle)); 0124 } 0125 else 0126 qCWarning(KSTARS_EKOS_CAPTURE()) << "Rotator Settings: Reading initial raw angle failed."; 0127 }); 0128 } 0129 0130 void RotatorSettings::updateRotator(double RAngle) 0131 { 0132 RotatorAngle->setValue(RAngle); 0133 double PAngle = RotatorUtils::Instance()->calcCameraAngle(RAngle, false); 0134 CameraPA->blockSignals(true); // Prevent reaction coupling via user input 0135 CameraPA->setValue(PAngle); 0136 CameraPA->blockSignals(false); 0137 CameraPASlider->setSliderPosition(PAngle * 100); // Prevent rounding to integer 0138 updateGauge(RAngle); 0139 } 0140 0141 void RotatorSettings::updateGauge(double RAngle) 0142 { 0143 rotatorGauge->setValue(-RAngle); // display in viewing direction 0144 CurrentRotatorAngle->setText(QString::number(RAngle, 'f', 2)); 0145 paGauge->setValue(-(RotatorUtils::Instance()->calcCameraAngle(RAngle, false))); 0146 } 0147 0148 void RotatorSettings::updateGaugeZeroPos(ISD::Mount::PierSide Pierside) 0149 { 0150 double RAngle = 0; 0151 if (Pierside == ISD::Mount::PIER_UNKNOWN) 0152 MountPierside->setStyleSheet("QComboBox {border: 1px solid red;}"); 0153 else 0154 MountPierside->setStyleSheet("QComboBox {}"); 0155 MountPierside->setCurrentIndex(Pierside); 0156 if (Pierside == ISD::Mount::PIER_WEST) 0157 rotatorGauge->setNullPosition(QRoundProgressBar::PositionTop); 0158 else if (Pierside == ISD::Mount::PIER_EAST) 0159 rotatorGauge->setNullPosition(QRoundProgressBar::PositionBottom); 0160 if (Options::astrometryFlipRotationAllowed()) // Preserve rotator raw angle 0161 RAngle = RotatorAngle->value(); 0162 else // Preserve camera position angle 0163 { 0164 RAngle = RotatorUtils::Instance()->calcRotatorAngle(CameraPA->value()); 0165 activateRotator(RAngle); 0166 } 0167 updateGauge(RAngle); 0168 updateRotator(RAngle); 0169 } 0170 0171 void RotatorSettings::setFlipPolicy(const int index) 0172 { 0173 Ekos::OpsAlign::FlipPriority Priority = static_cast<Ekos::OpsAlign::FlipPriority>(index); 0174 Ekos::OpsAlign *AlignOptionsModule = Ekos::Manager::Instance()->alignModule()->getAlignOptionsModule(); 0175 if (AlignOptionsModule) 0176 AlignOptionsModule->setFlipPolicy(Priority); 0177 } 0178 0179 void RotatorSettings::updateFlipPolicy(const bool FlipRotationAllowed) 0180 { 0181 int i = -1; 0182 if (FlipRotationAllowed) 0183 i = static_cast<int>(Ekos::OpsAlign::FlipPriority::ROTATOR_ANGLE); 0184 else 0185 i = static_cast<int>(Ekos::OpsAlign::FlipPriority::POSITION_ANGLE); 0186 FlipPolicy->blockSignals(true); // Prevent reaction coupling 0187 FlipPolicy->setCurrentIndex(i); 0188 FlipPolicy->blockSignals(false); 0189 } 0190 0191 void RotatorSettings::showAlignOptions() 0192 { 0193 KConfigDialog * alignSettings = KConfigDialog::exists("alignsettings"); 0194 if (alignSettings) 0195 { 0196 alignSettings->setEnabled(true); 0197 alignSettings->show(); 0198 } 0199 } 0200 0201 void RotatorSettings::activateRotator(double Angle) 0202 { 0203 m_CaptureDA->setRotatorAngle(Angle); 0204 } 0205 0206 void RotatorSettings::commitRotatorDirection(bool Reverse) 0207 { 0208 m_CaptureDA->reverseRotator(Reverse); 0209 } 0210 0211 void RotatorSettings::refresh(double PAngle) // Call from setAlignResults() in Module Capture 0212 { 0213 CameraPA->setValue(PAngle); 0214 syncFOV(PAngle); 0215 CameraOffset->setValue(Options::pAOffset()); 0216 } 0217 0218 void RotatorSettings::syncFOV(double PA) 0219 { 0220 for (auto oneFOV : KStarsData::Instance()->getTransientFOVs()) 0221 { 0222 // Only change the PA for the sensor FOV 0223 if (oneFOV->objectName() == "sensor_fov") 0224 { 0225 // Make sure that it is always displayed 0226 if (!Options::showSensorFOV()) 0227 { 0228 Options::setShowSensorFOV(true); 0229 oneFOV->setProperty("visible", true); 0230 } 0231 0232 // JM 2020-10-15 0233 // While we have the correct Position Angle 0234 // Because Ekos reads frame TOP-BOTTOM instead of the BOTTOM-TOP approach 0235 // used by astrometry, the PA is always 180 degree off. To avoid confusion to the user 0236 // the PA is drawn REVERSED to show the *expected* frame. However, the final PA is 0237 // the "correct" PA as expected by astrometry. 0238 //double drawnPA = PA >= 0 ? (PA - 180) : (PA + 180); 0239 oneFOV->setPA(PA); 0240 break; 0241 } 0242 } 0243 } 0244