[gnome-settings-daemon] color: Add functionality required for the natural light feature



commit 931e0ccdf70f6bfa68aa3423cf09b2bd1752e89d
Author: Richard Hughes <richard hughsie com>
Date:   Thu Feb 2 13:45:25 2017 +0000

    color: Add functionality required for the natural light feature
    
    This includes a function that gets the sunrise and sunset times as fractional
    hours, a function for converting a GDateTime to fractional hours and a function
    that tests if a fractional hour is inside a fractional time period.
    
    Additionally, this patch adds tests for each function.
    
    See https://bugzilla.gnome.org/show_bug.cgi?id=778039 for more details.

 plugins/color/Makefile.am                |    4 +
 plugins/color/gcm-self-test.c            |   43 ++++++++++
 plugins/color/gsd-natural-light-common.c |  126 ++++++++++++++++++++++++++++++
 plugins/color/gsd-natural-light-common.h |   39 +++++++++
 4 files changed, 212 insertions(+), 0 deletions(-)
---
diff --git a/plugins/color/Makefile.am b/plugins/color/Makefile.am
index 8fc729a..8ec20e1 100644
--- a/plugins/color/Makefile.am
+++ b/plugins/color/Makefile.am
@@ -15,6 +15,8 @@ gcm_self_test_CFLAGS =                        \
 gcm_self_test_SOURCES =                        \
        gcm-edid.c                      \
        gcm-edid.h                      \
+       gsd-natural-light-common.c      \
+       gsd-natural-light-common.h      \
        gcm-self-test.c
 
 gcm_self_test_LDADD =                  \
@@ -37,6 +39,8 @@ gsd_color_SOURCES =                   \
        gsd-color-profiles.h            \
        gsd-color-state.c               \
        gsd-color-state.h               \
+       gsd-natural-light-common.c      \
+       gsd-natural-light-common.h      \
        $(NULL)
 
 gsd_color_CFLAGS =                     \
diff --git a/plugins/color/gcm-self-test.c b/plugins/color/gcm-self-test.c
index 5edda78..08241ce 100644
--- a/plugins/color/gcm-self-test.c
+++ b/plugins/color/gcm-self-test.c
@@ -26,6 +26,7 @@
 #include <gtk/gtk.h>
 
 #include "gcm-edid.h"
+#include "gsd-natural-light-common.h"
 
 static void
 gcm_test_edid_func (void)
@@ -84,6 +85,46 @@ gcm_test_edid_func (void)
         g_object_unref (edid);
 }
 
+static void
+gcm_test_sunset_sunrise (void)
+{
+        gdouble sunrise;
+        gdouble sunrise_actual = 7.6;
+        gdouble sunset;
+        gdouble sunset_actual = 16.8;
+        g_autoptr(GDateTime) dt = g_date_time_new_utc (2007, 2, 1, 0, 0, 0);
+
+        /* get for London, today */
+        gsd_natural_light_get_sunrise_sunset (dt, 51.5, -0.1278, &sunrise, &sunset);
+        g_assert_cmpfloat (sunrise, <, sunrise_actual + 0.1);
+        g_assert_cmpfloat (sunrise, >, sunrise_actual - 0.1);
+        g_assert_cmpfloat (sunset, <, sunset_actual + 0.1);
+        g_assert_cmpfloat (sunset, >, sunset_actual - 0.1);
+}
+
+static void
+gcm_test_frac_day (void)
+{
+        g_autoptr(GDateTime) dt = g_date_time_new_utc (2007, 2, 1, 12, 59, 59);
+        gdouble fd;
+        gdouble fd_actual = 12.99;
+
+        /* test for 12:59:59 */
+        fd = gsd_natural_light_frac_day_from_dt (dt);
+        g_assert_cmpfloat (fd, >, fd_actual - 0.01);
+        g_assert_cmpfloat (fd, <, fd_actual + 0.01);
+
+        /* test same day */
+        g_assert (gsd_natural_light_frac_day_is_between (12, 6, 20));
+        g_assert (!gsd_natural_light_frac_day_is_between (5, 6, 20));
+        g_assert (gsd_natural_light_frac_day_is_between (12, 0, 24));
+        g_assert (gsd_natural_light_frac_day_is_between (12, -1, 25));
+
+        /* test rollover to next day */
+        g_assert (gsd_natural_light_frac_day_is_between (23, 20, 6));
+        g_assert (!gsd_natural_light_frac_day_is_between (12, 20, 6));
+}
+
 int
 main (int argc, char **argv)
 {
@@ -91,6 +132,8 @@ main (int argc, char **argv)
         g_test_init (&argc, &argv, NULL);
 
         g_test_add_func ("/color/edid", gcm_test_edid_func);
+        g_test_add_func ("/color/sunset-sunrise", gcm_test_sunset_sunrise);
+        g_test_add_func ("/color/fractional-day", gcm_test_frac_day);
 
         return g_test_run ();
 }
