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