Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/src/osmparser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2170 - (show annotations) (download) (as text)
Thu Jul 13 18:14:49 2023 UTC (20 months ago) by amb
File MIME type: text/x-csrc
File size: 37371 byte(s)
Refactor the OSM file parsing to move code from individual file format
specific parsers to the shared parser back-end.

1 /***************************************
2 OSM file parser (either JOSM or planet)
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2008-2015, 2018, 2023 Andrew M. Bishop
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Affero General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ***************************************/
21
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26 #include <ctype.h>
27
28 #include "types.h"
29 #include "typesx.h"
30
31 #include "nodesx.h"
32 #include "waysx.h"
33 #include "relationsx.h"
34
35 #include "osmparser.h"
36 #include "tagging.h"
37 #include "logging.h"
38
39
40 /* Macros */
41
42 /*+ Checks if a value in the XML is one of the allowed values for true. +*/
43 #define ISTRUE(xx) (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1"))
44
45 /*+ Checks if a value in the XML is one of the allowed values for false. +*/
46 #define ISFALSE(xx) (!strcmp(xx,"false") || !strcmp(xx,"no") || !strcmp(xx,"0"))
47
48 /* Local parsing variables (re-initialised for each file) */
49
50 static NodesX *nodes;
51 static WaysX *ways;
52 static RelationsX *relations;
53
54 static node_t *way_nodes;
55 static int way_nnodes;
56
57 static node_t *relation_nodes;
58 static int relation_nnodes;
59 static way_t *relation_ways;
60 static int relation_nways;
61 static relation_t *relation_relations;
62 static int relation_nrelations;
63 static way_t relation_from;
64 static int relation_from_count;
65 static way_t relation_to;
66 static int relation_to_count;
67 static node_t relation_via;
68 static int relation_via_count;
69
70 /* Local parsing functions */
71
72 static void ProcessNodeTags(TagList *tags,int64_t node_id,double latitude,double longitude,int mode);
73 static void ProcessWayTags(TagList *tags,int64_t way_id, int mode);
74 static void ProcessRelationTags(TagList *tags,int64_t relation_id,int mode);
75
76 static double parse_speed(way_t id,const char *k,const char *v);
77 static double parse_weight(way_t id,const char *k,const char *v);
78 static double parse_length(way_t id,const char *k,const char *v);
79
80
81 /*++++++++++++++++++++++++++++++++++++++
82 Initialise the OSM parser by initialising the local variables.
83
84 NodesX *OSMNodes The data structure of nodes to fill in.
85
86 WaysX *OSMWays The data structure of ways to fill in.
87
88 RelationsX *OSMRelations The data structure of relations to fill in.
89 ++++++++++++++++++++++++++++++++++++++*/
90
91 void InitialiseParser(NodesX *OSMNodes,WaysX *OSMWays,RelationsX *OSMRelations)
92 {
93 /* Copy the function parameters and initialise the variables */
94
95 nodes=OSMNodes;
96 ways=OSMWays;
97 relations=OSMRelations;
98
99 way_nodes=(node_t*)malloc(256*sizeof(node_t));
100
101 relation_nodes =(node_t *)malloc(256*sizeof(node_t));
102 relation_ways =(way_t *)malloc(256*sizeof(way_t));
103 relation_relations=(relation_t*)malloc(256*sizeof(relation_t));
104 }
105
106
107 /*++++++++++++++++++++++++++++++++++++++
108 Clean up the memory after parsing.
109 ++++++++++++++++++++++++++++++++++++++*/
110
111 void CleanupParser(void)
112 {
113 /* Free the variables */
114
115 free(way_nodes);
116
117 free(relation_nodes);
118 free(relation_ways);
119 free(relation_relations);
120 }
121
122
123 /*++++++++++++++++++++++++++++++++++++++
124 Add node references to a way.
125
126 int64_t node_id The node ID to add or zero to clear the list.
127 ++++++++++++++++++++++++++++++++++++++*/
128
129 void AddWayRefs(int64_t node_id)
130 {
131 if(node_id==0)
132 way_nnodes=0;
133 else
134 {
135 node_t id;
136
137 if(way_nnodes && (way_nnodes%256)==0)
138 way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t));
139
140 id=(node_t)node_id;
141 logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
142
143 way_nodes[way_nnodes++]=id;
144 }
145 }
146
147
148 /*++++++++++++++++++++++++++++++++++++++
149 Add node, way or relation references to a relation.
150
151 int64_t node_id The node ID to add or zero if it is not a node.
152
153 int64_t way_id The way ID to add or zero if it is not a way.
154
155 int64_t relation_id The relation ID to add or zero if it is not a relation.
156
157 const char *role The role played by this referenced item or NULL.
158
159 If all of node_id, way_id and relation_id are zero then the list is cleared.
160 ++++++++++++++++++++++++++++++++++++++*/
161
162 void AddRelationRefs(int64_t node_id,int64_t way_id,int64_t relation_id,const char *role)
163 {
164 if(node_id==0 && way_id==0 && relation_id==0)
165 {
166 relation_nnodes=0;
167 relation_nways=0;
168 relation_nrelations=0;
169
170 relation_from=NO_WAY_ID;
171 relation_from_count=0;
172 relation_from_count=0;
173 relation_to=NO_WAY_ID;
174 relation_to_count=0;
175 relation_via=NO_NODE_ID;
176 relation_via_count=0;
177 }
178 else if(node_id!=0)
179 {
180 node_t id;
181
182 id=(node_t)node_id;
183 logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
184
185 if(relation_nnodes && (relation_nnodes%256)==0)
186 relation_nodes=(node_t*)realloc((void*)relation_nodes,(relation_nnodes+256)*sizeof(node_t));
187
188 relation_nodes[relation_nnodes++]=id;
189
190 if(role)
191 {
192 if(!strcmp(role,"via"))
193 {
194 relation_via_count++;
195 if(relation_via==NO_NODE_ID)
196 relation_via=id;
197 }
198 }
199 }
200 else if(way_id!=0)
201 {
202 way_t id;
203
204 id=(way_t)way_id;
205 logassert((int64_t)id==way_id,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
206
207 if(relation_nways && (relation_nways%256)==0)
208 relation_ways=(way_t*)realloc((void*)relation_ways,(relation_nways+256)*sizeof(way_t));
209
210 relation_ways[relation_nways++]=id;
211
212 if(role)
213 {
214 if(!strcmp(role,"from"))
215 {
216 relation_from_count++;
217 if(relation_from==NO_WAY_ID)
218 relation_from=id;
219 }
220 else if(!strcmp(role,"to"))
221 {
222 relation_to_count++;
223 if(relation_to==NO_WAY_ID)
224 relation_to=id;
225 }
226 }
227 }
228 else /* if(relation_id!=0) */
229 {
230 relation_t id;
231
232 id=(relation_t)relation_id;
233 logassert((int64_t)id==relation_id,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
234
235 if(relation_nrelations && (relation_nrelations%256)==0)
236 relation_relations=(relation_t*)realloc((void*)relation_relations,(relation_nrelations+256)*sizeof(relation_t));
237
238 relation_relations[relation_nrelations++]=relation_id;
239 }
240 }
241
242
243 /*++++++++++++++++++++++++++++++++++++++
244 Add a node after processing the tags associated with it.
245
246 int64_t node_id The id of the node.
247
248 double latitude The latitude of the node.
249
250 double longitude The longitude of the node.
251
252 int mode The mode of operation to take (create, modify, delete).
253
254 TagList *raw_tags The accumulated set of tags for the node.
255 ++++++++++++++++++++++++++++++++++++++*/
256
257 void AddNode(int64_t node_id,double latitude,double longitude,int mode,TagList *raw_tags)
258 {
259 TagList *processed_tags=ApplyNodeTaggingRules(raw_tags,node_id);
260
261 ProcessNodeTags(processed_tags,node_id,latitude,longitude,mode);
262
263 DeleteTagList(raw_tags);
264 DeleteTagList(processed_tags);
265 }
266
267
268 /*++++++++++++++++++++++++++++++++++++++
269 Add a way after processing the tags associated with it.
270
271 int64_t way_id The id of the way.
272
273 int mode The mode of operation to take (create, modify, delete).
274
275 TagList *raw_tags The accumulated set of tags for the node.
276 ++++++++++++++++++++++++++++++++++++++*/
277
278 void AddWay(int64_t way_id,int mode,TagList *raw_tags)
279 {
280 TagList *processed_tags=ApplyWayTaggingRules(raw_tags,way_id);
281
282 ProcessWayTags(processed_tags,way_id,mode);
283
284 DeleteTagList(raw_tags);
285 DeleteTagList(processed_tags);
286 }
287
288
289 /*++++++++++++++++++++++++++++++++++++++
290 Add a relation after processing the tags associated with it.
291
292 int64_t relation_id The id of the relation.
293
294 int mode The mode of operation to take (create, modify, delete).
295
296 TagList *raw_tags The accumulated set of tags for the node.
297 ++++++++++++++++++++++++++++++++++++++*/
298
299 void AddRelation(int64_t relation_id,int mode,TagList *raw_tags)
300 {
301 TagList *processed_tags=ApplyRelationTaggingRules(raw_tags,relation_id);
302
303 ProcessRelationTags(processed_tags,relation_id,mode);
304
305 DeleteTagList(raw_tags);
306 DeleteTagList(processed_tags);
307 }
308
309
310 /*++++++++++++++++++++++++++++++++++++++
311 Process the tags associated with a node.
312
313 TagList *tags The list of node tags.
314
315 int64_t node_id The id of the node.
316
317 double latitude The latitude of the node.
318
319 double longitude The longitude of the node.
320
321 int mode The mode of operation to take (create, modify, delete).
322 ++++++++++++++++++++++++++++++++++++++*/
323
324 static void ProcessNodeTags(TagList *tags,int64_t node_id,double latitude,double longitude,int mode)
325 {
326 transports_t allow=Transports_ALL;
327 nodeflags_t flags=0;
328 node_t id;
329 int i;
330
331 /* Convert id */
332
333 id=(node_t)node_id;
334 logassert((int64_t)id==node_id,"Node ID too large (change node_t to 64-bits?)"); /* check node id can be stored in node_t data type. */
335
336 /* Delete */
337
338 if(mode==MODE_DELETE)
339 {
340 AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,NODE_DELETED);
341
342 return;
343 }
344
345 /* Parse the tags */
346
347 for(i=0;i<tags->ntags;i++)
348 {
349 int recognised=0;
350 char *k=tags->k[i];
351 char *v=tags->v[i];
352
353 switch(*k)
354 {
355 case 'b':
356 if(!strcmp(k,"bicycle"))
357 {
358 if(ISFALSE(v))
359 allow&=~Transports_Bicycle;
360 else if(!ISTRUE(v))
361 logerror("Node %"Pnode_t" has an unrecognised tag 'bicycle' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
362 recognised=1; break;
363 }
364
365 break;
366
367 case 'f':
368 if(!strcmp(k,"foot"))
369 {
370 if(ISFALSE(v))
371 allow&=~Transports_Foot;
372 else if(!ISTRUE(v))
373 logerror("Node %"Pnode_t" has an unrecognised tag 'foot' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
374 recognised=1; break;
375 }
376
377 break;
378
379 case 'g':
380 if(!strcmp(k,"goods"))
381 {
382 if(ISFALSE(v))
383 allow&=~Transports_Goods;
384 else if(!ISTRUE(v))
385 logerror("Node %"Pnode_t" has an unrecognised tag 'goods' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
386 recognised=1; break;
387 }
388
389 break;
390
391 case 'h':
392 if(!strcmp(k,"horse"))
393 {
394 if(ISFALSE(v))
395 allow&=~Transports_Horse;
396 else if(!ISTRUE(v))
397 logerror("Node %"Pnode_t" has an unrecognised tag 'horse' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
398 recognised=1; break;
399 }
400
401 if(!strcmp(k,"hgv"))
402 {
403 if(ISFALSE(v))
404 allow&=~Transports_HGV;
405 else if(!ISTRUE(v))
406 logerror("Node %"Pnode_t" has an unrecognised tag 'hgv' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
407 recognised=1; break;
408 }
409
410 break;
411
412 case 'm':
413 if(!strcmp(k,"moped"))
414 {
415 if(ISFALSE(v))
416 allow&=~Transports_Moped;
417 else if(!ISTRUE(v))
418 logerror("Node %"Pnode_t" has an unrecognised tag 'moped' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
419 recognised=1; break;
420 }
421
422 if(!strcmp(k,"motorcycle"))
423 {
424 if(ISFALSE(v))
425 allow&=~Transports_Motorcycle;
426 else if(!ISTRUE(v))
427 logerror("Node %"Pnode_t" has an unrecognised tag 'motorcycle' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
428 recognised=1; break;
429 }
430
431 if(!strcmp(k,"motorcar"))
432 {
433 if(ISFALSE(v))
434 allow&=~Transports_Motorcar;
435 else if(!ISTRUE(v))
436 logerror("Node %"Pnode_t" has an unrecognised tag 'motorcar' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
437 recognised=1; break;
438 }
439
440 break;
441
442 case 'p':
443 if(!strcmp(k,"psv"))
444 {
445 if(ISFALSE(v))
446 allow&=~Transports_PSV;
447 else if(!ISTRUE(v))
448 logerror("Node %"Pnode_t" has an unrecognised tag 'psv' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
449 recognised=1; break;
450 }
451
452 break;
453
454 case 'r':
455 if(!strcmp(k,"roundabout"))
456 {
457 if(ISTRUE(v))
458 flags|=NODE_MINIRNDBT;
459 else
460 logerror("Node %"Pnode_t" has an unrecognised tag 'roundabout' = '%s' (after tagging rules); using 'no'.\n",id,v);
461 recognised=1; break;
462 }
463
464 break;
465
466 case 'w':
467 if(!strcmp(k,"wheelchair"))
468 {
469 if(ISFALSE(v))
470 allow&=~Transports_Wheelchair;
471 else if(!ISTRUE(v))
472 logerror("Node %"Pnode_t" has an unrecognised tag 'wheelchair' = '%s' (after tagging rules); using 'yes'.\n",logerror_node(id),v);
473 recognised=1; break;
474 }
475
476 break;
477
478 default:
479 break;
480 }
481
482 if(!recognised)
483 logerror("Node %"Pnode_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_node(id),k,v);
484 }
485
486 /* Create the node */
487
488 AppendNodeList(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,flags);
489 }
490
491
492 /*++++++++++++++++++++++++++++++++++++++
493 Process the tags associated with a way.
494
495 TagList *tags The list of way tags.
496
497 int64_t way_id The id of the way.
498
499 int mode The mode of operation to take (create, modify, delete).
500 ++++++++++++++++++++++++++++++++++++++*/
501
502 static void ProcessWayTags(TagList *tags,int64_t way_id,int mode)
503 {
504 Way way={0};
505 int oneway=0,area=0;
506 int roundabout=0,lanes=0,cyclebothways=0;
507 char *name=NULL,*ref=NULL,*refname=NULL;
508 way_t id;
509 int i;
510
511 /* Convert id */
512
513 id=(way_t)way_id;
514 logassert((int64_t)id==way_id,"Way ID too large (change way_t to 64-bits?)"); /* check way id can be stored in way_t data type. */
515
516 /* Delete */
517
518 if(mode==MODE_DELETE || mode==MODE_MODIFY)
519 {
520 way.type=WAY_DELETED;
521
522 AppendWayList(ways,id,&way,way_nodes,way_nnodes,"");
523 }
524
525 if(mode==MODE_DELETE)
526 return;
527
528 /* Sanity check */
529
530 if(way_nnodes==0)
531 {
532 logerror("Way %"Pway_t" has no nodes.\n",logerror_way(id));
533 return;
534 }
535
536 if(way_nnodes==1)
537 {
538 logerror_node(way_nodes[0]); /* Extra logerror information since way isn't stored */
539 logerror("Way %"Pway_t" has only one node.\n",logerror_way(id));
540 return;
541 }
542
543 /* Parse the tags - just look for highway */
544
545 for(i=0;i<tags->ntags;i++)
546 {
547 char *k=tags->k[i];
548 char *v=tags->v[i];
549
550 if(!strcmp(k,"highway"))
551 {
552 way.type=HighwayType(v);
553
554 if(way.type==Highway_None)
555 logerror("Way %"Pway_t" has an unrecognised highway type '%s' (after tagging rules); ignoring it.\n",logerror_way(id),v);
556
557 break;
558 }
559 }
560
561 /* Don't continue if this is not a highway (bypass error logging) */
562
563 if(way.type==Highway_None)
564 return;
565
566 /* Parse the tags - look for the others */
567
568 for(i=0;i<tags->ntags;i++)
569 {
570 int recognised=0;
571 char *k=tags->k[i];
572 char *v=tags->v[i];
573
574 switch(*k)
575 {
576 case 'a':
577 if(!strcmp(k,"area"))
578 {
579 if(ISTRUE(v))
580 area=1;
581 else if(!ISFALSE(v))
582 logerror("Way %"Pway_t" has an unrecognised tag 'area' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
583 recognised=1; break;
584 }
585
586 break;
587
588 case 'b':
589 if(!strcmp(k,"bicycle"))
590 {
591 if(ISTRUE(v))
592 way.allow|=Transports_Bicycle;
593 else if(!ISFALSE(v))
594 logerror("Way %"Pway_t" has an unrecognised tag 'bicycle' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
595 recognised=1; break;
596 }
597
598 if(!strcmp(k,"bicycleroute"))
599 {
600 if(ISTRUE(v))
601 way.props|=Properties_BicycleRoute;
602 else if(!ISFALSE(v))
603 logerror("Way %"Pway_t" has an unrecognised tag 'bicycleroute' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
604 recognised=1; break;
605 }
606
607 if(!strcmp(k,"bridge"))
608 {
609 if(ISTRUE(v))
610 way.props|=Properties_Bridge;
611 else if(!ISFALSE(v))
612 logerror("Way %"Pway_t" has an unrecognised tag 'bridge' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
613 recognised=1; break;
614 }
615
616 break;
617
618 case 'c':
619 if(!strcmp(k,"cyclebothways"))
620 {
621 if(ISTRUE(v))
622 cyclebothways=1;
623 else if(!ISFALSE(v))
624 logerror("Way %"Pway_t" has an unrecognised tag 'cyclebothways' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
625 recognised=1; break;
626 }
627 break;
628
629 case 'f':
630 if(!strcmp(k,"foot"))
631 {
632 if(ISTRUE(v))
633 way.allow|=Transports_Foot;
634 else if(!ISFALSE(v))
635 logerror("Way %"Pway_t" has an unrecognised tag 'foot' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
636 recognised=1; break;
637 }
638
639 if(!strcmp(k,"footroute"))
640 {
641 if(ISTRUE(v))
642 way.props|=Properties_FootRoute;
643 else if(!ISFALSE(v))
644 logerror("Way %"Pway_t" has an unrecognised tag 'footroute' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
645 recognised=1; break;
646 }
647
648 break;
649
650 case 'g':
651 if(!strcmp(k,"goods"))
652 {
653 if(ISTRUE(v))
654 way.allow|=Transports_Goods;
655 else if(!ISFALSE(v))
656 logerror("Way %"Pway_t" has an unrecognised tag 'goods' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
657 recognised=1; break;
658 }
659
660 break;
661
662 case 'h':
663 if(!strcmp(k,"highway"))
664 {recognised=1; break;}
665
666 if(!strcmp(k,"horse"))
667 {
668 if(ISTRUE(v))
669 way.allow|=Transports_Horse;
670 else if(!ISFALSE(v))
671 logerror("Way %"Pway_t" has an unrecognised tag 'horse' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
672 recognised=1; break;
673 }
674
675 if(!strcmp(k,"hgv"))
676 {
677 if(ISTRUE(v))
678 way.allow|=Transports_HGV;
679 else if(!ISFALSE(v))
680 logerror("Way %"Pway_t" has an unrecognised tag 'hgv' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
681 recognised=1; break;
682 }
683
684 break;
685
686 case 'l':
687 if(!strcmp(k,"lanes"))
688 {
689 int en=0;
690 float lanesf;
691 if(sscanf(v,"%f%n",&lanesf,&en)==1 && en && !v[en])
692 lanes=(int)lanesf;
693 else
694 logerror("Way %"Pway_t" has an unrecognised tag 'lanes' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),v);
695 recognised=1; break;
696 }
697
698 break;
699
700 case 'm':
701 if(!strncmp(k,"max",3))
702 {
703 if(!strcmp(k+3,"speed"))
704 {
705 way.speed=kph_to_speed(parse_speed(id,k,v));
706 recognised=1; break;
707 }
708
709 if(!strcmp(k+3,"weight"))
710 {
711 way.weight=tonnes_to_weight(parse_weight(id,k,v));
712 recognised=1; break;
713 }
714
715 if(!strcmp(k+3,"height"))
716 {
717 way.height=metres_to_height(parse_length(id,k,v));
718 recognised=1; break;
719 }
720
721 if(!strcmp(k+3,"width"))
722 {
723 way.width=metres_to_height(parse_length(id,k,v));
724 recognised=1; break;
725 }
726
727 if(!strcmp(k+3,"length"))
728 {
729 way.length=metres_to_height(parse_length(id,k,v));
730 recognised=1; break;
731 }
732 }
733
734 if(!strcmp(k,"moped"))
735 {
736 if(ISTRUE(v))
737 way.allow|=Transports_Moped;
738 else if(!ISFALSE(v))
739 logerror("Way %"Pway_t" has an unrecognised tag 'moped' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
740 recognised=1; break;
741 }
742
743 if(!strcmp(k,"motorcycle"))
744 {
745 if(ISTRUE(v))
746 way.allow|=Transports_Motorcycle;
747 else if(!ISFALSE(v))
748 logerror("Way %"Pway_t" has an unrecognised tag 'motorcycle' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
749 recognised=1; break;
750 }
751
752 if(!strcmp(k,"motorcar"))
753 {
754 if(ISTRUE(v))
755 way.allow|=Transports_Motorcar;
756 else if(!ISFALSE(v))
757 logerror("Way %"Pway_t" has an unrecognised tag 'motorcar' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
758 recognised=1; break;
759 }
760
761 if(!strcmp(k,"multilane"))
762 {
763 if(ISTRUE(v))
764 way.props|=Properties_Multilane;
765 else if(!ISFALSE(v))
766 logerror("Way %"Pway_t" has an unrecognised tag 'multilane' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
767 recognised=1; break;
768 }
769
770 break;
771
772 case 'n':
773 if(!strcmp(k,"name"))
774 {
775 name=v;
776 recognised=1; break;
777 }
778
779 break;
780
781 case 'o':
782 if(!strcmp(k,"oneway"))
783 {
784 if(ISTRUE(v))
785 oneway=1;
786 else if(!strcmp(v,"-1"))
787 oneway=-1;
788 else if(!ISFALSE(v))
789 logerror("Way %"Pway_t" has an unrecognised tag 'oneway' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
790 recognised=1; break;
791 }
792
793 break;
794
795 case 'p':
796 if(!strcmp(k,"paved"))
797 {
798 if(ISTRUE(v))
799 way.props|=Properties_Paved;
800 else if(!ISFALSE(v))
801 logerror("Way %"Pway_t" has an unrecognised tag 'paved' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
802 recognised=1; break;
803 }
804
805 if(!strcmp(k,"psv"))
806 {
807 if(ISTRUE(v))
808 way.allow|=Transports_PSV;
809 else if(!ISFALSE(v))
810 logerror("Way %"Pway_t" has an unrecognised tag 'psv' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
811 recognised=1; break;
812 }
813
814 break;
815
816 case 'r':
817 if(!strcmp(k,"ref"))
818 {
819 ref=v;
820 recognised=1; break;
821 }
822
823 if(!strcmp(k,"roundabout"))
824 {
825 if(ISTRUE(v))
826 roundabout=1;
827 else if(!ISFALSE(v))
828 logerror("Way %"Pway_t" has an unrecognised tag 'roundabout' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
829 recognised=1; break;
830 }
831
832 break;
833
834 case 't':
835 if(!strcmp(k,"tunnel"))
836 {
837 if(ISTRUE(v))
838 way.props|=Properties_Tunnel;
839 else if(!ISFALSE(v))
840 logerror("Way %"Pway_t" has an unrecognised tag 'tunnel' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
841 recognised=1; break;
842 }
843
844 break;
845
846 case 'w':
847 if(!strcmp(k,"wheelchair"))
848 {
849 if(ISTRUE(v))
850 way.allow|=Transports_Wheelchair;
851 else if(!ISFALSE(v))
852 logerror("Way %"Pway_t" has an unrecognised tag 'wheelchair' = '%s' (after tagging rules); using 'no'.\n",logerror_way(id),v);
853 recognised=1; break;
854 }
855
856 break;
857
858 default:
859 break;
860 }
861
862 if(!recognised)
863 logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
864 }
865
866 /* Create the way */
867
868 if(area && oneway)
869 {
870 logerror("Way %"Pway_t" is an area and oneway; ignoring area tag.\n",logerror_way(id));
871 area=0;
872 }
873
874 if(cyclebothways && !oneway)
875 {
876 logerror("Way %"Pway_t" is cyclebothways but not oneway; ignoring cyclebothways tag.\n",logerror_way(id));
877 cyclebothways=0;
878 }
879
880 if(roundabout && !oneway)
881 {
882 logerror("Way %"Pway_t" is roundabout but not oneway; adding oneway tag.\n",logerror_way(id));
883 oneway=1;
884 }
885
886 if(!way.allow)
887 return;
888
889 if(cyclebothways)
890 way.type|=Highway_CycleBothWays;
891
892 if(oneway)
893 {
894 way.type|=Highway_OneWay;
895
896 if(oneway==-1)
897 for(i=0;i<way_nnodes/2;i++)
898 {
899 node_t temp;
900
901 temp=way_nodes[i];
902 way_nodes[i]=way_nodes[way_nnodes-i-1];
903 way_nodes[way_nnodes-i-1]=temp;
904 }
905 }
906
907 if(roundabout)
908 way.type|=Highway_Roundabout;
909
910 if(area)
911 {
912 way.type|=Highway_Area;
913
914 if(way_nodes[0]!=way_nodes[way_nnodes-1])
915 logerror("Way %"Pway_t" is an area but not closed.\n",logerror_way(id));
916 }
917
918 if(lanes)
919 {
920 if(oneway || (lanes/2)>1)
921 way.props|=Properties_Multilane;
922
923 if(oneway && lanes==1)
924 way.props&=~Properties_Multilane;
925 }
926
927 if(ref && name)
928 {
929 refname=(char*)malloc(strlen(ref)+strlen(name)+4);
930 sprintf(refname,"%s (%s)",name,ref);
931 }
932 else if(ref && !name)
933 refname=ref;
934 else if(!ref && name)
935 refname=name;
936 else /* if(!ref && !name) */
937 refname="";
938
939 AppendWayList(ways,id,&way,way_nodes,way_nnodes,refname);
940
941 if(ref && name)
942 free(refname);
943 }
944
945
946 /*++++++++++++++++++++++++++++++++++++++
947 Process the tags associated with a relation.
948
949 TagList *tags The list of relation tags.
950
951 int64_t relation_id The id of the relation.
952
953 int mode The mode of operation to take (create, modify, delete).
954 ++++++++++++++++++++++++++++++++++++++*/
955
956 static void ProcessRelationTags(TagList *tags,int64_t relation_id,int mode)
957 {
958 transports_t routes=Transports_None;
959 transports_t except=Transports_None;
960 int relation_turn_restriction=0;
961 TurnRestriction restriction=TurnRestrict_None;
962 relation_t id;
963 int i;
964
965 /* Convert id */
966
967 id=(relation_t)relation_id;
968 logassert((int64_t)id==relation_id,"Relation ID too large (change relation_t to 64-bits?)"); /* check relation id can be stored in relation_t data type. */
969
970 /* Delete */
971
972 if(mode==MODE_DELETE || mode==MODE_MODIFY)
973 {
974 AppendRouteRelationList(relations,id,RELATION_DELETED,
975 relation_nodes,relation_nnodes,
976 relation_ways,relation_nways,
977 relation_relations,relation_nrelations);
978
979 AppendTurnRelationList(relations,id,
980 relation_from,relation_to,relation_via,
981 restriction,RELATION_DELETED);
982 }
983
984 if(mode==MODE_DELETE)
985 return;
986
987 /* Sanity check */
988
989 if(relation_nnodes==0 && relation_nways==0 && relation_nrelations==0)
990 {
991 logerror("Relation %"Prelation_t" has no nodes, ways or relations.\n",logerror_relation(id));
992 return;
993 }
994
995 /* Parse the tags */
996
997 for(i=0;i<tags->ntags;i++)
998 {
999 int recognised=0;
1000 char *k=tags->k[i];
1001 char *v=tags->v[i];
1002
1003 switch(*k)
1004 {
1005 case 'b':
1006 if(!strcmp(k,"bicycleroute"))
1007 {
1008 if(ISTRUE(v))
1009 routes|=Transports_Bicycle;
1010 else if(!ISFALSE(v))
1011 logerror("Relation %"Prelation_t" has an unrecognised tag 'bicycleroute' = '%s' (after tagging rules); using 'no'.\n",logerror_relation(id),v);
1012 recognised=1; break;
1013 }
1014
1015 break;
1016
1017 case 'e':
1018 if(!strcmp(k,"except"))
1019 {
1020 for(i=1;i<Transport_Count;i++)
1021 if(strstr(v,TransportName(i)))
1022 except|=TRANSPORTS(i);
1023
1024 if(except==Transports_None)
1025 logerror("Relation %"Prelation_t" has an unrecognised tag 'except' = '%s' (after tagging rules); ignoring it.\n",logerror_relation(id),v);
1026
1027 recognised=1; break;
1028 }
1029
1030 break;
1031
1032 case 'f':
1033 if(!strcmp(k,"footroute"))
1034 {
1035 if(ISTRUE(v))
1036 routes|=Transports_Foot;
1037 else if(!ISFALSE(v))
1038 logerror("Relation %"Prelation_t" has an unrecognised tag 'footroute' = '%s' (after tagging rules); using 'no'.\n",logerror_relation(id),v);
1039 recognised=1; break;
1040 }
1041
1042 break;
1043
1044 case 'r':
1045 if(!strcmp(k,"restriction"))
1046 {
1047 if(!strcmp(v,"no_right_turn" )) restriction=TurnRestrict_no_right_turn;
1048 if(!strcmp(v,"no_left_turn" )) restriction=TurnRestrict_no_left_turn;
1049 if(!strcmp(v,"no_u_turn" )) restriction=TurnRestrict_no_u_turn;
1050 if(!strcmp(v,"no_straight_on" )) restriction=TurnRestrict_no_straight_on;
1051 if(!strcmp(v,"only_right_turn" )) restriction=TurnRestrict_only_right_turn;
1052 if(!strcmp(v,"only_left_turn" )) restriction=TurnRestrict_only_left_turn;
1053 if(!strcmp(v,"only_straight_on")) restriction=TurnRestrict_only_straight_on;
1054
1055 if(restriction==TurnRestrict_None)
1056 logerror("Relation %"Prelation_t" has an unrecognised tag 'restriction' = '%s' (after tagging rules); ignoring it.\n",logerror_relation(id),v);
1057
1058 recognised=1; break;
1059 }
1060
1061 break;
1062
1063 case 't':
1064 if(!strcmp(k,"type"))
1065 {
1066 if(!strcmp(v,"restriction"))
1067 relation_turn_restriction=1;
1068
1069 /* Don't log an error for relations of types that we don't handle - there are so many */
1070 recognised=1; break;
1071 }
1072
1073 break;
1074
1075 default:
1076 break;
1077 }
1078
1079 if(!recognised)
1080 logerror("Relation %"Prelation_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_relation(id),k,v);
1081 }
1082
1083 /* Create the route relation (must store all relations that have ways or
1084 relations even if they are not routes because they might be referenced by
1085 other relations that are routes) */
1086
1087 if((relation_nways || relation_nrelations) && !relation_turn_restriction)
1088 AppendRouteRelationList(relations,id,routes,
1089 relation_nodes,relation_nnodes,
1090 relation_ways,relation_nways,
1091 relation_relations,relation_nrelations);
1092
1093 /* Create the turn restriction relation. */
1094
1095 if(relation_turn_restriction && restriction!=TurnRestrict_None)
1096 {
1097 if(relation_from==NO_WAY_ID)
1098 {
1099 /* Extra logerror information since relation isn't stored */
1100 if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
1101 if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
1102 logerror("Turn Relation %"Prelation_t" has no 'from' way.\n",logerror_relation(id));
1103 }
1104 if(relation_to==NO_WAY_ID)
1105 {
1106 /* Extra logerror information since relation isn't stored */
1107 if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
1108 if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
1109 logerror("Turn Relation %"Prelation_t" has no 'to' way.\n",logerror_relation(id));
1110 }
1111 if(relation_via==NO_NODE_ID)
1112 {
1113 /* Extra logerror information since relation isn't stored */
1114 if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
1115 if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
1116 logerror("Turn Relation %"Prelation_t" has no 'via' node.\n",logerror_relation(id));
1117 }
1118
1119 if(relation_from_count>1)
1120 {
1121 if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
1122 if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
1123 if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
1124 logerror("Turn Relation %"Prelation_t" has more than one 'from' Way (used first one).\n",logerror_relation(relation_id));
1125 }
1126 if(relation_to_count>1)
1127 {
1128 if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
1129 if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
1130 if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
1131 logerror("Turn Relation %"Prelation_t" has more than one 'to' Way (used first one).\n",logerror_relation(relation_id));
1132 }
1133 if(relation_via_count>1)
1134 {
1135 if(relation_to!=NO_WAY_ID) logerror_way(relation_to);
1136 if(relation_via!=NO_NODE_ID) logerror_node(relation_via);
1137 if(relation_from!=NO_WAY_ID) logerror_way(relation_from);
1138 logerror("Turn Relation %"Prelation_t" has more than one 'via' Node (used first one).\n",logerror_relation(relation_id));
1139 }
1140
1141 if(relation_from!=NO_WAY_ID && relation_to!=NO_WAY_ID && relation_via!=NO_NODE_ID)
1142 AppendTurnRelationList(relations,id,
1143 relation_from,relation_to,relation_via,
1144 restriction,except);
1145 }
1146 }
1147
1148
1149 /*++++++++++++++++++++++++++++++++++++++
1150 Convert a string containing a speed into a double precision.
1151
1152 double parse_speed Returns the speed in km/h if it can be parsed.
1153
1154 way_t id The way being processed.
1155
1156 const char *k The tag key.
1157
1158 const char *v The tag value.
1159 ++++++++++++++++++++++++++++++++++++++*/
1160
1161 static double parse_speed(way_t id,const char *k,const char *v)
1162 {
1163 char *ev;
1164 double value=strtod(v,&ev);
1165
1166 if(v==ev)
1167 logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
1168 else
1169 {
1170 while(isspace(*ev)) ev++;
1171
1172 if(*ev==0)
1173 return(value);
1174
1175 if(!strcmp(ev,"km/h") || !strcmp(ev,"kph") || !strcmp(ev,"kmph"))
1176 return(value);
1177
1178 if(!strcmp(ev,"mph"))
1179 return(1.609*value);
1180
1181 if(!strcmp(ev,"knots"))
1182 return(1.852*value);
1183
1184 logerror("Way %"Pway_t" has an un-parseable tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
1185 }
1186
1187 return(0);
1188 }
1189
1190
1191 /*++++++++++++++++++++++++++++++++++++++
1192 Convert a string containing a weight into a double precision.
1193
1194 double parse_weight Returns the weight in tonnes if it can be parsed.
1195
1196 way_t id The way being processed.
1197
1198 const char *k The tag key.
1199
1200 const char *v The tag value.
1201 ++++++++++++++++++++++++++++++++++++++*/
1202
1203 static double parse_weight(way_t id,const char *k,const char *v)
1204 {
1205 char *ev;
1206 double value=strtod(v,&ev);
1207
1208 if(v==ev)
1209 logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
1210 else
1211 {
1212 while(isspace(*ev)) ev++;
1213
1214 if(*ev==0)
1215 return(value);
1216
1217 if(!strcmp(ev,"kg"))
1218 return(value/1000.0);
1219
1220 if(!strcmp(ev,"T") || !strcmp(ev,"t") ||
1221 !strcmp(ev,"ton") || !strcmp(ev,"tons") ||
1222 !strcmp(ev,"tonne") || !strcmp(ev,"tonnes"))
1223 return(value);
1224
1225 logerror("Way %"Pway_t" has an un-parseable tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
1226 }
1227
1228 return(0);
1229 }
1230
1231
1232 /*++++++++++++++++++++++++++++++++++++++
1233 Convert a string containing a length into a double precision.
1234
1235 double parse_length Returns the length in metres if it can be parsed.
1236
1237 way_t id The way being processed.
1238
1239 const char *k The tag key.
1240
1241 const char *v The tag value.
1242 ++++++++++++++++++++++++++++++++++++++*/
1243
1244 static double parse_length(way_t id,const char *k,const char *v)
1245 {
1246 char *ev;
1247 double value=strtod(v,&ev);
1248
1249 if(v==ev)
1250 logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
1251 else
1252 {
1253 int en=0;
1254 int feet=0,inches=0;
1255
1256 while(isspace(*ev)) ev++;
1257
1258 if(*ev==0)
1259 return(value);
1260
1261 if(!strcmp(ev,"m") || !strcmp(ev,"metre") || !strcmp(ev,"metres") || !strcmp(ev,"meter") || !strcmp(ev,"meters"))
1262 return(value);
1263
1264 if(!strcmp(ev,"'"))
1265 return(value*0.254);
1266
1267 if(!strcmp(ev,"′"))
1268 return(value*0.254);
1269
1270 if(!strcmp(ev,"ft") || !strcmp(ev,"feet"))
1271 return(value*0.254);
1272
1273 if(sscanf(v,"%d' %d\"%n",&feet,&inches,&en)==2 && en && !v[en])
1274 return((feet+(double)inches/12.0)*0.254);
1275
1276 if(sscanf(v,"%d'%d\"%n",&feet,&inches,&en)==2 && en && !v[en])
1277 return((feet+(double)inches/12.0)*0.254);
1278
1279 if(sscanf(v,"%d'-%d\"%n",&feet,&inches,&en)==2 && en && !v[en])
1280 return((feet+(double)inches/12.0)*0.254);
1281
1282 if(sscanf(v,"%d′ %d″%n",&feet,&inches,&en)==2 && en && !v[en])
1283 return((feet+(double)inches/12.0)*0.254);
1284
1285 if(sscanf(v,"%d′%d″%n",&feet,&inches,&en)==2 && en && !v[en])
1286 return((feet+(double)inches/12.0)*0.254);
1287
1288 if(sscanf(v,"%d′-%d″%n",&feet,&inches,&en)==2 && en && !v[en])
1289 return((feet+(double)inches/12.0)*0.254);
1290
1291 if(sscanf(v,"%d - %d%n",&feet,&inches,&en)==2 && en && !v[en])
1292 return((feet+(double)inches/12.0)*0.254);
1293
1294 if(sscanf(v,"%d ft %d in%n",&feet,&inches,&en)==2 && en && !v[en])
1295 return((feet+(double)inches/12.0)*0.254);
1296
1297 if(sscanf(v,"%d feet %d inches%n",&feet,&inches,&en)==2 && en && !v[en])
1298 return((feet+(double)inches/12.0)*0.254);
1299
1300 logerror("Way %"Pway_t" has an un-parseable tag '%s' = '%s' (after tagging rules); ignoring it.\n",logerror_way(id),k,v);
1301 }
1302
1303 return(0);
1304 }

Properties

Name Value
cvs:description OSM XML file parser.