diff --git a/resources/help/en/options b/resources/help/en/options index b0acfd4..ed89bfc 100644 --- a/resources/help/en/options +++ b/resources/help/en/options @@ -20,6 +20,19 @@ Options: Sets the descriptive text for the map. This may be displayed in QLandkarte, MapSource on on a GPS etc. +--country-name + Sets the map's country name. The default is "UNITED KINGDOM". + +--country-abbr + Sets the map's abbreviated country name. The default is "GBR". + +--region-name + Sets the map's region name. By default, the map has no region name. + +--region-abbr + Sets the map's abbreviated region name. By default, the map has + no abbreviated region name. + Label options: --latin1 diff --git a/src/uk/me/parabola/imgfmt/app/lbl/City.java b/src/uk/me/parabola/imgfmt/app/lbl/City.java index 86768d3..9f460c1 100644 --- a/src/uk/me/parabola/imgfmt/app/lbl/City.java +++ b/src/uk/me/parabola/imgfmt/app/lbl/City.java @@ -19,6 +19,8 @@ package uk.me.parabola.imgfmt.app.lbl; import uk.me.parabola.imgfmt.app.ImgFileWriter; import uk.me.parabola.imgfmt.app.Label; +import uk.me.parabola.imgfmt.app.trergn.Subdivision; + /** * A city is in a region. It also has (or can have anyway) a reference to * an indexed point within the map itself. @@ -27,10 +29,12 @@ import uk.me.parabola.imgfmt.app.Label; */ public class City { private static final int POINT_REF = 0x8000; + private static final int REGION_IS_COUNTRY = 0x4000; private final int index; private final Region region; + private final Country country; // This determines if a label is being used or a subdivision and point // combo. @@ -38,7 +42,7 @@ public class City { // The location of the city. These could both be zero if we are using a // label instead. - private char subdivision; + private Subdivision subdivision; private byte pointIndex; @@ -48,19 +52,31 @@ public class City { public City(Region region, int index) { this.region = region; + this.country = null; + this.index = index; + } + + public City(Country country, int index) { + this.country = country; + this.region = null; this.index = index; } void write(ImgFileWriter writer) { //writer.put3() if (pointRef) { + // System.err.println("City point = " + (int)pointIndex + " div = " + subdivision.getNumber()); writer.put(pointIndex); - writer.putChar(subdivision); + writer.putChar((char)subdivision.getNumber()); } else { writer.put3(label.getOffset()); } - - char info = (char) (region.getIndex() & 0x3fff); + + char info; + if(region != null) + info = (char) (region.getIndex() & 0x3fff); + else + info = (char) (REGION_IS_COUNTRY | (country.getIndex() & 0x3fff)); if (pointRef) info |= POINT_REF; @@ -81,7 +97,7 @@ public class City { this.pointIndex = pointIndex; } - public void setSubdivision(char subdivision) { + public void setSubdivision(Subdivision subdivision) { pointRef = true; this.subdivision = subdivision; } diff --git a/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java b/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java index d37f83c..a6e5a57 100644 --- a/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java +++ b/src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java @@ -143,14 +143,17 @@ public class LBLFile extends ImgFile { return places.createCountry(name, abbr); } - public Region createRegion(Country country, String region) { - return places.createRegion(country, region); + public Region createRegion(Country country, String region, String abbr) { + return places.createRegion(country, region, abbr); } public City createCity(Region region, String city) { return places.createCity(region, city); } - + + public City createCity(Country country, String city) { + return places.createCity(country, city); + } public void allPOIsDone() { places.allPOIsDone(); diff --git a/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java b/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java index 092e5aa..b669793 100644 --- a/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java +++ b/src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java @@ -81,7 +81,7 @@ public class PlacesFile { Country createCountry(String name, String abbr) { Country c = new Country(countries.size()+1); - String s = abbr != null ? name + 0x1d + abbr : name; + String s = abbr != null ? name + (char)0x1d + abbr : name; Label l = lblFile.newLabel(s); c.setLabel(l); @@ -90,21 +90,33 @@ public class PlacesFile { return c; } - Region createRegion(Country country, String name) { + Region createRegion(Country country, String name, String abbr) { Region r = new Region(country, regions.size()+1); - Label l = lblFile.newLabel(name); + String s = abbr != null ? name + (char)0x1d + abbr : name; + + Label l = lblFile.newLabel(s); r.setLabel(l); regions.put(name, r); return r; } + City createCity(Country country, String name) { + City c = new City(country, cities.size()+1); + + Label l = lblFile.newLabel(name); + c.setLabel(l); // label may be ignored if pointref is set + + cities.put(name, c); + return c; + } + City createCity(Region region, String name) { City c = new City(region, cities.size()+1); Label l = lblFile.newLabel(name); - c.setLabel(l); + c.setLabel(l); // label may be ignored if pointref is set cities.put(name, c); return c; diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Point.java b/src/uk/me/parabola/imgfmt/app/trergn/Point.java index 766b7ca..62a4435 100644 --- a/src/uk/me/parabola/imgfmt/app/trergn/Point.java +++ b/src/uk/me/parabola/imgfmt/app/trergn/Point.java @@ -47,8 +47,10 @@ public class Point extends MapObject { int type = getType(); byte subtype = 0; if (type > 0xff) { - hasSubtype = true; - subtype = (byte) type; + if((type & 0xff) != 0) { + hasSubtype = true; + subtype = (byte) type; + } type >>= 8; } @@ -65,8 +67,10 @@ public class Point extends MapObject { file.put3(off); file.putChar((char) getDeltaLong()); file.putChar((char) getDeltaLat()); - if (hasSubtype) + if (hasSubtype) { + // System.err.printf("Point has subtype (type = 0x%X)\n", getType()); file.put(subtype); + } } public void setPOIRecord(POIRecord poirecord) { diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java index 0838754..1d05fb9 100644 --- a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java +++ b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java @@ -373,13 +373,13 @@ public class Subdivision { * We are starting to draw the lines. These must be done before * polygons. */ - void startIndPoints() { + public void startIndPoints() { if (lastMapElement > MAP_INDEXED_POINT) throw new IllegalStateException("Indexed points must be done before lines and polygons"); lastMapElement = MAP_INDEXED_POINT; - rgnFile.setPolylinePtr(); + rgnFile.setIndPointPtr(); } /** diff --git a/src/uk/me/parabola/mkgmap/build/MapArea.java b/src/uk/me/parabola/mkgmap/build/MapArea.java index 2fc86ba..092bb82 100644 --- a/src/uk/me/parabola/mkgmap/build/MapArea.java +++ b/src/uk/me/parabola/mkgmap/build/MapArea.java @@ -75,6 +75,7 @@ public class MapArea implements MapDataSource { private final int[] elemCounts = new int[MAX_RESOLUTION+1]; private int nActivePoints; + private int nActiveIndPoints; private int nActiveLines; private int nActiveShapes; @@ -336,7 +337,7 @@ public class MapArea implements MapDataSource { * @return True if any active indexed points in the area. */ public boolean hasIndPoints() { - return false; + return nActiveIndPoints > 0; } /** @@ -390,8 +391,12 @@ public class MapArea implements MapDataSource { switch (kind) { case POINT_KIND: - if (res <= areaResolution) - nActivePoints++; + if (res <= areaResolution) { + if(((MapPoint) p).isCity()) + nActiveIndPoints++; + else + nActivePoints++; + } // Points are predictibly less than 9 bytes. s = 9; diff --git a/src/uk/me/parabola/mkgmap/build/MapBuilder.java b/src/uk/me/parabola/mkgmap/build/MapBuilder.java index 60f9d23..f8db9b6 100644 --- a/src/uk/me/parabola/mkgmap/build/MapBuilder.java +++ b/src/uk/me/parabola/mkgmap/build/MapBuilder.java @@ -21,10 +21,15 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.imgfmt.app.lbl.LBLFile; import uk.me.parabola.imgfmt.app.lbl.POIRecord; +import uk.me.parabola.imgfmt.app.lbl.City; +import uk.me.parabola.imgfmt.app.lbl.Country; +import uk.me.parabola.imgfmt.app.lbl.Region; import uk.me.parabola.imgfmt.app.map.Map; import uk.me.parabola.imgfmt.app.net.NETFile; import uk.me.parabola.imgfmt.app.net.NODFile; @@ -60,6 +65,8 @@ import uk.me.parabola.mkgmap.general.MapPoint; import uk.me.parabola.mkgmap.general.MapRoad; import uk.me.parabola.mkgmap.general.MapShape; import uk.me.parabola.mkgmap.general.RoadNetwork; +import uk.me.parabola.util.Configurable; +import uk.me.parabola.util.EnhancedProperties; /** * This is the core of the code to translate from the general representation @@ -71,13 +78,29 @@ import uk.me.parabola.mkgmap.general.RoadNetwork; * * @author Steve Ratcliffe */ -public class MapBuilder { +public class MapBuilder implements Configurable { private static final Logger log = Logger.getLogger(MapBuilder.class); private static final int CLEAR_TOP_BITS = (32 - 15); private final java.util.Map poimap = new HashMap(); + private final SortedMap sortedCities = new TreeMap(); private boolean doRoads; + private Country country = null; + private Region region = null; + + private String countryName = "UNITED KINGDOM"; + private String countryAbbr = "GBR"; + private String regionName = null; + private String regionAbbr = null; + + public void config(EnhancedProperties props) { + countryName = props.getProperty("country-name", countryName); + countryAbbr = props.getProperty("country-abbr", countryAbbr); + regionName = props.getProperty("region-name", null); + regionAbbr = props.getProperty("region-abbr", null); + } + /** * Main method to create the map, just calls out to several routines * that do the work. @@ -86,6 +109,16 @@ public class MapBuilder { * @param src The map data. */ public void makeMap(Map map, LoadableMapDataSource src) { + + RGNFile rgnFile = map.getRgnFile(); + TREFile treFile = map.getTreFile(); + LBLFile lblFile = map.getLblFile(); + NETFile netFile = map.getNetFile(); + + country = lblFile.createCountry(countryName, countryAbbr); + if(regionName != null) + region = lblFile.createRegion(country, regionName, regionAbbr); + processPOIs(map, src); //preProcessRoads(map, src); processOverviews(map, src); @@ -94,11 +127,6 @@ public class MapBuilder { //processRoads(map, src); //postProcessRoads(map, src); - RGNFile rgnFile = map.getRgnFile(); - TREFile treFile = map.getTreFile(); - LBLFile lblFile = map.getLblFile(); - NETFile netFile = map.getNetFile(); - treFile.setLastRgnPos(rgnFile.position() - RGNHeader.HEADER_LEN); rgnFile.write(); @@ -135,8 +163,29 @@ public class MapBuilder { */ private void processPOIs(Map map, MapDataSource src) { LBLFile lbl = map.getLblFile(); + + // collect the names of the cities + for (MapPoint p : src.getPoints()) { + if(p.isCity() && p.getName() != null) { + sortedCities.put(p.getName(), null); + } + } + // create the city records in alphabetic order + for (String s : sortedCities.keySet()) { + City c; + if(region != null) + c = lbl.createCity(region, s); + else + c = lbl.createCity(country, s); + sortedCities.put(s, c); + } for (MapPoint p : src.getPoints()) { - POIRecord r = lbl.createPOI(p.getName()); + POIRecord r = null; + //r = lbl.createPOI(p.getName()); + //if(p.isCity()) { + // r.setCityIndex(sortedCities.get(p.getName()).getIndex()); + //} + if(r != null) poimap.put(p, r); } lbl.allPOIsDone(); @@ -345,10 +394,17 @@ public class MapBuilder { div.startPoints(); int res = div.getResolution(); + boolean haveIndPoints = false; + for (MapPoint point : points) { if (point.getMinResolution() > res || point.getMaxResolution() < res) continue; + if(point.isCity()) { + haveIndPoints = true; + continue; + } + String name = point.getName(); Point p = div.createPoint(name); @@ -358,12 +414,55 @@ public class MapBuilder { p.setLatitude(coord.getLatitude()); p.setLongitude(coord.getLongitude()); - POIRecord r = poimap.get(point); - if (r != null) - p.setPOIRecord(r); + if(div.getZoom().getLevel() == 0) { + POIRecord r = poimap.get(point); + if (r != null) + p.setPOIRecord(r); + } map.addMapObject(p); } + + if(haveIndPoints) { + + div.startIndPoints(); + + int pointIndex = 1; + + for (MapPoint point : points) { + if (point.getMinResolution() > res || point.getMaxResolution() < res) + continue; + + if(!point.isCity()) + continue; + + String name = point.getName(); + + Point p = div.createPoint(name); + p.setType(point.getType()); + + Coord coord = point.getLocation(); + p.setLatitude(coord.getLatitude()); + p.setLongitude(coord.getLongitude()); + + if(div.getZoom().getLevel() == 0 && + name != null) { + City c = sortedCities.get(name); + + if(pointIndex > 255) { + System.err.println("Can't set city point index for " + name + " (too many indexed points in division)\n"); + } + else { + c.setPointIndex((byte)pointIndex); + c.setSubdivision(div); + } + //System.out.println("city " + point.getName() + " at point[" + pointIndex + "] in div " + div); + } + + map.addMapObject(p); + ++pointIndex; + } + } } /** diff --git a/src/uk/me/parabola/mkgmap/general/MapPoint.java b/src/uk/me/parabola/mkgmap/general/MapPoint.java index db899b0..609ef0a 100644 --- a/src/uk/me/parabola/mkgmap/general/MapPoint.java +++ b/src/uk/me/parabola/mkgmap/general/MapPoint.java @@ -56,4 +56,9 @@ public class MapPoint extends MapElement { return new Area(location.getLatitude(), location.getLongitude(), location.getLatitude(), location.getLongitude()); } + + public boolean isCity() { + int type = getType(); + return type >= 0x0100 && type <= 0x1100; + } } diff --git a/src/uk/me/parabola/mkgmap/main/MapMaker.java b/src/uk/me/parabola/mkgmap/main/MapMaker.java index 7bbb022..b7245bf 100644 --- a/src/uk/me/parabola/mkgmap/main/MapMaker.java +++ b/src/uk/me/parabola/mkgmap/main/MapMaker.java @@ -72,6 +72,7 @@ public class MapMaker implements MapProcessor { setOptions(map, args); MapBuilder builder = new MapBuilder(); + builder.config(args.getProperties()); if (args.getProperties().getProperty("route", false)) builder.setDoRoads(true); builder.makeMap(map, src);