initial packaging
[routino] / src / osmparser.c
1 /***************************************
2  $Header: /home/amb/routino/src/RCS/osmparser.c,v 1.69 2010/05/29 13:54:23 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 #include "nodesx.h"
33 #include "segmentsx.h"
34 #include "waysx.h"
35 #include "xmlparse.h"
36 #include "tagging.h"
37
38
39 /* Macros */
40
41 #define ISTRUE(xx) (!strcmp(xx,"true") || !strcmp(xx,"yes") || !strcmp(xx,"1"))
42
43
44 /* Local variables */
45
46 static long nnodes=0,nways=0,nrelations=0;
47 static TagList *current_tags=NULL;
48
49 static node_t *way_nodes=NULL;
50 static int     way_nnodes=0;
51
52 static NodesX    *nodes;
53 static SegmentsX *segments;
54 static WaysX     *ways;
55
56
57 /* Local functions */
58
59 static void process_way_tags(TagList *tags,way_t id);
60
61
62 /* The XML tag processing function prototypes */
63
64 //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding);
65 //static int osmType_function(const char *_tag_,int _type_);
66 static int relationType_function(const char *_tag_,int _type_,const char *id);
67 static int wayType_function(const char *_tag_,int _type_,const char *id);
68 //static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role);
69 static int ndType_function(const char *_tag_,int _type_,const char *ref);
70 static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon);
71 static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v);
72 //static int boundType_function(const char *_tag_,int _type_);
73 //static int boundsType_function(const char *_tag_,int _type_);
74
75
76 /* The XML tag definitions */
77
78 /*+ The boundsType type tag. +*/
79 static xmltag boundsType_tag=
80               {"bounds",
81                0, {NULL},
82                NULL,
83                {NULL}};
84
85 /*+ The boundType type tag. +*/
86 static xmltag boundType_tag=
87               {"bound",
88                0, {NULL},
89                NULL,
90                {NULL}};
91
92 /*+ The tagType type tag. +*/
93 static xmltag tagType_tag=
94               {"tag",
95                2, {"k","v"},
96                tagType_function,
97                {NULL}};
98
99 /*+ The nodeType type tag. +*/
100 static xmltag nodeType_tag=
101               {"node",
102                3, {"id","lat","lon"},
103                nodeType_function,
104                {&tagType_tag,NULL}};
105
106 /*+ The ndType type tag. +*/
107 static xmltag ndType_tag=
108               {"nd",
109                1, {"ref"},
110                ndType_function,
111                {NULL}};
112
113 /*+ The memberType type tag. +*/
114 static xmltag memberType_tag=
115               {"member",
116                3, {"type","ref","role"},
117                NULL,
118                {NULL}};
119
120 /*+ The wayType type tag. +*/
121 static xmltag wayType_tag=
122               {"way",
123                1, {"id"},
124                wayType_function,
125                {&ndType_tag,&tagType_tag,NULL}};
126
127 /*+ The relationType type tag. +*/
128 static xmltag relationType_tag=
129               {"relation",
130                1, {"id"},
131                relationType_function,
132                {&memberType_tag,&tagType_tag,NULL}};
133
134 /*+ The osmType type tag. +*/
135 static xmltag osmType_tag=
136               {"osm",
137                0, {NULL},
138                NULL,
139                {&boundsType_tag,&boundType_tag,&nodeType_tag,&wayType_tag,&relationType_tag,NULL}};
140
141 /*+ The xmlDeclaration type tag. +*/
142 static xmltag xmlDeclaration_tag=
143               {"xml",
144                2, {"version","encoding"},
145                NULL,
146                {NULL}};
147
148
149 /*+ The complete set of tags at the top level. +*/
150 static xmltag *xml_toplevel_tags[]={&xmlDeclaration_tag,&osmType_tag,NULL};
151
152
153 /* The XML tag processing functions */
154
155
156 /*++++++++++++++++++++++++++++++++++++++
157   The function that is called when the boundsType XSD type is seen
158
159   int boundsType_function Returns 0 if no error occured or something else otherwise.
160
161   const char *_tag_ Set to the name of the element tag that triggered this function call.
162
163   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
164   ++++++++++++++++++++++++++++++++++++++*/
165
166 //static int boundsType_function(const char *_tag_,int _type_)
167 //{
168 // return(0);
169 //}
170
171
172 /*++++++++++++++++++++++++++++++++++++++
173   The function that is called when the boundType XSD type is seen
174
175   int boundType_function Returns 0 if no error occured or something else otherwise.
176
177   const char *_tag_ Set to the name of the element tag that triggered this function call.
178
179   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
180   ++++++++++++++++++++++++++++++++++++++*/
181
182 //static int boundType_function(const char *_tag_,int _type_)
183 //{
184 // return(0);
185 //}
186
187
188 /*++++++++++++++++++++++++++++++++++++++
189   The function that is called when the tagType XSD type is seen
190
191   int tagType_function Returns 0 if no error occured or something else otherwise.
192
193   const char *_tag_ Set to the name of the element tag that triggered this function call.
194
195   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
196
197   const char *k The contents of the 'k' attribute (or NULL if not defined).
198
199   const char *v The contents of the 'v' attribute (or NULL if not defined).
200   ++++++++++++++++++++++++++++++++++++++*/
201
202 static int tagType_function(const char *_tag_,int _type_,const char *k,const char *v)
203 {
204  if(_type_&XMLPARSE_TAG_START && current_tags)
205    {
206     XMLPARSE_ASSERT_STRING(_tag_,k);
207     XMLPARSE_ASSERT_STRING(_tag_,v);
208
209     AppendTag(current_tags,k,v);
210    }
211
212  return(0);
213 }
214
215
216 /*++++++++++++++++++++++++++++++++++++++
217   The function that is called when the nodeType XSD type is seen
218
219   int nodeType_function Returns 0 if no error occured or something else otherwise.
220
221   const char *_tag_ Set to the name of the element tag that triggered this function call.
222
223   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
224
225   const char *id The contents of the 'id' attribute (or NULL if not defined).
226
227   const char *lat The contents of the 'lat' attribute (or NULL if not defined).
228
229   const char *lon The contents of the 'lon' attribute (or NULL if not defined).
230   ++++++++++++++++++++++++++++++++++++++*/
231
232 static int nodeType_function(const char *_tag_,int _type_,const char *id,const char *lat,const char *lon)
233 {
234  if(_type_&XMLPARSE_TAG_START)
235    {
236     node_t node_id;
237     double latitude,longitude;
238
239     nnodes++;
240
241     if(!(nnodes%1000))
242       {
243        printf("\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations);
244        fflush(stdout);
245       }
246
247     /* Handle the node information */
248
249     XMLPARSE_ASSERT_STRING(_tag_,id); node_id=atoll(id); /* need long long conversion */
250     XMLPARSE_ASSERT_FLOATING(_tag_,lat,latitude);
251     XMLPARSE_ASSERT_FLOATING(_tag_,lon,longitude);
252
253     AppendNode(nodes,node_id,degrees_to_radians(latitude),degrees_to_radians(longitude));
254
255 //    current_tags=NewTagList();
256     current_tags=NULL;
257    }
258
259 // if(_type_&XMLPARSE_TAG_END)
260 //   {
261 //    TagList *result=ApplyTaggingRules(&NodeRules,current_tags);
262 //
263 //    DeleteTagList(current_tags);
264 //    DeleteTagList(result);
265 //   }
266
267  return(0);
268 }
269
270
271 /*++++++++++++++++++++++++++++++++++++++
272   The function that is called when the ndType XSD type is seen
273
274   int ndType_function Returns 0 if no error occured or something else otherwise.
275
276   const char *_tag_ Set to the name of the element tag that triggered this function call.
277
278   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
279
280   const char *ref The contents of the 'ref' attribute (or NULL if not defined).
281   ++++++++++++++++++++++++++++++++++++++*/
282
283 static int ndType_function(const char *_tag_,int _type_,const char *ref)
284 {
285  if(_type_&XMLPARSE_TAG_START)
286    {
287     node_t node_id;
288
289     XMLPARSE_ASSERT_STRING(_tag_,ref); node_id=atoll(ref); /* need long long conversion */
290
291     if((way_nnodes%256)==0)
292        way_nodes=(node_t*)realloc((void*)way_nodes,(way_nnodes+256)*sizeof(node_t));
293
294     way_nodes[way_nnodes++]=node_id;
295    }
296
297  return(0);
298 }
299
300
301 /*++++++++++++++++++++++++++++++++++++++
302   The function that is called when the memberType XSD type is seen
303
304   int memberType_function Returns 0 if no error occured or something else otherwise.
305
306   const char *_tag_ Set to the name of the element tag that triggered this function call.
307
308   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
309
310   const char *type The contents of the 'type' attribute (or NULL if not defined).
311
312   const char *ref The contents of the 'ref' attribute (or NULL if not defined).
313
314   const char *role The contents of the 'role' attribute (or NULL if not defined).
315   ++++++++++++++++++++++++++++++++++++++*/
316
317 //static int memberType_function(const char *_tag_,int _type_,const char *type,const char *ref,const char *role)
318 //{
319 // return(0);
320 //}
321
322
323 /*++++++++++++++++++++++++++++++++++++++
324   The function that is called when the wayType XSD type is seen
325
326   int wayType_function Returns 0 if no error occured or something else otherwise.
327
328   const char *_tag_ Set to the name of the element tag that triggered this function call.
329
330   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
331
332   const char *id The contents of the 'id' attribute (or NULL if not defined).
333   ++++++++++++++++++++++++++++++++++++++*/
334
335 static int wayType_function(const char *_tag_,int _type_,const char *id)
336 {
337  static way_t way_id;
338
339  if(_type_&XMLPARSE_TAG_START)
340    {
341     nways++;
342
343     if(!(nways%1000))
344       {
345        printf("\rReading: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld",ParseXML_LineNumber(),nnodes,nways,nrelations);
346        fflush(stdout);
347       }
348
349     current_tags=NewTagList();
350     way_nnodes=0;
351
352     /* Handle the way information */
353
354     XMLPARSE_ASSERT_STRING(_tag_,id); way_id=atoll(id); /* need long long conversion */
355    }
356
357  if(_type_&XMLPARSE_TAG_END)
358    {
359     TagList *result=ApplyTaggingRules(&WayRules,current_tags);
360
361     process_way_tags(result,way_id);
362
363     DeleteTagList(current_tags);
364     DeleteTagList(result);
365    }
366
367  return(0);
368 }
369
370
371 /*++++++++++++++++++++++++++++++++++++++
372   The function that is called when the relationType XSD type is seen
373
374   int relationType_function Returns 0 if no error occured or something else otherwise.
375
376   const char *_tag_ Set to the name of the element tag that triggered this function call.
377
378   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
379
380   const char *id The contents of the 'id' attribute (or NULL if not defined).
381   ++++++++++++++++++++++++++++++++++++++*/
382
383 static int relationType_function(const char *_tag_,int _type_,const char *id)
384 {
385  if(_type_&XMLPARSE_TAG_START)
386    {
387     nrelations++;
388
389     if(!(nrelations%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     current_tags=NULL;
397    }
398
399 // if(_type_&XMLPARSE_TAG_END)
400 //   {
401 //    TagList *result=ApplyTaggingRules(&RelationRules,current_tags);
402 //
403 //    DeleteTagList(current_tags);
404 //    DeleteTagList(result);
405 //   }
406
407  return(0);
408 }
409
410
411 /*++++++++++++++++++++++++++++++++++++++
412   The function that is called when the osmType XSD type is seen
413
414   int osmType_function Returns 0 if no error occured or something else otherwise.
415
416   const char *_tag_ Set to the name of the element tag that triggered this function call.
417
418   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
419   ++++++++++++++++++++++++++++++++++++++*/
420
421 //static int osmType_function(const char *_tag_,int _type_)
422 //{
423 // return(0);
424 //}
425
426
427 /*++++++++++++++++++++++++++++++++++++++
428   The function that is called when the XML declaration is seen
429
430   int xmlDeclaration_function Returns 0 if no error occured or something else otherwise.
431
432   const char *_tag_ Set to the name of the element tag that triggered this function call.
433
434   int _type_ Set to XMLPARSE_TAG_START at the start of a tag and/or XMLPARSE_TAG_END at the end of a tag.
435
436   const char *version The contents of the 'version' attribute (or NULL if not defined).
437
438   const char *encoding The contents of the 'encoding' attribute (or NULL if not defined).
439   ++++++++++++++++++++++++++++++++++++++*/
440
441 //static int xmlDeclaration_function(const char *_tag_,int _type_,const char *version,const char *encoding)
442 //{
443 // return(0);
444 //}
445
446
447 /*++++++++++++++++++++++++++++++++++++++
448   Parse an OSM XML file (from JOSM or planet download).
449
450   int ParseOSM Returns 0 if OK or something else in case of an error.
451
452   FILE *file The file to read from.
453
454   NodesX *OSMNodes The array of nodes to fill in.
455
456   SegmentsX *OSMSegments The array of segments to fill in.
457
458   WaysX *OSMWays The arrray of ways to fill in.
459   ++++++++++++++++++++++++++++++++++++++*/
460
461 int ParseOSM(FILE *file,NodesX *OSMNodes,SegmentsX *OSMSegments,WaysX *OSMWays)
462 {
463  int retval;
464
465  /* Parse the file */
466
467  nodes=OSMNodes;
468  segments=OSMSegments;
469  ways=OSMWays;
470
471  nnodes=0,nways=0,nrelations=0;
472
473  printf("\rReading: Lines=0 Nodes=0 Ways=0 Relations=0");
474  fflush(stdout);
475
476  retval=ParseXML(file,xml_toplevel_tags,XMLPARSE_UNKNOWN_ATTR_IGNORE);
477
478  printf("\rRead: Lines=%ld Nodes=%ld Ways=%ld Relations=%ld   \n",ParseXML_LineNumber(),nnodes,nways,nrelations);
479  fflush(stdout);
480
481  return(retval);
482 }
483
484
485 /*++++++++++++++++++++++++++++++++++++++
486   Process the tags associated with a way.
487
488   TagList *tags The list of way tags.
489
490   way_t id The id of the way.
491   ++++++++++++++++++++++++++++++++++++++*/
492
493 static void process_way_tags(TagList *tags,way_t id)
494 {
495  Way   way={0};
496  int   oneway=0,roundabout=0;
497  char *name=NULL,*ref=NULL;
498
499  int i;
500
501  /* Parse the tags */
502
503  for(i=0;i<tags->ntags;i++)
504    {
505     char *k=tags->k[i];
506     char *v=tags->v[i];
507
508     switch(*k)
509       {
510       case 'b':
511        if(!strcmp(k,"bicycle"))
512           if(ISTRUE(v))
513              way.allow|= Allow_Bicycle;
514
515        if(!strcmp(k,"bridge"))
516           if(ISTRUE(v))
517              way.props|=Properties_Bridge;
518
519        break;
520
521       case 'f':
522        if(!strcmp(k,"foot"))
523           if(ISTRUE(v))
524              way.allow|= Allow_Foot;
525
526        break;
527
528       case 'g':
529        if(!strcmp(k,"goods"))
530           if(ISTRUE(v))
531              way.allow|=Allow_Goods;
532
533        break;
534
535       case 'h':
536        if(!strcmp(k,"highway"))
537           way.type=HighwayType(v);
538
539        if(!strcmp(k,"horse"))
540           if(ISTRUE(v))
541              way.allow|=Allow_Horse;
542
543        if(!strcmp(k,"hgv"))
544           if(ISTRUE(v))
545              way.allow|=Allow_HGV;
546
547        break;
548
549       case 'j':
550        if(!strcmp(k,"junction") && !strcmp(v,"roundabout"))
551           roundabout=1;
552
553        break;
554
555       case 'm':
556        if(!strcmp(k,"maxspeed"))
557          {
558           if(strstr(v,"mph"))
559              way.speed=kph_to_speed(1.609*atof(v));
560           else
561              way.speed=kph_to_speed(atof(v));
562          }
563
564        if(!strcmp(k,"maxweight"))
565          {
566           if(strstr(v,"kg"))
567              way.weight=tonnes_to_weight(atof(v)/1000);
568           else
569              way.weight=tonnes_to_weight(atof(v));
570          }
571
572        if(!strcmp(k,"maxheight"))
573          {
574           if(strchr(v,'\''))
575             {
576              int feet,inches;
577
578              if(sscanf(v,"%d'%d\"",&feet,&inches)==2)
579                 way.height=metres_to_height((feet+(double)inches/12.0)*0.254);
580              else if(sscanf(v,"%d'",&feet)==1)
581                 way.height=metres_to_height((feet+(double)inches/12.0)*0.254);
582             }
583           else if(strstr(v,"ft") || strstr(v,"feet"))
584              way.height=metres_to_height(atof(v)*0.254);
585           else
586              way.height=metres_to_height(atof(v));
587          }
588
589        if(!strcmp(k,"maxwidth"))
590          {
591           if(strchr(v,'\''))
592             {
593              int feet,inches;
594
595              if(sscanf(v,"%d'%d\"",&feet,&inches)==2)
596                 way.width=metres_to_height((feet+(double)inches/12.0)*0.254);
597              else if(sscanf(v,"%d'",&feet)==1)
598                 way.width=metres_to_height((feet+(double)inches/12.0)*0.254);
599             }
600           else if(strstr(v,"ft") || strstr(v,"feet"))
601              way.width=metres_to_width(atof(v)*0.254);
602           else
603              way.width=metres_to_width(atof(v));
604          }
605
606        if(!strcmp(k,"maxlength"))
607          {
608           if(strchr(v,'\''))
609             {
610              int feet,inches;
611
612              if(sscanf(v,"%d'%d\"",&feet,&inches)==2)
613                 way.length=metres_to_height((feet+(double)inches/12.0)*0.254);
614              else if(sscanf(v,"%d'",&feet)==1)
615                 way.length=metres_to_height((feet+(double)inches/12.0)*0.254);
616             }
617           else if(strstr(v,"ft") || strstr(v,"feet"))
618              way.length=metres_to_length(atof(v)*0.254);
619           else
620              way.length=metres_to_length(atof(v));
621          }
622
623        if(!strcmp(k,"moped"))
624           if(ISTRUE(v))
625              way.allow|=Allow_Moped;
626
627        if(!strcmp(k,"motorbike"))
628           if(ISTRUE(v))
629              way.allow|=Allow_Motorbike;
630
631        if(!strcmp(k,"motorcar"))
632           if(ISTRUE(v))
633              way.allow|=Allow_Motorcar;
634
635        if(!strcmp(k,"multilane"))
636           if(ISTRUE(v))
637              way.props|=Properties_Multilane;
638
639        break;
640
641       case 'n':
642        if(!strcmp(k,"name"))
643           name=v;
644
645        break;
646
647       case 'o':
648        if(!strcmp(k,"oneway"))
649          {
650           if(ISTRUE(v))
651              oneway=1;
652           else if(!strcmp(v,"-1"))
653              oneway=-1;
654          }
655
656        break;
657
658       case 'p':
659        if(!strcmp(k,"paved"))
660           if(ISTRUE(v))
661              way.props|=Properties_Paved;
662
663        if(!strcmp(k,"psv"))
664           if(ISTRUE(v))
665              way.allow|=Allow_PSV;
666
667        break;
668
669       case 'r':
670        if(!strcmp(k,"ref"))
671           ref=v;
672
673        break;
674
675       case 't':
676        if(!strcmp(k,"tunnel"))
677           if(ISTRUE(v))
678              way.props|=Properties_Tunnel;
679
680        break;
681
682       case 'w':
683        if(!strcmp(k,"wheelchair"))
684           if(ISTRUE(v))
685              way.allow|=Allow_Wheelchair;
686
687        break;
688
689       default:
690        ;
691       }
692    }
693
694  /* Create the way */
695
696  if(way.type>0 && way.type<Way_Count)
697    {
698     if(way.allow)
699       {
700        char *refname;
701
702        if(oneway)
703           way.type|=Way_OneWay;
704
705        if(roundabout)
706           way.type|=Way_Roundabout;
707
708        if(ref && name)
709          {
710           refname=(char*)malloc(strlen(ref)+strlen(name)+4);
711           sprintf(refname,"%s (%s)",name,ref);
712          }
713        else if(ref && !name)
714           refname=ref;
715        else if(!ref && name)
716           refname=name;
717        else /* if(!ref && !name) */
718           refname="";
719
720        AppendWay(ways,id,&way,refname);
721
722        if(ref && name)
723           free(refname);
724
725        for(i=1;i<way_nnodes;i++)
726          {
727           node_t from=way_nodes[i-1];
728           node_t to  =way_nodes[i];
729
730           if(oneway>0)
731             {
732              AppendSegment(segments,id,from,to,ONEWAY_1TO2);
733              AppendSegment(segments,id,to,from,ONEWAY_2TO1);
734             }
735           else if(oneway<0)
736             {
737              AppendSegment(segments,id,from,to,ONEWAY_2TO1);
738              AppendSegment(segments,id,to,from,ONEWAY_1TO2);
739             }
740           else
741             {
742              AppendSegment(segments,id,from,to,0);
743              AppendSegment(segments,id,to,from,0);
744             }
745          }
746       }
747    }
748 }