summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkarsh Simha <akarsh@kde.org>2016-09-25 07:02:50 (GMT)
committerAkarsh Simha <akarsh@kde.org>2016-09-28 22:16:21 (GMT)
commit8c2dffafcf756f6216f0213bf1517d3e197110fd (patch)
tree59b26f4d0281512f9a839485b2e62dddf0c4cfb0
parent37ba58d59222b77c663a460dfeb2fd7611119f4d (diff)
A CachingDms class that caches trigonometric values.
-rw-r--r--kstars/CMakeLists.txt1
-rw-r--r--kstars/auxiliary/cachingdms.cpp148
-rw-r--r--kstars/auxiliary/cachingdms.h211
-rw-r--r--kstars/auxiliary/dms.h3
-rw-r--r--kstars/auxiliary/geolocation.h8
-rw-r--r--kstars/kstarsdata.h4
6 files changed, 368 insertions, 7 deletions
diff --git a/kstars/CMakeLists.txt b/kstars/CMakeLists.txt
index f085c59..0790754 100644
--- a/kstars/CMakeLists.txt
+++ b/kstars/CMakeLists.txt
@@ -582,6 +582,7 @@ set(kstars_projection_SRCS
set(kstars_extra_SRCS
auxiliary/colorscheme.cpp
auxiliary/dms.cpp
+ auxiliary/cachingdms.cpp
auxiliary/geolocation.cpp
auxiliary/ksfilereader.cpp
auxiliary/ksuserdb.cpp
diff --git a/kstars/auxiliary/cachingdms.cpp b/kstars/auxiliary/cachingdms.cpp
new file mode 100644
index 0000000..51764cf
--- /dev/null
+++ b/kstars/auxiliary/cachingdms.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ cachingdms.cpp - KStars Planetarium
+ -------------------
+ begin : Sat 24 Sep 2016 23:16:25 CDT
+ copyright : (c) 2016 by Akarsh Simha
+ email : akarsh.simha@kdemail.net
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+/* Project Includes */
+#include "cachingdms.h"
+
+/* KDE Includes */
+
+/* Qt Includes */
+#include <QString>
+
+/* STL Includes */
+#include <cmath>
+
+#ifdef COUNT_DMS_SINCOS_CALLS
+unsigned long CachingDms::cachingdms_constructor_calls = 0;
+unsigned long CachingDms::cachingdms_delta = 0; // difference of ( trig function calls ) - ( trig computations )
+#endif
+
+CachingDms::CachingDms( const double &x ) : dms( x )
+{
+ dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_constructor_calls;
+ cachingdms_delta -= 2;
+#endif
+}
+
+
+CachingDms::CachingDms(const QString& s, bool isDeg) : dms( s, isDeg ) {
+ dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_constructor_calls;
+ cachingdms_delta -= 2;
+#endif
+}
+
+CachingDms::CachingDms(const int &d, const int &m, const int &s, const int &ms) :
+ dms( d, m, s, ms ) {
+ dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_constructor_calls;
+ cachingdms_delta -= 2;
+#endif
+}
+
+void CachingDms::setUsing_atan2(const double & y, const double & x) {
+ /*
+ * NOTE: A bit of independent profiling shows that on my machine
+ * (Intel Core i5, x86_64, glibc 2.24-2) the square-root based
+ * computation below has some advantage, running ~ 70% faster on
+ * average for some range of values.
+ *
+ */
+ dms::setRadians( atan2( y, x ) );
+ register double r = sqrt( y*y + x*x );
+ m_cos = x/r;
+ m_sin = y/r;
+
+ // One may be tempted to do the following:
+ // dms::setRadians( atan2( y, x ) );
+ // m_cos = dms::cos();
+ // m_sin = (y/x) * m_cos;
+ // However, this has a problem when x = 0. The result for m_sin
+ // must be 1, but instead the above code will result in NaN.
+ // So we will need a conditional:
+ // m_sin = (x == 0) ? 1. : (y/x) * m_cos;
+ // The conditional makes the performance worse than just setting
+ // the angle and using sincos()
+}
+
+void CachingDms::setUsing_asin(const double & sine) {
+ dms::setRadians( asin( sine ) );
+ m_sin = sine;
+ // Note: The below is valid because in the range of asin, which is
+ // [-pi/2, pi/2], cosine is always non-negative
+ m_cos = std::sqrt( 1 - sine*sine );
+}
+
+void CachingDms::setUsing_acos(const double & cosine) {
+ dms::setRadians( acos( cosine ) );
+ m_cos = cosine;
+ // Note: The below is valid because in the range of acos, which is
+ // [0, pi], sine is always non-negative
+ m_sin = std::sqrt( 1 - cosine*cosine );
+}
+
+CachingDms CachingDms::fromString(const QString& s, bool deg) {
+ CachingDms result;
+ result.setFromString( s, deg );
+ return result;
+}
+
+CachingDms CachingDms::operator -() {
+ return CachingDms( -D, -m_sin, m_cos );
+}
+
+CachingDms::CachingDms(const dms& angle) {
+ D = angle.Degrees();
+ dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_constructor_calls;
+ cachingdms_delta -= 2;
+#endif
+}
+
+// Makes trig identities more readable:
+#define sinA a.m_sin
+#define cosA a.m_cos
+#define sinB b.m_sin
+#define cosB b.m_cos
+
+// We use trigonometric addition / subtraction formulae to speed up
+// computation. This way, we have no trigonometric function calls at
+// all, but only floating point multiplications and
+// addition/subtraction instead.
+// The only caveat is that error can accumulate if used repeatedly!
+
+CachingDms operator +(const CachingDms &a, const CachingDms &b) {
+ return CachingDms( a.Degrees() + b.Degrees(),
+ sinA * cosB + cosA * sinB,
+ cosA * cosB - sinA * sinB );
+}
+
+CachingDms operator -(const CachingDms &a, const CachingDms &b) {
+ return CachingDms( a.Degrees() - b.Degrees(),
+ sinA * cosB - cosA * sinB,
+ cosA * cosB + sinA * sinB );
+}
+#undef sinA
+#undef cosA
+#undef sinB
+#undef cosB
diff --git a/kstars/auxiliary/cachingdms.h b/kstars/auxiliary/cachingdms.h
new file mode 100644
index 0000000..82ba7a3
--- /dev/null
+++ b/kstars/auxiliary/cachingdms.h
@@ -0,0 +1,211 @@
+/***************************************************************************
+ cachingdms.h - KStars Planetarium
+ -------------------
+ begin : Sat 24 Sep 2016 02:18:26 CDT
+ copyright : (c) 2016 by Akarsh Simha
+ email : akarsh.simha@kdemail.net
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+
+#ifndef CACHINGDMS_H
+#define CACHINGDMS_H
+
+#include "dms.h"
+
+/**
+ * @class CachingDms
+ * @short a dms subclass that caches its sine and cosine values every time the angle is changed.
+ * @note This is to be used for those angles where sin/cos is repeatedly computed.
+ * @author Akarsh Simha <akarsh@kde.org>
+ */
+
+class CachingDms : public dms {
+
+public:
+
+ /**
+ * @short Default Constructor
+ */
+ CachingDms() : dms(), m_sin( NaN::d ), m_cos( NaN::d ) {
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_constructor_calls;
+#endif
+ };
+
+ /**
+ * @short Degree angle constructor
+ * @param x is the angle in degrees
+ */
+ explicit CachingDms(const double &x );
+
+ /**
+ * @short QString constructor
+ */
+ explicit CachingDms( const QString &s, bool isDeg=true );
+
+ /**
+ * @short DMS representation constructor
+ */
+ explicit CachingDms( const int &d, const int &m=0, const int &s=0, const int &ms=0 );
+
+ /**
+ * @short Sets the angle in degrees supplied as a double
+ * @note Re-implements dms::setD() with sine/cosine caching
+ */
+ inline void setD( const double &x ) { dms::setD( x ); dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ cachingdms_delta -= 2;
+#endif
+ }
+
+ /**
+ * @short Sets the angle in hours, supplied as a double
+ * @note Re-implements dms::setH() with sine/cosine caching
+ * @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.
+ */
+ inline void setH( const double &x ) { dms::setH( x ); dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ cachingdms_delta -= 2;
+#endif
+ }
+
+ /**
+ * @short Sets the angle in HMS form
+ * @note Re-implements dms::setH() with sine/cosine caching
+ */
+ inline void setH( const int &h, const int &m, const int &s, const int &ms=0 ) { dms::setH( h, m, s, ms ); dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ cachingdms_delta -= 2;
+#endif
+ }
+
+ /**
+ * @short Sets the angle from string
+ * @note Re-implements dms::setFromString()
+ */
+ inline void setFromString( const QString &s, bool isDeg = true ) { dms::setFromString( s, isDeg ); dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ cachingdms_delta -= 2;
+#endif
+ }
+
+ /**
+ * @short Sets the angle in radians
+ */
+ inline void setRadians( const double &a ) { dms::setRadians( a ); dms::SinCos( m_sin, m_cos );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ cachingdms_delta -= 2;
+#endif
+ }
+
+ /**
+ * @short Sets the angle using atan2()
+ * @note The advantage is that we can calculate sin/cos faster because we know the tangent
+ */
+ void setUsing_atan2( const double & y, const double & x );
+
+ /**
+ * @short Sets the angle using asin()
+ * @param sine Sine of the angle
+ * @note The advantage is that we can cache the sine value supplied
+ * @note The limited range of asin must be borne in mind
+ */
+ void setUsing_asin( const double & sine );
+
+ /**
+ * @short Sets the angle using acos()
+ * @param cosine Cosine of the angle
+ * @note The advantage is that we can cache the cosine value supplied
+ * @note The limited range of acos must be borne in mind
+ */
+ void setUsing_acos( const double & cosine );
+
+ /**
+ * @short Get the sine and cosine together
+ * @note Re-implements dms::SinCos()
+ * @note This just uses the cached values assuming that they are good
+ */
+ inline void SinCos( double &s, double &c ) const { s = m_sin; c = m_cos;
+#ifdef COUNT_DMS_SINCOS_CALLS
+ cachingdms_delta += 2;
+#endif
+ }
+
+ /**
+ * @short Get the sine of this angle
+ * @note Re-implements dms::sin()
+ * @note This just uses the cached value assuming that it is good
+ */
+ inline double sin() const {
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_delta;
+#endif
+ return m_sin; }
+
+ /**
+ * @short Get the cosine of this angle
+ * @note Re-implements dms::cos()
+ * @note This just uses the cached value assuming that it is good
+ */
+ inline double cos() const {
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_delta;
+#endif
+ return m_cos; }
+
+ /**
+ * @short Construct an angle from the given string
+ * @note Re-implements dms::fromString()
+ */
+ static CachingDms fromString( const QString &s, bool deg );
+
+ /**
+ * @short operator -
+ * @note In addition to negating the angle, we negate the sine value
+ */
+ CachingDms operator - ();
+
+ /**
+ * @short Casting constructor
+ */
+ CachingDms( const dms &angle );
+
+private:
+ double m_sin, m_cos; // Cached values
+
+ /**
+ * @short Private constructor used to create a CachingDms with known sine and cosine
+ */
+ explicit CachingDms( const double &degrees, const double &sine, const double &cosine )
+ : dms( degrees ), m_sin( sine ), m_cos( cosine ) {
+#ifdef COUNT_DMS_SINCOS_CALLS
+ ++cachingdms_constructor_calls;
+#endif
+ }
+
+ /**
+ * @short Addition and subtraction operators
+ * @note Uses trigonometric identities to find the new trigonometric values
+ * @note Avoid repeated use, as the round-off errors will accumulate!
+ */
+ friend CachingDms operator +(const CachingDms &, const CachingDms &);
+ friend CachingDms operator -(const CachingDms &, const CachingDms &);
+
+#ifdef COUNT_DMS_SINCOS_CALLS
+public:
+ static unsigned long cachingdms_constructor_calls;
+ static unsigned long cachingdms_delta; // difference of ( trig function calls ) - ( trig computations )
+#endif
+};
+
+#endif
diff --git a/kstars/auxiliary/dms.h b/kstars/auxiliary/dms.h
index b07fbab..d4b7196 100644
--- a/kstars/auxiliary/dms.h
+++ b/kstars/auxiliary/dms.h
@@ -350,8 +350,9 @@ public:
static long unsigned redundant_trig_function_calls; // counts number of redundant trig function calls
static double seconds_in_trig; // accumulates number of seconds spent in trig function calls
#endif
-private:
+protected:
double D;
+private:
#ifdef COUNT_DMS_SINCOS_CALLS
mutable bool m_sinDirty, m_cosDirty, m_sinCosCalled;
#endif
diff --git a/kstars/auxiliary/geolocation.h b/kstars/auxiliary/geolocation.h
index 5ffffe0..433a6a2 100644
--- a/kstars/auxiliary/geolocation.h
+++ b/kstars/auxiliary/geolocation.h
@@ -22,7 +22,7 @@
#include <KLocalizedString>
-#include "dms.h"
+#include "cachingdms.h"
#include "timezonerule.h"
#include "kstarsdatetime.h"
@@ -75,10 +75,10 @@ public:
double TZ=0, TimeZoneRule *TZrule=NULL, bool readOnly=false, int iEllips=4 );
/** @return pointer to the longitude dms object */
- const dms* lng() const { return &Longitude; }
+ const CachingDms* lng() const { return &Longitude; }
/** @return pointer to the latitude dms object */
- const dms* lat() const { return &Latitude; }
+ const CachingDms* lat() const { return &Latitude; }
/** @return elevation above seal level (meters) */
double height() const { return Height; }
@@ -263,7 +263,7 @@ public:
void setReadOnly(bool value);
private:
- dms Longitude, Latitude;
+ CachingDms Longitude, Latitude;
QString Name, Province, Country;
TimeZoneRule *TZrule;
double TimeZone, Height;
diff --git a/kstars/kstarsdata.h b/kstars/kstarsdata.h
index b3b0f12..6d36e62 100644
--- a/kstars/kstarsdata.h
+++ b/kstars/kstarsdata.h
@@ -168,7 +168,7 @@ public:
Q_INVOKABLE SimClock *clock() { return &Clock; }
/** @return pointer to the local sidereal time: a dms object */
- dms *lst() { return &LST; }
+ CachingDms *lst() { return &LST; }
/** @return pointer to the GeoLocation object*/
GeoLocation *geo() { return &m_Geo; }
@@ -370,7 +370,7 @@ private:
//KLocale *locale;
- dms LST;
+ CachingDms LST;
QKeySequence resumeKey;