[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-panel-devel
Subject:    Re: Review Request: moved moonphase code to time dataengine.
From:       Petri =?utf-8?q?Damst=C3=A9n?= <petri.damsten () gmail ! com>
Date:       2009-04-27 8:09:45
Message-ID: 200904271109.50595.petri.damsten () gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/signed)]

[Attachment #4 (multipart/mixed)]


On Monday 27 April 2009 02:31:48 Davide Bettio wrote:
> moved moonphase code to time dataengine from luna plasmoid/moonphase kicker
> applet (as requested by petri). phases.cpp is missing but it comes from the
> plasmoid.

I have made moonrise / moonset calculation to the code. There is also moon 
phase there (phase calculation seems simple after sun and moon values for rise 
/ set are calculated). Currently phase is 0.0 - 1.0 (0.5 meaning full moon). 
How should we continue from here? 

Petri


["time.diff" (text/x-patch)]

Index: timeengine.cpp
===================================================================
--- timeengine.cpp	(revision 959786)
+++ timeengine.cpp	(working copy)
@@ -106,7 +106,7 @@
         // this is relatively cheap - KSTZ::local() is cached
         timezone = KSystemTimeZones::local().name();
     } else {
-        KTimeZone newTz = KSystemTimeZones::zone(tz);
+        KTimeZone newTz = KSystemTimeZones::zone(timezone);
         if (!newTz.isValid()) {
             return false;
         }
@@ -118,7 +118,7 @@
 
     QString trTimezone = i18n(timezone.toUtf8());
     data[I18N_NOOP("Timezone")] = trTimezone;
-    
+
     QStringList tzParts = trTimezone.split("/");
     data[I18N_NOOP("Timezone Continent")] = tzParts.value(0);
     data[I18N_NOOP("Timezone City")] = tzParts.value(1);
@@ -126,7 +126,8 @@
     if (args.count() > 0) {
         static const QString latitude = I18N_NOOP("Latitude");
         static const QString longitude = I18N_NOOP("Longitude");
-        
+        bool sun = false, moon = false;
+
         data[latitude] = args[latitude].toDouble();
         data[longitude] = args[longitude].toDouble();
         QDateTime dt = QDateTime::fromString(args[I18N_NOOP("DateTime")], Qt::ISODate);
@@ -137,10 +138,16 @@
             data[I18N_NOOP("Time")] = dt.time();
         }
         if (args.contains(I18N_NOOP("Solar"))) {
+            sun = true;
+        }
+        if (args.contains(I18N_NOOP("Lunar"))) {
+            moon = true;
+        }
+        if (sun || moon) {
             if (!solarPosition) {
                 solarPosition = new SolarPosition;
             }
-            solarPosition->appendData(data);
+            solarPosition->appendData(data, sun, moon);
         }
         if (args.contains(I18N_NOOP("Moon"))) {
             appendMoonphase(data);
Index: solarposition.cpp
===================================================================
--- solarposition.cpp	(revision 959786)
+++ solarposition.cpp	(working copy)
@@ -20,48 +20,106 @@
 #include <QDateTime>
 
 /*
- *   This class is ported from public domain javascript code:
+ *   Mathematics, ideas, public domain code used for these classes from:
+ *   http://www.stjarnhimlen.se/comp/tutorial.html
+ *   http://www.stjarnhimlen.se/comp/riset.html
  *   http://www.srrb.noaa.gov/highlights/solarrise/azel.html
  *   http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html
- *   Calculation details:
- *   http://www.srrb.noaa.gov/highlights/sunrise/calcdetails.html
+ *   http://bodmas.org/astronomy/riset.html
+ *   moontool.c by John Walker
+ *   Wikipedia
  */
 
-class NOAASolarCalc
+class SolarSystemObject
 {
     public:
-        static void   calc(const QDateTime &dt, double longitude, double latitude,
-                           double zone, double *jd, double *century, double *eqTime,
-                           double *solarDec, double *azimuth, double *zenith);
-        static double radToDeg(double angleRad);
-        static double degToRad(double angleDeg);
-        static double calcJD(double year, double month, double day);
-        static QDateTime calcDateFromJD(double jd, double minutes, double zone);
-        static double calcTimeJulianCent(double jd);
-        static double calcJDFromJulianCent(double t);
-        static double calcGeomMeanLongSun(double t);
-        static double calcGeomMeanAnomalySun(double t);
-        static double calcEccentricityEarthOrbit(double t);
-        static double calcSunEqOfCenter(double t);
-        static double calcSunTrueLong(double t);
-        static double calcSunTrueAnomaly(double t);
-        static double calcSunRadVector(double t);
-        static double calcSunApparentLong(double t);
-        static double calcMeanObliquityOfEcliptic(double t);
-        static double calcObliquityCorrection(double t);
-        static double calcSunRtAscension(double t);
-        static double calcSunDeclination(double t);
-        static double calcEquationOfTime(double t);
-        static void   calcAzimuthAndZenith(QDateTime now, double eqTime, double zone,
-                                           double solarDec, double latitude, double longitude,
-                                           double *zenith, double *azimuth);
-        static double calcElevation(double zenith);
-        static double calcHourAngle(double zenith, double solarDec, double latitude);
-        static void   calcTimeUTC(double zenith, bool rise, double *jd, double *minutes,
-                                  double latitude, double longitude);
-        static double calcSolNoonUTC(double t, double longitude);
+        SolarSystemObject(double latitude, double longitude);
+        virtual ~SolarSystemObject();
+
+        double meanLongitude() { return L; };
+        double meanAnomaly() { return M; };
+        double siderealTime();
+        double altitude() { return m_altitude; };
+        double azimuth() { return m_azimuth; };
+        double calcElevation();
+        QDateTime dateTime() { return m_local; };
+        double lambda() { return m_lambda; };
+        double eclipticLongitude() { return m_eclipticLongitude; };
+
+        virtual void calcForDateTime(const QDateTime& local, int offset);
+        QList< QPair<QDateTime, QDateTime> > timesForAngles(const QList<double>& angles,
+                                                            int offset);
+
+    protected:
+        void calc();
+        virtual bool calcPerturbations(double*, double*, double*) { return false; };
+        virtual void rotate(double*, double*) { };
+        virtual void topocentricCorrection(double*, double*) { };
+
+        inline double rev(double x);
+        inline double asind(double x);
+        inline double sind(double x);
+        inline double cosd(double x);
+        inline double atand(double x);
+        inline double tand(double x);
+        inline double atan2d(double y, double x);
+        void toRectangular(double lo, double la, double r, double *x, double *y, double *z);
+        void toSpherical(double x, double y, double z, double *lo, double *la, double *r);
+        QPair<double, double> zeroPoints(QPointF p1, QPointF p2, QPointF p3);
+
+        double N;
+        double i;
+        double w;
+        double a;
+        double e;
+        double M;
+        double m_obliquity;
+
+        QDateTime m_utc;
+        QDateTime m_local;
+        double m_day;
+        double m_latitude;
+        double m_longitude;
+
+        double L;
+        double rad;
+        double RA;
+        double dec;
+        double HA;
+        double m_altitude;
+        double m_azimuth;
+        double m_eclipticLongitude;
+        double m_lambda;
 };
 
+class Sun : public SolarSystemObject
+{
+    public:
+        Sun(double latitude, double longitude);
+
+        virtual void calcForDateTime(const QDateTime& local, int offset);
+
+    protected:
+        virtual void rotate(double*, double*);
+};
+
+class Moon : public SolarSystemObject
+{
+    public:
+        Moon(double latitude, double longitude, Sun *sun);
+
+        virtual void calcForDateTime(const QDateTime& local, int offset);
+        double phase();
+
+    protected:
+        virtual bool calcPerturbations(double *RA, double *dec, double *r);
+        virtual void rotate(double*, double*);
+        virtual void topocentricCorrection(double*, double*);
+
+    private:
+        Sun *m_sun;
+};
+
 SolarPosition::SolarPosition()
 {
 }
@@ -70,649 +128,352 @@
 {
 }
 
-void SolarPosition::appendData(Plasma::DataEngine::Data &data)
+void SolarPosition::appendData(Plasma::DataEngine::Data &data, bool fillSun, bool fillMoon)
 {
     //QTime time;
     //time.start();
     double longitude = data["Longitude"].toDouble();
     double latitude = data["Latitude"].toDouble();
-    double zone = data["Offset"].toDouble() / -3600.0;
-    QDateTime dt(data["Date"].toDate(), data["Time"].toTime());
-
-    double jd;
-    double century;
-    double eqTime;
-    double solarDec;
-    double azimuth;
-    double zenith;
-    
-    NOAASolarCalc::calc(dt, longitude, latitude, zone, &jd, &century, &eqTime,
-                        &solarDec, &azimuth, &zenith);
-    data["Equation of Time"] = eqTime;
-    data["Solar Declination"] = solarDec;
-    data["Azimuth"] = azimuth;
-    data["Zenith"] = zenith;
-    data["Corrected Elevation"] = NOAASolarCalc::calcElevation(zenith);
-
+    int offset = data["Offset"].toInt();
+    QDateTime local(data["Date"].toDate(), data["Time"].toTime());
     const QString cacheKey = QString("%1|%2|%3")
-            .arg(latitude).arg(longitude).arg(dt.date().toString(Qt::ISODate));
-    if (!m_cache.contains(cacheKey)) {
-        double minutes;
-        double jd2;
-        
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(90.833, true, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Apparent Sunrise"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(90.833, false, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Apparent Sunset"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
+            .arg(latitude).arg(longitude).arg(local.date().toString(Qt::ISODate));
+    Sun sun(latitude, longitude);
 
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(90.0, true, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Sunrise"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(90.0, false, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Sunset"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
+    if (fillSun) {
+        sun.calcForDateTime(local, offset);
+        data["Sun Azimuth"] = sun.azimuth();
+        data["Sun Zenith"] = 90.0 - sun.altitude();
+        data["Sun Corrected Elevation"] = sun.calcElevation();
 
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(96.0, true, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Civil Dawn"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(96.0, false, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Civil Dusk"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
+        if (!m_cache.contains(cacheKey) || !m_cache[cacheKey].contains("Sunrise")) {
+            QList< QPair<QDateTime, QDateTime> > times = sun.timesForAngles(
+                    QList<double>() << -0.833 << -6.0 << -12.0 << -18.0, offset);
 
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(102.0, true, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Nautical Dawn"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(102.0, false, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Nautical Dusk"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
+            m_cache[cacheKey]["Sunrise"] = times[0].first;
+            m_cache[cacheKey]["Sunset"] = times[0].second;
+            m_cache[cacheKey]["Civil Dawn"] = times[1].first;
+            m_cache[cacheKey]["Civil Dusk"] = times[1].second;
+            m_cache[cacheKey]["Nautical Dawn"] = times[2].first;
+            m_cache[cacheKey]["Nautical Dusk"] = times[2].second;
+            m_cache[cacheKey]["Astronomical Dawn"] = times[3].first;
+            m_cache[cacheKey]["Astronomical Dusk"] = times[3].second;
+        }
+    }
+    if (fillMoon) {
+        Moon moon(latitude, longitude, &sun);
+        moon.calcForDateTime(local, offset);
+        data["Moon Azimuth"] = moon.azimuth();
+        data["Moon Zenith"] = 90 - moon.altitude();
+        data["Moon Corrected Elevation"] = moon.calcElevation();
+        data["Moon Phase"] = moon.phase();
 
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(108.0, true, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Astronomical Dawn"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
-        jd2 = jd;
-        NOAASolarCalc::calcTimeUTC(108.0, false, &jd2, &minutes, latitude, longitude);
-        m_cache[cacheKey]["Astronomical Dusk"] = NOAASolarCalc::calcDateFromJD(jd2, minutes, zone);
-
-        century = NOAASolarCalc::calcTimeJulianCent(jd);
-        minutes = NOAASolarCalc::calcSolNoonUTC(century, longitude);
-        dt = NOAASolarCalc::calcDateFromJD(jd, minutes, zone);
-        NOAASolarCalc::calc(dt, longitude, latitude, zone, &jd, &century, &eqTime,
-                            &solarDec, &azimuth, &zenith);
-        m_cache[cacheKey]["Solar Noon"] = dt;
-        m_cache[cacheKey]["Min Zenith"] = zenith;
-        m_cache[cacheKey]["Max Corrected Elevation"] = NOAASolarCalc::calcElevation(zenith);
+        if (!m_cache.contains(cacheKey) || !m_cache[cacheKey].contains("Moonrise")) {
+            QList< QPair<QDateTime, QDateTime> > times = moon.timesForAngles(
+                    QList<double>() << -0.833, offset);
+            m_cache[cacheKey]["Moonrise"] = times[0].first;
+            m_cache[cacheKey]["Moonset"] = times[0].second;
+        }
     }
     data.unite(m_cache[cacheKey]);
     //kDebug() << "Calculation took:" << time.elapsed() << "ms";
     //kDebug() << data;
 }
 
-void NOAASolarCalc::calc(const QDateTime &dt, double longitude, double latitude,
-                         double zone, double *jd, double *century, double *eqTime,
-                         double *solarDec, double *azimuth, double *zenith)
+Sun::Sun(double latitude, double longitude)
+    : SolarSystemObject(latitude, longitude)
 {
-    double timenow = dt.time().hour() + dt.time().minute() / 60.0 +
-                     dt.time().second() / 3600.0 + zone;
-    *jd = NOAASolarCalc::calcJD(dt.date().year(), dt.date().month(), dt.date().day());
-    *century = NOAASolarCalc::calcTimeJulianCent(*jd + timenow / 24.0);
-    //double earthRadVec = NOAASolarCalc::calcSunRadVector(*century);
-    //double alpha = NOAASolarCalc::calcSunRtAscension(*century);
-    *eqTime = NOAASolarCalc::calcEquationOfTime(*century);
-    *solarDec = NOAASolarCalc::calcSunDeclination(*century);
-    NOAASolarCalc::calcAzimuthAndZenith(dt, *eqTime, zone, *solarDec, latitude, longitude,
-                                        zenith, azimuth);
 }
 
-// Convert radian angle to degrees
-double NOAASolarCalc::radToDeg(double angleRad)
+void Sun::calcForDateTime(const QDateTime& local, int offset)
 {
-    return (180.0 * angleRad / M_PI);
+    SolarSystemObject::calcForDateTime(local, offset);
+
+    N = 0.0;
+    i = 0.0;
+    w = rev(282.9404 + 4.70935E-5 * m_day);
+    a = 1.0;
+    e = rev(0.016709 - 1.151E-9 * m_day);
+    M = rev(356.0470 + 0.9856002585 * m_day);
+
+    calc();
 }
 
-// Convert degree angle to radians
-double NOAASolarCalc::degToRad(double angleDeg)
+void Sun::rotate(double* y, double* z)
 {
-    return (M_PI * angleDeg / 180.0);
+    *y *= cosd(m_obliquity);
+    *z *= sind(m_obliquity);
 }
 
-//***********************************************************************/
-//* Name:    calcJD                                                     */
-//* Type:    Function                                                   */
-//* Purpose: Julian day from calendar day                               */
-//* Arguments:                                                          */
-//*   year : 4 digit year                                               */
-//*   month: January = 1                                                */
-//*   day  : 1 - 31                                                     */
-//* Return value:                                                       */
-//*   The Julian day corresponding to the date                          */
-//* Note:                                                               */
-//*   Number is returned for start of day.  Fractional days should be   */
-//*   added later.                                                      */
-//***********************************************************************/
-double NOAASolarCalc::calcJD(double year, double month, double day)
+Moon::Moon(double latitude, double longitude, Sun *sun)
+    : SolarSystemObject(latitude, longitude)
+    , m_sun(sun)
 {
-    if (month <= 2) {
-        year -= 1;
-        month += 12;
-    }
-    double A = floor(year / 100.0);
-    double B = 2 - A + floor(A / 4.0);
-
-    return floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1))
-           + day + B - 1524.5;
 }
 
-//***********************************************************************/
-//* Name:    calcDateFromJD                                             */
-//* Type:    Function                                                   */
-//* Purpose: Calendar date from Julian Day                              */
-//* Arguments:                                                          */
-//*   jd   : Julian Day                                                 */
-//* Return value:                                                       */
-//*   QDateTime                                                         */
-//* Note:                                                               */
-//***********************************************************************/
-QDateTime NOAASolarCalc::calcDateFromJD(double jd, double minutes, double zone)
+void Moon::calcForDateTime(const QDateTime& local, int offset)
 {
-    QDateTime result;
-    
-    minutes -= 60 * zone;
-    if (minutes > 1440.0) {
-        minutes -= 1440.0;
-        jd += 1.0;
+    if (m_sun->dateTime() != local) {
+        m_sun->calcForDateTime(local, offset);
     }
-    if (minutes < 0.0) {
-        minutes += 1440.0;
-        jd -= 1.0;
-    }
-    double floatHour = minutes / 60.0;
-    double hour = floor(floatHour);
-    double floatMinute = 60.0 * (floatHour - floor(floatHour));
-    double minute = floor(floatMinute);
-    double floatSec = 60.0 * (floatMinute - floor(floatMinute));
-    double second = floor(floatSec + 0.5);
-    result.setTime(QTime(hour, minute, second));
 
-    double z = floor(jd + 0.5);
-    double f = (jd + 0.5) - z;
-    double A;
-    if (z < 2299161.0) {
-        A = z;
-    } else {
-        double alpha = floor((z - 1867216.25) / 36524.25);
-        A = z + 1.0 + alpha - floor(alpha / 4.0);
-    }
-    double B = A + 1524.0;
-    double C = floor((B - 122.1) / 365.25);
-    double D = floor(365.25 * C);
-    double E = floor((B - D) / 30.6001);
-    double day = B - D - floor(30.6001 * E) + f;
-    double month = (E < 14.0) ? E - 1 : E - 13.0;
-    double year = (month > 2.0) ? C - 4716.0 : C - 4715.0;
-    result.setDate(QDate(year, month, day));
+    SolarSystemObject::calcForDateTime(local, offset);
 
-    return result;
-}
+    N = rev(125.1228 - 0.0529538083 * m_day);
+    i = 5.1454;
+    w = rev(318.0634 + 0.1643573223 * m_day);
+    a = 60.2666;
+    e = 0.054900;
+    M = rev(115.3654 + 13.0649929509 * m_day);
 
-//***********************************************************************/
-//* Name:    calcTimeJulianCent                                         */
-//* Type:    Function                                                   */
-//* Purpose: convert Julian Day to centuries since J2000.0.             */
-//* Arguments:                                                          */
-//*   jd : the Julian Day to convert                                    */
-//* Return value:                                                       */
-//*   the T value corresponding to the Julian Day                       */
-//***********************************************************************/
-double NOAASolarCalc::calcTimeJulianCent(double jd)
-{
-    return (jd - 2451545.0) / 36525.0;
+    calc();
 }
 
-//***********************************************************************/
-//* Name:    calcJDFromJulianCent                                       */
-//* Type:    Function                                                   */
-//* Purpose: convert centuries since J2000.0 to Julian Day.             */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   the Julian Day corresponding to the t value                       */
-//***********************************************************************/
-double NOAASolarCalc::calcJDFromJulianCent(double t)
+bool Moon::calcPerturbations(double *lo, double *la, double *r)
 {
-    return t * 36525.0 + 2451545.0;
+    double Ms = m_sun->meanAnomaly();
+    double D = L - m_sun->meanLongitude();
+    double F = L - N;
+
+    *lo +=  -1.274 * sind(M - 2 * D)
+            +0.658 * sind(2 * D)
+            -0.186 * sind(Ms)
+            -0.059 * sind(2 * M - 2 * D)
+            -0.057 * sind(M - 2 * D + Ms)
+            +0.053 * sind(M + 2 * D)
+            +0.046 * sind(2 * D - Ms)
+            +0.041 * sind(M - Ms)
+            -0.035 * sind(D)
+            -0.031 * sind(M + Ms)
+            -0.015 * sind(2 * F - 2 * D)
+            +0.011 * sind(M - 4 * D);
+    *la +=  -0.173 * sind(F - 2 * D)
+            -0.055 * sind(M - F - 2 * D)
+            -0.046 * sind(M + F - 2 * D)
+            +0.033 * sind(F + 2 * D)
+            +0.017 * sind(2 * M + F);
+    *r +=   -0.58 * cosd(M - 2 * D)
+            -0.46 * cosd(2 * D);
+    return true;
 }
 
-//***********************************************************************/
-//* Name:    calcGeomMeanLongSun                                        */
-//* Type:    Function                                                   */
-//* Purpose: calculate the Geometric Mean Longitude of the Sun          */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   the Geometric Mean Longitude of the Solar in degrees              */
-//***********************************************************************/
-double NOAASolarCalc::calcGeomMeanLongSun(double t)
+void Moon::topocentricCorrection(double* RA, double* dec)
 {
-    double L0 = 280.46646 + t * (36000.76983 + 0.0003032 * t);
-    while (L0 > 360.0) {
-        L0 -= 360.0;
-    }
-    while(L0 < 0.0) {
-        L0 += 360.0;
-    }
-    return L0;      // in degrees
+    double HA = rev(siderealTime() - *RA);
+    double gclat = m_latitude - 0.1924 * sind(2 * m_latitude);
+    double rho = 0.99833 + 0.00167 * cosd(2 * m_latitude);
+    double mpar = asind(1 / rad);
+    double g = atand(tand(gclat) / cosd(HA));
+
+    *RA -= mpar * rho * cosd(gclat) * sind(HA) / cosd(*dec);
+    *dec -= mpar * rho * sind(gclat) * sind(g - *dec) / sind(g);
 }
 
-//***********************************************************************/
-//* Name:    calcGeomAnomalySun                                         */
-//* Type:    Function                                                   */
-//* Purpose: calculate the Geometric Mean Anomaly of the Sun            */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   the Geometric Mean Anomaly of the Solar in degrees                */
-//***********************************************************************/
-double NOAASolarCalc::calcGeomMeanAnomalySun(double t)
+double Moon::phase()
 {
-    return 357.52911 + t * (35999.05029 - 0.0001537 * t); // in degrees
+   return rev(m_eclipticLongitude - m_sun->lambda()) / 360.0;
 }
 
-//***********************************************************************/
-//* Name:    calcEccentricityEarthOrbit                                 */
-//* Type:    Function                                                   */
-//* Purpose: calculate the eccentricity of earth's orbit                */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   the unitless eccentricity                                         */
-//***********************************************************************/
-double NOAASolarCalc::calcEccentricityEarthOrbit(double t)
+void Moon::rotate(double* y, double* z)
 {
-    return 0.016708634 - t * (0.000042037 + 0.0000001267 * t); // unitless
+    double t = *y;
+    *y = t * cosd(m_obliquity) - *z * sind(m_obliquity);
+    *z = t * sind(m_obliquity) + *z * cosd(m_obliquity);
 }
 
-//***********************************************************************/
-//* Name:    calcSunEqOfCenter                                          */
-//* Type:    Function                                                   */
-//* Purpose: calculate the equation of center for the sun               */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   in degrees                                                        */
-//***********************************************************************/
-double NOAASolarCalc::calcSunEqOfCenter(double t)
+void SolarSystemObject::calc()
 {
-    double m = calcGeomMeanAnomalySun(t);
+    double x, y, z;
+    double la, r;
 
-    double mrad = degToRad(m);
-    double sinm = sin(mrad);
-    double sin2m = sin(mrad+mrad);
-    double sin3m = sin(mrad+mrad+mrad);
+    L = rev(N + w + M);
+    double E0 = 720.0;
+    double E = M + (180.0 / M_PI) * e * sind(M) * (1.0 + e * cosd(M));
+    for (int j = 0; fabs(E0 - E) > 0.005 && j < 10; ++j) {
+        E0 = E;
+        E = E0 - (E0 - (180.0 / M_PI) * e * sind(E0) - M) / (1 - e * cosd(E0));
+    }
+    x = a * (cosd(E) - e);
+    y = a * sind(E) * sqrt(1.0 - e * e);
+    r = sqrt(x * x + y * y);
+    double v = rev(atan2d(y, x));
+    m_lambda = rev(v + w);
+    x = r * (cosd(N) * cosd(m_lambda) - sind(N) * sind(m_lambda) * cosd(i));
+    y = r * (sind(N) * cosd(m_lambda) + cosd(N) * sind(m_lambda) * cosd(i));
+    z = r * sind(m_lambda);
+    if (!qFuzzyCompare(i, 0.0)) {
+        z *= sind(i);
+    }
+    toSpherical(x, y, z, &m_eclipticLongitude, &la, &r);
+    if (calcPerturbations(&m_eclipticLongitude, &la, &r)) {
+        toRectangular(m_eclipticLongitude, la, r, &x, &y, &z);
+    }
+    rotate(&y, &z);
+    toSpherical(x, y, z, &RA, &dec, &rad);
+    topocentricCorrection(&RA, &dec);
 
-    // in degrees
-    return sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) +
-           sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
+    HA = rev(siderealTime() - RA);
+    x = cosd(HA) * cosd(dec) * sind(m_latitude) - sind(dec) * cosd(m_latitude);
+    y = sind(HA) * cosd(dec);
+    z = cosd(HA) * cosd(dec) * cosd(m_latitude) + sind(dec) * sind(m_latitude);
+    m_azimuth = atan2d(y, x) + 180.0;
+    m_altitude = asind(z);
 }
 
-//***********************************************************************/
-//* Name:    calcSunTrueLong                                            */
-//* Type:    Function                                                   */
-//* Purpose: calculate the true longitude of the sun                    */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   solar's true longitude in degrees                                 */
-//***********************************************************************/
-double NOAASolarCalc::calcSunTrueLong(double t)
+double SolarSystemObject::siderealTime()
 {
-    double l0 = calcGeomMeanLongSun(t);
-    double c = calcSunEqOfCenter(t);
-
-    return l0 + c; // in degrees
+    double UT = m_utc.time().hour() + m_utc.time().minute() / 60.0 +
+                m_utc.time().second() / 3600.0;
+    double GMST0 = rev(282.9404 + 4.70935E-5 * m_day + 356.0470 + 0.9856002585 * m_day + 180.0);
+    return GMST0 + UT * 15.0 + m_longitude;
 }
 
-//***********************************************************************/
-//* Name:    calcSunTrueAnomaly                                         */
-//* Type:    Function                                                   */
-//* Purpose: calculate the true anamoly of the sun                      */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   solar's true anamoly in degrees                                   */
-//***********************************************************************/
-double NOAASolarCalc::calcSunTrueAnomaly(double t)
+void SolarSystemObject::calcForDateTime(const QDateTime& local, int offset)
 {
-    double m = calcGeomMeanAnomalySun(t);
-    double c = calcSunEqOfCenter(t);
-
-    return m + c; // in degrees
+    m_local = local;
+    m_utc = local.addSecs(-offset);
+    m_day = 367 * m_utc.date().year() - (7 * (m_utc.date().year() +
+            ((m_utc.date().month() + 9) / 12))) / 4 +
+            (275 * m_utc.date().month()) / 9 + m_utc.date().day() - 730530;
+    m_day += m_utc.time().hour() / 24.0 + m_utc.time().minute() / (24.0 * 60.0) +
+             m_utc.time().second() / (24.0 * 60.0 * 60.0);
+    m_obliquity = 23.4393 - 3.563E-7 * m_day;
 }
 
-//***********************************************************************/
-//* Name:    calcSunRadVector                                           */
-//* Type:    Function                                                   */
-//* Purpose: calculate the distance to the sun in AU                    */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   solar radius vector in AUs                                        */
-//***********************************************************************/
-double NOAASolarCalc::calcSunRadVector(double t)
+SolarSystemObject::SolarSystemObject(double latitude, double longitude)
+    : m_latitude(latitude)
+    , m_longitude(-longitude)
 {
-    double v = calcSunTrueAnomaly(t);
-    double e = calcEccentricityEarthOrbit(t);
-
-    // in AUs
-    return (1.000001018 * (1 - e * e)) / (1 + e * cos(degToRad(v)));
 }
 
-//***********************************************************************/
-//* Name:    calcSunApparentLong                                        */
-//* Type:    Function                                                   */
-//* Purpose: calculate the apparent longitude of the sun                */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   solar's apparent longitude in degrees                             */
-//***********************************************************************/
-double NOAASolarCalc::calcSunApparentLong(double t)
+SolarSystemObject::~SolarSystemObject()
 {
-    double o = calcSunTrueLong(t);
-
-    double omega = 125.04 - 1934.136 * t;
-    // in degrees
-    return o - 0.00569 - 0.00478 * sin(degToRad(omega));
 }
 
-//***********************************************************************/
-//* Name:    calcMeanObliquityOfEcliptic                                */
-//* Type:    Function                                                   */
-//* Purpose: calculate the mean obliquity of the ecliptic               */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   mean obliquity in degrees                                         */
-//***********************************************************************/
-double NOAASolarCalc::calcMeanObliquityOfEcliptic(double t)
+double SolarSystemObject::rev(double x)
 {
-    double seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * (0.001813)));
-    return 23.0 + (26.0 + (seconds/60.0)) / 60.0; // in degrees
+    return  x - floor(x / 360.0) * 360.0;
 }
 
-//***********************************************************************/
-//* Name:    calcObliquityCorrection                                    */
-//* Type:    Function                                                   */
-//* Purpose: calculate the corrected obliquity of the ecliptic          */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   corrected obliquity in degrees                                    */
-//***********************************************************************/
-double NOAASolarCalc::calcObliquityCorrection(double t)
+double SolarSystemObject::asind(double x)
 {
-    double e0 = calcMeanObliquityOfEcliptic(t);
-
-    double omega = 125.04 - 1934.136 * t;
-    return e0 + 0.00256 * cos(degToRad(omega)); // in degrees
+    return asin(x) * 180.0 / M_PI;
 }
 
-//***********************************************************************/
-//* Name:    calcSunRtAscension                                         */
-//* Type:    Function                                                   */
-//* Purpose: calculate the right ascension of the sun                   */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   solar's right ascension in degrees                                */
-//***********************************************************************/
-double NOAASolarCalc::calcSunRtAscension(double t)
+double SolarSystemObject::sind(double x)
 {
-    double e = calcObliquityCorrection(t);
-    double lambda = calcSunApparentLong(t);
-
-    double tananum = (cos(degToRad(e)) * sin(degToRad(lambda)));
-    double tanadenom = (cos(degToRad(lambda)));
-    return radToDeg(atan2(tananum, tanadenom)); // in degrees
+    return sin(x * M_PI / 180.0);
 }
 
-//***********************************************************************/
-//* Name:    calcSunDeclination                                         */
-//* Type:    Function                                                   */
-//* Purpose: calculate the declination of the sun                       */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   solar's declination in degrees                                    */
-//***********************************************************************/
-double NOAASolarCalc::calcSunDeclination(double t)
+double SolarSystemObject::cosd(double x)
 {
-    double e = calcObliquityCorrection(t);
-    double lambda = calcSunApparentLong(t);
-
-    double sint = sin(degToRad(e)) * sin(degToRad(lambda));
-    return radToDeg(asin(sint)); // in degrees
+    return cos(x * M_PI / 180.0);
 }
 
-//***********************************************************************/
-//* Name:    calcHourAngle                                              */
-//* Type:    Function                                                   */
-//* Purpose: calculate the hour angle of the sun at sunset for the      */
-//*          latitude                                                   */
-//* Arguments:                                                          */
-//*   zenith : zenith angle in degrees                                  */
-//*   lat : latitude of observer in degrees                             */
-//*   solarDec : declination angle of sun in degrees                    */
-//* Return value:                                                       */
-//*   hour angle of sunset in radians                                   */
-//***********************************************************************/
-double NOAASolarCalc::calcHourAngle(double zenith, double solarDec, double latitude)
+double SolarSystemObject::tand(double x)
 {
-    double latRad = degToRad(latitude);
-    double sdRad  = degToRad(solarDec);
-
-    //double HAarg = (cos(degToRad(90.833)) / (cos(latRad) * cos(sdRad)) - tan(latRad) * tan(sdRad));
-
-    double HA = (acos(cos(degToRad(zenith)) / (cos(latRad) * cos(sdRad)) - tan(latRad) * tan(sdRad)));
-
-    return HA;     // in radians
+    return tan(x * M_PI / 180.0);
 }
 
-//***********************************************************************/
-//* Name:    calcEquationOfTime                                         */
-//* Type:    Function                                                   */
-//* Purpose: calculate the difference between true solar time and mean  */
-//*     solar time                                                      */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//* Return value:                                                       */
-//*   equation of time in minutes of time                               */
-//***********************************************************************/
-double NOAASolarCalc::calcEquationOfTime(double t)
+double SolarSystemObject::atan2d(double y, double x)
 {
-    double epsilon = calcObliquityCorrection(t);
-    double l0 = calcGeomMeanLongSun(t);
-    double e = calcEccentricityEarthOrbit(t);
-    double m = calcGeomMeanAnomalySun(t);
+    return atan2(y, x) * 180.0 / M_PI;
+}
 
-    double y = tan(degToRad(epsilon) / 2.0);
-    y *= y;
-
-    double sin2l0 = sin(2.0 * degToRad(l0));
-    double sinm   = sin(degToRad(m));
-    double cos2l0 = cos(2.0 * degToRad(l0));
-    double sin4l0 = sin(4.0 * degToRad(l0));
-    double sin2m  = sin(2.0 * degToRad(m));
-
-    double Etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y * sinm * cos2l0
-            - 0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m;
-
-    return radToDeg(Etime) * 4.0; // in minutes of time
+double SolarSystemObject::atand(double x)
+{
+    return atan(x) * 180.0 / M_PI;
 }
 
-//***********************************************************************/
-//* Name:    calcSolNoonUTC                                             */
-//* Type:    Function                                                   */
-//* Purpose: calculate the Universal Coordinated Time (UTC) of solar    */
-//*     noon for the given day at the given location on earth           */
-//* Arguments:                                                          */
-//*   t : number of Julian centuries since J2000.0                      */
-//*   longitude : longitude of observer in degrees                      */
-//* Return value:                                                       */
-//*   time in minutes from zero Z                                       */
-//***********************************************************************/
-double NOAASolarCalc::calcSolNoonUTC(double t, double longitude)
+void SolarSystemObject::toRectangular(double lo, double la, double r, double *x, double *y, double *z)
 {
-    // First pass uses approximate solar noon to calculate eqtime
-    double tnoon = calcTimeJulianCent(calcJDFromJulianCent(t) + longitude / 360.0);
-    double eqTime = calcEquationOfTime(tnoon);
-    double solNoonUTC = 720 + (longitude * 4) - eqTime; // min
+    *x = r * cosd(lo) * cosd(la);
+    *y = r * sind(lo) * cosd(la);
+    *z = r * sind(la);
+}
 
-    double newt = calcTimeJulianCent(calcJDFromJulianCent(t) -0.5 + solNoonUTC / 1440.0);
-
-    eqTime = calcEquationOfTime(newt);
-    // double solarNoonDec = calcSunDeclination(newt);
-    solNoonUTC = 720 + (longitude * 4) - eqTime; // min
-    return solNoonUTC;
+void SolarSystemObject::toSpherical(double x, double y, double z, double *lo, double *la, double *r)
+{
+    *r = sqrt(x * x + y * y + z * z);
+    *la = asind(z / *r);
+    *lo = rev(atan2d(y, x));
 }
 
-//***********************************************************************/
-//* Name:    calcTimeUTC                                                */
-//* Type:    Function                                                   */
-//* Purpose: calculate the Universal Coordinated Time (UTC) of sunset   */
-//*         for the given day at the given location on earth            */
-//* Arguments:                                                          */
-//*   zenith : zenith in degrees                                        */
-//*   rise : rise or set                                                */
-//*   JD  : julian day                                                  */
-//*   latitude : latitude of observer in degrees                        */
-//*   longitude : longitude of observer in degrees                      */
-//* Return value:                                                       */
-//*   time in minutes from zero Z                                       */
-//***********************************************************************/
-void NOAASolarCalc::calcTimeUTC(double zenith, bool rise, double *jd, double *minutes,
-                                double latitude, double longitude)
+QPair<double, double> SolarSystemObject::zeroPoints(QPointF p1, QPointF p2, QPointF p3)
 {
-    forever {
-        double t = calcTimeJulianCent(*jd);
-        double m = (rise) ? 1.0 : -1.0;
+    double a = ((p2.y() - p1.y()) * (p1.x() - p3.x()) + (p3.y() - p1.y()) * (p2.x() - p1.x())) /
+               ((p1.x() - p3.x()) * (p2.x() * p2.x() - p1.x() * p1.x()) + (p2.x() - p1.x()) *
+                (p3.x() * p3.x() - p1.x() * p1.x()));
+    double b = ((p2.y() - p1.y()) - a * (p2.x() * p2.x() - p1.x() * p1.x())) / (p2.x() - p1.x());
+    double c = p1.y() - a * p1.x() * p1.x() - b * p1.x();
+    double discriminant = b * b - 4.0 * a * c;
+    double z1 = -1.0, z2 = -1.0;
 
-        // *** Find the time of solar noon at the location, and use
-        //     that declination. This is better than start of the
-        //     Julian day
-
-        double noonmin = calcSolNoonUTC(t, longitude);
-        double tnoon = calcTimeJulianCent(*jd + noonmin / 1440.0);
-
-        // First calculates sunrise and approx length of day
-
-        double eqTime = calcEquationOfTime(tnoon);
-        double solarDec = calcSunDeclination(tnoon);
-        double hourAngle = m * calcHourAngle(zenith, solarDec, latitude);
-
-        double delta = longitude - radToDeg(hourAngle);
-        double timeDiff = 4 * delta;
-        *minutes = 720 + timeDiff - eqTime;
-
-        // first pass used to include fractional day in gamma calc
-
-        double newt = calcTimeJulianCent(calcJDFromJulianCent(t) + *minutes / 1440.0);
-        eqTime = calcEquationOfTime(newt);
-        solarDec = calcSunDeclination(newt);
-        hourAngle = m * calcHourAngle(zenith, solarDec, latitude);
-
-        delta = longitude - radToDeg(hourAngle);
-        timeDiff = 4 * delta;
-        *minutes = 720 + timeDiff - eqTime; // in minutes
-        if (isnan(*minutes)) {
-            *jd -= m;
-        } else {
-            return;
-        }
+    if (discriminant >= 0.0) {
+        z1 = (-b + sqrt(discriminant)) / (2 * a);
+        z2 = (-b - sqrt(discriminant)) / (2 * a);
     }
+    return QPair<double, double>(z1, z2);
 }
 
-void NOAASolarCalc::calcAzimuthAndZenith(QDateTime dt, double eqTime, double zone,
-                                         double solarDec, double latitude, double longitude,
-                                         double *zenith, double *azimuth)
+QList< QPair<QDateTime, QDateTime> > SolarSystemObject::timesForAngles(const QList<double>& angles,
+                                                                       int offset)
 {
-    double solarTimeFix = eqTime - 4.0 * longitude + 60.0 * zone;
-    double trueSolarTime = dt.time().hour() * 60.0 + dt.time().minute() +
-                           dt.time().second() / 60.0 + solarTimeFix;
-    // in minutes
-    while (trueSolarTime > 1440) {
-        trueSolarTime -= 1440;
+    QList<double> altitudes;
+    QDate d = m_local.date();
+    QDateTime local(d, QTime(0, 0));
+    for (int j = 0; j <= 24; ++j) {
+        calcForDateTime(local, offset);
+        altitudes.append(altitude());
+        local = local.addSecs(60 * 60);
     }
-    //double hourAngle = calcHourAngle(timenow, m_longitude, eqTime);
-    double hourAngle = trueSolarTime / 4.0 - 180.0;
-    // Thanks to Louis Schwarzmayr for finding our error,
-    // and providing the following 4 lines to fix it:
-    if (hourAngle < -180.0) {
-        hourAngle += 360.0;
-    }
-
-    double haRad = degToRad(hourAngle);
-
-    double csz = sin(degToRad(latitude)) * sin(degToRad(solarDec)) +
-                 cos(degToRad(latitude)) * cos(degToRad(solarDec)) * cos(haRad);
-    if (csz > 1.0) {
-        csz = 1.0;
-    } else if (csz < -1.0) {
-        csz = -1.0;
-    }
-    *zenith = radToDeg(acos(csz));
-    double azDenom = (cos(degToRad(latitude)) * sin(degToRad(*zenith)));
-
-    if (fabs(azDenom) > 0.001) {
-        double azRad = ((sin(degToRad(latitude)) * cos(degToRad(*zenith))) -
-                         sin(degToRad(solarDec))) / azDenom;
-        if (fabs(azRad) > 1.0) {
-            if (azRad < 0) {
-                azRad = -1.0;
-            } else {
-                azRad = 1.0;
+    QList< QPair<QDateTime, QDateTime> > result;
+    QTime rise, set;
+    foreach (double angle, angles) {
+        for (int j = 3; j <= 24; j += 2) {
+            QPointF p1((j - 2) * 60 * 60, altitudes[j - 2] - angle);
+            QPointF p2((j - 1) * 60 * 60, altitudes[j - 1] - angle);
+            QPointF p3(j * 60 * 60, altitudes[j] - angle);
+            QPair<double, double> z = zeroPoints(p1, p2, p3);
+            if (z.first > p1.x() && z.first < p3.x()) {
+                if (p1.y() < 0.0) {
+                    rise = QTime(0, 0).addSecs(z.first);
+                } else {
+                    set = QTime(0, 0).addSecs(z.first);
+                }
             }
+            if (z.second > p1.x() && z.second < p3.x()) {
+                if (p3.y() < 0.0) {
+                    set = QTime(0, 0).addSecs(z.second);
+                } else {
+                    rise = QTime(0, 0).addSecs(z.second);
+                }
+            }
         }
-
-        *azimuth = 180.0 - radToDeg(acos(azRad));
-
-        if (hourAngle > 0.0) {
-            *azimuth = -*azimuth;
-        }
-    } else {
-        if (latitude > 0.0) {
-            *azimuth = 180.0;
-        } else {
-            *azimuth = 0.0;
-        }
+        result.append(QPair<QDateTime, QDateTime>(QDateTime(d, rise), QDateTime(d, set)));
     }
-    if (*azimuth < 0.0) {
-        *azimuth += 360.0;
-    }
+    return result;
 }
 
-double NOAASolarCalc::calcElevation(double zenith)
+double SolarSystemObject::calcElevation()
 {
-    double exoatmElevation = 90.0 - zenith;
     double refractionCorrection;
-    if (exoatmElevation > 85.0) {
+
+    if (m_altitude > 85.0) {
         refractionCorrection = 0.0;
     } else {
-        double te = tan(degToRad(exoatmElevation));
-        if (exoatmElevation > 5.0) {
+        double te = tand(m_altitude);
+        if (m_altitude > 5.0) {
             refractionCorrection = 58.1 / te - 0.07 / (te * te * te) +
                                    0.000086 / (te * te * te * te * te);
-        } else if (exoatmElevation > -0.575) {
-            refractionCorrection = 1735.0 + exoatmElevation *
-                (-518.2 + exoatmElevation * (103.4 + exoatmElevation *
-                (-12.79 + exoatmElevation * 0.711) ) );
+        } else if (m_altitude > -0.575) {
+            refractionCorrection = 1735.0 + m_altitude *
+                (-518.2 + m_altitude * (103.4 + m_altitude *
+                (-12.79 + m_altitude * 0.711) ) );
         } else {
             refractionCorrection = -20.774 / te;
         }
         refractionCorrection = refractionCorrection / 3600.0;
     }
-    double solarZen = zenith - refractionCorrection;
-    return 90.0 - solarZen;
+    return m_altitude + refractionCorrection;
 }
-
Index: solarposition.h
===================================================================
--- solarposition.h	(revision 959786)
+++ solarposition.h	(working copy)
@@ -26,7 +26,7 @@
         SolarPosition();
         virtual ~SolarPosition();
 
-        void appendData(Plasma::DataEngine::Data &data);
+        void appendData(Plasma::DataEngine::Data &data, bool sun, bool moon);
 
     private:
         QHash<QString, Plasma::DataEngine::Data> m_cache;

["signature.asc" (application/pgp-signature)]

_______________________________________________
Plasma-devel mailing list
Plasma-devel@kde.org
https://mail.kde.org/mailman/listinfo/plasma-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic