Contents of /trunk/src/osm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations)
Sun Jan 18 19:43:20 2009 UTC (15 years, 3 months ago) by harbaum
File MIME type: text/plain
File size: 65477 byte(s)
Option to use float math instead of double
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 /* xml parsing has a performance issue */
21 // #define OSM_DOM_PARSER
22 // #define OSM_STREAM_PARSER
23 #define OSM_QND_XML_PARSER
24
25 #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 #include "banner.h"
38
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 /* ------------------------- bounds handling --------------------- */
50
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 #ifdef OSM_DOM_PARSER
62 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 osm_bounds_free(bounds);
103 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 #endif
133
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 if(!name) return NULL;
157
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 if(!str) return 0;
179
180 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 #ifdef OSM_DOM_PARSER
334 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 /* scan for tags and attach a list of tags */
374 tag_t **tag = &node->tag;
375 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
376 if (cur_node->type == XML_ELEMENT_NODE) {
377 if(strcasecmp((char*)cur_node->name, "tag") == 0) {
378 /* attach tag to node */
379 *tag = osm_parse_osm_tag(osm, doc, cur_node);
380 if(*tag) tag = &((*tag)->next);
381 } else
382 printf("found unhandled osm/node/%s\n", cur_node->name);
383 }
384 }
385
386 pos2lpos(osm->bounds, &node->pos, &node->lpos);
387
388 return node;
389 }
390 #endif
391
392 /* ------------------- way handling ------------------- */
393
394 void osm_node_chain_free(node_chain_t *node_chain) {
395 while(node_chain) {
396 g_assert(node_chain->node->ways);
397
398 node_chain_t *next = node_chain->next;
399 node_chain->node->ways--;
400 g_free(node_chain);
401 node_chain = next;
402 }
403 }
404
405 void osm_way_free(way_t *way) {
406 // printf("freeing way #%ld\n", way->id);
407
408 osm_node_chain_free(way->node_chain);
409 osm_tags_free(way->tag);
410
411 /* there must not be anything left in this chain */
412 g_assert(!way->map_item_chain);
413
414 g_free(way);
415 }
416
417 static void osm_ways_free(way_t *way) {
418 while(way) {
419 way_t *next = way->next;
420 osm_way_free(way);
421 way = next;
422 }
423 }
424
425 void osm_way_append_node(way_t *way, node_t *node) {
426 node_chain_t **node_chain = &way->node_chain;
427
428 while(*node_chain)
429 node_chain = &((*node_chain)->next);
430
431 *node_chain = g_new0(node_chain_t, 1);
432 (*node_chain)->node = node;
433
434 node->ways++;
435 }
436
437 int osm_node_chain_length(node_chain_t *node_chain) {
438 int cnt = 0;
439 while(node_chain) {
440 cnt++;
441 node_chain = node_chain->next;
442 }
443
444 return cnt;
445 }
446
447 void osm_way_dump(way_t *way) {
448 char buf[64];
449 struct tm tm;
450
451 printf("Id: %lu\n", way->id);
452 printf("User: %s\n", way->user?way->user->name:"<unspecified>");
453 printf("Visible: %s\n", way->visible?"yes":"no");
454 node_chain_t *node_chain = way->node_chain;
455 while(node_chain) {
456 printf(" Node: %lu\n", node_chain->node->id);
457 node_chain = node_chain->next;
458 }
459
460 localtime_r(&way->time, &tm);
461 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", &tm);
462 printf("Time: %s\n", buf);
463 osm_tags_dump(way->tag);
464 }
465
466 void osm_ways_dump(way_t *way) {
467 printf("\nWay list:\n");
468 while(way) {
469 osm_way_dump(way);
470 printf("\n");
471 way = way->next;
472 }
473 }
474
475 node_chain_t *osm_parse_osm_way_nd(osm_t *osm,
476 xmlDocPtr doc, xmlNode *a_node) {
477 char *prop;
478
479 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) {
480 item_id_t id = strtoul(prop, NULL, 10);
481 node_chain_t *node_chain = g_new0(node_chain_t, 1);
482
483 /* search matching node */
484 node_chain->node = osm->node;
485 while(node_chain->node && node_chain->node->id != id)
486 node_chain->node = node_chain->node->next;
487
488 if(!node_chain->node) printf("Node id %lu not found\n", id);
489
490 if(node_chain->node)
491 node_chain->node->ways++;
492
493 xmlFree(prop);
494
495 return node_chain;
496 }
497
498 return NULL;
499 }
500
501 #ifdef OSM_DOM_PARSER
502 static way_t *osm_parse_osm_way(osm_t *osm,
503 xmlDocPtr doc, xmlNode *a_node) {
504 xmlNode *cur_node = NULL;
505
506 /* allocate a new way structure */
507 way_t *way = g_new0(way_t, 1);
508
509 char *prop;
510 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {
511 way->id = strtoul(prop, NULL, 10);
512 xmlFree(prop);
513 }
514
515 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {
516 way->user = osm_user(osm, prop);
517 xmlFree(prop);
518 }
519
520 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {
521 way->visible = (strcasecmp(prop, "true") == 0);
522 xmlFree(prop);
523 }
524
525 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {
526 way->time = convert_iso8601(prop);
527 xmlFree(prop);
528 }
529
530 /* scan for tags/nodes and attach their lists */
531 tag_t **tag = &way->tag;
532 node_chain_t **node_chain = &way->node_chain;
533
534 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
535 if (cur_node->type == XML_ELEMENT_NODE) {
536 if(strcasecmp((char*)cur_node->name, "tag") == 0) {
537 /* attach tag to node */
538 *tag = osm_parse_osm_tag(osm, doc, cur_node);
539 if(*tag) tag = &((*tag)->next);
540 } else if(strcasecmp((char*)cur_node->name, "nd") == 0) {
541 *node_chain = osm_parse_osm_way_nd(osm, doc, cur_node);
542 if(*node_chain)
543 node_chain = &((*node_chain)->next);
544 } else
545 printf("found unhandled osm/node/%s\n", cur_node->name);
546 }
547 }
548
549 return way;
550 }
551 #endif
552
553 /* ------------------- relation handling ------------------- */
554
555 void osm_member_free(member_t *member) {
556 if(member->role) g_free(member->role);
557 g_free(member);
558 }
559
560 void osm_members_free(member_t *member) {
561 while(member) {
562 member_t *next = member->next;
563 osm_member_free(member);
564 member = next;
565 }
566 }
567
568 static void osm_relations_free(relation_t *relation) {
569 while(relation) {
570 relation_t *next = relation->next;
571
572 osm_tags_free(relation->tag);
573 osm_members_free(relation->member);
574
575 g_free(relation);
576 relation = next;
577 }
578 }
579
580 void osm_relations_dump(relation_t *relation) {
581 printf("\nRelation list:\n");
582 while(relation) {
583 char buf[64];
584 struct tm tm;
585
586 printf("Id: %lu\n", relation->id);
587 printf("User: %s\n",
588 relation->user?relation->user->name:"<unspecified>");
589 printf("Visible: %s\n", relation->visible?"yes":"no");
590
591 member_t *member = relation->member;
592 while(member) {
593 switch(member->type) {
594 case ILLEGAL:
595 case NODE_ID:
596 case WAY_ID:
597 case RELATION_ID:
598 break;
599
600 case NODE:
601 if(member->node)
602 printf(" Member: Node, id = %lu, role = %s\n",
603 member->node->id, member->role);
604 break;
605
606 case WAY:
607 if(member->way)
608 printf(" Member: Way, id = %lu, role = %s\n",
609 member->way->id, member->role);
610 break;
611
612 case RELATION:
613 if(member->relation)
614 printf(" Member: Relation, id = %lu, role = %s\n",
615 member->relation->id, member->role);
616 break;
617 }
618
619 member = member->next;
620 }
621
622 localtime_r(&relation->time, &tm);
623 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %Z", &tm);
624 printf("Time: %s\n", buf);
625 osm_tags_dump(relation->tag);
626
627 printf("\n");
628 relation = relation->next;
629 }
630 }
631
632 member_t *osm_parse_osm_relation_member(osm_t *osm,
633 xmlDocPtr doc, xmlNode *a_node) {
634 char *prop;
635 member_t *member = g_new0(member_t, 1);
636 member->type = ILLEGAL;
637
638 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"type"))) {
639 if(strcasecmp(prop, "way") == 0) member->type = WAY;
640 else if(strcasecmp(prop, "node") == 0) member->type = NODE;
641 else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;
642 xmlFree(prop);
643 }
644
645 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) {
646 item_id_t id = strtoul(prop, NULL, 10);
647
648 switch(member->type) {
649 case ILLEGAL:
650 printf("Unable to store illegal type\n");
651 break;
652
653 case WAY:
654 /* search matching way */
655 member->way = osm->way;
656 while(member->way && member->way->id != id)
657 member->way = member->way->next;
658
659 if(!member->way) {
660 member->type = WAY_ID;
661 member->id = id;
662 }
663 break;
664
665 case NODE:
666 /* search matching node */
667 member->node = osm->node;
668 while(member->node && member->node->id != id)
669 member->node = member->node->next;
670
671 if(!member->node) {
672 member->type = NODE_ID;
673 member->id = id;
674 }
675 break;
676
677 case RELATION:
678 /* search matching relation */
679 member->relation = osm->relation;
680 while(member->relation && member->relation->id != id)
681 member->relation = member->relation->next;
682
683 if(!member->relation) {
684 member->type = NODE_ID;
685 member->id = id;
686 }
687 break;
688
689 case WAY_ID:
690 case NODE_ID:
691 case RELATION_ID:
692 break;
693 }
694
695 xmlFree(prop);
696 }
697
698 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"role"))) {
699 if(strlen(prop) > 0) member->role = g_strdup(prop);
700 xmlFree(prop);
701 }
702
703 return member;
704 }
705
706 #ifdef OSM_DOM_PARSER
707 static relation_t *osm_parse_osm_relation(osm_t *osm,
708 xmlDocPtr doc, xmlNode *a_node) {
709 xmlNode *cur_node = NULL;
710
711 /* allocate a new relation structure */
712 relation_t *relation = g_new0(relation_t, 1);
713
714 char *prop;
715 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {
716 relation->id = strtoul(prop, NULL, 10);
717 xmlFree(prop);
718 }
719
720 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {
721 relation->user = osm_user(osm, prop);
722 xmlFree(prop);
723 }
724
725 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {
726 relation->visible = (strcasecmp(prop, "true") == 0);
727 xmlFree(prop);
728 }
729
730 if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {
731 relation->time = convert_iso8601(prop);
732 xmlFree(prop);
733 }
734
735 /* scan for tags and attach a list of tags */
736 tag_t **tag = &relation->tag;
737 member_t **member = &relation->member;
738
739 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
740 if (cur_node->type == XML_ELEMENT_NODE) {
741 if(strcasecmp((char*)cur_node->name, "tag") == 0) {
742 /* attach tag to node */
743 *tag = osm_parse_osm_tag(osm, doc, cur_node);
744 if(*tag) tag = &((*tag)->next);
745 } else if(strcasecmp((char*)cur_node->name, "member") == 0) {
746 *member = osm_parse_osm_relation_member(osm, doc, cur_node);
747 if(*member) member = &((*member)->next);
748 } else
749 printf("found unhandled osm/node/%s\n", cur_node->name);
750 }
751 }
752
753 return relation;
754 }
755
756 /* ----------------------- generic xml handling -------------------------- */
757
758 /* parse loc entry */
759 static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) {
760 xmlNode *cur_node = NULL;
761
762 for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
763 if (cur_node->type == XML_ELEMENT_NODE) {
764 if(strcasecmp((char*)cur_node->name, "bounds") == 0)
765 osm->bounds = osm_parse_osm_bounds(osm, doc, cur_node);
766 else if(strcasecmp((char*)cur_node->name, "node") == 0) {
767 /* parse node and attach it to chain */
768 node_t *new = osm_parse_osm_node(osm, doc, cur_node);
769 if(new) {
770 node_t **node = &osm->node;
771
772 #ifdef OSM_SORT_ID
773 /* search chain of nodes */
774 while(*node && ((*node)->id < new->id))
775 node = &(*node)->next;
776 #endif
777
778 #ifdef OSM_SORT_LAST
779 while(*node) node = &(*node)->next;
780 #endif
781
782 /* insert into chain */
783 new->next = *node;
784 *node = new;
785 }
786 } else if(strcasecmp((char*)cur_node->name, "way") == 0) {
787 /* parse way and attach it to chain */
788 way_t *new = osm_parse_osm_way(osm, doc, cur_node);
789 if(new) {
790 way_t **way = &osm->way;
791
792 #ifdef OSM_SORT_ID
793 /* insert into chain */
794 while(*way && ((*way)->id < new->id))
795 way = &(*way)->next;
796 #endif
797
798 #ifdef OSM_SORT_LAST
799 while(*way) way = &(*way)->next;
800 #endif
801
802 /* insert into chain */
803 new->next = *way;
804 *way = new;
805 }
806 } else if(strcasecmp((char*)cur_node->name, "relation") == 0) {
807 /* parse relation and attach it to chain */
808 relation_t *new = osm_parse_osm_relation(osm, doc, cur_node);
809 if(new) {
810 relation_t **relation = &osm->relation;
811
812 #ifdef OSM_SORT_ID
813 /* search chain of ways */
814 while(*relation && ((*relation)->id < new->id))
815 relation = &(*relation)->next;
816 #endif
817
818 #ifdef OSM_SORT_LAST
819 while(*relation) relation = &(*relation)->next;
820 #endif
821
822 /* insert into chain */
823 new->next = *relation;
824 *relation = new;
825 }
826 } else
827 printf("found unhandled osm/%s\n", cur_node->name);
828
829 }
830 }
831 }
832
833 /* parse root element and search for "osm" */
834 static osm_t *osm_parse_root(xmlDocPtr doc, xmlNode * a_node) {
835 osm_t *osm;
836 xmlNode *cur_node = NULL;
837
838 /* allocate memory to hold osm file description */
839 osm = g_new0(osm_t, 1);
840
841 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
842 if (cur_node->type == XML_ELEMENT_NODE) {
843 /* parse osm osm file ... */
844 if(strcasecmp((char*)cur_node->name, "osm") == 0)
845 osm_parse_osm(osm, doc, cur_node);
846 else
847 printf("found unhandled %s\n", cur_node->name);
848 }
849 }
850
851 return osm;
852 }
853
854 static osm_t *osm_parse_doc(xmlDocPtr doc) {
855 osm_t *osm;
856
857 /* Get the root element node */
858 xmlNode *root_element = xmlDocGetRootElement(doc);
859
860 osm = osm_parse_root(doc, root_element);
861
862 /*free the document */
863 xmlFreeDoc(doc);
864
865 /*
866 * Free the global variables that may
867 * have been allocated by the parser.
868 */
869 xmlCleanupParser();
870
871 return osm;
872 }
873 #endif
874
875 /* ------------------ osm handling ----------------- */
876
877 void osm_free(icon_t **icon, osm_t *osm) {
878 if(!osm) return;
879
880 if(osm->bounds) osm_bounds_free(osm->bounds);
881 if(osm->user) osm_users_free(osm->user);
882 if(osm->way) osm_ways_free(osm->way);
883 if(osm->node) osm_nodes_free(icon, osm->node);
884 if(osm->relation) osm_relations_free(osm->relation);
885 g_free(osm);
886 }
887
888 void osm_dump(osm_t *osm) {
889 osm_bounds_dump(osm->bounds);
890 osm_users_dump(osm->user);
891 osm_nodes_dump(osm->node);
892 osm_ways_dump(osm->way);
893 osm_relations_dump(osm->relation);
894 }
895
896 #ifdef OSM_STREAM_PARSER
897 /* -------------------------- stream parser tests ------------------- */
898
899 #include <libxml/xmlreader.h>
900
901 static gint my_strcmp(const xmlChar *a, const xmlChar *b) {
902 if(!a && !b) return 0;
903 if(!a) return -1;
904 if(!b) return +1;
905 return strcmp((char*)a,(char*)b);
906 }
907
908 /* skip current element incl. everything below (mainly for testing) */
909 /* returns FALSE if something failed */
910 static gboolean skip_element(xmlTextReaderPtr reader) {
911 g_assert(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT);
912 const xmlChar *name = xmlTextReaderConstName(reader);
913 g_assert(name);
914 int depth = xmlTextReaderDepth(reader);
915
916 if(xmlTextReaderIsEmptyElement(reader))
917 return TRUE;
918
919 int ret = xmlTextReaderRead(reader);
920 while((ret == 1) &&
921 ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
922 (xmlTextReaderDepth(reader) > depth) ||
923 (my_strcmp(xmlTextReaderConstName(reader), name) != 0))) {
924 ret = xmlTextReaderRead(reader);
925 }
926 return(ret == 1);
927 }
928
929 /* parse bounds */
930 static bounds_t *process_bounds(xmlTextReaderPtr reader) {
931 char *prop = NULL;
932 bounds_t *bounds = g_new0(bounds_t, 1);
933
934 bounds->ll_min.lat = bounds->ll_min.lon = NAN;
935 bounds->ll_max.lat = bounds->ll_max.lon = NAN;
936
937 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "minlat"))) {
938 bounds->ll_min.lat = g_ascii_strtod(prop, NULL);
939 xmlFree(prop);
940 }
941
942 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "maxlat"))) {
943 bounds->ll_max.lat = g_ascii_strtod(prop, NULL);
944 xmlFree(prop);
945 }
946
947 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "minlon"))) {
948 bounds->ll_min.lon = g_ascii_strtod(prop, NULL);
949 xmlFree(prop);
950 }
951
952 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "maxlon"))) {
953 bounds->ll_max.lon = g_ascii_strtod(prop, NULL);
954 xmlFree(prop);
955 }
956
957 if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
958 isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
959 errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
960 bounds->ll_min.lat, bounds->ll_min.lon,
961 bounds->ll_max.lat, bounds->ll_max.lon);
962
963 osm_bounds_free(bounds);
964 return NULL;
965 }
966
967 /* skip everything below */
968 skip_element(reader);
969
970 /* calculate map zone which will be used as a reference for all */
971 /* drawing/projection later on */
972 pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
973 (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
974
975 pos2lpos_center(&center, &bounds->center);
976
977 /* the scale is needed to accomodate for "streching" */
978 /* by the mercartor projection */
979 bounds->scale = cos(DEG2RAD(center.lat));
980
981 pos2lpos_center(&bounds->ll_min, &bounds->min);
982 bounds->min.x -= bounds->center.x;
983 bounds->min.y -= bounds->center.y;
984 bounds->min.x *= bounds->scale;
985 bounds->min.y *= bounds->scale;
986
987 pos2lpos_center(&bounds->ll_max, &bounds->max);
988 bounds->max.x -= bounds->center.x;
989 bounds->max.y -= bounds->center.y;
990 bounds->max.x *= bounds->scale;
991 bounds->max.y *= bounds->scale;
992
993 return bounds;
994 }
995
996 static tag_t *process_tag(xmlTextReaderPtr reader) {
997 /* allocate a new tag structure */
998 tag_t *tag = g_new0(tag_t, 1);
999
1000 char *prop;
1001 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "k"))) {
1002 if(strlen(prop) > 0) tag->key = g_strdup(prop);
1003 xmlFree(prop);
1004 }
1005
1006 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "v"))) {
1007 if(strlen(prop) > 0) tag->value = g_strdup(prop);
1008 xmlFree(prop);
1009 }
1010
1011 if(!tag->key || !tag->value) {
1012 printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1013 osm_tags_free(tag);
1014 tag = NULL;
1015 }
1016
1017 skip_element(reader);
1018 return tag;
1019 }
1020
1021 static node_t *process_node(xmlTextReaderPtr reader, osm_t *osm) {
1022
1023 /* allocate a new node structure */
1024 node_t *node = g_new0(node_t, 1);
1025 node->pos.lat = node->pos.lon = NAN;
1026
1027 char *prop;
1028 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1029 node->id = strtoul(prop, NULL, 10);
1030 xmlFree(prop);
1031 }
1032
1033 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) {
1034 node->pos.lat = g_ascii_strtod(prop, NULL);
1035 xmlFree(prop);
1036 }
1037
1038 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lon"))) {
1039 node->pos.lon = g_ascii_strtod(prop, NULL);
1040 xmlFree(prop);
1041 }
1042
1043 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1044 node->user = osm_user(osm, prop);
1045 xmlFree(prop);
1046 }
1047
1048 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1049 node->visible = (strcasecmp(prop, "true") == 0);
1050 xmlFree(prop);
1051 }
1052
1053 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1054 node->time = convert_iso8601(prop);
1055 xmlFree(prop);
1056 }
1057
1058 pos2lpos(osm->bounds, &node->pos, &node->lpos);
1059
1060 /* just an empty element? then return the node as it is */
1061 if(xmlTextReaderIsEmptyElement(reader))
1062 return node;
1063
1064 /* parse tags if present */
1065 int depth = xmlTextReaderDepth(reader);
1066
1067 /* scan all elements on same level or its children */
1068 tag_t **tag = &node->tag;
1069 int ret = xmlTextReaderRead(reader);
1070 while((ret == 1) &&
1071 ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1072 (xmlTextReaderDepth(reader) != depth))) {
1073
1074 if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1075 char *subname = (char*)xmlTextReaderConstName(reader);
1076 if(strcasecmp(subname, "tag") == 0) {
1077 *tag = process_tag(reader);
1078 if(*tag) tag = &(*tag)->next;
1079 } else
1080 skip_element(reader);
1081 }
1082
1083 ret = xmlTextReaderRead(reader);
1084 }
1085
1086 return node;
1087 }
1088
1089 static node_chain_t *process_nd(xmlTextReaderPtr reader, osm_t *osm) {
1090 char *prop;
1091
1092 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
1093 item_id_t id = strtoul(prop, NULL, 10);
1094 node_chain_t *node_chain = g_new0(node_chain_t, 1);
1095
1096 /* search matching node */
1097 node_chain->node = osm->node;
1098 while(node_chain->node && node_chain->node->id != id)
1099 node_chain->node = node_chain->node->next;
1100
1101 if(!node_chain->node) printf("Node id %lu not found\n", id);
1102
1103 if(node_chain->node)
1104 node_chain->node->ways++;
1105
1106 xmlFree(prop);
1107
1108 skip_element(reader);
1109 return node_chain;
1110 }
1111
1112 skip_element(reader);
1113 return NULL;
1114 }
1115
1116 static way_t *process_way(xmlTextReaderPtr reader, osm_t *osm) {
1117 /* allocate a new way structure */
1118 way_t *way = g_new0(way_t, 1);
1119
1120 char *prop;
1121 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1122 way->id = strtoul(prop, NULL, 10);
1123 xmlFree(prop);
1124 }
1125
1126 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1127 way->user = osm_user(osm, prop);
1128 xmlFree(prop);
1129 }
1130
1131 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1132 way->visible = (strcasecmp(prop, "true") == 0);
1133 xmlFree(prop);
1134 }
1135
1136 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1137 way->time = convert_iso8601(prop);
1138 xmlFree(prop);
1139 }
1140
1141 /* just an empty element? then return the way as it is */
1142 /* (this should in fact never happen as this would be a way without nodes) */
1143 if(xmlTextReaderIsEmptyElement(reader))
1144 return way;
1145
1146 /* parse tags/nodes if present */
1147 int depth = xmlTextReaderDepth(reader);
1148
1149 /* scan all elements on same level or its children */
1150 tag_t **tag = &way->tag;
1151 node_chain_t **node_chain = &way->node_chain;
1152 int ret = xmlTextReaderRead(reader);
1153 while((ret == 1) &&
1154 ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1155 (xmlTextReaderDepth(reader) != depth))) {
1156
1157 if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1158 char *subname = (char*)xmlTextReaderConstName(reader);
1159 if(strcasecmp(subname, "nd") == 0) {
1160 *node_chain = process_nd(reader, osm);
1161 if(*node_chain) node_chain = &(*node_chain)->next;
1162 } else if(strcasecmp(subname, "tag") == 0) {
1163 *tag = process_tag(reader);
1164 if(*tag) tag = &(*tag)->next;
1165 } else
1166 skip_element(reader);
1167 }
1168 ret = xmlTextReaderRead(reader);
1169 }
1170
1171 return way;
1172 }
1173
1174 static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) {
1175 char *prop;
1176 member_t *member = g_new0(member_t, 1);
1177 member->type = ILLEGAL;
1178
1179 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) {
1180 if(strcasecmp(prop, "way") == 0) member->type = WAY;
1181 else if(strcasecmp(prop, "node") == 0) member->type = NODE;
1182 else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;
1183 xmlFree(prop);
1184 }
1185
1186 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
1187 item_id_t id = strtoul(prop, NULL, 10);
1188
1189 switch(member->type) {
1190 case ILLEGAL:
1191 printf("Unable to store illegal type\n");
1192 break;
1193
1194 case WAY:
1195 /* search matching way */
1196 member->way = osm->way;
1197 while(member->way && member->way->id != id)
1198 member->way = member->way->next;
1199
1200 if(!member->way) {
1201 member->type = WAY_ID;
1202 member->id = id;
1203 }
1204 break;
1205
1206 case NODE:
1207 /* search matching node */
1208 member->node = osm->node;
1209 while(member->node && member->node->id != id)
1210 member->node = member->node->next;
1211
1212 if(!member->node) {
1213 member->type = NODE_ID;
1214 member->id = id;
1215 }
1216 break;
1217
1218 case RELATION:
1219 /* search matching relation */
1220 member->relation = osm->relation;
1221 while(member->relation && member->relation->id != id)
1222 member->relation = member->relation->next;
1223
1224 if(!member->relation) {
1225 member->type = NODE_ID;
1226 member->id = id;
1227 }
1228 break;
1229
1230 case WAY_ID:
1231 case NODE_ID:
1232 case RELATION_ID:
1233 break;
1234 }
1235
1236 xmlFree(prop);
1237 }
1238
1239 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "role"))) {
1240 if(strlen(prop) > 0) member->role = g_strdup(prop);
1241 xmlFree(prop);
1242 }
1243
1244 return member;
1245 }
1246
1247 static relation_t *process_relation(xmlTextReaderPtr reader, osm_t *osm) {
1248 /* allocate a new relation structure */
1249 relation_t *relation = g_new0(relation_t, 1);
1250
1251 char *prop;
1252 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "id"))) {
1253 relation->id = strtoul(prop, NULL, 10);
1254 xmlFree(prop);
1255 }
1256
1257 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
1258 relation->user = osm_user(osm, prop);
1259 xmlFree(prop);
1260 }
1261
1262 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "visible"))) {
1263 relation->visible = (strcasecmp(prop, "true") == 0);
1264 xmlFree(prop);
1265 }
1266
1267 if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp"))) {
1268 relation->time = convert_iso8601(prop);
1269 xmlFree(prop);
1270 }
1271
1272 /* just an empty element? then return the relation as it is */
1273 /* (this should in fact never happen as this would be a relation */
1274 /* without members) */
1275 if(xmlTextReaderIsEmptyElement(reader))
1276 return relation;
1277
1278 /* parse tags/member if present */
1279 int depth = xmlTextReaderDepth(reader);
1280
1281 /* scan all elements on same level or its children */
1282 tag_t **tag = &relation->tag;
1283 member_t **member = &relation->member;
1284 int ret = xmlTextReaderRead(reader);
1285 while((ret == 1) &&
1286 ((xmlTextReaderNodeType(reader) != XML_READER_TYPE_END_ELEMENT) ||
1287 (xmlTextReaderDepth(reader) != depth))) {
1288
1289 if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
1290 char *subname = (char*)xmlTextReaderConstName(reader);
1291 if(strcasecmp(subname, "member") == 0) {
1292 *member = process_member(reader, osm);
1293 if(*member) member = &(*member)->next;
1294 } else if(strcasecmp(subname, "tag") == 0) {
1295 *tag = process_tag(reader);
1296 if(*tag) tag = &(*tag)->next;
1297 } else
1298 skip_element(reader);
1299 }
1300 ret = xmlTextReaderRead(reader);
1301 }
1302
1303 return relation;
1304 }
1305
1306 static osm_t *process_osm(xmlTextReaderPtr reader) {
1307 /* alloc osm structure */
1308 osm_t *osm = g_new0(osm_t, 1);
1309
1310 node_t **node = &osm->node;
1311 way_t **way = &osm->way;
1312 relation_t **relation = &osm->relation;
1313
1314 /* no attributes of interest */
1315
1316 const xmlChar *name = xmlTextReaderConstName(reader);
1317 g_assert(name);
1318
1319 /* read next node */
1320 int num_elems = 0;
1321 const int tick_every = 50; // Balance responsive appearance with performance.
1322 int ret = xmlTextReaderRead(reader);
1323 while(ret == 1) {
1324
1325 switch(xmlTextReaderNodeType(reader)) {
1326 case XML_READER_TYPE_ELEMENT:
1327
1328 g_assert(xmlTextReaderDepth(reader) == 1);
1329 char *name = (char*)xmlTextReaderConstName(reader);
1330 if(strcasecmp(name, "bounds") == 0) {
1331 osm->bounds = process_bounds(reader);
1332 } else if(strcasecmp(name, "node") == 0) {
1333 *node = process_node(reader, osm);
1334 if(*node) node = &(*node)->next;
1335 } else if(strcasecmp(name, "way") == 0) {
1336 *way = process_way(reader, osm);
1337 if(*way) way = &(*way)->next;
1338 } else if(strcasecmp(name, "relation") == 0) {
1339 *relation = process_relation(reader, osm);
1340 if(*relation) relation = &(*relation)->next;
1341 } else {
1342 printf("something unknown found\n");
1343 g_assert(0);
1344 skip_element(reader);
1345 }
1346 break;
1347
1348 case XML_READER_TYPE_END_ELEMENT:
1349 /* end element must be for the current element */
1350 g_assert(xmlTextReaderDepth(reader) == 0);
1351 return osm;
1352 break;
1353
1354 default:
1355 break;
1356 }
1357 ret = xmlTextReaderRead(reader);
1358
1359 if (num_elems++ > tick_every) {
1360 num_elems = 0;
1361 banner_busy_tick();
1362 }
1363 }
1364
1365 g_assert(0);
1366 return NULL;
1367 }
1368
1369 static osm_t *process_file(const char *filename) {
1370 osm_t *osm = NULL;
1371 xmlTextReaderPtr reader;
1372 int ret;
1373
1374 reader = xmlReaderForFile(filename, NULL, 0);
1375 if (reader != NULL) {
1376 ret = xmlTextReaderRead(reader);
1377 if(ret == 1) {
1378 char *name = (char*)xmlTextReaderConstName(reader);
1379 if(name && strcasecmp(name, "osm") == 0)
1380 osm = process_osm(reader);
1381 } else
1382 printf("file empty\n");
1383
1384 xmlFreeTextReader(reader);
1385 } else {
1386 fprintf(stderr, "Unable to open %s\n", filename);
1387 }
1388 return osm;
1389 }
1390
1391 /* ----------------------- end of stream parser tests ------------------- */
1392 #endif
1393
1394 #ifdef OSM_QND_XML_PARSER
1395 /* -------------------------- qnd-xml parser tests ------------------- */
1396
1397 #ifdef USE_FLOAT
1398 #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c)
1399 #else
1400 #define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c)
1401 #endif
1402
1403 gboolean osm_bounds_cb(qnd_xml_stack_t *stack,
1404 qnd_xml_attribute_t *attributes, gpointer data) {
1405
1406 /* get parent pointer */
1407 osm_t *osm = (osm_t*)stack->prev->userdata[0];
1408
1409 if(osm->bounds) {
1410 errorf(NULL, "Doubly defined bounds");
1411 return FALSE;
1412 }
1413
1414 bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1);
1415
1416 bounds->ll_min.lat = bounds->ll_min.lon = NAN;
1417 bounds->ll_max.lat = bounds->ll_max.lon = NAN;
1418
1419 GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat);
1420 GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon);
1421 GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat);
1422 GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon);
1423
1424 if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
1425 isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
1426 errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
1427 bounds->ll_min.lat, bounds->ll_min.lon,
1428 bounds->ll_max.lat, bounds->ll_max.lon);
1429
1430 osm_bounds_free(bounds);
1431 osm->bounds = NULL;
1432 return FALSE;
1433 }
1434
1435
1436 /* calculate map zone which will be used as a reference for all */
1437 /* drawing/projection later on */
1438 pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1439 (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1440
1441 pos2lpos_center(&center, &bounds->center);
1442
1443 /* the scale is needed to accomodate for "streching" */
1444 /* by the mercartor projection */
1445 bounds->scale = cos(DEG2RAD(center.lat));
1446
1447 pos2lpos_center(&bounds->ll_min, &bounds->min);
1448 bounds->min.x -= bounds->center.x;
1449 bounds->min.y -= bounds->center.y;
1450 bounds->min.x *= bounds->scale;
1451 bounds->min.y *= bounds->scale;
1452
1453 pos2lpos_center(&bounds->ll_max, &bounds->max);
1454 bounds->max.x -= bounds->center.x;
1455 bounds->max.y -= bounds->center.y;
1456 bounds->max.x *= bounds->scale;
1457 bounds->max.y *= bounds->scale;
1458
1459 return TRUE;
1460 }
1461
1462 static gboolean osm_tag_cb(qnd_xml_stack_t *stack,
1463 qnd_xml_attribute_t *attributes, gpointer data) {
1464
1465 tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1);
1466
1467 tag->key = qnd_xml_get_prop_str(attributes, "k");
1468 tag->value = qnd_xml_get_prop_str(attributes, "v");
1469
1470 if(!tag->key || !tag->value) {
1471 printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1472 osm_tags_free(tag);
1473 tag = NULL;
1474 } else
1475 stack->prev->userdata[1] = &tag->next;
1476
1477 return TRUE;
1478 }
1479
1480 static gboolean osm_node_cb(qnd_xml_stack_t *stack,
1481 qnd_xml_attribute_t *attributes, gpointer data) {
1482
1483 osm_t *osm = (osm_t*)stack->prev->userdata[0];
1484
1485 /* allocate a new node structure. userdata[1] points to the current */
1486 /* position a new node is to be stored */
1487 node_t *node = *(node_t**)stack->prev->userdata[1] =
1488 stack->userdata[0] = g_new0(node_t, 1);
1489 stack->prev->userdata[1] = &node->next;
1490
1491 qnd_xml_get_prop_gulong(attributes, "id", &node->id);
1492 GET_PROP_POS(attributes, "lat", &node->pos.lat);
1493 GET_PROP_POS(attributes, "lon", &node->pos.lon);
1494 node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1495 node->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1496 node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1497
1498 pos2lpos(osm->bounds, &node->pos, &node->lpos);
1499
1500 /* store current tag pointer in userdata for fast access to current tag */
1501 stack->userdata[1] = &node->tag;
1502
1503 return TRUE;
1504 }
1505
1506 static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack,
1507 qnd_xml_attribute_t *attributes, gpointer data) {
1508
1509 osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1510
1511 item_id_t id;
1512 if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1513 /* allocate a new node_chain structure */
1514 node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] =
1515 g_new0(node_chain_t, 1);
1516
1517 /* search matching node */
1518 node_chain->node = osm->node;
1519 while(node_chain->node && node_chain->node->id != id)
1520 node_chain->node = node_chain->node->next;
1521
1522 if(!node_chain->node) printf("Node id %lu not found\n", id);
1523
1524 if(node_chain->node)
1525 node_chain->node->ways++;
1526
1527 stack->prev->userdata[2] = &node_chain->next;
1528 }
1529
1530 return TRUE;
1531 }
1532
1533 gboolean osm_way_cb(qnd_xml_stack_t *stack,
1534 qnd_xml_attribute_t *attributes, gpointer data) {
1535
1536 osm_t *osm = (osm_t*)stack->prev->userdata[0];
1537
1538 /* allocate a new way structure. userdata[2] points to the current */
1539 /* position a new way is to be stored in the way list */
1540 way_t *way = *(way_t**)stack->prev->userdata[2] =
1541 stack->userdata[0] = g_new0(way_t, 1);
1542 stack->prev->userdata[2] = &way->next;
1543
1544 qnd_xml_get_prop_gulong(attributes, "id", &way->id);
1545 way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1546 way->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1547 way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1548
1549 /* store current tag and node_chain pointers in userdata for fast */
1550 /* access to current tag/node_chain entry */
1551 stack->userdata[1] = &way->tag;
1552 stack->userdata[2] = &way->node_chain;
1553
1554 return TRUE;
1555 }
1556
1557 static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack,
1558 qnd_xml_attribute_t *attributes, gpointer data) {
1559
1560 osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1561
1562 member_t *member = *(member_t**)stack->prev->userdata[2] =
1563 g_new0(member_t, 1);
1564 stack->prev->userdata[2] = &member->next;
1565 member->type = ILLEGAL;
1566
1567 char *type = qnd_xml_get_prop(attributes, "type");
1568 if(type) {
1569 if(strcasecmp(type, "way") == 0) member->type = WAY;
1570 else if(strcasecmp(type, "node") == 0) member->type = NODE;
1571 else if(strcasecmp(type, "relation") == 0) member->type = RELATION;
1572 }
1573
1574 item_id_t id;
1575 if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1576 switch(member->type) {
1577 case ILLEGAL:
1578 printf("Unable to store illegal type\n");
1579 break;
1580
1581 case WAY:
1582 /* search matching way */
1583 member->way = osm->way;
1584 while(member->way && member->way->id != id)
1585 member->way = member->way->next;
1586
1587 if(!member->way) {
1588 member->type = WAY_ID;
1589 member->id = id;
1590 }
1591 break;
1592
1593 case NODE:
1594 /* search matching node */
1595 member->node = osm->node;
1596 while(member->node && member->node->id != id)
1597 member->node = member->node->next;
1598
1599 if(!member->node) {
1600 member->type = NODE_ID;
1601 member->id = id;
1602 }
1603 break;
1604
1605 case RELATION:
1606 /* search matching relation */
1607 member->relation = osm->relation;
1608 while(member->relation && member->relation->id != id)
1609 member->relation = member->relation->next;
1610
1611 if(!member->relation) {
1612 member->type = NODE_ID;
1613 member->id = id;
1614 }
1615 break;
1616
1617 case WAY_ID:
1618 case NODE_ID:
1619 case RELATION_ID:
1620 break;
1621 }
1622 }
1623
1624 return TRUE;
1625 }
1626
1627 gboolean osm_rel_cb(qnd_xml_stack_t *stack,
1628 qnd_xml_attribute_t *attributes, gpointer data) {
1629
1630 osm_t *osm = (osm_t*)stack->prev->userdata[0];
1631
1632 /* allocate a new relation structure. userdata[3] points to the current */
1633 /* position a new relation is to be stored at in the relation list */
1634 relation_t *relation = *(relation_t**)stack->prev->userdata[3] =
1635 stack->userdata[0] = g_new0(relation_t, 1);
1636 stack->prev->userdata[3] = &relation->next;
1637
1638 qnd_xml_get_prop_gulong(attributes, "id", &relation->id);
1639 relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1640 relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1641 relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1642
1643 /* store current tag and member pointers in userdata for fast access */
1644 /* to current tag and members in their chains */
1645 stack->userdata[1] = &relation->tag;
1646 stack->userdata[2] = &relation->member;
1647
1648 return TRUE;
1649 }
1650
1651 gboolean osm_cb(qnd_xml_stack_t *stack,
1652 qnd_xml_attribute_t *attributes, gpointer data) {
1653
1654 g_assert(!stack->userdata[0]);
1655
1656 /* also set parents (roots) userdata as it's the parsers return value */
1657 osm_t *osm = stack->prev->userdata[0] =
1658 stack->userdata[0] = g_new0(osm_t, 1);
1659
1660 /* store direct pointers for faster list access */
1661 /* (otherwise we'd have to search the end of the lists for every item */
1662 /* to be attached) */
1663 stack->userdata[1] = &osm->node;
1664 stack->userdata[2] = &osm->way;
1665 stack->userdata[3] = &osm->relation;
1666
1667 return TRUE;
1668 }
1669
1670
1671 /* these structures describe the content qnd_xml expects while parsing */
1672 qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1673
1674 qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1675 qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF };
1676
1677 qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1678 qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF };
1679
1680 qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF };
1681
1682 qnd_xml_entry_t *node_children[] = { &osm_node_tag },
1683 osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) };
1684
1685 qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd },
1686 osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) };
1687
1688 qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member },
1689 osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) };
1690
1691 /* the osm element */
1692 qnd_xml_entry_t *osm_children[] = {
1693 &osm_bounds, &osm_node, &osm_way, &osm_rel };
1694 qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) };
1695
1696 /* the root element */
1697 qnd_xml_entry_t *root_children[] = { &osm };
1698 qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) };
1699
1700 // gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c
1701
1702
1703
1704 /* ----------------------- end of qnd-xml parser tests ------------------- */
1705 #endif
1706
1707
1708 #include <sys/time.h>
1709
1710 osm_t *osm_parse(char *filename) {
1711
1712 struct timeval start;
1713 gettimeofday(&start, NULL);
1714
1715
1716 #ifdef OSM_STREAM_PARSER
1717 LIBXML_TEST_VERSION;
1718
1719 // use stream parser
1720 osm_t *osm = process_file(filename);
1721 xmlCleanupParser();
1722 #endif
1723
1724 #ifdef OSM_DOM_PARSER
1725 LIBXML_TEST_VERSION;
1726
1727 // parse into a tree
1728 /* parse the file and get the DOM */
1729 xmlDoc *doc = NULL;
1730 if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) {
1731 xmlErrorPtr errP = xmlGetLastError();
1732 errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message);
1733 return NULL;
1734 }
1735
1736 osm_t *osm = osm_parse_doc(doc);
1737 #endif
1738
1739 #ifdef OSM_QND_XML_PARSER
1740 osm_t *osm = NULL;
1741 if(!(osm = qnd_xml_parse(filename, &root, NULL))) {
1742 errorf(NULL, "While parsing \"%s\"", filename);
1743 return NULL;
1744 }
1745 #endif
1746
1747 struct timeval end;
1748 gettimeofday(&end, NULL);
1749
1750 printf("total parse time: %ldms\n",
1751 (end.tv_usec - start.tv_usec)/1000 +
1752 (end.tv_sec - start.tv_sec)*1000);
1753
1754 return osm;
1755 }
1756
1757 gboolean osm_sanity_check(GtkWidget *parent, osm_t *osm) {
1758 if(!osm->bounds) {
1759 errorf(parent, _("Invalid data in OSM file:\n"
1760 "Boundary box missing!"));
1761 return FALSE;
1762 }
1763 if(!osm->node) {
1764 errorf(parent, _("Invalid data in OSM file:\n"
1765 "No drawable content found!"));
1766 return FALSE;
1767 }
1768 return TRUE;
1769 }
1770
1771 /* ------------------------- misc access functions -------------- */
1772
1773 char *osm_tag_get_by_key(tag_t *tag, char *key) {
1774 if(!tag || !key) return NULL;
1775
1776 while(tag) {
1777 if(strcasecmp(tag->key, key) == 0)
1778 return tag->value;
1779
1780 tag = tag->next;
1781 }
1782
1783 return NULL;
1784 }
1785
1786 char *osm_way_get_value(way_t *way, char *key) {
1787 tag_t *tag = way->tag;
1788
1789 while(tag) {
1790 if(strcasecmp(tag->key, key) == 0)
1791 return tag->value;
1792
1793 tag = tag->next;
1794 }
1795
1796 return NULL;
1797 }
1798
1799 char *osm_node_get_value(node_t *node, char *key) {
1800 tag_t *tag = node->tag;
1801
1802 while(tag) {
1803 if(strcasecmp(tag->key, key) == 0)
1804 return tag->value;
1805
1806 tag = tag->next;
1807 }
1808
1809 return NULL;
1810 }
1811
1812 gboolean osm_way_has_value(way_t *way, char *str) {
1813 tag_t *tag = way->tag;
1814
1815 while(tag) {
1816 if(tag->value && strcasecmp(tag->value, str) == 0)
1817 return TRUE;
1818
1819 tag = tag->next;
1820 }
1821 return FALSE;
1822 }
1823
1824 gboolean osm_node_has_value(node_t *node, char *str) {
1825 tag_t *tag = node->tag;
1826
1827 while(tag) {
1828 if(tag->value && strcasecmp(tag->value, str) == 0)
1829 return TRUE;
1830
1831 tag = tag->next;
1832 }
1833 return FALSE;
1834 }
1835
1836 gboolean osm_node_has_tag(node_t *node) {
1837 tag_t *tag = node->tag;
1838
1839 if(tag && strcasecmp(tag->key, "created_by") == 0)
1840 tag = tag->next;
1841
1842 return tag != NULL;
1843 }
1844
1845 /* return true if node is part of way */
1846 gboolean osm_node_in_way(way_t *way, node_t *node) {
1847 node_chain_t *node_chain = way->node_chain;
1848 while(node_chain) {
1849 if(node_chain->node == node)
1850 return TRUE;
1851
1852 node_chain = node_chain->next;
1853 }
1854 return FALSE;
1855 }
1856
1857 static void osm_generate_tags(tag_t *tag, xmlNodePtr node) {
1858 while(tag) {
1859 /* make sure "created_by" tag contains our id */
1860 if(strcasecmp(tag->key, "created_by") == 0) {
1861 g_free(tag->value);
1862 tag->value = g_strdup(PACKAGE " v" VERSION);
1863 }
1864
1865 xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL);
1866 xmlNewProp(tag_node, BAD_CAST "k", BAD_CAST tag->key);
1867 xmlNewProp(tag_node, BAD_CAST "v", BAD_CAST tag->value);
1868 tag = tag->next;
1869 }
1870 }
1871
1872 /* build xml representation for a way */
1873 char *osm_generate_xml(osm_t *osm, type_t type, void *item) {
1874 char str[32];
1875 xmlChar *result = NULL;
1876 int len = 0;
1877
1878 LIBXML_TEST_VERSION;
1879
1880 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1881 xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");
1882 xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0.5");
1883 xmlNewProp(root_node, BAD_CAST "generator", BAD_CAST PACKAGE " V" VERSION);
1884 xmlDocSetRootElement(doc, root_node);
1885
1886 switch(type) {
1887 case NODE:
1888 {
1889 node_t *node = (node_t*)item;
1890 xmlNodePtr node_node = xmlNewChild(root_node, NULL,
1891 BAD_CAST "node", NULL);
1892 /* new nodes don't have an id, but get one after the upload */
1893 if(!(node->flags & OSM_FLAG_NEW)) {
1894 snprintf(str, sizeof(str), "%u", (unsigned)node->id);
1895 xmlNewProp(node_node, BAD_CAST "id", BAD_CAST str);
1896 }
1897 g_ascii_dtostr(str, sizeof(str), node->pos.lat);
1898 xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str);
1899 g_ascii_dtostr(str, sizeof(str), node->pos.lon);
1900 xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str);
1901 osm_generate_tags(node->tag, node_node);
1902 }
1903 break;
1904
1905 case WAY:
1906 {
1907 way_t *way = (way_t*)item;
1908 xmlNodePtr way_node = xmlNewChild(root_node, NULL, BAD_CAST "way", NULL);
1909 snprintf(str, sizeof(str), "%u", (unsigned)way->id);
1910 xmlNewProp(way_node, BAD_CAST "id", BAD_CAST str);
1911
1912 node_chain_t *node_chain = way->node_chain;
1913 while(node_chain) {
1914 xmlNodePtr nd_node = xmlNewChild(way_node, NULL, BAD_CAST "nd", NULL);
1915 char *str = g_strdup_printf("%ld", node_chain->node->id);
1916 xmlNewProp(nd_node, BAD_CAST "ref", BAD_CAST str);
1917 g_free(str);
1918 node_chain = node_chain->next;
1919 }
1920
1921 osm_generate_tags(way->tag, way_node);
1922 }
1923 break;
1924
1925 case RELATION:
1926 {
1927 relation_t *relation = (relation_t*)item;
1928 xmlNodePtr rel_node = xmlNewChild(root_node, NULL,
1929 BAD_CAST "relation", NULL);
1930 snprintf(str, sizeof(str), "%u", (unsigned)relation->id);
1931 xmlNewProp(rel_node, BAD_CAST "id", BAD_CAST str);
1932
1933 member_t *member = relation->member;
1934 while(member) {
1935 xmlNodePtr m_node = xmlNewChild(rel_node,NULL,BAD_CAST "member", NULL);
1936 char *str = NULL;
1937
1938 switch(member->type) {
1939 case NODE:
1940 xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "node");
1941 str = g_strdup_printf("%ld", member->node->id);
1942 break;
1943
1944 case WAY:
1945 xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "way");
1946 str = g_strdup_printf("%ld", member->way->id);
1947 break;
1948
1949 case RELATION:
1950 xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "relation");
1951 str = g_strdup_printf("%ld", member->relation->id);
1952 break;
1953
1954 default:
1955 break;
1956 }
1957
1958 if(str) {
1959 xmlNewProp(m_node, BAD_CAST "ref", BAD_CAST str);
1960 g_free(str);
1961 }
1962
1963 if(member->role)
1964 xmlNewProp(m_node, BAD_CAST "role", BAD_CAST member->role);
1965 else
1966 xmlNewProp(m_node, BAD_CAST "role", BAD_CAST "");
1967
1968 member = member->next;
1969 }
1970 osm_generate_tags(relation->tag, rel_node);
1971 }
1972 break;
1973
1974 default:
1975 printf("neither NODE nor WAY nor RELATION\n");
1976 g_assert(0);
1977 break;
1978 }
1979
1980 xmlDocDumpFormatMemoryEnc(doc, &result, &len, "UTF-8", 1);
1981 xmlFreeDoc(doc);
1982 xmlCleanupParser();
1983
1984 // puts("xml encoding result:");
1985 // puts((char*)result);
1986
1987 return (char*)result;
1988 }
1989
1990 /* build xml representation for a node */
1991 char *osm_generate_xml_node(osm_t *osm, node_t *node) {
1992 return osm_generate_xml(osm, NODE, node);
1993 }
1994
1995 /* build xml representation for a way */
1996 char *osm_generate_xml_way(osm_t *osm, way_t *way) {
1997 return osm_generate_xml(osm, WAY, way);
1998 }
1999
2000 /* build xml representation for a relation */
2001 char *osm_generate_xml_relation(osm_t *osm, relation_t *relation) {
2002 return osm_generate_xml(osm, RELATION, relation);
2003 }
2004
2005 node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) {
2006 node_t *node = osm->node;
2007 while(node) {
2008 if(node->id == id)
2009 return node;
2010
2011 node = node->next;
2012 }
2013 return NULL;
2014 }
2015
2016 way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) {
2017 way_t *way = osm->way;
2018 while(way) {
2019 if(way->id == id)
2020 return way;
2021
2022 way = way->next;
2023 }
2024 return NULL;
2025 }
2026
2027 relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) {
2028 relation_t *relation = osm->relation;
2029 while(relation) {
2030 if(relation->id == id)
2031 return relation;
2032
2033 relation = relation->next;
2034 }
2035
2036 return NULL;
2037 }
2038
2039 /* ---------- edit functions ------------- */
2040
2041 item_id_t osm_new_way_id(osm_t *osm) {
2042 item_id_t id = -1;
2043
2044 while(TRUE) {
2045 gboolean found = FALSE;
2046 way_t *way = osm->way;
2047 while(way) {
2048 if(way->id == id)
2049 found = TRUE;
2050
2051 way = way->next;
2052 }
2053
2054 /* no such id so far -> use it */
2055 if(!found) return id;
2056
2057 id--;
2058 }
2059 g_assert(0);
2060 return 0;
2061 }
2062
2063 item_id_t osm_new_node_id(osm_t *osm) {
2064 item_id_t id = -1;
2065
2066 while(TRUE) {
2067 gboolean found = FALSE;
2068 node_t *node = osm->node;
2069 while(node) {
2070 if(node->id == id)
2071 found = TRUE;
2072
2073 node = node->next;
2074 }
2075
2076 /* no such id so far -> use it */
2077 if(!found) return id;
2078
2079 id--;
2080 }
2081 g_assert(0);
2082 return 0;
2083 }
2084
2085 node_t *osm_node_new(osm_t *osm, gint x, gint y) {
2086 printf("Creating new node\n");
2087
2088 node_t *node = g_new0(node_t, 1);
2089 node->lpos.x = x;
2090 node->lpos.y = y;
2091 node->visible = TRUE;
2092 node->time = time(NULL);
2093
2094 /* add created_by tag */
2095 node->tag = g_new0(tag_t, 1);
2096 node->tag->key = g_strdup("created_by");
2097 node->tag->value = g_strdup(PACKAGE " v" VERSION);
2098
2099 /* convert screen position back to ll */
2100 lpos2pos(osm->bounds, &node->lpos, &node->pos);
2101
2102 printf(" new at %d %d (%f %f)\n",
2103 node->lpos.x, node->lpos.y, node->pos.lat, node->pos.lon);
2104
2105 return node;
2106 }
2107
2108
2109 void osm_node_attach(osm_t *osm, node_t *node) {
2110 printf("Attaching node\n");
2111
2112 node->id = osm_new_node_id(osm);
2113 node->flags = OSM_FLAG_NEW;
2114
2115 /* attach to end of node list */
2116 node_t **lnode = &osm->node;
2117 while(*lnode) lnode = &(*lnode)->next;
2118 *lnode = node;
2119 }
2120
2121 way_t *osm_way_new(void) {
2122 printf("Creating new way\n");
2123
2124 way_t *way = g_new0(way_t, 1);
2125 way->visible = TRUE;
2126 way->flags = OSM_FLAG_NEW;
2127 way->time = time(NULL);
2128
2129 /* add created_by tag */
2130 way->tag = g_new0(tag_t, 1);
2131 way->tag->key = g_strdup("created_by");
2132 way->tag->value = g_strdup(PACKAGE " v" VERSION);
2133
2134 return way;
2135 }
2136
2137 void osm_way_attach(osm_t *osm, way_t *way) {
2138 printf("Attaching way\n");
2139
2140 way->id = osm_new_way_id(osm);
2141 way->flags = OSM_FLAG_NEW;
2142
2143 /* attach to end of way list */
2144 way_t **lway = &osm->way;
2145 while(*lway) lway = &(*lway)->next;
2146 *lway = way;
2147 }
2148
2149 /* returns pointer to chain of ways affected by this deletion */
2150 way_chain_t *osm_node_delete(osm_t *osm, icon_t **icon,
2151 node_t *node, gboolean permanently,
2152 gboolean affect_ways) {
2153 way_chain_t *way_chain = NULL, **cur_way_chain = &way_chain;
2154
2155 /* new nodes aren't stored on the server and are just deleted permanently */
2156 if(node->flags & OSM_FLAG_NEW) {
2157 printf("About to delete NEW node #%ld -> force permanent delete\n",
2158 node->id);
2159 permanently = TRUE;
2160 }
2161
2162 /* first remove node from all ways using it */
2163 way_t *way = osm->way;
2164 while(way) {
2165 node_chain_t **chain = &(way->node_chain);
2166 gboolean modified = FALSE;
2167 while(*chain) {
2168 /* remove node from chain */
2169 if(node == (*chain)->node) {
2170 modified = TRUE;
2171 if(affect_ways) {
2172 node_chain_t *next = (*chain)->next;
2173 g_free(*chain);
2174 *chain = next;
2175 } else
2176 chain = &((*chain)->next);
2177 } else
2178 chain = &((*chain)->next);
2179 }
2180
2181 if(modified) {
2182 way->flags |= OSM_FLAG_DIRTY;
2183
2184 /* and add the way to the list of affected ways */
2185 *cur_way_chain = g_new0(way_chain_t, 1);
2186 (*cur_way_chain)->way = way;
2187 cur_way_chain = &((*cur_way_chain)->next);
2188 }
2189
2190 way = way->next;
2191 }
2192
2193 if(!permanently) {
2194 printf("mark node #%ld as deleted\n", node->id);
2195 node->flags |= OSM_FLAG_DELETED;
2196 } else {
2197 printf("permanently delete node #%ld\n", node->id);
2198
2199 /* remove it from the chain */
2200 node_t **cnode = &osm->node;
2201 int found = 0;
2202
2203 while(*cnode) {
2204 if(*cnode == node) {
2205 found++;
2206 *cnode = (*cnode)->next;
2207
2208 osm_node_free(icon, node);
2209 } else
2210 cnode = &((*cnode)->next);
2211 }
2212 g_assert(found == 1);
2213 }
2214
2215 return way_chain;
2216 }
2217
2218 guint osm_way_number_of_nodes(way_t *way) {
2219 guint nodes = 0;
2220 node_chain_t *chain = way->node_chain;
2221 while(chain) {
2222 nodes++;
2223 chain = chain->next;
2224 }
2225 return nodes;
2226 }
2227
2228 /* return all relations a node is in */
2229 relation_chain_t *osm_node_to_relation(osm_t *osm, node_t *node) {
2230 relation_chain_t *rel_chain = NULL, **cur_rel_chain = &rel_chain;
2231
2232 relation_t *relation = osm->relation;
2233 while(relation) {
2234 gboolean is_member = FALSE;
2235
2236 member_t *member = relation->member;
2237 while(member) {
2238 switch(member->type) {
2239 case NODE:
2240 /* nodes are checked directly */
2241 if(member->node == node)
2242 is_member = TRUE;
2243 break;
2244
2245 case WAY: {
2246 /* ways have to be checked for the nodes they consist of */
2247 node_chain_t *chain = member->way->node_chain;
2248 while(chain && !is_member) {
2249 if(chain->node == node)
2250 is_member = TRUE;
2251
2252 chain = chain->next;
2253 }
2254 } break;
2255
2256 default:
2257 break;
2258 }
2259 member = member->next;
2260 }
2261
2262 /* node is a member of this relation, so move it to the member chain */
2263 if(is_member) {
2264 *cur_rel_chain = g_new0(relation_chain_t, 1);
2265 (*cur_rel_chain)->relation = relation;
2266 cur_rel_chain = &((*cur_rel_chain)->next);
2267 }
2268
2269 relation = relation->next;
2270 }
2271
2272 return rel_chain;
2273 }
2274
2275 /* return all relations a way is in */
2276 relation_chain_t *osm_way_to_relation(osm_t *osm, way_t *way) {
2277 relation_chain_t *rel_chain = NULL, **cur_rel_chain = &rel_chain;
2278
2279 relation_t *relation = osm->relation;
2280 while(relation) {
2281 gboolean is_member = FALSE;
2282
2283 member_t *member = relation->member;
2284 while(member) {
2285 switch(member->type) {
2286 case WAY: {
2287 /* ways can be check directly */
2288 if(member->way == way)
2289 is_member = TRUE;
2290 } break;
2291
2292 default:
2293 break;
2294 }
2295 member = member->next;
2296 }
2297
2298 /* way is a member of this relation, so move it to the member chain */
2299 if(is_member) {
2300 *cur_rel_chain = g_new0(relation_chain_t, 1);
2301 (*cur_rel_chain)->relation = relation;
2302 cur_rel_chain = &((*cur_rel_chain)->next);
2303 }
2304
2305 relation = relation->next;
2306 }
2307
2308 return rel_chain;
2309 }
2310
2311 /* return all ways a node is in */
2312 way_chain_t *osm_node_to_way(osm_t *osm, node_t *node) {
2313 way_chain_t *chain = NULL, **cur_chain = &chain;
2314
2315 way_t *way = osm->way;
2316 while(way) {
2317 gboolean is_member = FALSE;
2318
2319 node_chain_t *node_chain = way->node_chain;
2320 while(node_chain) {
2321 if(node_chain->node == node)
2322 is_member = TRUE;
2323
2324 node_chain = node_chain->next;
2325 }
2326
2327 /* node is a member of this relation, so move it to the member chain */
2328 if(is_member) {
2329 *cur_chain = g_new0(way_chain_t, 1);
2330 (*cur_chain)->way = way;
2331 cur_chain = &((*cur_chain)->next);
2332 }
2333
2334 way = way->next;
2335 }
2336
2337 return chain;
2338 }
2339
2340 gboolean osm_position_within_bounds(osm_t *osm, gint x, gint y) {
2341 if((x < osm->bounds->min.x) || (x > osm->bounds->max.x)) return FALSE;
2342 if((y < osm->bounds->min.y) || (y > osm->bounds->max.y)) return FALSE;
2343 return TRUE;
2344 }
2345
2346 /* remove the given node from all relations. used if the node is to */
2347 /* be deleted */
2348 void osm_node_remove_from_relation(osm_t *osm, node_t *node) {
2349 relation_t *relation = osm->relation;
2350 printf("removing node #%ld from all relations:\n", node->id);
2351
2352 while(relation) {
2353 member_t **member = &relation->member;
2354 while(*member) {
2355 if(((*member)->type == NODE) &&
2356 ((*member)->node == node)) {
2357
2358 printf(" from relation #%ld\n", relation->id);
2359
2360 member_t *cur = *member;
2361 *member = (*member)->next;
2362 osm_member_free(cur);
2363
2364 relation->flags |= OSM_FLAG_DIRTY;
2365 } else
2366 member = &(*member)->next;
2367 }
2368 relation = relation->next;
2369 }
2370 }
2371
2372 /* remove the given way from all relations */
2373 void osm_way_remove_from_relation(osm_t *osm, way_t *way) {
2374 relation_t *relation = osm->relation;
2375 printf("removing way #%ld from all relations:\n", way->id);
2376
2377 while(relation) {
2378 member_t **member = &relation->member;
2379 while(*member) {
2380 if(((*member)->type == WAY) &&
2381 ((*member)->way == way)) {
2382
2383 printf(" from relation #%ld\n", relation->id);
2384
2385 member_t *cur = *member;
2386 *member = (*member)->next;
2387 osm_member_free(cur);
2388
2389 relation->flags |= OSM_FLAG_DIRTY;
2390 } else
2391 member = &(*member)->next;
2392 }
2393 relation = relation->next;
2394 }
2395 }
2396
2397 void osm_way_delete(osm_t *osm, icon_t **icon,
2398 way_t *way, gboolean permanently) {
2399
2400 /* new ways aren't stored on the server and are just deleted permanently */
2401 if(way->flags & OSM_FLAG_NEW) {
2402 printf("About to delete NEW way #%ld -> force permanent delete\n",
2403 way->id);
2404 permanently = TRUE;
2405 }
2406
2407 /* delete all nodes that aren't in other use now */
2408 node_chain_t **chain = &way->node_chain;
2409 while(*chain) {
2410
2411 (*chain)->node->ways--;
2412 printf("checking node #%ld (still used by %d)\n",
2413 (*chain)->node->id, (*chain)->node->ways);
2414
2415 /* this node must only be part of this way */
2416 if(!(*chain)->node->ways) {
2417 /* delete this node, but don't let this actually affect the */
2418 /* associated ways as the only such way is the oen we are currently */
2419 /* deleting */
2420 way_chain_t *way_chain =
2421 osm_node_delete(osm, icon, (*chain)->node, FALSE, FALSE);
2422 g_assert(way_chain);
2423 while(way_chain) {
2424 way_chain_t *way_next = way_chain->next;
2425 g_assert(way_chain->way == way);
2426 g_free(way_chain);
2427 way_chain = way_next;
2428 }
2429 }
2430
2431 node_chain_t *cur = (*chain);
2432 *chain = cur->next;
2433 g_free(cur);
2434 }
2435 way->node_chain = NULL;
2436
2437 if(!permanently) {
2438 printf("mark way #%ld as deleted\n", way->id);
2439 way->flags |= OSM_FLAG_DELETED;
2440 } else {
2441 printf("permanently delete way #%ld\n", way->id);
2442
2443 /* remove it from the chain */
2444 way_t **cway = &osm->way;
2445 int found = 0;
2446
2447 while(*cway) {
2448 if(*cway == way) {
2449 found++;
2450 *cway = (*cway)->next;
2451
2452 osm_way_free(way);
2453 } else
2454 cway = &((*cway)->next);
2455 }
2456 g_assert(found == 1);
2457 }
2458 }
2459
2460 void osm_way_revert(way_t *way) {
2461 node_chain_t *new = NULL;
2462
2463 /* walk old chain first to last */
2464 node_chain_t *old = way->node_chain;
2465 while(old) {
2466 node_chain_t *next = old->next;
2467
2468 /* and prepend each node to the new chain */
2469 old->next = new;
2470 new = old;
2471
2472 old = next;
2473 }
2474
2475 way->node_chain = new;
2476 }
2477
2478 node_t *osm_way_get_first_node(way_t *way) {
2479 node_chain_t *chain = way->node_chain;
2480 if(!chain) return NULL;
2481 return chain->node;
2482 }
2483
2484 node_t *osm_way_get_last_node(way_t *way) {
2485 node_chain_t *chain = way->node_chain;
2486
2487 while(chain && chain->next) chain=chain->next;
2488
2489 if(!chain) return NULL;
2490
2491 return chain->node;
2492 }
2493
2494 void osm_way_rotate(way_t *way, gint offset) {
2495 if(!offset) return;
2496
2497 /* needs at least two nodes to work properly */
2498 g_assert(way->node_chain);
2499 g_assert(way->node_chain->next);
2500
2501 while(offset--) {
2502 node_chain_t *chain = way->node_chain;
2503 chain->node->ways--; // reduce way count of old start/end node
2504
2505 /* move all nodes ahead one chain element ... */
2506 while(chain->next) {
2507 chain->node = chain->next->node;
2508 chain = chain->next;
2509 }
2510
2511 /* ... and make last one same as first one */
2512 chain->node = way->node_chain->node;
2513 chain->node->ways++; // increase way count of new start/end node
2514 }
2515 }
2516
2517 tag_t *osm_tags_copy(tag_t *src_tag, gboolean update_creator) {
2518 tag_t *new_tags = NULL;
2519 tag_t **dst_tag = &new_tags;
2520
2521 while(src_tag) {
2522 *dst_tag = g_new0(tag_t, 1);
2523 (*dst_tag)->key = g_strdup(src_tag->key);
2524 if(update_creator && (strcasecmp(src_tag->key, "created_by") == 0))
2525 (*dst_tag)->value = g_strdup(PACKAGE " v" VERSION);
2526 else
2527 (*dst_tag)->value = g_strdup(src_tag->value);
2528
2529 dst_tag = &(*dst_tag)->next;
2530 src_tag = src_tag->next;
2531 }
2532
2533 return new_tags;
2534 }
2535 // vim:et:ts=8:sw=2:sts=2:ai