Contents of /src/track.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Tue Dec 9 20:06:06 2008 UTC (15 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 16083 byte(s)
Initial import
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of OSM2Go.
5     *
6     * OSM2Go 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     * OSM2Go 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 OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include <libxml/parser.h>
21     #include <libxml/tree.h>
22    
23     #include "appdata.h"
24    
25     #ifndef LIBXML_TREE_ENABLED
26     #error "Tree not enabled in libxml"
27     #endif
28    
29     /* enable/disable menu with respect to mode */
30     void track_set_mode(appdata_t *appdata, track_t *track, track_mode_t mode) {
31     /* import and gps are always enabled */
32     const gboolean clear[] = { FALSE, TRUE, TRUE };
33     const gboolean export[] = { FALSE, FALSE, TRUE };
34    
35     gtk_widget_set_sensitive(appdata->track.menu_item_clear, clear[mode]);
36     gtk_widget_set_sensitive(appdata->track.menu_item_export, export[mode]);
37    
38     /* adjust menu item if required */
39     if((mode == TRACK_GPS) &&
40     !gtk_check_menu_item_get_active(
41     GTK_CHECK_MENU_ITEM(appdata->track.menu_item_gps)))
42     gtk_check_menu_item_set_active(
43     GTK_CHECK_MENU_ITEM(appdata->track.menu_item_gps), TRUE);
44    
45     if((mode != TRACK_GPS) &&
46     gtk_check_menu_item_get_active(
47     GTK_CHECK_MENU_ITEM(appdata->track.menu_item_gps)))
48     gtk_check_menu_item_set_active(
49     GTK_CHECK_MENU_ITEM(appdata->track.menu_item_gps), FALSE);
50    
51     if(track)
52     track->mode = mode;
53     }
54    
55     gint track_seg_points(track_seg_t *seg) {
56     gint points = 0;
57    
58     track_point_t *point = seg->track_point;
59     while(point) {
60     points++;
61     point = point->next;
62     }
63     return points;
64     }
65    
66     static gboolean track_get_prop_pos(xmlNode *node, pos_t *pos) {
67     char *str_lat = (char*)xmlGetProp(node, BAD_CAST "lat");
68     char *str_lon = (char*)xmlGetProp(node, BAD_CAST "lon");
69    
70     if(!str_lon || !str_lat) {
71     if(!str_lon) xmlFree(str_lon);
72     if(!str_lat) xmlFree(str_lat);
73     return FALSE;
74     }
75    
76     pos->lat = g_ascii_strtod(str_lat, NULL);
77     pos->lon = g_ascii_strtod(str_lon, NULL);
78    
79     xmlFree(str_lon);
80     xmlFree(str_lat);
81    
82     return TRUE;
83     }
84    
85     static track_point_t *track_parse_trkpt(bounds_t *bounds, xmlDocPtr doc,
86     xmlNode *a_node) {
87     track_point_t *point = NULL;
88     pos_t pos;
89    
90     /* parse position */
91     if(!track_get_prop_pos(a_node, &pos))
92     return NULL;
93    
94     point = g_new0(track_point_t, 1);
95    
96     pos2lpos(bounds, &pos, &point->lpos);
97    
98     /* check if point is within bounds */
99     if((point->lpos.x < bounds->min.x) || (point->lpos.x > bounds->max.x) ||
100     (point->lpos.y < bounds->min.y) || (point->lpos.y > bounds->max.y)) {
101     g_free(point);
102     point = NULL;
103     }
104    
105     return point;
106     }
107    
108     static void track_parse_trkseg(track_t *track, bounds_t *bounds,
109     xmlDocPtr doc, xmlNode *a_node) {
110     xmlNode *cur_node = NULL;
111     track_point_t **point = NULL;
112     track_seg_t **seg = &(track->track_seg);
113    
114     /* search end of track_seg list */
115     while(*seg) seg = &((*seg)->next);
116    
117     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
118     if (cur_node->type == XML_ELEMENT_NODE) {
119     if(strcasecmp((char*)cur_node->name, "trkpt") == 0) {
120     track_point_t *cpnt = track_parse_trkpt(bounds, doc, cur_node);
121     if(cpnt) {
122     if(!point) {
123     /* start a new segment */
124     *seg = g_new0(track_seg_t, 1);
125     point = &((*seg)->track_point);
126     }
127     /* attach point to chain */
128     *point = cpnt;
129     point = &((*point)->next);
130     } else {
131     /* end segment if point could not be parsed and start a new one */
132     /* close segment if there is one */
133     if(point) {
134     printf("ending track segment leaving bounds\n");
135     seg = &((*seg)->next);
136     point = NULL;
137     }
138     }
139     } else
140     printf("found unhandled gpx/trk/trkseg/%s\n", cur_node->name);
141    
142     }
143     }
144     }
145    
146     static track_t *track_parse_trk(bounds_t *bounds,
147     xmlDocPtr doc, xmlNode *a_node) {
148     track_t *track = g_new0(track_t, 1);
149     xmlNode *cur_node = NULL;
150    
151     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
152     if (cur_node->type == XML_ELEMENT_NODE) {
153     if(strcasecmp((char*)cur_node->name, "trkseg") == 0) {
154     track_parse_trkseg(track, bounds, doc, cur_node);
155     } else
156     printf("found unhandled gpx/trk/%s\n", cur_node->name);
157    
158     }
159     }
160     return track;
161     }
162    
163     static track_t *track_parse_gpx(bounds_t *bounds,
164     xmlDocPtr doc, xmlNode *a_node) {
165     track_t *track = NULL;
166     xmlNode *cur_node = NULL;
167    
168     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
169     if (cur_node->type == XML_ELEMENT_NODE) {
170     if(strcasecmp((char*)cur_node->name, "trk") == 0) {
171     if(!track)
172     track = track_parse_trk(bounds, doc, cur_node);
173     else
174     printf("ignoring additional track\n");
175     } else
176     printf("found unhandled gpx/%s\n", cur_node->name);
177     }
178     }
179     return track;
180     }
181    
182     /* parse root element and search for "track" */
183     static track_t *track_parse_root(bounds_t *bounds,
184     xmlDocPtr doc, xmlNode *a_node) {
185     track_t *track = NULL;
186     xmlNode *cur_node = NULL;
187    
188     for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
189     if (cur_node->type == XML_ELEMENT_NODE) {
190     /* parse track file ... */
191     if(strcasecmp((char*)cur_node->name, "gpx") == 0)
192     track = track_parse_gpx(bounds, doc, cur_node);
193     else
194     printf("found unhandled %s\n", cur_node->name);
195     }
196     }
197     return track;
198     }
199    
200     static track_t *track_parse_doc(bounds_t *bounds, xmlDocPtr doc) {
201     track_t *track;
202    
203     /* Get the root element node */
204     xmlNode *root_element = xmlDocGetRootElement(doc);
205    
206     track = track_parse_root(bounds, doc, root_element);
207    
208     /*free the document */
209     xmlFreeDoc(doc);
210    
211     /*
212     * Free the global variables that may
213     * have been allocated by the parser.
214     */
215     xmlCleanupParser();
216    
217     return track;
218     }
219    
220     void track_info(track_t *track) {
221     printf("Loaded track: %s\n", track->filename);
222     printf("Track has %sbeen saved in project.\n", track->saved?"":"not ");
223    
224     gint segs = 0, points = 0;
225     track_seg_t *seg = track->track_seg;
226     while(seg) {
227     points += track_seg_points(seg);
228     segs++;
229     seg = seg->next;
230     }
231    
232     printf("%d points in %d segments\n", points, segs);
233    
234     }
235    
236     static track_t *track_import(osm_t *osm, char *filename) {
237     printf("============================================================\n");
238     printf("loading track %s\n", filename);
239    
240     xmlDoc *doc = NULL;
241    
242     LIBXML_TEST_VERSION;
243    
244     /* parse the file and get the DOM */
245     if((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
246     xmlErrorPtr errP = xmlGetLastError();
247     errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message);
248     return NULL;
249     }
250    
251     track_t *track = track_parse_doc(osm->bounds, doc);
252     track->filename = g_strdup(filename);
253     track->saved = FALSE;
254    
255     track_info(track);
256    
257     return track;
258     }
259    
260     void track_point_free(track_point_t *point) {
261     g_free(point);
262     }
263    
264     void track_seg_free(track_seg_t *seg) {
265     track_point_t *point = seg->track_point;
266     while(point) {
267     track_point_t *next = point->next;
268     track_point_free(point);
269     point = next;
270     }
271    
272     g_free(seg);
273     }
274    
275     /* --------------------------------------------------------------- */
276    
277     static void track_clear(appdata_t *appdata, track_t *track) {
278     printf("clearing track\n");
279    
280     if(appdata->map)
281     map_track_remove(appdata);
282    
283     track_seg_t *seg = track->track_seg;
284     while(seg) {
285     track_seg_t *next = seg->next;
286     track_seg_free(seg);
287     seg = next;
288     }
289    
290     g_free(track->filename);
291     g_free(track);
292     }
293    
294     /* ---------------------- saving track --------------------------- */
295    
296     void track_save_points(track_point_t *point, xmlNodePtr node) {
297     while(point) {
298     xmlNodePtr node_point = xmlNewChild(node, NULL, BAD_CAST "point", NULL);
299    
300     char *str = g_strdup_printf("%d", point->lpos.x);
301     xmlNewProp(node_point, BAD_CAST "x", BAD_CAST str);
302     g_free(str);
303    
304     str = g_strdup_printf("%d", point->lpos.y);
305     xmlNewProp(node_point, BAD_CAST "y", BAD_CAST str);
306     g_free(str);
307    
308     point = point->next;
309     }
310     }
311    
312     void track_save_segs(track_seg_t *seg, xmlNodePtr node) {
313     while(seg) {
314     xmlNodePtr node_seg = xmlNewChild(node, NULL, BAD_CAST "seg", NULL);
315     track_save_points(seg->track_point, node_seg);
316     seg = seg->next;
317     }
318     }
319    
320     /* save track in project */
321     void track_save(project_t *project, track_t *track) {
322     if(!project) return;
323    
324     char *trk_name = g_strdup_printf("%s/%s.trk", project->path, project->name);
325    
326     if(!track) {
327     g_remove(trk_name);
328     g_free(trk_name);
329     return;
330     }
331    
332     /* no need to save again if it has already been saved */
333     if(track->saved) {
334     printf("track already saved, don't save it again\n");
335     g_free(trk_name);
336     return;
337     }
338    
339     printf("saving track\n");
340    
341     LIBXML_TEST_VERSION;
342    
343     xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
344     xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "trk");
345     xmlNewProp(root_node, BAD_CAST "filename", BAD_CAST track->filename);
346     char *mode_str = g_strdup_printf("%d", track->mode);
347     xmlNewProp(root_node, BAD_CAST "mode", BAD_CAST mode_str);
348     g_free(mode_str);
349     xmlDocSetRootElement(doc, root_node);
350    
351     track_save_segs(track->track_seg, root_node);
352    
353     xmlSaveFormatFileEnc(trk_name, doc, "UTF-8", 1);
354     xmlFreeDoc(doc);
355     xmlCleanupParser();
356    
357     g_free(trk_name);
358    
359     track->saved = TRUE;
360     }
361    
362     /* ---------------------- loading track --------------------------- */
363    
364     static int xml_get_prop_int(xmlNode *node, char *prop) {
365     char *str = (char*)xmlGetProp(node, BAD_CAST prop);
366     int value = 0;
367    
368     if(str) {
369     value = strtoul(str, NULL, 10);
370     xmlFree(str);
371     }
372    
373     return value;
374     }
375    
376     track_t *track_restore(appdata_t *appdata, project_t *project) {
377     char *trk_name = g_strdup_printf("%s/%s.trk", project->path, project->name);
378     track_t *track = NULL;
379    
380     LIBXML_TEST_VERSION;
381    
382     if(!g_file_test(trk_name, G_FILE_TEST_EXISTS)) {
383     printf("no track present!\n");
384     g_free(trk_name);
385     return NULL;
386     }
387    
388     printf("track found, loading ...\n");
389    
390     xmlDoc *doc = NULL;
391     xmlNode *root_element = NULL;
392    
393     /* parse the file and get the DOM */
394     if((doc = xmlReadFile(trk_name, NULL, 0)) == NULL) {
395     errorf(GTK_WIDGET(appdata->window),
396     "Error: could not parse file %s\n", trk_name);
397     g_free(trk_name);
398     return NULL;
399     }
400    
401     /* Get the root element node */
402     root_element = xmlDocGetRootElement(doc);
403    
404     xmlNode *cur_node = NULL;
405     for (cur_node = root_element; cur_node; cur_node = cur_node->next) {
406     if (cur_node->type == XML_ELEMENT_NODE) {
407     if(strcasecmp((char*)cur_node->name, "trk") == 0) {
408     printf("found track\n");
409    
410     track = g_new0(track_t, 1);
411     track->mode = xml_get_prop_int(cur_node, "mode");
412    
413     char *str = (char*)xmlGetProp(cur_node, BAD_CAST "filename");
414     if(str) {
415     track->filename = g_strdup(str);
416     xmlFree(str);
417     }
418    
419     xmlNodePtr seg_node = cur_node->children;
420     track_seg_t **seg = &track->track_seg;
421     while(seg_node) {
422     if(seg_node->type == XML_ELEMENT_NODE) {
423    
424     if(strcasecmp((char*)seg_node->name, "seg") == 0) {
425     *seg = g_new0(track_seg_t, 1);
426    
427     xmlNodePtr point_node = seg_node->children;
428     track_point_t **point = &(*seg)->track_point;
429     while(point_node) {
430     if(point_node->type == XML_ELEMENT_NODE) {
431    
432     if(strcasecmp((char*)point_node->name, "point") == 0) {
433     *point = g_new0(track_point_t, 1);
434     (*point)->lpos.x = xml_get_prop_int(point_node, "x");
435     (*point)->lpos.y = xml_get_prop_int(point_node, "y");
436    
437     point = &((*point)->next);
438     }
439     }
440     point_node = point_node->next;
441     }
442    
443     seg = &((*seg)->next);
444     }
445     }
446     seg_node = seg_node->next;
447     }
448     }
449     }
450     }
451    
452     g_free(trk_name);
453    
454     printf("restoring track mode %d\n", track->mode);
455     track_set_mode(appdata, track, track->mode);
456     track->saved = TRUE;
457     track_info(track);
458    
459     return track;
460     }
461    
462     static void track_end_segment(track_t *track) {
463     if(track->cur_seg) {
464     printf("ending a segment\n");
465    
466     /* todo: check if segment only has 1 point */
467    
468     track->cur_seg = NULL;
469     }
470     }
471    
472     static void track_append_position(appdata_t *appdata, pos_t *pos) {
473     track_t *track = appdata->track.track;
474    
475     if(!track->cur_seg) {
476     printf("starting new segment\n");
477    
478     track_seg_t **seg = &(track->track_seg);
479     while(*seg) seg = &((*seg)->next);
480    
481     *seg = track->cur_seg = g_new0(track_seg_t, 1);
482     } else
483     printf("appending to current segment\n");
484    
485     gint seg_len = 0;
486     track_point_t **point = &(track->cur_seg->track_point);
487     while(*point) { seg_len++; point = &((*point)->next); }
488    
489     /* create utm coordinates */
490     lpos_t lpos;
491     bounds_t *bounds = appdata->osm->bounds;
492     pos2lpos(bounds, pos, &lpos);
493    
494     /* check if point is within bounds */
495     if((lpos.x < bounds->min.x) || (lpos.x > bounds->max.x) ||
496     (lpos.y < bounds->min.y) || (lpos.y > bounds->max.y)) {
497     printf("position out of bounds\n");
498    
499     /* end segment */
500     track_end_segment(track);
501     map_track_pos(appdata, NULL);
502     } else {
503     map_track_pos(appdata, &lpos);
504    
505     /* don't append if point is the same as last time */
506     track_point_t *prev = track->cur_seg->track_point;
507     while(prev && prev->next) prev = prev->next;
508    
509     if(prev && prev->lpos.x == lpos.x && prev->lpos.y == lpos.y) {
510     printf("same value as last point -> ignore\n");
511     } else {
512    
513     *point = g_new0(track_point_t, 1);
514     (*point)->lpos.x = lpos.x;
515     (*point)->lpos.y = lpos.y;
516     track->saved = FALSE;
517    
518     /* if segment length was 1 the segment can now be drawn for the first time */
519     if(seg_len <= 1) {
520     printf("initial/second draw with seg_len %d\n", seg_len);
521    
522     if(seg_len == 0) g_assert(!track->cur_seg->item);
523     else g_assert(track->cur_seg->item);
524    
525     map_track_draw_seg(appdata->map, track->cur_seg);
526     }
527    
528     /* if segment length was > 1 the segment has to be updated */
529     if(seg_len > 1) {
530     printf("update draw\n");
531    
532     g_assert(track->cur_seg->item);
533     map_track_update_seg(appdata->map, track->cur_seg);
534     }
535     }
536     }
537     }
538    
539     static gboolean update(gpointer data) {
540     appdata_t *appdata = (appdata_t*)data;
541    
542     pos_t *pos = gps_get_pos(appdata);
543     if(pos) {
544     printf("valid position %f/%f\n", pos->lat, pos->lon);
545     track_append_position(appdata, pos);
546     } else {
547     printf("no valid position\n");
548     /* end segment */
549     track_end_segment(appdata->track.track);
550     map_track_pos(appdata, NULL);
551     }
552    
553     return TRUE;
554     }
555    
556     static void track_enable_gps(appdata_t *appdata) {
557     appdata->gps_enabled = TRUE;
558    
559     if(!appdata->track.handler_id) {
560     appdata->track.handler_id = gtk_timeout_add(1000, update, appdata);
561    
562     if(appdata->track.track) {
563     printf("there's already a track -> restored!!\n");
564     map_track_draw(appdata->map, appdata->track.track);
565     } else
566     appdata->track.track = g_new0(track_t, 1);
567     }
568     }
569    
570     static void track_disable_gps(appdata_t *appdata) {
571     appdata->gps_enabled = FALSE;
572    
573     if(appdata->track.handler_id) {
574     gtk_timeout_remove(appdata->track.handler_id);
575     appdata->track.handler_id = 0;
576     }
577     }
578    
579     void track_do(appdata_t *appdata, track_mode_t mode, char *name) {
580    
581     printf("track do %d\n", mode);
582    
583     /* remove existing track */
584     if(appdata->track.track) {
585     track_clear(appdata, appdata->track.track);
586     appdata->track.track = NULL;
587     map_track_pos(appdata, NULL);
588     }
589    
590     switch(mode) {
591     case TRACK_NONE:
592     /* disable gps if it was on */
593     track_disable_gps(appdata);
594    
595     track_set_mode(appdata, appdata->track.track, TRACK_NONE);
596     break;
597    
598     case TRACK_IMPORT:
599     /* disable gps if it was on */
600     track_disable_gps(appdata);
601    
602     appdata->track.track = track_import(appdata->osm, name);
603     map_track_draw(appdata->map, appdata->track.track);
604     track_set_mode(appdata, appdata->track.track, TRACK_IMPORT);
605     break;
606    
607     case TRACK_GPS:
608     track_enable_gps(appdata);
609    
610     track_set_mode(appdata, appdata->track.track, TRACK_GPS);
611     break;
612     }
613     }