Codebase list mkgmap / c8d5d62
New upstream version 0.0.0+svn4287 Bas Couwenberg 4 years ago
31 changed file(s) with 542 addition(s) and 346 deletion(s). Raw diff Collapse all Expand all
5858 </tstamp>
5959
6060 <!-- ivy dependency support -->
61 <property name="ivy.version" value="2.2.0"/>
61 <property name="ivy.version" value="2.4.0"/>
6262 <property name="ivy.lib.dir" value="${basedir}/lib" />
6363 <property name="ivy.jar.dir" value="${ivy.lib.dir}/build" />
6464 <property name="ivy.retrieve.pattern" value="${ivy.lib.dir}/[conf]/[artifact]-[revision].[ext]" />
3333 ;--read-config=filename
3434 : Each line of the named file contains a command option in the form
3535 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>
3740 Lines beginning with a # character are ignored and can be used as
3841 comments. Any command line option can be specified, however the
3942 leading '--' must be omitted. The short option names with a single
101104 gmapsupp.img file so that address search will work on a GPS
102105 device.
103106 <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.
113110 <p>
114111 If the map is sent to the device by MapSource, it will enable
115112 find by name and address search on the GPS.
796793 <p>
797794 ;--tdbfile
798795 : 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.
800797 <p>
801798 ;--show-profiles=1
802799 : Sets a flag in tdb file. The meaning depends on the availability of DEM
894891 points as the original that allows bicycle traffic. Also,
895892 bicycle traffic is prohibited from using the original way
896893 (unless that way's bicycle access has been defined).
897 </nowiki></div>
894 </nowiki></div>
116116 | +mkgmap:area2poi+ | The value is +true+ if the POI is derived from a polygon | 'add-pois-to-areas'
117117 | +mkgmap:line2poi+ | The value is +true+ if the POI is derived from a line | 'add-pois-to-lines'
118118 | +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'
119120 | +mkgmap:exit_hint+ | +true+ for the part on link roads that should contain information about the exit | 'process-exits'
120121 | +mkgmap:exit_hint_name+ | The +name+ tag value of the links exit node | 'process-exits'
121122 | +mkgmap:exit_hint_ref+ | The +ref+ tag value of the links exit node | 'process-exits'
2727 rev="6.5.15-mkg.1b"
2828 conf="compile->default(*)"
2929 />
30
31 <dependency org="javax.xml.bind" name="jaxb-api"
32 rev="2.3.0"
33 conf="test->default(*)"/>
3034
3135 <dependency org="junit" name="junit"
3236 rev="4.11"
3131 --read-config=filename
3232 Each line of the named file contains a command option in the form
3333 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.
3537 Lines beginning with a # character are ignored and can be used as
3638 comments. Any command line option can be specified, however the
3739 leading '--' must be omitted. The short option names with a single
100102 gmapsupp.img file so that address search will work on a GPS
101103 device.
102104
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.
112108
113109 If the map is sent to the device by MapSource, it will enable
114110 find by name and address search on the GPS.
809805
810806 --tdbfile
811807 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.
813809
814810 --show-profiles=1
815811 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
116116 highway=path & foot=designated
117117 {set highway=footway}
118118
119 leisure=track & area!=yes {add highway=footway; name '${name} (${sport})' | '${name}'}
119 leisure=track & area!=yes {name '${name} (${sport})' | '${sport}'} [0x30 resolution 22]
120120 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']
121123
122124 # Roundabouts
123125 junction=roundabout & (highway=trunk | highway=trunk_link) [0x0c road_class=4 road_speed=2 resolution 24 continue]
154156 # Ways sorted roughly by descending order of class
155157 highway=motorway & mkgmap:fast_road=yes [0x01 road_class=4 road_speed=7 resolution 14]
156158 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]
158160 highway=motorway_link [0x09 road_class=4 road_speed=2 resolution 20]
159161
160162 highway=trunk & mkgmap:fast_road=yes [0x02 road_class=4 road_speed=5 resolution 15]
161163 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]
163165 highway=trunk_link [0x09 road_class=4 road_speed=2 resolution 20]
164166 highway=* & motorroad=yes [0x02 road_class=4 road_speed=4 resolution 18]
165167 highway=primary & mkgmap:fast_road=yes [0x03 road_class=4 road_speed=4 resolution 17]
166168 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]
169171 highway=primary_link & mkgmap:fast_road=yes [0x08 road_class=4 road_speed=1 resolution 21]
170172 highway=primary_link [0x08 road_class=3 road_speed=1 resolution 21]
171173 highway=secondary & mkgmap:fast_road=yes [0x04 road_class=3 road_speed=3 resolution 18]
197199 highway=service & (service=alley | service=driveway) [0x07 road_class=0 road_speed=0 resolution 23]
198200 highway=service [0x07 road_class=0 road_speed=2 resolution 22]
199201
200 highway=cycleway [0x07 road_class=0 road_speed=1 resolution 23]
202 highway=cycleway [0x11 road_class=0 road_speed=1 resolution 23]
201203
202204 # highway=footway is often an area as well, continue for polygon processing
203205 highway=footway {set tmp:stopMopUp=yes} [0x16 road_class=0 road_speed=0 resolution 23 continue with_actions]
250252 boundary=national [0x1e resolution 17]
251253 boundary=political [0x1c resolution 19]
252254
255 barrier=wall | barrier=fence | barrier=hedge | barrier=ditch {add name='${barrier|subst:"_=> "}'} [0x17 resolution 24]
256
253257 route=ferry & (toll=no | toll=false) {set mkgmap:toll=no}
254258 route=ferry {set mkgmap:numbers=false; set mkgmap:ferry=1; add mkgmap:toll=yes}
255259 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]
257261
258262 (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]
260264
261265 waterway=canal [0x1f resolution 21]
262266 waterway=river [0x1f resolution 18]
155155 amenity=taxi [0x2f17 resolution 24]
156156 amenity=telephone [0x2f12 resolution 24 default_name 'Telephone']
157157 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']
160159 amenity=townhall [0x3003 resolution 24]
161160 amenity=university [0x2c05 resolution 24]
162161 # amenity=zoo is superceded by tourism=zoo
265264 tourism=wilderness_hut [0x2b07 resolution 24 default_name 'wilderness hut']
266265 tourism=museum [0x2c02 resolution 24]
267266 tourism=picnic_site [0x4a00 resolution 24]
267 tourism=resort [0x2b04 resolution 24]
268268 tourism=theme_park [0x2c01 resolution 24]
269269 tourism=viewpoint {name '${name} - ${description}' | '${name}'} [0x2c04 resolution 24]
270270 tourism=wine_cellar [0x2c0a resolution 24]
328328 #amenity=fast_food & cuisine=* {add name='${cuisine|subst:"_=> "}'} [0x2a07 resolution 24]
329329 #amenity=fast_food [0x2a07 resolution 24]
330330
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]
333334
334335 landuse=basin | landuse=reservoir [0x650f resolution 24]
335336
3636 healthcare=hospital | amenity=hospital | amenity=clinic [0x0b resolution 22]
3737 healthcare=* | amenity=dentist | amenity=doctors | amenity=nursing_home [0x0b resolution 23]
3838
39 leisure=common [0x17 resolution 21]
40 leisure=garden [0x17 resolution 21]
39 leisure=common [0x1d resolution 21]
40 leisure=garden [0x20 resolution 21]
4141 leisure=golf_course [0x18 resolution 21]
4242 leisure=ice_rink [0x19 resolution 22]
4343 leisure=nature_reserve [0x16 resolution 19]
5656 shop=* {add name='${shop|subst:"_=> "}'} [0x08 resolution 22]
5757
5858 # 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]
6161 # 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]
6363
6464 # 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]
6666
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
6969
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]
7171
7272 landuse=basin [0x3f resolution 20]
7373 landuse=reservoir | (natural=water & water=reservoir) [0x3f resolution 20]
7777 natural=bay [0x3d resolution 18]
7878 natural=glacier [0x4d resolution 18]
7979 natural=marsh [0x51 resolution 20]
80 natural=tundra [0x52 resolution 18]
8081 natural=mud [0x51 resolution 20]
82 natural=beach | natural=sand [0x53 resolution 20]
8183 natural=wetland [0x51 resolution 20]
8284 natural=water & water=canal [0x48 resolution 22]
8385 natural=water & water=lock [0x4c resolution 22 default_name 'Lock']
9395
9496 landuse=allotments [0x4e resolution 21]
9597 landuse=cemetery | landuse=cemetary | amenity=grave_yard [0x1a resolution 21]
96 landuse=commercial [0x0c resolution 19]
98 landuse=commercial [0x0f resolution 19]
9799 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]
100103 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]
103106 landuse=military [0x04 resolution 19]
104107 landuse=quarry [0x0c resolution 19]
105108 landuse=recreation_ground [0x19 resolution 19]
106109 # dedicate resolution 24 for building=* instead of related landuse=*
107110 landuse=industrial [0x0c resolution 19-23]
108111 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]
111114 landuse=vineyard [0x4e resolution 20]
112115 landuse=orchard [0x4e resolution 20]
113116
114117 military=airfield [0x04 resolution 20]
115118 military=barracks [0x04 resolution 23]
116 military=danger_area [0x04 resolution 20]
119 military=danger_area [0x11 resolution 20]
117120 military=range [0x04 resolution 20]
118121
119122 natural=scrub [0x4f resolution 20]
120123 natural=wood [0x50 resolution 20]
121124
122125 # 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]
124127 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]
126129
127130 # 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]
129132
130133 # render small named islands
131134 place=island & name=* & area_size() < 1000000 [0x53 resolution 19]
206206 * @param val The value to write. Unsigned
207207 */
208208 public void putNu(int nBytes, int val) {
209 assert nBytes >= 1 && nBytes <= 4: nBytes;
209210 try {
210211 file.write(val);
211212 if (nBytes <= 1) {
3535 private List<Mdr5Record> cities = new ArrayList<>();
3636 private int maxCityIndex;
3737 private int localCitySize;
38 private int mdr20PointerSize = 0; // bytes for mdr20 pointer, or 0 if no mdr20
3839
3940 public Mdr5(MdrConfig config) {
4041 setConfig(config);
187188 }
188189
189190 public void writeSectData(ImgFileWriter writer) {
190 int size20 = getSizes().getMdr20Size();
191191 Mdr5Record lastCity = null;
192192 boolean hasString = hasFlag(0x8);
193193 boolean hasRegion = hasFlag(0x4);
216216 writer.put2u(region);
217217 if (hasString)
218218 putStringOffset(writer, city.getStringOffset());
219 writer.putNu(size20, city.getMdr20());
219 if (mdr20PointerSize > 0)
220 writer.putNu(mdr20PointerSize, city.getMdr20());
220221 }
221222 }
222223
238239 int size = sizes.getMapSize()
239240 + localCitySize
240241 + 3
241 + sizes.getMdr20Size();
242 + mdr20PointerSize;
242243 if (hasFlag(0x4))
243244 size += 2;
244245 if (hasFlag(0x8))
251252 }
252253
253254 /**
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
258264 * @return The value to be placed in the header.
259265 */
260266 public int getExtraValue() {
268274 val |= 0x08; // string
269275 }
270276 val |= 0x10;
271 val |= 0x100; // mdr20 present
277 if (getSizes().getNumberOfItems(20) > 0) {
278 mdr20PointerSize = getSizes().getMdr20Size();
279 val |= 0x100; // mdr20 present
280 }
272281 return val;
273282 }
274283
214214 public int getSize(int sect) {
215215 return sections[sect].getSizeForRecord();
216216 }
217
218 public int getNumberOfItems(int sect) {
219 return sections[sect].getNumberOfItems();
220 }
217221 }
218222 }
1212 package uk.me.parabola.imgfmt.app.net;
1313
1414 import java.io.ByteArrayOutputStream;
15 import java.util.Iterator;
1615 import java.util.List;
1716
1817 import uk.me.parabola.imgfmt.Utils;
115114 private int setup() {
116115 // Should we use the swapped default numbering style EVEN/ODD rather than
117116 // 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);
123118 if (numbers.isEmpty())
124119 throw new Abandon("no numbers");
125120
380380 // a bit more complex: determine the to-node and arc(s)
381381 RouteNode tn = null;
382382 int toId = 0;
383 List<RouteArc> toArcs = new ArrayList<>();
383 List<RouteArc> toArcs;
384384 if (grr.getToNode() != null){
385385 // polish input data provides id
386386 toId = grr.getToNode().getId();
389389 log.error(sourceDesc, "can't locate 'to' RouteNode with id", toId);
390390 return 0;
391391 }
392 toArcs = lastViaNode.getDirectArcsTo(tn, grr.getToWayId());
392393 } else {
393394 // we can have multiple arcs between last via node and to node. The
394395 // arcs can be on the same OSM way or on different OSM ways.
123123 for (ArgType a : arglist) {
124124 a.processArg();
125125 }
126
127 proc.endOptions(new CommandArgs(this.args));
126 if (arglist.getFilenameCount() > 0)
127 proc.endOptions(new CommandArgs(this.args));
128128 }
129129
130130
980980 private void processInfo(Map map, LoadableMapDataSource src) {
981981 // The bounds of the map.
982982 map.setBounds(src.getBounds());
983 if (src instanceof OverviewMapDataSource == false)
983 if (!(src instanceof OverviewMapDataSource))
984984 poiDisplayFlags |= TREHeader.POI_FLAG_DETAIL;
985985
986 if(poiDisplayFlags != 0) // POI requested alternate address notation
986 poiDisplayFlags |= src.getPoiDispFlag();
987
988 if(poiDisplayFlags != 0)
987989 map.addPoiDisplayFlags(poiDisplayFlags);
988990
989991 // You can add anything here.
2323 import java.util.ArrayList;
2424 import java.util.List;
2525 import java.util.Locale;
26 import java.util.Map;
2627
2728 import uk.me.parabola.imgfmt.Utils;
2829 import uk.me.parabola.mkgmap.CommandArgs;
3839 private String id;
3940 private int productId;
4041
41 private boolean hasIndex;
42 private final boolean hasIndex;
4243 private boolean hasTyp;
4344
4445 private final List<String> mapList = new ArrayList<>();
4546 private String typName;
47
48 public NsisBuilder(Map<String, Combiner> combinerMap) {
49 this.hasIndex = combinerMap.containsKey("mdx");
50 }
4651
4752 public void init(CommandArgs args) {
4853 int familyId = args.get("family-id", CommandArgs.DEFAULT_FAMILYID);
5964 licenseFilename = baseFilename + "_license.txt";
6065
6166 outputDir = args.getOutputDir();
62
63 hasIndex = args.exists("index");
6467 }
6568
6669 public void onMapEnd(FileInfo info) {
7376 File typFile = new File(info.getFilename());
7477 typName = typFile.getName();
7578 break;
76 case MDR_KIND:
77 hasIndex = true;
78 break;
79 case APP_KIND:
80 case GMAPSUPP_KIND:
81 case UNKNOWN_KIND:
79 default:
8280 break;
8381 }
8482 }
424424 /**
425425 * Add the prefix to the file name.
426426 * @param name filename
427 * @return filename of the corresponding overview img file
427 * @return filename of the corresponding overview img file (without a path)
428428 */
429429 public static String getOverviewImgName (String name){
430430 File f = new File(name);
431 return new File(f.getParent(),OverviewBuilder.OVERVIEW_PREFIX + f.getName()).getAbsolutePath();
431 return OverviewBuilder.OVERVIEW_PREFIX + f.getName();
432432 }
433433
434434 public static String getMapName(String name) {
9595 */
9696 public String[] copyrightMessages();
9797
98 public int getPoiDispFlag();
9899 }
6262 public long getFullArea() { // this is unadulterated size, +ve if clockwise
6363 if (this.fullArea == Long.MAX_VALUE) {
6464 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)))
6666 this.fullArea = ShapeMergeFilter.calcAreaSizeTestVal(points);
6767 }
6868 return this.fullArea;
1818 import java.io.InputStream;
1919 import java.io.InputStreamReader;
2020 import java.io.PrintStream;
21 import java.lang.OutOfMemoryError;
2221 import java.lang.management.ManagementFactory;
2322 import java.lang.management.MemoryPoolMXBean;
2423 import java.lang.management.MemoryType;
2524 import java.lang.management.MemoryUsage;
25 import java.nio.file.Files;
2626 import java.time.Duration;
2727 import java.time.Instant;
2828 import java.util.ArrayList;
637637 String fileName = file.getFilename();
638638 if (!fileName.endsWith(".img"))
639639 continue;
640 fileName = OverviewBuilder.getOverviewImgName(fileName);
640 File f1 = new File(fileName);
641 fileName = new File(f1.getParent(), OverviewBuilder.getOverviewImgName(fileName)).getAbsolutePath();
642
641643 log.info(" " + fileName);
644
642645 FileInfo fileInfo = FileInfo.getFileInfo(fileName);
646
643647 fileInfo.setArgs(file.getArgs());
644648 // add the real input file
645649 foundOvmFiles.add(file.getFilename());
677681 c.onFinish();
678682
679683 if (tdbBuilderAdded && args.getProperties().getProperty("remove-ovm-work-files", false)){
680 for (String fName:foundOvmFiles){
684 for (String fName : foundOvmFiles) {
681685 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 }
684695 }
685696 }
686697 }
690701 boolean gmapsuppOpt = args.exists("gmapsupp");
691702 boolean tdbOpt = args.exists("tdbfile");
692703 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 }
694711 if (tdbOpt || createTdbFiles){
695712 addTdbBuilder();
696 }
697 if (args.exists("nsis")) {
698 addCombiner("nsis", new NsisBuilder());
699713 }
700714 if (gmapsuppOpt) {
701715 GmapsuppBuilder gmapBuilder = new GmapsuppBuilder();
704718 addCombiner("gmapsupp", gmapBuilder);
705719 }
706720
707 if (indexOpt && (tdbOpt || !gmapsuppOpt)) {
721 if (indexOpt && (tdbOpt || !gmapsuppOpt || gmapiOpt || nsisOpt)) {
708722 addCombiner("mdr", new MdrBuilder());
709723 addCombiner("mdx", new MdxBuilder());
710724 }
711
712725 if (gmapiOpt) {
713726 addCombiner("gmapi", new GmapiBuilder(combinerMap));
714727 }
728 if (nsisOpt) {
729 addCombiner("nsis", new NsisBuilder(combinerMap));
730 }
731
715732 }
716733
717734 /**
1717
1818 import java.io.File;
1919 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.nio.file.Files;
2022
2123 import uk.me.parabola.imgfmt.FileExistsException;
2224 import uk.me.parabola.imgfmt.FileNotWritableException;
5557 makeMap(args, src, OverviewBuilder.OVERVIEW_PREFIX);
5658 } else {
5759 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());
6468 }
6569 }
6670 }
123127 * @param map The map to modify.
124128 * @param args The command line arguments.
125129 */
126 private void setOptions(Map map, CommandArgs args) {
130 private static void setOptions(Map map, CommandArgs args) {
127131 map.config(args.getProperties());
128132
129133 String s = args.getCharset();
144148 * @throws FileNotFoundException For non existing files.
145149 * @throws FormatException When the file format is not valid.
146150 */
147 private LoadableMapDataSource loadFromFile(CommandArgs args, String name) throws
151 private static LoadableMapDataSource loadFromFile(CommandArgs args, String name) throws
148152 FileNotFoundException, FormatException
149153 {
150154 LoadableMapDataSource src = MapReader.createMapReader(name);
356356 public boolean isFileSupported(String name) {
357357 return true; // we always try xml reader if nothing else matched
358358 }
359
360 @Override
361 public int getPoiDispFlag() {
362 return 0; // no info in OSM data
363 }
359364 }
7575 public static final short AREA2POI_TAG = TagDict.getInstance().xlate("mkgmap:area2poi");
7676 public static final short LINE2POI_TAG = TagDict.getInstance().xlate("mkgmap:line2poi");
7777 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
7981 public boolean init(ElementSaver saver, EnhancedProperties props) {
8082 poisToAreas = props.containsKey("add-pois-to-areas");
8183 poisToLines = props.containsKey("add-pois-to-lines");
8284
83 if ((poisToAreas || poisToLines) == false) {
85 if (!(poisToAreas || poisToLines)) {
8486 log.info("Disable Areas2POIHook because add-pois-to-areas and add-pois-to-lines option is not set.");
8587 return false;
8688 }
99101 * @return the parsed tag definition list
100102 */
101103 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")) {
103105 return Collections.emptyList();
104106 }
105107
106 List<Entry<String,String>> tagList = new ArrayList<Entry<String,String>>();
108 List<Entry<String,String>> tagList = new ArrayList<>();
107109
108110 String placementDefs = props.getProperty("pois-to-areas-placement", "entrance=main;entrance=yes;building=entrance");
109111 placementDefs = placementDefs.trim();
141143 tagValue = null;
142144 }
143145 }
144 Entry<String,String> tag = new AbstractMap.SimpleImmutableEntry<String,String>(tagName, tagValue);
146 Entry<String,String> tag = new AbstractMap.SimpleImmutableEntry<>(tagName, tagValue);
145147 tagList.add(tag);
146148 }
147149 return tagList;
148150 }
149151
150152
153 @Override
151154 public Set<String> getUsedTags() {
152155 // return all tags defined in the poiPlacementTags
153 Set<String> tags = new HashSet<String>();
156 Set<String> tags = new HashSet<>();
154157 for (Entry<String,String> poiTag : poiPlacementTags) {
155158 tags.add(poiTag.getKey());
156159 }
157160 return tags;
158161 }
159162
163 @Override
160164 public void end() {
161165 log.info(getClass().getSimpleName(), "started");
162166 addPOIsForWays();
168172 for (int order = 0; order < poiPlacementTags.size(); order++) {
169173 Entry<String,String> poiTagDef = poiPlacementTags.get(order);
170174 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;
175177 }
176178 }
177179 // no poi tag match
179181 }
180182
181183 private void addPOIsForWays() {
182 Map<Coord, Integer> labelCoords = new IdentityHashMap<Coord, Integer>();
184 Map<Coord, Integer> labelCoords = new IdentityHashMap<>();
183185
184186 // save all coords with one of the placement tags to a map
185187 // so that ways use this coord as its labeling point
186 if (poiPlacementTags.isEmpty() == false && poisToAreas) {
188 if (!poiPlacementTags.isEmpty() && poisToAreas) {
187189 for (Node n : saver.getNodes().values()) {
188190 int order = getPlacementOrder(n);
189191 if (order >= 0) {
233235 }
234236
235237 private void addPOItoPolygon(Way polygon, Map<Coord, Integer> labelCoords) {
236 if (poisToAreas == false) {
238 if (!poisToAreas) {
237239 return;
238240 }
239241
265267 }
266268 // add tag mkgmap:cache_area_size to the original polygon so that it is copied to the POI
267269 areaSizeFunction.value(polygon);
268 Node poi = createPOI(polygon, poiCoord, AREA2POI_TAG);
270 Node poi = createPOI(polygon, poiCoord, AREA2POI_TAG, 0);
269271 saver.addNode(poi);
270272 }
271273
272274
273275 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);
275290 startNode.addTag(LINE2POI_TYPE_TAG,"start");
276291 saver.addNode(startNode);
277292
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);
279294 endNode.addTag(LINE2POI_TYPE_TAG,"end");
280295 saver.addNode(endNode);
281296
287302 continue;
288303 }
289304 lastPoint = inPoint;
290 Node innerNode = createPOI(line, inPoint, LINE2POI_TAG);
305 Node innerNode = createPOI(line, inPoint, LINE2POI_TAG, sumDist);
291306 innerNode.addTag(LINE2POI_TYPE_TAG,"inner");
292307 saver.addNode(innerNode);
293308 noPOIs++;
294309 }
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;
308310 }
309311
310312 Coord midPoint = null;
320322 }
321323
322324 if (midPoint != null) {
323 Node midNode = createPOI(line, midPoint, LINE2POI_TAG);
325 Node midNode = createPOI(line, midPoint, LINE2POI_TAG, sumDist);
324326 midNode.addTag(LINE2POI_TYPE_TAG,"mid");
325327 saver.addNode(midNode);
326328 noPOIs++;
329331
330332 }
331333
332 private static Node createPOI(Element source, Coord poiCoord, short poiTypeTagKey) {
334 private static Node createPOI(Element source, Coord poiCoord, short poiTypeTagKey, double wayLength) {
333335 Node poi = new Node(source.getOriginalId(), poiCoord);
334336 poi.setFakeId();
335337 poi.copyTags(source);
336338 poi.deleteTag(MultiPolygonRelation.STYLE_FILTER_TAG);
337339 poi.addTag(poiTypeTagKey, "true");
340 if (poiTypeTagKey == LINE2POI_TAG) {
341 poi.addTag(WAY_LENGTH_TAG, String.valueOf(Math.round(wayLength)));
342 }
338343 if (log.isDebugEnabled()) {
339344 log.debug("Create POI",poi.toTagString(),"from",source.getId(),source.toTagString());
340345 }
347352 for (Relation r : saver.getRelations().values()) {
348353
349354 // 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;
354359 Node labelPOI = null;
355360 String relName = nameFinder.getName(r);
356361 if (relName != null){
364369 // location of it
365370 String pName = nameFinder.getName(el);
366371 if (relName.equals(pName)){
367 admin_centre = (Node) el;
372 adminCentre = (Node) el;
368373 if (log.isDebugEnabled())
369374 log.debug("using admin_centre node as location for POI for rel",r.getId(),relName,"at",((Node) el).getLocation().toDegreeString());
370375 }
383388 }
384389 }
385390 Coord point = null;
386 if (admin_centre == null && labelPOI == null)
391 if (adminCentre == null && labelPOI == null)
387392 point = ((MultiPolygonRelation)r).getCofG();
388393 else {
389394 if (labelPOI != null)
390395 point = labelPOI.getLocation();
391396 else
392 point = admin_centre.getLocation();
397 point = adminCentre.getLocation();
393398 }
394399 if (point == null) {
395400 continue;
396401 }
397402
398 Node poi = createPOI(r, point, AREA2POI_TAG);
403 Node poi = createPOI(r, point, AREA2POI_TAG, 0);
399404 // remove the type tag which makes only sense for relations
400405 poi.deleteTag("type");
401406 saver.addNode(poi);
175175 public void addThroughRoute(int junctionNodeId, long roadIdA, long roadIdB) {
176176 log.error("This is not supposed to be called");
177177 }
178
179 @Override
180 public int getPoiDispFlag() {
181 return 0;
182 }
178183 }
3232 import java.nio.charset.CodingErrorAction;
3333 import java.util.ArrayList;
3434 import java.util.HashMap;
35 import java.util.LinkedHashMap;
3536 import java.util.List;
3637 import java.util.Map;
3738
3839 import uk.me.parabola.imgfmt.FormatException;
3940 import uk.me.parabola.imgfmt.Utils;
41 import uk.me.parabola.imgfmt.app.Area;
4042 import uk.me.parabola.imgfmt.app.Coord;
4143 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;
4246 import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes;
47 import uk.me.parabola.imgfmt.app.trergn.TREHeader;
4348 import uk.me.parabola.log.Logger;
4449 import uk.me.parabola.mkgmap.filters.LineSplitterFilter;
50 import uk.me.parabola.mkgmap.general.CityInfo;
4551 import uk.me.parabola.mkgmap.general.LevelInfo;
4652 import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
4753 import uk.me.parabola.mkgmap.general.MapElement;
4854 import uk.me.parabola.mkgmap.general.MapLine;
4955 import uk.me.parabola.mkgmap.general.MapPoint;
5056 import uk.me.parabola.mkgmap.general.MapShape;
57 import uk.me.parabola.mkgmap.general.ZipCodeInfo;
5158 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;
5263
5364 /**
5465 * Read an data file in Polish format. This is the format used by a number
7889
7990 private PolishTurnRestriction restriction;
8091
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<>();
8294
8395 private final RoadHelper roadHelper = new RoadHelper();
8496 private final RestrictionHelper restrictionHelper = new RestrictionHelper();
90102 private LevelInfo[] levels;
91103 private int endLevel;
92104 private char elevUnits;
105 private int currentLevel;
106 private int poiDispFlag;
107 private String defaultCountry;
108 private String defaultRegion;
93109 private static final double METERS_TO_FEET = 3.2808399;
94110
95111 private int lineNo;
106122 }
107123
108124 @Override
109 public void load(String name, boolean addBackground) throws FileNotFoundException, FormatException {
125 public void load(String name, boolean addBackground) throws FileNotFoundException {
110126 Reader reader;
111127 try {
112128 reader = new InputStreamReader(Utils.openFile(name), READING_CHARSET);
119135 dec = Charset.forName("utf-8").newDecoder();
120136 dec.onUnmappableCharacter(CodingErrorAction.REPLACE);
121137
122 BufferedReader in = new BufferedReader(reader);
123 try {
138
139 try (BufferedReader in = new BufferedReader(reader)){
124140 String line;
125141 while ((line = in.readLine()) != null) {
126142 ++lineNo;
170186
171187 if (levelSpec == null)
172188 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;
177194 }
178195
179196 /**
201218
202219 if (name.equalsIgnoreCase("IMG ID")) {
203220 section = S_IMG_ID;
221 poiDispFlag = 0;
204222 } else if (name.equalsIgnoreCase("POI") || name.equals("RGN10") || name.equals("RGN20")) {
205223 point = new MapPoint();
206224 section = S_POINT;
236254 mapper.addPoint(point);
237255 break;
238256 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);
258293 }
259294 }
260 if(!segPoints.isEmpty()) {
261 polyline.setPoints(segPoints);
262 mapper.addLine(polyline);
263 }
264 }
265 else {
266 polyline.setPoints(points);
267 mapper.addLine(polyline);
268295 }
269296 }
270297 }
271298 break;
272299 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());
277306 }
278 shape.setPoints(points);
279 if(extraAttributes != null && shape.hasExtendedType())
280 shape.setExtTypeAttributes(makeExtTypeAttributes());
281 mapper.addShape(shape);
282307 }
283308 break;
284309 case S_RESTRICTION:
296321 // Clear the section state.
297322 section = 0;
298323 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
300357 }
301358
302359 /**
303360 * 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.
305362 *
306363 * @param line The raw input line from the file.
307364 */
385442 if (name.equals("Type")) {
386443 polyline.setType(Integer.decode(value));
387444 } else if (name.startsWith("Data")) {
388 List<Coord> newPoints = coordsFromString(value);
445 extractResolution(name);
446 addLineString(value, false);
389447 // If it is a contour line, then fix the elevation if required.
390448 if ((polyline.getType() == 0x20) ||
391449 (polyline.getType() == 0x21) ||
392450 (polyline.getType() == 0x22)) {
393451 fixElevation();
394452 }
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;
403453 } else if (name.equals("RoadID")) {
404454 roadHelper.setRoadId(Integer.parseInt(value));
405455 } else if (name.startsWith("Nod")) {
409459 } else if (name.equals("DirIndicator")) {
410460 polyline.setDirection(Integer.parseInt(value) > 0);
411461 } else if (name.startsWith("Numbers")) {
412 roadHelper.addNumbers(value);
462 roadHelper.addNumbers(parseNumbers(value));
413463 } else {
414464 if (extraAttributes == null)
415465 extraAttributes = new HashMap<>();
417467 }
418468 }
419469
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) {
421524 String[] ords = value.split("\\) *, *\\(");
422525 List<Coord> points = new ArrayList<>();
423526
427530 log.debug(" L: ", co);
428531 mapper.addToBounds(co);
429532 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));
430537 }
431538 log.debug(points.size() + " points from " + value);
432539 return points;
463570 private void shape(String name, String value) {
464571 if (name.equals("Type")) {
465572 int type = Integer.decode(value);
573 if (type == 0x4a00)
574 type = 0x4a;
466575 shape.setType(type);
467576 if(type == 0x4b)
468577 havePolygon4B = true;
469578 } 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);
477581 }
478582 else {
479583 if(extraAttributes == null)
482586 }
483587 }
484588
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
485598 private boolean isCommonValue(MapElement elem, String name, String value) {
486599 if (name.equals("Label")) {
487600 elem.setName(unescape(recode(value)));
508621 } else if (name.equals("CountryName")) {
509622 elem.setCountry(unescape(recode(value)));
510623 } else if (name.equals("RegionName")) {
511 //System.out.println("RegionName " + value);
512624 elem.setRegion(recode(value));
513625 } else {
514626 return false;
540652 char[] buf = s.toCharArray();
541653 while (ind < buf.length) {
542654 if (ind < buf.length-2 && buf[ind] == '~' && buf[ind+1] == '[') {
543 StringBuffer num = new StringBuffer();
655 StringBuilder num = new StringBuilder();
544656 ind += 2; // skip "~["
545657 while (ind < buf.length && buf[ind++] != ']')
546658 num.append(buf[ind - 1]);
597709 }
598710
599711 private void setResolution(MapElement elem, String name) {
712
600713 if (endLevel > 0) {
601714 elem.setMinResolution(extractResolution(endLevel));
602715 elem.setMaxResolution(extractResolution(name));
607720 }
608721 }
609722
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
610742 /**
611743 * Extract the resolution from the Data label. The name will be something
612744 * like Data2: from that we know it is at level 2 and we can look up
618750 * @return The resolution that corresponds to the level.
619751 */
620752 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);
623755 }
624756
625757 /**
652784 if (name.equals("Copyright")) {
653785 copyright = value;
654786 } else if (name.equals("Levels")) {
655 int nlev = Integer.valueOf(value);
787 int nlev = Integer.parseInt(value);
656788 levels = new LevelInfo[nlev];
657789 } 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);
660792 LevelInfo info = new LevelInfo(level, bits);
661793
662794 int nlevels = levels.length;
668800 char fc = value.charAt(0);
669801 if (fc == 'm' || fc == 'M')
670802 elevUnits = 'm';
671 } else if (name.equals("CodePage")) {
803 } else if (name.equalsIgnoreCase("CodePage")) {
672804 dec = Charset.forName("cp" + value).newDecoder();
673805 dec.onUnmappableCharacter(CodingErrorAction.REPLACE);
674806 } else if (name.endsWith("LeftSideTraffic")){
677809 } else if ("N".equals(value)){
678810 setDriveOnLeft(false);
679811 }
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
681833 }
682834
683835 /**
773925 try {
774926 // Proceed only if the restriction is not already marked as invalid.
775927 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")) {
810935 restriction.setExceptMask(getRestrictionExceptionMask(value));
811 } else if (name.equals("Time")) {
936 } else if (name.equalsIgnoreCase("Time")) {
812937 // Do nothing for now
813938 }
814939 }
840965 * @param value Tag value
841966 * @return the exceptMask in mkgmap internal format
842967 */
843 private byte getRestrictionExceptionMask(String value) {
968 private static byte getRestrictionExceptionMask(String value) {
844969 String[] params = value.split(",");
845970 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++) {
848973 if ("1".equals(params[i])) {
849974 switch(i) {
850975 case 0:
8801005
8811006 return exceptMask;
8821007 }
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 }
8831021 }
1111 */
1212 package uk.me.parabola.mkgmap.reader.polish;
1313
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
1421 /**
1522 * Holder for each turn restriction definition.
1623 * @author Supun Jayathilake
1724 */
1825 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;
2829
2930 // Consider as a valid node upon the instantiation.
3031 private boolean valid = true;
3637 public void setValid(boolean valid) {
3738 this.valid = valid;
3839 }
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
9640 public byte getExceptMask() {
9741 return exceptMask;
9842 }
10347
10448 @Override
10549 public String toString() {
106 return "TurnRestriction[FromNodId=" + fromNodId + ", ViaNodId=" + nodId + ", ToNodId=" + toNodId + "]";
50 return "TurnRestriction" + trafficNodes;
10751 }
10852
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
109108 }
1616 import uk.me.parabola.mkgmap.general.MapDetails;
1717
1818 import java.util.ArrayList;
19 import java.util.Arrays;
2019 import java.util.List;
2120 import java.util.Map;
2221
3231 public class RestrictionHelper {
3332
3433 // Holds all collected restrictions.
35 private final List<PolishTurnRestriction> allRestrictions = new ArrayList<PolishTurnRestriction>();
34 private final List<PolishTurnRestriction> allRestrictions = new ArrayList<>();
3635
3736 public void processAndAddRestrictions(RoadHelper roadHelper, MapDetails mapper) {
3837 Map<Long, CoordNode> allNodes = roadHelper.getNodeCoords();
3938
4039 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 }
5246 }
53 mapper.addRestriction(grr); // restriction should be part of the map
5447 }
5548 }
5649
5952 * @param restriction Restriction to be added to the map.
6053 */
6154 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 }
6360 }
6461 }
2020 import java.util.List;
2121 import java.util.Map;
2222
23 import uk.me.parabola.imgfmt.MapFailedException;
2324 import uk.me.parabola.imgfmt.app.Coord;
2425 import uk.me.parabola.imgfmt.app.CoordNode;
2526 import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits;
118119
119120 public MapRoad makeRoad(MapLine l) {
120121 assert roadId != 0;
121
122122 if (log.isDebugEnabled())
123123 log.debug("finishing road id " + roadId);
124124
144144 int n = ni.index;
145145 if (log.isDebugEnabled())
146146 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 }
147150 Coord coord = points.get(n);
148151 long id = coord.getId();
149152 if (id == 0) {
184187 return nodeCoords;
185188 }
186189
187 public void addNumbers(String value) {
190 public void addNumbers(Numbers nums) {
188191 if (numbers == null)
189192 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);
193195 }
194196
195197 private static class NodeIndex {
3838 * variables BASE_LAT and BASE_LONG set to something just SW of where you
3939 * are then the map generated will be located near where you are. Otherwise
4040 * the default location is at (51.7, 0.24).
41 * Options --x-base-lat and --x-base-long have the same effect.
4142 *
4243 * To run, something like:
4344 * java -jar mkgmap.jar --gmapsupp test-map:all-elements ...
102103
103104 private void drawBackground(MapCollector mapper, double startLat, double startLong, int nUp, int nAcross) {
104105 MapShape shape = new MapShape();
105 int type = 0x51; // Wetlands // 0x4d; // glacier-white
106 int type = 0x1b; // Area - Green // 0x4d; // glacier-white
106107 shape.setMinResolution(10);
107108 shape.setName("background");
108109
1818 import java.io.FileNotFoundException;
1919 import java.util.Properties;
2020
21 import uk.me.parabola.imgfmt.app.trergn.TREHeader;
2122 import uk.me.parabola.mkgmap.general.LevelInfo;
2223 import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
2324 import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
8081 public void config(EnhancedProperties props) {
8182 this.configProps = props;
8283 }
84
85 @Override
86 public int getPoiDispFlag() {
87 return TREHeader.POI_FLAG_TRANSPARENT;
88 }
8389 }