Merge branch 'upstream'
[routino] / src / osmparser.c
1 /***************************************
2  $Header: /home/amb/routino/src/RCS/osmparser.c,v 1.73 2010/11/13 14:22:28 amb Exp $
3
4  OSM XML file parser (either JOSM or planet)
5
6  Part of the Routino routing software.
7  ******************/ /******************
8  This file Copyright 2008-2010 Andrew M. Bishop
9
10  This program is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Affero General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU Affero General Public License for more details.
19
20  You should have received a copy of the GNU Affero General Public License
21  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  ***************************************/
23
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #include "typesx.h"
31 #include "functionsx.h"
32
33 #include "nodesx.h"
34 #include "segmentsx.h"
35 #include "waysx.h"
36 #include "relationsx.h"
37
38 #include "xmlparse.h"
39 #include "tagging.h"
40
41 #include "logging.h"
42
43
44 /* Macros */
45
46 #define ISTRUE(xx) (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1"))
47
48
49 /* Local variables */
50
51 static long nnodes=0,nways=0,nrelations=0;
52 static TagList *current_tags=NULL;
53
54 static node_t *way_nodes=NULL;
55 static int     way_nnodes=0;
56
57 static node_t     *relation_nodes=NULL;
58 static int         relation_nnodes=0;
59 static way_t      *relation_ways=NULL;
60 static int         relation_nways=0;
61 static relation_t *relation_relations=NULL;
62 static int         relation_nrelations=0;
63
64 static NodesX     *nodes;
65 static SegmentsX  *segments;
66 static WaysX      *ways;
67 static RelationsX *relations;
68
69
70 /* Local functions */
71
72 static void process_node_tags(TagList *tags,node_t id,double latitude,double longitude);
73 static void process_way_tags(TagList *tags,way_t id);
74 static void process_relation_tags(TagList *tags,relation_t id);
75
76
77 /* The XML tag processing function prototypes */
78
79 //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
80 //static int osmType_function(const char *_tag_,int _type_);
81 static int relationType_function(const char *_tag_,int _type_,const char *id);
82 static int wayType_function(const char *_tag_,int _type_,const char *id);
83 static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role);
84 static int ndType_function(const char *_tag_,int _type_,const char *ref);
85 static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon);
86 static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v);
87 //static int boundType_function(const char *_tag_,int _type_);
88 //static int boundsType_function(const char *_tag_,int _type_);
89
90
91 /* The XML tag definitions */
92
93 /*+ The boundsType type tag. +*/
94 static xmltag boundsType_tag=
95               {"bounds",
96                0, {NULL},
97                NULL,
98                {NULL}};
99
100 /*+ The boundType type tag. +*/
101 static xmltag boundType_tag=
102               {"bound",
103                0, {NULL},
104                NULL,
105                {NULL}};
106
107 /*+ The tagType type tag. +*/
108 static xmltag tagType_tag=
109               {"tag",
110                2, {"k","v"},
111                tagType_function,
112                {NULL}};
113
114 /*+ The nodeType type tag. +*/
115 static xmltag nodeType_tag=
116               {"node",
117                3, {"id","lat","lon"},
118                nodeType_function,
119                {&tagType_tag,NULL}};
120
121 /*+ The ndType type tag. +*/
122 static xmltag ndType_tag=
123               {"nd",
124                1, {"ref"},
125                ndType_function,
126                {NULL}};
127
128 /*+ The memberType type tag. +*/
129 static xmltag memberType_tag=
130               {"member",
131                3, {"type","ref","role"},
132                memberType_function,
133                {NULL}};
134
135 /*+ The wayType type tag. +*/
136 static xmltag wayType_tag=
137               {"way",
138                1, {"id"},
139                wayType_function,
140                {&ndType_tag,&tagType_tag,NULL}};
141
142 /*+ The relationType type tag. +*/
143 static xmltag relationType_tag=
144               {"relation",
145                1, {"id"},
146                relationType_function,
147                {&memberType_tag,&tagType_tag,NULL}};
148
149 /*+ The osmType type tag. +*/
150 static xmltag osmType_tag=
151               {"osm",
152                0, {NULL},
153                NULL,
154                {&boundsType_tag,&boundType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
155
156 /*+ The xmlDeclaration type tag. +*/
157 static xmltag xmlDeclaration_tag=
158               {"xml",
159                2, {"version","encoding"},
160                NULL,
161                {NULL}};
162
163
164 /*+ The complete set of tags at the top level. +*/
165 static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL};
166
167
168 /* The XML tag processing functions */
169
170
171 /*++++++++++++++++++++++++++++++++++++++
172   The function that is called when the boundsType XSD type is seen
173
174   int boundsType_function Returns 0 if no error occured or something else otherwise.
175
176   const char *_tag_ Set to the name of the element tag that triggered this function call.
177
178   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
179   ++++++++++++++++++++++++++++++++++++++*/
180
181 //static int boundsType_function(const char *_tag_,int _type_)
182 //{
183 // return(0);
184 //}
185
186
187 /*++++++++++++++++++++++++++++++++++++++
188   The function that is called when the boundType XSD type is seen
189
190   int boundType_function Returns 0 if no error occured or something else otherwise.
191
192   const char *_tag_ Set to the name of the element tag that triggered this function call.
193
194   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
195   ++++++++++++++++++++++++++++++++++++++*/
196
197 //static int boundType_function(const char *_tag_,int _type_)
198 //{
199 // return(0);
200 //}
201
202
203 /*++++++++++++++++++++++++++++++++++++++
204   The function that is called when the tagType XSD type is seen
205
206   int tagType_function Returns 0 if no error occured or something else otherwise.
207
208   const char *_tag_ Set to the name of the element tag that triggered this function call.
209
210   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
211
212   const char *k The contents of the 'k' attribute (or NULL if not defined).
213
214   const char *v The contents of the 'v' attribute (or NULL if not defined).
215   ++++++++++++++++++++++++++++++++++++++*/
216
217 static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v)
218 {
219  if(_type_&XMLPARSE_TAG_START && current_tags)
220    {
221     XMLPARSE_ASSERT_STRING(_tag_,k);
222     XMLPARSE_ASSERT_STRING(_tag_,v);
223
224     AppendTag(current_tags,k,v);
225    }
226
227  return(0);
228 }
229
230
231 /*++++++++++++++++++++++++++++++++++++++
232   The function that is called when the nodeType XSD type is seen
233
234   int nodeType_function Returns 0 if no error occured or something else otherwise.
235
236   const char *_tag_ Set to the name of the element tag that triggered this function call.
237
238   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
239
240   const char *id The contents of the 'id' attribute (or NULL if not defined).
241
242   const char *lat The contents of the 'lat' attribute (or NULL if not defined).
243
244   const char *lon The contents of the 'lon' attribute (or NULL if not defined).
245   ++++++++++++++++++++++++++++++++++++++*/
246
247 static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon)
248 {
249  static node_t node_id;
250  static double latitude,longitude;
251
252  if(_type_&XMLPARSE_TAG_START)
253    {
254     nnodes++;
255
256     if(!(nnodes%1000))
257        printf_middle("Reading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations);
258
259     current_tags=NewTagList();
260
261     /* Handle the node information */
262
263     XMLPARSE_ASSERT_STRING(_tag_,id); node_id=atoll(id); /* need long long conversion */
264     XMLPARSE_ASSERT_FLOATING(_tag_,lat,latitude);
265     XMLPARSE_ASSERT_FLOATING(_tag_,lon,longitude);
266    }
267
268  if(_type_&XMLPARSE_TAG_END)
269    {
270     TagList *result=ApplyTaggingRules(&NodeRules,current_tags);
271
272     process_node_tags(result,node_id,latitude,longitude);
273
274     DeleteTagList(current_tags);
275     DeleteTagList(result);
276    }
277
278  return(0);
279 }
280
281
282 /*++++++++++++++++++++++++++++++++++++++
283   The function that is called when the ndType XSD type is seen
284
285   int ndType_function Returns 0 if no error occured or something else otherwise.
286
287   const char *_tag_ Set to the name of the element tag that triggered this function call.
288
289   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
290
291   const char *ref The contents of the 'ref' attribute (or NULL if not defined).
292   ++++++++++++++++++++++++++++++++++++++*/
293
294 static int ndType_function(const char *_tag_,int _type_,const char *ref)
295 {
296  if(_type_&XMLPARSE_TAG_START)
297    {
298     node_t node_id;
299
300     XMLPARSE_ASSERT_STRING(_tag_,ref); node_id=atoll(ref); /* need long long conversion */
301
302     if(way_nnodes && (way_nnodes%256)==0)
303        way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t));
304
305     way_nodes[way_nnodes++]=node_id;
306    }
307
308  return(0);
309 }
310
311
312 /*++++++++++++++++++++++++++++++++++++++
313   The function that is called when the memberType XSD type is seen
314
315   int memberType_function Returns 0 if no error occured or something else otherwise.
316
317   const char *_tag_ Set to the name of the element tag that triggered this function call.
318
319   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
320
321   const char *type The contents of the 'type' attribute (or NULL if not defined).
322
323   const char *ref The contents of the 'ref' attribute (or NULL if not defined).
324
325   const char *role The contents of the 'role' attribute (or NULL if not defined).
326   ++++++++++++++++++++++++++++++++++++++*/
327
328 static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role)
329 {
330  if(_type_&XMLPARSE_TAG_START)
331    {
332     XMLPARSE_ASSERT_STRING(_tag_,type);
333     XMLPARSE_ASSERT_STRING(_tag_,ref);
334
335     if(!strcmp(type,"node"))
336       {
337        node_t node_id=atoll(ref); /* need long long conversion */
338
339        if(relation_nnodes && (relation_nnodes%256)==0)
340           relation_nodes=(node_t*)realloc((void*)relation_nodes,(relation_nnodes+256)*sizeof(node_t));
341
342        relation_nodes[relation_nnodes++]=node_id;
343       }
344     else if(!strcmp(type,"way"))
345       {
346        way_t way_id=atoll(ref); /* need long long conversion */
347
348        if(relation_nways && (relation_nways%256)==0)
349           relation_ways=(way_t*)realloc((void*)relation_ways,(relation_nways+256)*sizeof(way_t));
350
351        relation_ways[relation_nways++]=way_id;
352       }
353     else if(!strcmp(type,"relation"))
354       {
355        relation_t relation_id=atoll(ref); /* need long long conversion */
356
357        if(relation_nrelations && (relation_nrelations%256)==0)
358           relation_relations=(relation_t*)realloc((void*)relation_relations,(relation_nrelations+256)*sizeof(relation_t));
359
360        relation_relations[relation_nrelations++]=relation_id;
361       }
362    }
363
364  return(0);
365 }
366
367
368 /*++++++++++++++++++++++++++++++++++++++
369   The function that is called when the wayType XSD type is seen
370
371   int wayType_function Returns 0 if no error occured or something else otherwise.
372
373   const char *_tag_ Set to the name of the element tag that triggered this function call.
374
375   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
376
377   const char *id The contents of the 'id' attribute (or NULL if not defined).
378   ++++++++++++++++++++++++++++++++++++++*/
379
380 static int wayType_function(const char *_tag_,int _type_,const char *id)
381 {
382  static way_t way_id;
383
384  if(_type_&XMLPARSE_TAG_START)
385    {
386     nways++;
387
388     if(!(nways%1000))
389        printf_middle("Reading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations);
390
391     current_tags=NewTagList();
392
393     way_nnodes=0;
394
395     /* Handle the way information */
396
397     XMLPARSE_ASSERT_STRING(_tag_,id); way_id=atoll(id); /* need long long conversion */
398    }
399
400  if(_type_&XMLPARSE_TAG_END)
401    {
402     TagList *result=ApplyTaggingRules(&WayRules,current_tags);
403
404     process_way_tags(result,way_id);
405
406     DeleteTagList(current_tags);
407     DeleteTagList(result);
408    }
409
410  return(0);
411 }
412
413
414 /*++++++++++++++++++++++++++++++++++++++
415   The function that is called when the relationType XSD type is seen
416
417   int relationType_function Returns 0 if no error occured or something else otherwise.
418
419   const char *_tag_ Set to the name of the element tag that triggered this function call.
420
421   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
422
423   const char *id The contents of the 'id' attribute (or NULL if not defined).
424   ++++++++++++++++++++++++++++++++++++++*/
425
426 static int relationType_function(const char *_tag_,int _type_,const char *id)
427 {
428  static relation_t relation_id;
429
430  if(_type_&XMLPARSE_TAG_START)
431    {
432     nrelations++;
433
434     if(!(nrelations%1000))
435        printf_middle("Reading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations);
436
437     current_tags=NewTagList();
438
439     relation_nnodes=relation_nways=relation_nrelations=0;
440
441     /* Handle the relation information */
442
443     XMLPARSE_ASSERT_STRING(_tag_,id); relation_id=atoll(id); /* need long long conversion */
444    }
445
446  if(_type_&XMLPARSE_TAG_END)
447    {
448     TagList *result=ApplyTaggingRules(&RelationRules,current_tags);
449
450     process_relation_tags(result,relation_id);
451
452     DeleteTagList(current_tags);
453     DeleteTagList(result);
454    }
455
456  return(0);
457 }
458
459
460 /*++++++++++++++++++++++++++++++++++++++
461   The function that is called when the osmType XSD type is seen
462
463   int osmType_function Returns 0 if no error occured or something else otherwise.
464
465   const char *_tag_ Set to the name of the element tag that triggered this function call.
466
467   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
468   ++++++++++++++++++++++++++++++++++++++*/
469
470 //static int osmType_function(const char *_tag_,int _type_)
471 //{
472 // return(0);
473 //}
474
475
476 /*++++++++++++++++++++++++++++++++++++++
477   The function that is called when the XML declaration is seen
478
479   int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
480
481   const char *_tag_ Set to the name of the element tag that triggered this function call.
482
483   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
484
485   const char *version The contents of the 'version' attribute (or NULL if not defined).
486
487   const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
488   ++++++++++++++++++++++++++++++++++++++*/
489
490 //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
491 //{
492 // return(0);
493 //}
494
495
496 /*++++++++++++++++++++++++++++++++++++++
497   Parse an OSM XML file (from JOSM or planet download).
498
499   int ParseOSM Returns 0 if OK or something else in case of an error.
500
501   FILE *file The file to read from.
502
503   NodesX *OSMNodes The data structure of nodes to fill in.
504
505   SegmentsX *OSMSegments The data structure of segments to fill in.
506
507   WaysX *OSMWays The data structure of ways to fill in.
508
509   RelationsX *OSMRelations The data structure of relations to fill in.
510   ++++++++++++++++++++++++++++++++++++++*/
511
512 int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays,RelationsX *OSMRelations)
513 {
514  int retval;
515
516  /* Copy the function parameters and initialise the variables. */
517
518  nodes=OSMNodes;
519  segments=OSMSegments;
520  ways=OSMWays;
521  relations=OSMRelations;
522
523  way_nodes=(node_t*)malloc(256*sizeof(node_t));
524
525  relation_nodes    =(node_t    *)malloc(256*sizeof(node_t));
526  relation_ways     =(way_t     *)malloc(256*sizeof(way_t));
527  relation_relations=(relation_t*)malloc(256*sizeof(relation_t));
528
529  /* Parse the file */
530
531  nnodes=0,nways=0,nrelations=0;
532
533  printf_first("Reading: Lines=0 Nodes=0 Ways=0 Relations=0");
534
535  retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
536
537  printf_last("Read: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations);
538
539  return(retval);
540 }
541
542
543 /*++++++++++++++++++++++++++++++++++++++
544   Process the tags associated with a node.
545
546   TagList *tags The list of node tags.
547
548   node_t id The id of the node.
549
550   double latitude The latitude of the node.
551
552   double longitude The longitude of the node.
553   ++++++++++++++++++++++++++++++++++++++*/
554
555 static void process_node_tags(TagList *tags,node_t id,double latitude,double longitude)
556 {
557  allow_t allow=Allow_ALL;
558
559  int i;
560
561  /* Parse the tags */
562
563  for(i=0;i<tags->ntags;i++)
564    {
565     char *k=tags->k[i];
566     char *v=tags->v[i];
567
568     switch(*k)
569       {
570       case 'b':
571        if(!strcmp(k,"bicycle"))
572           if(!ISTRUE(v))
573              allow&=~Allow_Bicycle;
574
575        break;
576
577       case 'f':
578        if(!strcmp(k,"foot"))
579           if(!ISTRUE(v))
580              allow&=~Allow_Foot;
581
582        break;
583
584       case 'g':
585        if(!strcmp(k,"goods"))
586           if(!ISTRUE(v))
587              allow&=~Allow_Goods;
588
589        break;
590
591       case 'h':
592        if(!strcmp(k,"horse"))
593           if(!ISTRUE(v))
594              allow&=~Allow_Horse;
595
596        if(!strcmp(k,"hgv"))
597           if(!ISTRUE(v))
598              allow&=~Allow_HGV;
599
600        break;
601
602       case 'm':
603        if(!strcmp(k,"moped"))
604           if(!ISTRUE(v))
605              allow&=~Allow_Moped;
606
607        if(!strcmp(k,"motorbike"))
608           if(!ISTRUE(v))
609              allow&=~Allow_Motorbike;
610
611        if(!strcmp(k,"motorcar"))
612           if(!ISTRUE(v))
613              allow&=~Allow_Motorcar;
614
615        break;
616
617       case 'p':
618        if(!strcmp(k,"psv"))
619           if(!ISTRUE(v))
620              allow&=~Allow_PSV;
621
622        break;
623
624       case 'w':
625        if(!strcmp(k,"wheelchair"))
626           if(!ISTRUE(v))
627              allow&=~Allow_Wheelchair;
628
629        break;
630
631       default:
632        ;
633       }
634    }
635
636  /* Create the node */
637
638  AppendNode(nodes,id,degrees_to_radians(latitude),degrees_to_radians(longitude),allow);
639 }
640
641
642 /*++++++++++++++++++++++++++++++++++++++
643   Process the tags associated with a way.
644
645   TagList *tags The list of way tags.
646
647   way_t id The id of the way.
648   ++++++++++++++++++++++++++++++++++++++*/
649
650 static void process_way_tags(TagList *tags,way_t id)
651 {
652  Way   way={0};
653  int   oneway=0,roundabout=0;
654  char *name=NULL,*ref=NULL;
655
656  int i;
657
658  /* Parse the tags */
659
660  for(i=0;i<tags->ntags;i++)
661    {
662     char *k=tags->k[i];
663     char *v=tags->v[i];
664
665     switch(*k)
666       {
667       case 'b':
668        if(!strcmp(k,"bicycle"))
669           if(ISTRUE(v))
670              way.allow|= Allow_Bicycle;
671
672        if(!strcmp(k,"bicycleroute"))
673           if(ISTRUE(v))
674              way.props|=Properties_BicycleRoute;
675
676        if(!strcmp(k,"bridge"))
677           if(ISTRUE(v))
678              way.props|=Properties_Bridge;
679
680        break;
681
682       case 'f':
683        if(!strcmp(k,"foot"))
684           if(ISTRUE(v))
685              way.allow|= Allow_Foot;
686
687        if(!strcmp(k,"footroute"))
688           if(ISTRUE(v))
689              way.props|=Properties_FootRoute;
690
691        break;
692
693       case 'g':
694        if(!strcmp(k,"goods"))
695           if(ISTRUE(v))
696              way.allow|=Allow_Goods;
697
698        break;
699
700       case 'h':
701        if(!strcmp(k,"highway"))
702           way.type=HighwayType(v);
703
704        if(!strcmp(k,"horse"))
705           if(ISTRUE(v))
706              way.allow|=Allow_Horse;
707
708        if(!strcmp(k,"hgv"))
709           if(ISTRUE(v))
710              way.allow|=Allow_HGV;
711
712        break;
713
714       case 'j':
715        if(!strcmp(k,"junction") && !strcmp(v,"roundabout"))
716           roundabout=1;
717
718        break;
719
720       case 'm':
721        if(!strcmp(k,"maxspeed"))
722          {
723           if(strstr(v,"mph"))
724              way.speed=kph_to_speed(1.609*atof(v));
725           else
726              way.speed=kph_to_speed(atof(v));
727          }
728
729        if(!strcmp(k,"maxweight"))
730          {
731           if(strstr(v,"kg"))
732              way.weight=tonnes_to_weight(atof(v)/1000);
733           else
734              way.weight=tonnes_to_weight(atof(v));
735          }
736
737        if(!strcmp(k,"maxheight"))
738          {
739           if(strchr(v,'\''))
740             {
741              int feet,inches;
742
743              if(sscanf(v,"%d'%d\"",&feet,&inches)==2)
744                 way.height=metres_to_height((feet+(double)inches/12.0)*0.254);
745              else if(sscanf(v,"%d'",&feet)==1)
746                 way.height=metres_to_height((feet+(double)inches/12.0)*0.254);
747             }
748           else if(strstr(v,"ft") || strstr(v,"feet"))
749              way.height=metres_to_height(atof(v)*0.254);
750           else
751              way.height=metres_to_height(atof(v));
752          }
753
754        if(!strcmp(k,"maxwidth"))
755          {
756           if(strchr(v,'\''))
757             {
758              int feet,inches;
759
760              if(sscanf(v,"%d'%d\"",&feet,&inches)==2)
761                 way.width=metres_to_height((feet+(double)inches/12.0)*0.254);
762              else if(sscanf(v,"%d'",&feet)==1)
763                 way.width=metres_to_height((feet+(double)inches/12.0)*0.254);
764             }
765           else if(strstr(v,"ft") || strstr(v,"feet"))
766              way.width=metres_to_width(atof(v)*0.254);
767           else
768              way.width=metres_to_width(atof(v));
769          }
770
771        if(!strcmp(k,"maxlength"))
772          {
773           if(strchr(v,'\''))
774             {
775              int feet,inches;
776
777              if(sscanf(v,"%d'%d\"",&feet,&inches)==2)
778                 way.length=metres_to_height((feet+(double)inches/12.0)*0.254);
779              else if(sscanf(v,"%d'",&feet)==1)
780                 way.length=metres_to_height((feet+(double)inches/12.0)*0.254);
781             }
782           else if(strstr(v,"ft") || strstr(v,"feet"))
783              way.length=metres_to_length(atof(v)*0.254);
784           else
785              way.length=metres_to_length(atof(v));
786          }
787
788        if(!strcmp(k,"moped"))
789           if(ISTRUE(v))
790              way.allow|=Allow_Moped;
791
792        if(!strcmp(k,"motorbike"))
793           if(ISTRUE(v))
794              way.allow|=Allow_Motorbike;
795
796        if(!strcmp(k,"motorcar"))
797           if(ISTRUE(v))
798              way.allow|=Allow_Motorcar;
799
800        if(!strcmp(k,"multilane"))
801           if(ISTRUE(v))
802              way.props|=Properties_Multilane;
803
804        break;
805
806       case 'n':
807        if(!strcmp(k,"name"))
808           name=v;
809
810        break;
811
812       case 'o':
813        if(!strcmp(k,"oneway"))
814          {
815           if(ISTRUE(v))
816              oneway=1;
817           else if(!strcmp(v,"-1"))
818              oneway=-1;
819          }
820
821        break;
822
823       case 'p':
824        if(!strcmp(k,"paved"))
825           if(ISTRUE(v))
826              way.props|=Properties_Paved;
827
828        if(!strcmp(k,"psv"))
829           if(ISTRUE(v))
830              way.allow|=Allow_PSV;
831
832        break;
833
834       case 'r':
835        if(!strcmp(k,"ref"))
836           ref=v;
837
838        break;
839
840       case 't':
841        if(!strcmp(k,"tunnel"))
842           if(ISTRUE(v))
843              way.props|=Properties_Tunnel;
844
845        break;
846
847       case 'w':
848        if(!strcmp(k,"wheelchair"))
849           if(ISTRUE(v))
850              way.allow|=Allow_Wheelchair;
851
852        break;
853
854       default:
855        ;
856       }
857    }
858
859  /* Create the way */
860
861  if(way.type>0 && way.type<Way_Count)
862    {
863     if(way.allow)
864       {
865        char *refname;
866
867        if(oneway)
868           way.type|=Way_OneWay;
869
870        if(roundabout)
871           way.type|=Way_Roundabout;
872
873        if(ref && name)
874          {
875           refname=(char*)malloc(strlen(ref)+strlen(name)+4);
876           sprintf(refname,"%s (%s)",name,ref);
877          }
878        else if(ref && !name)
879           refname=ref;
880        else if(!ref && name)
881           refname=name;
882        else /* if(!ref && !name) */
883           refname="";
884
885        AppendWay(ways,id,&way,refname);
886
887        if(ref && name)
888           free(refname);
889
890        for(i=1;i<way_nnodes;i++)
891          {
892           node_t from=way_nodes[i-1];
893           node_t to  =way_nodes[i];
894
895           if(oneway>0)
896             {
897              AppendSegment(segments,id,from,to,ONEWAY_1TO2);
898              AppendSegment(segments,id,to,from,ONEWAY_2TO1);
899             }
900           else if(oneway<0)
901             {
902              AppendSegment(segments,id,from,to,ONEWAY_2TO1);
903              AppendSegment(segments,id,to,from,ONEWAY_1TO2);
904             }
905           else
906             {
907              AppendSegment(segments,id,from,to,0);
908              AppendSegment(segments,id,to,from,0);
909             }
910          }
911       }
912    }
913 }
914
915
916 /*++++++++++++++++++++++++++++++++++++++
917   Process the tags associated with a relation.
918
919   TagList *tags The list of relation tags.
920
921   relation_t id The id of the relation.
922   ++++++++++++++++++++++++++++++++++++++*/
923
924 static void process_relation_tags(TagList *tags,relation_t id)
925 {
926  allow_t routes=Allow_None;
927  int i;
928
929  /* Parse the tags */
930
931  for(i=0;i<tags->ntags;i++)
932    {
933     char *k=tags->k[i];
934     char *v=tags->v[i];
935
936     switch(*k)
937       {
938       case 'b':
939        if(!strcmp(k,"bicycleroute"))
940           if(ISTRUE(v))
941              routes|=Allow_Bicycle;
942
943        break;
944
945       case 'f':
946        if(!strcmp(k,"footroute"))
947           if(ISTRUE(v))
948              routes|=Allow_Foot;
949
950        break;
951
952       default:
953        ;
954       }
955    }
956
957  /* Create the route relation (must store all relations that have ways or
958     relations even if they are not routes because they might be referenced by
959     other relations that are routes) */
960
961  if(relation_nways || relation_nrelations)
962     AppendRouteRelation(relations,id,routes,
963                         relation_ways,relation_nways,
964                         relation_relations,relation_nrelations);
965 }