Imported Upstream version 1.5
[routino] / src / planetsplitter.c
1 /***************************************
2  $Header: /home/amb/routino/src/RCS/planetsplitter.c,v 1.81 2010/09/17 18:38:39 amb Exp $
3
4  OSM planet file splitter.
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 <errno.h>
29
30 #include "types.h"
31 #include "ways.h"
32
33 #include "typesx.h"
34 #include "nodesx.h"
35 #include "segmentsx.h"
36 #include "waysx.h"
37 #include "relationsx.h"
38 #include "superx.h"
39
40 #include "files.h"
41 #include "functions.h"
42 #include "functionsx.h"
43 #include "tagging.h"
44
45
46 /* Global variables */
47
48 /*+ The name of the temporary directory. +*/
49 char *option_tmpdirname=NULL;
50
51 /*+ The amount of RAM to use for filesorting. +*/
52 size_t option_filesort_ramsize=0;
53
54
55 /* Local functions */
56
57 static void print_usage(int detail,const char *argerr,const char *err);
58
59
60 /*++++++++++++++++++++++++++++++++++++++
61   The main program for the planetsplitter.
62   ++++++++++++++++++++++++++++++++++++++*/
63
64 int main(int argc,char** argv)
65 {
66  NodesX     *Nodes;
67  SegmentsX  *Segments,*SuperSegments=NULL,*MergedSegments=NULL;
68  WaysX      *Ways;
69  RelationsX *Relations;
70  int         iteration=0,quit=0;
71  int         max_iterations=10;
72  char       *dirname=NULL,*prefix=NULL,*tagging=NULL;
73  int         option_parse_only=0,option_process_only=0;
74  int         option_filenames=0;
75  int         arg;
76
77  /* Parse the command line arguments */
78
79  for(arg=1;arg<argc;arg++)
80    {
81     if(!strcmp(argv[arg],"--help"))
82        print_usage(1,NULL,NULL);
83     else if(!strncmp(argv[arg],"--sort-ram-size=",16))
84        option_filesort_ramsize=atoi(&argv[arg][16]);
85     else if(!strncmp(argv[arg],"--dir=",6))
86        dirname=&argv[arg][6];
87     else if(!strncmp(argv[arg],"--tmpdir=",9))
88        option_tmpdirname=&argv[arg][9];
89     else if(!strncmp(argv[arg],"--prefix=",9))
90        prefix=&argv[arg][9];
91     else if(!strcmp(argv[arg],"--parse-only"))
92        option_parse_only=1;
93     else if(!strcmp(argv[arg],"--process-only"))
94        option_process_only=1;
95     else if(!strncmp(argv[arg],"--max-iterations=",17))
96        max_iterations=atoi(&argv[arg][17]);
97     else if(!strncmp(argv[arg],"--tagging=",10))
98        tagging=&argv[arg][10];
99     else if(argv[arg][0]=='-' && argv[arg][1]=='-')
100        print_usage(0,argv[arg],NULL);
101     else
102        option_filenames++;
103    }
104
105  /* Check the specified command line options */
106
107  if(option_parse_only && option_process_only)
108     print_usage(0,NULL,"Cannot use '--parse-only' and '--process-only' at the same time.");
109
110  if(option_filenames && option_process_only)
111     print_usage(0,NULL,"Cannot use '--process-only' and filenames at the same time.");
112
113  if(!option_filesort_ramsize)
114    {
115 #if SLIM
116        option_filesort_ramsize=64*1024*1024;
117 #else
118        option_filesort_ramsize=256*1024*1024;
119 #endif
120    }
121  else
122     option_filesort_ramsize*=1024*1024;
123
124  if(!option_tmpdirname)
125    {
126     if(!dirname)
127        option_tmpdirname=".";
128     else
129        option_tmpdirname=dirname;
130    }
131
132  if(tagging)
133    {
134     if(!ExistsFile(tagging))
135       {
136        fprintf(stderr,"Error: The '--tagging' option specifies a file that does not exist.\n");
137        return(1);
138       }
139    }
140  else
141    {
142     if(ExistsFile(FileName(dirname,prefix,"tagging.xml")))
143        tagging=FileName(dirname,prefix,"tagging.xml");
144     else if(ExistsFile(FileName(DATADIR,NULL,"tagging.xml")))
145        tagging=FileName(DATADIR,NULL,"tagging.xml");
146     else
147       {
148        fprintf(stderr,"Error: The '--tagging' option was not used and the default 'tagging.xml' does not exist.\n");
149        return(1);
150       }
151    }
152
153  if(ParseXMLTaggingRules(tagging))
154    {
155     fprintf(stderr,"Error: Cannot read the tagging rules in the file '%s'.\n",tagging);
156     return(1);
157    }
158
159  /* Create new node, segment, way and relation variables */
160
161  Nodes=NewNodeList(option_parse_only||option_process_only);
162
163  Segments=NewSegmentList(option_parse_only||option_process_only);
164
165  Ways=NewWayList(option_parse_only||option_process_only);
166
167  Relations=NewRelationList(option_parse_only||option_process_only);
168
169  /* Parse the file */
170
171  if(option_filenames)
172    {
173     for(arg=1;arg<argc;arg++)
174       {
175        FILE *file;
176
177        if(argv[arg][0]=='-' && argv[arg][1]=='-')
178           continue;
179
180        file=fopen(argv[arg],"rb");
181
182        if(!file)
183          {
184           fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",argv[arg],strerror(errno));
185           exit(EXIT_FAILURE);
186          }
187
188        printf("\nParse OSM Data [%s]\n==============\n\n",argv[arg]);
189        fflush(stdout);
190
191        if(ParseOSM(file,Nodes,Segments,Ways,Relations))
192           exit(EXIT_FAILURE);
193
194        fclose(file);
195       }
196    }
197  else if(!option_process_only)
198    {
199     printf("\nParse OSM Data\n==============\n\n");
200     fflush(stdout);
201
202     if(ParseOSM(stdin,Nodes,Segments,Ways,Relations))
203        exit(EXIT_FAILURE);
204    }
205
206  if(option_parse_only)
207    {
208     FreeNodeList(Nodes,1);
209     FreeSegmentList(Segments,1);
210     FreeWayList(Ways,1);
211     FreeRelationList(Relations,1);
212
213     return(0);
214    }
215
216  /* Process the data */
217
218  printf("\nProcess OSM Data\n================\n\n");
219  fflush(stdout);
220
221  /* Sort the nodes, segments, ways and relations */
222
223  SortNodeList(Nodes);
224
225  SortSegmentList(Segments);
226
227  SortWayList(Ways);
228
229  SortRelationList(Relations);
230
231  /* Process the route relations (must be before compacting the ways) */
232
233  ProcessRouteRelations(Relations,Ways);
234
235  FreeRelationList(Relations,0);
236
237  /* Compact the ways (must be before measuring the segments) */
238
239  CompactWayList(Ways);
240
241  /* Remove bad segments (must be after sorting the nodes and segments) */
242
243  RemoveBadSegments(Nodes,Segments);
244
245  /* Remove non-highway nodes (must be after removing the bad segments) */
246
247  RemoveNonHighwayNodes(Nodes,Segments);
248
249  /* Measure the segments and replace node/way id with index (must be after removing non-highway nodes) */
250
251  UpdateSegments(Segments,Nodes,Ways);
252
253
254  /* Repeated iteration on Super-Nodes and Super-Segments */
255
256  do
257    {
258     printf("\nProcess Super-Data (iteration %d)\n================================%s\n\n",iteration,iteration>9?"=":"");
259     fflush(stdout);
260
261     if(iteration==0)
262       {
263        /* Select the super-nodes */
264
265        ChooseSuperNodes(Nodes,Segments,Ways);
266
267        /* Select the super-segments */
268
269        SuperSegments=CreateSuperSegments(Nodes,Segments,Ways,iteration);
270       }
271     else
272       {
273        SegmentsX *SuperSegments2;
274
275        /* Select the super-nodes */
276
277        ChooseSuperNodes(Nodes,SuperSegments,Ways);
278
279        /* Select the super-segments */
280
281        SuperSegments2=CreateSuperSegments(Nodes,SuperSegments,Ways,iteration);
282
283        if(SuperSegments->xnumber==SuperSegments2->xnumber)
284           quit=1;
285
286        FreeSegmentList(SuperSegments,0);
287
288        SuperSegments=SuperSegments2;
289       }
290
291     /* Sort the super-segments */
292
293     SortSegmentList(SuperSegments);
294
295     /* Remove duplicated super-segments */
296
297     DeduplicateSegments(SuperSegments,Nodes,Ways);
298
299     iteration++;
300
301     if(iteration>max_iterations)
302        quit=1;
303    }
304  while(!quit);
305
306  /* Combine the super-segments */
307
308  printf("\nCombine Segments and Super-Segments\n===================================\n\n");
309  fflush(stdout);
310
311  /* Merge the super-segments */
312
313  MergedSegments=MergeSuperSegments(Segments,SuperSegments);
314
315  FreeSegmentList(Segments,0);
316
317  FreeSegmentList(SuperSegments,0);
318
319  Segments=MergedSegments;
320
321  /* Rotate segments so that node1<node2 */
322
323  RotateSegments(Segments);
324
325  /* Sort the segments */
326
327  SortSegmentList(Segments);
328
329  /* Remove duplicated segments */
330
331  DeduplicateSegments(Segments,Nodes,Ways);
332
333  /* Cross reference the nodes and segments */
334
335  printf("\nCross-Reference Nodes and Segments\n==================================\n\n");
336  fflush(stdout);
337
338  /* Sort the node list geographically */
339
340  SortNodeListGeographically(Nodes);
341
342  /* Create the real segments and nodes */
343
344  CreateRealNodes(Nodes,iteration);
345
346  CreateRealSegments(Segments,Ways);
347
348  /* Fix the segment and node indexes */
349
350  IndexNodes(Nodes,Segments);
351
352  IndexSegments(Segments,Nodes);
353
354  /* Output the results */
355
356  printf("\nWrite Out Database Files\n========================\n\n");
357  fflush(stdout);
358
359  /* Write out the nodes */
360
361  SaveNodeList(Nodes,FileName(dirname,prefix,"nodes.mem"));
362
363  FreeNodeList(Nodes,0);
364
365  /* Write out the segments */
366
367  SaveSegmentList(Segments,FileName(dirname,prefix,"segments.mem"));
368
369  FreeSegmentList(Segments,0);
370
371  /* Write out the ways */
372
373  SaveWayList(Ways,FileName(dirname,prefix,"ways.mem"));
374
375  FreeWayList(Ways,0);
376
377  return(0);
378 }
379
380
381 /*++++++++++++++++++++++++++++++++++++++
382   Print out the usage information.
383
384   int detail The level of detail to use - 0 = low, 1 = high.
385
386   const char *argerr The argument that gave the error (if there is one).
387
388   const char *err Other error message (if there is one).
389   ++++++++++++++++++++++++++++++++++++++*/
390
391 static void print_usage(int detail,const char *argerr,const char *err)
392 {
393  fprintf(stderr,
394          "Usage: planetsplitter [--help]\n"
395          "                      [--dir=<dirname>] [--prefix=<name>]\n"
396          "                      [--sort-ram-size=<size>]\n"
397          "                      [--tmpdir=<dirname>]\n"
398          "                      [--parse-only | --process-only]\n"
399          "                      [--max-iterations=<number>]\n"
400          "                      [--tagging=<filename>]\n"
401          "                      [<filename.osm> ...]\n");
402
403  if(argerr)
404     fprintf(stderr,
405             "\n"
406             "Error with command line parameter: %s\n",argerr);
407
408  if(err)
409     fprintf(stderr,
410             "\n"
411             "Error: %s\n",err);
412
413  if(detail)
414     fprintf(stderr,
415             "\n"
416             "--help                    Prints this information.\n"
417             "\n"
418             "--dir=<dirname>           The directory containing the routing database.\n"
419             "--prefix=<name>           The filename prefix for the routing database.\n"
420             "\n"
421             "--sort-ram-size=<size>    The amount of RAM (in MB) to use for data sorting\n"
422 #if SLIM
423             "                          (defaults to 64MB otherwise.)\n"
424 #else
425             "                          (defaults to 256MB otherwise.)\n"
426 #endif
427             "--tmpdir=<dirname>        The directory name for temporary files.\n"
428             "                          (defaults to the '--dir' option directory.)\n"
429             "\n"
430             "--parse-only              Parse the input OSM files and store the results.\n"
431             "--process-only            Process the stored results from previous option.\n"
432             "\n"
433             "--max-iterations=<number> The number of iterations for finding super-nodes.\n"
434             "\n"
435             "--tagging=<filename>      The name of the XML file containing the tagging rules\n"
436             "                          (defaults to 'tagging.xml' with '--dir' and\n"
437             "                           '--prefix' options or the file installed in\n"
438             "                           '" DATADIR "').\n"
439             "\n"
440             "<filename.osm> ...        The name(s) of the file(s) to process (by default\n"
441             "                          data is read from standard input).\n"
442             "\n"
443             "<transport> defaults to all but can be set to:\n"
444             "%s"
445             "\n"
446             "<highway> can be selected from:\n"
447             "%s"
448             "\n"
449             "<property> can be selected from:\n"
450             "%s",
451             TransportList(),HighwayList(),PropertyList());
452
453  exit(!detail);
454 }