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 812 -
(show annotations)
(download)
(as text)
Thu Jul 21 18:44:52 2011 UTC (13 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 36768 byte(s)
Thu Jul 21 18:44:52 2011 UTC (13 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 36768 byte(s)
Add logging of parsing and processing errors.
1 | /*************************************** |
2 | OSM XML file parser (either JOSM or planet) |
3 | |
4 | Part of the Routino routing software. |
5 | ******************/ /****************** |
6 | This file Copyright 2008-2011 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 <assert.h> |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | #include <ctype.h> |
28 | |
29 | #include "typesx.h" |
30 | #include "functionsx.h" |
31 | |
32 | #include "nodesx.h" |
33 | #include "segmentsx.h" |
34 | #include "waysx.h" |
35 | #include "relationsx.h" |
36 | |
37 | #include "xmlparse.h" |
38 | #include "tagging.h" |
39 | |
40 | #include "logging.h" |
41 | |
42 | |
43 | /* Macros */ |
44 | |
45 | /*+ Checks if a value in the XML is one of the allowed values for true. +*/ |
46 | #define ISTRUE(xx) (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1")) |
47 | |
48 | /*+ Checks if a value in the XML is one of the allowed values for false. +*/ |
49 | #define ISFALSE(xx) (!strcmp(xx,"false") || !strcmp(xx,"no") || !strcmp(xx,"0")) |
50 | |
51 | |
52 | /* Local variables */ |
53 | |
54 | static index_t nnodes=0; |
55 | static index_t nways=0; |
56 | static index_t nrelations=0; |
57 | |
58 | static TagList *current_tags=NULL; |
59 | |
60 | static node_t *way_nodes=NULL; |
61 | static int way_nnodes=0; |
62 | |
63 | static node_t *relation_nodes=NULL; |
64 | static int relation_nnodes=0; |
65 | static way_t *relation_ways=NULL; |
66 | static int relation_nways=0; |
67 | static relation_t *relation_relations=NULL; |
68 | static int relation_nrelations=0; |
69 | static way_t relation_from=NO_WAY_ID; |
70 | static way_t relation_to=NO_WAY_ID; |
71 | static node_t relation_via=NO_NODE_ID; |
72 | |
73 | static NodesX *nodes; |
74 | static SegmentsX *segments; |
75 | static WaysX *ways; |
76 | static RelationsX *relations; |
77 | |
78 | |
79 | /* Local functions */ |
80 | |
81 | static void process_node_tags(TagList *tags,node_t id,double latitude,double longitude); |
82 | static void process_way_tags(TagList *tags,way_t id); |
83 | static void process_relation_tags(TagList *tags,relation_t id); |
84 | |
85 | static double parse_speed(way_t id,const char *k,const char *v); |
86 | static double parse_weight(way_t id,const char *k,const char *v); |
87 | static double parse_length(way_t id,const char *k,const char *v); |
88 | |
89 | |
90 | /* The XML tag processing function prototypes */ |
91 | |
92 | //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding); |
93 | //static int osmType_function(const char *_tag_,int _type_); |
94 | static int relationType_function(const char *_tag_,int _type_,const char *id); |
95 | static int wayType_function(const char *_tag_,int _type_,const char *id); |
96 | static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role); |
97 | static int ndType_function(const char *_tag_,int _type_,const char *ref); |
98 | static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon); |
99 | static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v); |
100 | //static int boundType_function(const char *_tag_,int _type_); |
101 | //static int boundsType_function(const char *_tag_,int _type_); |
102 | |
103 | |
104 | /* The XML tag definitions */ |
105 | |
106 | /*+ The boundsType type tag. +*/ |
107 | static xmltag boundsType_tag= |
108 | {"bounds", |
109 | 0, {NULL}, |
110 | NULL, |
111 | {NULL}}; |
112 | |
113 | /*+ The boundType type tag. +*/ |
114 | static xmltag boundType_tag= |
115 | {"bound", |
116 | 0, {NULL}, |
117 | NULL, |
118 | {NULL}}; |
119 | |
120 | /*+ The tagType type tag. +*/ |
121 | static xmltag tagType_tag= |
122 | {"tag", |
123 | 2, {"k","v"}, |
124 | tagType_function, |
125 | {NULL}}; |
126 | |
127 | /*+ The nodeType type tag. +*/ |
128 | static xmltag nodeType_tag= |
129 | {"node", |
130 | 3, {"id","lat","lon"}, |
131 | nodeType_function, |
132 | {&tagType_tag,NULL}}; |
133 | |
134 | /*+ The ndType type tag. +*/ |
135 | static xmltag ndType_tag= |
136 | {"nd", |
137 | 1, {"ref"}, |
138 | ndType_function, |
139 | {NULL}}; |
140 | |
141 | /*+ The memberType type tag. +*/ |
142 | static xmltag memberType_tag= |
143 | {"member", |
144 | 3, {"type","ref","role"}, |
145 | memberType_function, |
146 | {NULL}}; |
147 | |
148 | /*+ The wayType type tag. +*/ |
149 | static xmltag wayType_tag= |
150 | {"way", |
151 | 1, {"id"}, |
152 | wayType_function, |
153 | {&ndType_tag,&tagType_tag,NULL}}; |
154 | |
155 | /*+ The relationType type tag. +*/ |
156 | static xmltag relationType_tag= |
157 | {"relation", |
158 | 1, {"id"}, |
159 | relationType_function, |
160 | {&memberType_tag,&tagType_tag,NULL}}; |
161 | |
162 | /*+ The osmType type tag. +*/ |
163 | static xmltag osmType_tag= |
164 | {"osm", |
165 | 0, {NULL}, |
166 | NULL, |
167 | {&boundsType_tag,&boundType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}}; |
168 | |
169 | /*+ The xmlDeclaration type tag. +*/ |
170 | static xmltag xmlDeclaration_tag= |
171 | {"xml", |
172 | 2, {"version","encoding"}, |
173 | NULL, |
174 | {NULL}}; |
175 | |
176 | |
177 | /*+ The complete set of tags at the top level. +*/ |
178 | static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL}; |
179 | |
180 | |
181 | /* The XML tag processing functions */ |
182 | |
183 | |
184 | /*++++++++++++++++++++++++++++++++++++++ |
185 | The function that is called when the boundsType XSD type is seen |
186 | |
187 | int boundsType_function Returns 0 if no error occured or something else otherwise. |
188 | |
189 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
190 | |
191 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
192 | ++++++++++++++++++++++++++++++++++++++*/ |
193 | |
194 | //static int boundsType_function(const char *_tag_,int _type_) |
195 | //{ |
196 | // return(0); |
197 | //} |
198 | |
199 | |
200 | /*++++++++++++++++++++++++++++++++++++++ |
201 | The function that is called when the boundType XSD type is seen |
202 | |
203 | int boundType_function Returns 0 if no error occured or something else otherwise. |
204 | |
205 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
206 | |
207 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
208 | ++++++++++++++++++++++++++++++++++++++*/ |
209 | |
210 | //static int boundType_function(const char *_tag_,int _type_) |
211 | //{ |
212 | // return(0); |
213 | //} |
214 | |
215 | |
216 | /*++++++++++++++++++++++++++++++++++++++ |
217 | The function that is called when the tagType XSD type is seen |
218 | |
219 | int tagType_function Returns 0 if no error occured or something else otherwise. |
220 | |
221 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
222 | |
223 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
224 | |
225 | const char *k The contents of the 'k' attribute (or NULL if not defined). |
226 | |
227 | const char *v The contents of the 'v' attribute (or NULL if not defined). |
228 | ++++++++++++++++++++++++++++++++++++++*/ |
229 | |
230 | static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v) |
231 | { |
232 | if(_type_&XMLPARSE_TAG_START && current_tags) |
233 | { |
234 | XMLPARSE_ASSERT_STRING(_tag_,k); |
235 | XMLPARSE_ASSERT_STRING(_tag_,v); |
236 | |
237 | AppendTag(current_tags,k,v); |
238 | } |
239 | |
240 | return(0); |
241 | } |
242 | |
243 | |
244 | /*++++++++++++++++++++++++++++++++++++++ |
245 | The function that is called when the nodeType XSD type is seen |
246 | |
247 | int nodeType_function Returns 0 if no error occured or something else otherwise. |
248 | |
249 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
250 | |
251 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
252 | |
253 | const char *id The contents of the 'id' attribute (or NULL if not defined). |
254 | |
255 | const char *lat The contents of the 'lat' attribute (or NULL if not defined). |
256 | |
257 | const char *lon The contents of the 'lon' attribute (or NULL if not defined). |
258 | ++++++++++++++++++++++++++++++++++++++*/ |
259 | |
260 | static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon) |
261 | { |
262 | static node_t node_id; |
263 | static double latitude,longitude; |
264 | |
265 | if(_type_&XMLPARSE_TAG_START) |
266 | { |
267 | long long llid; |
268 | nnodes++; |
269 | |
270 | if(!(nnodes%10000)) |
271 | printf_middle("Reading: Lines=%llu Nodes=%"Pindex_t" Ways=%"Pindex_t" Relations=%"Pindex_t,ParseXML_LineNumber(),nnodes,nways,nrelations); |
272 | |
273 | current_tags=NewTagList(); |
274 | |
275 | /* Handle the node information */ |
276 | |
277 | XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */ |
278 | node_id=(node_t)llid; |
279 | assert((long long)node_id==llid); /* check node id can be stored in node_t data type. */ |
280 | |
281 | XMLPARSE_ASSERT_FLOATING(_tag_,lat); latitude =atof(lat); |
282 | XMLPARSE_ASSERT_FLOATING(_tag_,lon); longitude=atof(lon); |
283 | } |
284 | |
285 | if(_type_&XMLPARSE_TAG_END) |
286 | { |
287 | TagList *result=ApplyTaggingRules(&NodeRules,current_tags); |
288 | |
289 | process_node_tags(result,node_id,latitude,longitude); |
290 | |
291 | DeleteTagList(current_tags); |
292 | DeleteTagList(result); |
293 | } |
294 | |
295 | return(0); |
296 | } |
297 | |
298 | |
299 | /*++++++++++++++++++++++++++++++++++++++ |
300 | The function that is called when the ndType XSD type is seen |
301 | |
302 | int ndType_function Returns 0 if no error occured or something else otherwise. |
303 | |
304 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
305 | |
306 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
307 | |
308 | const char *ref The contents of the 'ref' attribute (or NULL if not defined). |
309 | ++++++++++++++++++++++++++++++++++++++*/ |
310 | |
311 | static int ndType_function(const char *_tag_,int _type_,const char *ref) |
312 | { |
313 | if(_type_&XMLPARSE_TAG_START) |
314 | { |
315 | long long llid; |
316 | node_t node_id; |
317 | |
318 | XMLPARSE_ASSERT_INTEGER(_tag_,ref); llid=atoll(ref); /* need long long conversion */ |
319 | node_id=(node_t)llid; |
320 | assert((long long)node_id==llid); /* check node id can be stored in node_t data type. */ |
321 | |
322 | if(way_nnodes && (way_nnodes%256)==0) |
323 | way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t)); |
324 | |
325 | way_nodes[way_nnodes++]=node_id; |
326 | } |
327 | |
328 | return(0); |
329 | } |
330 | |
331 | |
332 | /*++++++++++++++++++++++++++++++++++++++ |
333 | The function that is called when the memberType XSD type is seen |
334 | |
335 | int memberType_function Returns 0 if no error occured or something else otherwise. |
336 | |
337 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
338 | |
339 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
340 | |
341 | const char *type The contents of the 'type' attribute (or NULL if not defined). |
342 | |
343 | const char *ref The contents of the 'ref' attribute (or NULL if not defined). |
344 | |
345 | const char *role The contents of the 'role' attribute (or NULL if not defined). |
346 | ++++++++++++++++++++++++++++++++++++++*/ |
347 | |
348 | static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role) |
349 | { |
350 | if(_type_&XMLPARSE_TAG_START) |
351 | { |
352 | long long llid; |
353 | |
354 | XMLPARSE_ASSERT_STRING(_tag_,type); |
355 | XMLPARSE_ASSERT_INTEGER(_tag_,ref); llid=atoll(ref); /* need long long conversion */ |
356 | |
357 | if(!strcmp(type,"node")) |
358 | { |
359 | node_t node_id; |
360 | |
361 | node_id=(node_t)llid; |
362 | assert((long long)node_id==llid); /* check node id can be stored in node_t data type. */ |
363 | |
364 | if(relation_nnodes && (relation_nnodes%256)==0) |
365 | relation_nodes=(node_t*)realloc((void*)relation_nodes,(relation_nnodes+256)*sizeof(node_t)); |
366 | |
367 | relation_nodes[relation_nnodes++]=node_id; |
368 | |
369 | if(role) |
370 | { |
371 | if(!strcmp(role,"via")) |
372 | relation_via=node_id; |
373 | } |
374 | } |
375 | else if(!strcmp(type,"way")) |
376 | { |
377 | way_t way_id; |
378 | |
379 | way_id=(way_t)llid; |
380 | assert((long long)way_id==llid); /* check way id can be stored in way_t data type. */ |
381 | |
382 | if(relation_nways && (relation_nways%256)==0) |
383 | relation_ways=(way_t*)realloc((void*)relation_ways,(relation_nways+256)*sizeof(way_t)); |
384 | |
385 | relation_ways[relation_nways++]=way_id; |
386 | |
387 | if(role) |
388 | { |
389 | if(!strcmp(role,"from")) |
390 | relation_from=way_id; |
391 | if(!strcmp(role,"to")) |
392 | relation_to=way_id; |
393 | } |
394 | } |
395 | else if(!strcmp(type,"relation")) |
396 | { |
397 | relation_t relation_id; |
398 | |
399 | relation_id=(relation_t)llid; |
400 | assert((long long)relation_id==llid); /* check relation id can be stored in relation_t data type. */ |
401 | |
402 | if(relation_nrelations && (relation_nrelations%256)==0) |
403 | relation_relations=(relation_t*)realloc((void*)relation_relations,(relation_nrelations+256)*sizeof(relation_t)); |
404 | |
405 | relation_relations[relation_nrelations++]=relation_id; |
406 | } |
407 | } |
408 | |
409 | return(0); |
410 | } |
411 | |
412 | |
413 | /*++++++++++++++++++++++++++++++++++++++ |
414 | The function that is called when the wayType XSD type is seen |
415 | |
416 | int wayType_function Returns 0 if no error occured or something else otherwise. |
417 | |
418 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
419 | |
420 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
421 | |
422 | const char *id The contents of the 'id' attribute (or NULL if not defined). |
423 | ++++++++++++++++++++++++++++++++++++++*/ |
424 | |
425 | static int wayType_function(const char *_tag_,int _type_,const char *id) |
426 | { |
427 | static way_t way_id; |
428 | |
429 | if(_type_&XMLPARSE_TAG_START) |
430 | { |
431 | long long llid; |
432 | |
433 | nways++; |
434 | |
435 | if(!(nways%1000)) |
436 | printf_middle("Reading: Lines=%llu Nodes=%"Pindex_t" Ways=%"Pindex_t" Relations=%"Pindex_t,ParseXML_LineNumber(),nnodes,nways,nrelations); |
437 | |
438 | current_tags=NewTagList(); |
439 | |
440 | way_nnodes=0; |
441 | |
442 | /* Handle the way information */ |
443 | |
444 | XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */ |
445 | |
446 | way_id=(way_t)llid; |
447 | assert((long long)way_id==llid); /* check way id can be stored in way_t data type. */ |
448 | } |
449 | |
450 | if(_type_&XMLPARSE_TAG_END) |
451 | { |
452 | TagList *result=ApplyTaggingRules(&WayRules,current_tags); |
453 | |
454 | process_way_tags(result,way_id); |
455 | |
456 | DeleteTagList(current_tags); |
457 | DeleteTagList(result); |
458 | } |
459 | |
460 | return(0); |
461 | } |
462 | |
463 | |
464 | /*++++++++++++++++++++++++++++++++++++++ |
465 | The function that is called when the relationType XSD type is seen |
466 | |
467 | int relationType_function Returns 0 if no error occured or something else otherwise. |
468 | |
469 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
470 | |
471 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
472 | |
473 | const char *id The contents of the 'id' attribute (or NULL if not defined). |
474 | ++++++++++++++++++++++++++++++++++++++*/ |
475 | |
476 | static int relationType_function(const char *_tag_,int _type_,const char *id) |
477 | { |
478 | static relation_t relation_id; |
479 | |
480 | if(_type_&XMLPARSE_TAG_START) |
481 | { |
482 | long long llid; |
483 | |
484 | nrelations++; |
485 | |
486 | if(!(nrelations%1000)) |
487 | printf_middle("Reading: Lines=%llu Nodes=%"Pindex_t" Ways=%"Pindex_t" Relations=%"Pindex_t,ParseXML_LineNumber(),nnodes,nways,nrelations); |
488 | |
489 | current_tags=NewTagList(); |
490 | |
491 | relation_nnodes=relation_nways=relation_nrelations=0; |
492 | |
493 | relation_from=NO_WAY_ID; |
494 | relation_to=NO_WAY_ID; |
495 | relation_via=NO_NODE_ID; |
496 | |
497 | /* Handle the relation information */ |
498 | |
499 | XMLPARSE_ASSERT_INTEGER(_tag_,id); llid=atoll(id); /* need long long conversion */ |
500 | |
501 | relation_id=(relation_t)llid; |
502 | assert((long long)relation_id==llid); /* check relation id can be stored in relation_t data type. */ |
503 | } |
504 | |
505 | if(_type_&XMLPARSE_TAG_END) |
506 | { |
507 | TagList *result=ApplyTaggingRules(&RelationRules,current_tags); |
508 | |
509 | process_relation_tags(result,relation_id); |
510 | |
511 | DeleteTagList(current_tags); |
512 | DeleteTagList(result); |
513 | } |
514 | |
515 | return(0); |
516 | } |
517 | |
518 | |
519 | /*++++++++++++++++++++++++++++++++++++++ |
520 | The function that is called when the osmType XSD type is seen |
521 | |
522 | int osmType_function Returns 0 if no error occured or something else otherwise. |
523 | |
524 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
525 | |
526 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
527 | ++++++++++++++++++++++++++++++++++++++*/ |
528 | |
529 | //static int osmType_function(const char *_tag_,int _type_) |
530 | //{ |
531 | // return(0); |
532 | //} |
533 | |
534 | |
535 | /*++++++++++++++++++++++++++++++++++++++ |
536 | The function that is called when the XML declaration is seen |
537 | |
538 | int xmlDeclaration_function Returns 0 if no error occured or something else otherwise. |
539 | |
540 | const char *_tag_ Set to the name of the element tag that triggered this function call. |
541 | |
542 | int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag. |
543 | |
544 | const char *version The contents of the 'version' attribute (or NULL if not defined). |
545 | |
546 | const char *encoding The contents of the 'encoding' attribute (or NULL if not defined). |
547 | ++++++++++++++++++++++++++++++++++++++*/ |
548 | |
549 | //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding) |
550 | //{ |
551 | // return(0); |
552 | //} |
553 | |
554 | |
555 | /*++++++++++++++++++++++++++++++++++++++ |
556 | Parse an OSM XML file (from JOSM or planet download). |
557 | |
558 | int ParseOSM Returns 0 if OK or something else in case of an error. |
559 | |
560 | FILE *file The file to read from. |
561 | |
562 | NodesX *OSMNodes The data structure of nodes to fill in. |
563 | |
564 | SegmentsX *OSMSegments The data structure of segments to fill in. |
565 | |
566 | WaysX *OSMWays The data structure of ways to fill in. |
567 | |
568 | RelationsX *OSMRelations The data structure of relations to fill in. |
569 | ++++++++++++++++++++++++++++++++++++++*/ |
570 | |
571 | int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,RelationsX *OSMRelations) |
572 | { |
573 | int retval; |
574 | |
575 | /* Copy the function parameters and initialise the variables. */ |
576 | |
577 | nodes=OSMNodes; |
578 | segments=OSMSegments; |
579 | ways=OSMWays; |
580 | relations=OSMRelations; |
581 | |
582 | way_nodes=(node_t*)malloc(256*sizeof(node_t)); |
583 | |
584 | relation_nodes =(node_t *)malloc(256*sizeof(node_t)); |
585 | relation_ways =(way_t *)malloc(256*sizeof(way_t)); |
586 | relation_relations=(relation_t*)malloc(256*sizeof(relation_t)); |
587 | |
588 | /* Parse the file */ |
589 | |
590 | nnodes=0,nways=0,nrelations=0; |
591 | |
592 | printf_first("Reading: Lines=0 Nodes=0 Ways=0 Relations=0"); |
593 | |
594 | retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE); |
595 | |
596 | printf_last("Read: Lines=%llu Nodes=%"Pindex_t" Ways=%"Pindex_t" Relations=%"Pindex_t,ParseXML_LineNumber(),nnodes,nways,nrelations); |
597 | |
598 | free(way_nodes); |
599 | |
600 | free(relation_nodes); |
601 | free(relation_ways); |
602 | free(relation_relations); |
603 | |
604 | return(retval); |
605 | } |
606 | |
607 | |
608 | /*++++++++++++++++++++++++++++++++++++++ |
609 | Process the tags associated with a node. |
610 | |
611 | TagList *tags The list of node tags. |
612 | |
613 | node_t id The id of the node. |
614 | |
615 | double latitude The latitude of the node. |
616 | |
617 | double longitude The longitude of the node. |
618 | ++++++++++++++++++++++++++++++++++++++*/ |
619 | |
620 | static void process_node_tags(TagList *tags,node_t id,double latitude,double longitude) |
621 | { |
622 | transports_t allow=Transports_ALL; |
623 | uint16_t flags=0; |
624 | int i; |
625 | |
626 | /* Parse the tags */ |
627 | |
628 | for(i=0;i<tags->ntags;i++) |
629 | { |
630 | char *k=tags->k[i]; |
631 | char *v=tags->v[i]; |
632 | |
633 | switch(*k) |
634 | { |
635 | case 'b': |
636 | if(!strcmp(k,"bicycle")) |
637 | { |
638 | if(ISFALSE(v)) |
639 | allow&=~Transports_Bicycle; |
640 | else if(!ISTRUE(v)) |
641 | logerror("Node %"Pnode_t" has an unrecognised tag value 'bicycle' = '%s' (after processing tagging rules).\n",id,v); |
642 | } |
643 | |
644 | break; |
645 | |
646 | case 'f': |
647 | if(!strcmp(k,"foot")) |
648 | { |
649 | if(ISFALSE(v)) |
650 | allow&=~Transports_Foot; |
651 | else if(!ISTRUE(v)) |
652 | logerror("Node %"Pnode_t" has an unrecognised tag value 'foot' = '%s' (after processing tagging rules).\n",id,v); |
653 | } |
654 | |
655 | break; |
656 | |
657 | case 'g': |
658 | if(!strcmp(k,"goods")) |
659 | { |
660 | if(ISFALSE(v)) |
661 | allow&=~Transports_Goods; |
662 | else if(!ISTRUE(v)) |
663 | logerror("Node %"Pnode_t" has an unrecognised tag value 'goods' = '%s' (after processing tagging rules).\n",id,v); |
664 | } |
665 | |
666 | break; |
667 | |
668 | case 'h': |
669 | if(!strcmp(k,"highway")) |
670 | if(!strcmp(v,"mini_roundabout")) |
671 | flags|=NODE_MINIRNDBT; |
672 | |
673 | if(!strcmp(k,"horse")) |
674 | { |
675 | if(ISFALSE(v)) |
676 | allow&=~Transports_Horse; |
677 | else if(!ISTRUE(v)) |
678 | logerror("Node %"Pnode_t" has an unrecognised tag value 'horse' = '%s' (after processing tagging rules).\n",id,v); |
679 | } |
680 | |
681 | if(!strcmp(k,"hgv")) |
682 | { |
683 | if(ISFALSE(v)) |
684 | allow&=~Transports_HGV; |
685 | else if(!ISTRUE(v)) |
686 | logerror("Node %"Pnode_t" has an unrecognised tag value 'hgv' = '%s' (after processing tagging rules).\n",id,v); |
687 | } |
688 | |
689 | break; |
690 | |
691 | case 'm': |
692 | if(!strcmp(k,"moped")) |
693 | { |
694 | if(ISFALSE(v)) |
695 | allow&=~Transports_Moped; |
696 | else if(!ISTRUE(v)) |
697 | logerror("Node %"Pnode_t" has an unrecognised tag value 'moped' = '%s' (after processing tagging rules).\n",id,v); |
698 | } |
699 | |
700 | if(!strcmp(k,"motorbike")) |
701 | { |
702 | if(ISFALSE(v)) |
703 | allow&=~Transports_Motorbike; |
704 | else if(!ISTRUE(v)) |
705 | logerror("Node %"Pnode_t" has an unrecognised tag value 'motorbike' = '%s' (after processing tagging rules).\n",id,v); |
706 | } |
707 | |
708 | if(!strcmp(k,"motorcar")) |
709 | { |
710 | if(ISFALSE(v)) |
711 | allow&=~Transports_Motorcar; |
712 | else if(!ISTRUE(v)) |
713 | logerror("Node %"Pnode_t" has an unrecognised tag value 'motorcar' = '%s' (after processing tagging rules).\n",id,v); |
714 | } |
715 | |
716 | break; |
717 | |
718 | case 'p': |
719 | if(!strcmp(k,"psv")) |
720 | { |
721 | if(ISFALSE(v)) |
722 | allow&=~Transports_PSV; |
723 | else if(!ISTRUE(v)) |
724 | logerror("Node %"Pnode_t" has an unrecognised tag value 'psv' = '%s' (after processing tagging rules).\n",id,v); |
725 | } |
726 | |
727 | break; |
728 | |
729 | case 'w': |
730 | if(!strcmp(k,"wheelchair")) |
731 | { |
732 | if(ISFALSE(v)) |
733 | allow&=~Transports_Wheelchair; |
734 | else if(!ISTRUE(v)) |
735 | logerror("Node %"Pnode_t" has an unrecognised tag value 'wheelchair' = '%s' (after processing tagging rules).\n",id,v); |
736 | } |
737 | |
738 | break; |
739 | |
740 | default: |
741 | logerror("Node %"Pnode_t" has an unrecognised tag '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
742 | } |
743 | } |
744 | |
745 | /* Create the node */ |
746 | |
747 | AppendNode(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow,flags); |
748 | } |
749 | |
750 | |
751 | /*++++++++++++++++++++++++++++++++++++++ |
752 | Process the tags associated with a way. |
753 | |
754 | TagList *tags The list of way tags. |
755 | |
756 | way_t id The id of the way. |
757 | ++++++++++++++++++++++++++++++++++++++*/ |
758 | |
759 | static void process_way_tags(TagList *tags,way_t id) |
760 | { |
761 | Way way={0}; |
762 | int oneway=0; |
763 | char *name=NULL,*ref=NULL,*refname=NULL; |
764 | int i; |
765 | |
766 | /* Parse the tags */ |
767 | |
768 | for(i=0;i<tags->ntags;i++) |
769 | { |
770 | char *k=tags->k[i]; |
771 | char *v=tags->v[i]; |
772 | |
773 | switch(*k) |
774 | { |
775 | case 'b': |
776 | if(!strcmp(k,"bicycle")) |
777 | { |
778 | if(ISTRUE(v)) |
779 | way.allow|= Transports_Bicycle; |
780 | else if(!ISFALSE(v)) |
781 | logerror("Way %"Pway_t" has an unrecognised tag value 'bicycle' = '%s' (after processing tagging rules).\n",id,v); |
782 | } |
783 | |
784 | if(!strcmp(k,"bicycleroute")) |
785 | { |
786 | if(ISTRUE(v)) |
787 | way.props|=Properties_BicycleRoute; |
788 | else if(!ISFALSE(v)) |
789 | logerror("Way %"Pway_t" has an unrecognised tag value 'bicycleroute' = '%s' (after processing tagging rules).\n",id,v); |
790 | } |
791 | |
792 | if(!strcmp(k,"bridge")) |
793 | { |
794 | if(ISTRUE(v)) |
795 | way.props|=Properties_Bridge; |
796 | else if(!ISFALSE(v)) |
797 | logerror("Way %"Pway_t" has an unrecognised tag value 'bridge' = '%s' (after processing tagging rules).\n",id,v); |
798 | } |
799 | |
800 | break; |
801 | |
802 | case 'f': |
803 | if(!strcmp(k,"foot")) |
804 | { |
805 | if(ISTRUE(v)) |
806 | way.allow|= Transports_Foot; |
807 | else if(!ISFALSE(v)) |
808 | logerror("Way %"Pway_t" has an unrecognised tag value 'foot' = '%s' (after processing tagging rules).\n",id,v); |
809 | } |
810 | |
811 | if(!strcmp(k,"footroute")) |
812 | { |
813 | if(ISTRUE(v)) |
814 | way.props|=Properties_FootRoute; |
815 | else if(!ISFALSE(v)) |
816 | logerror("Way %"Pway_t" has an unrecognised tag value 'footroute' = '%s' (after processing tagging rules).\n",id,v); |
817 | } |
818 | |
819 | break; |
820 | |
821 | case 'g': |
822 | if(!strcmp(k,"goods")) |
823 | { |
824 | if(ISTRUE(v)) |
825 | way.allow|=Transports_Goods; |
826 | else if(!ISFALSE(v)) |
827 | logerror("Way %"Pway_t" has an unrecognised tag value 'goods' = '%s' (after processing tagging rules).\n",id,v); |
828 | } |
829 | |
830 | break; |
831 | |
832 | case 'h': |
833 | if(!strcmp(k,"highway")) |
834 | { |
835 | way.type=HighwayType(v); |
836 | |
837 | if(way.type==Way_Count) |
838 | logerror("Way %"Pway_t" has an unrecognised highway type '%s' (after processing tagging rules).\n",id,v); |
839 | } |
840 | |
841 | if(!strcmp(k,"horse")) |
842 | { |
843 | if(ISTRUE(v)) |
844 | way.allow|=Transports_Horse; |
845 | else if(!ISFALSE(v)) |
846 | logerror("Way %"Pway_t" has an unrecognised tag value 'horse' = '%s' (after processing tagging rules).\n",id,v); |
847 | } |
848 | |
849 | if(!strcmp(k,"hgv")) |
850 | { |
851 | if(ISTRUE(v)) |
852 | way.allow|=Transports_HGV; |
853 | else if(!ISFALSE(v)) |
854 | logerror("Way %"Pway_t" has an unrecognised tag value 'hgv' = '%s' (after processing tagging rules).\n",id,v); |
855 | } |
856 | |
857 | break; |
858 | |
859 | case 'm': |
860 | if(!strcmp(k,"maxspeed")) |
861 | way.speed=kph_to_speed(parse_speed(id,k,v)); |
862 | |
863 | if(!strcmp(k,"maxweight")) |
864 | way.weight=tonnes_to_weight(parse_weight(id,k,v)); |
865 | |
866 | if(!strcmp(k,"maxheight")) |
867 | way.height=metres_to_height(parse_length(id,k,v)); |
868 | |
869 | if(!strcmp(k,"maxwidth")) |
870 | way.width=metres_to_height(parse_length(id,k,v)); |
871 | |
872 | if(!strcmp(k,"maxlength")) |
873 | way.length=metres_to_height(parse_length(id,k,v)); |
874 | |
875 | if(!strcmp(k,"moped")) |
876 | { |
877 | if(ISTRUE(v)) |
878 | way.allow|=Transports_Moped; |
879 | else if(!ISFALSE(v)) |
880 | logerror("Way %"Pway_t" has an unrecognised tag value 'moped' = '%s' (after processing tagging rules).\n",id,v); |
881 | } |
882 | |
883 | if(!strcmp(k,"motorbike")) |
884 | { |
885 | if(ISTRUE(v)) |
886 | way.allow|=Transports_Motorbike; |
887 | else if(!ISFALSE(v)) |
888 | logerror("Way %"Pway_t" has an unrecognised tag value 'motorbike' = '%s' (after processing tagging rules).\n",id,v); |
889 | } |
890 | |
891 | if(!strcmp(k,"motorcar")) |
892 | { |
893 | if(ISTRUE(v)) |
894 | way.allow|=Transports_Motorcar; |
895 | else if(!ISFALSE(v)) |
896 | logerror("Way %"Pway_t" has an unrecognised tag value 'motorcar' = '%s' (after processing tagging rules).\n",id,v); |
897 | } |
898 | |
899 | if(!strcmp(k,"multilane")) |
900 | { |
901 | if(ISTRUE(v)) |
902 | way.props|=Properties_Multilane; |
903 | else if(!ISFALSE(v)) |
904 | logerror("Way %"Pway_t" has an unrecognised tag value 'multilane' = '%s' (after processing tagging rules).\n",id,v); |
905 | } |
906 | |
907 | break; |
908 | |
909 | case 'n': |
910 | if(!strcmp(k,"name")) |
911 | name=v; |
912 | |
913 | break; |
914 | |
915 | case 'o': |
916 | if(!strcmp(k,"oneway")) |
917 | { |
918 | if(ISTRUE(v)) |
919 | oneway=1; |
920 | else if(!strcmp(v,"-1")) |
921 | oneway=-1; |
922 | else if(!ISFALSE(v)) |
923 | logerror("Way %"Pway_t" has an unrecognised tag value 'oneway' = '%s' (after processing tagging rules).\n",id,v); |
924 | } |
925 | |
926 | break; |
927 | |
928 | case 'p': |
929 | if(!strcmp(k,"paved")) |
930 | { |
931 | if(ISTRUE(v)) |
932 | way.props|=Properties_Paved; |
933 | else if(!ISFALSE(v)) |
934 | logerror("Way %"Pway_t" has an unrecognised tag value 'paved' = '%s' (after processing tagging rules).\n",id,v); |
935 | } |
936 | |
937 | if(!strcmp(k,"psv")) |
938 | { |
939 | if(ISTRUE(v)) |
940 | way.allow|=Transports_PSV; |
941 | else if(!ISFALSE(v)) |
942 | logerror("Way %"Pway_t" has an unrecognised tag value 'psv' = '%s' (after processing tagging rules).\n",id,v); |
943 | } |
944 | |
945 | break; |
946 | |
947 | case 'r': |
948 | if(!strcmp(k,"ref")) |
949 | ref=v; |
950 | |
951 | break; |
952 | |
953 | case 't': |
954 | if(!strcmp(k,"tunnel")) |
955 | { |
956 | if(ISTRUE(v)) |
957 | way.props|=Properties_Tunnel; |
958 | else if(!ISFALSE(v)) |
959 | logerror("Way %"Pway_t" has an unrecognised tag value 'tunnel' = '%s' (after processing tagging rules).\n",id,v); |
960 | } |
961 | |
962 | break; |
963 | |
964 | case 'w': |
965 | if(!strcmp(k,"wheelchair")) |
966 | { |
967 | if(ISTRUE(v)) |
968 | way.allow|=Transports_Wheelchair; |
969 | else if(!ISFALSE(v)) |
970 | logerror("Way %"Pway_t" has an unrecognised tag value 'wheelchair' = '%s' (after processing tagging rules).\n",id,v); |
971 | } |
972 | |
973 | break; |
974 | |
975 | default: |
976 | logerror("Way %"Pway_t" has an unrecognised tag '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
977 | } |
978 | } |
979 | |
980 | /* Create the way */ |
981 | |
982 | if(way.type==0 || way.type==Way_Count) |
983 | return; |
984 | |
985 | if(!way.allow) |
986 | return; |
987 | |
988 | if(way_nnodes==0) |
989 | { |
990 | logerror("Way %"Pway_t" has no nodes.\n",id); |
991 | |
992 | return; |
993 | } |
994 | |
995 | if(oneway) |
996 | way.type|=Way_OneWay; |
997 | |
998 | if(ref && name) |
999 | { |
1000 | refname=(char*)malloc(strlen(ref)+strlen(name)+4); |
1001 | sprintf(refname,"%s (%s)",name,ref); |
1002 | } |
1003 | else if(ref && !name) |
1004 | refname=ref; |
1005 | else if(!ref && name) |
1006 | refname=name; |
1007 | else /* if(!ref && !name) */ |
1008 | refname=""; |
1009 | |
1010 | AppendWay(ways,id,&way,refname); |
1011 | |
1012 | if(ref && name) |
1013 | free(refname); |
1014 | |
1015 | for(i=1;i<way_nnodes;i++) |
1016 | { |
1017 | node_t from=way_nodes[i-1]; |
1018 | node_t to =way_nodes[i]; |
1019 | |
1020 | if(oneway>0) |
1021 | AppendSegment(segments,id,from,to,ONEWAY_1TO2); |
1022 | else if(oneway<0) |
1023 | AppendSegment(segments,id,from,to,ONEWAY_2TO1); |
1024 | else |
1025 | AppendSegment(segments,id,from,to,0); |
1026 | } |
1027 | } |
1028 | |
1029 | |
1030 | /*++++++++++++++++++++++++++++++++++++++ |
1031 | Process the tags associated with a relation. |
1032 | |
1033 | TagList *tags The list of relation tags. |
1034 | |
1035 | relation_t id The id of the relation. |
1036 | ++++++++++++++++++++++++++++++++++++++*/ |
1037 | |
1038 | static void process_relation_tags(TagList *tags,relation_t id) |
1039 | { |
1040 | transports_t routes=Transports_None; |
1041 | transports_t except=Transports_None; |
1042 | int relation_turn_restriction=0; |
1043 | TurnRestriction restriction=TurnRestrict_None; |
1044 | int i; |
1045 | |
1046 | /* Parse the tags */ |
1047 | |
1048 | for(i=0;i<tags->ntags;i++) |
1049 | { |
1050 | char *k=tags->k[i]; |
1051 | char *v=tags->v[i]; |
1052 | |
1053 | switch(*k) |
1054 | { |
1055 | case 'b': |
1056 | if(!strcmp(k,"bicycleroute")) |
1057 | { |
1058 | if(ISTRUE(v)) |
1059 | routes|=Transports_Bicycle; |
1060 | else if(!ISFALSE(v)) |
1061 | logerror("Relation %"Prelation_t" has an unrecognised tag value 'bicycleroute' = '%s' (after processing tagging rules).\n",id,v); |
1062 | } |
1063 | |
1064 | break; |
1065 | |
1066 | case 'e': |
1067 | if(!strcmp(k,"except")) |
1068 | { |
1069 | for(i=1;i<Transport_Count;i++) |
1070 | if(!strstr(v,TransportName(i))) |
1071 | except|=TRANSPORTS(i); |
1072 | |
1073 | if(except==Transports_None) |
1074 | logerror("Relation %"Prelation_t" has an unrecognised tag value 'except' = '%s' (after processing tagging rules).\n",id,v); |
1075 | } |
1076 | |
1077 | break; |
1078 | |
1079 | case 'f': |
1080 | if(!strcmp(k,"footroute")) |
1081 | { |
1082 | if(ISTRUE(v)) |
1083 | routes|=Transports_Foot; |
1084 | else if(!ISFALSE(v)) |
1085 | logerror("Relation %"Prelation_t" has an unrecognised tag value 'footroute' = '%s' (after processing tagging rules).\n",id,v); |
1086 | } |
1087 | |
1088 | break; |
1089 | |
1090 | case 'r': |
1091 | if(!strcmp(k,"restriction")) |
1092 | { |
1093 | if(!strcmp(v,"no_right_turn" )) restriction=TurnRestrict_no_right_turn; |
1094 | if(!strcmp(v,"no_left_turn" )) restriction=TurnRestrict_no_left_turn; |
1095 | if(!strcmp(v,"no_u_turn" )) restriction=TurnRestrict_no_u_turn; |
1096 | if(!strcmp(v,"no_straight_on" )) restriction=TurnRestrict_no_straight_on; |
1097 | if(!strcmp(v,"only_right_turn" )) restriction=TurnRestrict_only_right_turn; |
1098 | if(!strcmp(v,"only_left_turn" )) restriction=TurnRestrict_only_left_turn; |
1099 | if(!strcmp(v,"only_straight_on")) restriction=TurnRestrict_only_straight_on; |
1100 | |
1101 | if(restriction==TurnRestrict_None) |
1102 | logerror("Relation %"Prelation_t" has an unrecognised tag value 'restriction' = '%s' (after processing tagging rules).\n",id,v); |
1103 | } |
1104 | |
1105 | break; |
1106 | |
1107 | case 't': |
1108 | if(!strcmp(k,"type")) |
1109 | { |
1110 | if(!strcmp(v,"restriction")) |
1111 | relation_turn_restriction=1; |
1112 | else |
1113 | logerror("Relation %"Prelation_t" has an unrecognised tag value 'type' = '%s' (after processing tagging rules).\n",id,v); |
1114 | } |
1115 | break; |
1116 | |
1117 | default: |
1118 | logerror("Relation %"Prelation_t" has an unrecognised tag '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1119 | } |
1120 | } |
1121 | |
1122 | /* Create the route relation (must store all relations that have ways or |
1123 | relations even if they are not routes because they might be referenced by |
1124 | other relations that are routes) */ |
1125 | |
1126 | if((relation_nways || relation_nrelations) && !relation_turn_restriction) |
1127 | AppendRouteRelation(relations,id,routes, |
1128 | relation_ways,relation_nways, |
1129 | relation_relations,relation_nrelations); |
1130 | |
1131 | /* Create the turn restriction relation. */ |
1132 | |
1133 | if(relation_turn_restriction && restriction!=TurnRestrict_None) |
1134 | { |
1135 | if(relation_from==NO_WAY_ID) |
1136 | logerror("Relation %"Prelation_t" is a turn restriction but has no 'from' way (after processing tagging rules).\n",id); |
1137 | else if(relation_to==NO_WAY_ID) |
1138 | logerror("Relation %"Prelation_t" is a turn restriction but has no 'to' way (after processing tagging rules).\n",id); |
1139 | else if(relation_via==NO_NODE_ID) |
1140 | logerror("Relation %"Prelation_t" is a turn restriction but has no 'via' node (after processing tagging rules).\n",id); |
1141 | else |
1142 | AppendTurnRestrictRelation(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 value '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1168 | else |
1169 | { |
1170 | while(isspace(*ev)) ev++; |
1171 | |
1172 | if(!strcmp(ev,"mph")) |
1173 | return(1.609*value); |
1174 | else if(*ev==0) |
1175 | return(value); |
1176 | else |
1177 | logerror("Way %"Pway_t" has an un-parseable tag value '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1178 | } |
1179 | |
1180 | return(0); |
1181 | } |
1182 | |
1183 | |
1184 | /*++++++++++++++++++++++++++++++++++++++ |
1185 | Convert a string containing a weight into a double precision. |
1186 | |
1187 | double parse_weight Returns the weight in tonnes if it can be parsed. |
1188 | |
1189 | way_t id The way being processed. |
1190 | |
1191 | const char *k The tag key. |
1192 | |
1193 | const char *v The tag value. |
1194 | ++++++++++++++++++++++++++++++++++++++*/ |
1195 | |
1196 | static double parse_weight(way_t id,const char *k,const char *v) |
1197 | { |
1198 | char *ev; |
1199 | double value=strtod(v,&ev); |
1200 | |
1201 | if(v==ev) |
1202 | logerror("Way %"Pway_t" has an unrecognised tag value '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1203 | else |
1204 | { |
1205 | while(isspace(*ev)) ev++; |
1206 | |
1207 | if(!strcmp(ev,"kg")) |
1208 | return(value/1000.0); |
1209 | else if(*ev==0) |
1210 | return(value); |
1211 | else |
1212 | logerror("Way %"Pway_t" has an un-parseable tag value '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1213 | } |
1214 | |
1215 | return(0); |
1216 | } |
1217 | |
1218 | |
1219 | /*++++++++++++++++++++++++++++++++++++++ |
1220 | Convert a string containing a length into a double precision. |
1221 | |
1222 | double parse_length Returns the length in metres if it can be parsed. |
1223 | |
1224 | way_t id The way being processed. |
1225 | |
1226 | const char *k The tag key. |
1227 | |
1228 | const char *v The tag value. |
1229 | ++++++++++++++++++++++++++++++++++++++*/ |
1230 | |
1231 | static double parse_length(way_t id,const char *k,const char *v) |
1232 | { |
1233 | char *ev; |
1234 | double value=strtod(v,&ev); |
1235 | |
1236 | if(v==ev) |
1237 | logerror("Way %"Pway_t" has an unrecognised tag value '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1238 | else |
1239 | { |
1240 | int feet,inches; |
1241 | while(isspace(*ev)) ev++; |
1242 | |
1243 | if(sscanf(v,"%d'%d\"",&feet,&inches)==2) |
1244 | return((feet+(double)inches/12.0)*0.254); |
1245 | else if(sscanf(v,"%d'",&feet)==1) |
1246 | return(feet*0.254); |
1247 | else if(!strcmp(ev,"ft") || !strcmp(ev,"feet")) |
1248 | return(value*0.254); |
1249 | else if(*ev==0) |
1250 | return(value); |
1251 | else |
1252 | logerror("Way %"Pway_t" has an un-parseable tag value '%s' = '%s' (after processing tagging rules).\n",id,k,v); |
1253 | } |
1254 | |
1255 | return(0); |
1256 | } |
Properties
Name | Value |
---|---|
cvs:description | OSM XML file parser. |