[Xfce4-commits] <xfce4-weather-plugin:master> Fix forecasts only being reported for up to 3 days (bug #9781).

Harald Judt noreply at xfce.org
Fri Feb 1 16:20:01 CET 2013


Updating branch refs/heads/master
         to 96982f5d60998702a510c8bc3d655bf6636552c0 (commit)
       from 3b990467c41898200575f2e2443ebc19f90b36ab (commit)

commit 96982f5d60998702a510c8bc3d655bf6636552c0
Author: Harald Judt <h.judt at gmx.at>
Date:   Thu Jan 31 15:25:28 2013 +0100

    Fix forecasts only being reported for up to 3 days (bug #9781).
    
    The new code doesn't work quite well for some timezones, resulting in missing
    forecasts. This patch fixes this.
    
    What's more, these changes will make it also easier to calculate min/max
    temperatures for a day, which will be a possible future feature.

 panel-plugin/weather-data.c    |  226 ++++++++++++++++++++++++++++++++-------
 panel-plugin/weather-data.h    |    6 +-
 panel-plugin/weather-summary.c |   10 ++-
 3 files changed, 198 insertions(+), 44 deletions(-)

diff --git a/panel-plugin/weather-data.c b/panel-plugin/weather-data.c
index e0bb803..645e349 100644
--- a/panel-plugin/weather-data.c
+++ b/panel-plugin/weather-data.c
@@ -32,6 +32,11 @@
 #define NIGHT_TIME_START 21
 #define NIGHT_TIME_END 5
 
+/* interval used for searching raw data relevant to a day */
+#define DAY_START 3
+#define DAY_END 33
+#define DAYTIME_LEN 6
+
 /* If some value is not present or cannot be computed, return this instead */
 #define INVALID_VALUE -9999
 
@@ -170,7 +175,7 @@ calc_apparent_temperature(const xml_location *loc,
 
             return 13.12 + 0.6215 * temp - 11.37 * pow(windspeed, 0.16)
                 + 0.3965 * temp * pow(windspeed, 0.16);
-         }
+        }
 
         if (temp >= 26.7 || (night_time && temp >= 22.0)) {
             /* humidity needs to be higher than 40% for a valid result */
@@ -991,7 +996,7 @@ find_point_data(const xml_weather *wd,
 
         /* add point data if within limits */
         diff = difftime(timeslice->end, point_t);
-        if (diff < 0) {   /* before point_t */
+        if (diff <= 0) {  /* before point_t */
             diff *= -1;
             if (diff < min_diff || diff > max_diff)
                 continue;
@@ -1056,63 +1061,202 @@ make_current_conditions(xml_weather *wd,
 }
 
 
-static time_t
-get_daytime(int day,
-            daytime dt)
+/*
+ * Get all point data relevant for a given day.
+ */
+GArray *
+get_point_data_for_day(xml_weather *wd,
+                       int day)
 {
-    struct tm point_tm;
-    time_t point_t;
+    GArray *found;
+    xml_time *timeslice;
+    struct tm day_tm;
+    time_t day_t;
+    gint i;
 
-    /* initialize times to the current day */
-    time(&point_t);
-    point_tm = *localtime(&point_t);
+    /* calculate 00:00 for the requested day */
+    time(&day_t);
+    day_tm = *localtime(&day_t);
+    day_tm.tm_mday += day;
+    day_tm.tm_hour = day_tm.tm_min = day_tm.tm_sec = 0;
+    day_tm.tm_isdst = -1;
+    day_t = mktime(&day_tm);
+
+    /* loop over weather data and pick relevant point data */
+    found = g_array_new(FALSE, TRUE, sizeof(xml_time *));
+    g_assert(found != NULL);
+    if (G_UNLIKELY(found == NULL))
+        return NULL;
 
-    /* calculate daytime for the requested day */
-    point_tm.tm_mday += day;
-    point_tm.tm_min = point_tm.tm_sec = 0;
-    point_tm.tm_isdst = -1;
-    switch (dt) {
-    case MORNING:
-        point_tm.tm_hour = 9;
-        break;
-    case AFTERNOON:
-        point_tm.tm_hour = 15;
-        break;
-    case EVENING:
-        point_tm.tm_hour = 21;
-        break;
-    case NIGHT:
-        point_tm.tm_hour = 27;
-        break;
+    weather_debug("Checking %d timeslices for point data relevant to day %d.",
+                  wd->timeslices->len, day);
+    for (i = 0; i < wd->timeslices->len; i++) {
+        timeslice = g_array_index(wd->timeslices, xml_time *, i);
+
+        /* look only for point data, not intervals */
+        if (G_UNLIKELY(timeslice == NULL) || timeslice_is_interval(timeslice))
+            continue;
+
+        if (difftime(timeslice->start, day_t) >= DAY_START * 3600 &&
+            difftime(timeslice->end, day_t) <= DAY_END * 3600) {
+            weather_dump(weather_dump_timeslice, timeslice);
+            g_array_append_val(found, timeslice);
+        }
     }
-    point_t = mktime(&point_tm);
-    return point_t;
+    g_array_sort(found, (GCompareFunc) xml_time_compare);
+    weather_debug("Found %d timeslices for day %d.", found->len, day);
+    return found;
 }
 
 
 /*
- * Get forecast data for a given daytime for the day (today + day).
+ * Return forecast data for a given daytime, using the data provided.
  */
 xml_time *
 make_forecast_data(xml_weather *wd,
-                   int day,
+                   GArray *daydata,
+                   gint day,
                    daytime dt)
 {
-    point_data_results *found = NULL;
-    xml_time *interval = NULL;
-    time_t point_t;
+    xml_time *ts1, *ts2, *interval = NULL;
+    struct tm point_tm, start_tm, end_tm;
+    time_t point_t, start_t, end_t;
+    gint min, max, point, i, j;
 
     g_assert(wd != NULL);
     if (G_UNLIKELY(wd == NULL))
         return NULL;
 
-    point_t = get_daytime(day, dt);
-    found = find_point_data(wd, point_t, 1, 5 * 3600);
-    interval = find_largest_interval(wd, found);
-    point_data_results_free(found);
-    weather_dump(weather_dump_timeslice, interval);
-    if (interval == NULL)
+    g_assert(daydata != NULL);
+    if (G_UNLIKELY(daydata == NULL))
         return NULL;
 
-    return make_combined_timeslice(wd, interval, &point_t);
+    /* choose search interval and desired point in time depending on daytime */
+    switch (dt) {
+    case MORNING:
+        min = 3;
+        max = 15;
+        point = 9;
+        break;
+    case AFTERNOON:
+        min = 9;
+        max = 21;
+        point = 15;
+        break;
+    case EVENING:
+        min = 15;
+        max = 27;
+        point = 21;
+        break;
+    case NIGHT:
+        min = 21;
+        max = 33;
+        point = 27;
+        break;
+    }
+
+    /* initialize times to the current day */
+    time(&point_t);
+    start_tm = end_tm = point_tm = *localtime(&point_t);
+
+    /* calculate daytime limits for the requested day */
+    point_tm.tm_mday += day;
+    point_tm.tm_hour = point;
+    point_tm.tm_min = point_tm.tm_sec = 0;
+    point_tm.tm_isdst = -1;
+    point_t = mktime(&point_tm);
+
+    start_tm.tm_mday += day;
+    start_tm.tm_hour = min;
+    start_tm.tm_min = start_tm.tm_sec = 0;
+    start_tm.tm_isdst = -1;
+    start_t = mktime(&start_tm);
+
+    end_tm.tm_mday += day;
+    end_tm.tm_hour = max;
+    end_tm.tm_min = end_tm.tm_sec = 0;
+    end_tm.tm_isdst = -1;
+    end_t = mktime(&end_tm);
+
+    /* using search criteria, find an appropriate interval */
+    for (i = 0; i < daydata->len; i++) {
+        weather_debug("checking start ts %d", i);
+
+        /* try start timeslice for interval */
+        ts1 = g_array_index(daydata, xml_time *, i);
+
+        if (G_UNLIKELY(ts1 == NULL))
+            continue;
+        weather_debug("start ts is not null");
+
+        /* start timeslice needs to be within max daytime interval */
+        if (difftime(ts1->start, start_t) < 0 ||
+            difftime(end_t, ts1->start) < 0)
+            continue;
+        weather_debug("start ts is in max daytime interval");
+
+        for (j = 0; j < daydata->len; j++) {
+            weather_debug("checking end ts %d", j);
+
+            /* find end timeslice for interval */
+            ts2 = g_array_index(daydata, xml_time *, j);
+
+            if (G_UNLIKELY(ts2 == NULL))
+                continue;
+            weather_debug("end ts is not null");
+
+            /* end timeslice has to be different from the start timeslice */
+            if (ts1 == ts2)
+                continue;
+            weather_debug("start ts is different from end ts");
+
+            /* end timeslice needs to be after start timeslice */
+            if (difftime(ts2->start, ts1->start) <= 0)
+                continue;
+            weather_debug("start ts is before end ts");
+
+            /* end timeslice needs to be in max daytime interval */
+            if (difftime(ts2->start, start_t) < 0 ||
+                difftime(end_t, ts2->start) < 0)
+                continue;
+            weather_debug("end ts is in max daytime interval");
+
+            /* start and end timeslice need to be a 6 hour interval... */
+            if (difftime(ts2->start, ts1->start) != DAYTIME_LEN * 3600)
+                /* ...however we may need to take into account possible dst
+                   difference so let's also try DAYTIME_LEN ±1 hour */
+                if ((difftime(ts2->start, ts1->start) < (DAYTIME_LEN - 1) * 3600 ||
+                     difftime(ts2->start, ts1->start) > (DAYTIME_LEN + 1) * 3600) &&
+                    get_timeslice(wd, ts1->start, ts2->end, NULL) == NULL)
+                    continue;
+            weather_debug("start and end ts are 6 hours apart");
+
+            /* daytime point needs to be within the interval */
+            if (difftime(point_t, ts1->start) < 0 ||
+                difftime(ts2->start, point_t) < 0)
+                continue;
+            weather_debug("daytime point is within the found interval");
+
+            /* we got the interval, but point may be too much near start */
+            if (difftime(point_t, ts1->start) <= 3600)
+                point_t = time_calc_hour(point_tm, 2);
+            else if (difftime(point_t, ts1->start) <= 2 * 3600)
+                point_t = time_calc_hour(point_tm, 1);
+
+            /* we got the interval, but point may be too much near end */
+            if (difftime(ts2->start, point_t) <= 3600)
+                point_t = time_calc_hour(point_tm, -2);
+            else if (difftime(ts2->start, point_t) <= 2 * 3600)
+                point_t = time_calc_hour(point_tm, -1);
+
+            /* combine the interval with interpolated point data */
+            interval = get_timeslice(wd, ts1->start, ts2->end, NULL);
+            if (interval == NULL)
+                continue;
+
+            weather_debug("returning valid interval");
+            return make_combined_timeslice(wd, interval, &point_t);
+        }
+    }
+    return NULL;
 }
diff --git a/panel-plugin/weather-data.h b/panel-plugin/weather-data.h
index 17b8ad1..a236d2a 100644
--- a/panel-plugin/weather-data.h
+++ b/panel-plugin/weather-data.h
@@ -145,8 +145,12 @@ xml_time *get_current_conditions(const xml_weather *wd);
 xml_time *make_current_conditions(xml_weather *wd,
                                   time_t now_t);
 
+GArray *get_point_data_for_day(xml_weather *wd,
+                               int day);
+
 xml_time *make_forecast_data(xml_weather *wd,
-                             int day,
+                             GArray *daydata,
+                             gint day,
                              daytime dt);
 
 G_END_DECLS
diff --git a/panel-plugin/weather-summary.c b/panel-plugin/weather-summary.c
index d6832d3..b03da45 100644
--- a/panel-plugin/weather-summary.c
+++ b/panel-plugin/weather-summary.c
@@ -723,6 +723,7 @@ add_forecast_header(const gchar *text,
 
 static GtkWidget *
 add_forecast_cell(plugin_data *data,
+                  GArray *daydata,
                   gint day,
                   gint daytime)
 {
@@ -734,7 +735,7 @@ add_forecast_cell(plugin_data *data,
 
     box = gtk_vbox_new(FALSE, 0);
 
-    fcdata = make_forecast_data(data->weatherdata, day, daytime);
+    fcdata = make_forecast_data(data->weatherdata, daydata, day, daytime);
     if (fcdata == NULL)
         return box;
 
@@ -813,6 +814,7 @@ make_forecast(plugin_data *data)
     GtkWidget *forecast_box;
     const GdkColor lightbg = {0, 0xeaea, 0xeaea, 0xeaea};
     const GdkColor darkbg = {0, 0x6666, 0x6666, 0x6666};
+    GArray *daydata;
     gchar *dayname;
     gint i;
     daytime daytime;
@@ -853,9 +855,12 @@ make_forecast(plugin_data *data)
             gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(ebox),
                                       0, 1, i+1, i+2);
 
+        /* to speed up things, first get forecast data for all daytimes */
+        daydata = get_point_data_for_day(data->weatherdata, i);
+
         /* get forecast data for each daytime */
         for (daytime = MORNING; daytime <= NIGHT; daytime++) {
-            forecast_box = add_forecast_cell(data, i, daytime);
+            forecast_box = add_forecast_cell(data, daydata, i, daytime);
             align = gtk_alignment_new(0.5, 0.5, 1, 1);
             gtk_container_set_border_width(GTK_CONTAINER(align), 4);
             gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(forecast_box));
@@ -873,6 +878,7 @@ make_forecast(plugin_data *data)
                                           GTK_WIDGET(ebox),
                                           1+daytime, 2+daytime, i+1, i+2);
         }
+        g_array_free(daydata, FALSE);
     }
     return table;
 }


More information about the Xfce4-commits mailing list