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