File indexing completed on 2024-04-28 07:29:36
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 °rees, 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 };