source: subversion/applications/utils/export/garmincyclemap/noname.pl @ 11278

Last change on this file since 11278 was 8484, checked in by nickb, 11 years ago

Andy Allan's noname rendering script used at downloads.cloudmade.com

File size: 8.7 KB
Line 
1#!/usr/bin/perl -w
2
3        #ÊPreprocess .osm file for cycling map
4        # 1. changes highway and ref tags for easier processing
5        # 2. calls osmcut to split into smaller .osm files
6        # 3. calls mkgmap to create map
7
8        # Richard Fairhurst 8-13.1.08, 6.4.08
9        # released under the WTFPL
10
11        # To use:
12        # - download mkgmap
13        # - download osmcut and put the .jar in the mkgmap/ directory
14        # - put this file in the mkgmap/ directory
15        # - put cycling-map-features.csv in mkgmap/resources
16        # - perl preprocess.pl yourosmfile.osm
17        # ...and the result is a gmapsupp.img file to copy to your Garmin
18
19        # Still to do:
20        # - rationalise 'proposed routes' code?
21        # - cycle node handling
22
23        use IO::Uncompress::Bunzip2 qw ($Bunzip2Error);
24        use IO::File;
25
26        # ===== Constants
27
28        use constant NODE     => 1;
29        use constant WAY      => 2;
30        use constant RELATION => 3;
31       
32        use constant NCN                  => 1;
33        use constant RCN                  => 2;
34        use constant LCN                  => 3;
35        use constant NCN_PROPOSED => 4;
36        use constant RCN_PROPOSED => 5;
37        use constant LCN_PROPOSED => 6;
38        use constant NONE                 => 9;
39
40        # ----- Map OSM highway tags to ncn_/rcn_/lcn_ suffixes
41        #               so a local route on a trunk road would become lcn_major
42       
43        %roads=('motorway','major',
44                        'motorway_link','major',
45                        'trunk','major',
46                        'trunk_link','major',
47                        'primary','major',
48                        'primary_link','major',
49                        'secondary','minor',
50                        'tertiary','minor',
51                        'unclassified','minor',
52                        'residential','minor',
53                        'service','minor',
54                        'living_street','minor');
55       
56        # ----- Read in only the tags we use
57       
58        %usetag=('name',1, 'ref',1, 'route',1,
59                         'ncn',1, 'ncn_ref',1,
60                         'rcn',1, 'rcn_ref',1,
61                         'lcn',1, 'lcn_ref',1);
62        open (INFILE,"resources/noname-map-features.csv") or die "Can't find cycling styles: $!\n";
63        while (<INFILE>) {
64                chomp ($t=$_);
65                if ($t=~/^\w+\|(\w+)/) { $usetag{$1}=1; }
66        }
67        close INFILE;
68       
69        # ===== Open file
70       
71        $fn=shift @ARGV;
72        $ofn=Open_File($fn);
73        open (OUTFILE,">$ofn") or die "Couldn't open output file: $!\n";
74       
75        # ----- Read relations
76
77        print "Reading relations\n";
78        # uncomment following line if you've saved relations into a separate file
79        # $fh->close; $fh=new IO::File; $fh->open("relations_only.txt");
80        %wayrefs=();
81        %waytypes=();
82        $in=0;
83        while (<$fh>) {
84                chomp ($t=$_);
85                if ($t=~/^  <relation id="(\d+)".+>$/) {
86                        $c=$1; print "relation $c     \r";
87                        $in=RELATION; %tags=(); @members=();
88                        $tags{'type'}=''; $tags{'route'}='bicycle';
89                        $tags{'state'}=''; $tags{'network'}='';
90                } elsif ($t =~/^    <member type="way" ref="(\d+)".*\/>$/) {
91                        push @members,$1;
92                } elsif ($t =~/^    <tag k="(.+)" v="(.*)"\s*\/>$/ and $in==RELATION) {
93                        $tags{$1}=$2;
94                } elsif ($t eq '  </relation>') {
95                        $in=0;
96                        next if ($tags{'type'} ne 'route');
97                        next if ($tags{'route'} ne 'bicycle');
98                        # What network are we in? (default LCN)
99                        $cycle=LCN; $prefix=''; $suffix='';
100                        if    ($tags{'network'} eq 'ncn') { $cycle=NCN; }
101                        elsif ($tags{'network'} eq 'rcn') { $cycle=RCN; $prefix='R'; }
102                        elsif ($tags{'network'} eq 'lcn') { $cycle=LCN; $prefix='L'; }
103                        if ($tags{'state'} eq 'proposed') { $cycle+=(NCN_PROPOSED)-(NCN); $suffix='*'; }
104                        # What's the ref? (fallback to name if none)
105                        $n='';
106                        if (exists $tags{'ref'}) { $n=$prefix.$tags{'ref'}.$suffix; }
107                        elsif (exists $tags{'name'}) { $n=$tags{'name'}.$suffix; }
108                        elsif (exists $tags{'network'}) { $n=$tags{'network'}.$suffix; }
109                        if ($n ne '') { $n.=' '; }
110                        # Set in all members
111                        foreach $m (@members) {
112                                if   (!exists $waytypes{$m}) { $waytypes{$m}=$cycle; }
113                                elsif ($waytypes{$m}>$cycle) { $waytypes{$m}=$cycle; }
114                                if (!exists $wayrefs{$m}) { $wayrefs{$m} =$n; }
115                                                                         else { $wayrefs{$m}.=$n; }
116                        }
117                }
118        }
119        $fh->close;
120        $in=0;
121       
122        # ----- Read whole file
123       
124        print "Reading tags and ways\n";
125        Open_File($fn);
126        while (<$fh>) {
127                chomp ($t=$_);
128                $t=~s/ timestamp="[^"]+"//;
129                if ($t=~/^  <node id="(\d+)".+">$/) {
130                        # - Start of node element
131                        $c=$1; if ($c=~/[05]0$/) { print "node $c    \r"; }
132                        $in=NODE; %tags=();
133                } elsif ($t=~/^  <way id="(\d+)".*>$/) {
134                        # - Start of way element
135                        $c=$1; if ($c=~/[05]0$/) { print "way $c    \r"; }
136                        $in=WAY; %tags=();
137                } elsif ($t eq '  </node>') {
138                        # -     End of node element, process tags
139                        $in=0;
140                        if (exists $tags{'created_by'}) { delete $tags{'created_by'}; }
141                        foreach $k (keys %tags) { print OUTFILE "    <tag k=\"$k\" v=\"$tags{$k}\" />\n"; }
142                } elsif ($t eq '  </way>') {
143                        # - End of way element, process tags
144                        $in=0;
145                        $refnum=''; $highway='';
146                        $cycle=NONE; if (exists $waytypes{$c}) { $cycle=$waytypes{$c}; }
147                        $cycleref=''; if (exists $wayrefs{$c}) { $cycleref=$wayrefs{$c}; }
148                        if (exists $tags{'ref'})                { $refnum=$tags{'ref'}; delete $tags{'ref'}; }
149                        if (exists $tags{'highway'})    { $highway=$tags{'highway'}; delete $tags{'highway'}; }
150                        if (exists $tags{'ncn'})                { if ($tags{'ncn'} eq 'proposed') { Set_Cycle(NCN_PROPOSED); }
151                                                                                                                                             else { Set_Cycle(NCN); } 
152                                                                                          delete $tags{'ncn'}; }
153                        elsif (exists $tags{'rcn'})             { if ($tags{'rcn'} eq 'proposed') { Set_Cycle(RCN_PROPOSED); }
154                                                                                                                                             else { Set_Cycle(RCN); }
155                                                                                          delete $tags{'rcn'}; }
156                        elsif (exists $tags{'lcn'})             { if ($tags{'lcn'} eq 'proposed') { Set_Cycle(LCN_PROPOSED); }
157                                                                                                                                             else { Set_Cycle(LCN); }
158                                                                                          delete $tags{'lcn'}; }
159                        if (exists $tags{'route'})              { if    ($tags{'route'} eq 'ncn'        ) { Set_Cycle(NCN); }
160                                                                                          elsif ($tags{'route'} eq 'rcn'        ) { Set_Cycle(RCN); }
161                                                                                          elsif ($tags{'route'} eq 'lcn'        ) { Set_Cycle(LCN); }
162                                                                                          delete $tags{'route'}; }
163
164                        #       munge ref tag
165                        if (exists $tags{'ncn_ref'})    { if ($cycle!=NCN_PROPOSED) { Set_Cycle(NCN); }
166                                                                                          $cycleref.=$tags{'ncn_ref'}; delete $tags{'ncn_ref'};
167                                                                                          if ($cycle==NCN_PROPOSED) { $cycleref.='*'; } 
168                                                                                          $cycleref.=' '; }
169                        if (exists $tags{'rcn_ref'})    { if ($cycle!=RCN_PROPOSED) { Set_Cycle(RCN); }
170                                                                                          $cycleref.='R'.$tags{'rcn_ref'}; delete $tags{'rcn_ref'};
171                                                                                          if ($cycle==RCN_PROPOSED) { $cycleref.='*'; } 
172                                                                                          $cycleref.=' '; }
173                        if (exists $tags{'lcn_ref'})    { if ($cycle!=LCN_PROPOSED) { Set_Cycle(LCN); }
174                                                                                          $cycleref.='L'.$tags{'lcn_ref'}; delete $tags{'lcn_ref'};
175                                                                                          if ($cycle==LCN_PROPOSED) { $cycleref.='*'; }
176                                                                                          $cycleref.=' '; }
177                        $refnum=$cycleref.$refnum; $refnum=~s/\s+$//;
178                        if ($refnum) { $tags{'ref'}=$refnum; }
179
180                        #       munge highway tag
181                        if (exists $roads{$highway}) { $hwp=$roads{$highway}; }
182                                                                        else { $hwp='offroad'; }
183                        if (!(exists $roads{$highway} and not exists $tags{'name'})) { #don't munge highway tag if it needs the noname treatment...
184                                if    ($cycle==NCN         ) { $highway="ncn_$hwp"; }
185                                elsif ($cycle==NCN_PROPOSED) { $highway="ncn_$hwp"; }
186                                elsif ($cycle==RCN         ) { $highway="rcn_$hwp"; }
187                                elsif ($cycle==NCN_PROPOSED) { $highway="rcn_$hwp"; }
188                                elsif ($cycle==LCN         ) { $highway="lcn_$hwp"; }
189                                elsif ($cycle==LCN_PROPOSED) { $highway="lcn_$hwp"; }
190                        }
191                        if ($highway) { $tags{'highway'}=$highway; }
192
193                        #       fix annoying case where name=ref
194                        if (exists $tags{'ref'} and exists $tags{'name'}) {
195                                if ($tags{'ref'} eq $tags{'name'}) { delete $tags{'name'}; }
196                        }
197
198                        # munge highway tag if it's a road with no name
199                        if (exists $roads{$highway} and not exists $tags{'name'}) {
200                                $tags{'highway'} = 'noname';
201                        }
202
203
204                        #       write tags
205                        foreach $k (keys %tags) { print OUTFILE "    <tag k=\"$k\" v=\"$tags{$k}\" />\n"; }
206#                       if ($cycle!=NONE or $cycleref) { print "$refnum ($highway)\n"; }
207
208                } elsif ($t =~/^    <tag k="(.+)" v="(.*)"\s*\/>$/) {
209                        # - read tag
210                        if ($usetag{$1}) { $tags{$1}=$2; }
211                        $t="";
212                }
213                if ($t) { $t=~s/^\s+//; print OUTFILE "$t\n"; }
214        }
215
216        $fh->close;
217        close OUTFILE;
218
219        # ===== Call osmcut to split into smaller files
220        #               (probably save in temporary directory)
221
222        $tempdir='temp';
223        print "Splitting with osmcut\n";
224        system ("mkdir $tempdir");
225        system ("./osmcut --force -s 2 -d $tempdir $ofn");
226        #system ("java -Xmx512M -jar osmcut.0.5.jar 0.5 $ofn $tempdir");
227        system ("rm $ofn");
228       
229        # ===== Call mkgmap to create map
230        #               (delete temporary directory afterwards)
231       
232        print "Creating Garmin map with mkgmap\n";
233        system ("java -Xmx512M -jar mkgmap.jar --map-features=resources/noname-map-features.csv --gmapsupp $tempdir/*");
234        print "Deleting temporary files\n";
235        system ("rm 6*.img");
236        system ("rm 6*.tdb");
237        system ("rm -rf $tempdir");
238        print "Finished!\n";
239
240
241        # ===========================
242        # General-purpose subroutines
243       
244        sub Set_Cycle { if ($_[0]<$cycle) { $cycle=$_[0]; } }
245
246        sub Open_File {
247                my $fn=$_[0];
248                if ($fn=~/^(.+)\.bz2$/) {
249                        $fh=new IO::Uncompress::Bunzip2 $fn or die "Couldn't open bzipped input file: $Bunzip2Error\n";
250                        return "$1.processed";
251                } else {
252                        $fh=new IO::File($fn) or die "Couldn't open input file: $!\n";
253                        return "$fn.processed";
254                }
255        }
Note: See TracBrowser for help on using the repository browser.