Contents of /trunk/src/osm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 76 - (hide annotations)
Fri Feb 13 12:02:26 2009 UTC (15 years, 3 months ago) by harbaum
File MIME type: text/plain
File size: 72520 byte(s)
Global relation handling
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 harbaum 42 /* these defines select one of three possible xml parsers */
21     /* this is in fact selected depending on the plattform in the Makefile */
22 harbaum 39 // #define OSM_DOM_PARSER
23     // #define OSM_STREAM_PARSER
24 harbaum 8
25 harbaum 1 #include <stdio.h>
26     #include <stdlib.h>
27     #include <string.h>
28     #include <math.h>
29    
30     #define __USE_XOPEN
31     #include <time.h>
32    
33     #include <libxml/parser.h>
34     #include <libxml/tree.h>
35    
36     #include "appdata.h"
37 achadwick 28 #include "banner.h"
38 harbaum 1
39     #ifndef LIBXML_TREE_ENABLED
40     #error "Tree not enabled in libxml"
41     #endif
42    
43     /* determine where a node/way/relation read from the osm file */
44     /* is inserted into the internal database */
45     // #define OSM_SORT_ID
46     #define OSM_SORT_LAST
47     // #define OSM_SORT_FIRST
48    
49 harbaum 9 /* ------------------------- bounds handling --------------------- */
50 harbaum 1
51     static void osm_bounds_free(bounds_t *bounds) {
52     free(bounds);
53     }
54    
55     static void osm_bounds_dump(bounds_t *bounds) {
56     printf("\nBounds: %f->%f %f->%f\n",
57     bounds->ll_min.lat, bounds->ll_max.lat,
58     bounds->ll_min.lon, bounds->ll_max.lon);
59     }
60    
61 harbaum 39 #ifdef OSM_DOM_PARSER
62 harbaum 1 static bounds_t *osm_parse_osm_bounds(osm_t *osm,
63     xmlDocPtr doc, xmlNode *a_node) {
64     char *prop;
65    
66     if(osm->bounds) {
67     errorf(NULL, "Doubly defined bounds");
68     return NULL;
69     }
70    
71     bounds_t *bounds = g_new0(bounds_t, 1);
72    
73     bounds->ll_min.lat = bounds->ll_min.lon = NAN;
74     bounds->ll_max.lat = bounds->ll_max.lon = NAN;
75    
76     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlat"))) {
77     bounds->ll_min.lat = g_ascii_strtod(prop, NULL);
78     xmlFree(prop);
79     }
80    
81     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlat"))) {
82     bounds->ll_max.lat = g_ascii_strtod(prop, NULL);
83     xmlFree(prop);
84     }
85    
86     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlon"))) {
87     bounds->ll_min.lon = g_ascii_strtod(prop, NULL);
88     xmlFree(prop);
89     }
90    
91     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlon"))) {
92     bounds->ll_max.lon = g_ascii_strtod(prop, NULL);
93     xmlFree(prop);
94     }
95    
96     if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
97     isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
98     errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
99     bounds->ll_min.lat, bounds->ll_min.lon,
100     bounds->ll_max.lat, bounds->ll_max.lon);
101    
102 harbaum 8 osm_bounds_free(bounds);
103 harbaum 1 return NULL;
104     }
105    
106    
107     /* calculate map zone which will be used as a reference for all */
108     /* drawing/projection later on */
109     pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
110     (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
111    
112     pos2lpos_center(&center, &bounds->center);
113    
114     /* the scale is needed to accomodate for "streching" */
115     /* by the mercartor projection */
116     bounds->scale = cos(DEG2RAD(center.lat));
117    
118     pos2lpos_center(&bounds->ll_min, &bounds->min);
119     bounds->min.x -= bounds->center.x;
120     bounds->min.y -= bounds->center.y;
121     bounds->min.x *= bounds->scale;
122     bounds->min.y *= bounds->scale;
123    
124     pos2lpos_center(&bounds->ll_max, &bounds->max);
125     bounds->max.x -= bounds->center.x;
126     bounds->max.y -= bounds->center.y;
127     bounds->max.x *= bounds->scale;
128     bounds->max.y *= bounds->scale;
129    
130     return bounds;
131     }
132 harbaum 8 #endif
133 harbaum 1
134     /* ------------------------- user handling --------------------- */
135    
136     void osm_users_free(user_t *user) {
137     while(user) {
138     user_t *next = user->next;
139    
140     if(user->name) g_free(user->name);
141     g_free(user);
142    
143     user = next;
144     }
145     }
146    
147     void osm_users_dump(user_t *user) {
148     printf("\nUser list:\n");
149     while(user) {
150     printf("Name: %s\n", user->name);
151     user = user->next;
152     }
153     }
154    
155     static user_t *osm_user(osm_t *osm, char *name) {
156 harbaum 39 if(!name) return NULL;
157 harbaum 1
158     /* search through user list */
159     user_t **user = &osm->user;
160     while(*user && strcasecmp((*user)->name, name) < 0)
161     user = &(*user)->next;
162    
163     /* end of list or inexact match? create new user entry! */
164     if(!*user || strcasecmp((*user)->name, name)) {
165     user_t *new = g_new0(user_t, 1);
166     new->name = g_strdup(name);
167     new->next = *user;
168     *user = new;
169    
170     return new;
171     }
172    
173     return *user;
174     }
175    
176     static
177     time_t convert_iso8601(const char *str) {
178 harbaum 39 if(!str) return 0;
179    
180 harbaum 1 tzset();
181    
182     struct tm ctime;
183     memset(&ctime, 0, sizeof(struct tm));
184     strptime(str, "%FT%T%z", &ctime);
185    
186     return mktime(&ctime) - timezone;
187     }
188    
189     /* -------------------- tag handling ----------------------- */
190    
191     void osm_tag_free(tag_t *tag) {
192     if(tag->key) g_free(tag->key);
193     if(tag->value) g_free(tag->value);
194     g_free(tag);
195     }
196    
197     void osm_tags_free(tag_t *tag) {
198     while(tag) {
199     tag_t *next = tag->next;
200     osm_tag_free(tag);
201     tag = next;
202     }
203     }
204    
205     static void osm_tags_dump(tag_t *tag) {
206     while(tag) {
207     printf("Key/Val: %s/%s\n", tag->key, tag->value);
208     tag = tag->next;
209     }
210     }
211    
212     tag_t *osm_parse_osm_tag(osm_t *osm, xmlDocPtr doc, xmlNode *a_node) {
213     xmlNode *cur_node = NULL;
214    
215     /* allocate a new tag structure */
216     tag_t *tag = g_new0(tag_t, 1);
217    
218     char *prop;
219     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"k"))) {
220     if(strlen(prop) > 0) tag->key = g_strdup(prop);
221     xmlFree(prop);
222     }
223    
224     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"v"))) {
225     if(strlen(prop) > 0) tag->value = g_strdup(prop);
226     xmlFree(prop);
227     }
228    
229     if(!tag->key || !tag->value) {
230     printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
231     osm_tags_free(tag);
232     return NULL;
233     }
234    
235     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next)
236     if (cur_node->type == XML_ELEMENT_NODE)
237     printf("found unhandled osm/node/tag/%s\n", cur_node->name);
238    
239     return tag;
240     }
241    
242     gboolean osm_is_creator_tag(tag_t *tag) {
243     if(strcasecmp(tag->key, "created_by") == 0) return TRUE;
244     if(strcasecmp(tag->key, "source") == 0) return TRUE;
245    
246     return FALSE;
247     }
248    
249     gboolean osm_tag_key_and_value_present(tag_t *haystack, tag_t *tag) {
250     while(haystack) {
251     if((strcasecmp(haystack->key, tag->key) == 0) &&
252     (strcasecmp(haystack->value, tag->value) == 0))
253     return TRUE;
254    
255     haystack = haystack->next;
256     }
257     return FALSE;
258     }
259    
260     gboolean osm_tag_key_other_value_present(tag_t *haystack, tag_t *tag) {
261     while(haystack) {
262     if((strcasecmp(haystack->key, tag->key) == 0) &&
263     (strcasecmp(haystack->value, tag->value) != 0))
264     return TRUE;
265    
266     haystack = haystack->next;
267     }
268     return FALSE;
269     }
270    
271     gboolean osm_way_ends_with_node(way_t *way, node_t *node) {
272     /* and deleted way may even not contain any nodes at all */
273     /* so ignore it */
274     if(way->flags & OSM_FLAG_DELETED)
275     return FALSE;
276    
277     /* any valid way must have at least two nodes */
278     g_assert(way->node_chain && way->node_chain->next);
279    
280     node_chain_t *chain = way->node_chain;
281     if(chain->node == node) return TRUE;
282    
283     while(chain->next) chain = chain->next;
284     if(chain->node == node) return TRUE;
285    
286     return FALSE;
287     }
288    
289     /* ------------------- node handling ------------------- */
290    
291     void osm_node_free(icon_t **icon, node_t *node) {
292     if(node->icon_buf)
293     icon_free(icon, node->icon_buf);
294    
295     /* there must not be anything left in this chain */
296     g_assert(!node->map_item_chain);
297    
298     osm_tags_free(node->tag);
299     g_free(node);
300     }
301    
302     static void osm_nodes_free(icon_t **icon, node_t *node) {
303     while(node) {
304     node_t *next = node->next;
305     osm_node_free(icon, node);
306     node = next;
307     }
308     }
309    
310     void osm_node_dump(node_t *node) {
311     char buf[64];
312     struct tm tm;
313    
314     printf("Id: %lu\n", node->id);
315     printf("User: %s\n", node->user?node->user->name:"<unspecified>");
316     printf("Visible: %s\n", node->visible?"yes":"no");
317    
318     localtime_r(&node->time, &tm);
319     strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", &tm);
320     printf("Time: %s\n", buf);
321     osm_tags_dump(node->tag);
322     }
323    
324     void osm_nodes_dump(node_t *node) {
325     printf("\nNode list:\n");
326     while(node) {
327     osm_node_dump(node);
328     printf("\n");
329     node = node->next;
330     }
331     }
332    
333 harbaum 39 #ifdef OSM_DOM_PARSER
334 harbaum 1 static node_t *osm_parse_osm_node(osm_t *osm,
335     xmlDocPtr doc, xmlNode *a_node) {
336     xmlNode *cur_node = NULL;
337    
338     /* allocate a new node structure */
339     node_t *node = g_new0(node_t, 1);
340     node->pos.lat = node->pos.lon = NAN;
341    
342     char *prop;
343     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {
344     node->id = strtoul(prop, NULL, 10);
345     xmlFree(prop);
346     }
347    
348     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lat"))) {
349     node->pos.lat = g_ascii_strtod(prop, NULL);
350     xmlFree(prop);
351     }
352    
353     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lon"))) {
354     node->pos.lon = g_ascii_strtod(prop, NULL);
355     xmlFree(prop);
356     }
357    
358     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {
359     node->user = osm_user(osm, prop);
360     xmlFree(prop);
361     }
362    
363     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {
364     node->visible = (strcasecmp(prop, "true") == 0);
365     xmlFree(prop);
366     }
367    
368     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {
369     node->time = convert_iso8601(prop);
370     xmlFree(prop);
371     }
372    
373 harbaum 42 /* append node to end of hash table if present */
374     if(osm->node_hash) {
375     hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
376     while(*item) item = &(*item)->next;
377    
378     *item = g_new0(hash_item_t, 1);
379     (*item)->data.node = node;
380     }
381    
382 harbaum 1 /* scan for tags and attach a list of tags */
383     tag_t **tag = &node->tag;
384     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
385     if (cur_node->type == XML_ELEMENT_NODE) {
386     if(strcasecmp((char*)cur_node->name, "tag") == 0) {
387     /* attach tag to node */
388     *tag = osm_parse_osm_tag(osm, doc, cur_node);
389     if(*tag) tag = &((*tag)->next);
390     } else
391     printf("found unhandled osm/node/%s\n", cur_node->name);
392     }
393     }
394    
395     pos2lpos(osm->bounds, &node->pos, &node->lpos);
396    
397     return node;
398     }
399 harbaum 8 #endif
400 harbaum 1
401     /* ------------------- way handling ------------------- */
402    
403     void osm_node_chain_free(node_chain_t *node_chain) {
404     while(node_chain) {
405     g_assert(node_chain->node->ways);
406    
407     node_chain_t *next = node_chain->next;
408     node_chain->node->ways--;
409     g_free(node_chain);
410     node_chain = next;
411     }
412     }
413    
414     void osm_way_free(way_t *way) {
415     // printf("freeing way #%ld\n", way->id);
416    
417     osm_node_chain_free(way->node_chain);
418     osm_tags_free(way->tag);
419    
420     /* there must not be anything left in this chain */
421     g_assert(!way->map_item_chain);
422    
423     g_free(way);
424     }
425    
426     static void osm_ways_free(way_t *way) {
427     while(way) {
428     way_t *next = way->next;
429     osm_way_free(way);
430     way = next;
431     }
432     }
433    
434     void osm_way_append_node(way_t *way, node_t *node) {
435     node_chain_t **node_chain = &way->node_chain;
436    
437     while(*node_chain)
438     node_chain = &((*node_chain)->next);
439    
440     *node_chain = g_new0(node_chain_t, 1);
441     (*node_chain)->node = node;
442    
443     node->ways++;
444     }
445    
446     int osm_node_chain_length(node_chain_t *node_chain) {
447     int cnt = 0;
448     while(node_chain) {
449     cnt++;
450     node_chain = node_chain->next;
451     }
452    
453     return cnt;
454     }
455    
456     void osm_way_dump(way_t *way) {
457     char buf[64];
458     struct tm tm;
459    
460     printf("Id: %lu\n", way->id);
461     printf("User: %s\n", way->user?way->user->name:"<unspecified>");
462     printf("Visible: %s\n", way->visible?"yes":"no");
463     node_chain_t *node_chain = way->node_chain;
464     while(node_chain) {
465     printf(" Node: %lu\n", node_chain->node->id);
466     node_chain = node_chain->next;
467     }
468    
469     localtime_r(&way->time, &tm);
470     strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", &tm);
471     printf("Time: %s\n", buf);
472     osm_tags_dump(way->tag);
473     }
474    
475     void osm_ways_dump(way_t *way) {
476     printf("\nWay list:\n");
477     while(way) {
478     osm_way_dump(way);
479     printf("\n");
480     way = way->next;
481     }
482     }
483    
484     node_chain_t *osm_parse_osm_way_nd(osm_t *osm,
485     xmlDocPtr doc, xmlNode *a_node) {
486     char *prop;
487    
488     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) {
489     item_id_t id = strtoul(prop, NULL, 10);
490     node_chain_t *node_chain = g_new0(node_chain_t, 1);
491    
492     /* search matching node */
493 harbaum 42 node_chain->node = osm_get_node_by_id(osm, id);
494 harbaum 1 if(!node_chain->node) printf("Node id %lu not found\n", id);
495 harbaum 42 else node_chain->node->ways++;
496 harbaum 1
497     xmlFree(prop);
498    
499     return node_chain;
500     }
501    
502     return NULL;
503     }
504    
505 harbaum 39 #ifdef OSM_DOM_PARSER
506 harbaum 1 static way_t *osm_parse_osm_way(osm_t *osm,
507     xmlDocPtr doc, xmlNode *a_node) {
508     xmlNode *cur_node = NULL;
509    
510     /* allocate a new way structure */
511     way_t *way = g_new0(way_t, 1);
512    
513     char *prop;
514     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {
515     way->id = strtoul(prop, NULL, 10);
516     xmlFree(prop);
517     }
518    
519     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {
520     way->user = osm_user(osm, prop);
521     xmlFree(prop);
522     }
523    
524     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {
525     way->visible = (strcasecmp(prop, "true") == 0);
526     xmlFree(prop);
527     }
528    
529     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {
530     way->time = convert_iso8601(prop);
531     xmlFree(prop);
532     }
533    
534 harbaum 42 /* append way to end of hash table if present */
535     if(osm->way_hash) {
536     hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
537     while(*item) item = &(*item)->next;
538    
539     *item = g_new0(hash_item_t, 1);
540     (*item)->data.way = way;
541     }
542    
543 harbaum 1 /* scan for tags/nodes and attach their lists */
544     tag_t **tag = &way->tag;
545     node_chain_t **node_chain = &way->node_chain;
546    
547     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
548     if (cur_node->type == XML_ELEMENT_NODE) {
549     if(strcasecmp((char*)cur_node->name, "tag") == 0) {
550     /* attach tag to node */
551     *tag = osm_parse_osm_tag(osm, doc, cur_node);
552     if(*tag) tag = &((*tag)->next);
553     } else if(strcasecmp((char*)cur_node->name, "nd") == 0) {
554     *node_chain = osm_parse_osm_way_nd(osm, doc, cur_node);
555     if(*node_chain)
556     node_chain = &((*node_chain)->next);
557     } else
558     printf("found unhandled osm/node/%s\n", cur_node->name);
559     }
560     }
561    
562     return way;
563     }
564 harbaum 8 #endif
565 harbaum 1
566     /* ------------------- relation handling ------------------- */
567    
568     void osm_member_free(member_t *member) {
569     if(member->role) g_free(member->role);
570     g_free(member);
571     }
572    
573     void osm_members_free(member_t *member) {
574     while(member) {
575     member_t *next = member->next;
576     osm_member_free(member);
577     member = next;
578     }
579     }
580    
581 harbaum 73 void osm_relation_free(relation_t *relation) {
582     osm_tags_free(relation->tag);
583     osm_members_free(relation->member);
584    
585     g_free(relation);
586     }
587    
588 harbaum 1 static void osm_relations_free(relation_t *relation) {
589     while(relation) {
590     relation_t *next = relation->next;
591 harbaum 73 osm_relation_free(relation);
592 harbaum 1 relation = next;
593     }
594     }
595    
596     void osm_relations_dump(relation_t *relation) {
597     printf("\nRelation list:\n");
598     while(relation) {
599     char buf[64];
600     struct tm tm;
601    
602     printf("Id: %lu\n", relation->id);
603     printf("User: %s\n",
604     relation->user?relation->user->name:"<unspecified>");
605     printf("Visible: %s\n", relation->visible?"yes":"no");
606    
607     member_t *member = relation->member;
608     while(member) {
609     switch(member->type) {
610     case ILLEGAL:
611     case NODE_ID:
612     case WAY_ID:
613     case RELATION_ID:
614     break;
615    
616     case NODE:
617     if(member->node)
618     printf(" Member: Node, id = %lu, role = %s\n",
619     member->node->id, member->role);
620     break;
621    
622     case WAY:
623     if(member->way)
624     printf(" Member: Way, id = %lu, role = %s\n",
625     member->way->id, member->role);
626     break;
627    
628     case RELATION:
629     if(member->relation)
630     printf(" Member: Relation, id = %lu, role = %s\n",
631     member->relation->id, member->role);
632     break;
633     }
634    
635     member = member->next;
636     }
637    
638     localtime_r(&relation->time, &tm);
639     strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", &tm);
640     printf("Time: %s\n", buf);
641     osm_tags_dump(relation->tag);
642    
643     printf("\n");
644     relation = relation->next;
645     }
646     }
647    
648     member_t *osm_parse_osm_relation_member(osm_t *osm,
649     xmlDocPtr doc, xmlNode *a_node) {
650     char *prop;
651     member_t *member = g_new0(member_t, 1);
652     member->type = ILLEGAL;
653    
654     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"type"))) {
655     if(strcasecmp(prop, "way") == 0) member->type = WAY;
656     else if(strcasecmp(prop, "node") == 0) member->type = NODE;
657     else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;
658     xmlFree(prop);
659     }
660    
661     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) {
662     item_id_t id = strtoul(prop, NULL, 10);
663    
664     switch(member->type) {
665     case ILLEGAL:
666     printf("Unable to store illegal type\n");
667     break;
668    
669     case WAY:
670     /* search matching way */
671 harbaum 42 member->way = osm_get_way_by_id(osm, id);
672 harbaum 1 if(!member->way) {
673     member->type = WAY_ID;
674     member->id = id;
675     }
676     break;
677    
678     case NODE:
679     /* search matching node */
680 harbaum 42 member->node = osm_get_node_by_id(osm, id);
681 harbaum 1 if(!member->node) {
682     member->type = NODE_ID;
683     member->id = id;
684     }
685     break;
686    
687     case RELATION:
688     /* search matching relation */
689 harbaum 42 member->relation = osm_get_relation_by_id(osm, id);
690 harbaum 1 if(!member->relation) {
691     member->type = NODE_ID;
692     member->id = id;
693     }
694     break;
695    
696     case WAY_ID:
697     case NODE_ID:
698     case RELATION_ID:
699     break;
700     }
701    
702     xmlFree(prop);
703     }
704    
705     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"role"))) {
706     if(strlen(prop) > 0) member->role = g_strdup(prop);
707     xmlFree(prop);
708     }
709    
710     return member;
711     }
712    
713 harbaum 39 #ifdef OSM_DOM_PARSER
714 harbaum 1 static relation_t *osm_parse_osm_relation(osm_t *osm,
715     xmlDocPtr doc, xmlNode *a_node) {
716     xmlNode *cur_node = NULL;
717    
718     /* allocate a new relation structure */
719     relation_t *relation = g_new0(relation_t, 1);
720    
721     char *prop;
722     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {
723     relation->id = strtoul(prop, NULL, 10);
724     xmlFree(prop);
725     }
726    
727     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {
728     relation->user = osm_user(osm, prop);
729     xmlFree(prop);
730     }
731    
732     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {
733     relation->visible = (strcasecmp(prop, "true") == 0);
734     xmlFree(prop);
735     }
736    
737     if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {
738     relation->time = convert_iso8601(prop);
739     xmlFree(prop);
740     }
741    
742     /* scan for tags and attach a list of tags */
743     tag_t **tag = &relation->tag;
744     member_t **member = &relation->member;
745    
746     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
747     if (cur_node->type == XML_ELEMENT_NODE) {
748     if(strcasecmp((char*)cur_node->name, "tag") == 0) {
749     /* attach tag to node */
750     *tag = osm_parse_osm_tag(osm, doc, cur_node);
751     if(*tag) tag = &((*tag)->next);
752     } else if(strcasecmp((char*)cur_node->name, "member") == 0) {
753     *member = osm_parse_osm_relation_member(osm, doc, cur_node);
754     if(*member) member = &((*member)->next);
755     } else
756     printf("found unhandled osm/node/%s\n", cur_node->name);
757     }
758     }
759    
760     return relation;
761     }
762    
763     /* ----------------------- generic xml handling -------------------------- */
764    
765 harbaum 42 /* parse osm entry */
766 harbaum 1 static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) {
767     xmlNode *cur_node = NULL;
768    
769     for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
770     if (cur_node->type == XML_ELEMENT_NODE) {
771     if(strcasecmp((char*)cur_node->name, "bounds") == 0)
772     osm->bounds = osm_parse_osm_bounds(osm, doc, cur_node);
773     else if(strcasecmp((char*)cur_node->name, "node") == 0) {
774     /* parse node and attach it to chain */
775     node_t *new = osm_parse_osm_node(osm, doc, cur_node);
776     if(new) {
777     node_t **node = &osm->node;
778    
779     #ifdef OSM_SORT_ID
780     /* search chain of nodes */
781     while(*node && ((*node)->id < new->id))
782     node = &(*node)->next;
783     #endif
784    
785     #ifdef OSM_SORT_LAST
786     while(*node) node = &(*node)->next;
787     #endif
788    
789     /* insert into chain */
790     new->next = *node;
791     *node = new;
792     }
793     } else if(strcasecmp((char*)cur_node->name, "way") == 0) {
794     /* parse way and attach it to chain */
795     way_t *new = osm_parse_osm_way(osm, doc, cur_node);
796     if(new) {
797     way_t **way = &osm->way;
798    
799     #ifdef OSM_SORT_ID
800     /* insert into chain */
801     while(*way && ((*way)->id < new->id))
802     way = &(*way)->next;
803     #endif
804    
805     #ifdef OSM_SORT_LAST
806     while(*way) way = &(*way)->next;
807     #endif
808    
809     /* insert into chain */
810     new->next = *way;
811     *way = new;
812     }
813     } else if(strcasecmp((char*)cur_node->name, "relation") == 0) {
814     /* parse relation and attach it to chain */
815     relation_t *new = osm_parse_osm_relation(osm, doc, cur_node);
816     if(new) {
817     relation_t **relation = &osm->relation;
818    
819     #ifdef OSM_SORT_ID
820     /* search chain of ways */
821     while(*relation && ((*relation)->id < new->id))
822     relation = &(*relation)->next;
823     #endif
824    
825     #ifdef OSM_SORT_LAST
826     while(*relation) relation = &(*relation)->next;
827     #endif
828    
829     /* insert into chain */
830     new->next = *relation;
831     *relation = new;
832     }
833     } else
834     printf("found unhandled osm/%s\n", cur_node->name);
835    
836     }
837     }
838     }
839    
840     /* parse root element and search for "osm" */
841     static osm_t *osm_parse_root(xmlDocPtr doc, xmlNode * a_node) {
842     osm_t *osm;
843     xmlNode *cur_node = NULL;
844    
845     /* allocate memory to hold osm file description */
846     osm = g_new0(osm_t, 1);
847 harbaum 42 osm->node_hash = g_new0(hash_table_t, 1);
848     osm->way_hash = g_new0(hash_table_t, 1);
849 harbaum 1
850     for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
851     if (cur_node->type == XML_ELEMENT_NODE) {
852     /* parse osm osm file ... */
853     if(strcasecmp((char*)cur_node->name, "osm") == 0)
854     osm_parse_osm(osm, doc, cur_node);
855     else
856     printf("found unhandled %s\n", cur_node->name);
857     }
858     }
859    
860     return osm;
861     }
862    
863     static osm_t *osm_parse_doc(xmlDocPtr doc) {
864     osm_t *osm;
865    
866     /* Get the root element node */
867     xmlNode *root_element = xmlDocGetRootElement(doc);
868    
869     osm = osm_parse_root(doc, root_element);
870    
871     /*free the document */
872     xmlFreeDoc(doc);
873    
874     /*
875     * Free the global variables that may
876     * have been allocated by the parser.
877     */
878     xmlCleanupParser();
879    
880     return osm;
881     }
882 harbaum 8 #endif
883 harbaum 1
884     /* ------------------ osm handling ----------------- */
885    
886 harbaum 42 /* the two hash tables eat over 512kBytes memory and may thus be */
887     /* freed at any time. osm2go can work without them (albeit slower) */
888     static void hash_table_free(hash_table_t *table) {
889     if(!table) return;
890    
891     int i;
892     for(i=0;i<65536;i++) {
893     hash_item_t *item = table->hash[i];
894     while(item) {
895     hash_item_t *next = item->next;
896     g_free(item);
897     item = next;
898     }
899     }
900     }
901    
902     void osm_hash_tables_free(osm_t *osm) {
903     hash_table_free(osm->node_hash);
904     osm->node_hash = NULL;
905     hash_table_free(osm->way_hash);
906     osm->way_hash = NULL;
907     }
908    
909 harbaum 1 void osm_free(icon_t **icon, osm_t *osm) {
910     if(!osm) return;
911    
912 harbaum 42 osm_hash_tables_free(osm);
913    
914 harbaum 1 if(osm->bounds) osm_bounds_free(osm->bounds);
915     if(osm->user) osm_users_free(osm->user);
916     if(osm->way) osm_ways_free(osm->way);
917     if(osm->node) osm_nodes_free(icon, osm->node);
918     if(osm->relation) osm_relations_free(osm->relation);
919     g_free(osm);
920     }
921    
922     void osm_dump(osm_t *osm) {
923     osm_bounds_dump(osm->bounds);
924     osm_users_dump(osm->user);
925     osm_nodes_dump(osm->node);
926     osm_ways_dump(osm->way);
927     osm_relations_dump(osm->relation);
928     }
929    
930 harbaum 8 #ifdef OSM_STREAM_PARSER
931     /* -------------------------- stream parser tests ------------------- */
932    
933     #include <libxml/xmlreader.h>
934    
935     static gint my_strcmp(const xmlChar *a, const xmlChar *b) {
936     if(!a && !b) return 0;
937     if(!a) return -1;
938     if(!b) return +1;
939     return strcmp((char*)a,(char*)b);
940     }
941    
942     /* skip current element incl. everything below (mainly for testing) */
943     /* returns FALSE if something failed */
944     static gboolean skip_element(xmlTextReaderPtr reader) {
945     g_assert(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT);
946     const xmlChar *name = xmlTextReaderConstName(reader);
947     g_assert(name);
948     int depth = xmlTextReaderDepth(reader);
949    
950     if(xmlTextReaderIsEmptyElement(reader))
951     return TRUE;
952    
953     int ret = xmlTextReaderRead(reader);
954     while((ret == 1) &&
955     ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
956     (xmlTextReaderDepth(reader) > depth) ||
957     (my_strcmp(xmlTextReaderConstName(reader), name) != 0))) {
958     ret = xmlTextReaderRead(reader);
959     }
960     return(ret == 1);
961     }
962    
963     /* parse bounds */
964     static bounds_t *process_bounds(xmlTextReaderPtr reader) {
965     char *prop = NULL;
966     bounds_t *bounds = g_new0(bounds_t, 1);
967    
968     bounds->ll_min.lat = bounds->ll_min.lon = NAN;
969     bounds->ll_max.lat = bounds->ll_max.lon = NAN;
970    
971     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "minlat"))) {
972     bounds->ll_min.lat = g_ascii_strtod(prop, NULL);
973     xmlFree(prop);
974     }
975    
976     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "maxlat"))) {
977     bounds->ll_max.lat = g_ascii_strtod(prop, NULL);
978     xmlFree(prop);
979     }
980    
981     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "minlon"))) {
982     bounds->ll_min.lon = g_ascii_strtod(prop, NULL);
983     xmlFree(prop);
984     }
985    
986     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "maxlon"))) {
987     bounds->ll_max.lon = g_ascii_strtod(prop, NULL);
988     xmlFree(prop);
989     }
990    
991     if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
992     isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
993     errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
994     bounds->ll_min.lat, bounds->ll_min.lon,
995     bounds->ll_max.lat, bounds->ll_max.lon);
996    
997     osm_bounds_free(bounds);
998     return NULL;
999     }
1000    
1001     /* skip everything below */
1002     skip_element(reader);
1003    
1004     /* calculate map zone which will be used as a reference for all */
1005     /* drawing/projection later on */
1006     pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1007     (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1008    
1009     pos2lpos_center(&center, &bounds->center);
1010    
1011     /* the scale is needed to accomodate for "streching" */
1012     /* by the mercartor projection */
1013     bounds->scale = cos(DEG2RAD(center.lat));
1014    
1015     pos2lpos_center(&bounds->ll_min, &bounds->min);
1016     bounds->min.x -= bounds->center.x;
1017     bounds->min.y -= bounds->center.y;
1018     bounds->min.x *= bounds->scale;
1019     bounds->min.y *= bounds->scale;
1020    
1021     pos2lpos_center(&bounds->ll_max, &bounds->max);
1022     bounds->max.x -= bounds->center.x;
1023     bounds->max.y -= bounds->center.y;
1024     bounds->max.x *= bounds->scale;
1025     bounds->max.y *= bounds->scale;
1026    
1027     return bounds;
1028     }
1029    
1030     static tag_t *process_tag(xmlTextReaderPtr reader) {
1031     /* allocate a new tag structure */
1032     tag_t *tag = g_new0(tag_t, 1);
1033    
1034     char *prop;
1035     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "k"))) {
1036     if(strlen(prop) > 0) tag->key = g_strdup(prop);
1037     xmlFree(prop);
1038     }
1039    
1040     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "v"))) {
1041     if(strlen(prop) > 0) tag->value = g_strdup(prop);
1042     xmlFree(prop);
1043     }
1044    
1045     if(!tag->key || !tag->value) {
1046     printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1047     osm_tags_free(tag);
1048     tag = NULL;
1049     }
1050    
1051     skip_element(reader);
1052     return tag;
1053     }
1054    
1055     static node_t *process_node(xmlTextReaderPtr reader, osm_t *osm) {
1056    
1057     /* allocate a new node structure */
1058     node_t *node = g_new0(node_t, 1);
1059     node->pos.lat = node->pos.lon = NAN;
1060    
1061     char *prop;
1062     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1063     node->id = strtoul(prop, NULL, 10);
1064     xmlFree(prop);
1065     }
1066    
1067     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) {
1068     node->pos.lat = g_ascii_strtod(prop, NULL);
1069     xmlFree(prop);
1070     }
1071    
1072     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lon"))) {
1073     node->pos.lon = g_ascii_strtod(prop, NULL);
1074     xmlFree(prop);
1075     }
1076    
1077     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1078     node->user = osm_user(osm, prop);
1079     xmlFree(prop);
1080     }
1081    
1082     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1083     node->visible = (strcasecmp(prop, "true") == 0);
1084     xmlFree(prop);
1085     }
1086    
1087     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1088     node->time = convert_iso8601(prop);
1089     xmlFree(prop);
1090     }
1091    
1092     pos2lpos(osm->bounds, &node->pos, &node->lpos);
1093    
1094 harbaum 42 /* append node to end of hash table if present */
1095     if(osm->node_hash) {
1096     hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
1097     while(*item) item = &(*item)->next;
1098    
1099     *item = g_new0(hash_item_t, 1);
1100     (*item)->data.node = node;
1101     }
1102    
1103 harbaum 8 /* just an empty element? then return the node as it is */
1104     if(xmlTextReaderIsEmptyElement(reader))
1105     return node;
1106    
1107     /* parse tags if present */
1108     int depth = xmlTextReaderDepth(reader);
1109    
1110     /* scan all elements on same level or its children */
1111     tag_t **tag = &node->tag;
1112     int ret = xmlTextReaderRead(reader);
1113     while((ret == 1) &&
1114     ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1115     (xmlTextReaderDepth(reader) != depth))) {
1116    
1117     if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1118     char *subname = (char*)xmlTextReaderConstName(reader);
1119     if(strcasecmp(subname, "tag") == 0) {
1120     *tag = process_tag(reader);
1121     if(*tag) tag = &(*tag)->next;
1122     } else
1123     skip_element(reader);
1124     }
1125    
1126     ret = xmlTextReaderRead(reader);
1127     }
1128    
1129     return node;
1130     }
1131    
1132     static node_chain_t *process_nd(xmlTextReaderPtr reader, osm_t *osm) {
1133     char *prop;
1134    
1135     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
1136     item_id_t id = strtoul(prop, NULL, 10);
1137     node_chain_t *node_chain = g_new0(node_chain_t, 1);
1138    
1139     /* search matching node */
1140 harbaum 42 node_chain->node = osm_get_node_by_id(osm, id);
1141 harbaum 8 if(!node_chain->node) printf("Node id %lu not found\n", id);
1142 harbaum 42 else node_chain->node->ways++;
1143 harbaum 8
1144     xmlFree(prop);
1145    
1146     skip_element(reader);
1147     return node_chain;
1148     }
1149    
1150     skip_element(reader);
1151     return NULL;
1152     }
1153    
1154     static way_t *process_way(xmlTextReaderPtr reader, osm_t *osm) {
1155     /* allocate a new way structure */
1156     way_t *way = g_new0(way_t, 1);
1157    
1158     char *prop;
1159     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1160     way->id = strtoul(prop, NULL, 10);
1161     xmlFree(prop);
1162     }
1163    
1164     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1165     way->user = osm_user(osm, prop);
1166     xmlFree(prop);
1167     }
1168    
1169     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1170     way->visible = (strcasecmp(prop, "true") == 0);
1171     xmlFree(prop);
1172     }
1173    
1174     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1175     way->time = convert_iso8601(prop);
1176     xmlFree(prop);
1177     }
1178    
1179 harbaum 42 /* append way to end of hash table if present */
1180     if(osm->way_hash) {
1181     hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1182     while(*item) item = &(*item)->next;
1183    
1184     *item = g_new0(hash_item_t, 1);
1185     (*item)->data.way = way;
1186     }
1187    
1188 harbaum 8 /* just an empty element? then return the way as it is */
1189     /* (this should in fact never happen as this would be a way without nodes) */
1190     if(xmlTextReaderIsEmptyElement(reader))
1191     return way;
1192    
1193     /* parse tags/nodes if present */
1194     int depth = xmlTextReaderDepth(reader);
1195    
1196     /* scan all elements on same level or its children */
1197     tag_t **tag = &way->tag;
1198     node_chain_t **node_chain = &way->node_chain;
1199     int ret = xmlTextReaderRead(reader);
1200     while((ret == 1) &&
1201     ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1202     (xmlTextReaderDepth(reader) != depth))) {
1203    
1204     if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1205     char *subname = (char*)xmlTextReaderConstName(reader);
1206     if(strcasecmp(subname, "nd") == 0) {
1207     *node_chain = process_nd(reader, osm);
1208     if(*node_chain) node_chain = &(*node_chain)->next;
1209     } else if(strcasecmp(subname, "tag") == 0) {
1210     *tag = process_tag(reader);
1211     if(*tag) tag = &(*tag)->next;
1212     } else
1213     skip_element(reader);
1214     }
1215     ret = xmlTextReaderRead(reader);
1216     }
1217    
1218     return way;
1219     }
1220    
1221     static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) {
1222     char *prop;
1223     member_t *member = g_new0(member_t, 1);
1224     member->type = ILLEGAL;
1225    
1226     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) {
1227     if(strcasecmp(prop, "way") == 0) member->type = WAY;
1228     else if(strcasecmp(prop, "node") == 0) member->type = NODE;
1229     else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;
1230     xmlFree(prop);
1231     }
1232    
1233     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
1234     item_id_t id = strtoul(prop, NULL, 10);
1235    
1236     switch(member->type) {
1237     case ILLEGAL:
1238     printf("Unable to store illegal type\n");
1239     break;
1240    
1241     case WAY:
1242     /* search matching way */
1243 harbaum 42 member->way = osm_get_way_by_id(osm, id);
1244 harbaum 8 if(!member->way) {
1245     member->type = WAY_ID;
1246     member->id = id;
1247     }
1248     break;
1249    
1250     case NODE:
1251     /* search matching node */
1252 harbaum 42 member->node = osm_get_node_by_id(osm, id);
1253 harbaum 8 if(!member->node) {
1254     member->type = NODE_ID;
1255     member->id = id;
1256     }
1257     break;
1258    
1259     case RELATION:
1260     /* search matching relation */
1261 harbaum 42 member->relation = osm_get_relation_by_id(osm, id);
1262 harbaum 8 if(!member->relation) {
1263     member->type = NODE_ID;
1264     member->id = id;
1265     }
1266     break;
1267    
1268     case WAY_ID:
1269     case NODE_ID:
1270     case RELATION_ID:
1271     break;
1272     }
1273    
1274     xmlFree(prop);
1275     }
1276    
1277     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "role"))) {
1278     if(strlen(prop) > 0) member->role = g_strdup(prop);
1279     xmlFree(prop);
1280     }
1281    
1282     return member;
1283     }
1284    
1285     static relation_t *process_relation(xmlTextReaderPtr reader, osm_t *osm) {
1286     /* allocate a new relation structure */
1287     relation_t *relation = g_new0(relation_t, 1);
1288    
1289     char *prop;
1290     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1291     relation->id = strtoul(prop, NULL, 10);
1292     xmlFree(prop);
1293     }
1294    
1295     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1296     relation->user = osm_user(osm, prop);
1297     xmlFree(prop);
1298     }
1299    
1300     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1301     relation->visible = (strcasecmp(prop, "true") == 0);
1302     xmlFree(prop);
1303     }
1304    
1305     if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1306     relation->time = convert_iso8601(prop);
1307     xmlFree(prop);
1308     }
1309    
1310     /* just an empty element? then return the relation as it is */
1311     /* (this should in fact never happen as this would be a relation */
1312     /* without members) */
1313     if(xmlTextReaderIsEmptyElement(reader))
1314     return relation;
1315    
1316     /* parse tags/member if present */
1317     int depth = xmlTextReaderDepth(reader);
1318    
1319     /* scan all elements on same level or its children */
1320     tag_t **tag = &relation->tag;
1321     member_t **member = &relation->member;
1322     int ret = xmlTextReaderRead(reader);
1323     while((ret == 1) &&
1324     ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1325     (xmlTextReaderDepth(reader) != depth))) {
1326    
1327     if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1328     char *subname = (char*)xmlTextReaderConstName(reader);
1329 achadwick 35 if(strcasecmp(subname, "member") == 0) {
1330 harbaum 8 *member = process_member(reader, osm);
1331     if(*member) member = &(*member)->next;
1332     } else if(strcasecmp(subname, "tag") == 0) {
1333     *tag = process_tag(reader);
1334     if(*tag) tag = &(*tag)->next;
1335     } else
1336     skip_element(reader);
1337     }
1338     ret = xmlTextReaderRead(reader);
1339     }
1340    
1341     return relation;
1342     }
1343    
1344     static osm_t *process_osm(xmlTextReaderPtr reader) {
1345     /* alloc osm structure */
1346     osm_t *osm = g_new0(osm_t, 1);
1347 harbaum 42 osm->node_hash = g_new0(hash_table_t, 1);
1348     osm->way_hash = g_new0(hash_table_t, 1);
1349 harbaum 8
1350     node_t **node = &osm->node;
1351     way_t **way = &osm->way;
1352     relation_t **relation = &osm->relation;
1353    
1354     /* no attributes of interest */
1355    
1356     const xmlChar *name = xmlTextReaderConstName(reader);
1357     g_assert(name);
1358    
1359     /* read next node */
1360 achadwick 28 int num_elems = 0;
1361     const int tick_every = 50; // Balance responsive appearance with performance.
1362 harbaum 8 int ret = xmlTextReaderRead(reader);
1363     while(ret == 1) {
1364    
1365     switch(xmlTextReaderNodeType(reader)) {
1366     case XML_READER_TYPE_ELEMENT:
1367    
1368     g_assert(xmlTextReaderDepth(reader) == 1);
1369     char *name = (char*)xmlTextReaderConstName(reader);
1370     if(strcasecmp(name, "bounds") == 0) {
1371     osm->bounds = process_bounds(reader);
1372     } else if(strcasecmp(name, "node") == 0) {
1373     *node = process_node(reader, osm);
1374     if(*node) node = &(*node)->next;
1375     } else if(strcasecmp(name, "way") == 0) {
1376     *way = process_way(reader, osm);
1377     if(*way) way = &(*way)->next;
1378     } else if(strcasecmp(name, "relation") == 0) {
1379     *relation = process_relation(reader, osm);
1380     if(*relation) relation = &(*relation)->next;
1381     } else {
1382     printf("something unknown found\n");
1383     g_assert(0);
1384     skip_element(reader);
1385     }
1386     break;
1387    
1388     case XML_READER_TYPE_END_ELEMENT:
1389     /* end element must be for the current element */
1390     g_assert(xmlTextReaderDepth(reader) == 0);
1391     return osm;
1392     break;
1393    
1394     default:
1395     break;
1396     }
1397     ret = xmlTextReaderRead(reader);
1398 achadwick 28
1399     if (num_elems++ > tick_every) {
1400     num_elems = 0;
1401     banner_busy_tick();
1402     }
1403 harbaum 8 }
1404    
1405     g_assert(0);
1406     return NULL;
1407     }
1408    
1409     static osm_t *process_file(const char *filename) {
1410     osm_t *osm = NULL;
1411     xmlTextReaderPtr reader;
1412     int ret;
1413    
1414     reader = xmlReaderForFile(filename, NULL, 0);
1415     if (reader != NULL) {
1416     ret = xmlTextReaderRead(reader);
1417     if(ret == 1) {
1418     char *name = (char*)xmlTextReaderConstName(reader);
1419     if(name && strcasecmp(name, "osm") == 0)
1420     osm = process_osm(reader);
1421     } else
1422     printf("file empty\n");
1423    
1424     xmlFreeTextReader(reader);
1425     } else {
1426     fprintf(stderr, "Unable to open %s\n", filename);
1427     }
1428     return osm;
1429     }
1430    
1431     /* ----------------------- end of stream parser tests ------------------- */
1432     #endif
1433    
1434 harbaum 39 #ifdef OSM_QND_XML_PARSER
1435     /* -------------------------- qnd-xml parser tests ------------------- */
1436    
1437 harbaum 40 #ifdef USE_FLOAT
1438     #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c)
1439     #else
1440     #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c)
1441     #endif
1442    
1443 harbaum 39 gboolean osm_bounds_cb(qnd_xml_stack_t *stack,
1444     qnd_xml_attribute_t *attributes, gpointer data) {
1445    
1446     /* get parent pointer */
1447     osm_t *osm = (osm_t*)stack->prev->userdata[0];
1448    
1449     if(osm->bounds) {
1450     errorf(NULL, "Doubly defined bounds");
1451     return FALSE;
1452     }
1453    
1454     bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1);
1455    
1456     bounds->ll_min.lat = bounds->ll_min.lon = NAN;
1457     bounds->ll_max.lat = bounds->ll_max.lon = NAN;
1458    
1459 harbaum 40 GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat);
1460     GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon);
1461     GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat);
1462     GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon);
1463 harbaum 39
1464     if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
1465     isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
1466     errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
1467     bounds->ll_min.lat, bounds->ll_min.lon,
1468     bounds->ll_max.lat, bounds->ll_max.lon);
1469    
1470     osm_bounds_free(bounds);
1471     osm->bounds = NULL;
1472     return FALSE;
1473     }
1474    
1475    
1476     /* calculate map zone which will be used as a reference for all */
1477     /* drawing/projection later on */
1478     pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1479     (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1480    
1481     pos2lpos_center(&center, &bounds->center);
1482    
1483     /* the scale is needed to accomodate for "streching" */
1484     /* by the mercartor projection */
1485     bounds->scale = cos(DEG2RAD(center.lat));
1486    
1487     pos2lpos_center(&bounds->ll_min, &bounds->min);
1488     bounds->min.x -= bounds->center.x;
1489     bounds->min.y -= bounds->center.y;
1490     bounds->min.x *= bounds->scale;
1491     bounds->min.y *= bounds->scale;
1492    
1493     pos2lpos_center(&bounds->ll_max, &bounds->max);
1494     bounds->max.x -= bounds->center.x;
1495     bounds->max.y -= bounds->center.y;
1496     bounds->max.x *= bounds->scale;
1497     bounds->max.y *= bounds->scale;
1498    
1499     return TRUE;
1500     }
1501    
1502     static gboolean osm_tag_cb(qnd_xml_stack_t *stack,
1503     qnd_xml_attribute_t *attributes, gpointer data) {
1504    
1505     tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1);
1506    
1507     tag->key = qnd_xml_get_prop_str(attributes, "k");
1508     tag->value = qnd_xml_get_prop_str(attributes, "v");
1509    
1510     if(!tag->key || !tag->value) {
1511     printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1512     osm_tags_free(tag);
1513     tag = NULL;
1514     } else
1515     stack->prev->userdata[1] = &tag->next;
1516    
1517     return TRUE;
1518     }
1519    
1520     static gboolean osm_node_cb(qnd_xml_stack_t *stack,
1521     qnd_xml_attribute_t *attributes, gpointer data) {
1522    
1523     osm_t *osm = (osm_t*)stack->prev->userdata[0];
1524    
1525     /* allocate a new node structure. userdata[1] points to the current */
1526     /* position a new node is to be stored */
1527     node_t *node = *(node_t**)stack->prev->userdata[1] =
1528     stack->userdata[0] = g_new0(node_t, 1);
1529     stack->prev->userdata[1] = &node->next;
1530    
1531     qnd_xml_get_prop_gulong(attributes, "id", &node->id);
1532 harbaum 40 GET_PROP_POS(attributes, "lat", &node->pos.lat);
1533     GET_PROP_POS(attributes, "lon", &node->pos.lon);
1534 harbaum 39 node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1535     node->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1536     node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1537    
1538     pos2lpos(osm->bounds, &node->pos, &node->lpos);
1539    
1540     /* store current tag pointer in userdata for fast access to current tag */
1541     stack->userdata[1] = &node->tag;
1542    
1543 harbaum 42 /* append node to end of hash table if present */
1544     if(osm->node_hash) {
1545     hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
1546     while(*item) item = &(*item)->next;
1547    
1548     *item = g_new0(hash_item_t, 1);
1549     (*item)->data.node = node;
1550     }
1551    
1552 harbaum 39 return TRUE;
1553     }
1554    
1555     static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack,
1556     qnd_xml_attribute_t *attributes, gpointer data) {
1557    
1558     osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1559    
1560     item_id_t id;
1561     if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1562     /* allocate a new node_chain structure */
1563     node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] =
1564     g_new0(node_chain_t, 1);
1565    
1566     /* search matching node */
1567 harbaum 42 node_chain->node = osm_get_node_by_id(osm, id);
1568 harbaum 39 if(!node_chain->node) printf("Node id %lu not found\n", id);
1569 harbaum 42 else node_chain->node->ways++;
1570 harbaum 39
1571     stack->prev->userdata[2] = &node_chain->next;
1572     }
1573    
1574     return TRUE;
1575     }
1576    
1577     gboolean osm_way_cb(qnd_xml_stack_t *stack,
1578     qnd_xml_attribute_t *attributes, gpointer data) {
1579    
1580     osm_t *osm = (osm_t*)stack->prev->userdata[0];
1581    
1582     /* allocate a new way structure. userdata[2] points to the current */
1583     /* position a new way is to be stored in the way list */
1584     way_t *way = *(way_t**)stack->prev->userdata[2] =
1585     stack->userdata[0] = g_new0(way_t, 1);
1586     stack->prev->userdata[2] = &way->next;
1587    
1588     qnd_xml_get_prop_gulong(attributes, "id", &way->id);
1589     way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1590     way->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1591     way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1592    
1593     /* store current tag and node_chain pointers in userdata for fast */
1594     /* access to current tag/node_chain entry */
1595     stack->userdata[1] = &way->tag;
1596     stack->userdata[2] = &way->node_chain;
1597    
1598 harbaum 42 /* append way to end of hash table if present */
1599     if(osm->way_hash) {
1600     hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
1601     while(*item) item = &(*item)->next;
1602    
1603     *item = g_new0(hash_item_t, 1);
1604     (*item)->data.way = way;
1605     }
1606    
1607 harbaum 39 return TRUE;
1608     }
1609    
1610     static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack,
1611     qnd_xml_attribute_t *attributes, gpointer data) {
1612    
1613     osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1614    
1615     member_t *member = *(member_t**)stack->prev->userdata[2] =
1616     g_new0(member_t, 1);
1617     stack->prev->userdata[2] = &member->next;
1618     member->type = ILLEGAL;
1619    
1620     char *type = qnd_xml_get_prop(attributes, "type");
1621     if(type) {
1622     if(strcasecmp(type, "way") == 0) member->type = WAY;
1623     else if(strcasecmp(type, "node") == 0) member->type = NODE;
1624     else if(strcasecmp(type, "relation") == 0) member->type = RELATION;
1625     }
1626    
1627     item_id_t id;
1628     if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1629     switch(member->type) {
1630     case ILLEGAL:
1631     printf("Unable to store illegal type\n");
1632     break;
1633    
1634     case WAY:
1635     /* search matching way */
1636 harbaum 42 member->way = osm_get_way_by_id(osm, id);
1637 harbaum 39 if(!member->way) {
1638     member->type = WAY_ID;
1639     member->id = id;
1640     }
1641     break;
1642    
1643     case NODE:
1644     /* search matching node */
1645 harbaum 42 member->node = osm_get_node_by_id(osm, id);
1646 harbaum 39 if(!member->node) {
1647     member->type = NODE_ID;
1648     member->id = id;
1649     }
1650     break;
1651    
1652     case RELATION:
1653     /* search matching relation */
1654 harbaum 42 member->relation = osm_get_relation_by_id(osm, id);
1655 harbaum 39 if(!member->relation) {
1656     member->type = NODE_ID;
1657     member->id = id;
1658     }
1659     break;
1660    
1661     case WAY_ID:
1662     case NODE_ID:
1663     case RELATION_ID:
1664     break;
1665     }
1666     }
1667    
1668     return TRUE;
1669     }
1670    
1671     gboolean osm_rel_cb(qnd_xml_stack_t *stack,
1672     qnd_xml_attribute_t *attributes, gpointer data) {
1673    
1674     osm_t *osm = (osm_t*)stack->prev->userdata[0];
1675    
1676     /* allocate a new relation structure. userdata[3] points to the current */
1677     /* position a new relation is to be stored at in the relation list */
1678     relation_t *relation = *(relation_t**)stack->prev->userdata[3] =
1679     stack->userdata[0] = g_new0(relation_t, 1);
1680     stack->prev->userdata[3] = &relation->next;
1681    
1682     qnd_xml_get_prop_gulong(attributes, "id", &relation->id);
1683     relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1684     relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1685     relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1686    
1687     /* store current tag and member pointers in userdata for fast access */
1688     /* to current tag and members in their chains */
1689     stack->userdata[1] = &relation->tag;
1690     stack->userdata[2] = &relation->member;
1691    
1692     return TRUE;
1693     }
1694    
1695     gboolean osm_cb(qnd_xml_stack_t *stack,
1696     qnd_xml_attribute_t *attributes, gpointer data) {
1697    
1698     g_assert(!stack->userdata[0]);
1699    
1700     /* also set parents (roots) userdata as it's the parsers return value */
1701     osm_t *osm = stack->prev->userdata[0] =
1702     stack->userdata[0] = g_new0(osm_t, 1);
1703    
1704 harbaum 42 osm->node_hash = g_new0(hash_table_t, 1);
1705     osm->way_hash = g_new0(hash_table_t, 1);
1706    
1707 harbaum 39 /* store direct pointers for faster list access */
1708     /* (otherwise we'd have to search the end of the lists for every item */
1709     /* to be attached) */
1710     stack->userdata[1] = &osm->node;
1711     stack->userdata[2] = &osm->way;
1712     stack->userdata[3] = &osm->relation;
1713    
1714     return TRUE;
1715     }
1716    
1717    
1718     /* these structures describe the content qnd_xml expects while parsing */
1719     qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1720    
1721     qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1722     qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF };
1723    
1724     qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1725     qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF };
1726    
1727     qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF };
1728    
1729     qnd_xml_entry_t *node_children[] = { &osm_node_tag },
1730     osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) };
1731    
1732     qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd },
1733     osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) };
1734    
1735     qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member },
1736     osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) };
1737    
1738     /* the osm element */
1739     qnd_xml_entry_t *osm_children[] = {
1740     &osm_bounds, &osm_node, &osm_way, &osm_rel };
1741     qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) };
1742    
1743     /* the root element */
1744     qnd_xml_entry_t *root_children[] = { &osm };
1745     qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) };
1746    
1747     // gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c
1748    
1749    
1750    
1751     /* ----------------------- end of qnd-xml parser tests ------------------- */
1752     #endif
1753    
1754    
1755 harbaum 8 #include <sys/time.h>
1756    
1757 harbaum 1 osm_t *osm_parse(char *filename) {
1758    
1759 harbaum 8 struct timeval start;
1760     gettimeofday(&start, NULL);
1761    
1762 harbaum 39 #ifdef OSM_STREAM_PARSER
1763 harbaum 1 LIBXML_TEST_VERSION;
1764    
1765 harbaum 8 // use stream parser
1766     osm_t *osm = process_file(filename);
1767     xmlCleanupParser();
1768 harbaum 39 #endif
1769 harbaum 8
1770 harbaum 39 #ifdef OSM_DOM_PARSER
1771     LIBXML_TEST_VERSION;
1772    
1773 harbaum 8 // parse into a tree
1774 harbaum 1 /* parse the file and get the DOM */
1775 harbaum 8 xmlDoc *doc = NULL;
1776 harbaum 1 if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
1777     xmlErrorPtr errP = xmlGetLastError();
1778     errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message);
1779     return NULL;
1780     }
1781    
1782 harbaum 8 osm_t *osm = osm_parse_doc(doc);
1783     #endif
1784    
1785 harbaum 39 #ifdef OSM_QND_XML_PARSER
1786     osm_t *osm = NULL;
1787     if(!(osm = qnd_xml_parse(filename, &root, NULL))) {
1788     errorf(NULL, "While parsing \"%s\"", filename);
1789     return NULL;
1790     }
1791     #endif
1792    
1793 harbaum 8 struct timeval end;
1794     gettimeofday(&end, NULL);
1795    
1796     printf("total parse time: %ldms\n",
1797     (end.tv_usec - start.tv_usec)/1000 +
1798     (end.tv_sec - start.tv_sec)*1000);
1799    
1800     return osm;
1801 harbaum 1 }
1802    
1803     gboolean osm_sanity_check(GtkWidget *parent, osm_t *osm) {
1804     if(!osm->bounds) {
1805 achadwick 6 errorf(parent, _("Invalid data in OSM file:\n"
1806 harbaum 1 "Boundary box missing!"));
1807     return FALSE;
1808     }
1809     if(!osm->node) {
1810 achadwick 6 errorf(parent, _("Invalid data in OSM file:\n"
1811 harbaum 1 "No drawable content found!"));
1812     return FALSE;
1813     }
1814     return TRUE;
1815     }
1816    
1817     /* ------------------------- misc access functions -------------- */
1818    
1819     char *osm_tag_get_by_key(tag_t *tag, char *key) {
1820     if(!tag || !key) return NULL;
1821    
1822     while(tag) {
1823     if(strcasecmp(tag->key, key) == 0)
1824     return tag->value;
1825    
1826     tag = tag->next;
1827     }
1828    
1829     return NULL;
1830     }
1831    
1832     char *osm_way_get_value(way_t *way, char *key) {
1833     tag_t *tag = way->tag;
1834    
1835     while(tag) {
1836     if(strcasecmp(tag->key, key) == 0)
1837     return tag->value;
1838    
1839     tag = tag->next;
1840     }
1841    
1842     return NULL;
1843     }
1844    
1845     char *osm_node_get_value(node_t *node, char *key) {
1846     tag_t *tag = node->tag;
1847    
1848     while(tag) {
1849     if(strcasecmp(tag->key, key) == 0)
1850     return tag->value;
1851    
1852     tag = tag->next;
1853     }
1854    
1855     return NULL;
1856     }
1857    
1858     gboolean osm_way_has_value(way_t *way, char *str) {
1859     tag_t *tag = way->tag;
1860    
1861     while(tag) {
1862     if(tag->value && strcasecmp(tag->value, str) == 0)
1863     return TRUE;
1864    
1865     tag = tag->next;
1866     }
1867     return FALSE;
1868     }
1869    
1870     gboolean osm_node_has_value(node_t *node, char *str) {
1871     tag_t *tag = node->tag;
1872    
1873     while(tag) {
1874     if(tag->value && strcasecmp(tag->value, str) == 0)
1875     return TRUE;
1876    
1877     tag = tag->next;
1878     }
1879     return FALSE;
1880     }
1881    
1882     gboolean osm_node_has_tag(node_t *node) {
1883     tag_t *tag = node->tag;
1884    
1885     if(tag && strcasecmp(tag->key, "created_by") == 0)
1886     tag = tag->next;
1887    
1888     return tag != NULL;
1889     }
1890    
1891     /* return true if node is part of way */
1892     gboolean osm_node_in_way(way_t *way, node_t *node) {
1893     node_chain_t *node_chain = way->node_chain;
1894     while(node_chain) {
1895     if(node_chain->node == node)
1896     return TRUE;
1897    
1898     node_chain = node_chain->next;
1899     }
1900     return FALSE;
1901     }
1902    
1903     static void osm_generate_tags(tag_t *tag, xmlNodePtr node) {
1904     while(tag) {
1905     /* make sure "created_by" tag contains our id */
1906     if(strcasecmp(tag->key, "created_by") == 0) {
1907     g_free(tag->value);
1908     tag->value = g_strdup(PACKAGE " v" VERSION);
1909     }
1910    
1911     xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL);
1912     xmlNewProp(tag_node, BAD_CAST "k", BAD_CAST tag->key);
1913     xmlNewProp(tag_node, BAD_CAST "v", BAD_CAST tag->value);
1914     tag = tag->next;
1915     }
1916     }
1917    
1918     /* build xml representation for a way */
1919     char *osm_generate_xml(osm_t *osm, type_t type, void *item) {
1920     char str[32];
1921     xmlChar *result = NULL;
1922     int len = 0;
1923    
1924     LIBXML_TEST_VERSION;
1925    
1926     xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1927     xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");
1928     xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0.5");
1929     xmlNewProp(root_node, BAD_CAST "generator", BAD_CAST PACKAGE " V" VERSION);
1930     xmlDocSetRootElement(doc, root_node);
1931    
1932     switch(type) {
1933     case NODE:
1934     {
1935     node_t *node = (node_t*)item;
1936     xmlNodePtr node_node = xmlNewChild(root_node, NULL,
1937     BAD_CAST "node", NULL);
1938     /* new nodes don't have an id, but get one after the upload */
1939     if(!(node->flags & OSM_FLAG_NEW)) {
1940     snprintf(str, sizeof(str), "%u", (unsigned)node->id);
1941     xmlNewProp(node_node, BAD_CAST "id", BAD_CAST str);
1942     }
1943     g_ascii_dtostr(str, sizeof(str), node->pos.lat);
1944     xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str);
1945     g_ascii_dtostr(str, sizeof(str), node->pos.lon);
1946     xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str);
1947     osm_generate_tags(node->tag, node_node);
1948     }
1949     break;
1950    
1951     case WAY:
1952     {
1953     way_t *way = (way_t*)item;
1954     xmlNodePtr way_node = xmlNewChild(root_node, NULL, BAD_CAST "way", NULL);
1955     snprintf(str, sizeof(str), "%u", (unsigned)way->id);
1956     xmlNewProp(way_node, BAD_CAST "id", BAD_CAST str);
1957    
1958     node_chain_t *node_chain = way->node_chain;
1959     while(node_chain) {
1960     xmlNodePtr nd_node = xmlNewChild(way_node, NULL, BAD_CAST "nd", NULL);
1961     char *str = g_strdup_printf("%ld", node_chain->node->id);
1962     xmlNewProp(nd_node, BAD_CAST "ref", BAD_CAST str);
1963     g_free(str);
1964     node_chain = node_chain->next;
1965     }
1966    
1967     osm_generate_tags(way->tag, way_node);
1968     }
1969     break;
1970    
1971     case RELATION:
1972     {
1973     relation_t *relation = (relation_t*)item;
1974     xmlNodePtr rel_node = xmlNewChild(root_node, NULL,
1975     BAD_CAST "relation", NULL);
1976     snprintf(str, sizeof(str), "%u", (unsigned)relation->id);
1977     xmlNewProp(rel_node, BAD_CAST "id", BAD_CAST str);
1978    
1979     member_t *member = relation->member;
1980     while(member) {
1981     xmlNodePtr m_node = xmlNewChild(rel_node,NULL,BAD_CAST "member", NULL);
1982     char *str = NULL;
1983    
1984     switch(member->type) {
1985     case NODE:
1986     xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "node");
1987     str = g_strdup_printf("%ld", member->node->id);
1988     break;
1989    
1990     case WAY:
1991     xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "way");
1992     str = g_strdup_printf("%ld", member->way->id);
1993     break;
1994    
1995     case RELATION:
1996     xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "relation");
1997     str = g_strdup_printf("%ld", member->relation->id);
1998     break;
1999    
2000     default:
2001     break;
2002     }
2003    
2004     if(str) {
2005     xmlNewProp(m_node, BAD_CAST "ref", BAD_CAST str);
2006     g_free(str);
2007     }
2008    
2009     if(member->role)
2010     xmlNewProp(m_node, BAD_CAST "role", BAD_CAST member->role);
2011     else
2012     xmlNewProp(m_node, BAD_CAST "role", BAD_CAST "");
2013    
2014     member = member->next;
2015     }
2016     osm_generate_tags(relation->tag, rel_node);
2017     }
2018     break;
2019    
2020     default:
2021     printf("neither NODE nor WAY nor RELATION\n");
2022     g_assert(0);
2023     break;
2024     }
2025    
2026     xmlDocDumpFormatMemoryEnc(doc, &result, &len, "UTF-8", 1);
2027     xmlFreeDoc(doc);
2028     xmlCleanupParser();
2029    
2030     // puts("xml encoding result:");
2031     // puts((char*)result);
2032    
2033     return (char*)result;
2034     }
2035    
2036     /* build xml representation for a node */
2037     char *osm_generate_xml_node(osm_t *osm, node_t *node) {
2038     return osm_generate_xml(osm, NODE, node);
2039     }
2040    
2041     /* build xml representation for a way */
2042     char *osm_generate_xml_way(osm_t *osm, way_t *way) {
2043     return osm_generate_xml(osm, WAY, way);
2044     }
2045    
2046     /* build xml representation for a relation */
2047     char *osm_generate_xml_relation(osm_t *osm, relation_t *relation) {
2048     return osm_generate_xml(osm, RELATION, relation);
2049     }
2050    
2051 harbaum 42 /* the following three functions are eating much CPU power */
2052     /* as they search the objects lists. Hashing is supposed to help */
2053 harbaum 1 node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) {
2054 harbaum 42 if(id > 0 && osm->node_hash) {
2055     // use hash table if present
2056     hash_item_t *item = osm->node_hash->hash[ID2HASH(id)];
2057     while(item) {
2058     if(item->data.node->id == id)
2059     return item->data.node;
2060    
2061     item = item->next;
2062     }
2063     }
2064    
2065     /* use linear search if no hash tables are present or search in hash table failed */
2066 harbaum 1 node_t *node = osm->node;
2067     while(node) {
2068     if(node->id == id)
2069     return node;
2070 harbaum 42
2071 harbaum 1 node = node->next;
2072     }
2073 harbaum 42
2074 harbaum 1 return NULL;
2075     }
2076    
2077     way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) {
2078 harbaum 42 if(id > 0 && osm->way_hash) {
2079     // use hash table if present
2080     hash_item_t *item = osm->way_hash->hash[ID2HASH(id)];
2081     while(item) {
2082     if(item->data.way->id == id)
2083     return item->data.way;
2084    
2085     item = item->next;
2086     }
2087     }
2088    
2089     /* use linear search if no hash tables are present or search on hash table failed */
2090 harbaum 1 way_t *way = osm->way;
2091     while(way) {
2092     if(way->id == id)
2093     return way;
2094 harbaum 42
2095 harbaum 1 way = way->next;
2096     }
2097 harbaum 42
2098 harbaum 1 return NULL;
2099     }
2100    
2101     relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) {
2102 harbaum 42 // use linear search
2103 harbaum 1 relation_t *relation = osm->relation;
2104     while(relation) {
2105     if(relation->id == id)
2106     return relation;
2107    
2108     relation = relation->next;
2109     }
2110    
2111     return NULL;
2112     }
2113    
2114     /* ---------- edit functions ------------- */
2115    
2116     item_id_t osm_new_way_id(osm_t *osm) {
2117     item_id_t id = -1;
2118    
2119     while(TRUE) {
2120     gboolean found = FALSE;
2121     way_t *way = osm->way;
2122     while(way) {
2123     if(way->id == id)
2124     found = TRUE;
2125    
2126     way = way->next;
2127     }
2128    
2129     /* no such id so far -> use it */
2130     if(!found) return id;
2131    
2132     id--;
2133     }
2134     g_assert(0);
2135     return 0;
2136     }
2137    
2138     item_id_t osm_new_node_id(osm_t *osm) {
2139     item_id_t id = -1;
2140    
2141     while(TRUE) {
2142     gboolean found = FALSE;
2143     node_t *node = osm->node;
2144     while(node) {
2145     if(node->id == id)
2146     found = TRUE;
2147    
2148     node = node->next;
2149     }
2150    
2151     /* no such id so far -> use it */
2152     if(!found) return id;
2153    
2154     id--;
2155     }
2156     g_assert(0);
2157     return 0;
2158     }
2159    
2160 harbaum 73 item_id_t osm_new_relation_id(osm_t *osm) {
2161     item_id_t id = -1;
2162    
2163     while(TRUE) {
2164     gboolean found = FALSE;
2165     relation_t *relation = osm->relation;
2166     while(relation) {
2167     if(relation->id == id)
2168     found = TRUE;
2169    
2170     relation = relation->next;
2171     }
2172    
2173     /* no such id so far -> use it */
2174     if(!found) return id;
2175    
2176     id--;
2177     }
2178     g_assert(0);
2179     return 0;
2180     }
2181    
2182 harbaum 1 node_t *osm_node_new(osm_t *osm, gint x, gint y) {
2183     printf("Creating new node\n");
2184    
2185     node_t *node = g_new0(node_t, 1);
2186     node->lpos.x = x;
2187     node->lpos.y = y;
2188     node->visible = TRUE;
2189     node->time = time(NULL);
2190    
2191     /* add created_by tag */
2192     node->tag = g_new0(tag_t, 1);
2193     node->tag->key = g_strdup("created_by");
2194     node->tag->value = g_strdup(PACKAGE " v" VERSION);
2195    
2196     /* convert screen position back to ll */
2197     lpos2pos(osm->bounds, &node->lpos, &node->pos);
2198    
2199     printf(" new at %d %d (%f %f)\n",
2200     node->lpos.x, node->lpos.y, node->pos.lat, node->pos.lon);
2201    
2202     return node;
2203     }
2204    
2205    
2206     void osm_node_attach(osm_t *osm, node_t *node) {
2207     printf("Attaching node\n");
2208    
2209     node->id = osm_new_node_id(osm);
2210     node->flags = OSM_FLAG_NEW;
2211    
2212     /* attach to end of node list */
2213     node_t **lnode = &osm->node;
2214     while(*lnode) lnode = &(*lnode)->next;
2215     *lnode = node;
2216     }
2217    
2218 harbaum 64 void osm_node_restore(osm_t *osm, node_t *node) {
2219     printf("Restoring node\n");
2220    
2221     /* attach to end of node list */
2222     node_t **lnode = &osm->node;
2223     while(*lnode) lnode = &(*lnode)->next;
2224     *lnode = node;
2225     }
2226    
2227 harbaum 1 way_t *osm_way_new(void) {
2228     printf("Creating new way\n");
2229    
2230     way_t *way = g_new0(way_t, 1);
2231     way->visible = TRUE;
2232     way->flags = OSM_FLAG_NEW;
2233     way->time = time(NULL);
2234    
2235     /* add created_by tag */
2236     way->tag = g_new0(tag_t, 1);
2237     way->tag->key = g_strdup("created_by");
2238     way->tag->value = g_strdup(PACKAGE " v" VERSION);
2239    
2240     return way;
2241     }
2242    
2243     void osm_way_attach(osm_t *osm, way_t *way) {
2244     printf("Attaching way\n");
2245    
2246     way->id = osm_new_way_id(osm);
2247     way->flags = OSM_FLAG_NEW;
2248    
2249     /* attach to end of way list */
2250     way_t **lway = &osm->way;
2251     while(*lway) lway = &(*lway)->next;
2252     *lway = way;
2253     }
2254    
2255     /* returns pointer to chain of ways affected by this deletion */
2256     way_chain_t *osm_node_delete(osm_t *osm, icon_t **icon,
2257     node_t *node, gboolean permanently,
2258     gboolean affect_ways) {
2259     way_chain_t *way_chain = NULL, **cur_way_chain = &way_chain;
2260    
2261     /* new nodes aren't stored on the server and are just deleted permanently */
2262     if(node->flags & OSM_FLAG_NEW) {
2263     printf("About to delete NEW node #%ld -> force permanent delete\n",
2264     node->id);
2265     permanently = TRUE;
2266     }
2267    
2268     /* first remove node from all ways using it */
2269     way_t *way = osm->way;
2270     while(way) {
2271     node_chain_t **chain = &(way->node_chain);
2272     gboolean modified = FALSE;
2273     while(*chain) {
2274     /* remove node from chain */
2275     if(node == (*chain)->node) {
2276     modified = TRUE;
2277     if(affect_ways) {
2278     node_chain_t *next = (*chain)->next;
2279     g_free(*chain);
2280     *chain = next;
2281     } else
2282     chain = &((*chain)->next);
2283     } else
2284     chain = &((*chain)->next);
2285     }
2286    
2287     if(modified) {
2288     way->flags |= OSM_FLAG_DIRTY;
2289    
2290     /* and add the way to the list of affected ways */
2291     *cur_way_chain = g_new0(way_chain_t, 1);
2292     (*cur_way_chain)->way = way;
2293     cur_way_chain = &((*cur_way_chain)->next);
2294     }
2295    
2296     way = way->next;
2297     }
2298    
2299     if(!permanently) {
2300     printf("mark node #%ld as deleted\n", node->id);
2301     node->flags |= OSM_FLAG_DELETED;
2302     } else {
2303     printf("permanently delete node #%ld\n", node->id);
2304    
2305     /* remove it from the chain */
2306     node_t **cnode = &osm->node;
2307     int found = 0;
2308    
2309     while(*cnode) {
2310     if(*cnode == node) {
2311     found++;
2312     *cnode = (*cnode)->next;
2313    
2314     osm_node_free(icon, node);
2315     } else
2316     cnode = &((*cnode)->next);
2317     }
2318     g_assert(found == 1);
2319     }
2320    
2321     return way_chain;
2322     }
2323    
2324     guint osm_way_number_of_nodes(way_t *way) {
2325     guint nodes = 0;
2326     node_chain_t *chain = way->node_chain;
2327     while(chain) {
2328     nodes++;
2329     chain = chain->next;
2330     }
2331     return nodes;
2332     }
2333    
2334     /* return all relations a node is in */
2335     relation_chain_t *osm_node_to_relation(osm_t *osm, node_t *node) {
2336     relation_chain_t *rel_chain = NULL, **cur_rel_chain = &rel_chain;
2337    
2338     relation_t *relation = osm->relation;
2339     while(relation) {
2340     gboolean is_member = FALSE;
2341    
2342     member_t *member = relation->member;
2343     while(member) {
2344     switch(member->type) {
2345     case NODE:
2346     /* nodes are checked directly */
2347     if(member->node == node)
2348     is_member = TRUE;
2349     break;
2350    
2351     case WAY: {
2352     /* ways have to be checked for the nodes they consist of */
2353     node_chain_t *chain = member->way->node_chain;
2354     while(chain && !is_member) {
2355     if(chain->node == node)
2356     is_member = TRUE;
2357    
2358     chain = chain->next;
2359     }
2360     } break;
2361    
2362     default:
2363     break;
2364     }
2365     member = member->next;
2366     }
2367    
2368     /* node is a member of this relation, so move it to the member chain */
2369     if(is_member) {
2370     *cur_rel_chain = g_new0(relation_chain_t, 1);
2371     (*cur_rel_chain)->relation = relation;
2372     cur_rel_chain = &((*cur_rel_chain)->next);
2373     }
2374    
2375     relation = relation->next;
2376     }
2377    
2378     return rel_chain;
2379     }
2380    
2381     /* return all relations a way is in */
2382     relation_chain_t *osm_way_to_relation(osm_t *osm, way_t *way) {
2383     relation_chain_t *rel_chain = NULL, **cur_rel_chain = &rel_chain;
2384    
2385     relation_t *relation = osm->relation;
2386     while(relation) {
2387     gboolean is_member = FALSE;
2388    
2389     member_t *member = relation->member;
2390     while(member) {
2391     switch(member->type) {
2392     case WAY: {
2393     /* ways can be check directly */
2394     if(member->way == way)
2395     is_member = TRUE;
2396     } break;
2397    
2398     default:
2399     break;
2400     }
2401     member = member->next;
2402     }
2403    
2404     /* way is a member of this relation, so move it to the member chain */
2405     if(is_member) {
2406     *cur_rel_chain = g_new0(relation_chain_t, 1);
2407     (*cur_rel_chain)->relation = relation;
2408     cur_rel_chain = &((*cur_rel_chain)->next);
2409     }
2410    
2411     relation = relation->next;
2412     }
2413    
2414     return rel_chain;
2415     }
2416    
2417     /* return all ways a node is in */
2418     way_chain_t *osm_node_to_way(osm_t *osm, node_t *node) {
2419     way_chain_t *chain = NULL, **cur_chain = &chain;
2420    
2421     way_t *way = osm->way;
2422     while(way) {
2423     gboolean is_member = FALSE;
2424    
2425     node_chain_t *node_chain = way->node_chain;
2426     while(node_chain) {
2427     if(node_chain->node == node)
2428     is_member = TRUE;
2429    
2430     node_chain = node_chain->next;
2431     }
2432    
2433     /* node is a member of this relation, so move it to the member chain */
2434     if(is_member) {
2435     *cur_chain = g_new0(way_chain_t, 1);
2436     (*cur_chain)->way = way;
2437     cur_chain = &((*cur_chain)->next);
2438     }
2439    
2440 harbaum 8 way = way->next;
2441 harbaum 1 }
2442    
2443     return chain;
2444     }
2445    
2446     gboolean osm_position_within_bounds(osm_t *osm, gint x, gint y) {
2447     if((x < osm->bounds->min.x) || (x > osm->bounds->max.x)) return FALSE;
2448     if((y < osm->bounds->min.y) || (y > osm->bounds->max.y)) return FALSE;
2449     return TRUE;
2450     }
2451    
2452     /* remove the given node from all relations. used if the node is to */
2453     /* be deleted */
2454     void osm_node_remove_from_relation(osm_t *osm, node_t *node) {
2455     relation_t *relation = osm->relation;
2456     printf("removing node #%ld from all relations:\n", node->id);
2457    
2458     while(relation) {
2459     member_t **member = &relation->member;
2460     while(*member) {
2461     if(((*member)->type == NODE) &&
2462     ((*member)->node == node)) {
2463    
2464     printf(" from relation #%ld\n", relation->id);
2465    
2466     member_t *cur = *member;
2467     *member = (*member)->next;
2468     osm_member_free(cur);
2469    
2470     relation->flags |= OSM_FLAG_DIRTY;
2471     } else
2472     member = &(*member)->next;
2473     }
2474     relation = relation->next;
2475     }
2476     }
2477    
2478     /* remove the given way from all relations */
2479     void osm_way_remove_from_relation(osm_t *osm, way_t *way) {
2480     relation_t *relation = osm->relation;
2481     printf("removing way #%ld from all relations:\n", way->id);
2482    
2483     while(relation) {
2484     member_t **member = &relation->member;
2485     while(*member) {
2486     if(((*member)->type == WAY) &&
2487     ((*member)->way == way)) {
2488    
2489     printf(" from relation #%ld\n", relation->id);
2490    
2491     member_t *cur = *member;
2492     *member = (*member)->next;
2493     osm_member_free(cur);
2494    
2495     relation->flags |= OSM_FLAG_DIRTY;
2496     } else
2497     member = &(*member)->next;
2498     }
2499     relation = relation->next;
2500     }
2501     }
2502    
2503 harbaum 73 relation_t *osm_relation_new(void) {
2504     printf("Creating new relation\n");
2505    
2506     relation_t *relation = g_new0(relation_t, 1);
2507     relation->visible = TRUE;
2508     relation->flags = OSM_FLAG_NEW;
2509     relation->time = time(NULL);
2510    
2511     /* add created_by tag */
2512     relation->tag = g_new0(tag_t, 1);
2513     relation->tag->key = g_strdup("created_by");
2514     relation->tag->value = g_strdup(PACKAGE " v" VERSION);
2515    
2516     return relation;
2517     }
2518    
2519     void osm_relation_attach(osm_t *osm, relation_t *relation) {
2520     printf("Attaching relation\n");
2521    
2522     relation->id = osm_new_relation_id(osm);
2523     relation->flags = OSM_FLAG_NEW;
2524    
2525     /* attach to end of relation list */
2526     relation_t **lrelation = &osm->relation;
2527     while(*lrelation) lrelation = &(*lrelation)->next;
2528     *lrelation = relation;
2529     }
2530    
2531    
2532 harbaum 1 void osm_way_delete(osm_t *osm, icon_t **icon,
2533     way_t *way, gboolean permanently) {
2534    
2535     /* new ways aren't stored on the server and are just deleted permanently */
2536     if(way->flags & OSM_FLAG_NEW) {
2537     printf("About to delete NEW way #%ld -> force permanent delete\n",
2538     way->id);
2539     permanently = TRUE;
2540     }
2541    
2542     /* delete all nodes that aren't in other use now */
2543     node_chain_t **chain = &way->node_chain;
2544     while(*chain) {
2545    
2546     (*chain)->node->ways--;
2547     printf("checking node #%ld (still used by %d)\n",
2548     (*chain)->node->id, (*chain)->node->ways);
2549    
2550     /* this node must only be part of this way */
2551     if(!(*chain)->node->ways) {
2552     /* delete this node, but don't let this actually affect the */
2553     /* associated ways as the only such way is the oen we are currently */
2554     /* deleting */
2555     way_chain_t *way_chain =
2556     osm_node_delete(osm, icon, (*chain)->node, FALSE, FALSE);
2557     g_assert(way_chain);
2558     while(way_chain) {
2559     way_chain_t *way_next = way_chain->next;
2560     g_assert(way_chain->way == way);
2561     g_free(way_chain);
2562     way_chain = way_next;
2563     }
2564     }
2565    
2566     node_chain_t *cur = (*chain);
2567     *chain = cur->next;
2568     g_free(cur);
2569     }
2570     way->node_chain = NULL;
2571    
2572     if(!permanently) {
2573     printf("mark way #%ld as deleted\n", way->id);
2574     way->flags |= OSM_FLAG_DELETED;
2575     } else {
2576     printf("permanently delete way #%ld\n", way->id);
2577    
2578     /* remove it from the chain */
2579     way_t **cway = &osm->way;
2580     int found = 0;
2581    
2582     while(*cway) {
2583     if(*cway == way) {
2584     found++;
2585     *cway = (*cway)->next;
2586    
2587     osm_way_free(way);
2588     } else
2589     cway = &((*cway)->next);
2590     }
2591     g_assert(found == 1);
2592     }
2593     }
2594    
2595 harbaum 75 void osm_relation_delete(osm_t *osm, relation_t *relation,
2596     gboolean permanently) {
2597    
2598     /* new relations aren't stored on the server and are just */
2599     /* deleted permanently */
2600     if(relation->flags & OSM_FLAG_NEW) {
2601     printf("About to delete NEW relation #%ld -> force permanent delete\n",
2602     relation->id);
2603     permanently = TRUE;
2604     }
2605    
2606     /* the deletion of a relation doesn't affect the members as they */
2607     /* don't have any reference to the relation they are part of */
2608    
2609     if(!permanently) {
2610     printf("mark relation #%ld as deleted\n", relation->id);
2611     relation->flags |= OSM_FLAG_DELETED;
2612     } else {
2613     printf("permanently delete relation #%ld\n", relation->id);
2614    
2615     /* remove it from the chain */
2616     relation_t **crelation = &osm->relation;
2617     int found = 0;
2618    
2619     while(*crelation) {
2620     if(*crelation == relation) {
2621     found++;
2622     *crelation = (*crelation)->next;
2623    
2624     osm_relation_free(relation);
2625     } else
2626     crelation = &((*crelation)->next);
2627     }
2628     g_assert(found == 1);
2629     }
2630     }
2631    
2632 harbaum 1 void osm_way_revert(way_t *way) {
2633     node_chain_t *new = NULL;
2634    
2635     /* walk old chain first to last */
2636     node_chain_t *old = way->node_chain;
2637     while(old) {
2638     node_chain_t *next = old->next;
2639    
2640     /* and prepend each node to the new chain */
2641     old->next = new;
2642     new = old;
2643    
2644     old = next;
2645     }
2646    
2647     way->node_chain = new;
2648     }
2649    
2650     node_t *osm_way_get_first_node(way_t *way) {
2651     node_chain_t *chain = way->node_chain;
2652     if(!chain) return NULL;
2653     return chain->node;
2654     }
2655    
2656     node_t *osm_way_get_last_node(way_t *way) {
2657     node_chain_t *chain = way->node_chain;
2658    
2659     while(chain && chain->next) chain=chain->next;
2660    
2661     if(!chain) return NULL;
2662    
2663     return chain->node;
2664     }
2665    
2666     void osm_way_rotate(way_t *way, gint offset) {
2667     if(!offset) return;
2668    
2669     /* needs at least two nodes to work properly */
2670     g_assert(way->node_chain);
2671     g_assert(way->node_chain->next);
2672    
2673     while(offset--) {
2674     node_chain_t *chain = way->node_chain;
2675     chain->node->ways--; // reduce way count of old start/end node
2676    
2677     /* move all nodes ahead one chain element ... */
2678     while(chain->next) {
2679     chain->node = chain->next->node;
2680     chain = chain->next;
2681     }
2682    
2683     /* ... and make last one same as first one */
2684     chain->node = way->node_chain->node;
2685     chain->node->ways++; // increase way count of new start/end node
2686     }
2687     }
2688    
2689     tag_t *osm_tags_copy(tag_t *src_tag, gboolean update_creator) {
2690     tag_t *new_tags = NULL;
2691     tag_t **dst_tag = &new_tags;
2692    
2693     while(src_tag) {
2694     *dst_tag = g_new0(tag_t, 1);
2695     (*dst_tag)->key = g_strdup(src_tag->key);
2696     if(update_creator && (strcasecmp(src_tag->key, "created_by") == 0))
2697     (*dst_tag)->value = g_strdup(PACKAGE " v" VERSION);
2698     else
2699     (*dst_tag)->value = g_strdup(src_tag->value);
2700    
2701     dst_tag = &(*dst_tag)->next;
2702     src_tag = src_tag->next;
2703     }
2704    
2705     return new_tags;
2706     }
2707 harbaum 54
2708     /* return plain text of type */
2709     char *osm_type_string(type_t type) {
2710     const struct { type_t type; char *name; } types[] = {
2711     { ILLEGAL, "illegal" },
2712     { NODE, "node" },
2713     { WAY, "way" },
2714     { RELATION, "relation" },
2715     { NODE_ID, "node id" },
2716     { WAY_ID, "way id" },
2717     { RELATION_ID, "relation id" },
2718     { 0, NULL }
2719     };
2720    
2721     int i;
2722     for(i=0;types[i].name;i++)
2723     if(type == types[i].type)
2724     return types[i].name;
2725    
2726     return NULL;
2727     }
2728    
2729 harbaum 64 char *osm_object_string(type_t type, void *object) {
2730     char *type_str = osm_type_string(type);
2731 harbaum 54
2732 harbaum 64 if(!object)
2733     return g_strdup_printf("%s #<invalid>", type_str);
2734    
2735     switch(type) {
2736     case ILLEGAL:
2737     return g_strdup_printf("%s #<unspec>", type_str);
2738     break;
2739     case NODE:
2740     return g_strdup_printf("%s #%ld", type_str, ((node_t*)object)->id);
2741     break;
2742     case WAY:
2743     return g_strdup_printf("%s #%ld", type_str, ((way_t*)object)->id);
2744     break;
2745     case RELATION:
2746     return g_strdup_printf("%s #%ld", type_str, ((relation_t*)object)->id);
2747     break;
2748     case NODE_ID:
2749     case WAY_ID:
2750     case RELATION_ID:
2751 harbaum 76 return g_strdup_printf("%s #%ld", type_str, ((item_id_t)object));
2752 harbaum 64 break;
2753     }
2754     return NULL;
2755     }
2756    
2757 harbaum 76 char *osm_id_string(type_t type, void *object) {
2758     if(!object) return NULL;
2759    
2760     switch(type) {
2761     case ILLEGAL:
2762     return NULL;
2763     break;
2764     case NODE:
2765     return g_strdup_printf("#%ld", ((node_t*)object)->id);
2766     break;
2767     case WAY:
2768     return g_strdup_printf("#%ld", ((way_t*)object)->id);
2769     break;
2770     case RELATION:
2771     return g_strdup_printf("#%ld", ((relation_t*)object)->id);
2772     break;
2773     case NODE_ID:
2774     case WAY_ID:
2775     case RELATION_ID:
2776     return g_strdup_printf("#%ld", ((item_id_t)object));
2777     break;
2778     }
2779     return NULL;
2780     }
2781    
2782     tag_t *osm_object_get_tags(type_t type, void *object) {
2783     if(!object) return NULL;
2784    
2785     switch(type) {
2786     case ILLEGAL:
2787     return NULL;
2788     break;
2789     case NODE:
2790     return ((node_t*)object)->tag;
2791     break;
2792     case WAY:
2793     return ((way_t*)object)->tag;
2794     break;
2795     case RELATION:
2796     return ((relation_t*)object)->tag;
2797     break;
2798     case NODE_ID:
2799     case WAY_ID:
2800     case RELATION_ID:
2801     return NULL;
2802     break;
2803     }
2804     return NULL;
2805     }
2806    
2807    
2808     gint osm_relation_members_num(relation_t *relation) {
2809     gint num = 0;
2810     member_t *member = relation->member;
2811     while(member) {
2812     num++;
2813     member = member->next;
2814     }
2815     return num;
2816     }
2817    
2818 achadwick 28 // vim:et:ts=8:sw=2:sts=2:ai