Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /trunk/src/filedumper.c
Parent Directory
|
Revision Log
Revision 1321 -
(show annotations)
(download)
(as text)
Fri May 17 14:54:56 2013 UTC (11 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 36515 byte(s)
Fri May 17 14:54:56 2013 UTC (11 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 36515 byte(s)
Allow dumping error logs from filedumper.
1 | /*************************************** |
2 | Memory file dumper. |
3 | |
4 | Part of the Routino routing software. |
5 | ******************/ /****************** |
6 | This file Copyright 2008-2013 Andrew M. Bishop |
7 | |
8 | This program is free software: you can redistribute it and/or modify |
9 | it under the terms of the GNU Affero General Public License as published by |
10 | the Free Software Foundation, either version 3 of the License, or |
11 | (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU Affero General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Affero General Public License |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | ***************************************/ |
21 | |
22 | |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | #include <sys/stat.h> |
27 | #include <sys/time.h> |
28 | #include <time.h> |
29 | #include <math.h> |
30 | |
31 | #include "types.h" |
32 | #include "nodes.h" |
33 | #include "segments.h" |
34 | #include "ways.h" |
35 | #include "relations.h" |
36 | #include "errorlog.h" |
37 | |
38 | #include "files.h" |
39 | #include "visualiser.h" |
40 | #include "xmlparse.h" |
41 | |
42 | |
43 | /* Local functions */ |
44 | |
45 | static void print_node(Nodes *nodes,index_t item); |
46 | static void print_segment(Segments *segments,index_t item); |
47 | static void print_way(Ways *ways,index_t item); |
48 | static void print_turn_relation(Relations *relations,index_t item,Segments *segments,Nodes *nodes); |
49 | static void print_errorlog(ErrorLogs *errorlogs,index_t item); |
50 | |
51 | static void print_head_osm(int coordcount,double latmin,double latmax,double lonmin,double lonmax); |
52 | static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations, |
53 | double latmin,double latmax,double lonmin,double lonmax,int option_no_super); |
54 | static void print_node_osm(Nodes *nodes,index_t item); |
55 | static void print_segment_osm(Segments *segments,index_t item,Ways *ways); |
56 | static void print_turn_relation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes); |
57 | static void print_tail_osm(void); |
58 | |
59 | static char *RFC822Date(time_t t); |
60 | |
61 | static void print_usage(int detail,const char *argerr,const char *err); |
62 | |
63 | |
64 | /*++++++++++++++++++++++++++++++++++++++ |
65 | The main program for the file dumper. |
66 | ++++++++++++++++++++++++++++++++++++++*/ |
67 | |
68 | int main(int argc,char** argv) |
69 | { |
70 | Nodes *OSMNodes; |
71 | Segments *OSMSegments; |
72 | Ways *OSMWays; |
73 | Relations*OSMRelations; |
74 | ErrorLogs*OSMErrorLogs=NULL; |
75 | int arg; |
76 | char *dirname=NULL,*prefix=NULL; |
77 | char *nodes_filename,*segments_filename,*ways_filename,*relations_filename,*errorlogs_filename; |
78 | int option_statistics=0; |
79 | int option_visualiser=0,coordcount=0; |
80 | double latmin=0,latmax=0,lonmin=0,lonmax=0; |
81 | char *option_data=NULL; |
82 | int option_dump=0; |
83 | int option_dump_osm=0,option_no_super=0; |
84 | |
85 | /* Parse the command line arguments */ |
86 | |
87 | for(arg=1;arg<argc;arg++) |
88 | { |
89 | if(!strcmp(argv[arg],"--help")) |
90 | print_usage(1,NULL,NULL); |
91 | else if(!strncmp(argv[arg],"--dir=",6)) |
92 | dirname=&argv[arg][6]; |
93 | else if(!strncmp(argv[arg],"--prefix=",9)) |
94 | prefix=&argv[arg][9]; |
95 | else if(!strcmp(argv[arg],"--statistics")) |
96 | option_statistics=1; |
97 | else if(!strcmp(argv[arg],"--visualiser")) |
98 | option_visualiser=1; |
99 | else if(!strcmp(argv[arg],"--dump")) |
100 | option_dump=1; |
101 | else if(!strcmp(argv[arg],"--dump-osm")) |
102 | option_dump_osm=1; |
103 | else if(!strncmp(argv[arg],"--latmin",8) && argv[arg][8]=='=') |
104 | {latmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;} |
105 | else if(!strncmp(argv[arg],"--latmax",8) && argv[arg][8]=='=') |
106 | {latmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;} |
107 | else if(!strncmp(argv[arg],"--lonmin",8) && argv[arg][8]=='=') |
108 | {lonmin=degrees_to_radians(atof(&argv[arg][9]));coordcount++;} |
109 | else if(!strncmp(argv[arg],"--lonmax",8) && argv[arg][8]=='=') |
110 | {lonmax=degrees_to_radians(atof(&argv[arg][9]));coordcount++;} |
111 | else if(!strncmp(argv[arg],"--data",6) && argv[arg][6]=='=') |
112 | option_data=&argv[arg][7]; |
113 | else if(!strcmp(argv[arg],"--no-super")) |
114 | option_no_super=1; |
115 | else if(!strncmp(argv[arg],"--node=",7)) |
116 | ; |
117 | else if(!strncmp(argv[arg],"--segment=",10)) |
118 | ; |
119 | else if(!strncmp(argv[arg],"--way=",6)) |
120 | ; |
121 | else if(!strncmp(argv[arg],"--turn-relation=",16)) |
122 | ; |
123 | else if(!strncmp(argv[arg],"--errorlog=",11)) |
124 | ; |
125 | else |
126 | print_usage(0,argv[arg],NULL); |
127 | } |
128 | |
129 | if((option_statistics + option_visualiser + option_dump + option_dump_osm)!=1) |
130 | print_usage(0,NULL,"Must choose --visualiser, --statistics, --dump or --dump-osm."); |
131 | |
132 | /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */ |
133 | |
134 | OSMNodes=LoadNodeList(nodes_filename=FileName(dirname,prefix,"nodes.mem")); |
135 | |
136 | OSMSegments=LoadSegmentList(segments_filename=FileName(dirname,prefix,"segments.mem")); |
137 | |
138 | OSMWays=LoadWayList(ways_filename=FileName(dirname,prefix,"ways.mem")); |
139 | |
140 | OSMRelations=LoadRelationList(relations_filename=FileName(dirname,prefix,"relations.mem")); |
141 | |
142 | if(ExistsFile(errorlogs_filename=FileName(dirname,prefix,"errorlogs.mem"))) |
143 | OSMErrorLogs=LoadErrorLogs(errorlogs_filename); |
144 | else |
145 | errorlogs_filename=NULL; |
146 | |
147 | /* Write out the visualiser data */ |
148 | |
149 | if(option_visualiser) |
150 | { |
151 | Highway highway; |
152 | Transport transport; |
153 | Property property; |
154 | |
155 | if(coordcount!=4) |
156 | print_usage(0,NULL,"The --visualiser option must have --latmin, --latmax, --lonmin, --lonmax.\n"); |
157 | |
158 | if(!option_data) |
159 | print_usage(0,NULL,"The --visualiser option must have --data.\n"); |
160 | |
161 | if(!strcmp(option_data,"junctions")) |
162 | OutputJunctions(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
163 | else if(!strcmp(option_data,"super")) |
164 | OutputSuper(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
165 | else if(!strcmp(option_data,"oneway")) |
166 | OutputOneway(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
167 | else if(!strncmp(option_data,"highway",7) && option_data[7]=='-' && (highway=HighwayType(option_data+8))!=Highway_None) |
168 | OutputHighway(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,highway); |
169 | else if(!strncmp(option_data,"transport",9) && option_data[9]=='-' && (transport=TransportType(option_data+10))!=Transport_None) |
170 | OutputTransport(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,transport); |
171 | else if(!strncmp(option_data,"barrier",7) && option_data[7]=='-' && (transport=TransportType(option_data+8))!=Transport_None) |
172 | OutputBarrier(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,transport); |
173 | else if(!strcmp(option_data,"turns")) |
174 | OutputTurnRestrictions(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
175 | else if(!strcmp(option_data,"speed")) |
176 | OutputSpeedLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
177 | else if(!strcmp(option_data,"weight")) |
178 | OutputWeightLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
179 | else if(!strcmp(option_data,"height")) |
180 | OutputHeightLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
181 | else if(!strcmp(option_data,"width")) |
182 | OutputWidthLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
183 | else if(!strcmp(option_data,"length")) |
184 | OutputLengthLimits(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax); |
185 | else if(!strncmp(option_data,"property",8) && option_data[8]=='-' && (property=PropertyType(option_data+9))!=Property_None) |
186 | OutputProperty(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,property); |
187 | else if(!strcmp(option_data,"errorlogs")) |
188 | OutputErrorLog(OSMErrorLogs,latmin,latmax,lonmin,lonmax); |
189 | else |
190 | print_usage(0,option_data,NULL); |
191 | } |
192 | |
193 | /* Print out statistics */ |
194 | |
195 | if(option_statistics) |
196 | { |
197 | struct stat buf; |
198 | |
199 | /* Examine the files */ |
200 | |
201 | printf("Files\n"); |
202 | printf("-----\n"); |
203 | printf("\n"); |
204 | |
205 | stat(nodes_filename,&buf); |
206 | |
207 | printf("'%s%snodes.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size); |
208 | printf("%s\n",RFC822Date(buf.st_mtime)); |
209 | printf("\n"); |
210 | |
211 | stat(segments_filename,&buf); |
212 | |
213 | printf("'%s%ssegments.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size); |
214 | printf("%s\n",RFC822Date(buf.st_mtime)); |
215 | printf("\n"); |
216 | |
217 | stat(ways_filename,&buf); |
218 | |
219 | printf("'%s%sways.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size); |
220 | printf("%s\n",RFC822Date(buf.st_mtime)); |
221 | printf("\n"); |
222 | |
223 | stat(relations_filename,&buf); |
224 | |
225 | printf("'%s%srelations.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size); |
226 | printf("%s\n",RFC822Date(buf.st_mtime)); |
227 | printf("\n"); |
228 | |
229 | if(errorlogs_filename) |
230 | { |
231 | stat(errorlogs_filename,&buf); |
232 | |
233 | printf("'%s%serrorlogs.mem' - %9"PRIu64" Bytes\n",prefix?prefix:"",prefix?"-":"",(uint64_t)buf.st_size); |
234 | printf("%s\n",RFC822Date(buf.st_mtime)); |
235 | printf("\n"); |
236 | } |
237 | |
238 | /* Examine the nodes */ |
239 | |
240 | printf("Nodes\n"); |
241 | printf("-----\n"); |
242 | printf("\n"); |
243 | |
244 | printf("sizeof(Node) =%9lu Bytes\n",(unsigned long)sizeof(Node)); |
245 | printf("Number =%9"Pindex_t"\n",OSMNodes->file.number); |
246 | printf("Number(super)=%9"Pindex_t"\n",OSMNodes->file.snumber); |
247 | printf("\n"); |
248 | |
249 | printf("Lat bins= %4d\n",(int)OSMNodes->file.latbins); |
250 | printf("Lon bins= %4d\n",(int)OSMNodes->file.lonbins); |
251 | printf("\n"); |
252 | |
253 | printf("Lat zero=%5d (%8.4f deg)\n",(int)OSMNodes->file.latzero,radians_to_degrees(latlong_to_radians(bin_to_latlong(OSMNodes->file.latzero)))); |
254 | printf("Lon zero=%5d (%8.4f deg)\n",(int)OSMNodes->file.lonzero,radians_to_degrees(latlong_to_radians(bin_to_latlong(OSMNodes->file.lonzero)))); |
255 | |
256 | /* Examine the segments */ |
257 | |
258 | printf("\n"); |
259 | printf("Segments\n"); |
260 | printf("--------\n"); |
261 | printf("\n"); |
262 | |
263 | printf("sizeof(Segment)=%9lu Bytes\n",(unsigned long)sizeof(Segment)); |
264 | printf("Number(total) =%9"Pindex_t"\n",OSMSegments->file.number); |
265 | printf("Number(super) =%9"Pindex_t"\n",OSMSegments->file.snumber); |
266 | printf("Number(normal) =%9"Pindex_t"\n",OSMSegments->file.nnumber); |
267 | |
268 | /* Examine the ways */ |
269 | |
270 | printf("\n"); |
271 | printf("Ways\n"); |
272 | printf("----\n"); |
273 | printf("\n"); |
274 | |
275 | printf("sizeof(Way)=%9lu Bytes\n",(unsigned long)sizeof(Way)); |
276 | printf("Number =%9"Pindex_t"\n",OSMWays->file.number); |
277 | printf("\n"); |
278 | |
279 | stat(ways_filename,&buf); |
280 | printf("Total names=%9lu Bytes\n",(unsigned long)buf.st_size-(unsigned long)sizeof(Ways)-(unsigned long)OSMWays->file.number*(unsigned long)sizeof(Way)); |
281 | printf("\n"); |
282 | |
283 | printf("Included highways : %s\n",HighwaysNameList(OSMWays->file.highways)); |
284 | printf("Included transports: %s\n",AllowedNameList(OSMWays->file.allow)); |
285 | printf("Included properties: %s\n",PropertiesNameList(OSMWays->file.props)); |
286 | |
287 | /* Examine the relations */ |
288 | |
289 | printf("\n"); |
290 | printf("Relations\n"); |
291 | printf("---------\n"); |
292 | printf("\n"); |
293 | |
294 | printf("sizeof(TurnRelation)=%9lu Bytes\n",(unsigned long)sizeof(TurnRelation)); |
295 | printf("Number =%9"Pindex_t"\n",OSMRelations->file.trnumber); |
296 | |
297 | if(errorlogs_filename) |
298 | { |
299 | printf("\n"); |
300 | printf("Error Logs\n"); |
301 | printf("----------\n"); |
302 | printf("\n"); |
303 | |
304 | printf("Number(total) =%9"Pindex_t"\n",OSMErrorLogs->file.number); |
305 | printf("Number(geographical) =%9"Pindex_t"\n",OSMErrorLogs->file.number_geo); |
306 | printf("Number(non-geographical)=%9"Pindex_t"\n",OSMErrorLogs->file.number_nongeo); |
307 | |
308 | printf("\n"); |
309 | stat(errorlogs_filename,&buf); |
310 | #if !SLIM |
311 | printf("Total strings=%9lu Bytes\n",(unsigned long)buf.st_size-(unsigned long)(OSMErrorLogs->strings-(char*)OSMErrorLogs->data)); |
312 | #else |
313 | printf("Total strings=%9lu Bytes\n",(unsigned long)buf.st_size-(unsigned long)OSMErrorLogs->stringsoffset); |
314 | #endif |
315 | } |
316 | } |
317 | |
318 | /* Print out internal data (in plain text format) */ |
319 | |
320 | if(option_dump) |
321 | { |
322 | index_t item; |
323 | |
324 | for(arg=1;arg<argc;arg++) |
325 | if(!strcmp(argv[arg],"--node=all")) |
326 | { |
327 | for(item=0;item<OSMNodes->file.number;item++) |
328 | print_node(OSMNodes,item); |
329 | } |
330 | else if(!strncmp(argv[arg],"--node=",7)) |
331 | { |
332 | item=atoi(&argv[arg][7]); |
333 | |
334 | if(item<OSMNodes->file.number) |
335 | print_node(OSMNodes,item); |
336 | else |
337 | printf("Invalid node number; minimum=0, maximum=%"Pindex_t".\n",OSMNodes->file.number-1); |
338 | } |
339 | else if(!strcmp(argv[arg],"--segment=all")) |
340 | { |
341 | for(item=0;item<OSMSegments->file.number;item++) |
342 | print_segment(OSMSegments,item); |
343 | } |
344 | else if(!strncmp(argv[arg],"--segment=",10)) |
345 | { |
346 | item=atoi(&argv[arg][10]); |
347 | |
348 | if(item<OSMSegments->file.number) |
349 | print_segment(OSMSegments,item); |
350 | else |
351 | printf("Invalid segment number; minimum=0, maximum=%"Pindex_t".\n",OSMSegments->file.number-1); |
352 | } |
353 | else if(!strcmp(argv[arg],"--way=all")) |
354 | { |
355 | for(item=0;item<OSMWays->file.number;item++) |
356 | print_way(OSMWays,item); |
357 | } |
358 | else if(!strncmp(argv[arg],"--way=",6)) |
359 | { |
360 | item=atoi(&argv[arg][6]); |
361 | |
362 | if(item<OSMWays->file.number) |
363 | print_way(OSMWays,item); |
364 | else |
365 | printf("Invalid way number; minimum=0, maximum=%"Pindex_t".\n",OSMWays->file.number-1); |
366 | } |
367 | else if(!strcmp(argv[arg],"--turn-relation=all")) |
368 | { |
369 | for(item=0;item<OSMRelations->file.trnumber;item++) |
370 | print_turn_relation(OSMRelations,item,OSMSegments,OSMNodes); |
371 | } |
372 | else if(!strncmp(argv[arg],"--turn-relation=",16)) |
373 | { |
374 | item=atoi(&argv[arg][16]); |
375 | |
376 | if(item<OSMRelations->file.trnumber) |
377 | print_turn_relation(OSMRelations,item,OSMSegments,OSMNodes); |
378 | else |
379 | printf("Invalid turn relation number; minimum=0, maximum=%"Pindex_t".\n",OSMRelations->file.trnumber-1); |
380 | } |
381 | else if(!strcmp(argv[arg],"--errorlog=all")) |
382 | { |
383 | for(item=0;item<OSMErrorLogs->file.number;item++) |
384 | print_errorlog(OSMErrorLogs,item); |
385 | } |
386 | else if(!strncmp(argv[arg],"--errorlog=",11)) |
387 | { |
388 | item=atoi(&argv[arg][11]); |
389 | |
390 | if(item<OSMErrorLogs->file.number) |
391 | print_errorlog(OSMErrorLogs,item); |
392 | else |
393 | printf("Invalid error log number; minimum=0, maximum=%"Pindex_t".\n",OSMErrorLogs->file.number-1); |
394 | } |
395 | } |
396 | |
397 | /* Print out internal data (in OSM XML format) */ |
398 | |
399 | if(option_dump_osm) |
400 | { |
401 | if(coordcount>0 && coordcount!=4) |
402 | print_usage(0,NULL,"The --dump-osm option must have all of --latmin, --latmax, --lonmin, --lonmax or none.\n"); |
403 | |
404 | print_head_osm(coordcount,latmin,latmax,lonmin,lonmax); |
405 | |
406 | if(coordcount) |
407 | print_region_osm(OSMNodes,OSMSegments,OSMWays,OSMRelations,latmin,latmax,lonmin,lonmax,option_no_super); |
408 | else |
409 | { |
410 | index_t item; |
411 | |
412 | for(item=0;item<OSMNodes->file.number;item++) |
413 | print_node_osm(OSMNodes,item); |
414 | |
415 | for(item=0;item<OSMSegments->file.number;item++) |
416 | if(!option_no_super || IsNormalSegment(LookupSegment(OSMSegments,item,1))) |
417 | print_segment_osm(OSMSegments,item,OSMWays); |
418 | |
419 | for(item=0;item<OSMRelations->file.trnumber;item++) |
420 | print_turn_relation_osm(OSMRelations,item,OSMSegments,OSMNodes); |
421 | } |
422 | |
423 | print_tail_osm(); |
424 | } |
425 | |
426 | return(0); |
427 | } |
428 | |
429 | |
430 | /*++++++++++++++++++++++++++++++++++++++ |
431 | Print out the contents of a node from the routing database (as plain text). |
432 | |
433 | Nodes *nodes The set of nodes to use. |
434 | |
435 | index_t item The node index to print. |
436 | ++++++++++++++++++++++++++++++++++++++*/ |
437 | |
438 | static void print_node(Nodes *nodes,index_t item) |
439 | { |
440 | Node *nodep=LookupNode(nodes,item,1); |
441 | double latitude,longitude; |
442 | |
443 | GetLatLong(nodes,item,nodep,&latitude,&longitude); |
444 | |
445 | printf("Node %"Pindex_t"\n",item); |
446 | printf(" firstseg=%"Pindex_t"\n",nodep->firstseg); |
447 | printf(" latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",nodep->latoffset,nodep->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude)); |
448 | printf(" allow=%02x (%s)\n",nodep->allow,AllowedNameList(nodep->allow)); |
449 | if(IsSuperNode(nodep)) |
450 | printf(" Super-Node\n"); |
451 | if(nodep->flags & NODE_MINIRNDBT) |
452 | printf(" Mini-roundabout\n"); |
453 | } |
454 | |
455 | |
456 | /*++++++++++++++++++++++++++++++++++++++ |
457 | Print out the contents of a segment from the routing database (as plain text). |
458 | |
459 | Segments *segments The set of segments to use. |
460 | |
461 | index_t item The segment index to print. |
462 | ++++++++++++++++++++++++++++++++++++++*/ |
463 | |
464 | static void print_segment(Segments *segments,index_t item) |
465 | { |
466 | Segment *segmentp=LookupSegment(segments,item,1); |
467 | |
468 | printf("Segment %"Pindex_t"\n",item); |
469 | printf(" node1=%"Pindex_t" node2=%"Pindex_t"\n",segmentp->node1,segmentp->node2); |
470 | printf(" next2=%"Pindex_t"\n",segmentp->next2); |
471 | printf(" way=%"Pindex_t"\n",segmentp->way); |
472 | printf(" distance=%d (%.3f km)\n",DISTANCE(segmentp->distance),distance_to_km(DISTANCE(segmentp->distance))); |
473 | if(IsSuperSegment(segmentp) && IsNormalSegment(segmentp)) |
474 | printf(" Super-Segment AND normal Segment\n"); |
475 | else if(IsSuperSegment(segmentp) && !IsNormalSegment(segmentp)) |
476 | printf(" Super-Segment\n"); |
477 | if(IsOnewayTo(segmentp,segmentp->node1)) |
478 | printf(" One-Way from node2 to node1\n"); |
479 | if(IsOnewayTo(segmentp,segmentp->node2)) |
480 | printf(" One-Way from node1 to node2\n"); |
481 | } |
482 | |
483 | |
484 | /*++++++++++++++++++++++++++++++++++++++ |
485 | Print out the contents of a way from the routing database (as plain text). |
486 | |
487 | Ways *ways The set of ways to use. |
488 | |
489 | index_t item The way index to print. |
490 | ++++++++++++++++++++++++++++++++++++++*/ |
491 | |
492 | static void print_way(Ways *ways,index_t item) |
493 | { |
494 | Way *wayp=LookupWay(ways,item,1); |
495 | char *name=WayName(ways,wayp); |
496 | |
497 | printf("Way %"Pindex_t"\n",item); |
498 | if(*name) |
499 | printf(" name=%s\n",name); |
500 | printf(" type=%02x (%s%s%s)\n",wayp->type,HighwayName(HIGHWAY(wayp->type)),wayp->type&Highway_OneWay?",One-Way":"",wayp->type&Highway_Roundabout?",Roundabout":""); |
501 | printf(" allow=%02x (%s)\n",wayp->allow,AllowedNameList(wayp->allow)); |
502 | if(wayp->props) |
503 | printf(" props=%02x (%s)\n",wayp->props,PropertiesNameList(wayp->props)); |
504 | if(wayp->speed) |
505 | printf(" speed=%d (%d km/hr)\n",wayp->speed,speed_to_kph(wayp->speed)); |
506 | if(wayp->weight) |
507 | printf(" weight=%d (%.1f tonnes)\n",wayp->weight,weight_to_tonnes(wayp->weight)); |
508 | if(wayp->height) |
509 | printf(" height=%d (%.1f m)\n",wayp->height,height_to_metres(wayp->height)); |
510 | if(wayp->width) |
511 | printf(" width=%d (%.1f m)\n",wayp->width,width_to_metres(wayp->width)); |
512 | if(wayp->length) |
513 | printf(" length=%d (%.1f m)\n",wayp->length,length_to_metres(wayp->length)); |
514 | } |
515 | |
516 | |
517 | /*++++++++++++++++++++++++++++++++++++++ |
518 | Print out the contents of a turn relation from the routing database (as plain text). |
519 | |
520 | Relations *relations The set of relations to use. |
521 | |
522 | index_t item The turn relation index to print. |
523 | |
524 | Segments *segments The set of segments to use. |
525 | |
526 | Nodes *nodes The set of nodes to use. |
527 | ++++++++++++++++++++++++++++++++++++++*/ |
528 | |
529 | static void print_turn_relation(Relations *relations,index_t item,Segments *segments,Nodes *nodes) |
530 | { |
531 | Segment *segmentp; |
532 | TurnRelation *relationp=LookupTurnRelation(relations,item,1); |
533 | Node *nodep=LookupNode(nodes,relationp->via,1); |
534 | index_t from_way=NO_WAY,to_way=NO_WAY; |
535 | index_t from_node=NO_NODE,to_node=NO_NODE; |
536 | |
537 | segmentp=FirstSegment(segments,nodep,1); |
538 | |
539 | do |
540 | { |
541 | index_t seg=IndexSegment(segments,segmentp); |
542 | |
543 | if(seg==relationp->from) |
544 | { |
545 | from_node=OtherNode(segmentp,relationp->from); |
546 | from_way=segmentp->way; |
547 | } |
548 | |
549 | if(seg==relationp->to) |
550 | { |
551 | to_node=OtherNode(segmentp,relationp->to); |
552 | to_way=segmentp->way; |
553 | } |
554 | |
555 | segmentp=NextSegment(segments,segmentp,relationp->via); |
556 | } |
557 | while(segmentp); |
558 | |
559 | printf("Relation %"Pindex_t"\n",item); |
560 | printf(" from=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relationp->from,from_way,from_node); |
561 | printf(" via=%"Pindex_t" (node)\n",relationp->via); |
562 | printf(" to=%"Pindex_t" (segment) = %"Pindex_t" (way) = %"Pindex_t" (node)\n",relationp->to,to_way,to_node); |
563 | if(relationp->except) |
564 | printf(" except=%02x (%s)\n",relationp->except,AllowedNameList(relationp->except)); |
565 | } |
566 | |
567 | |
568 | /*++++++++++++++++++++++++++++++++++++++ |
569 | Print out the contents of an error log from the routing database (as plain text). |
570 | |
571 | ErrorLogs *errorlogs The set of error logs to use. |
572 | |
573 | index_t item The error log index to print. |
574 | ++++++++++++++++++++++++++++++++++++++*/ |
575 | |
576 | static void print_errorlog(ErrorLogs *errorlogs,index_t item) |
577 | { |
578 | ErrorLog *errorlogp=LookupErrorLog(errorlogs,item,1); |
579 | |
580 | printf("Error Log %"Pindex_t"\n",item); |
581 | |
582 | if(item<errorlogs->file.number_geo) |
583 | { |
584 | double latitude,longitude; |
585 | |
586 | GetErrorLogLatLong(errorlogs,item,errorlogp,&latitude,&longitude); |
587 | |
588 | printf(" latoffset=%d lonoffset=%d (latitude=%.6f longitude=%.6f)\n",errorlogp->latoffset,errorlogp->lonoffset,radians_to_degrees(latitude),radians_to_degrees(longitude)); |
589 | } |
590 | else |
591 | printf(" No geographical information\n"); |
592 | |
593 | printf(" '%s'\n",LookupErrorLogString(errorlogs,item)); |
594 | } |
595 | |
596 | |
597 | /*++++++++++++++++++++++++++++++++++++++ |
598 | Print out a header in OSM XML format. |
599 | |
600 | int coordcount If true then include a bounding box. |
601 | |
602 | double latmin The minimum latitude. |
603 | |
604 | double latmax The maximum latitude. |
605 | |
606 | double lonmin The minimum longitude. |
607 | |
608 | double lonmax The maximum longitude. |
609 | ++++++++++++++++++++++++++++++++++++++*/ |
610 | |
611 | static void print_head_osm(int coordcount,double latmin,double latmax,double lonmin,double lonmax) |
612 | { |
613 | printf("<?xml version='1.0' encoding='UTF-8'?>\n"); |
614 | printf("<osm version='0.6' generator='Routino'>\n"); |
615 | |
616 | if(coordcount) |
617 | printf(" <bounds minlat='%.6f' maxlat='%.6f' minlon='%.6f' maxlon='%.6f' />\n", |
618 | radians_to_degrees(latmin),radians_to_degrees(latmax),radians_to_degrees(lonmin),radians_to_degrees(lonmax)); |
619 | } |
620 | |
621 | |
622 | /*++++++++++++++++++++++++++++++++++++++ |
623 | Print a region of the database in OSM XML format. |
624 | |
625 | Nodes *nodes The set of nodes to use. |
626 | |
627 | Segments *segments The set of segments to use. |
628 | |
629 | Ways *ways The set of ways to use. |
630 | |
631 | Relations *relations The set of relations to use. |
632 | |
633 | double latmin The minimum latitude. |
634 | |
635 | double latmax The maximum latitude. |
636 | |
637 | double lonmin The minimum longitude. |
638 | |
639 | double lonmax The maximum longitude. |
640 | |
641 | int option_no_super The option to print no super-segments. |
642 | ++++++++++++++++++++++++++++++++++++++*/ |
643 | |
644 | static void print_region_osm(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations, |
645 | double latmin,double latmax,double lonmin,double lonmax,int option_no_super) |
646 | { |
647 | ll_bin_t latminbin=latlong_to_bin(radians_to_latlong(latmin))-nodes->file.latzero; |
648 | ll_bin_t latmaxbin=latlong_to_bin(radians_to_latlong(latmax))-nodes->file.latzero; |
649 | ll_bin_t lonminbin=latlong_to_bin(radians_to_latlong(lonmin))-nodes->file.lonzero; |
650 | ll_bin_t lonmaxbin=latlong_to_bin(radians_to_latlong(lonmax))-nodes->file.lonzero; |
651 | ll_bin_t latb,lonb; |
652 | index_t item,index1,index2; |
653 | |
654 | if(latminbin<0) latminbin=0; |
655 | if(latmaxbin>nodes->file.latbins) latmaxbin=nodes->file.latbins-1; |
656 | if(lonminbin<0) lonminbin=0; |
657 | if(lonmaxbin>nodes->file.lonbins) lonmaxbin=nodes->file.lonbins-1; |
658 | |
659 | /* Loop through all of the nodes. */ |
660 | |
661 | for(latb=latminbin;latb<=latmaxbin;latb++) |
662 | for(lonb=lonminbin;lonb<=lonmaxbin;lonb++) |
663 | { |
664 | ll_bin2_t llbin=lonb*nodes->file.latbins+latb; |
665 | |
666 | if(llbin<0 || llbin>(nodes->file.latbins*nodes->file.lonbins)) |
667 | continue; |
668 | |
669 | index1=LookupNodeOffset(nodes,llbin); |
670 | index2=LookupNodeOffset(nodes,llbin+1); |
671 | |
672 | for(item=index1;item<index2;item++) |
673 | { |
674 | Node *nodep=LookupNode(nodes,item,1); |
675 | double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(nodep->latoffset)); |
676 | double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(nodep->lonoffset)); |
677 | |
678 | if(lat>latmin && lat<latmax && lon>lonmin && lon<lonmax) |
679 | { |
680 | Segment *segmentp; |
681 | |
682 | print_node_osm(nodes,item); |
683 | |
684 | segmentp=FirstSegment(segments,nodep,1); |
685 | |
686 | while(segmentp) |
687 | { |
688 | double olat,olon; |
689 | index_t oitem=OtherNode(segmentp,item); |
690 | |
691 | GetLatLong(nodes,oitem,NULL,&olat,&olon); |
692 | |
693 | if(olat>latmin && olat<latmax && olon>lonmin && olon<lonmax) |
694 | if(item>oitem) |
695 | if(!option_no_super || IsNormalSegment(segmentp)) |
696 | print_segment_osm(segments,IndexSegment(segments,segmentp),ways); |
697 | |
698 | segmentp=NextSegment(segments,segmentp,item); |
699 | } |
700 | |
701 | if(IsTurnRestrictedNode(nodep)) |
702 | { |
703 | index_t relindex=FindFirstTurnRelation1(relations,item); |
704 | |
705 | while(relindex!=NO_RELATION) |
706 | { |
707 | print_turn_relation_osm(relations,relindex,segments,nodes); |
708 | |
709 | relindex=FindNextTurnRelation1(relations,relindex); |
710 | } |
711 | } |
712 | } |
713 | } |
714 | } |
715 | } |
716 | |
717 | |
718 | /*++++++++++++++++++++++++++++++++++++++ |
719 | Print out the contents of a node from the routing database (in OSM XML format). |
720 | |
721 | Nodes *nodes The set of nodes to use. |
722 | |
723 | index_t item The node index to print. |
724 | ++++++++++++++++++++++++++++++++++++++*/ |
725 | |
726 | static void print_node_osm(Nodes *nodes,index_t item) |
727 | { |
728 | Node *nodep=LookupNode(nodes,item,1); |
729 | double latitude,longitude; |
730 | int i; |
731 | |
732 | GetLatLong(nodes,item,nodep,&latitude,&longitude); |
733 | |
734 | if(nodep->allow==Transports_ALL && nodep->flags==0) |
735 | printf(" <node id='%lu' lat='%.7f' lon='%.7f' version='1' />\n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude)); |
736 | else |
737 | { |
738 | printf(" <node id='%lu' lat='%.7f' lon='%.7f' version='1'>\n",(unsigned long)item+1,radians_to_degrees(latitude),radians_to_degrees(longitude)); |
739 | |
740 | if(nodep->flags & NODE_SUPER) |
741 | printf(" <tag k='routino:super' v='yes' />\n"); |
742 | |
743 | if(nodep->flags & NODE_UTURN) |
744 | printf(" <tag k='routino:uturn' v='yes' />\n"); |
745 | |
746 | if(nodep->flags & NODE_MINIRNDBT) |
747 | printf(" <tag k='junction' v='roundabout' />\n"); |
748 | |
749 | if(nodep->flags & NODE_TURNRSTRCT) |
750 | printf(" <tag k='routino:turnrestriction' v='yes' />\n"); |
751 | |
752 | for(i=1;i<Transport_Count;i++) |
753 | if(!(nodep->allow & TRANSPORTS(i))) |
754 | printf(" <tag k='%s' v='no' />\n",TransportName(i)); |
755 | |
756 | printf(" </node>\n"); |
757 | } |
758 | } |
759 | |
760 | |
761 | /*++++++++++++++++++++++++++++++++++++++ |
762 | Print out the contents of a segment from the routing database (as a way in OSM XML format). |
763 | |
764 | Segments *segments The set of segments to use. |
765 | |
766 | index_t item The segment index to print. |
767 | |
768 | Ways *ways The set of ways to use. |
769 | ++++++++++++++++++++++++++++++++++++++*/ |
770 | |
771 | static void print_segment_osm(Segments *segments,index_t item,Ways *ways) |
772 | { |
773 | Segment *segmentp=LookupSegment(segments,item,1); |
774 | Way *wayp=LookupWay(ways,segmentp->way,1); |
775 | char *name=WayName(ways,wayp); |
776 | int i; |
777 | |
778 | printf(" <way id='%lu' version='1'>\n",(unsigned long)item+1); |
779 | |
780 | if(IsOnewayTo(segmentp,segmentp->node1)) |
781 | { |
782 | printf(" <nd ref='%lu' />\n",(unsigned long)segmentp->node2+1); |
783 | printf(" <nd ref='%lu' />\n",(unsigned long)segmentp->node1+1); |
784 | } |
785 | else |
786 | { |
787 | printf(" <nd ref='%lu' />\n",(unsigned long)segmentp->node1+1); |
788 | printf(" <nd ref='%lu' />\n",(unsigned long)segmentp->node2+1); |
789 | } |
790 | |
791 | if(IsSuperSegment(segmentp)) |
792 | printf(" <tag k='routino:super' v='yes' />\n"); |
793 | if(IsNormalSegment(segmentp)) |
794 | printf(" <tag k='routino:normal' v='yes' />\n"); |
795 | |
796 | printf(" <tag k='routino:distance' v='%.3f' />\n",distance_to_km(DISTANCE(segmentp->distance))); |
797 | |
798 | if(wayp->type & Highway_OneWay) |
799 | printf(" <tag k='oneway' v='yes' />\n"); |
800 | |
801 | if(wayp->type & Highway_Roundabout) |
802 | printf(" <tag k='roundabout' v='yes' />\n"); |
803 | |
804 | printf(" <tag k='highway' v='%s' />\n",HighwayName(HIGHWAY(wayp->type))); |
805 | |
806 | if(IsNormalSegment(segmentp) && *name) |
807 | printf(" <tag k='name' v='%s' />\n",ParseXML_Encode_Safe_XML(name)); |
808 | |
809 | for(i=1;i<Transport_Count;i++) |
810 | if(wayp->allow & TRANSPORTS(i)) |
811 | printf(" <tag k='%s' v='yes' />\n",TransportName(i)); |
812 | |
813 | for(i=1;i<Property_Count;i++) |
814 | if(wayp->props & PROPERTIES(i)) |
815 | printf(" <tag k='%s' v='yes' />\n",PropertyName(i)); |
816 | |
817 | if(wayp->speed) |
818 | printf(" <tag k='maxspeed' v='%d' />\n",speed_to_kph(wayp->speed)); |
819 | |
820 | if(wayp->weight) |
821 | printf(" <tag k='maxweight' v='%.1f' />\n",weight_to_tonnes(wayp->weight)); |
822 | if(wayp->height) |
823 | printf(" <tag k='maxheight' v='%.1f' />\n",height_to_metres(wayp->height)); |
824 | if(wayp->width) |
825 | printf(" <tag k='maxwidth' v='%.1f' />\n",width_to_metres(wayp->width)); |
826 | if(wayp->length) |
827 | printf(" <tag k='maxlength' v='%.1f' />\n",length_to_metres(wayp->length)); |
828 | |
829 | printf(" </way>\n"); |
830 | } |
831 | |
832 | |
833 | /*++++++++++++++++++++++++++++++++++++++ |
834 | Print out the contents of a turn relation from the routing database (in OSM XML format). |
835 | |
836 | Relations *relations The set of relations to use. |
837 | |
838 | index_t item The relation index to print. |
839 | |
840 | Segments *segments The set of segments to use. |
841 | |
842 | Nodes *nodes The set of nodes to use. |
843 | ++++++++++++++++++++++++++++++++++++++*/ |
844 | |
845 | static void print_turn_relation_osm(Relations *relations,index_t item,Segments *segments,Nodes *nodes) |
846 | { |
847 | TurnRelation *relationp=LookupTurnRelation(relations,item,1); |
848 | |
849 | Segment *segmentp_from=LookupSegment(segments,relationp->from,1); |
850 | Segment *segmentp_to =LookupSegment(segments,relationp->to ,2); |
851 | |
852 | double angle=TurnAngle(nodes,segmentp_from,segmentp_to,relationp->via); |
853 | |
854 | char *restriction; |
855 | |
856 | if(angle>150 || angle<-150) |
857 | restriction="no_u_turn"; |
858 | else if(angle>30) |
859 | restriction="no_right_turn"; |
860 | else if(angle<-30) |
861 | restriction="no_left_turn"; |
862 | else |
863 | restriction="no_straight_on"; |
864 | |
865 | printf(" <relation id='%lu' version='1'>\n",(unsigned long)item+1); |
866 | printf(" <tag k='type' v='restriction' />\n"); |
867 | printf(" <tag k='restriction' v='%s'/>\n",restriction); |
868 | |
869 | if(relationp->except) |
870 | printf(" <tag k='except' v='%s' />\n",AllowedNameList(relationp->except)); |
871 | |
872 | printf(" <member type='way' ref='%lu' role='from' />\n",(unsigned long)relationp->from+1); |
873 | printf(" <member type='node' ref='%lu' role='via' />\n",(unsigned long)relationp->via+1); |
874 | printf(" <member type='way' ref='%lu' role='to' />\n",(unsigned long)relationp->to+1); |
875 | |
876 | printf(" </relation>\n"); |
877 | } |
878 | |
879 | |
880 | /*++++++++++++++++++++++++++++++++++++++ |
881 | Print out a tail in OSM XML format. |
882 | ++++++++++++++++++++++++++++++++++++++*/ |
883 | |
884 | static void print_tail_osm(void) |
885 | { |
886 | printf("</osm>\n"); |
887 | } |
888 | |
889 | |
890 | /*+ Conversion from time_t to date string (day of week). +*/ |
891 | static const char* const weekdays[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; |
892 | |
893 | /*+ Conversion from time_t to date string (month of year). +*/ |
894 | static const char* const months[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; |
895 | |
896 | |
897 | /*++++++++++++++++++++++++++++++++++++++ |
898 | Convert the time into an RFC 822 compliant date. |
899 | |
900 | char *RFC822Date Returns a pointer to a fixed string containing the date. |
901 | |
902 | time_t t The time. |
903 | ++++++++++++++++++++++++++++++++++++++*/ |
904 | |
905 | static char *RFC822Date(time_t t) |
906 | { |
907 | static char value[32]; |
908 | char weekday[4]; |
909 | char month[4]; |
910 | struct tm *tim; |
911 | |
912 | tim=gmtime(&t); |
913 | |
914 | strcpy(weekday,weekdays[tim->tm_wday]); |
915 | strcpy(month,months[tim->tm_mon]); |
916 | |
917 | /* Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 */ |
918 | |
919 | sprintf(value,"%3s, %02d %3s %4d %02d:%02d:%02d %s", |
920 | weekday, |
921 | tim->tm_mday, |
922 | month, |
923 | tim->tm_year+1900, |
924 | tim->tm_hour, |
925 | tim->tm_min, |
926 | tim->tm_sec, |
927 | "GMT" |
928 | ); |
929 | |
930 | return(value); |
931 | } |
932 | |
933 | |
934 | /*++++++++++++++++++++++++++++++++++++++ |
935 | Print out the usage information. |
936 | |
937 | int detail The level of detail to use - 0 = low, 1 = high. |
938 | |
939 | const char *argerr The argument that gave the error (if there is one). |
940 | |
941 | const char *err Other error message (if there is one). |
942 | ++++++++++++++++++++++++++++++++++++++*/ |
943 | |
944 | static void print_usage(int detail,const char *argerr,const char *err) |
945 | { |
946 | fprintf(stderr, |
947 | "Usage: filedumper [--help]\n" |
948 | " [--dir=<dirname>] [--prefix=<name>]\n" |
949 | " [--statistics]\n" |
950 | " [--visualiser --latmin=<latmin> --latmax=<latmax>\n" |
951 | " --lonmin=<lonmin> --lonmax=<lonmax>\n" |
952 | " --data=<data-type>]\n" |
953 | " [--dump [--node=<node> ...]\n" |
954 | " [--segment=<segment> ...]\n" |
955 | " [--way=<way> ...]\n" |
956 | " [--turn-relation=<rel> ...]]\n" |
957 | " [--dump-osm [--no-super]\n" |
958 | " [--latmin=<latmin> --latmax=<latmax>\n" |
959 | " --lonmin=<lonmin> --lonmax=<lonmax>]]\n"); |
960 | |
961 | if(argerr) |
962 | fprintf(stderr, |
963 | "\n" |
964 | "Error with command line parameter: %s\n",argerr); |
965 | |
966 | if(err) |
967 | fprintf(stderr, |
968 | "\n" |
969 | "Error: %s\n",err); |
970 | |
971 | if(detail) |
972 | fprintf(stderr, |
973 | "\n" |
974 | "--help Prints this information.\n" |
975 | "\n" |
976 | "--dir=<dirname> The directory containing the routing database.\n" |
977 | "--prefix=<name> The filename prefix for the routing database.\n" |
978 | "\n" |
979 | "--statistics Print statistics about the routing database.\n" |
980 | "\n" |
981 | "--visualiser Extract selected data from the routing database:\n" |
982 | " --latmin=<latmin> * the minimum latitude (degrees N).\n" |
983 | " --latmax=<latmax> * the maximum latitude (degrees N).\n" |
984 | " --lonmin=<lonmin> * the minimum longitude (degrees E).\n" |
985 | " --lonmax=<lonmax> * the maximum longitude (degrees E).\n" |
986 | " --data=<data-type> * the type of data to select.\n" |
987 | "\n" |
988 | " <data-type> can be selected from:\n" |
989 | " junctions = segment count at each junction.\n" |
990 | " super = super-node and super-segments.\n" |
991 | " oneway = oneway segments.\n" |
992 | " highway-* = segments of the specified highway type.\n" |
993 | " transport-* = segments allowing the specified transport type.\n" |
994 | " barrier-* = nodes disallowing the specified transport type.\n" |
995 | " turns = turn restrictions.\n" |
996 | " speed = speed limits.\n" |
997 | " weight = weight limits.\n" |
998 | " height = height limits.\n" |
999 | " width = width limits.\n" |
1000 | " length = length limits.\n" |
1001 | " property-* = segments with the specified property.\n" |
1002 | " errorlogs = errors logged during parsing.\n" |
1003 | "\n" |
1004 | "--dump Dump selected contents of the database.\n" |
1005 | " --node=<node> * the node with the selected index.\n" |
1006 | " --segment=<segment> * the segment with the selected index.\n" |
1007 | " --way=<way> * the way with the selected index.\n" |
1008 | " --turn-relation=<rel> * the turn relation with the selected index.\n" |
1009 | " --errorlog=<rel> * the error log with the selected index.\n" |
1010 | " Use 'all' instead of a number to get all of them.\n" |
1011 | "\n" |
1012 | "--dump-osm Dump all or part of the database as an XML file.\n" |
1013 | " --no-super * exclude the super-segments.\n" |
1014 | " --latmin=<latmin> * the minimum latitude (degrees N).\n" |
1015 | " --latmax=<latmax> * the maximum latitude (degrees N).\n" |
1016 | " --lonmin=<lonmin> * the minimum longitude (degrees E).\n" |
1017 | " --lonmax=<lonmax> * the maximum longitude (degrees E).\n"); |
1018 | |
1019 | exit(!detail); |
1020 | } |
Properties
Name | Value |
---|---|
cvs:description | Test program for mmap files. |