1 /* 2 SPDX-FileCopyrightText: 2016 Akarsh Simha <akarsh.simha@kdemail.net> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #pragma once 8 9 #include "dms.h" 10 11 /** 12 * @class CachingDms 13 * @short a dms subclass that caches its sine and cosine values every time the angle is changed. 14 * @note This is to be used for those angles where sin/cos is repeatedly computed. 15 * @author Akarsh Simha <akarsh@kde.org> 16 */ 17 18 class CachingDms : public dms 19 { 20 public: 21 /** 22 * @short Default Constructor 23 */ CachingDms()24 CachingDms() : dms(), m_sin(NaN::d), m_cos(NaN::d) 25 { 26 #ifdef COUNT_DMS_SINCOS_CALLS 27 m_cacheUsed = true; 28 ++cachingdms_constructor_calls; 29 #endif 30 }; 31 32 /** 33 * @short Degree angle constructor 34 * @param x is the angle in degrees 35 */ 36 explicit CachingDms(const double &x); 37 38 /** 39 * @short QString constructor 40 */ 41 explicit CachingDms(const QString &s, bool isDeg = true); 42 43 /** 44 * @short DMS representation constructor 45 */ 46 explicit CachingDms(const int &d, const int &m = 0, const int &s = 0, const int &ms = 0); 47 48 #ifdef COUNT_DMS_SINCOS_CALLS 49 /** 50 * @short Destructor must count bad cache uses 51 */ 52 ~CachingDms(); 53 #endif 54 55 /** 56 * @short Sets the angle in degrees supplied as a double 57 * @note Re-implements dms::setD() with sine/cosine caching 58 */ setD(const double & x)59 inline void setD(const double &x) override 60 { 61 dms::setD(x); 62 dms::SinCos(m_sin, m_cos); 63 #ifdef COUNT_DMS_SINCOS_CALLS 64 cachingdms_delta -= 2; 65 if (!m_cacheUsed) 66 ++cachingdms_bad_uses; 67 m_cacheUsed = false; 68 #endif 69 } 70 71 /** 72 * @short Overrides dms::setD() 73 */ 74 inline void setD(const int &d, const int &m, const int &s, const int &ms = 0) override 75 { 76 dms::setD(d, m, s, ms); 77 dms::SinCos(m_sin, m_cos); 78 #ifdef COUNT_DMS_SINCOS_CALLS 79 cachingdms_delta -= 2; 80 if (!m_cacheUsed) 81 ++cachingdms_bad_uses; 82 m_cacheUsed = false; 83 #endif 84 } 85 86 /** 87 * @short Sets the angle in hours, supplied as a double 88 * @note Re-implements dms::setH() with sine/cosine caching 89 * @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. 90 */ setH(const double & x)91 inline void setH(const double &x) override 92 { 93 dms::setH(x); 94 dms::SinCos(m_sin, m_cos); 95 #ifdef COUNT_DMS_SINCOS_CALLS 96 cachingdms_delta -= 2; 97 if (!m_cacheUsed) 98 ++cachingdms_bad_uses; 99 m_cacheUsed = false; 100 #endif 101 } 102 103 /** 104 * @short Sets the angle in HMS form 105 * @note Re-implements dms::setH() with sine/cosine caching 106 */ 107 inline void setH(const int &h, const int &m, const int &s, const int &ms = 0) override 108 { 109 dms::setH(h, m, s, ms); 110 dms::SinCos(m_sin, m_cos); 111 #ifdef COUNT_DMS_SINCOS_CALLS 112 cachingdms_delta -= 2; 113 #endif 114 } 115 116 /** 117 * @short Sets the angle from string 118 * @note Re-implements dms::setFromString() 119 */ 120 inline bool setFromString(const QString &s, bool isDeg = true) override 121 { 122 bool retval = dms::setFromString(s, isDeg); 123 dms::SinCos(m_sin, m_cos); 124 #ifdef COUNT_DMS_SINCOS_CALLS 125 cachingdms_delta -= 2; 126 if (!m_cacheUsed) 127 ++cachingdms_bad_uses; 128 m_cacheUsed = false; 129 #endif 130 return retval; 131 } 132 133 /** 134 * @short Sets the angle in radians 135 */ setRadians(const double & a)136 inline void setRadians(const double &a) override 137 { 138 dms::setRadians(a); 139 dms::SinCos(m_sin, m_cos); 140 #ifdef COUNT_DMS_SINCOS_CALLS 141 cachingdms_delta -= 2; 142 if (!m_cacheUsed) 143 ++cachingdms_bad_uses; 144 m_cacheUsed = false; 145 #endif 146 } 147 148 /** 149 * @short Sets the angle using atan2() 150 * @note The advantage is that we can calculate sin/cos faster because we know the tangent 151 */ 152 void setUsing_atan2(const double &y, const double &x); 153 154 /** 155 * @short Sets the angle using asin() 156 * @param sine Sine of the angle 157 * @note The advantage is that we can cache the sine value supplied 158 * @note The limited range of asin must be borne in mind 159 */ 160 void setUsing_asin(const double &sine); 161 162 /** 163 * @short Sets the angle using acos() 164 * @param cosine Cosine of the angle 165 * @note The advantage is that we can cache the cosine value supplied 166 * @note The limited range of acos must be borne in mind 167 */ 168 void setUsing_acos(const double &cosine); 169 170 /** 171 * @short Get the sine and cosine together 172 * @note Re-implements dms::SinCos() 173 * @note This just uses the cached values assuming that they are good 174 */ SinCos(double & s,double & c)175 inline void SinCos(double &s, double &c) const 176 { 177 s = m_sin; 178 c = m_cos; 179 #ifdef COUNT_DMS_SINCOS_CALLS 180 cachingdms_delta += 2; 181 m_cacheUsed = true; 182 #endif 183 } 184 185 /** 186 * @short Get the sine of this angle 187 * @note Re-implements dms::sin() 188 * @note This just uses the cached value assuming that it is good 189 */ sin()190 inline double sin() const 191 { 192 #ifdef COUNT_DMS_SINCOS_CALLS 193 ++cachingdms_delta; 194 m_cacheUsed = true; 195 #endif 196 return m_sin; 197 } 198 199 /** 200 * @short Get the cosine of this angle 201 * @note Re-implements dms::cos() 202 * @note This just uses the cached value assuming that it is good 203 */ cos()204 inline double cos() const 205 { 206 #ifdef COUNT_DMS_SINCOS_CALLS 207 ++cachingdms_delta; 208 m_cacheUsed = true; 209 #endif 210 return m_cos; 211 } 212 213 /** 214 * @short Construct an angle from the given string 215 * @note Re-implements dms::fromString() 216 */ 217 static CachingDms fromString(const QString &s, bool deg); 218 219 /** 220 * @short operator - 221 * @note In addition to negating the angle, we negate the sine value 222 */ 223 CachingDms operator-(); 224 225 /** 226 * @short Casting constructor 227 */ 228 CachingDms(const dms &angle); 229 230 #ifdef COUNT_DMS_SINCOS_CALLS 231 /** 232 * Copy constructor that sets m_cacheUsed to true 233 */ 234 CachingDms(const CachingDms &o); 235 CachingDms &operator=(const CachingDms &o); 236 #endif 237 238 private: 239 double m_sin, m_cos; // Cached values 240 241 /** 242 * @short Private constructor used to create a CachingDms with known sine and cosine 243 */ CachingDms(const double & degrees,const double & sine,const double & cosine)244 explicit CachingDms(const double °rees, const double &sine, const double &cosine) 245 : dms(degrees), m_sin(sine), m_cos(cosine) 246 { 247 #ifdef COUNT_DMS_SINCOS_CALLS 248 ++cachingdms_constructor_calls; 249 m_cacheUsed = false; 250 #endif 251 } 252 253 /** 254 * @short Addition and subtraction operators 255 * @note Uses trigonometric identities to find the new trigonometric values 256 * @note Avoid repeated use, as the round-off errors will accumulate! 257 */ 258 friend CachingDms operator+(const CachingDms &, const CachingDms &); 259 friend CachingDms operator-(const CachingDms &, const CachingDms &); 260 friend CachingDms operator+(const dms &a, const CachingDms &b); 261 friend CachingDms operator-(const dms &a, const CachingDms &b); 262 friend CachingDms operator+(const CachingDms &a, const dms &b); 263 friend CachingDms operator-(const CachingDms &a, const dms &b); 264 265 #ifdef COUNT_DMS_SINCOS_CALLS 266 private: 267 mutable bool m_cacheUsed; 268 269 public: 270 static unsigned long cachingdms_constructor_calls; 271 static long cachingdms_delta; // difference of ( trig function calls ) - ( trig computations ) 272 static unsigned long cachingdms_bad_uses; 273 #endif 274 }; 275