Update upstream source from tag 'upstream/0.0.0+svn4287'
Update to upstream version '0.0.0+svn4287'
with Debian dir d8daedb77a4e562e08a324d9ff531db5b33b7108
Bas Couwenberg
4 years ago
58 | 58 | </tstamp> |
59 | 59 | |
60 | 60 | <!-- ivy dependency support --> |
61 | <property name="ivy.version" value="2.2.0"/> | |
61 | <property name="ivy.version" value="2.4.0"/> | |
62 | 62 | <property name="ivy.lib.dir" value="${basedir}/lib" /> |
63 | 63 | <property name="ivy.jar.dir" value="${ivy.lib.dir}/build" /> |
64 | 64 | <property name="ivy.retrieve.pattern" value="${ivy.lib.dir}/[conf]/[artifact]-[revision].[ext]" /> |
33 | 33 | ;--read-config=filename |
34 | 34 | : Each line of the named file contains a command option in the form |
35 | 35 | option=value or option:value. The options are included as arguments of |
36 | the executed command as if they had been specified on the command line. | |
36 | the executed command as if they had been specified on the command line with one | |
37 | exception: a relative path given with option input-file is assumed to be relative | |
38 | to the location of the file. | |
39 | <p> | |
37 | 40 | Lines beginning with a # character are ignored and can be used as |
38 | 41 | comments. Any command line option can be specified, however the |
39 | 42 | leading '--' must be omitted. The short option names with a single |
101 | 104 | gmapsupp.img file so that address search will work on a GPS |
102 | 105 | device. |
103 | 106 | <p> |
104 | If instead the --tdbfile option is given then the index consists | |
105 | of two files named osmmap.mdx and osmmap_mdr.img which can be used | |
106 | with MapSource. The --overview-mapname option can be used to change | |
107 | these names. (For compatibility, you do not need the tdbfile | |
108 | option if gmapsupp is not given). | |
109 | <p> | |
110 | If both the --gmapsupp and --tdbfile options are given alongside | |
111 | the --index option, then both indexes will be created. Note that | |
112 | this will require roughly twice as much memory. | |
107 | If both the --gmapsupp and any of --tdbfile, --gmapi, or --nsis options | |
108 | are given alongside the --index option, then both indexes will be created. | |
109 | Note that this will require roughly twice as much memory. | |
113 | 110 | <p> |
114 | 111 | If the map is sent to the device by MapSource, it will enable |
115 | 112 | find by name and address search on the GPS. |
796 | 793 | <p> |
797 | 794 | ;--tdbfile |
798 | 795 | : Write files that are essential to running with MapSource, a .tdb file and |
799 | an overview map. | |
796 | an overview map. The options --nsis and --gmapi imply --tdbfile. | |
800 | 797 | <p> |
801 | 798 | ;--show-profiles=1 |
802 | 799 | : Sets a flag in tdb file. The meaning depends on the availability of DEM |
894 | 891 | points as the original that allows bicycle traffic. Also, |
895 | 892 | bicycle traffic is prohibited from using the original way |
896 | 893 | (unless that way's bicycle access has been defined). |
897 | </nowiki></div>⏎ | |
894 | </nowiki></div> |
116 | 116 | | +mkgmap:area2poi+ | The value is +true+ if the POI is derived from a polygon | 'add-pois-to-areas' |
117 | 117 | | +mkgmap:line2poi+ | The value is +true+ if the POI is derived from a line | 'add-pois-to-lines' |
118 | 118 | | +mkgmap:line2poitype+ | The tag is set for each POI generated from a line. Possible values are: +start+, +end+, +mid+, +inner+. | 'add-pois-to-lines' |
119 | | +mkgmap:way-length+ | The tag is set for each POI generated from a line. It gives the way length rounded to meters. | 'add-pois-to-lines' | |
119 | 120 | | +mkgmap:exit_hint+ | +true+ for the part on link roads that should contain information about the exit | 'process-exits' |
120 | 121 | | +mkgmap:exit_hint_name+ | The +name+ tag value of the links exit node | 'process-exits' |
121 | 122 | | +mkgmap:exit_hint_ref+ | The +ref+ tag value of the links exit node | 'process-exits' |
27 | 27 | rev="6.5.15-mkg.1b" |
28 | 28 | conf="compile->default(*)" |
29 | 29 | /> |
30 | ||
31 | <dependency org="javax.xml.bind" name="jaxb-api" | |
32 | rev="2.3.0" | |
33 | conf="test->default(*)"/> | |
30 | 34 | |
31 | 35 | <dependency org="junit" name="junit" |
32 | 36 | rev="4.11" |
31 | 31 | --read-config=filename |
32 | 32 | Each line of the named file contains a command option in the form |
33 | 33 | option=value or option:value. The options are included as arguments of |
34 | the executed command as if they had been specified on the command line. | |
34 | the executed command as if they had been specified on the command line with | |
35 | one exception: a relative path given with option input-file is assumed to be | |
36 | relative to the location of the file. | |
35 | 37 | Lines beginning with a # character are ignored and can be used as |
36 | 38 | comments. Any command line option can be specified, however the |
37 | 39 | leading '--' must be omitted. The short option names with a single |
100 | 102 | gmapsupp.img file so that address search will work on a GPS |
101 | 103 | device. |
102 | 104 | |
103 | If instead the --tdbfile option is given then the index consists | |
104 | of two files named osmmap.mdx and osmmap_mdr.img which can be used | |
105 | with MapSource. The --overview-mapname option can be used to change | |
106 | these names. (For compatibility, you do not need the tdbfile | |
107 | option if gmapsupp is not given). | |
108 | ||
109 | If both the --gmapsupp and --tdbfile options are given alongside | |
110 | the --index option, then both indexes will be created. Note that | |
111 | this will require roughly twice as much memory. | |
105 | If both the --gmapsupp and any of --tdbfile, --gmapi, or --nsis options | |
106 | are given alongside the --index option, then both indexes will be created. | |
107 | Note that this will require roughly twice as much memory. | |
112 | 108 | |
113 | 109 | If the map is sent to the device by MapSource, it will enable |
114 | 110 | find by name and address search on the GPS. |
809 | 805 | |
810 | 806 | --tdbfile |
811 | 807 | Write files that are essential to running with MapSource, a .tdb file and |
812 | an overview map. | |
808 | an overview map. The options --nsis and --gmapi imply --tdbfile. | |
813 | 809 | |
814 | 810 | --show-profiles=1 |
815 | 811 | Sets a flag in tdb file. The meaning depends on the availability of DEM |
0 | svn.version: 4262 | |
1 | build.timestamp: 2019-01-11T09:35:26+0000 | |
0 | svn.version: 4287 | |
1 | build.timestamp: 2019-06-05T14:49:17+0100 |
116 | 116 | highway=path & foot=designated |
117 | 117 | {set highway=footway} |
118 | 118 | |
119 | leisure=track & area!=yes {add highway=footway; name '${name} (${sport})' | '${name}'} | |
119 | leisure=track & area!=yes {name '${name} (${sport})' | '${sport}'} [0x30 resolution 22] | |
120 | 120 | man_made=pier | man_made=piste:halfpipe {add highway=footway; name '${ref} ${name}' | '${ref}' | '${name}'} |
121 | ||
122 | man_made=breakwater & is_closed()=false & mkgmap:mp_created!=true [0x17 resolution 22 default_name 'Breakwater'] | |
121 | 123 | |
122 | 124 | # Roundabouts |
123 | 125 | junction=roundabout & (highway=trunk | highway=trunk_link) [0x0c road_class=4 road_speed=2 resolution 24 continue] |
154 | 156 | # Ways sorted roughly by descending order of class |
155 | 157 | highway=motorway & mkgmap:fast_road=yes [0x01 road_class=4 road_speed=7 resolution 14] |
156 | 158 | highway=motorway [0x01 road_class=4 road_speed=7 resolution 15] |
157 | highway=motorway_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) [0x06 road_class=4 road_speed=2 resolution 20] | |
159 | highway=motorway_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) [0x0b road_class=4 road_speed=2 resolution 20] | |
158 | 160 | highway=motorway_link [0x09 road_class=4 road_speed=2 resolution 20] |
159 | 161 | |
160 | 162 | highway=trunk & mkgmap:fast_road=yes [0x02 road_class=4 road_speed=5 resolution 15] |
161 | 163 | highway=trunk [0x02 road_class=4 road_speed=5 resolution 18] |
162 | highway=trunk_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) [0x06 road_class=4 road_speed=2 resolution 20] | |
164 | highway=trunk_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) [0x0b road_class=4 road_speed=2 resolution 20] | |
163 | 165 | highway=trunk_link [0x09 road_class=4 road_speed=2 resolution 20] |
164 | 166 | highway=* & motorroad=yes [0x02 road_class=4 road_speed=4 resolution 18] |
165 | 167 | highway=primary & mkgmap:fast_road=yes [0x03 road_class=4 road_speed=4 resolution 17] |
166 | 168 | highway=primary [0x03 road_class=3 road_speed=4 resolution 19] |
167 | highway=primary_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) & mkgmap:fast_road=yes [0x06 road_class=4 road_speed=1 resolution 21] | |
168 | highway=primary_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) [0x06 road_class=3 road_speed=1 resolution 21] | |
169 | highway=primary_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) & mkgmap:fast_road=yes [0x0b road_class=4 road_speed=1 resolution 21] | |
170 | highway=primary_link & (mkgmap:exit_hint=true | mkgmap:dest_hint=*) [0x0b road_class=3 road_speed=1 resolution 21] | |
169 | 171 | highway=primary_link & mkgmap:fast_road=yes [0x08 road_class=4 road_speed=1 resolution 21] |
170 | 172 | highway=primary_link [0x08 road_class=3 road_speed=1 resolution 21] |
171 | 173 | highway=secondary & mkgmap:fast_road=yes [0x04 road_class=3 road_speed=3 resolution 18] |
197 | 199 | highway=service & (service=alley | service=driveway) [0x07 road_class=0 road_speed=0 resolution 23] |
198 | 200 | highway=service [0x07 road_class=0 road_speed=2 resolution 22] |
199 | 201 | |
200 | highway=cycleway [0x07 road_class=0 road_speed=1 resolution 23] | |
202 | highway=cycleway [0x11 road_class=0 road_speed=1 resolution 23] | |
201 | 203 | |
202 | 204 | # highway=footway is often an area as well, continue for polygon processing |
203 | 205 | highway=footway {set tmp:stopMopUp=yes} [0x16 road_class=0 road_speed=0 resolution 23 continue with_actions] |
250 | 252 | boundary=national [0x1e resolution 17] |
251 | 253 | boundary=political [0x1c resolution 19] |
252 | 254 | |
255 | barrier=wall | barrier=fence | barrier=hedge | barrier=ditch {add name='${barrier|subst:"_=> "}'} [0x17 resolution 24] | |
256 | ||
253 | 257 | route=ferry & (toll=no | toll=false) {set mkgmap:toll=no} |
254 | 258 | route=ferry {set mkgmap:numbers=false; set mkgmap:ferry=1; add mkgmap:toll=yes} |
255 | 259 | route=ferry & (motorcar=no | motor_vehicle=no) [0x1b road_class=0 road_speed=0 resolution 23] |
256 | route=ferry [0x1b road_class=3 road_speed=0 resolution 19] | |
260 | route=ferry [0x1a road_class=3 road_speed=0 resolution 19] | |
257 | 261 | |
258 | 262 | (waterway=river | waterway=canal) & intermittent=yes [0x26 resolution 20] |
259 | (waterway=stream | waterway=drain) & intermittent=yes [0x10A02 resolution 22] | |
263 | (waterway=stream | waterway=drain) & intermittent=yes [0x26 resolution 22] | |
260 | 264 | |
261 | 265 | waterway=canal [0x1f resolution 21] |
262 | 266 | waterway=river [0x1f resolution 18] |
155 | 155 | amenity=taxi [0x2f17 resolution 24] |
156 | 156 | amenity=telephone [0x2f12 resolution 24 default_name 'Telephone'] |
157 | 157 | amenity=theatre [0x2d01 resolution 24] |
158 | amenity=toilets & highway=rest_area [0x2f0c resolution 24] | |
159 | amenity=toilets [0x4e00 resolution 24 default_name 'Toilets'] | |
158 | amenity=toilets [0x2f0c resolution 24 default_name 'Toilets'] | |
160 | 159 | amenity=townhall [0x3003 resolution 24] |
161 | 160 | amenity=university [0x2c05 resolution 24] |
162 | 161 | # amenity=zoo is superceded by tourism=zoo |
265 | 264 | tourism=wilderness_hut [0x2b07 resolution 24 default_name 'wilderness hut'] |
266 | 265 | tourism=museum [0x2c02 resolution 24] |
267 | 266 | tourism=picnic_site [0x4a00 resolution 24] |
267 | tourism=resort [0x2b04 resolution 24] | |
268 | 268 | tourism=theme_park [0x2c01 resolution 24] |
269 | 269 | tourism=viewpoint {name '${name} - ${description}' | '${name}'} [0x2c04 resolution 24] |
270 | 270 | tourism=wine_cellar [0x2c0a resolution 24] |
328 | 328 | #amenity=fast_food & cuisine=* {add name='${cuisine|subst:"_=> "}'} [0x2a07 resolution 24] |
329 | 329 | #amenity=fast_food [0x2a07 resolution 24] |
330 | 330 | |
331 | barrier=bollard | barrier=bus_trap | barrier=gate [0x660f resolution 24] | |
332 | barrier=block | barrier=cycle_barrier | barrier=stile | barrier=kissing_gate [0x660f resolution 24] | |
331 | barrier=bollard | barrier=bus_trap | barrier=gate | barrier=block | barrier=cycle_barrier | | |
332 | barrier=stile | barrier=kissing_gate | barrier=lift_gate | barrier=swing_gate | |
333 | {add name='${barrier|subst:"_=> "}'} [0x3200 resolution 24] | |
333 | 334 | |
334 | 335 | landuse=basin | landuse=reservoir [0x650f resolution 24] |
335 | 336 |
36 | 36 | healthcare=hospital | amenity=hospital | amenity=clinic [0x0b resolution 22] |
37 | 37 | healthcare=* | amenity=dentist | amenity=doctors | amenity=nursing_home [0x0b resolution 23] |
38 | 38 | |
39 | leisure=common [0x17 resolution 21] | |
40 | leisure=garden [0x17 resolution 21] | |
39 | leisure=common [0x1d resolution 21] | |
40 | leisure=garden [0x20 resolution 21] | |
41 | 41 | leisure=golf_course [0x18 resolution 21] |
42 | 42 | leisure=ice_rink [0x19 resolution 22] |
43 | 43 | leisure=nature_reserve [0x16 resolution 19] |
56 | 56 | shop=* {add name='${shop|subst:"_=> "}'} [0x08 resolution 22] |
57 | 57 | |
58 | 58 | # squares and plazas |
59 | place=square [0x17 resolution 22] | |
60 | highway=pedestrian & (area=yes | mkgmap:mp_created=true) [0x17 resolution 22] | |
59 | place=square [0x25 resolution 22] | |
60 | highway=pedestrian & (area=yes | mkgmap:mp_created=true) [0x25 resolution 22] | |
61 | 61 | # following rule also renders a closed way without area attribute as a plaza |
62 | highway=pedestrian & area!=no [0x17 resolution 22] | |
62 | highway=pedestrian & area!=no [0x25 resolution 22] | |
63 | 63 | |
64 | 64 | # footways areas are similar, but should be explicity marked as such |
65 | highway=footway & area=yes [0x17 resolution 24] | |
65 | highway=footway & area=yes [0x25 resolution 24] | |
66 | 66 | |
67 | # other highways that have area=yes are probably parking lots, eg services/rest_area | |
68 | (highway=services | highway=rest_area) & area!=no [0x05 resolution 22] | |
67 | highway=services [0x12 resolution 22] # service station complex; show as retail | |
68 | highway=rest_area & area!=no [0x05 resolution 22] # show as parking lot | |
69 | 69 | |
70 | historic=* & historic!=no & historic!=yes & boundary!=* {add name='${historic|subst:"_=> "}'} [0x1e resolution 21] | |
70 | historic=* & historic!=no & historic!=yes & boundary!=* {add name='${historic|subst:"_=> "}'} [0x22 resolution 21] | |
71 | 71 | |
72 | 72 | landuse=basin [0x3f resolution 20] |
73 | 73 | landuse=reservoir | (natural=water & water=reservoir) [0x3f resolution 20] |
77 | 77 | natural=bay [0x3d resolution 18] |
78 | 78 | natural=glacier [0x4d resolution 18] |
79 | 79 | natural=marsh [0x51 resolution 20] |
80 | natural=tundra [0x52 resolution 18] | |
80 | 81 | natural=mud [0x51 resolution 20] |
82 | natural=beach | natural=sand [0x53 resolution 20] | |
81 | 83 | natural=wetland [0x51 resolution 20] |
82 | 84 | natural=water & water=canal [0x48 resolution 22] |
83 | 85 | natural=water & water=lock [0x4c resolution 22 default_name 'Lock'] |
93 | 95 | |
94 | 96 | landuse=allotments [0x4e resolution 21] |
95 | 97 | landuse=cemetery | landuse=cemetary | amenity=grave_yard [0x1a resolution 21] |
96 | landuse=commercial [0x0c resolution 19] | |
98 | landuse=commercial [0x0f resolution 19] | |
97 | 99 | landuse=construction [0x0c resolution 21] |
98 | landuse=farm | landuse=farmland [0x4e resolution 20] | |
99 | landuse=farmyard [0x10 resolution 22] | |
100 | landuse=farm [0x26 resolution 22] | |
101 | landuse=farmland [0x1c resolution 20] | |
102 | landuse=farmyard [0x26 resolution 22] | |
100 | 103 | landuse=forest | landuse=wood [0x50 resolution 20] |
101 | landuse=greenfield [0x17 resolution 20] | |
102 | landuse=meadow | landuse=grass [0x17 resolution 19] | |
104 | landuse=greenfield [0x1c resolution 20] | |
105 | landuse=meadow | landuse=grass [0x1c resolution 19] | |
103 | 106 | landuse=military [0x04 resolution 19] |
104 | 107 | landuse=quarry [0x0c resolution 19] |
105 | 108 | landuse=recreation_ground [0x19 resolution 19] |
106 | 109 | # dedicate resolution 24 for building=* instead of related landuse=* |
107 | 110 | landuse=industrial [0x0c resolution 19-23] |
108 | 111 | landuse=residential [0x10 resolution 19-23] |
109 | landuse=retail [0x08 resolution 20-23] | |
110 | landuse=village_green [0x17 resolution 20] | |
112 | landuse=retail [0x12 resolution 20-23] | |
113 | landuse=village_green [0x15 resolution 20] | |
111 | 114 | landuse=vineyard [0x4e resolution 20] |
112 | 115 | landuse=orchard [0x4e resolution 20] |
113 | 116 | |
114 | 117 | military=airfield [0x04 resolution 20] |
115 | 118 | military=barracks [0x04 resolution 23] |
116 | military=danger_area [0x04 resolution 20] | |
119 | military=danger_area [0x11 resolution 20] | |
117 | 120 | military=range [0x04 resolution 20] |
118 | 121 | |
119 | 122 | natural=scrub [0x4f resolution 20] |
120 | 123 | natural=wood [0x50 resolution 20] |
121 | 124 | |
122 | 125 | # building tag should be last |
123 | amenity=* & area!=no & amenity!=grave_yard {add name='${amenity|subst:"_=> "}'} [0x13 resolution 24] | |
126 | amenity=* & area!=no & amenity!=grave_yard {add name='${amenity|subst:"_=> "}'} [0x23 resolution 24] | |
124 | 127 | building=* & building!=no [0x13 resolution 24] |
125 | tourism=* & area!=no & waterway!=* {add name='${tourism|subst:"_=> "}'} [0x1f resolution 24] | |
128 | tourism=* & area!=no & waterway!=* {add name='${tourism|subst:"_=> "}'} [0x21 resolution 24] | |
126 | 129 | |
127 | 130 | # man_made can be used on areas or lines |
128 | man_made=* & area!=no {add name='${man_made|subst:"_=> "}'} [0x13 resolution 24] | |
131 | man_made=* & area!=no {add name='${man_made|subst:"_=> "}'} [0x24 resolution 24] | |
129 | 132 | |
130 | 133 | # render small named islands |
131 | 134 | place=island & name=* & area_size() < 1000000 [0x53 resolution 19] |
206 | 206 | * @param val The value to write. Unsigned |
207 | 207 | */ |
208 | 208 | public void putNu(int nBytes, int val) { |
209 | assert nBytes >= 1 && nBytes <= 4: nBytes; | |
209 | 210 | try { |
210 | 211 | file.write(val); |
211 | 212 | if (nBytes <= 1) { |
35 | 35 | private List<Mdr5Record> cities = new ArrayList<>(); |
36 | 36 | private int maxCityIndex; |
37 | 37 | private int localCitySize; |
38 | private int mdr20PointerSize = 0; // bytes for mdr20 pointer, or 0 if no mdr20 | |
38 | 39 | |
39 | 40 | public Mdr5(MdrConfig config) { |
40 | 41 | setConfig(config); |
187 | 188 | } |
188 | 189 | |
189 | 190 | public void writeSectData(ImgFileWriter writer) { |
190 | int size20 = getSizes().getMdr20Size(); | |
191 | 191 | Mdr5Record lastCity = null; |
192 | 192 | boolean hasString = hasFlag(0x8); |
193 | 193 | boolean hasRegion = hasFlag(0x4); |
216 | 216 | writer.put2u(region); |
217 | 217 | if (hasString) |
218 | 218 | putStringOffset(writer, city.getStringOffset()); |
219 | writer.putNu(size20, city.getMdr20()); | |
219 | if (mdr20PointerSize > 0) | |
220 | writer.putNu(mdr20PointerSize, city.getMdr20()); | |
220 | 221 | } |
221 | 222 | } |
222 | 223 | |
238 | 239 | int size = sizes.getMapSize() |
239 | 240 | + localCitySize |
240 | 241 | + 3 |
241 | + sizes.getMdr20Size(); | |
242 | + mdr20PointerSize; | |
242 | 243 | if (hasFlag(0x4)) |
243 | 244 | size += 2; |
244 | 245 | if (hasFlag(0x8)) |
251 | 252 | } |
252 | 253 | |
253 | 254 | /** |
254 | * Known structure: | |
255 | * bits 0-1: size of local city index - 1 (all values appear to work) | |
256 | * bit 3: has region | |
257 | * bit 4: has string | |
255 | * Known structure bits/masks: | |
256 | * 0x0003 size of local city index - 1 (all values appear to work) | |
257 | * 0x0004 has region/country | |
258 | * 0x0008 has string | |
259 | * 0x0010 ? set unconditionally ? | |
260 | * 0x0040 mdr17 sub section | |
261 | * 0x0100 mdr20 present | |
262 | * 0x0400 28_29 offset | |
263 | * 0x0800 mdr20 offset | |
258 | 264 | * @return The value to be placed in the header. |
259 | 265 | */ |
260 | 266 | public int getExtraValue() { |
268 | 274 | val |= 0x08; // string |
269 | 275 | } |
270 | 276 | val |= 0x10; |
271 | val |= 0x100; // mdr20 present | |
277 | if (getSizes().getNumberOfItems(20) > 0) { | |
278 | mdr20PointerSize = getSizes().getMdr20Size(); | |
279 | val |= 0x100; // mdr20 present | |
280 | } | |
272 | 281 | return val; |
273 | 282 | } |
274 | 283 |
214 | 214 | public int getSize(int sect) { |
215 | 215 | return sections[sect].getSizeForRecord(); |
216 | 216 | } |
217 | ||
218 | public int getNumberOfItems(int sect) { | |
219 | return sections[sect].getNumberOfItems(); | |
220 | } | |
217 | 221 | } |
218 | 222 | } |
12 | 12 | package uk.me.parabola.imgfmt.app.net; |
13 | 13 | |
14 | 14 | import java.io.ByteArrayOutputStream; |
15 | import java.util.Iterator; | |
16 | 15 | import java.util.List; |
17 | 16 | |
18 | 17 | import uk.me.parabola.imgfmt.Utils; |
115 | 114 | private int setup() { |
116 | 115 | // Should we use the swapped default numbering style EVEN/ODD rather than |
117 | 116 | // ODD/EVEN and the initialValue. |
118 | for (Iterator<Numbers> iterator = numbers.listIterator(); iterator.hasNext(); ) { | |
119 | Numbers n = iterator.next(); | |
120 | if (n.getLeftNumberStyle() == NONE && n.getRightNumberStyle() == NONE) | |
121 | iterator.remove(); | |
122 | } | |
117 | numbers.removeIf(Numbers::isEmpty); | |
123 | 118 | if (numbers.isEmpty()) |
124 | 119 | throw new Abandon("no numbers"); |
125 | 120 |
380 | 380 | // a bit more complex: determine the to-node and arc(s) |
381 | 381 | RouteNode tn = null; |
382 | 382 | int toId = 0; |
383 | List<RouteArc> toArcs = new ArrayList<>(); | |
383 | List<RouteArc> toArcs; | |
384 | 384 | if (grr.getToNode() != null){ |
385 | 385 | // polish input data provides id |
386 | 386 | toId = grr.getToNode().getId(); |
389 | 389 | log.error(sourceDesc, "can't locate 'to' RouteNode with id", toId); |
390 | 390 | return 0; |
391 | 391 | } |
392 | toArcs = lastViaNode.getDirectArcsTo(tn, grr.getToWayId()); | |
392 | 393 | } else { |
393 | 394 | // we can have multiple arcs between last via node and to node. The |
394 | 395 | // arcs can be on the same OSM way or on different OSM ways. |
123 | 123 | for (ArgType a : arglist) { |
124 | 124 | a.processArg(); |
125 | 125 | } |
126 | ||
127 | proc.endOptions(new CommandArgs(this.args)); | |
126 | if (arglist.getFilenameCount() > 0) | |
127 | proc.endOptions(new CommandArgs(this.args)); | |
128 | 128 | } |
129 | 129 | |
130 | 130 |
980 | 980 | private void processInfo(Map map, LoadableMapDataSource src) { |
981 | 981 | // The bounds of the map. |
982 | 982 | map.setBounds(src.getBounds()); |
983 | if (src instanceof OverviewMapDataSource == false) | |
983 | if (!(src instanceof OverviewMapDataSource)) | |
984 | 984 | poiDisplayFlags |= TREHeader.POI_FLAG_DETAIL; |
985 | 985 | |
986 | if(poiDisplayFlags != 0) // POI requested alternate address notation | |
986 | poiDisplayFlags |= src.getPoiDispFlag(); | |
987 | ||
988 | if(poiDisplayFlags != 0) | |
987 | 989 | map.addPoiDisplayFlags(poiDisplayFlags); |
988 | 990 | |
989 | 991 | // You can add anything here. |
23 | 23 | import java.util.ArrayList; |
24 | 24 | import java.util.List; |
25 | 25 | import java.util.Locale; |
26 | import java.util.Map; | |
26 | 27 | |
27 | 28 | import uk.me.parabola.imgfmt.Utils; |
28 | 29 | import uk.me.parabola.mkgmap.CommandArgs; |
38 | 39 | private String id; |
39 | 40 | private int productId; |
40 | 41 | |
41 | private boolean hasIndex; | |
42 | private final boolean hasIndex; | |
42 | 43 | private boolean hasTyp; |
43 | 44 | |
44 | 45 | private final List<String> mapList = new ArrayList<>(); |
45 | 46 | private String typName; |
47 | ||
48 | public NsisBuilder(Map<String, Combiner> combinerMap) { | |
49 | this.hasIndex = combinerMap.containsKey("mdx"); | |
50 | } | |
46 | 51 | |
47 | 52 | public void init(CommandArgs args) { |
48 | 53 | int familyId = args.get("family-id", CommandArgs.DEFAULT_FAMILYID); |
59 | 64 | licenseFilename = baseFilename + "_license.txt"; |
60 | 65 | |
61 | 66 | outputDir = args.getOutputDir(); |
62 | ||
63 | hasIndex = args.exists("index"); | |
64 | 67 | } |
65 | 68 | |
66 | 69 | public void onMapEnd(FileInfo info) { |
73 | 76 | File typFile = new File(info.getFilename()); |
74 | 77 | typName = typFile.getName(); |
75 | 78 | break; |
76 | case MDR_KIND: | |
77 | hasIndex = true; | |
78 | break; | |
79 | case APP_KIND: | |
80 | case GMAPSUPP_KIND: | |
81 | case UNKNOWN_KIND: | |
79 | default: | |
82 | 80 | break; |
83 | 81 | } |
84 | 82 | } |
424 | 424 | /** |
425 | 425 | * Add the prefix to the file name. |
426 | 426 | * @param name filename |
427 | * @return filename of the corresponding overview img file | |
427 | * @return filename of the corresponding overview img file (without a path) | |
428 | 428 | */ |
429 | 429 | public static String getOverviewImgName (String name){ |
430 | 430 | File f = new File(name); |
431 | return new File(f.getParent(),OverviewBuilder.OVERVIEW_PREFIX + f.getName()).getAbsolutePath(); | |
431 | return OverviewBuilder.OVERVIEW_PREFIX + f.getName(); | |
432 | 432 | } |
433 | 433 | |
434 | 434 | public static String getMapName(String name) { |
62 | 62 | public long getFullArea() { // this is unadulterated size, +ve if clockwise |
63 | 63 | if (this.fullArea == Long.MAX_VALUE) { |
64 | 64 | java.util.List<Coord> points = this.getPoints(); |
65 | if (points.size() >= 4 && points.get(0).highPrecEquals(points.get(points.size()-1))) | |
65 | if (points != null && points.size() >= 4 && points.get(0).highPrecEquals(points.get(points.size()-1))) | |
66 | 66 | this.fullArea = ShapeMergeFilter.calcAreaSizeTestVal(points); |
67 | 67 | } |
68 | 68 | return this.fullArea; |
18 | 18 | import java.io.InputStream; |
19 | 19 | import java.io.InputStreamReader; |
20 | 20 | import java.io.PrintStream; |
21 | import java.lang.OutOfMemoryError; | |
22 | 21 | import java.lang.management.ManagementFactory; |
23 | 22 | import java.lang.management.MemoryPoolMXBean; |
24 | 23 | import java.lang.management.MemoryType; |
25 | 24 | import java.lang.management.MemoryUsage; |
25 | import java.nio.file.Files; | |
26 | 26 | import java.time.Duration; |
27 | 27 | import java.time.Instant; |
28 | 28 | import java.util.ArrayList; |
637 | 637 | String fileName = file.getFilename(); |
638 | 638 | if (!fileName.endsWith(".img")) |
639 | 639 | continue; |
640 | fileName = OverviewBuilder.getOverviewImgName(fileName); | |
640 | File f1 = new File(fileName); | |
641 | fileName = new File(f1.getParent(), OverviewBuilder.getOverviewImgName(fileName)).getAbsolutePath(); | |
642 | ||
641 | 643 | log.info(" " + fileName); |
644 | ||
642 | 645 | FileInfo fileInfo = FileInfo.getFileInfo(fileName); |
646 | ||
643 | 647 | fileInfo.setArgs(file.getArgs()); |
644 | 648 | // add the real input file |
645 | 649 | foundOvmFiles.add(file.getFilename()); |
677 | 681 | c.onFinish(); |
678 | 682 | |
679 | 683 | if (tdbBuilderAdded && args.getProperties().getProperty("remove-ovm-work-files", false)){ |
680 | for (String fName:foundOvmFiles){ | |
684 | for (String fName : foundOvmFiles) { | |
681 | 685 | String ovmFile = OverviewBuilder.getOverviewImgName(fName); |
682 | log.info("removing " + ovmFile); | |
683 | new File(ovmFile).delete(); | |
686 | File f = new File(args.getOutputDir(), ovmFile); | |
687 | if (f.exists() && f.isFile()) { | |
688 | try { | |
689 | Files.delete(f.toPath()); | |
690 | log.warn("removed " + f); | |
691 | } catch (IOException e) { | |
692 | log.warn("removing " + f + "failed with " + e.getMessage()); | |
693 | } | |
694 | } | |
684 | 695 | } |
685 | 696 | } |
686 | 697 | } |
690 | 701 | boolean gmapsuppOpt = args.exists("gmapsupp"); |
691 | 702 | boolean tdbOpt = args.exists("tdbfile"); |
692 | 703 | boolean gmapiOpt = args.exists("gmapi"); |
693 | ||
704 | boolean nsisOpt = args.exists("nsis"); | |
705 | ||
706 | for (String opt : Arrays.asList("gmapi", "nsis")) { | |
707 | if (!createTdbFiles && args.exists(opt)) { | |
708 | throw new ExitException("Options --" + opt + " and --no-tdbfiles are mutually exclusive"); | |
709 | } | |
710 | } | |
694 | 711 | if (tdbOpt || createTdbFiles){ |
695 | 712 | addTdbBuilder(); |
696 | } | |
697 | if (args.exists("nsis")) { | |
698 | addCombiner("nsis", new NsisBuilder()); | |
699 | 713 | } |
700 | 714 | if (gmapsuppOpt) { |
701 | 715 | GmapsuppBuilder gmapBuilder = new GmapsuppBuilder(); |
704 | 718 | addCombiner("gmapsupp", gmapBuilder); |
705 | 719 | } |
706 | 720 | |
707 | if (indexOpt && (tdbOpt || !gmapsuppOpt)) { | |
721 | if (indexOpt && (tdbOpt || !gmapsuppOpt || gmapiOpt || nsisOpt)) { | |
708 | 722 | addCombiner("mdr", new MdrBuilder()); |
709 | 723 | addCombiner("mdx", new MdxBuilder()); |
710 | 724 | } |
711 | ||
712 | 725 | if (gmapiOpt) { |
713 | 726 | addCombiner("gmapi", new GmapiBuilder(combinerMap)); |
714 | 727 | } |
728 | if (nsisOpt) { | |
729 | addCombiner("nsis", new NsisBuilder(combinerMap)); | |
730 | } | |
731 | ||
715 | 732 | } |
716 | 733 | |
717 | 734 | /** |
17 | 17 | |
18 | 18 | import java.io.File; |
19 | 19 | import java.io.FileNotFoundException; |
20 | import java.io.IOException; | |
21 | import java.nio.file.Files; | |
20 | 22 | |
21 | 23 | import uk.me.parabola.imgfmt.FileExistsException; |
22 | 24 | import uk.me.parabola.imgfmt.FileNotWritableException; |
55 | 57 | makeMap(args, src, OverviewBuilder.OVERVIEW_PREFIX); |
56 | 58 | } else { |
57 | 59 | String fname = OverviewBuilder.getOverviewImgName(args.getMapname()); |
58 | File f = new File(fname); | |
59 | if (f.exists()) { | |
60 | if (f.isFile() ) | |
61 | f.delete(); | |
62 | else { | |
63 | // TODO: error message ? | |
60 | ||
61 | File f = new File(args.getOutputDir(), fname); | |
62 | if (f.exists() && f.isFile()) { | |
63 | try { | |
64 | Files.delete(f.toPath()); | |
65 | log.warn("removed " + f); | |
66 | } catch (IOException e) { | |
67 | log.warn("removing " + f + "failed with " + e.getMessage()); | |
64 | 68 | } |
65 | 69 | } |
66 | 70 | } |
123 | 127 | * @param map The map to modify. |
124 | 128 | * @param args The command line arguments. |
125 | 129 | */ |
126 | private void setOptions(Map map, CommandArgs args) { | |
130 | private static void setOptions(Map map, CommandArgs args) { | |
127 | 131 | map.config(args.getProperties()); |
128 | 132 | |
129 | 133 | String s = args.getCharset(); |
144 | 148 | * @throws FileNotFoundException For non existing files. |
145 | 149 | * @throws FormatException When the file format is not valid. |
146 | 150 | */ |
147 | private LoadableMapDataSource loadFromFile(CommandArgs args, String name) throws | |
151 | private static LoadableMapDataSource loadFromFile(CommandArgs args, String name) throws | |
148 | 152 | FileNotFoundException, FormatException |
149 | 153 | { |
150 | 154 | LoadableMapDataSource src = MapReader.createMapReader(name); |
356 | 356 | public boolean isFileSupported(String name) { |
357 | 357 | return true; // we always try xml reader if nothing else matched |
358 | 358 | } |
359 | ||
360 | @Override | |
361 | public int getPoiDispFlag() { | |
362 | return 0; // no info in OSM data | |
363 | } | |
359 | 364 | } |
75 | 75 | public static final short AREA2POI_TAG = TagDict.getInstance().xlate("mkgmap:area2poi"); |
76 | 76 | public static final short LINE2POI_TAG = TagDict.getInstance().xlate("mkgmap:line2poi"); |
77 | 77 | public static final short LINE2POI_TYPE_TAG = TagDict.getInstance().xlate("mkgmap:line2poitype"); |
78 | ||
78 | public static final short WAY_LENGTH_TAG = TagDict.getInstance().xlate("mkgmap:way-length"); | |
79 | ||
80 | @Override | |
79 | 81 | public boolean init(ElementSaver saver, EnhancedProperties props) { |
80 | 82 | poisToAreas = props.containsKey("add-pois-to-areas"); |
81 | 83 | poisToLines = props.containsKey("add-pois-to-lines"); |
82 | 84 | |
83 | if ((poisToAreas || poisToLines) == false) { | |
85 | if (!(poisToAreas || poisToLines)) { | |
84 | 86 | log.info("Disable Areas2POIHook because add-pois-to-areas and add-pois-to-lines option is not set."); |
85 | 87 | return false; |
86 | 88 | } |
99 | 101 | * @return the parsed tag definition list |
100 | 102 | */ |
101 | 103 | public static List<Entry<String,String>> getPoiPlacementTags(EnhancedProperties props) { |
102 | if (props.containsKey("add-pois-to-areas") == false) { | |
104 | if (!props.containsKey("add-pois-to-areas")) { | |
103 | 105 | return Collections.emptyList(); |
104 | 106 | } |
105 | 107 | |
106 | List<Entry<String,String>> tagList = new ArrayList<Entry<String,String>>(); | |
108 | List<Entry<String,String>> tagList = new ArrayList<>(); | |
107 | 109 | |
108 | 110 | String placementDefs = props.getProperty("pois-to-areas-placement", "entrance=main;entrance=yes;building=entrance"); |
109 | 111 | placementDefs = placementDefs.trim(); |
141 | 143 | tagValue = null; |
142 | 144 | } |
143 | 145 | } |
144 | Entry<String,String> tag = new AbstractMap.SimpleImmutableEntry<String,String>(tagName, tagValue); | |
146 | Entry<String,String> tag = new AbstractMap.SimpleImmutableEntry<>(tagName, tagValue); | |
145 | 147 | tagList.add(tag); |
146 | 148 | } |
147 | 149 | return tagList; |
148 | 150 | } |
149 | 151 | |
150 | 152 | |
153 | @Override | |
151 | 154 | public Set<String> getUsedTags() { |
152 | 155 | // return all tags defined in the poiPlacementTags |
153 | Set<String> tags = new HashSet<String>(); | |
156 | Set<String> tags = new HashSet<>(); | |
154 | 157 | for (Entry<String,String> poiTag : poiPlacementTags) { |
155 | 158 | tags.add(poiTag.getKey()); |
156 | 159 | } |
157 | 160 | return tags; |
158 | 161 | } |
159 | 162 | |
163 | @Override | |
160 | 164 | public void end() { |
161 | 165 | log.info(getClass().getSimpleName(), "started"); |
162 | 166 | addPOIsForWays(); |
168 | 172 | for (int order = 0; order < poiPlacementTags.size(); order++) { |
169 | 173 | Entry<String,String> poiTagDef = poiPlacementTags.get(order); |
170 | 174 | String tagValue = elem.getTag(poiTagDef.getKey()); |
171 | if (tagValue != null) { | |
172 | if (poiTagDef.getValue() == null || poiTagDef.getValue().equals(tagValue)) { | |
173 | return order; | |
174 | } | |
175 | if (tagValue != null && poiTagDef.getValue() == null || poiTagDef.getValue().equals(tagValue)) { | |
176 | return order; | |
175 | 177 | } |
176 | 178 | } |
177 | 179 | // no poi tag match |
179 | 181 | } |
180 | 182 | |
181 | 183 | private void addPOIsForWays() { |
182 | Map<Coord, Integer> labelCoords = new IdentityHashMap<Coord, Integer>(); | |
184 | Map<Coord, Integer> labelCoords = new IdentityHashMap<>(); | |
183 | 185 | |
184 | 186 | // save all coords with one of the placement tags to a map |
185 | 187 | // so that ways use this coord as its labeling point |
186 | if (poiPlacementTags.isEmpty() == false && poisToAreas) { | |
188 | if (!poiPlacementTags.isEmpty() && poisToAreas) { | |
187 | 189 | for (Node n : saver.getNodes().values()) { |
188 | 190 | int order = getPlacementOrder(n); |
189 | 191 | if (order >= 0) { |
233 | 235 | } |
234 | 236 | |
235 | 237 | private void addPOItoPolygon(Way polygon, Map<Coord, Integer> labelCoords) { |
236 | if (poisToAreas == false) { | |
238 | if (!poisToAreas) { | |
237 | 239 | return; |
238 | 240 | } |
239 | 241 | |
265 | 267 | } |
266 | 268 | // add tag mkgmap:cache_area_size to the original polygon so that it is copied to the POI |
267 | 269 | areaSizeFunction.value(polygon); |
268 | Node poi = createPOI(polygon, poiCoord, AREA2POI_TAG); | |
270 | Node poi = createPOI(polygon, poiCoord, AREA2POI_TAG, 0); | |
269 | 271 | saver.addNode(poi); |
270 | 272 | } |
271 | 273 | |
272 | 274 | |
273 | 275 | private int addPOItoLine(Way line) { |
274 | Node startNode = createPOI(line, line.getPoints().get(0), LINE2POI_TAG); | |
276 | // calculate the middle of the line | |
277 | Coord prevC = null; | |
278 | double sumDist = 0.0; | |
279 | ArrayList<Double> dists = new ArrayList<>(line.getPoints().size()-1); | |
280 | for (Coord c : line.getPoints()) { | |
281 | if (prevC != null) { | |
282 | double dist = prevC.distance(c); | |
283 | dists.add(dist); | |
284 | sumDist+=dist; | |
285 | } | |
286 | prevC = c; | |
287 | } | |
288 | ||
289 | Node startNode = createPOI(line, line.getPoints().get(0), LINE2POI_TAG, sumDist); | |
275 | 290 | startNode.addTag(LINE2POI_TYPE_TAG,"start"); |
276 | 291 | saver.addNode(startNode); |
277 | 292 | |
278 | Node endNode = createPOI(line, line.getPoints().get(line.getPoints().size()-1), LINE2POI_TAG); | |
293 | Node endNode = createPOI(line, line.getPoints().get(line.getPoints().size()-1), LINE2POI_TAG, sumDist); | |
279 | 294 | endNode.addTag(LINE2POI_TYPE_TAG,"end"); |
280 | 295 | saver.addNode(endNode); |
281 | 296 | |
287 | 302 | continue; |
288 | 303 | } |
289 | 304 | lastPoint = inPoint; |
290 | Node innerNode = createPOI(line, inPoint, LINE2POI_TAG); | |
305 | Node innerNode = createPOI(line, inPoint, LINE2POI_TAG, sumDist); | |
291 | 306 | innerNode.addTag(LINE2POI_TYPE_TAG,"inner"); |
292 | 307 | saver.addNode(innerNode); |
293 | 308 | noPOIs++; |
294 | 309 | } |
295 | } | |
296 | ||
297 | // calculate the middle of the line | |
298 | Coord prevC = null; | |
299 | double sumDist = 0.0; | |
300 | ArrayList<Double> dists = new ArrayList<Double>(line.getPoints().size()-1); | |
301 | for (Coord c : line.getPoints()) { | |
302 | if (prevC != null) { | |
303 | double dist = prevC.distance(c); | |
304 | dists.add(dist); | |
305 | sumDist+=dist; | |
306 | } | |
307 | prevC = c; | |
308 | 310 | } |
309 | 311 | |
310 | 312 | Coord midPoint = null; |
320 | 322 | } |
321 | 323 | |
322 | 324 | if (midPoint != null) { |
323 | Node midNode = createPOI(line, midPoint, LINE2POI_TAG); | |
325 | Node midNode = createPOI(line, midPoint, LINE2POI_TAG, sumDist); | |
324 | 326 | midNode.addTag(LINE2POI_TYPE_TAG,"mid"); |
325 | 327 | saver.addNode(midNode); |
326 | 328 | noPOIs++; |
329 | 331 | |
330 | 332 | } |
331 | 333 | |
332 | private static Node createPOI(Element source, Coord poiCoord, short poiTypeTagKey) { | |
334 | private static Node createPOI(Element source, Coord poiCoord, short poiTypeTagKey, double wayLength) { | |
333 | 335 | Node poi = new Node(source.getOriginalId(), poiCoord); |
334 | 336 | poi.setFakeId(); |
335 | 337 | poi.copyTags(source); |
336 | 338 | poi.deleteTag(MultiPolygonRelation.STYLE_FILTER_TAG); |
337 | 339 | poi.addTag(poiTypeTagKey, "true"); |
340 | if (poiTypeTagKey == LINE2POI_TAG) { | |
341 | poi.addTag(WAY_LENGTH_TAG, String.valueOf(Math.round(wayLength))); | |
342 | } | |
338 | 343 | if (log.isDebugEnabled()) { |
339 | 344 | log.debug("Create POI",poi.toTagString(),"from",source.getId(),source.toTagString()); |
340 | 345 | } |
347 | 352 | for (Relation r : saver.getRelations().values()) { |
348 | 353 | |
349 | 354 | // create POIs for multipolygon relations only |
350 | if (r instanceof MultiPolygonRelation == false) { | |
351 | continue; | |
352 | } | |
353 | Node admin_centre = null; | |
355 | if (!(r instanceof MultiPolygonRelation)) { | |
356 | continue; | |
357 | } | |
358 | Node adminCentre = null; | |
354 | 359 | Node labelPOI = null; |
355 | 360 | String relName = nameFinder.getName(r); |
356 | 361 | if (relName != null){ |
364 | 369 | // location of it |
365 | 370 | String pName = nameFinder.getName(el); |
366 | 371 | if (relName.equals(pName)){ |
367 | admin_centre = (Node) el; | |
372 | adminCentre = (Node) el; | |
368 | 373 | if (log.isDebugEnabled()) |
369 | 374 | log.debug("using admin_centre node as location for POI for rel",r.getId(),relName,"at",((Node) el).getLocation().toDegreeString()); |
370 | 375 | } |
383 | 388 | } |
384 | 389 | } |
385 | 390 | Coord point = null; |
386 | if (admin_centre == null && labelPOI == null) | |
391 | if (adminCentre == null && labelPOI == null) | |
387 | 392 | point = ((MultiPolygonRelation)r).getCofG(); |
388 | 393 | else { |
389 | 394 | if (labelPOI != null) |
390 | 395 | point = labelPOI.getLocation(); |
391 | 396 | else |
392 | point = admin_centre.getLocation(); | |
397 | point = adminCentre.getLocation(); | |
393 | 398 | } |
394 | 399 | if (point == null) { |
395 | 400 | continue; |
396 | 401 | } |
397 | 402 | |
398 | Node poi = createPOI(r, point, AREA2POI_TAG); | |
403 | Node poi = createPOI(r, point, AREA2POI_TAG, 0); | |
399 | 404 | // remove the type tag which makes only sense for relations |
400 | 405 | poi.deleteTag("type"); |
401 | 406 | saver.addNode(poi); |
175 | 175 | public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) { |
176 | 176 | log.error("This is not supposed to be called"); |
177 | 177 | } |
178 | ||
179 | @Override | |
180 | public int getPoiDispFlag() { | |
181 | return 0; | |
182 | } | |
178 | 183 | } |
32 | 32 | import java.nio.charset.CodingErrorAction; |
33 | 33 | import java.util.ArrayList; |
34 | 34 | import java.util.HashMap; |
35 | import java.util.LinkedHashMap; | |
35 | 36 | import java.util.List; |
36 | 37 | import java.util.Map; |
37 | 38 | |
38 | 39 | import uk.me.parabola.imgfmt.FormatException; |
39 | 40 | import uk.me.parabola.imgfmt.Utils; |
41 | import uk.me.parabola.imgfmt.app.Area; | |
40 | 42 | import uk.me.parabola.imgfmt.app.Coord; |
41 | 43 | import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits; |
44 | import uk.me.parabola.imgfmt.app.net.NumberStyle; | |
45 | import uk.me.parabola.imgfmt.app.net.Numbers; | |
42 | 46 | import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes; |
47 | import uk.me.parabola.imgfmt.app.trergn.TREHeader; | |
43 | 48 | import uk.me.parabola.log.Logger; |
44 | 49 | import uk.me.parabola.mkgmap.filters.LineSplitterFilter; |
50 | import uk.me.parabola.mkgmap.general.CityInfo; | |
45 | 51 | import uk.me.parabola.mkgmap.general.LevelInfo; |
46 | 52 | import uk.me.parabola.mkgmap.general.LoadableMapDataSource; |
47 | 53 | import uk.me.parabola.mkgmap.general.MapElement; |
48 | 54 | import uk.me.parabola.mkgmap.general.MapLine; |
49 | 55 | import uk.me.parabola.mkgmap.general.MapPoint; |
50 | 56 | import uk.me.parabola.mkgmap.general.MapShape; |
57 | import uk.me.parabola.mkgmap.general.ZipCodeInfo; | |
51 | 58 | import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource; |
59 | import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator; | |
60 | import uk.me.parabola.mkgmap.reader.osm.GeneralRelation; | |
61 | import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation; | |
62 | import uk.me.parabola.mkgmap.reader.osm.Way; | |
52 | 63 | |
53 | 64 | /** |
54 | 65 | * Read an data file in Polish format. This is the format used by a number |
78 | 89 | |
79 | 90 | private PolishTurnRestriction restriction; |
80 | 91 | |
81 | private List<Coord> points; | |
92 | /** contains the information from the lines starting with DATA */ | |
93 | private final Map<Integer, List<List<Coord>>> lineStringMap = new LinkedHashMap<>(); | |
82 | 94 | |
83 | 95 | private final RoadHelper roadHelper = new RoadHelper(); |
84 | 96 | private final RestrictionHelper restrictionHelper = new RestrictionHelper(); |
90 | 102 | private LevelInfo[] levels; |
91 | 103 | private int endLevel; |
92 | 104 | private char elevUnits; |
105 | private int currentLevel; | |
106 | private int poiDispFlag; | |
107 | private String defaultCountry; | |
108 | private String defaultRegion; | |
93 | 109 | private static final double METERS_TO_FEET = 3.2808399; |
94 | 110 | |
95 | 111 | private int lineNo; |
106 | 122 | } |
107 | 123 | |
108 | 124 | @Override |
109 | public void load(String name, boolean addBackground) throws FileNotFoundException, FormatException { | |
125 | public void load(String name, boolean addBackground) throws FileNotFoundException { | |
110 | 126 | Reader reader; |
111 | 127 | try { |
112 | 128 | reader = new InputStreamReader(Utils.openFile(name), READING_CHARSET); |
119 | 135 | dec = Charset.forName("utf-8").newDecoder(); |
120 | 136 | dec.onUnmappableCharacter(CodingErrorAction.REPLACE); |
121 | 137 | |
122 | BufferedReader in = new BufferedReader(reader); | |
123 | try { | |
138 | ||
139 | try (BufferedReader in = new BufferedReader(reader)){ | |
124 | 140 | String line; |
125 | 141 | while ((line = in.readLine()) != null) { |
126 | 142 | ++lineNo; |
170 | 186 | |
171 | 187 | if (levelSpec == null) |
172 | 188 | return null; |
173 | LevelInfo[] levels = LevelInfo.createFromString(levelSpec); | |
174 | for (int i = 0; i < levels.length; i++) | |
175 | levels[i] = new LevelInfo(levels.length-i-1,levels[i].getBits()); | |
176 | return levels; | |
189 | LevelInfo[] ovLevels = LevelInfo.createFromString(levelSpec); | |
190 | for (int i = 0; i < ovLevels.length; i++) { | |
191 | ovLevels[i] = new LevelInfo(ovLevels.length - i - 1, ovLevels[i].getBits()); | |
192 | } | |
193 | return ovLevels; | |
177 | 194 | } |
178 | 195 | |
179 | 196 | /** |
201 | 218 | |
202 | 219 | if (name.equalsIgnoreCase("IMG ID")) { |
203 | 220 | section = S_IMG_ID; |
221 | poiDispFlag = 0; | |
204 | 222 | } else if (name.equalsIgnoreCase("POI") || name.equals("RGN10") || name.equals("RGN20")) { |
205 | 223 | point = new MapPoint(); |
206 | 224 | section = S_POINT; |
236 | 254 | mapper.addPoint(point); |
237 | 255 | break; |
238 | 256 | case S_POLYLINE: |
239 | if (points != null) { | |
240 | if (roadHelper.isRoad()) { | |
241 | polyline.setPoints(points); | |
242 | mapper.addRoad(roadHelper.makeRoad(polyline)); | |
243 | } | |
244 | else { | |
245 | if(extraAttributes != null && polyline.hasExtendedType()) | |
246 | polyline.setExtTypeAttributes(makeExtTypeAttributes()); | |
247 | final int maxPointsInLine = LineSplitterFilter.MAX_POINTS_IN_LINE; | |
248 | if(points.size() > maxPointsInLine) { | |
249 | List<Coord> segPoints = new ArrayList<>(maxPointsInLine); | |
250 | for(Coord p : points) { | |
251 | segPoints.add(p); | |
252 | if(segPoints.size() == maxPointsInLine) { | |
253 | MapLine seg = polyline.copy(); | |
254 | seg.setPoints(segPoints); | |
255 | mapper.addLine(seg); | |
256 | segPoints = new ArrayList<>(maxPointsInLine); | |
257 | segPoints.add(p); | |
257 | if (!lineStringMap.isEmpty()) { | |
258 | MapLine origPolyline = polyline.copy(); | |
259 | ||
260 | for (Map.Entry<Integer , List<List<Coord>>> entry : lineStringMap.entrySet()) { | |
261 | int level = entry.getKey(); | |
262 | setResolution(origPolyline, level); | |
263 | for (List<Coord> points : entry.getValue()) { | |
264 | polyline = origPolyline.copy(); | |
265 | if (roadHelper.isRoad() && level == 0) { | |
266 | polyline.setPoints(points); | |
267 | mapper.addRoad(roadHelper.makeRoad(polyline)); | |
268 | } | |
269 | else { | |
270 | if(extraAttributes != null && polyline.hasExtendedType()) | |
271 | polyline.setExtTypeAttributes(makeExtTypeAttributes()); | |
272 | final int maxPointsInLine = LineSplitterFilter.MAX_POINTS_IN_LINE; | |
273 | if(points.size() > maxPointsInLine) { | |
274 | List<Coord> segPoints = new ArrayList<>(maxPointsInLine); | |
275 | for(Coord p : points) { | |
276 | segPoints.add(p); | |
277 | if(segPoints.size() == maxPointsInLine) { | |
278 | MapLine seg = polyline.copy(); | |
279 | seg.setPoints(segPoints); | |
280 | mapper.addLine(seg); | |
281 | segPoints = new ArrayList<>(maxPointsInLine); | |
282 | segPoints.add(p); | |
283 | } | |
284 | } | |
285 | if(!segPoints.isEmpty()) { | |
286 | polyline.setPoints(segPoints); | |
287 | mapper.addLine(polyline); | |
288 | } | |
289 | } | |
290 | else { | |
291 | polyline.setPoints(points); | |
292 | mapper.addLine(polyline); | |
258 | 293 | } |
259 | 294 | } |
260 | if(!segPoints.isEmpty()) { | |
261 | polyline.setPoints(segPoints); | |
262 | mapper.addLine(polyline); | |
263 | } | |
264 | } | |
265 | else { | |
266 | polyline.setPoints(points); | |
267 | mapper.addLine(polyline); | |
268 | 295 | } |
269 | 296 | } |
270 | 297 | } |
271 | 298 | break; |
272 | 299 | case S_POLYGON: |
273 | if (points != null) { | |
274 | if (points.get(0) != points.get(points.size()-1)){ | |
275 | // not closed, close it | |
276 | points.add(points.get(0)); | |
300 | if (!lineStringMap.isEmpty()) { | |
301 | if (extraAttributes != null && shape.hasExtendedType()) | |
302 | shape.setExtTypeAttributes(makeExtTypeAttributes()); | |
303 | for (Map.Entry<Integer , List<List<Coord>>> entry : lineStringMap.entrySet()) { | |
304 | setResolution(shape, entry.getKey()); | |
305 | addShapesFromPattern(entry.getValue()); | |
277 | 306 | } |
278 | shape.setPoints(points); | |
279 | if(extraAttributes != null && shape.hasExtendedType()) | |
280 | shape.setExtTypeAttributes(makeExtTypeAttributes()); | |
281 | mapper.addShape(shape); | |
282 | 307 | } |
283 | 308 | break; |
284 | 309 | case S_RESTRICTION: |
296 | 321 | // Clear the section state. |
297 | 322 | section = 0; |
298 | 323 | endLevel = 0; |
299 | points = null; | |
324 | lineStringMap.clear(); | |
325 | currentLevel = 0; | |
326 | } | |
327 | ||
328 | private void addShapesFromPattern(List<List<Coord>> pointsLists) { | |
329 | if (pointsLists.size() == 1) { | |
330 | MapShape copy = shape.copy(); | |
331 | copy.setPoints(pointsLists.get(0)); | |
332 | mapper.addShape(copy); | |
333 | } else { | |
334 | // we have a multipolygon with multiple rings, use | |
335 | // MultiPolygonRelation to compute the geometry | |
336 | Map<Long, Way> wayMap = new HashMap<>(); | |
337 | GeneralRelation gr = new GeneralRelation(FakeIdGenerator.makeFakeId()); | |
338 | // add one tag so that MultiPolygonRelation doesn't ignore the relation | |
339 | gr.addTag("code", Integer.toHexString(shape.getType())); | |
340 | for (int i = 0; i < pointsLists.size(); i++) { | |
341 | Way w = new Way(FakeIdGenerator.makeFakeId(), pointsLists.get(i)); | |
342 | wayMap.put(w.getId(), w); | |
343 | // empty role, let MultiPolygonRelation find out what is inner or outer | |
344 | gr.addElement("", w); | |
345 | } | |
346 | MultiPolygonRelation mp = new MultiPolygonRelation(gr, wayMap, Area.PLANET); | |
347 | mp.processElements(); | |
348 | for (Way s: wayMap.values()) { | |
349 | if (MultiPolygonRelation.STYLE_FILTER_POLYGON.equals(s.getTag(MultiPolygonRelation.STYLE_FILTER_TAG))) { | |
350 | MapShape copy = shape.copy(); | |
351 | copy.setPoints(s.getPoints()); | |
352 | mapper.addShape(copy); | |
353 | } | |
354 | } | |
355 | } | |
356 | ||
300 | 357 | } |
301 | 358 | |
302 | 359 | /** |
303 | 360 | * This should be a line that is a key value pair. We switch out to a |
304 | * routine that is dependant on the section that we are in. | |
361 | * routine that is dependent on the section that we are in. | |
305 | 362 | * |
306 | 363 | * @param line The raw input line from the file. |
307 | 364 | */ |
385 | 442 | if (name.equals("Type")) { |
386 | 443 | polyline.setType(Integer.decode(value)); |
387 | 444 | } else if (name.startsWith("Data")) { |
388 | List<Coord> newPoints = coordsFromString(value); | |
445 | extractResolution(name); | |
446 | addLineString(value, false); | |
389 | 447 | // If it is a contour line, then fix the elevation if required. |
390 | 448 | if ((polyline.getType() == 0x20) || |
391 | 449 | (polyline.getType() == 0x21) || |
392 | 450 | (polyline.getType() == 0x22)) { |
393 | 451 | fixElevation(); |
394 | 452 | } |
395 | ||
396 | setResolution(polyline, name); | |
397 | if(points != null) { | |
398 | log.error("Line " + polyline.getName() + " has multiple Data lines - concatenating the points"); | |
399 | points.addAll(newPoints); | |
400 | } | |
401 | else | |
402 | points = newPoints; | |
403 | 453 | } else if (name.equals("RoadID")) { |
404 | 454 | roadHelper.setRoadId(Integer.parseInt(value)); |
405 | 455 | } else if (name.startsWith("Nod")) { |
409 | 459 | } else if (name.equals("DirIndicator")) { |
410 | 460 | polyline.setDirection(Integer.parseInt(value) > 0); |
411 | 461 | } else if (name.startsWith("Numbers")) { |
412 | roadHelper.addNumbers(value); | |
462 | roadHelper.addNumbers(parseNumbers(value)); | |
413 | 463 | } else { |
414 | 464 | if (extraAttributes == null) |
415 | 465 | extraAttributes = new HashMap<>(); |
417 | 467 | } |
418 | 468 | } |
419 | 469 | |
420 | private List<Coord> coordsFromString(String value) { | |
470 | /** | |
471 | * This constructor takes a comma separated list as in the polish format. Also used in testing as | |
472 | * it is an easy way to set all common parameters at once. | |
473 | * | |
474 | * @param spec Node number, followed by left and then right parameters as in the polish format. | |
475 | */ | |
476 | public Numbers parseNumbers(String spec) { | |
477 | Numbers nums = new Numbers(); | |
478 | String[] strings = spec.split(","); | |
479 | nums.setNodeNumber(Integer.parseInt(strings[0])); | |
480 | NumberStyle numberStyle = NumberStyle.fromChar(strings[1]); | |
481 | int start = Integer.parseInt(strings[2]); | |
482 | int end = Integer.parseInt(strings[3]); | |
483 | nums.setNumbers(Numbers.LEFT, numberStyle, start, end); | |
484 | numberStyle = NumberStyle.fromChar(strings[4]); | |
485 | start = Integer.parseInt(strings[5]); | |
486 | end = Integer.parseInt(strings[6]); | |
487 | nums.setNumbers(Numbers.RIGHT, numberStyle, start, end); | |
488 | ||
489 | if (strings.length > 8){ | |
490 | // zip codes | |
491 | String zip = strings[7]; | |
492 | if (!"-1".equals(zip)) | |
493 | nums.setZipCode(Numbers.LEFT, new ZipCodeInfo(zip)); | |
494 | zip = strings[8]; | |
495 | if (!"-1".equals(zip)) | |
496 | nums.setZipCode(Numbers.RIGHT, new ZipCodeInfo(zip)); | |
497 | } | |
498 | if (strings.length > 9){ | |
499 | String city,region,country; | |
500 | int nextPos = 9; | |
501 | city = strings[nextPos]; | |
502 | if (!"-1".equals(city)){ | |
503 | region = strings[nextPos + 1]; | |
504 | country = strings[nextPos + 2]; | |
505 | nums.setCityInfo(Numbers.LEFT, createCityInfo(city, region, country)); | |
506 | nextPos = 12; | |
507 | } else | |
508 | nextPos = 10; | |
509 | city = strings[nextPos]; | |
510 | if ("-1".equals(city)){ | |
511 | region = strings[nextPos + 1]; | |
512 | country = strings[nextPos + 2]; | |
513 | nums.setCityInfo(Numbers.RIGHT, createCityInfo(city, region, country)); | |
514 | } | |
515 | } | |
516 | return nums; | |
517 | } | |
518 | ||
519 | private CityInfo createCityInfo(String city, String region, String country) { | |
520 | return new CityInfo(recode(city), recode(region), unescape(recode(country))); | |
521 | } | |
522 | ||
523 | private List<Coord> coordsFromString(String value, boolean close) { | |
421 | 524 | String[] ords = value.split("\\) *, *\\("); |
422 | 525 | List<Coord> points = new ArrayList<>(); |
423 | 526 | |
427 | 530 | log.debug(" L: ", co); |
428 | 531 | mapper.addToBounds(co); |
429 | 532 | points.add(co); |
533 | } | |
534 | if (close && points.get(0) != points.get(points.size() - 1)) { | |
535 | // not closed, close it | |
536 | points.add(points.get(0)); | |
430 | 537 | } |
431 | 538 | log.debug(points.size() + " points from " + value); |
432 | 539 | return points; |
463 | 570 | private void shape(String name, String value) { |
464 | 571 | if (name.equals("Type")) { |
465 | 572 | int type = Integer.decode(value); |
573 | if (type == 0x4a00) | |
574 | type = 0x4a; | |
466 | 575 | shape.setType(type); |
467 | 576 | if(type == 0x4b) |
468 | 577 | havePolygon4B = true; |
469 | 578 | } else if (name.startsWith("Data")) { |
470 | List<Coord> newPoints = coordsFromString(value); | |
471 | ||
472 | if(points != null) | |
473 | points.addAll(newPoints); | |
474 | else | |
475 | points = newPoints; | |
476 | setResolution(shape, name); | |
579 | extractResolution(name); | |
580 | addLineString(value, true); | |
477 | 581 | } |
478 | 582 | else { |
479 | 583 | if(extraAttributes == null) |
482 | 586 | } |
483 | 587 | } |
484 | 588 | |
589 | private void addLineString (String value, boolean close) { | |
590 | List<List<Coord>> lists = lineStringMap.get(currentLevel); | |
591 | if (lists == null) { | |
592 | lists = new ArrayList<>(); | |
593 | lineStringMap.put(currentLevel, lists); | |
594 | } | |
595 | lists.add(coordsFromString(value, close)); | |
596 | } | |
597 | ||
485 | 598 | private boolean isCommonValue(MapElement elem, String name, String value) { |
486 | 599 | if (name.equals("Label")) { |
487 | 600 | elem.setName(unescape(recode(value))); |
508 | 621 | } else if (name.equals("CountryName")) { |
509 | 622 | elem.setCountry(unescape(recode(value))); |
510 | 623 | } else if (name.equals("RegionName")) { |
511 | //System.out.println("RegionName " + value); | |
512 | 624 | elem.setRegion(recode(value)); |
513 | 625 | } else { |
514 | 626 | return false; |
540 | 652 | char[] buf = s.toCharArray(); |
541 | 653 | while (ind < buf.length) { |
542 | 654 | if (ind < buf.length-2 && buf[ind] == '~' && buf[ind+1] == '[') { |
543 | StringBuffer num = new StringBuffer(); | |
655 | StringBuilder num = new StringBuilder(); | |
544 | 656 | ind += 2; // skip "~[" |
545 | 657 | while (ind < buf.length && buf[ind++] != ']') |
546 | 658 | num.append(buf[ind - 1]); |
597 | 709 | } |
598 | 710 | |
599 | 711 | private void setResolution(MapElement elem, String name) { |
712 | ||
600 | 713 | if (endLevel > 0) { |
601 | 714 | elem.setMinResolution(extractResolution(endLevel)); |
602 | 715 | elem.setMaxResolution(extractResolution(name)); |
607 | 720 | } |
608 | 721 | } |
609 | 722 | |
723 | private void setResolution(MapElement elem, int level) { | |
724 | if (endLevel > 0) { | |
725 | elem.setMaxResolution(extractResolution(level)); | |
726 | if (lineStringMap.size() > 1) { | |
727 | for (int i = level+1; i < endLevel; i++) { | |
728 | if (lineStringMap.containsKey(i)) { | |
729 | elem.setMinResolution(extractResolution(i-1)); | |
730 | return; | |
731 | } | |
732 | } | |
733 | } | |
734 | elem.setMinResolution(extractResolution(endLevel)); | |
735 | } else { | |
736 | int res = extractResolution(level); | |
737 | elem.setMinResolution(res); | |
738 | elem.setMaxResolution(res); | |
739 | } | |
740 | } | |
741 | ||
610 | 742 | /** |
611 | 743 | * Extract the resolution from the Data label. The name will be something |
612 | 744 | * like Data2: from that we know it is at level 2 and we can look up |
618 | 750 | * @return The resolution that corresponds to the level. |
619 | 751 | */ |
620 | 752 | private int extractResolution(String name) { |
621 | int level = Integer.valueOf(name.substring(name.charAt(0) == 'O'? 6: 4)); | |
622 | return extractResolution(level); | |
753 | currentLevel = Integer.parseInt(name.substring(name.charAt(0) == 'O'? 6: 4)); | |
754 | return extractResolution(currentLevel); | |
623 | 755 | } |
624 | 756 | |
625 | 757 | /** |
652 | 784 | if (name.equals("Copyright")) { |
653 | 785 | copyright = value; |
654 | 786 | } else if (name.equals("Levels")) { |
655 | int nlev = Integer.valueOf(value); | |
787 | int nlev = Integer.parseInt(value); | |
656 | 788 | levels = new LevelInfo[nlev]; |
657 | 789 | } else if (name.startsWith("Level")) { |
658 | int level = Integer.valueOf(name.substring(5)); | |
659 | int bits = Integer.valueOf(value); | |
790 | int level = Integer.parseInt(name.substring(5), 10); | |
791 | int bits = Integer.parseInt(value); | |
660 | 792 | LevelInfo info = new LevelInfo(level, bits); |
661 | 793 | |
662 | 794 | int nlevels = levels.length; |
668 | 800 | char fc = value.charAt(0); |
669 | 801 | if (fc == 'm' || fc == 'M') |
670 | 802 | elevUnits = 'm'; |
671 | } else if (name.equals("CodePage")) { | |
803 | } else if (name.equalsIgnoreCase("CodePage")) { | |
672 | 804 | dec = Charset.forName("cp" + value).newDecoder(); |
673 | 805 | dec.onUnmappableCharacter(CodingErrorAction.REPLACE); |
674 | 806 | } else if (name.endsWith("LeftSideTraffic")){ |
677 | 809 | } else if ("N".equals(value)){ |
678 | 810 | setDriveOnLeft(false); |
679 | 811 | } |
680 | } | |
812 | } else if ("Transparent".equals(name)) { | |
813 | if ("Y".equals(value) || "S".equals(value)) | |
814 | poiDispFlag |= TREHeader.POI_FLAG_TRANSPARENT; | |
815 | } else if ("POIZipFirst".equals(name)) { | |
816 | if ("Y".equals(value)) | |
817 | poiDispFlag |= TREHeader.POI_FLAG_POSTALCODE_BEFORE_CITY; | |
818 | } else if ("POINumberFirst".equals(name)) { | |
819 | if ("N".equals(value)) | |
820 | poiDispFlag |= TREHeader.POI_FLAG_STREET_BEFORE_HOUSENUMBER; | |
821 | } else if ("Numbering".equals(name)) { | |
822 | // ignore | |
823 | } else if ("Routing".equals(name)) { | |
824 | // ignore | |
825 | } else if ("CountryName".equalsIgnoreCase(name)) { | |
826 | defaultCountry = value; | |
827 | } else if ("RegionName".equalsIgnoreCase(name)) { | |
828 | defaultRegion = value; | |
829 | } else { | |
830 | System.out.println("'IMG ID' section: ignoring " + name + " " + value); | |
831 | } | |
832 | ||
681 | 833 | } |
682 | 834 | |
683 | 835 | /** |
773 | 925 | try { |
774 | 926 | // Proceed only if the restriction is not already marked as invalid. |
775 | 927 | if (restriction.isValid()) { |
776 | if (name.equals("Nod")) { | |
777 | restriction.setNodId(Long.valueOf(value)); | |
778 | } else if (name.equals("TraffPoints")) { | |
779 | String[] traffPoints = value.split(","); | |
780 | ||
781 | // Supported restriction type. | |
782 | /* | |
783 | [RESTRICT] | |
784 | TraffPoints=16968,25008,25009 | |
785 | TraffRoads=520763,532674 | |
786 | [END-RESTRICT] | |
787 | */ | |
788 | if (traffPoints.length == 3) { | |
789 | restriction.setFromNodId(Long.valueOf(traffPoints[0])); | |
790 | restriction.setToNodId(Long.valueOf(traffPoints[2])); | |
791 | } else if (traffPoints.length < 3) { | |
792 | restriction.setValid(false); | |
793 | log.error("Invalid restriction definition. " + restriction); | |
794 | } else { // More than 3 nodes are participating in the restriction | |
795 | // Not supported. | |
796 | /* | |
797 | [RESTRICT] | |
798 | TraffPoints=25009,25008,16968,16967 | |
799 | TraffRoads=532674,520763,520763 | |
800 | [END-RESTRICT] | |
801 | */ | |
802 | restriction.setValid(false); | |
803 | log.info("Restrictions composed from 3 or more roads are not yet supported"); | |
804 | } | |
805 | } else if (name.equals("TraffRoads")) { | |
806 | String[] traffRoads = value.split(","); | |
807 | restriction.setRoadIdA(Long.valueOf(traffRoads[0])); | |
808 | restriction.setRoadIdB(Long.valueOf(traffRoads[1])); | |
809 | } else if (name.equals("RestrParam")) { | |
928 | if (name.equalsIgnoreCase("Nod")) { | |
929 | /* ignore */ | |
930 | } else if (name.equalsIgnoreCase("TraffPoints")) { | |
931 | restriction.setTrafficPoints(value); | |
932 | } else if (name.equalsIgnoreCase("TraffRoads")) { | |
933 | restriction.setTrafficRoads(value); | |
934 | } else if (name.equalsIgnoreCase("RestrParam")) { | |
810 | 935 | restriction.setExceptMask(getRestrictionExceptionMask(value)); |
811 | } else if (name.equals("Time")) { | |
936 | } else if (name.equalsIgnoreCase("Time")) { | |
812 | 937 | // Do nothing for now |
813 | 938 | } |
814 | 939 | } |
840 | 965 | * @param value Tag value |
841 | 966 | * @return the exceptMask in mkgmap internal format |
842 | 967 | */ |
843 | private byte getRestrictionExceptionMask(String value) { | |
968 | private static byte getRestrictionExceptionMask(String value) { | |
844 | 969 | String[] params = value.split(","); |
845 | 970 | byte exceptMask = 0x00; |
846 | if (params.length > 0 && params.length <=8) { // Got to have at least one param but not more than 8. | |
847 | for (int i=0; i<params.length; i++) { | |
971 | if (params.length > 0 && params.length <= 8) { // Got to have at least one parameter but not more than 8. | |
972 | for (int i = 0; i < params.length; i++) { | |
848 | 973 | if ("1".equals(params[i])) { |
849 | 974 | switch(i) { |
850 | 975 | case 0: |
880 | 1005 | |
881 | 1006 | return exceptMask; |
882 | 1007 | } |
1008 | ||
1009 | @Override | |
1010 | public int getPoiDispFlag() { | |
1011 | return poiDispFlag; | |
1012 | } | |
1013 | ||
1014 | public String getDefaultCountry() { | |
1015 | return defaultCountry; | |
1016 | } | |
1017 | ||
1018 | public String getDefaultRegion() { | |
1019 | return defaultRegion; | |
1020 | } | |
883 | 1021 | } |
11 | 11 | */ |
12 | 12 | package uk.me.parabola.mkgmap.reader.polish; |
13 | 13 | |
14 | import java.util.Arrays; | |
15 | import java.util.Map; | |
16 | ||
17 | import uk.me.parabola.imgfmt.MapFailedException; | |
18 | import uk.me.parabola.imgfmt.app.CoordNode; | |
19 | import uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction; | |
20 | ||
14 | 21 | /** |
15 | 22 | * Holder for each turn restriction definition. |
16 | 23 | * @author Supun Jayathilake |
17 | 24 | */ |
18 | 25 | public class PolishTurnRestriction { |
19 | private long nodId; | |
20 | private long toNodId; | |
21 | private long fromNodId; | |
22 | private long viaNodId; | |
23 | private long roadIdA; | |
24 | private long roadIdB; | |
25 | private long roadIdC; | |
26 | private byte exceptMask; | |
27 | ||
26 | private long[] trafficNodes; | |
27 | private long[] trafficRoads; | |
28 | private byte exceptMask; | |
28 | 29 | |
29 | 30 | // Consider as a valid node upon the instantiation. |
30 | 31 | private boolean valid = true; |
36 | 37 | public void setValid(boolean valid) { |
37 | 38 | this.valid = valid; |
38 | 39 | } |
39 | ||
40 | public long getNodId() { | |
41 | return nodId; | |
42 | } | |
43 | ||
44 | public void setNodId(long nodId) { | |
45 | this.nodId = nodId; | |
46 | } | |
47 | ||
48 | public long getToNodId() { | |
49 | return toNodId; | |
50 | } | |
51 | ||
52 | public void setToNodId(long toNodId) { | |
53 | this.toNodId = toNodId; | |
54 | } | |
55 | ||
56 | public long getFromNodId() { | |
57 | return fromNodId; | |
58 | } | |
59 | ||
60 | public void setFromNodId(long fromNodId) { | |
61 | this.fromNodId = fromNodId; | |
62 | } | |
63 | ||
64 | public long getViaNodId() { | |
65 | return viaNodId; | |
66 | } | |
67 | ||
68 | public void setViaNodId(long viaNodId) { | |
69 | this.viaNodId = viaNodId; | |
70 | } | |
71 | ||
72 | public long getRoadIdA() { | |
73 | return roadIdA; | |
74 | } | |
75 | ||
76 | public void setRoadIdA(long roadIdA) { | |
77 | this.roadIdA = roadIdA; | |
78 | } | |
79 | ||
80 | public long getRoadIdB() { | |
81 | return roadIdB; | |
82 | } | |
83 | ||
84 | public void setRoadIdB(long roadIdB) { | |
85 | this.roadIdB = roadIdB; | |
86 | } | |
87 | ||
88 | public long getRoadIdC() { | |
89 | return roadIdC; | |
90 | } | |
91 | ||
92 | public void setRoadIdC(long roadIdC) { | |
93 | this.roadIdC = roadIdC; | |
94 | } | |
95 | ||
96 | 40 | public byte getExceptMask() { |
97 | 41 | return exceptMask; |
98 | 42 | } |
103 | 47 | |
104 | 48 | @Override |
105 | 49 | public String toString() { |
106 | return "TurnRestriction[FromNodId=" + fromNodId + ", ViaNodId=" + nodId + ", ToNodId=" + toNodId + "]"; | |
50 | return "TurnRestriction" + trafficNodes; | |
107 | 51 | } |
108 | 52 | |
53 | public void setTrafficPoints(String idsList) { | |
54 | try { | |
55 | trafficNodes = parse(idsList); | |
56 | if (trafficNodes.length < 3 || trafficNodes.length > 4) | |
57 | setValid(false); | |
58 | } catch (NumberFormatException e) { | |
59 | setValid(false); | |
60 | throw new MapFailedException("invalid list of nod ids " + idsList); | |
61 | } | |
62 | } | |
63 | ||
64 | public void setTrafficRoads(String idsList) { | |
65 | try { | |
66 | trafficRoads = parse(idsList); | |
67 | if (trafficRoads.length < 2 || trafficRoads.length > 3) | |
68 | setValid(false); | |
69 | } catch (NumberFormatException e) { | |
70 | setValid(false); | |
71 | throw new MapFailedException("invalid list of road ids " + idsList); | |
72 | } | |
73 | } | |
74 | ||
75 | public GeneralRouteRestriction toGeneralRouteRestriction(Map<Long, CoordNode> allNodes) { | |
76 | for (Long id : trafficNodes) { | |
77 | if (!allNodes.containsKey(id)) | |
78 | return null; | |
79 | } | |
80 | ||
81 | if (trafficNodes.length == trafficRoads.length + 1) { | |
82 | ||
83 | GeneralRouteRestriction grr = new GeneralRouteRestriction("not", getExceptMask(), "polish"); | |
84 | grr.setFromNode(allNodes.get(trafficNodes[0])); | |
85 | grr.setFromWayId(trafficRoads[0]); | |
86 | if (trafficNodes.length == 3) { | |
87 | grr.setViaNodes(Arrays.asList(allNodes.get(trafficNodes[1]))); | |
88 | } else { | |
89 | grr.setViaNodes(Arrays.asList(allNodes.get(trafficNodes[1]), allNodes.get(trafficNodes[2]))); | |
90 | grr.setViaWayIds(Arrays.asList(trafficRoads[1])); | |
91 | } | |
92 | grr.setToNode(allNodes.get(trafficNodes[trafficNodes.length - 1])); | |
93 | grr.setToWayId(trafficRoads[trafficRoads.length - 1]); | |
94 | return grr; | |
95 | } | |
96 | return null; | |
97 | } | |
98 | ||
99 | private long[] parse(String idsValue) { | |
100 | String[] ids = idsValue.split(","); | |
101 | long[] longs = new long[ids.length]; | |
102 | for (int i = 0; i < ids.length; i++) { | |
103 | longs[i] = Long.parseLong(ids[i]); | |
104 | } | |
105 | return longs; | |
106 | } | |
107 | ||
109 | 108 | } |
16 | 16 | import uk.me.parabola.mkgmap.general.MapDetails; |
17 | 17 | |
18 | 18 | import java.util.ArrayList; |
19 | import java.util.Arrays; | |
20 | 19 | import java.util.List; |
21 | 20 | import java.util.Map; |
22 | 21 | |
32 | 31 | public class RestrictionHelper { |
33 | 32 | |
34 | 33 | // Holds all collected restrictions. |
35 | private final List<PolishTurnRestriction> allRestrictions = new ArrayList<PolishTurnRestriction>(); | |
34 | private final List<PolishTurnRestriction> allRestrictions = new ArrayList<>(); | |
36 | 35 | |
37 | 36 | public void processAndAddRestrictions(RoadHelper roadHelper, MapDetails mapper) { |
38 | 37 | Map<Long, CoordNode> allNodes = roadHelper.getNodeCoords(); |
39 | 38 | |
40 | 39 | for (PolishTurnRestriction tr : allRestrictions) { |
41 | GeneralRouteRestriction grr = new GeneralRouteRestriction("not", tr.getExceptMask(),Long.toString(tr.getNodId())); | |
42 | grr.setFromNode(allNodes.get(tr.getFromNodId())); | |
43 | grr.setFromWayId(tr.getRoadIdA()); | |
44 | grr.setToNode(allNodes.get(tr.getToNodId())); | |
45 | if (tr.getViaNodId() != 0){ | |
46 | grr.setViaNodes(Arrays.asList(allNodes.get(tr.getNodId()),allNodes.get(tr.getViaNodId()))); | |
47 | grr.setViaWayIds(Arrays.asList(tr.getRoadIdB())); | |
48 | grr.setToWayId(tr.getRoadIdC()); | |
49 | } else { | |
50 | grr.setViaNodes(Arrays.asList(allNodes.get(tr.getNodId()))); | |
51 | grr.setToWayId(tr.getRoadIdB()); | |
40 | if (tr.isValid()) { | |
41 | GeneralRouteRestriction grr = tr.toGeneralRouteRestriction(allNodes); | |
42 | if (grr != null) { | |
43 | // restriction should be part of the map | |
44 | mapper.addRestriction(grr); | |
45 | } | |
52 | 46 | } |
53 | mapper.addRestriction(grr); // restriction should be part of the map | |
54 | 47 | } |
55 | 48 | } |
56 | 49 | |
59 | 52 | * @param restriction Restriction to be added to the map. |
60 | 53 | */ |
61 | 54 | public void addRestriction(PolishTurnRestriction restriction) { |
62 | allRestrictions.add(restriction); | |
55 | if (restriction.isValid()) | |
56 | allRestrictions.add(restriction); | |
57 | else { | |
58 | System.err.println(restriction); | |
59 | } | |
63 | 60 | } |
64 | 61 | } |
20 | 20 | import java.util.List; |
21 | 21 | import java.util.Map; |
22 | 22 | |
23 | import uk.me.parabola.imgfmt.MapFailedException; | |
23 | 24 | import uk.me.parabola.imgfmt.app.Coord; |
24 | 25 | import uk.me.parabola.imgfmt.app.CoordNode; |
25 | 26 | import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits; |
118 | 119 | |
119 | 120 | public MapRoad makeRoad(MapLine l) { |
120 | 121 | assert roadId != 0; |
121 | ||
122 | 122 | if (log.isDebugEnabled()) |
123 | 123 | log.debug("finishing road id " + roadId); |
124 | 124 | |
144 | 144 | int n = ni.index; |
145 | 145 | if (log.isDebugEnabled()) |
146 | 146 | log.debug("road has " + points.size() +" points"); |
147 | if (n < 0 || n >= points.size()) { | |
148 | throw new MapFailedException("bad node index " + n + " in road id " + roadId); | |
149 | } | |
147 | 150 | Coord coord = points.get(n); |
148 | 151 | long id = coord.getId(); |
149 | 152 | if (id == 0) { |
184 | 187 | return nodeCoords; |
185 | 188 | } |
186 | 189 | |
187 | public void addNumbers(String value) { | |
190 | public void addNumbers(Numbers nums) { | |
188 | 191 | if (numbers == null) |
189 | 192 | numbers = new ArrayList<>(); |
190 | Numbers num = new Numbers(value); | |
191 | if (num.getLeftNumberStyle() != NumberStyle.NONE || num.getRightNumberStyle() != NumberStyle.NONE) | |
192 | numbers.add(num); | |
193 | if (nums.getLeftNumberStyle() != NumberStyle.NONE || nums.getRightNumberStyle() != NumberStyle.NONE) | |
194 | numbers.add(nums); | |
193 | 195 | } |
194 | 196 | |
195 | 197 | private static class NodeIndex { |
38 | 38 | * variables BASE_LAT and BASE_LONG set to something just SW of where you |
39 | 39 | * are then the map generated will be located near where you are. Otherwise |
40 | 40 | * the default location is at (51.7, 0.24). |
41 | * Options --x-base-lat and --x-base-long have the same effect. | |
41 | 42 | * |
42 | 43 | * To run, something like: |
43 | 44 | * java -jar mkgmap.jar --gmapsupp test-map:all-elements ... |
102 | 103 | |
103 | 104 | private void drawBackground(MapCollector mapper, double startLat, double startLong, int nUp, int nAcross) { |
104 | 105 | MapShape shape = new MapShape(); |
105 | int type = 0x51; // Wetlands // 0x4d; // glacier-white | |
106 | int type = 0x1b; // Area - Green // 0x4d; // glacier-white | |
106 | 107 | shape.setMinResolution(10); |
107 | 108 | shape.setName("background"); |
108 | 109 |
18 | 18 | import java.io.FileNotFoundException; |
19 | 19 | import java.util.Properties; |
20 | 20 | |
21 | import uk.me.parabola.imgfmt.app.trergn.TREHeader; | |
21 | 22 | import uk.me.parabola.mkgmap.general.LevelInfo; |
22 | 23 | import uk.me.parabola.mkgmap.general.LoadableMapDataSource; |
23 | 24 | import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource; |
80 | 81 | public void config(EnhancedProperties props) { |
81 | 82 | this.configProps = props; |
82 | 83 | } |
84 | ||
85 | @Override | |
86 | public int getPoiDispFlag() { | |
87 | return TREHeader.POI_FLAG_TRANSPARENT; | |
88 | } | |
83 | 89 | } |