File indexing completed on 2024-04-21 03:42:13

0001 /*
0002     SPDX-FileCopyrightText: 2016 Akarsh Simha <akarsh.simha@kdemail.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "dms.h"
0010 
0011 /**
0012  * @class CachingDms
0013  * @short a dms subclass that caches its sine and cosine values every time the angle is changed.
0014  * @note This is to be used for those angles where sin/cos is repeatedly computed.
0015  * @author Akarsh Simha <akarsh@kde.org>
0016  */
0017 
0018 class CachingDms : public dms
0019 {
0020   public:
0021     /**
0022      * @short Default Constructor
0023      */
0024     CachingDms() : dms(), m_sin(NaN::d), m_cos(NaN::d)
0025     {
0026 #ifdef COUNT_DMS_SINCOS_CALLS
0027         m_cacheUsed = true;
0028         ++cachingdms_constructor_calls;
0029 #endif
0030     };
0031 
0032     /**
0033      * @short Degree angle constructor
0034      * @param x is the angle in degrees
0035      */
0036     explicit CachingDms(const double &x);
0037 
0038     /**
0039      * @short QString constructor
0040      */
0041     explicit CachingDms(const QString &s, bool isDeg = true);
0042 
0043     /**
0044      * @short DMS representation constructor
0045      */
0046     explicit CachingDms(const int &d, const int &m = 0, const int &s = 0, const int &ms = 0);
0047 
0048 #ifdef COUNT_DMS_SINCOS_CALLS
0049     /**
0050      * @short Destructor must count bad cache uses
0051      */
0052     ~CachingDms();
0053 #endif
0054 
0055     /**
0056      * @short Sets the angle in degrees supplied as a double
0057      * @note Re-implements dms::setD() with sine/cosine caching
0058      */
0059     inline void setD(const double &x) override
0060     {
0061         dms::setD(x);
0062         dms::SinCos(m_sin, m_cos);
0063 #ifdef COUNT_DMS_SINCOS_CALLS
0064         cachingdms_delta -= 2;
0065         if (!m_cacheUsed)
0066             ++cachingdms_bad_uses;
0067         m_cacheUsed = false;
0068 #endif
0069     }
0070 
0071     /**
0072      * @short Overrides dms::setD()
0073      */
0074     inline void setD(const int &d, const int &m, const int &s, const int &ms = 0) override
0075     {
0076         dms::setD(d, m, s, ms);
0077         dms::SinCos(m_sin, m_cos);
0078 #ifdef COUNT_DMS_SINCOS_CALLS
0079         cachingdms_delta -= 2;
0080         if (!m_cacheUsed)
0081             ++cachingdms_bad_uses;
0082         m_cacheUsed = false;
0083 #endif
0084     }
0085 
0086     /**
0087      * @short Sets the angle in hours, supplied as a double
0088      * @note Re-implements dms::setH() with sine/cosine caching
0089      * @note While this and other methods internally call setD, we want to avoid unnecessary vtable lookups. We'd rather have inline than virtual when speed matters in general.
0090      */
0091     inline void setH(const double &x) override
0092     {
0093         dms::setH(x);
0094         dms::SinCos(m_sin, m_cos);
0095 #ifdef COUNT_DMS_SINCOS_CALLS
0096         cachingdms_delta -= 2;
0097         if (!m_cacheUsed)
0098             ++cachingdms_bad_uses;
0099         m_cacheUsed = false;
0100 #endif
0101     }
0102 
0103     /**
0104      * @short Sets the angle in HMS form
0105      * @note Re-implements dms::setH() with sine/cosine caching
0106      */
0107     inline void setH(const int &h, const int &m, const int &s, const int &ms = 0) override
0108     {
0109         dms::setH(h, m, s, ms);
0110         dms::SinCos(m_sin, m_cos);
0111 #ifdef COUNT_DMS_SINCOS_CALLS
0112         cachingdms_delta -= 2;
0113 #endif
0114     }
0115 
0116     /**
0117      * @short Sets the angle from string
0118      * @note Re-implements dms::setFromString()
0119      */
0120     inline bool setFromString(const QString &s, bool isDeg = true) override
0121     {
0122         bool retval = dms::setFromString(s, isDeg);
0123         dms::SinCos(m_sin, m_cos);
0124 #ifdef COUNT_DMS_SINCOS_CALLS
0125         cachingdms_delta -= 2;
0126         if (!m_cacheUsed)
0127             ++cachingdms_bad_uses;
0128         m_cacheUsed = false;
0129 #endif
0130         return retval;
0131     }
0132 
0133     /**
0134      * @short Sets the angle in radians
0135      */
0136     inline void setRadians(const double &a) override
0137     {
0138         dms::setRadians(a);
0139         dms::SinCos(m_sin, m_cos);
0140 #ifdef COUNT_DMS_SINCOS_CALLS
0141         cachingdms_delta -= 2;
0142         if (!m_cacheUsed)
0143             ++cachingdms_bad_uses;
0144         m_cacheUsed = false;
0145 #endif
0146     }
0147 
0148     /**
0149      * @short Sets the angle using atan2()
0150      * @note The advantage is that we can calculate sin/cos faster because we know the tangent
0151      */
0152     void setUsing_atan2(const double &y, const double &x);
0153 
0154     /**
0155      * @short Sets the angle using asin()
0156      * @param sine Sine of the angle
0157      * @note The advantage is that we can cache the sine value supplied
0158      * @note The limited range of asin must be borne in mind
0159      */
0160     void setUsing_asin(const double &sine);
0161 
0162     /**
0163      * @short Sets the angle using acos()
0164      * @param cosine Cosine of the angle
0165      * @note The advantage is that we can cache the cosine value supplied
0166      * @note The limited range of acos must be borne in mind
0167      */
0168     void setUsing_acos(const double &cosine);
0169 
0170     /**
0171      * @short Get the sine and cosine together
0172      * @note Re-implements dms::SinCos()
0173      * @note This just uses the cached values assuming that they are good
0174      */
0175     inline void SinCos(double &s, double &c) const
0176     {
0177         s = m_sin;
0178         c = m_cos;
0179 #ifdef COUNT_DMS_SINCOS_CALLS
0180         cachingdms_delta += 2;
0181         m_cacheUsed = true;
0182 #endif
0183     }
0184 
0185     /**
0186      * @short Get the sine of this angle
0187      * @note Re-implements dms::sin()
0188      * @note This just uses the cached value assuming that it is good
0189      */
0190     inline double sin() const
0191     {
0192 #ifdef COUNT_DMS_SINCOS_CALLS
0193         ++cachingdms_delta;
0194         m_cacheUsed = true;
0195 #endif
0196         return m_sin;
0197     }
0198 
0199     /**
0200      * @short Get the cosine of this angle
0201      * @note Re-implements dms::cos()
0202      * @note This just uses the cached value assuming that it is good
0203      */
0204     inline double cos() const
0205     {
0206 #ifdef COUNT_DMS_SINCOS_CALLS
0207         ++cachingdms_delta;
0208         m_cacheUsed = true;
0209 #endif
0210         return m_cos;
0211     }
0212 
0213     /**
0214      * @short Construct an angle from the given string
0215      * @note Re-implements dms::fromString()
0216      */
0217     static CachingDms fromString(const QString &s, bool deg);
0218 
0219     /**
0220      * @short operator -
0221      * @note In addition to negating the angle, we negate the sine value
0222      */
0223     CachingDms operator-();
0224 
0225     /**
0226      * @short Casting constructor
0227      */
0228     CachingDms(const dms &angle);
0229 
0230 #ifdef COUNT_DMS_SINCOS_CALLS
0231     /**
0232      * Copy constructor that sets m_cacheUsed to true
0233      */
0234     CachingDms(const CachingDms &o);
0235     CachingDms &operator=(const CachingDms &o);
0236 #endif
0237 
0238   private:
0239     double m_sin, m_cos; // Cached values
0240 
0241     /**
0242      * @short Private constructor used to create a CachingDms with known sine and cosine
0243      */
0244     explicit CachingDms(const double &degrees, const double &sine, const double &cosine)
0245         : dms(degrees), m_sin(sine), m_cos(cosine)
0246     {
0247 #ifdef COUNT_DMS_SINCOS_CALLS
0248         ++cachingdms_constructor_calls;
0249         m_cacheUsed = false;
0250 #endif
0251     }
0252 
0253     /**
0254      * @short Addition and subtraction operators
0255      * @note Uses trigonometric identities to find the new trigonometric values
0256      * @note Avoid repeated use, as the round-off errors will accumulate!
0257      */
0258     friend CachingDms operator+(const CachingDms &, const CachingDms &);
0259     friend CachingDms operator-(const CachingDms &, const CachingDms &);
0260     friend CachingDms operator+(const dms &a, const CachingDms &b);
0261     friend CachingDms operator-(const dms &a, const CachingDms &b);
0262     friend CachingDms operator+(const CachingDms &a, const dms &b);
0263     friend CachingDms operator-(const CachingDms &a, const dms &b);
0264 
0265 #ifdef COUNT_DMS_SINCOS_CALLS
0266   private:
0267     mutable bool m_cacheUsed;
0268 
0269   public:
0270     static unsigned long cachingdms_constructor_calls;
0271     static long cachingdms_delta; // difference of ( trig function calls ) - ( trig computations )
0272     static unsigned long cachingdms_bad_uses;
0273 #endif
0274 };