Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Wed Jul 29 19:24:15 2009 UTC (14 years, 9 months ago) by harbaum
File MIME type: text/plain
File size: 10854 byte(s)
Invalid positions marked by NANs
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of GPXView.
5     *
6     * GPXView is free software: you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * GPXView is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include <math.h>
21     #include <string.h>
22     #include <ctype.h>
23    
24     #include "gpxview.h"
25    
26     char strlastchr(char *str) {
27     return str[strlen(str)]-1;
28     }
29    
30     /* make sure the entire path "dir" exists and create it if not */
31     int checkdir(char *dir) {
32     struct stat filestat;
33     char *p = dir, tmp;
34    
35     /* don't try to create root dir */
36     if(p[0] == '/') p++;
37    
38     do {
39     while(*p && *p != '/') p++;
40     tmp = *p;
41     *p = 0;
42    
43     int err = stat(dir, &filestat);
44     if(err) {
45     if(mkdir(dir, S_IRWXU) != 0) {
46     perror("mkdir()");
47     *p++ = tmp;
48     return -1;
49     }
50     } else {
51     if(!filestat.st_mode & S_IFDIR) {
52     printf("File %s exists and is _no_ directory\n", dir);
53     *p++ = tmp;
54     return -1;
55     }
56     }
57    
58     *p++ = tmp;
59     } while(tmp && strchr(p, '/'));
60    
61     return 0;
62     }
63    
64     void pos_lat_str(char *str, int len, float latitude) {
65     char *c = _("N");
66     float integral, fractional;
67    
68 harbaum 13 if(isnan(latitude))
69     str[0] = 0;
70     else {
71     if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
72     fractional = modff(latitude, &integral);
73 harbaum 1
74 harbaum 13 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
75     }
76 harbaum 1 }
77    
78     GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
79     char str[32];
80    
81     pos_lat_str(str, sizeof(str), latitude);
82     return gtk_label_attrib(str, size, strikethrough);
83     }
84    
85     void pos_lon_str(char *str, int len, float longitude) {
86     char *c = _("E");
87     float integral, fractional;
88    
89 harbaum 13 if(isnan(longitude))
90     str[0] = 0;
91     else {
92     if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
93     fractional = modff(longitude, &integral);
94 harbaum 1
95 harbaum 13 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
96     }
97 harbaum 1 }
98    
99     GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
100     char str[32];
101    
102     pos_lon_str(str, sizeof(str), longitude);
103     return gtk_label_attrib(str, size, strikethrough);
104     }
105    
106     float pos_parse_lat(char *str) {
107     int integral_int;
108     float fractional;
109     char c;
110    
111     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
112     c = toupper(c);
113    
114     if(c != 'S' && c != 'N')
115     return NAN;
116    
117     /* prevent -0.0 */
118     if(!integral_int && (fractional == 0.0))
119     return 0.0;
120    
121     return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
122     }
123    
124     return NAN;
125     }
126    
127     float pos_parse_lon(char *str) {
128     int integral_int;
129     float fractional;
130     char c;
131    
132     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
133     c = toupper(c);
134    
135     /* O is german "Ost" for "East" */
136     if(c != 'E' && c != 'W' && c != 'O')
137     return NAN;
138    
139     /* prevent -0.0 */
140     if(!integral_int && (fractional == 0.0))
141     return 0.0;
142    
143     return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
144     }
145    
146     return NAN;
147     }
148    
149     const char *pos_get_bearing_str(pos_t from, pos_t to) {
150     static const char *bear_str[]={
151     "N", "NE", "E", "SE", "S", "SW", "W", "NW" };
152     int idx = (gpx_pos_get_bearing(from, to)+22.5)/45.0;
153     /* make sure we stay in icon bounds */
154     while(idx < 0) idx += 8;
155     while(idx > 7) idx -= 8;
156     return _(bear_str[idx]);
157     }
158    
159     /* the maemo font size is quite huge, so we adjust some fonts */
160     /* differently on maemo and non-maemo. Basically "BIG" does nothing */
161     /* on maemo and "SMALL" only does something on maemo */
162     #ifdef USE_MAEMO
163     #define MARKUP_SMALL "<span size='small'>%s</span>"
164     GtkWidget *gtk_label_small(char *str) {
165     GtkWidget *label = gtk_label_new("");
166     char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
167     gtk_label_set_markup(GTK_LABEL(label), markup);
168     g_free(markup);
169     return label;
170     }
171     #else
172     #define MARKUP_BIG "<span size='x-large'>%s</span>"
173     GtkWidget *gtk_label_big(char *str) {
174     GtkWidget *label = gtk_label_new("");
175     char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
176     gtk_label_set_markup(GTK_LABEL(label), markup);
177     g_free(markup);
178     return label;
179     }
180     #endif
181    
182     void gtk_label_attrib_set(GtkWidget *label,
183     char *str, int size, int strikethrough) {
184     char format[80];
185    
186     snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
187     #ifdef USE_MAEMO
188     (size==SIZE_SMALL)?" size='small'":"",
189     #else
190     (size==SIZE_BIG)?" size='x-large'":"",
191     #endif
192     strikethrough?" strikethrough='yes'":"",
193     (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
194    
195     char *markup = g_markup_printf_escaped(format, str);
196     // printf("markup = %s\n", markup);
197     gtk_label_set_markup(GTK_LABEL(label), markup);
198     g_free(markup);
199     }
200    
201     GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
202     GtkWidget *label = gtk_label_new("");
203     gtk_label_attrib_set(label, str, size, strikethrough);
204     return label;
205     }
206    
207     GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
208     GtkWidget *button = gtk_button_new_with_label("");
209     gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
210     str, size, strikethrough);
211     return button;
212     }
213    
214     void textbox_disable(GtkWidget *widget) {
215     gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
216     gtk_widget_set_sensitive(widget, FALSE);
217     }
218    
219     void textbox_enable(GtkWidget *widget) {
220     gtk_widget_set_sensitive(widget, TRUE);
221     gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
222     }
223    
224     pos_t *get_pos(appdata_t *appdata) {
225     pos_t *pos = &appdata->home;
226    
227     if(appdata->active_location) {
228     int i = appdata->active_location-1;
229     location_t *loc = appdata->location;
230     while(i--) loc = loc->next;
231     pos = &loc->pos;
232     }
233    
234     if(appdata->use_gps) {
235     pos = gps_get_pos(appdata);
236    
237     if(!pos) pos = &appdata->gps; /* use saved position */
238     else appdata->gps = *pos; /* save position */
239     }
240     return pos;
241     }
242    
243     void distance_str(char *str, int len, float dist, gboolean imperial) {
244 harbaum 34 if(isnan(dist))
245     snprintf(str, len, "---");
246     else if(imperial) {
247 harbaum 1 /* 1 mil = 1760 yd = 5280 ft ... */
248     if(dist<0.018) snprintf(str, len, "%.1f ft", dist*5280.0);
249     else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
250     else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
251     else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
252     else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
253     else snprintf(str, len, "%.0f mi", dist);
254     } else {
255     if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
256     else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
257     else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
258     else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
259     else snprintf(str, len, "%.0f km", dist);
260     }
261     }
262    
263     /* return distance in miles or kilometers */
264     float distance_parse(char *str, gboolean imperial) {
265     char unit[4];
266     float val = NAN;
267    
268     if(sscanf(str, "%f %3s", &val, unit) == 2) {
269     gboolean fimp = FALSE;
270    
271     if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
272     else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
273     else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
274     else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
275     else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
276     else val = NAN;
277    
278     /* found imperial and metric requested? convert miles into kilometers */
279     if(fimp & !imperial) val *= 1.609344;
280    
281     /* found metric and imperial requested? convert kilometers into miles */
282     if(!fimp & imperial) val /= 1.609344;
283     }
284     return val;
285     }
286    
287     static gboolean mark(GtkWidget *widget, gboolean valid) {
288     gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
289     return valid;
290     }
291    
292     static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
293     float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
294     mark(widget, !isnan(i));
295     }
296    
297     /* a entry that is colored red when being "active" */
298     GtkWidget *lat_entry_new(float lat) {
299     GdkColor color;
300     GtkWidget *widget = gtk_entry_new();
301     gdk_color_parse("#ff0000", &color);
302     gtk_widget_modify_text(widget, TAG_STATE, &color);
303    
304     char str[32];
305     pos_lat_str(str, sizeof(str), lat);
306     gtk_entry_set_text(GTK_ENTRY(widget), str);
307    
308     g_signal_connect(G_OBJECT(widget), "changed",
309     G_CALLBACK(callback_modified_lat), NULL);
310    
311     return widget;
312     }
313    
314     static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
315     float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
316     mark(widget, !isnan(i));
317     }
318    
319     /* a entry that is colored red when filled with invalid coordinate */
320     GtkWidget *lon_entry_new(float lon) {
321     GdkColor color;
322     GtkWidget *widget = gtk_entry_new();
323     gdk_color_parse("#ff0000", &color);
324     gtk_widget_modify_text(widget, TAG_STATE, &color);
325    
326     char str[32];
327     pos_lon_str(str, sizeof(str), lon);
328     gtk_entry_set_text(GTK_ENTRY(widget), str);
329    
330     g_signal_connect(G_OBJECT(widget), "changed",
331     G_CALLBACK(callback_modified_lon), NULL);
332    
333     return widget;
334     }
335    
336    
337     float lat_get(GtkWidget *widget) {
338     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
339     return pos_parse_lat(p);
340     }
341    
342     float lon_get(GtkWidget *widget) {
343     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
344     return pos_parse_lon(p);
345     }
346    
347     static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
348     /* don't care for metric/imperial since we only want to know if this */
349     /* is parseable at all */
350     float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
351     mark(widget, !isnan(i));
352     }
353    
354     /* a entry that is colored red when filled with invalid distance */
355     GtkWidget *dist_entry_new(float dist, gboolean mil) {
356     GdkColor color;
357     GtkWidget *widget = gtk_entry_new();
358     gdk_color_parse("#ff0000", &color);
359     gtk_widget_modify_text(widget, TAG_STATE, &color);
360    
361     char str[32];
362     distance_str(str, sizeof(str), dist, mil);
363     gtk_entry_set_text(GTK_ENTRY(widget), str);
364    
365     g_signal_connect(G_OBJECT(widget), "changed",
366     G_CALLBACK(callback_modified_dist), NULL);
367    
368     return widget;
369     }
370    
371     float dist_get(GtkWidget *widget, gboolean mil) {
372     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
373     return distance_parse(p, mil);
374     }
375    
376     #ifndef USE_MAEMO
377     #ifdef ENABLE_BROWSER_INTERFACE
378     #include <libgnome/gnome-url.h>
379    
380     int browser_url(appdata_t *appdata, char *url) {
381     /* taken from gnome-open, part of libgnome */
382     GError *err = NULL;
383     gnome_url_show(url, &err);
384     return 0;
385     }
386     #endif
387     #endif