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 1263 - (show annotations) (download) (as text)
Sat Mar 2 14:13:14 2013 UTC (12 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 36549 byte(s)
Recognise mini-roundabouts tagged as junction=roundabout (as well as
highway=mini_roundabout).  Pass them through the parser as roundabout=yes.
Output them from the filedumper as junction=roundabout.  Update the
documentation for mini-roundabouts.

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

Properties

Name Value
cvs:description OSM XML file parser.