Skip to content
Commits on Source (4)
......@@ -13,7 +13,7 @@ but now the maps are becoming useful in their own right.
Using
=====
This program requires Java 1.6 or above to run.
This program requires Java 1.8 or above to run.
Producing a map is simple. Save OpenStreetMap data from JOSM
or by any other method to a file and copy it to the mkgmap
......@@ -60,6 +60,8 @@ by suitable options. Run
to obtain an up to date and complete listing of options.
Also consider examples/sample.cfg as a starting point for your options package
Processing more than one file at a time
---------------------------------------
......
......@@ -401,6 +401,7 @@
<copy todir="${dist}/examples">
<fileset dir="resources">
<include name="roadNameConfig.txt"/>
<include name="sample.cfg"/>
<include name="known-hgt.txt"/>
<include name="installer/**"/>
<include name="styles/default/**"/>
......
mkgmap (0.0.0+svn4380-1) unstable; urgency=medium
* New upstream SVN snapshot.
-- Bas Couwenberg <sebastic@debian.org> Sun, 01 Dec 2019 06:06:50 +0100
mkgmap (0.0.0+svn4323-1) unstable; urgency=medium
* New upstream SVN snapshot.
......
......@@ -576,6 +576,25 @@ and that no more than one connecting highway joins at each node.
: Check that roundabout flare roads point in the correct
direction, are one-way and don't extend too far.
<p>
;--check-routing-island-len=INTEGER
: Routing islands are small road networks which are not connected to other
roads. A typical case is a footway that is not connected to the main road
network, or a small set of ways on the inner courtyard of a large building
: These islands can cause problems if you try to calculate a route and the GPS
selects a point on the island as a start or end. It will fail to calculate the
route even if a major road is only a few steps away. If this option is
specified, then mkgmap will detect these islands. If the value is set to zero,
mkgmap will simply report the islands (you will need to set
uk.me.parabola.imgfmt.app.net.RoadNetwork.level=INFO to activate logging of
the message). If the value is greater than zero, mkgmap will mark islands with
a total length less than the specified value in metres as not routable.
Reasonable values are 500 or higher. The default is for the check to not take
place. If any of the roads forming the island touches a tile boundary or a
country border the island is ignored, as it may be connected to other roads in
a different tile.
: See also option --add-boundary-nodes-at-admin-boundaries.
: This option seems to cause routing problems in BaseCamp.
<p>
;--max-flare-length-ratio=NUM
: When checking flare roads, ignore roads whose length is
greater than NUM (an integer) times the distance between the
......
......@@ -65,7 +65,10 @@ A112 | Usually only the first label is displayed. On some units the second label
| +mkgmap:dir-check+ | Set to +false+ to tell mkgmap to ignore the way when checking roundabouts for direction | 'check-roundabouts'
| +mkgmap:no-dir-check+ | Set to +true+ to tell mkgmap to ignore the way when checking roundabouts for direction | 'check-roundabouts'
| +mkgmap:synthesised+ | Set to +true+ to tell mkgmap that this is an additional way created using the continue statement in an action block and that it should be excluded from checks | 'check-roundabouts', 'check-roundabout-flares'
| +mkgmap:set_unconnected_type+ | Set to +none+ to remove unconected roads from the map once that all roads are known, or to a valid line type if you want a normal line instead of a road. Works also with overlay lines for the same way. |
| +mkgmap:set_semi_connected_type+ | Like mkgmap:set_unconnected_type, but matches for roads with exactly one connection to other roads |
|=========================================================
......
......@@ -567,6 +567,27 @@ Miscellaneous options:
Check that roundabout flare roads point in the correct direction,
are one-way and don't extend too far.
--check-routing-island-len=INTEGER
Routing islands are small road networks which are not connected to other
roads. A typical case is a footway that is not connected to the main
road network, or a small set of ways on the inner courtyard of a large
building
These islands can cause problems if you try to calculate a route and the GPS
selects a point on the island as a start or end. It will fail to calculate
the route even if a major road is only a few steps away. If this option is
specified, then mkgmap will detect these islands. If the value is set to
zero, mkgmap will simply report the islands (you will need to set
uk.me.parabola.imgfmt.app.net.RoadNetwork.level=INFO to activate logging of
the message). If the value is greater than zero, mkgmap will mark islands
with a total length less than the specified value in metres as not routable.
Reasonable values are 500 or higher.
The default is for the check to not take place.
If any of the roads forming the island touches a tile boundary or
a country border the island is ignored, as it may be connected to other
roads in a different tile.
See also option --add-boundary-nodes-at-admin-boundaries.
This option seems to cause routing problems in BaseCamp.
--max-flare-length-ratio=NUM
When checking flare roads, ignore roads whose length is
greater than NUM (an integer) times the distance between the
......
svn.version: 4323
build.timestamp: 2019-10-26T09:00:42+0100
svn.version: 4380
build.timestamp: 2019-11-28T14:08:04+0000
# Sample mkgmap option file to create a map for a GARMIN GPS and compatible PC Programs
#
# The options given here are a reasonable set for generating a routable map, but you
# will probably need to copy this file into your working environment and adapt it by
# fixing paths, adjusting options etc.
#
# Generally, where the default value for an option as acceptable, it isn't specified here.
# Please see the standard help information for details of what the options do.
#
# Typical command line invocation, after using the splitter to generate a set of tiles:
#> java -jar mkgmap-rel/mkgmap.jar -c mkgmap-rel/examples/sample.cfg -c template.args mkgmap-rel/examples/typ-files/mkgmap.txt
#
gmapsupp
gmapi
route
index
bounds=bounds.zip
precomp-sea=sea.zip
location-autofill=is_in,nearest
housenumbers
max-jobs
drive-on=detect
add-pois-to-areas
link-pois-to-ways
process-destination
process-exits
code-page=1252
check-routing-island-len=700
remove-ovm-work-files
#
# Other common options you may wish to consider:
#
#style-file=mkgmap-rel/examples/styles/default
# The above is the default style, change and enable this to use your own style
#road-name-config=mkgmap-rel/examples/roadNameConfig.txt
#split-name-index
#make-opposite-cycleways
#order-by-decreasing-area
#name-tag-list=name:en,int_name,name,place_name,loc_name
......@@ -5,7 +5,8 @@ description "Hebrew sort"
characters
=0008=000e=000f=0010=0011=0012=0013=0014=0015=0016=0017=0018=0019=001a=001b=001c=001d=001e=001f=007f=00ad=05bd=200e=200f,0001,0002,0003,0004,0005,0006,0007 ; 05b0 ; 05b1 ; 05b2 ; 05b3 ; 05b4 ; 05b5 ; 05b6 ; 05b7 ; 05b8 ; 05b9 ; 05bb ; 05c2 ; 05c1 ; 05bc ; 05bf
=0008=000e=000f=0010=0011=0012=0013=0014=0015=0016=0017=0018=0019=001a=001b=001c=001d=001e=001f=007f=00ad=05bd=200e=200f,0001,0002,0003,0004,0005,0006,0007
< 05b0 ; 05b1 ; 05b2 ; 05b3 ; 05b4 ; 05b5 ; 05b6 ; 05b7 ; 05b8 ; 05b9 ; 05bb ; 05c2 ; 05c1 ; 05bc ; 05bf
< 0009
< 000a
< 000b
......
......@@ -32,7 +32,7 @@ import uk.me.parabola.log.Logger;
*/
public class Area {
private static final Logger log = Logger.getLogger(Area.class);
public final static Area PLANET = new Area(-90.0, -180.0, 90.0, 180.0);
public static final Area PLANET = new Area(-90.0, -180.0, 90.0, 180.0);
private final int minLat;
private final int minLong;
......@@ -169,7 +169,7 @@ public class Area {
* @throws MapFailedException if more complex split operation couldn't be honoured.
*/
public Area[] split(int xsplit, int ysplit, int resolutionShift) {
Area[] areas = new Area[xsplit * ysplit];
Area[] areas = new Area[xsplit * ysplit];
int xstart;
int xend;
......@@ -182,22 +182,22 @@ public class Area {
if (x == xsplit - 1)
xend = maxLong;
else
xend = roundPof2(xstart + (maxLong - xstart) / (xsplit - x),
resolutionShift);
xend = roundPof2(xstart + (maxLong - xstart) / (xsplit - x), resolutionShift);
ystart = minLat;
for (int y = 0; y < ysplit; y++) {
if (y == ysplit - 1)
yend = maxLat;
else
yend = roundPof2(ystart + (maxLat - ystart) / (ysplit - y),
resolutionShift);
yend = roundPof2(ystart + (maxLat - ystart) / (ysplit - y), resolutionShift);
if (xstart < xend && ystart < yend) {
Area a = new Area(ystart, xstart, yend, xend);
// log.debug(x, y, a);
log.debug("Area.split", minLat, minLong, maxLat, maxLong, "res", resolutionShift, "to", ystart, xstart, yend, xend);
log.debug("Area.split", minLat, minLong, maxLat, maxLong, "res", resolutionShift, "to", ystart,
xstart, yend, xend);
areas[nAreas++] = a;
} else
log.warn("Area.split", minLat, minLong, maxLat, maxLong, "res", resolutionShift, "can't", xsplit, ysplit);
} else {
log.warn("Area.split", minLat, minLong, maxLat, maxLong, "res", resolutionShift, "can't", xsplit,
ysplit);
}
ystart = yend;
}
xstart = xend;
......@@ -318,17 +318,13 @@ public class Area {
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Area area = (Area) o;
if (maxLat != area.maxLat) return false;
if (maxLong != area.maxLong) return false;
if (minLat != area.minLat) return false;
if (minLong != area.minLong) return false;
return true;
return maxLat == area.maxLat && maxLong == area.maxLong && minLat == area.minLat && minLong == area.minLong;
}
public int hashCode() {
......@@ -343,16 +339,12 @@ public class Area {
* @return list of coords that form the rectangle
*/
public List<Coord> toCoords(){
List<Coord> coords = new ArrayList<Coord>(5);
Coord start = new Coord(minLat, minLong);
coords.add(start);
Coord co = new Coord(minLat, maxLong);
coords.add(co);
co = new Coord(maxLat, maxLong);
coords.add(co);
co = new Coord(maxLat, minLong);
coords.add(co);
coords.add(start);
List<Coord> coords = new ArrayList<>(5);
coords.add(new Coord(minLat, minLong));
coords.add(new Coord(minLat, maxLong));
coords.add(new Coord(maxLat, maxLong));
coords.add(new Coord(maxLat, minLong));
coords.add(coords.get(0));
return coords;
}
......
......@@ -37,29 +37,29 @@ import uk.me.parabola.mkgmap.filters.ShapeMergeFilter;
* @author Steve Ratcliffe
*/
public class Coord implements Comparable<Coord> {
private final static short ON_BOUNDARY_MASK = 0x0001; // bit in flags is true if point lies on a boundary
private final static short PRESERVED_MASK = 0x0002; // bit in flags is true if point should not be filtered out
private final static short REPLACED_MASK = 0x0004; // bit in flags is true if point was replaced
private final static short ADDED_BY_CLIPPER_MASK = 0x0008; // bit in flags is true if point was added by clipper
private final static short FIXME_NODE_MASK = 0x0010; // bit in flags is true if a node with this coords has a fixme tag
private final static short REMOVE_MASK = 0x0020; // bit in flags is true if this point should be removed
private final static short VIA_NODE_MASK = 0x0040; // bit in flags is true if a node with this coords is the via node of a RestrictionRelation
private final static short PART_OF_BAD_ANGLE = 0x0080; // bit in flags is true if point should be treated as a node
private final static short PART_OF_SHAPE2 = 0x0100; // use only in ShapeMerger
private final static short END_OF_WAY = 0x0200; // use only in WrongAngleFixer
private final static short HOUSENUMBER_NODE = 0x0400; // start/end of house number interval
private final static short ADDED_HOUSENUMBER_NODE = 0x0800; // node was added for house numbers
private final static short ON_COUNTRY_BORDER = 0x1000; // node is on a country border
private final static int HIGH_PREC_BITS = 30;
public final static int DELTA_SHIFT = HIGH_PREC_BITS - 24;
private final static int MAX_DELTA = 1 << (DELTA_SHIFT - 2); // max delta abs value that is considered okay
private final static long FACTOR_HP = 1L << HIGH_PREC_BITS;
public final static double R = 6378137.0; // Radius of earth at equator as defined by WGS84
public final static double U = R * 2 * Math.PI; // circumference of earth at equator (WGS84)
public final static double MEAN_EARTH_RADIUS = 6371000; // earth is a flattened sphere
private static final short ON_BOUNDARY_MASK = 0x0001; // bit in flags is true if point lies on a boundary
private static final short PRESERVED_MASK = 0x0002; // bit in flags is true if point should not be filtered out
private static final short REPLACED_MASK = 0x0004; // bit in flags is true if point was replaced
private static final short ADDED_BY_CLIPPER_MASK = 0x0008; // bit in flags is true if point was added by clipper
private static final short FIXME_NODE_MASK = 0x0010; // bit in flags is true if a node with this coords has a fixme tag
private static final short REMOVE_MASK = 0x0020; // bit in flags is true if this point should be removed
private static final short VIA_NODE_MASK = 0x0040; // bit in flags is true if a node with this coords is the via node of a RestrictionRelation
private static final short PART_OF_BAD_ANGLE = 0x0080; // bit in flags is true if point should be treated as a node
private static final short PART_OF_SHAPE2 = 0x0100; // use only in ShapeMerger
private static final short END_OF_WAY = 0x0200; // use only in WrongAngleFixer
private static final short HOUSENUMBER_NODE = 0x0400; // start/end of house number interval
private static final short ADDED_HOUSENUMBER_NODE = 0x0800; // node was added for house numbers
private static final short ON_COUNTRY_BORDER = 0x1000; // node is on a country border
private static final int HIGH_PREC_BITS = 30;
public static final int DELTA_SHIFT = HIGH_PREC_BITS - 24;
private static final int MAX_DELTA = 1 << (DELTA_SHIFT - 2); // max delta abs value that is considered okay
private static final long FACTOR_HP = 1L << HIGH_PREC_BITS;
public static final double R = 6378137.0; // Radius of earth at equator as defined by WGS84
public static final double U = R * 2 * Math.PI; // circumference of earth at equator (WGS84)
public static final double MEAN_EARTH_RADIUS = 6371000; // earth is a flattened sphere
private final int latitude;
private final int longitude;
......@@ -94,8 +94,8 @@ public class Coord implements Comparable<Coord> {
this.lonDelta = (byte) ((this.longitude << DELTA_SHIFT) - lonHighPrec);
// verify math
assert (this.latitude << DELTA_SHIFT) - latDelta == latHighPrec;
assert (this.longitude << DELTA_SHIFT) - lonDelta == lonHighPrec;
assert (this.latitude << DELTA_SHIFT) - (int) latDelta == latHighPrec;
assert (this.longitude << DELTA_SHIFT) - (int) lonDelta == lonHighPrec;
}
private Coord (int lat, int lon, byte latDelta, byte lonDelta){
......@@ -404,7 +404,7 @@ public class Coord implements Comparable<Coord> {
* Compares the coordinates that are displayed in the map
*/
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Coord))
if (!(obj instanceof Coord))
return false;
Coord other = (Coord) obj;
return latitude == other.latitude && longitude == other.longitude;
......@@ -486,8 +486,7 @@ public class Coord implements Comparable<Coord> {
double sinMidLat = Math.sin((lat1-lat2)/2);
double sinMidLon = Math.sin((lon1-lon2)/2);
double dRad = 2*Math.asin(Math.sqrt(sinMidLat*sinMidLat + Math.cos(lat1)*Math.cos(lat2)*sinMidLon*sinMidLon));
double distance= dRad * R;
return distance;
return dRad * R; // the distance
}
/**
......@@ -513,10 +512,7 @@ public class Coord implements Comparable<Coord> {
// distance is pythagoras on 'stretched' Mercator projection
double distRad = Math.sqrt(dLat*dLat + q*q*dLon*dLon); // angular distance in radians
double dist = distRad * R;
return dist;
return distRad * R; // the distance
}
/**
......@@ -652,7 +648,7 @@ public class Coord implements Comparable<Coord> {
/* Factor for conversion to radians using HIGH_PREC_BITS bits
* (Math.PI / 180) * (360.0 / (1 << HIGH_PREC_BITS))
*/
final static double HIGH_PREC_RAD_FACTOR = 2 * Math.PI / FACTOR_HP;
static final double HIGH_PREC_RAD_FACTOR = 2 * Math.PI / FACTOR_HP;
/**
* Convert to radians using high precision
......@@ -667,14 +663,14 @@ public class Coord implements Comparable<Coord> {
* @return Latitude as signed HIGH_PREC_BITS bit integer
*/
public int getHighPrecLat() {
return (latitude << DELTA_SHIFT) - latDelta;
return (latitude << DELTA_SHIFT) - (int) latDelta;
}
/**
* @return Longitude as signed HIGH_PREC_BITS bit integer
*/
public int getHighPrecLon() {
return (longitude << DELTA_SHIFT) - lonDelta;
return (longitude << DELTA_SHIFT) - (int) lonDelta;
}
/**
......
......@@ -60,9 +60,7 @@ public class City {
}
void write(ImgFileWriter writer) {
//writer.put3()
if (pointRef) {
// System.err.println("City point = " + (int)pointIndex + " div = " + subdivision.getNumber());
writer.put1u(pointIndex);
writer.put2u(subdivision.getNumber());
} else {
......@@ -106,15 +104,11 @@ public class City {
}
public String getName() {
if (label == null)
return "";
return label.getText();
return label == null ? "" : label.getText();
}
public int getLblOffset() {
if (label == null)
return 0;
return label.getOffset();
return label == null ? 0 : label.getOffset();
}
public String toString() {
......@@ -124,9 +118,9 @@ public class City {
if (subdivision != null)
result += " " + subdivision.getNumber() + "/" + pointIndex;
if(country != null)
result += " in country " + (0 + country.getIndex());
result += " in country " + country.getIndex();
if(region != null)
result += " in region " + (0 + region.getIndex());
result += " in region " + region.getIndex();
return result;
}
......@@ -159,7 +153,7 @@ public class City {
}
public int getCountryNumber() {
return country != null ? country.getIndex() : 0;
return country == null ? 0 : country.getIndex();
}
public Label getLabel() {
......
......@@ -27,10 +27,11 @@ import uk.me.parabola.imgfmt.app.ImgFileWriter;
public class Country {
// The country number. This is not recorded in the file
private int index;
private Label label;
private final Label label;
public Country(int index) {
this.index = (char) index;
public Country(int index, Label label) {
this.index = index;
this.label = label;
}
void write(ImgFileWriter writer) {
......@@ -41,10 +42,6 @@ public class Country {
return index;
}
public void setLabel(Label label) {
this.label = label;
}
public Label getLabel() {
return label;
}
......
......@@ -57,18 +57,18 @@ public class LBLFile extends ImgFile {
private final PlacesFile places = new PlacesFile();
private Sort sort;
// Shift value for the label offset.
private final int offsetMultiplier = 1;
// Shift value for the label offset, we always use 1 here.
private static final int OFFSET_MULTIPLIER = 1;
public LBLFile(ImgChannel chan, Sort sort) {
this.sort = sort;
lblHeader.setSort(sort);
lblHeader.setOffsetMultiplier(offsetMultiplier);
lblHeader.setOffsetMultiplier(OFFSET_MULTIPLIER);
setHeader(lblHeader);
setWriter(new BufferedImgFileWriter(chan));
position(LBLHeader.HEADER_LEN + lblHeader.getSortDescriptionLength());
position((long) LBLHeader.HEADER_LEN + lblHeader.getSortDescriptionLength());
// The zero offset is for no label.
getWriter().put1u(0);
......@@ -156,12 +156,12 @@ public class LBLFile extends ImgFile {
*/
private void alignForNext() {
// Align ready for next label
while ((getCurrentLabelOffset() & ((1 << offsetMultiplier) - 1)) != 0)
while ((getCurrentLabelOffset() & ((1 << OFFSET_MULTIPLIER) - 1)) != 0)
getWriter().put1u(0);
}
private int getNextLabelOffset() {
return getCurrentLabelOffset() >> offsetMultiplier;
return getCurrentLabelOffset() >> OFFSET_MULTIPLIER;
}
private int getCurrentLabelOffset() {
......
......@@ -143,8 +143,7 @@ public class LBLFileReader extends ImgFile {
Label label = fetchLabel(offset);
if (label != null) {
Country country = new Country(index);
country.setLabel(label);
Country country = new Country(index, label);
countries.add(country);
}
index++;
......@@ -171,9 +170,8 @@ public class LBLFileReader extends ImgFile {
int offset = reader.get3u();
Label label = fetchLabel(offset);
if (label != null) {
Region region = new Region(countries.get(country));
Region region = new Region(countries.get(country), label);
region.setIndex(index);
region.setLabel(label);
regions.add(region);
}
......@@ -245,7 +243,7 @@ public class LBLFileReader extends ImgFile {
int start = header.getLabelStart();
int size = header.getLabelSize();
reader.position(start + mult);
reader.position((long) start + mult);
int labelOffset = mult;
for (int off = mult; off <= size; off++) {
......@@ -313,8 +311,7 @@ public class LBLFileReader extends ImgFile {
while (reader.position() < end) {
int lblOffset = reader.get3u();
Zip zip = new Zip();
zip.setLabel(fetchLabel(lblOffset));
Zip zip = new Zip(fetchLabel(lblOffset));
zip.setIndex(zipIndex);
zips.put(zip.getIndex(), zip);
......
......@@ -35,7 +35,7 @@ public class POIIndex {
this.name = name;
this.poiIndex = poiIndex;
this.group = group;
this.subType = subType & 0xff;
this.subType = subType;
}
void write(ImgFileWriter writer) {
......
......@@ -20,7 +20,9 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;
import uk.me.parabola.imgfmt.app.Exit;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
......@@ -34,7 +36,6 @@ import uk.me.parabola.imgfmt.app.trergn.Subdivision;
* This is really part of the LBLFile. We split out all the parts of the file
* that are to do with location to here.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class PlacesFile {
public static final int MIN_INDEXED_POI_TYPE = 0x29;
public static final int MAX_INDEXED_POI_TYPE = 0x30;
......@@ -53,7 +54,7 @@ public class PlacesFile {
private final List<Highway> highways = new ArrayList<>();
private final List<ExitFacility> exitFacilities = new ArrayList<>();
private final List<POIRecord> pois = new ArrayList<>();
private final List[] poiIndex = new ArrayList[256];
private final TreeMap<Integer, List<POIIndex>> poiIndex = new TreeMap<>();
private LBLFile lblFile;
private PlacesHeader placeHeader;
......@@ -76,32 +77,27 @@ public class PlacesFile {
}
void write(ImgFileWriter writer) {
for (Country c : countryList)
c.write(writer);
countryList.forEach(c -> c.write(writer));
placeHeader.endCountries(writer.position());
for (Region region : regionList)
region.write(writer);
regionList.forEach(r -> r.write(writer));
placeHeader.endRegions(writer.position());
for (City sc : cityList)
sc.write(writer);
cityList.forEach(sc -> sc.write(writer));
placeHeader.endCity(writer.position());
for (List<POIIndex> pil : poiIndex) {
if(pil != null) {
// sort entries by POI name
List<SortKey<POIIndex>> sorted = new ArrayList<>();
for (POIIndex index : pil) {
SortKey<POIIndex> sortKey = sort.createSortKey(index, index.getName());
sorted.add(sortKey);
}
sorted.sort(null);
for (SortKey<POIIndex> key : sorted) {
key.getObject().write(writer);
}
for (List<POIIndex> pil : poiIndex.values()) {
// sort entries by POI name
List<SortKey<POIIndex>> sorted = new ArrayList<>();
for (POIIndex index : pil) {
SortKey<POIIndex> sortKey = sort.createSortKey(index, index.getName());
sorted.add(sortKey);
}
sorted.sort(null);
for (SortKey<POIIndex> key : sorted) {
key.getObject().write(writer);
}
}
placeHeader.endPOIIndex(writer.position());
......@@ -114,17 +110,15 @@ public class PlacesFile {
placeHeader.endPOI(writer.position());
int numPoiIndexEntries = 0;
for (int i = 0; i < 256; ++i) {
if(poiIndex[i] != null) {
writer.put1u(i);
writer.put3u(numPoiIndexEntries + 1);
numPoiIndexEntries += poiIndex[i].size();
}
for (Entry<Integer, List<POIIndex>> entry : poiIndex.entrySet()) {
int i = entry.getKey();
writer.put1u(i);
writer.put3u(numPoiIndexEntries + 1);
numPoiIndexEntries += entry.getValue().size();
}
placeHeader.endPOITypeIndex(writer.position());
for (Zip z : zipList)
z.write(writer);
zipList.forEach(z -> z.write(writer));
placeHeader.endZip(writer.position());
int extraHighwayDataOffset = 0;
......@@ -135,59 +129,37 @@ public class PlacesFile {
}
placeHeader.endHighway(writer.position());
for (ExitFacility ef : exitFacilities)
ef.write(writer);
exitFacilities.forEach(ef -> ef.write(writer));
placeHeader.endExitFacility(writer.position());
for (Highway h : highways)
h.write(writer, true);
highways.forEach(h -> h.write(writer, true));
placeHeader.endHighwayData(writer.position());
}
Country createCountry(String name, String abbr) {
String s = abbr != null ? name + (char)0x1d + abbr : name;
Country c = countries.get(s);
if(c == null) {
c = new Country(countries.size()+1);
Label l = lblFile.newLabel(s);
c.setLabel(l);
countries.put(s, c);
}
return c;
return countries.computeIfAbsent(s, k -> new Country(countries.size() + 1, lblFile.newLabel(s)));
}
Region createRegion(Country country, String name, String abbr) {
String s = abbr != null ? name + (char)0x1d + abbr : name;
String s = abbr != null ? name + (char) 0x1d + abbr : name;
String uniqueRegionName = s.toUpperCase() + "_C" + country.getLabel().getOffset();
Region r = regions.get(uniqueRegionName);
if(r == null) {
r = new Region(country);
Label l = lblFile.newLabel(s);
r.setLabel(l);
regionList.add(r);
regions.put(uniqueRegionName, r);
}
return r;
return regions.computeIfAbsent(uniqueRegionName, k -> new Region(country, lblFile.newLabel(s)));
}
/**
* Create city without region
* @param country the country
* @param name the name of the city
* @param unique set to true if you needed a new city object
* @return the city object
*/
City createCity(Country country, String name, boolean unique) {
String uniqueCityName = name.toUpperCase() + "_C" + country.getLabel().getOffset();
// if unique is true, make sure that the name really is unique
if(unique && cities.get(uniqueCityName) != null) {
do {
// add random suffix
uniqueCityName += "_" + new Random().nextInt(0x10000);
} while(cities.get(uniqueCityName) != null);
if (unique) {
uniqueCityName = createUniqueCityName(uniqueCityName);
}
City c = null;
......@@ -197,8 +169,7 @@ public class PlacesFile {
if (c == null) {
c = new City(country);
Label l = lblFile.newLabel(name);
c.setLabel(l);
c.setLabel(lblFile.newLabel(name));
cityList.add(c);
cities.put(uniqueCityName, c);
......@@ -208,27 +179,30 @@ public class PlacesFile {
return c;
}
/**
* Create city with region
* @param region the region
* @param name the name of the city
* @param unique set to true if you needed a new city object
* @return the city object
*/
City createCity(Region region, String name, boolean unique) {
String uniqueCityName = name.toUpperCase() + "_R" + region.getLabel().getOffset();
// if unique is true, make sure that the name really is unique
if (unique && cities.get(uniqueCityName) != null) {
do {
// add semi-random suffix.
uniqueCityName += "_" + random.nextInt(0x10000);
} while(cities.get(uniqueCityName) != null);
if (unique) {
uniqueCityName = createUniqueCityName(uniqueCityName);
}
City c = null;
if(!unique)
if(!unique) {
c = cities.get(uniqueCityName);
}
if(c == null) {
c = new City(region);
Label l = lblFile.newLabel(name);
c.setLabel(l);
c.setLabel(lblFile.newLabel(name));
cityList.add(c);
cities.put(uniqueCityName, c);
......@@ -238,26 +212,23 @@ public class PlacesFile {
return c;
}
Zip createZip(String code) {
Zip z = postalCodes.get(code);
if(z == null) {
z = new Zip();
Label l = lblFile.newLabel(code);
z.setLabel(l);
zipList.add(z);
postalCodes.put(code, z);
private String createUniqueCityName(String name) {
String uniqueCityName = name;
while (cities.get(uniqueCityName) != null) {
// add semi-random suffix.
uniqueCityName += "_" + random.nextInt(0x10000);
}
return z;
return uniqueCityName;
}
Zip createZip(String code) {
return postalCodes.computeIfAbsent(code, k -> new Zip(lblFile.newLabel(code)));
}
Highway createHighway(Region region, String name) {
Highway h = new Highway(region, highways.size()+1);
Label l = lblFile.newLabel(name);
h.setLabel(l);
h.setLabel(lblFile.newLabel(name));
highways.add(h);
return h;
......@@ -272,12 +243,9 @@ public class PlacesFile {
POIRecord createPOI(String name) {
assert !poisClosed;
// TODO...
POIRecord p = new POIRecord();
Label l = lblFile.newLabel(name);
p.setLabel(l);
p.setLabel(lblFile.newLabel(name));
pois.add(p);
return p;
......@@ -285,14 +253,10 @@ public class PlacesFile {
POIRecord createExitPOI(String name, Exit exit) {
assert !poisClosed;
// TODO...
POIRecord p = new POIRecord();
Label l = lblFile.newLabel(name);
p.setLabel(l);
p.setLabel(lblFile.newLabel(name));
p.setExit(exit);
pois.add(p);
return p;
......@@ -304,10 +268,8 @@ public class PlacesFile {
if (t < MIN_INDEXED_POI_TYPE || t > MAX_INDEXED_POI_TYPE)
return;
POIIndex pi = new POIIndex(name, index, group, type);
if(poiIndex[t] == null)
poiIndex[t] = new ArrayList<POIIndex>();
poiIndex[t].add(pi);
POIIndex pi = new POIIndex(name, index, group, type & 0xff);
poiIndex.computeIfAbsent(t, k -> new ArrayList<>()).add(pi);
}
void allPOIsDone() {
......@@ -330,7 +292,7 @@ public class PlacesFile {
}
/**
* I don't know that you have to sort these (after all most tiles will
* I don't know that you have to sort these (after almost all tiles will
* only be in one country or at least a very small number).
*
* But why not?
......@@ -357,7 +319,7 @@ public class PlacesFile {
*/
private void sortRegions() {
List<SortKey<Region>> keys = new ArrayList<>();
for (Region r : regionList) {
for (Region r : regions.values()) {
SortKey<Region> key = sort.createSortKey(r, r.getLabel(), r.getCountry().getIndex());
keys.add(key);
}
......
......@@ -28,10 +28,11 @@ public class Region {
private int index;
private final Country country;
private Label label;
private final Label label;
public Region(Country country) {
public Region(Country country, Label label) {
this.country = country;
this.label = label;
}
public void write(ImgFileWriter writer) {
......@@ -52,10 +53,6 @@ public class Region {
this.index = index;
}
public void setLabel(Label label) {
this.label = label;
}
public Label getLabel() {
return label;
}
......
......@@ -28,7 +28,11 @@ public class Zip {
// The index is not stored in the file, you just use the index of it in
// the section.
private int index;
private Label label;
private final Label label;
public Zip(Label label) {
this.label = label;
}
public void write(ImgFileWriter writer) {
writer.put3u(label.getOffset());
......@@ -38,10 +42,6 @@ public class Zip {
return label;
}
public void setLabel(Label label) {
this.label = label;
}
public int getIndex() {
return index;
}
......
......@@ -57,14 +57,13 @@ public abstract class LargeListSorter<T extends NamedRecord> {
merge(list,start,len);
} else {
// sort one chunk
// System.out.println("sorting list of roads. positions " + start + " to " + (start + len - 1));
Map<String, byte[]> cache = new HashMap<>();
List<SortKey<T>> keys = new ArrayList<>(len);
for (int i = start; i < start + len; i++) {
keys.add(makeKey(list.get(i), sort, cache));
}
cache = null;
cache = null; // release memory
keys.sort(null);
for (int i = 0; i < keys.size(); i++){
......@@ -72,13 +71,11 @@ public abstract class LargeListSorter<T extends NamedRecord> {
T r = sk.getObject();
list.set(start+i, r);
}
return;
}
}
private void merge(List<T> list, int start, int len) {
// System.out.println("merging positions " + start + " to " + (start + len - 1));
int pos1 = start;
int pos2 = start + len / 2;
int stop1 = start + len / 2;
......@@ -89,11 +86,11 @@ public abstract class LargeListSorter<T extends NamedRecord> {
SortKey<T> sk1 = null;
SortKey<T> sk2 = null;
while (pos1 < stop1 && pos2 < stop2) {
if (fetch1 && pos1 < stop1) {
if (fetch1) {
sk1 = makeKey(list.get(pos1), sort, null);
fetch1 = false;
}
if (fetch2 && pos2 < stop2) {
if (fetch2) {
sk2 = makeKey(list.get(pos2), sort, null);
fetch2 = false;
}
......