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