]> git.itanic.dy.fi Git - maemo-mapper/blob - src/util.c
e94791496728b3394683b661b43eca8f6bcd21a4
[maemo-mapper] / src / util.c
1 /*
2  * Copyright (C) 2006, 2007 John Costigan.
3  *
4  * POI and GPS-Info code originally written by Cezary Jackiewicz.
5  *
6  * Default map data provided by http://www.openstreetmap.org/
7  *
8  * This file is part of Maemo Mapper.
9  *
10  * Maemo Mapper is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Maemo Mapper is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #    include "config.h"
26 #endif
27
28 #define _GNU_SOURCE
29
30 #include <ctype.h>
31 #include <string.h>
32 #include <math.h>
33
34 #ifndef LEGACY
35 #    include <hildon/hildon-note.h>
36 #else
37 #    include <hildon-widgets/hildon-note.h>
38 #endif
39
40 #include "types.h"
41 #include "data.h"
42 #include "defines.h"
43
44 #include "gpx.h"
45 #include "util.h"
46
47
48 /**
49  * Pop up a modal dialog box with simple error information in it.
50  */
51 void
52 popup_error(GtkWidget *window, const gchar *error)
53 {
54     GtkWidget *dialog;
55     printf("%s(\"%s\")\n", __PRETTY_FUNCTION__, error);
56
57     dialog = hildon_note_new_information(GTK_WINDOW(window), error);
58
59     gtk_dialog_run(GTK_DIALOG(dialog));
60     gtk_widget_destroy(dialog);
61
62     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
63 }
64
65 void
66 deg_format(gdouble coor, gchar *scoor, gchar neg_char, gchar pos_char)
67 {
68     gdouble min;
69     gdouble acoor = fabs(coor);
70     printf("%s()\n", __PRETTY_FUNCTION__);
71
72     switch(_degformat)
73     {
74         case DDPDDDDD:
75             sprintf(scoor, "%.5f°", coor);
76             break;
77         case DDPDDDDD_NSEW:
78             sprintf(scoor, "%.5f° %c", acoor,
79                     coor < 0.0 ? neg_char : pos_char);
80             break;
81         case NSEW_DDPDDDDD:
82             sprintf(scoor, "%c %.5f°",
83                     coor < 0.0 ? neg_char : pos_char,
84                     acoor);
85             break;
86
87         case DD_MMPMMM:
88             sprintf(scoor, "%d°%06.3f'",
89                     (int)coor, (acoor - (int)acoor)*60.0);
90             break;
91         case DD_MMPMMM_NSEW:
92             sprintf(scoor, "%d°%06.3f' %c",
93                     (int)acoor, (acoor - (int)acoor)*60.0,
94                     coor < 0.0 ? neg_char : pos_char);
95             break;
96         case NSEW_DD_MMPMMM:
97             sprintf(scoor, "%c %d° %06.3f'",
98                     coor < 0.0 ? neg_char : pos_char,
99                     (int)acoor, (acoor - (int)acoor)*60.0);
100             break;
101
102         case DD_MM_SSPS:
103             min = (acoor - (int)acoor)*60.0;
104             sprintf(scoor, "%d°%02d'%04.1f\"", (int)coor, (int)min,
105                     ((min - (int)min)*60.0));
106             break;
107         case DD_MM_SSPS_NSEW:
108             min = (acoor - (int)acoor)*60.0;
109             sprintf(scoor, "%d°%02d'%04.1f\" %c", (int)acoor, (int)min,
110                     ((min - (int)min)*60.0),
111                     coor < 0.0 ? neg_char : pos_char);
112             break;
113         case NSEW_DD_MM_SSPS:
114             min = (acoor - (int)acoor)*60.0;
115             sprintf(scoor, "%c %d° %02d' %04.1f\"",
116                     coor < 0.0 ? neg_char : pos_char,
117                     (int)acoor, (int)min,
118                     ((min - (int)min)*60.0));
119             break;
120     }
121     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
122 }
123
124 /** Return the location (in units) of the given string address.  This function
125   * makes a call to the internet, so it may take some time. */
126 Point locate_address(GtkWidget *parent, const gchar *addr)
127 {
128     Path temp;
129     Point retval = _point_null;
130     GnomeVFSResult vfs_result;
131     gint size;
132     gchar *bytes = NULL;
133     gchar *addr_escaped;
134     gchar *buffer;
135     printf("%s(%s)\n", __PRETTY_FUNCTION__, addr);
136
137     addr_escaped = gnome_vfs_escape_string(addr);
138     buffer = g_strdup_printf(_route_dl_url, addr_escaped, addr_escaped);
139     g_free(addr_escaped);
140
141     /* Attempt to download the route from the server. */
142     if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
143                 buffer, &size, &bytes)))
144     {
145         g_free(buffer);
146         g_free(bytes);
147         popup_error(parent, _("Failed to connect to GPX Directions server"));
148         return _point_null;
149     }
150
151     g_free(buffer);
152
153     MACRO_PATH_INIT(temp);
154
155     if(strncmp(bytes, "<?xml", strlen("<?xml")))
156     {
157         /* Not an XML document - must be bad locations. */
158         popup_error(parent, _("Invalid address."));
159     }
160     /* Else, if GPS is enabled, replace the route, otherwise append it. */
161     else if(!gpx_path_parse(&temp, bytes, size, 0) || !temp.head[1].unity)
162     {
163         popup_error(parent, _("Unknown error while locating address."));
164     }
165     else
166     {
167         /* Save Destination in Route Locations list. */
168         GtkTreeIter iter;
169         if(!g_slist_find_custom(_loc_list, addr, (GCompareFunc)strcmp))
170         {
171             _loc_list = g_slist_prepend(_loc_list, g_strdup(addr));
172             gtk_list_store_insert_with_values(_loc_model, &iter,
173                     INT_MAX, 0, addr, -1);
174         }
175
176         retval = temp.head[1];
177     }
178
179     MACRO_PATH_FREE(temp);
180     g_free(bytes);
181
182     vprintf("%s(): return (%d, %d)\n", __PRETTY_FUNCTION__,
183             retval.unitx, retval.unity);
184     return retval;
185 }
186
187 /**
188  * Calculate the distance between two lat/lon pairs.  The distance is returned
189  * in nautical miles and should be converted using UNITS_CONVERT[_units].
190  */
191 gdouble
192 calculate_distance(gdouble lat1, gdouble lon1, gdouble lat2, gdouble lon2)
193 {
194     gdouble dlat, dlon, slat, slon, a;
195
196     /* Convert to radians. */
197     lat1 = deg2rad(lat1);
198     lon1 = deg2rad(lon1);
199     lat2 = deg2rad(lat2);
200     lon2 = deg2rad(lon2);
201
202     dlat = lat2 - lat1;
203     dlon = lon2 - lon1;
204
205     slat = sin(dlat / 2.0);
206     slon = sin(dlon / 2.0);
207     a = (slat * slat) + (cos(lat1) * cos(lat2) * slon * slon);
208
209     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
210     return ((2.0 * atan2(sqrt(a), sqrt(1.0 - a))) * EARTH_RADIUS);
211 }
212
213 /**
214  * Calculate the bearing between two lat/lon pairs.  The bearing is returned
215  * as the angle from lat1/lon1 to lat2/lon2.
216  */
217 gdouble
218 calculate_bearing(gdouble lat1, gdouble lon1, gdouble lat2, gdouble lon2)
219 {
220     gdouble x, y;
221     gdouble dlon = deg2rad(lon2 - lon1);
222     lat1 = deg2rad(lat1);
223     lat2 = deg2rad(lat2);
224
225     y = sin(dlon) * cos(lat2);
226     x = (cos(lat1) * sin(lat2)) - (sin(lat1) * cos(lat2) * cos(dlon));
227
228     dlon = rad2deg(atan2(y, x));
229     if(dlon < 0.0)
230         dlon += 360.0;
231     return dlon;
232 }
233
234
235
236 void
237 force_min_visible_bars(HildonControlbar *control_bar, gint num_bars)
238 {
239 #ifdef LEGACY
240     GValue val;
241     printf("%s()\n", __PRETTY_FUNCTION__);
242     memset(&val, 0, sizeof(val));
243     g_value_init(&val, G_TYPE_INT);
244     g_value_set_int(&val, num_bars);
245     g_object_set_property(G_OBJECT(control_bar), "minimum-visible-bars", &val);
246     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
247 #endif
248 }
249
250 gboolean
251 banner_reset()
252 {
253     printf("%s()\n", __PRETTY_FUNCTION__);
254
255     /* Re-enable any banners that might have been up. */
256     {
257         if(_connect_banner)
258         {
259             gtk_widget_hide(_connect_banner);
260             gtk_widget_unrealize(_connect_banner);
261             gtk_widget_realize(_connect_banner);
262             gtk_widget_show(_connect_banner);
263         }
264
265         if(_fix_banner)
266         {
267             gtk_widget_hide(_fix_banner);
268             gtk_widget_unrealize(_fix_banner);
269             gtk_widget_realize(_fix_banner);
270             gtk_widget_show(_fix_banner);
271         }
272
273         if(_waypoint_banner)
274         {
275             gtk_widget_hide(_waypoint_banner);
276             gtk_widget_unrealize(_waypoint_banner);
277             gtk_widget_realize(_waypoint_banner);
278             gtk_widget_show(_waypoint_banner);
279         }
280
281         if(_download_banner)
282         {
283             gtk_widget_hide(_download_banner);
284             gtk_widget_unrealize(_download_banner);
285             gtk_widget_realize(_download_banner);
286             gtk_widget_show(_download_banner);
287         }
288
289         /*
290         ConnState old_state = _gps_state;
291         set_conn_state(RCVR_OFF);
292         set_conn_state(old_state);
293         */
294     }
295
296     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
297     return FALSE;
298 }
299 /*
300  * Get one numeric token off the string, fractional part separator
301  * is ',' or '.' and number may follow any token from sep.
302  * Return value found is in d.
303  *
304  * If utf8_deg is set then accept also Unicode degree symbol U+00B0
305  * encoded as UTF-8 octets 0xc2 0xb0.
306  *
307  * @returns
308  *    0 : on error.
309  *    1 : when nothing or just white space was seen.
310  *    2 : when fractional number was seen.
311  *    3 : when whole number was seen.
312  *  In case 0, endptr points to the beginning of the input string nptr,
313  *  d is undefined.
314  *
315  *  In case 1 endptr points past the whitespace, d is undefined.
316  *
317  *  In cases 2 and 3 the found number is stored in d and endptr points
318  *  to first char not part of the number.
319  *
320  */
321 static gint
322 strdmstod_1(gdouble *d, gchar *nptr, gchar **endptr, gchar *sep, gint utf8_deg)
323 {
324     guchar *p;
325     gint v_flag, f_flag;
326     gdouble v;
327
328     p = nptr;
329
330     while (*p && isspace(*p)) {
331         p++;
332     }
333
334     v_flag = 0;
335     f_flag = 0;
336
337     /* whole part */
338     v = 0.0;
339     while (*p && isdigit(*p)) {
340         v *= 10;
341         v += *p++ - '0';
342         v_flag = 1;
343     }
344
345     if (v_flag) {
346         if (*p && (*p == '.' || *p == ',')) {
347             gdouble f;
348             gint n;
349
350             p++;
351
352             /* fractional part */
353             f = 0.0;
354             n = 1;
355             while (*p && isdigit(*p)) {
356                 f *= 10.0;
357                 f += *p++ - '0';
358                 n *= 10;
359             }
360
361             if (n > 1) {
362                 f_flag = 1;
363                 v += f/n;
364             }
365         }
366
367         /* allow for extra sep char at the end */
368         if (*p && strchr(sep, *p)) {
369             p++;
370         } else if (utf8_deg && *p == 0xc2 && *(p+1) == 0xb0) {
371             p += 2;
372         }
373
374         *d = v;
375         if (endptr) *endptr = p;
376         return f_flag ? 2 : 3;
377     }
378
379     if (endptr) *endptr = p;
380     return *p == 0;
381 }
382
383 static gdouble
384 strdmstod_2(gchar *nptr, gchar **endptr)
385 {
386     gint ret;
387     guchar *p;
388     gdouble d, m, s;
389
390     p = nptr;
391
392     /* degrees */
393     ret = strdmstod_1(&d, p, endptr, "dD@", 1);
394     switch (ret) {
395         case 0: return 0.0;
396         case 1:
397                 if (endptr) *endptr = (char *)nptr;
398                 return 0.0;
399         case 2: return d;
400     }
401
402     /* minutes */
403     p = *endptr;
404     m = 0.0;
405     ret = strdmstod_1(&m, p, endptr, "mM'", 0);
406     switch (ret) {
407         case 0: return 0.0;
408         case 1: return d;
409         case 2: return d + m/60.0;
410     }
411
412     /* seconds */
413     p = *endptr;
414     ret = strdmstod_1(&s, p, endptr, "sS\"", 0);
415     switch (ret) {
416         case 0: return 0.0;
417         case 1: return d + m/60.0;
418         case 2:
419         case 3: return d + m/60.0 + s/3600.0;
420     }
421
422     /* can't be here */
423     return 0.0;
424 }
425
426 /*
427  * format: / \s* [+-NSWE]? \s* ( d | D \s+ m | D \s+ M \s+ s ) [NSWE]? /x
428  * where D := / \d+[@d°]? /ix
429  *       M := / \d+['m]? /ix
430  *       d := / D | \d+[,.]\d+[@d°]? /ix
431  *       m := / M | \d+[,.]\d+['m]? /ix
432  *       s := / S | \d+[,.]\d+["s]? /ix
433  *
434  *   and N or W are treated as positive, S or E are treated as negative,
435  *   they may occur only once.
436  */
437 gdouble
438 strdmstod(const gchar *nptr, gchar **endptr)
439 {
440     gint s;
441     gchar *p, *end;
442     gchar *sign = 0;
443     gdouble d;
444
445     p = (char *)nptr;
446
447     while(*p && isspace(*p))
448         p++;
449
450     if(!*p) {
451         if(endptr)
452             *endptr = (char *)nptr;
453         return 0.0;
454     }
455
456     if(strchr("nwseNWSE-+", *p)) {
457         sign = p;
458         p++;
459     }
460
461     d = strdmstod_2(p, &end);
462     if(p == end && d == 0.0) {
463         if(endptr) *endptr = end;
464         return d;
465     }
466
467     p = end;
468     while(*p && isspace(*p))
469         p++;
470
471     s = 1;
472     if(sign == 0) {
473         if(*p && strchr("nwseNWSE", *p)) {
474             if(tolower(*p) == 's' || tolower(*p) == 'w')
475                 s = -1;
476             p++;
477         }
478     } else {
479         if(tolower(*sign) == 's' || tolower(*sign) == 'w' || *sign == '-')
480             s = -1;
481         printf("s: %d\n", s);
482     }
483
484     if(endptr) *endptr = p;
485     return s * d;
486 }
487
488 #if 0
489 struct t_case {
490     gchar *fmt;
491     gdouble value;
492 } t_cases[] = {
493     { "12°", 12 },
494     { "+12d", 12 },
495     { "-12.345d", -12.345 },
496     { "12.345 E", -12.345 },
497     { "12d34m", 12.5666667 },
498     { "N 12 34", 12.5666667 },
499     { "S 12d34.56m", -12.576 },
500     { "W 12 34.56", 12.576 },
501     { "E 12d34m56s", -12.582222 },
502     { "12 34 56 S", -12.582222 },
503     { "12 34 56", 12.582222 },
504     { "12d34m56.7s E", -12.582417 },
505     { "12 34 56.7 W", 12.582417 },
506     { "12° 34 56.7 W", 12.582417 },
507
508     { 0, 0 }
509 };
510
511 int
512 strdmstod_test()
513 {
514     struct t_case *t;
515     gint fail, ok;
516
517     fail = ok = 0;
518
519     for (t = t_cases; t->fmt; t++) {
520         gdouble v;
521         gchar *endp;
522
523         v = strdmstod(t->fmt, &endp);
524         if (endp == t->fmt || *endp != 0) {
525             fprintf(stderr, "FAIL syntax %s\n", t->fmt);
526             fail++;
527         } else if (fabs(v - t->value) > 0.000001) {
528             fprintf(stderr, "FAIL value %s -> %.10g (%.10g)\n",
529                     t->fmt, v, t->value);
530             fail++;
531         } else {
532             ok++;
533         }
534     }
535
536     if (fail == 0) {
537         fprintf(stderr, "ALL TESTS OK\n");
538     } else {
539         fprintf(stderr, "FAIL %d, OK %d\n", fail, ok);
540     }
541 }
542 #endif