diff --git a/plugins/color/gsd-natural-light-common.c b/plugins/color/gsd-natural-light-common.c
new file mode 100644
index 0000000..10b693d
--- /dev/null
+++ b/plugins/color/gsd-natural-light-common.c
@@ -0,0 +1,126 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Richard Hughes <richard hughsie com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <math.h>
+
+#include "gsd-natural-light-common.h"
+
+static gdouble
+deg2rad (gdouble degrees)
+{
+        return (M_PI * degrees) / 180.f;
+}
+
+static gdouble
+rad2deg (gdouble radians)
+{
+        return radians * (180.f / M_PI);
+}
+
+/*
+ * Formulas taken from https://www.esrl.noaa.gov/gmd/grad/solcalc/calcdetails.html
+ *
+ * The returned values are fractional hours, so 6am would be 6.0 and 4:30pm
+ * would be 16.5.
+ *
+ * The values returned by this function might not make sense for locations near
+ * the polar regions. For example, in the north of Lapland there might not be
+ * a sunrise at all.
+ */
+gboolean
+gsd_natural_light_get_sunrise_sunset (GDateTime *dt,
+                                      gdouble pos_lat, gdouble pos_long,
+                                      gdouble *sunrise, gdouble *sunset)
+{
+        g_autoptr(GDateTime) dt_zero = g_date_time_new_utc (1900, 1, 1, 0, 0, 0);
+        GTimeSpan ts = g_date_time_difference (dt, dt_zero);
+
+        g_return_val_if_fail (pos_lat < 180.f && pos_lat > -180.f, FALSE);
+        g_return_val_if_fail (pos_long < 180.f && pos_long > -180.f, FALSE);
+
+        gdouble tz_offset =  g_date_time_get_utc_offset (dt) / G_USEC_PER_SEC / 60 / 60; // B5
+        gdouble date_as_number = ts / G_USEC_PER_SEC / 24 / 60 / 60 + 2;  // B7
+        gdouble time_past_local_midnight = 0;  // E2, unused in this calculation
+        gdouble julian_day = date_as_number + 2415018.5 +
+                        time_past_local_midnight - tz_offset / 24;
+        gdouble julian_century = (julian_day - 2451545) / 36525;
+        gdouble geom_mean_long_sun = fmod (280.46646 + julian_century *
+                        (36000.76983 + julian_century * 0.0003032), 360); // I2
+        gdouble geom_mean_anom_sun = 357.52911 + julian_century *
+                        (35999.05029 - 0.0001537 * julian_century);  // J2
+        gdouble eccent_earth_orbit = 0.016708634 - julian_century *
+                        (0.000042037 + 0.0000001267 * julian_century); // K2
+        gdouble sun_eq_of_ctr = sin (deg2rad (geom_mean_anom_sun)) *
+                        (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century)) +
+                        sin (deg2rad (2 * geom_mean_anom_sun)) * (0.019993 - 0.000101 * julian_century) +
+                        sin (deg2rad (3 * geom_mean_anom_sun)) * 0.000289; // L2
+        gdouble sun_true_long = geom_mean_long_sun + sun_eq_of_ctr; // M2
+        gdouble sun_app_long = sun_true_long - 0.00569 - 0.00478 *
+                        sin (deg2rad (125.04 - 1934.136 * julian_century)); // P2
+        gdouble mean_obliq_ecliptic = 23 +  (26 +  ((21.448 - julian_century *
+                        (46.815 + julian_century * (0.00059 - julian_century * 0.001813)))) / 60) / 60; // Q2
+        gdouble obliq_corr = mean_obliq_ecliptic + 0.00256 *
+                        cos (deg2rad (125.04 - 1934.136 * julian_century)); // R2
+        gdouble sun_declin = rad2deg (asin (sin (deg2rad (obliq_corr)) *
+                                            sin (deg2rad (sun_app_long)))); // T2
+        gdouble var_y = tan (deg2rad (obliq_corr/2)) * tan (deg2rad (obliq_corr / 2)); // U2
+        gdouble eq_of_time = 4 * rad2deg (var_y * sin (2 * deg2rad (geom_mean_long_sun)) -
+                        2 * eccent_earth_orbit * sin (deg2rad (geom_mean_anom_sun)) +
+                        4 * eccent_earth_orbit * var_y *
+                                sin (deg2rad (geom_mean_anom_sun)) *
+                                cos (2 * deg2rad (geom_mean_long_sun)) -
+                        0.5 * var_y * var_y * sin (4 * deg2rad (geom_mean_long_sun)) -
+                        1.25 * eccent_earth_orbit * eccent_earth_orbit *
+                                sin (2 * deg2rad (geom_mean_anom_sun))); // V2
+        gdouble ha_sunrise = rad2deg (acos (cos (deg2rad (90.833)) / (cos (deg2rad (pos_lat)) *
+                        cos (deg2rad (sun_declin))) - tan (deg2rad (pos_lat)) *
+                        tan (deg2rad (sun_declin)))); // W2
+        gdouble solar_noon =  (720 - 4 * pos_long - eq_of_time + tz_offset * 60) / 1440; // X2
+        gdouble sunrise_time = solar_noon - ha_sunrise * 4 / 1440; //  Y2
+        gdouble sunset_time = solar_noon + ha_sunrise * 4 / 1440; // Z2
+
+        /* convert to hours */
+        if (sunrise != NULL)
+                *sunrise = sunrise_time * 24;
+        if (sunset != NULL)
+                *sunset = sunset_time * 24;
+        return TRUE;
+}
+
+gdouble
+gsd_natural_light_frac_day_from_dt (GDateTime *dt)
+{
+        return g_date_time_get_hour (dt) +
+                (gdouble) g_date_time_get_minute (dt) / 60.f +
+                (gdouble) g_date_time_get_second (dt) / 3600.f;
+}
+
+gboolean
+gsd_natural_light_frac_day_is_between (gdouble value, gdouble start, gdouble end)
+{
+        /* wraparound to the next day */
+        if (end < start)
+                end += 24;
+
+        /* test limits */
+        return value > start && value < end;
+}
diff --git a/plugins/color/gsd-natural-light-common.h b/plugins/color/gsd-natural-light-common.h
new file mode 100644
index 0000000..dd04ffd
--- /dev/null
+++ b/plugins/color/gsd-natural-light-common.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Richard Hughes <richard hughsie com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __GSD_NATURAL_LIGHT_COMMON_H
+#define __GSD_NATURAL_LIGHT_COMMON_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+gboolean gsd_natural_light_get_sunrise_sunset           (GDateTime      *dt,
+                                                         gdouble         pos_lat,
+                                                         gdouble         pos_long,
+                                                         gdouble        *sunrise,
+                                                         gdouble        *sunset);
+gdouble  gsd_natural_light_frac_day_from_dt             (GDateTime      *dt);
+gboolean gsd_natural_light_frac_day_is_between          (gdouble         value,
+                                                         gdouble         start,
+                                                         gdouble         end);
+
+G_END_DECLS
+
+#endif /* __GSD_NATURAL_LIGHT_COMMON_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]