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