1
/* $Id: weather.c 10520 2007-11-14 21:49:57Z ryanl $ */
4
* Papadimitriou Spiros <spapadim+@cs.cmu.edu>
6
* This code released under the GNU GPL.
7
* Read the file COPYING for more information.
9
* Overall weather server functions.
29
#include <sys/types.h>
35
#include <glib/gi18n-lib.h>
36
#include <gtk/gtkicontheme.h>
37
#include <gdk-pixbuf/gdk-pixbuf.h>
38
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
39
#include <libgnomevfs/gnome-vfs.h>
41
#include <libgweather/weather.h>
42
#include "weather-priv.h"
45
close_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data);
49
* Convert string of the form "DD-MM-SSH" to radians
50
* DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW)
51
* Return value is positive for N,E; negative for S,W.
53
static gdouble dmsh2rad (const gchar *latlon)
56
int deg, min, sec, dir;
61
p1 = strchr(latlon, '-');
62
p2 = strrchr(latlon, '-');
63
if (p1 == NULL || p1 == latlon) {
65
} else if (p1 == p2) {
66
sscanf (latlon, "%d-%d", °, &min);
68
} else if (p2 == 1 + p1) {
71
sscanf (latlon, "%d-%d-%d", °, &min, &sec);
73
if (deg > 180 || min >= 60 || sec >= 60)
75
value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI / 648000.;
77
dir = toupper(latlon[strlen(latlon) - 1]);
78
if (dir == 'W' || dir == 'S')
80
else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0'))
85
WeatherLocation *weather_location_new (const gchar *name, const gchar *code,
86
const gchar *zone, const gchar *radar,
87
const gchar *coordinates)
89
WeatherLocation *location;
91
location = g_new(WeatherLocation, 1);
93
/* name and metar code must be set */
94
location->name = g_strdup(name);
95
location->code = g_strdup(code);
98
location->zone = g_strdup(zone);
100
location->zone = g_strdup("------");
104
location->radar = g_strdup(radar);
106
location->radar = g_strdup("---");
109
if (location->zone[0] == '-') {
110
location->zone_valid = FALSE;
112
location->zone_valid = TRUE;
115
location->coordinates = NULL;
120
pieces = g_strsplit (coordinates, " ", -1);
122
if (g_strv_length (pieces) == 2)
124
location->coordinates = g_strdup(coordinates);
125
location->latitude = dmsh2rad (pieces[0]);
126
location->longitude = dmsh2rad (pieces[1]);
132
if (!location->coordinates)
134
location->coordinates = g_strdup("---");
135
location->latitude = DBL_MAX;
136
location->longitude = DBL_MAX;
139
location->latlon_valid = (location->latitude < DBL_MAX && location->longitude < DBL_MAX);
144
WeatherLocation *weather_location_clone (const WeatherLocation *location)
146
WeatherLocation *clone;
148
clone = weather_location_new (location->name,
149
location->code, location->zone,
150
location->radar, location->coordinates);
151
clone->latitude = location->latitude;
152
clone->longitude = location->longitude;
153
clone->latlon_valid = location->latlon_valid;
157
void weather_location_free (WeatherLocation *location)
160
g_free (location->name);
161
g_free (location->code);
162
g_free (location->zone);
163
g_free (location->radar);
164
g_free (location->coordinates);
170
gboolean weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2)
172
if (!location1->code || !location2->code)
174
return ( (strcmp(location1->code, location2->code) == 0) &&
175
(strcmp(location1->name, location2->name) == 0) );
178
static const gchar *wind_direction_str[] = {
180
N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
181
N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
182
N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
183
N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")
186
const gchar *weather_wind_direction_string (WeatherWindDirection wind)
190
if (wind >= (sizeof (wind_direction_str) / sizeof (char *)))
193
return _(wind_direction_str[(int)wind]);
196
static const gchar *sky_str[] = {
199
N_("Scattered clouds"),
204
const gchar *weather_sky_string (WeatherSky sky)
207
sky >= (sizeof (sky_str) / sizeof (char *)))
210
return _(sky_str[(int)sky]);
215
* Even though tedious, I switched to a 2D array for weather condition
216
* strings, in order to facilitate internationalization, esp. for languages
221
* Almost all reportable combinations listed in
222
* http://www.crh.noaa.gov/arx/wx.tbl.html are entered below, except those
223
* having 2 qualifiers mixed together [such as "Blowing snow in vicinity"
224
* (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc].
225
* Combinations that are not possible are filled in with "??".
226
* Some other exceptions not handled yet, such as "SN BLSN" which has
231
* Note, magic numbers, when you change the size here, make sure to change
232
* the below function so that new values are recognized
234
/* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */
235
/* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
236
static const gchar *conditions_str[24][13] = {
237
/* TRANSLATOR: If you want to know what "blowing" "shallow" "partial"
238
* etc means, you can go to http://www.weather.com/glossary/ and
239
* http://www.crh.noaa.gov/arx/wx.tbl.html */
240
/* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm"), "??", "??", "??", "??" },
241
/* DRIZZLE */ {N_("Drizzle"), "??", N_("Light drizzle"), N_("Moderate drizzle"), N_("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle") },
242
/* RAIN */ {N_("Rain"), "??", N_("Light rain"), N_("Moderate rain"), N_("Heavy rain"), "??", "??", "??", N_("Thunderstorm"), "??", N_("Rain showers"), "??", N_("Freezing rain") },
243
/* SNOW */ {N_("Snow"), "??", N_("Light snow"), N_("Moderate snow"), N_("Heavy snow"), "??", "??", "??", N_("Snowstorm"), N_("Blowing snowfall"), N_("Snow showers"), N_("Drifting snow"), "??" },
244
/* SNOW_GRAINS */ {N_("Snow grains"), "??", N_("Light snow grains"), N_("Moderate snow grains"), N_("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" },
245
/* ICE_CRYSTALS */ {N_("Ice crystals"), "??", "??", N_("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
246
/* ICE_PELLETS */ {N_("Ice pellets"), "??", N_("Few ice pellets"), N_("Moderate ice pellets"), N_("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm"), "??", N_("Showers of ice pellets"), "??", "??" },
247
/* HAIL */ {N_("Hail"), "??", "??", N_("Hail"), "??", "??", "??", "??", N_("Hailstorm"), "??", N_("Hail showers"), "??", "??", },
248
/* SMALL_HAIL */ {N_("Small hail"), "??", "??", N_("Small hail"), "??", "??", "??", "??", N_("Small hailstorm"), "??", N_("Showers of small hail"), "??", "??" },
249
/* PRECIPITATION */ {N_("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
250
/* MIST */ {N_("Mist"), "??", "??", N_("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
251
/* FOG */ {N_("Fog"), N_("Fog in the vicinity") , "??", N_("Fog"), "??", N_("Shallow fog"), N_("Patches of fog"), N_("Partial fog"), "??", "??", "??", "??", N_("Freezing fog") },
252
/* SMOKE */ {N_("Smoke"), "??", "??", N_("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
253
/* VOLCANIC_ASH */ {N_("Volcanic ash"), "??", "??", N_("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
254
/* SAND */ {N_("Sand"), "??", "??", N_("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand"), "", N_("Drifting sand"), "??" },
255
/* HAZE */ {N_("Haze"), "??", "??", N_("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
256
/* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays"), "??", "??", "??" },
257
/* DUST */ {N_("Dust"), "??", "??", N_("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust"), "??", N_("Drifting dust"), "??" },
258
/* SQUALL */ {N_("Squall"), "??", "??", N_("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" },
259
/* SANDSTORM */ {N_("Sandstorm"), N_("Sandstorm in the vicinity") , "??", N_("Sandstorm"), N_("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
260
/* DUSTSTORM */ {N_("Duststorm"), N_("Duststorm in the vicinity") , "??", N_("Duststorm"), N_("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" },
261
/* FUNNEL_CLOUD */ {N_("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
262
/* TORNADO */ {N_("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" },
263
/* DUST_WHIRLS */ {N_("Dust whirls"), N_("Dust whirls in the vicinity") , "??", N_("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }
266
const gchar *weather_conditions_string (WeatherConditions cond)
270
if (!cond.significant) {
273
if (cond.phenomenon >= 0 &&
274
cond.phenomenon < 24 &&
275
cond.qualifier >= 0 &&
277
str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier]);
280
return (strlen(str) > 0) ? str : "-";
284
/* Locals turned global to facilitate asynchronous HTTP requests */
287
gboolean requests_init (WeatherInfo *info)
289
if (info->requests_pending)
292
/*g_assert(!metar_handle && !iwin_handle && !wx_handle && !met_handle);*/
294
info->requests_pending = TRUE;
299
void request_done (GnomeVFSAsyncHandle *handle, WeatherInfo *info)
304
gnome_vfs_async_close(handle, close_cb, info);
306
info->sunValid = info->valid && calc_sun(info);
310
void requests_done_check (WeatherInfo *info)
312
g_return_if_fail(info->requests_pending);
314
if (!info->metar_handle && !info->iwin_handle &&
315
!info->wx_handle && !info->met_handle &&
317
info->requests_pending = FALSE;
318
info->finish_cb(info, info->cb_data);
323
close_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data)
325
WeatherInfo *info = (WeatherInfo *)data;
327
g_return_if_fail (info != NULL);
329
if (result != GNOME_VFS_OK)
330
g_warning("Error closing GnomeVFSAsyncHandle.\n");
332
if (handle == info->metar_handle)
333
info->metar_handle = NULL;
334
if (handle == info->iwin_handle)
335
info->iwin_handle = NULL;
336
if (handle == info->wx_handle)
337
info->wx_handle = NULL;
338
if (handle == info->met_handle)
339
info->met_handle = NULL;
340
if (handle == info->bom_handle)
341
info->bom_handle = NULL;
343
requests_done_check(info);
348
/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */
351
static inline gdouble calc_humidity(gdouble temp, gdouble dewp)
355
if (temp > -500.0 && dewp > -500.0) {
356
temp = TEMP_F_TO_C(temp);
357
dewp = TEMP_F_TO_C(dewp);
359
esat = 6.11 * pow(10.0, (7.5 * temp) / (237.7 + temp));
360
esurf = 6.11 * pow(10.0, (7.5 * dewp) / (237.7 + dewp));
365
return ((esurf/esat) * 100.0);
368
static inline gdouble calc_apparent (WeatherInfo *info)
370
gdouble temp = info->temp;
371
gdouble wind = WINDSPEED_KNOTS_TO_MPH(info->windspeed);
372
gdouble apparent = -1000.;
376
* Wind chill calculations as of 01-Nov-2001
377
* http://www.nws.noaa.gov/om/windchill/index.shtml
378
* Some pages suggest that the formula will soon be adjusted
379
* to account for solar radiation (bright sun vs cloudy sky)
383
gdouble v = pow(wind, 0.16);
384
apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v;
385
} else if (wind >= 0.) {
390
* Heat index calculations:
391
* http://www.srh.noaa.gov/fwd/heatindex/heat5.html
393
else if (temp >= 80.0) {
394
if (info->temp >= -500. && info->dew >= -500.) {
395
gdouble humidity = calc_humidity(info->temp, info->dew);
396
gdouble t2 = temp * temp;
397
gdouble h2 = humidity * humidity;
401
* A really precise formula. Note that overall precision is
402
* constrained by the accuracy of the instruments and that the
403
* we receive the temperature and dewpoints as integers.
405
gdouble t3 = t2 * temp;
406
gdouble h3 = h2 * temp;
411
- 0.100254 * temp * humidity
414
+ 3.45372e-4 * t2 * humidity
415
- 8.14971e-4 * temp * h2
416
+ 1.02102e-5 * t2 * h2
419
+ 1.42721e-6 * t3 * humidity
420
+ 1.97483e-7 * temp * h3
421
- 2.18429e-8 * t3 * h2
422
+ 8.43296e-10 * t2 * h3
423
- 4.81975e-11 * t3 * h3;
426
* An often cited alternative: values are within 5 degrees for
427
* most ranges between 10% and 70% humidity and to 110 degrees.
431
+ 10.14333127 * humidity
432
- 0.22475541 * temp * humidity
435
+ 1.22874e-3 * t2 * humidity
436
+ 8.5282e-4 * temp * h2
450
_weather_info_fill (WeatherInfo *info,
451
WeatherLocation *location,
452
const WeatherPrefs *prefs,
456
g_return_val_if_fail(((info == NULL) && (location != NULL)) || \
457
((info != NULL) && (location == NULL)), NULL);
458
g_return_val_if_fail(prefs != NULL, NULL);
460
/* FIXME: i'm not sure this works as intended anymore */
462
info = g_new0(WeatherInfo, 1);
463
info->metar_handle = NULL;
464
info->iwin_handle = NULL;
465
info->wx_handle = NULL;
466
info->met_handle = NULL;
467
info->bom_handle = NULL;
468
info->requests_pending = FALSE;
469
info->metar_buffer = NULL;
470
info->iwin_buffer = NULL;
471
info->met_buffer = NULL;
472
info->bom_buffer = NULL;
473
info->location = weather_location_clone(location);
475
location = info->location;
477
g_free (info->forecast);
479
info->forecast = NULL;
480
if (info->radar != NULL) {
481
g_object_unref (info->radar);
486
/* Update in progress */
487
if (!requests_init(info)) {
491
/* Defaults (just in case...) */
492
/* Well, no just in case anymore. We may actually fail to fetch some
494
info->forecast_type = prefs->type;
496
info->temperature_unit = prefs->temperature_unit;
497
info->speed_unit = prefs->speed_unit;
498
info->pressure_unit = prefs->pressure_unit;
499
info->distance_unit = prefs->distance_unit;
503
info->cond.significant = FALSE;
504
info->cond.phenomenon = PHENOMENON_NONE;
505
info->cond.qualifier = QUALIFIER_NONE;
506
info->temp = -1000.0;
509
info->windspeed = -1;
510
info->pressure = -1.0;
511
info->visibility = -1.0;
512
info->sunValid = FALSE;
515
info->forecast = NULL;
517
info->radar_url = prefs->radar && prefs->radar_custom_url ?
518
g_strdup (prefs->radar_custom_url) : NULL;
519
info->metar_handle = NULL;
520
info->iwin_handle = NULL;
521
info->wx_handle = NULL;
522
info->met_handle = NULL;
523
info->bom_handle = NULL;
524
info->requests_pending = TRUE;
525
info->finish_cb = cb;
526
info->cb_data = data;
528
metar_start_open(info);
529
iwin_start_open(info);
537
void weather_info_abort (WeatherInfo *info)
539
if (info->metar_handle) {
540
gnome_vfs_async_cancel(info->metar_handle);
541
info->metar_handle = NULL;
544
if (info->iwin_handle) {
545
gnome_vfs_async_cancel(info->iwin_handle);
546
info->iwin_handle = NULL;
549
if (info->wx_handle) {
550
gnome_vfs_async_cancel(info->wx_handle);
551
info->wx_handle = NULL;
554
if (info->met_handle) {
555
gnome_vfs_async_cancel(info->met_handle);
556
info->met_handle = NULL;
559
if (info->bom_handle) {
560
gnome_vfs_async_cancel(info->bom_handle);
561
info->bom_handle = NULL;
564
info->requests_pending = FALSE;
567
WeatherInfo *weather_info_clone (const WeatherInfo *info)
571
g_return_val_if_fail(info != NULL, NULL);
573
clone = g_new(WeatherInfo, 1);
576
/* move everything */
577
g_memmove(clone, info, sizeof(WeatherInfo));
581
clone->location = weather_location_clone(info->location);
582
/* This handles null correctly */
583
clone->forecast = g_strdup(info->forecast);
584
clone->radar_url = g_strdup (info->radar_url);
586
clone->radar = info->radar;
587
if (clone->radar != NULL)
588
g_object_ref (clone->radar);
593
void weather_info_free (WeatherInfo *info)
598
weather_info_abort (info);
600
weather_location_free(info->location);
601
info->location = NULL;
603
g_free(info->forecast);
604
info->forecast = NULL;
606
if (info->radar != NULL) {
607
g_object_unref (info->radar);
611
if (info->iwin_buffer)
612
g_free (info->iwin_buffer);
614
if (info->metar_buffer)
615
g_free (info->metar_buffer);
617
if (info->met_buffer)
618
g_free (info->met_buffer);
620
if (info->bom_buffer)
621
g_free (info->bom_buffer);
626
gboolean weather_info_is_valid (WeatherInfo *info)
628
g_return_val_if_fail(info != NULL, FALSE);
632
const WeatherLocation *weather_info_get_location (WeatherInfo *info)
634
g_return_val_if_fail(info != NULL, NULL);
635
return info->location;
638
const gchar *weather_info_get_location_name (WeatherInfo *info)
640
g_return_val_if_fail(info != NULL, NULL);
641
g_return_val_if_fail(info->location != NULL, NULL);
642
return info->location->name;
645
const gchar *weather_info_get_update (WeatherInfo *info)
647
static gchar buf[200];
648
char *utf8, *timeformat;
650
g_return_val_if_fail(info != NULL, NULL);
655
if (info->update != 0) {
657
localtime_r (&info->update, &tm);
658
/* TRANSLATOR: this is a format string for strftime
659
* see `man 3 strftime` for more details
661
timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M"), -1,
666
else if (strftime(buf, sizeof(buf), timeformat, &tm) <= 0) {
671
/* Convert to UTF-8 */
672
utf8 = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
676
strncpy(buf, _("Unknown observation time"), sizeof (buf));
677
buf[sizeof(buf)-1] = '\0';
683
const gchar *weather_info_get_sky (WeatherInfo *info)
685
g_return_val_if_fail(info != NULL, NULL);
690
return weather_sky_string(info->sky);
693
const gchar *weather_info_get_conditions (WeatherInfo *info)
695
g_return_val_if_fail(info != NULL, NULL);
698
return weather_conditions_string(info->cond);
701
static const gchar *temperature_string (gfloat far, TempUnit to_unit, gboolean round)
703
static gchar buf[100];
706
case TEMP_UNIT_FAHRENHEIT:
708
/* TRANSLATOR: This is the temperature in degrees Fahrenheit (\342\204\211 is the "DEGREE FAHRENHEIT" symbol) */
709
g_snprintf(buf, sizeof (buf), _("%.1f \342\204\211"), far);
711
/* TRANSLATOR: This is the temperature in degrees Fahrenheit (\342\204\211 is the "DEGREE FAHRENHEIT" symbol) */
712
g_snprintf(buf, sizeof (buf), _("%d \342\204\211"), (int)floor(far + 0.5));
715
case TEMP_UNIT_CENTIGRADE:
717
/* TRANSLATOR: This is the temperature in degrees Celsius (\342\204\203 is the "DEGREE CELSIUS" symbol) */
718
g_snprintf (buf, sizeof (buf), _("%.1f \342\204\203"), TEMP_F_TO_C(far));
720
/* TRANSLATOR: This is the temperature in degrees Celsius (\342\204\203 is the "DEGREE CELSIUS" symbol) */
721
g_snprintf (buf, sizeof (buf), _("%d \342\204\203"), (int)floor(TEMP_F_TO_C(far) + 0.5));
724
case TEMP_UNIT_KELVIN:
726
/* TRANSLATOR: This is the temperature in kelvin */
727
g_snprintf (buf, sizeof (buf), _("%.1f K"), TEMP_F_TO_K(far));
729
/* TRANSLATOR: This is the temperature in kelvin */
730
g_snprintf (buf, sizeof (buf), _("%d K"), (int)floor(TEMP_F_TO_K(far)));
734
case TEMP_UNIT_INVALID:
735
case TEMP_UNIT_DEFAULT:
737
g_warning("Conversion to illegal temperature unit: %d", to_unit);
738
return (_("Unknown"));
744
const gchar *weather_info_get_temp (WeatherInfo *info)
746
g_return_val_if_fail(info != NULL, NULL);
750
if (info->temp < -500.0)
753
return temperature_string (info->temp, info->temperature_unit, FALSE);
756
const gchar *weather_info_get_dew (WeatherInfo *info)
758
g_return_val_if_fail(info != NULL, NULL);
762
if (info->dew < -500.0)
765
return temperature_string (info->dew, info->temperature_unit, FALSE);
768
const gchar *weather_info_get_humidity (WeatherInfo *info)
770
static gchar buf[20];
772
g_return_val_if_fail(info != NULL, NULL);
776
humidity = calc_humidity(info->temp, info->dew);
780
/* TRANSLATOR: This is the humidity in percent */
781
g_snprintf(buf, sizeof (buf), _("%.f%%"), humidity);
785
const gchar *weather_info_get_apparent (WeatherInfo *info)
788
g_return_val_if_fail(info != NULL, NULL);
792
apparent = calc_apparent(info);
793
if (apparent < -500.0)
796
return temperature_string (apparent, info->temperature_unit, FALSE);
799
static const gchar *windspeed_string (gfloat knots, SpeedUnit to_unit)
801
static gchar buf[100];
804
case SPEED_UNIT_KNOTS:
805
/* TRANSLATOR: This is the wind speed in knots */
806
g_snprintf(buf, sizeof (buf), _("%0.1f knots"), knots);
809
/* TRANSLATOR: This is the wind speed in miles per hour */
810
g_snprintf(buf, sizeof (buf), _("%.1f mph"), WINDSPEED_KNOTS_TO_MPH(knots));
813
/* TRANSLATOR: This is the wind speed in kilometers per hour */
814
g_snprintf(buf, sizeof (buf), _("%.1f km/h"), WINDSPEED_KNOTS_TO_KPH(knots));
817
/* TRANSLATOR: This is the wind speed in meters per second */
818
g_snprintf(buf, sizeof (buf), _("%.1f m/s"), WINDSPEED_KNOTS_TO_MS(knots));
821
/* TRANSLATOR: This is the wind speed as a Beaufort force factor
822
* (commonly used in nautical wind estimation).
824
g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f"),
825
WINDSPEED_KNOTS_TO_BFT (knots));
827
case SPEED_UNIT_INVALID:
828
case SPEED_UNIT_DEFAULT:
830
g_warning("Conversion to illegal speed unit: %d", to_unit);
836
const gchar *weather_info_get_wind (WeatherInfo *info)
838
static gchar buf[200];
839
g_return_val_if_fail(info != NULL, NULL);
842
if (info->windspeed < 0.0 || info->wind < 0)
844
if (info->windspeed == 0.00) {
845
strncpy(buf, _("Calm"), sizeof(buf));
846
buf[sizeof(buf)-1] = '\0';
848
/* TRANSLATOR: This is 'wind direction' / 'wind speed' */
849
g_snprintf(buf, sizeof(buf), _("%s / %s"),
850
weather_wind_direction_string(info->wind),
851
windspeed_string(info->windspeed, info->speed_unit));
855
const gchar *weather_info_get_pressure (WeatherInfo *info)
857
static gchar buf[100];
858
g_return_val_if_fail(info != NULL, NULL);
861
if (info->pressure < 0.0)
864
switch (info->pressure_unit) {
865
case PRESSURE_UNIT_INCH_HG:
866
/* TRANSLATOR: This is pressure in inches of mercury */
867
g_snprintf (buf, sizeof (buf), _("%.2f inHg"), info->pressure);
869
case PRESSURE_UNIT_MM_HG:
870
/* TRANSLATOR: This is pressure in millimeters of mercury */
871
g_snprintf (buf, sizeof (buf), _("%.1f mmHg"), PRESSURE_INCH_TO_MM(info->pressure));
873
case PRESSURE_UNIT_KPA:
874
/* TRANSLATOR: This is pressure in kiloPascals */
875
g_snprintf (buf, sizeof (buf), _("%.2f kPa"), PRESSURE_INCH_TO_KPA(info->pressure));
877
case PRESSURE_UNIT_HPA:
878
/* TRANSLATOR: This is pressure in hectoPascals */
879
g_snprintf (buf, sizeof (buf), _("%.2f hPa"), PRESSURE_INCH_TO_HPA(info->pressure));
881
case PRESSURE_UNIT_MB:
882
/* TRANSLATOR: This is pressure in millibars */
883
g_snprintf (buf, sizeof (buf), _("%.2f mb"), PRESSURE_INCH_TO_MB(info->pressure));
885
case PRESSURE_UNIT_ATM:
886
/* TRANSLATOR: This is pressure in atmospheres */
887
g_snprintf (buf, sizeof (buf), _("%.3f atm"), PRESSURE_INCH_TO_ATM(info->pressure));
890
case PRESSURE_UNIT_INVALID:
891
case PRESSURE_UNIT_DEFAULT:
893
g_warning("Conversion to illegal pressure unit: %d", info->pressure_unit);
900
const gchar *weather_info_get_visibility (WeatherInfo *info)
902
static gchar buf[100];
903
g_return_val_if_fail(info != NULL, NULL);
906
if (info->visibility < 0.0)
909
switch (info->distance_unit) {
910
case DISTANCE_UNIT_MILES:
911
/* TRANSLATOR: This is the visibility in miles */
912
g_snprintf(buf, sizeof (buf), _("%.1f miles"), info->visibility);
914
case DISTANCE_UNIT_KM:
915
/* TRANSLATOR: This is the visibility in kilometers */
916
g_snprintf(buf, sizeof (buf), _("%.1f km"), VISIBILITY_SM_TO_KM(info->visibility));
918
case DISTANCE_UNIT_METERS:
919
/* TRANSLATOR: This is the visibility in meters */
920
g_snprintf(buf, sizeof (buf), _("%.0fm"), VISIBILITY_SM_TO_M(info->visibility));
923
case DISTANCE_UNIT_INVALID:
924
case DISTANCE_UNIT_DEFAULT:
926
g_warning("Conversion to illegal visibility unit: %d", info->pressure_unit);
933
const gchar *weather_info_get_sunrise (WeatherInfo *info)
935
static gchar buf[200];
938
g_return_val_if_fail(info && info->location, NULL);
940
if (!info->location->latlon_valid)
944
if (!calc_sun (info))
947
localtime_r(&info->sunrise, &tm);
948
if (strftime(buf, sizeof(buf), _("%H:%M"), &tm) <= 0)
953
const gchar *weather_info_get_sunset (WeatherInfo *info)
955
static gchar buf[200];
958
g_return_val_if_fail(info && info->location, NULL);
960
if (!info->location->latlon_valid)
964
if (!calc_sun (info))
967
localtime_r(&info->sunset, &tm);
968
if (strftime(buf, sizeof(buf), _("%H:%M"), &tm) <= 0)
973
const gchar *weather_info_get_forecast (WeatherInfo *info)
975
g_return_val_if_fail(info != NULL, NULL);
976
return info->forecast;
979
GdkPixbufAnimation *weather_info_get_radar (WeatherInfo *info)
981
g_return_val_if_fail(info != NULL, NULL);
985
const gchar *weather_info_get_temp_summary (WeatherInfo *info)
989
if (!info->valid || info->temp < -500.0)
992
return temperature_string (info->temp, info->temperature_unit, TRUE);
996
gchar *weather_info_get_weather_summary (WeatherInfo *info)
999
g_return_val_if_fail(info != NULL, NULL);
1001
return g_strdup (_("Retrieval failed"));
1002
buf = weather_info_get_conditions(info);
1003
if (!strcmp(buf, "-"))
1004
buf = weather_info_get_sky(info);
1005
return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf);
1009
weather_info_get_icon_name (WeatherInfo *info)
1011
WeatherConditions cond;
1013
time_t current_time;
1016
if (!info || !info->valid)
1022
if (cond.significant) {
1023
if (cond.phenomenon != PHENOMENON_NONE &&
1024
cond.qualifier == QUALIFIER_THUNDERSTORM)
1025
return "weather-storm";
1027
switch (cond.phenomenon) {
1028
case PHENOMENON_NONE:
1031
case PHENOMENON_DRIZZLE:
1032
case PHENOMENON_RAIN:
1033
case PHENOMENON_UNKNOWN_PRECIPITATION:
1034
case PHENOMENON_HAIL:
1035
case PHENOMENON_SMALL_HAIL:
1036
return "weather-showers";
1038
case PHENOMENON_SNOW:
1039
case PHENOMENON_SNOW_GRAINS:
1040
case PHENOMENON_ICE_PELLETS:
1041
case PHENOMENON_ICE_CRYSTALS:
1042
return "weather-snow";
1044
case PHENOMENON_TORNADO:
1045
case PHENOMENON_SQUALL:
1046
return "weather-storm";
1048
case PHENOMENON_MIST:
1049
case PHENOMENON_FOG:
1050
case PHENOMENON_SMOKE:
1051
case PHENOMENON_VOLCANIC_ASH:
1052
case PHENOMENON_SAND:
1053
case PHENOMENON_HAZE:
1054
case PHENOMENON_SPRAY:
1055
case PHENOMENON_DUST:
1056
case PHENOMENON_SANDSTORM:
1057
case PHENOMENON_DUSTSTORM:
1058
case PHENOMENON_FUNNEL_CLOUD:
1059
case PHENOMENON_DUST_WHIRLS:
1060
return "weather-fog";
1064
current_time = time (NULL);
1065
daytime = ((!info->sunValid) ||
1066
(current_time >= info->sunrise &&
1067
current_time < info->sunset));
1073
return "weather-clear";
1075
return "weather-clear-night";
1081
return "weather-few-clouds";
1083
return "weather-few-clouds-night";
1086
return "weather-overcast";