File indexing completed on 2024-04-28 15:09:12

0001 /*
0002     SPDX-FileCopyrightText: 2022 Toni Schriber
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /******************************************************************************************************
0008 * Angle calculations are based on position measurements of
0009 * - Rotator angle in "Circular Angle (A)" mode (0 <> 359.99° CCW)
0010 * - Camera offset angle & Camera position angle in "Position Angle (PA)" mode (180 <> -179.99° CCW)
0011 * This leads to the following calculations:
0012 * - Camera PA = calcCameraAngel(Rotator A)
0013 * - Rotator A = calcRotatorAngle(Camera PA)
0014 * - Camera offset PA = calcOffsetAngle(Rotator A, Camera PA)
0015 *******************************************************************************************************/
0016 
0017 #include "rotatorutils.h"
0018 #include "Options.h"
0019 
0020 #include "opticaltrainmanager.h"
0021 
0022 #include <indicom.h>
0023 #include <basedevice.h>
0024 #include <cmath>
0025 
0026 RotatorUtils * RotatorUtils::m_Instance = nullptr;
0027 
0028 RotatorUtils * RotatorUtils::Instance()
0029 {
0030     if (m_Instance)
0031         return m_Instance;
0032 
0033     m_Instance = new RotatorUtils();
0034     return m_Instance;
0035 }
0036 
0037 void RotatorUtils::release()
0038 {
0039     delete (m_Instance);
0040     m_Instance = nullptr;
0041 }
0042 
0043 RotatorUtils::RotatorUtils() {}
0044 
0045 RotatorUtils::~RotatorUtils() {}
0046 
0047 void RotatorUtils::initRotatorUtils(const QString &train)
0048 {
0049     m_Offset = Options::pAOffset();
0050     m_Mount = Ekos::OpticalTrainManager::Instance()->getMount(train);
0051 
0052     if (m_Mount)
0053     {
0054         connect(m_Mount, &ISD::Mount::pierSideChanged, this, [this] (ISD::Mount::PierSide Side)
0055         {
0056             m_flippedMount = (Side != m_CalPierside);
0057             emit changedPierside(Side);
0058         });
0059     }
0060 }
0061 
0062 double RotatorUtils::calcRotatorAngle(double PositionAngle)
0063 {
0064     if (m_flippedMount)
0065     {
0066         PositionAngle += 180;
0067     }
0068     return KSUtils::range360(PositionAngle - m_Offset);
0069 }
0070 
0071 double RotatorUtils::calcCameraAngle(double RotatorAngle, bool flippedImage)
0072 {
0073     double PositionAngle = 0;
0074     if (RotatorAngle > 180)
0075     {
0076         PositionAngle = (RotatorAngle - 360) + m_Offset;
0077     }
0078     else
0079     {
0080         PositionAngle = RotatorAngle + m_Offset;
0081     }
0082     if (!m_flippedMount != !flippedImage) // XOR
0083     {
0084         if (PositionAngle > 0)
0085         {
0086             PositionAngle -= 180;
0087         }
0088         else
0089         {
0090             PositionAngle += 180;
0091         }
0092 
0093     }
0094     return KSUtils::rangePA(PositionAngle);
0095 }
0096 
0097 double RotatorUtils::calcOffsetAngle(double RotatorAngle, double PositionAngle)
0098 {
0099     double OffsetAngle = 0;
0100     if (RotatorAngle > 180)
0101     {
0102         OffsetAngle = PositionAngle - (RotatorAngle - 360);
0103     }
0104     else
0105     {
0106         OffsetAngle = PositionAngle - RotatorAngle;
0107     }
0108     if (m_flippedMount)
0109     {
0110         OffsetAngle -= 180;
0111     }
0112     return KSUtils::rangePA(OffsetAngle);
0113 }
0114 
0115 void RotatorUtils::updateOffset(double Angle)
0116 {
0117     m_Offset = Angle;
0118     Options::setPAOffset(Angle);
0119 }
0120 
0121 ISD::Mount::PierSide RotatorUtils::getMountPierside()
0122 {
0123     return(m_Mount->pierSide());
0124 }
0125 
0126 void RotatorUtils::setImagePierside(ISD::Mount::PierSide ImgPierside)
0127 {
0128     m_ImgPierside = ImgPierside;
0129 }
0130 
0131 bool RotatorUtils::checkImageFlip()
0132 {
0133     bool flipped = false;
0134 
0135     if (m_ImgPierside != ISD::Mount::PIER_UNKNOWN)
0136         if (!m_flippedMount != (m_ImgPierside == m_CalPierside)) // XOR
0137             flipped = true;
0138     return flipped;
0139 }
0140 
0141 double RotatorUtils::DiffPA(double diff)
0142 {
0143     if (diff > 180)
0144         return (360 - diff);
0145     else
0146         return diff;
0147 }
0148 
0149 void RotatorUtils::initTimeFrame(const double EndAngle)
0150 {
0151     m_EndAngle = EndAngle;
0152     m_initParameter = true;
0153     m_CCW = true;
0154 }
0155 
0156 int RotatorUtils::calcTimeFrame(const double CurrentAngle)
0157 {
0158     m_CurrentTime = QTime::currentTime();
0159     m_DeltaTime = m_StartTime.secsTo(m_CurrentTime);
0160     m_TimeFrame = 0;
0161     if (m_DeltaTime >= 1)
0162     {
0163         if (m_initParameter)
0164         {
0165             m_DeltaAngle = CurrentAngle + m_ShiftAngle;
0166             // Moving CCW or positive
0167             if (m_DeltaAngle >= 360)
0168             {
0169                 if (m_DiffAngle < 0)
0170                     m_DiffAngle = (360 + m_DiffAngle);
0171             }
0172             else // Moving CW or negative
0173             {
0174                 if (m_DiffAngle > 0)
0175                     m_DiffAngle = (360 - m_DiffAngle);
0176                 m_CCW = false;
0177             }
0178             m_initParameter = false;
0179         }
0180         m_DeltaAngle = KSUtils::range360(CurrentAngle + m_ShiftAngle);
0181         if (!m_CCW)
0182                 m_DeltaAngle = 360 - m_DeltaAngle;
0183 
0184         m_TimeFrame = fabs(m_DiffAngle) / fabs(m_DeltaAngle/m_DeltaTime);
0185     }
0186     return m_TimeFrame;
0187 }
0188 
0189 void RotatorUtils::startTimeFrame(const double StartAngle)
0190 {
0191     m_StartAngle = StartAngle;
0192     m_StartTime = QTime::currentTime();
0193     m_ShiftAngle = 360 - m_StartAngle;
0194     m_DiffAngle = m_EndAngle - m_StartAngle;
0195 }