mkgmap-dev
Threads by month
- ----- 2025 -----
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
February 2009
- 43 participants
- 195 discussions
Find attached an patch (usable on R915), which reduces the point density
of ways and roads to reduce the filesize of the resulting img file.
It does it by using the douglas peucker algorithm. With this algorithm
it is possible to set a max error distance and the resulting line will
have filtered out all points without any points outside this distance band.
For an exact explanation consult wikipedia.
I tried it with an error distance of 10m. Higher distances don't gain
much more.
The saving is in some areas with bad osm data (useless high point
density) up to 25%.
In general it saves only 5% in file size.
Consider this patch as an alpha release, which should only show the
possibilities.
For the release it will need at least an option at the commandline for
setting the error distance.
Also I'm not sure, if the StyledConverter.java is the correct file for
this patch. I've seen there is some filter infrastructure in the mkgmap
project, but I've no idea how to use it.
5
14
Hello,
I wonder if anyone has tried mkgmap-generated map on Garmin mobileXT
(symbian). Text labels (POI and streetnames) are all abbreviated. Burger
King appears as B K, but KFC is OK. A spell search on 'Burger' correctly
returns 'B K'.
Setting all labels as uppercase doesn't work though. I've tried
different options (latin1, lower-case in mkgmap and upcase, codepage in
osm2mp) but still the same problem. No such problem viewing the map in
mapsource.
I use osm2mp.pl to generate the mp file and the same mp file works OK
when compiled at mapcenter2. Attached are screenshots of mkgmap and
mapcenter2 generated maps for comparison.
best regards,
nyem
5
8
Hi,
Currently the default style creates a residential road for plazas
correctly marked with highway=pedestrian, area=yes. An example of such a
plaza can be found here:
http://openstreetmap.org/?lat=9.932554&lon=-84.071404&zoom=18&layers=B000FTF
A patch to correct this behaviour is attached. Comments are appreciated.
Cheers, Ben
diff --git a/resources/styles/default/lines b/resources/styles/default/lines
index 9594a9a..cc21b2c 100644
--- a/resources/styles/default/lines
+++ b/resources/styles/default/lines
@@ -24,7 +24,7 @@ highway=footway [0x16 road_class=0 road_speed=0 resolution 23]
highway=minor [0x06 road_class=1 road_speed=2 resolution 21]
highway=motorway {add oneway = yes } [0x01 road_class=4 road_speed=6 resolution 12]
highway=motorway_link [0x01 road_class=4 road_speed=3 resolution 16]
-highway=pedestrian [0x06 road_class=0 road_speed=0 resolution 22]
+highway=pedestrian & area!=yes [0x06 road_class=0 road_speed=0 resolution 22]
highway=primary [0x02 road_class=3 road_speed=4 resolution 19]
highway=primary_link [0x03 road_class=3 road_speed=3 resolution 19]
highway=residential | highway=living_street [0x06 road_class=0 road_speed=2 resolution 21]
@@ -40,7 +40,7 @@ highway=unclassified [0x06 road_class=1 road_speed=2 resolution 21]
highway=unsurfaced [0x0a road_class=0 road_speed=1 resolution 21]
# Mop up any unrecognised highway types
-highway=* [0x07 ]
+highway=* & area!=yes [0x07 ]
natural=coastline [0x15 resolution 12]
power=line [0x29 resolution 20]
diff --git a/resources/styles/default/polygons b/resources/styles/default/polygons
index 606f26f..74b5d74 100644
--- a/resources/styles/default/polygons
+++ b/resources/styles/default/polygons
@@ -42,4 +42,9 @@ natural=wood [0x50 resolution 18]
place=village [0x03 resolution 18]
+# squares and plazas
+highway=pedestrian & area=yes [0x17 resolution 20]
+# other highways that have area=yes set must be parking lots
+highway=* & area=yes [0x05 resolution 21]
+
waterway=riverbank [0x46 resolution 20]
6
16
> Steve - any chance that support for this will be added to mkgmap?
Yes, we need to add setting the draw priority and making the map transparent.
I can easily add an option to set the draw priority which I believe is simply a case of
setting a value in the TRE header.
I am not so sure about the ins and outs of transparency. I think it is just a case
of leaving out the background polygons. At one time mkgmap didn't add these and
people said that the maps were transparent. However they didn't appear to be so
for me, so there may be more to it. There is a flag that also appears to be
something to do with transparency too.
Anyway I will try those changes, and ask you to test it out if you don't mind.
It will be probably not be until the new year though.
..Steve
_________________________________________________________________
Are you a PC? Upload your PC story and show the world
http://clk.atdmt.com/UKM/go/122465942/direct/01/
5
7
I'm sorry if this was discussed before, I just subscribed!
In the version route-r806 the option --latin1 worked to get german
Umlauts displayed correctly (Using nocodepage option for osm2mp).
Now i tried r858 and r861, and runnig with same options the unlauts will
be displayed as ??, on Garmin oregon and QLandkarte.
This was pretty working for umlauts:
#java -Xmx512M -enableassertions -jar mkgmap-route-r806/mkgmap.jar
--latin1 --route --gmapsupp map1.mp
This produces ?? instead of umlauts:
java -Xmx512M -enableassertions -jar mkgmap-r861/mkgmap.jar --latin1
--route --gmapsupp map1.mp
Something known about this?
Best regards, Jan
5
11
I have my nuvi configured to select fastest route for car/motorcycle. In
the attached image, going from A to B it selected first a service way
(first red circle) through a petrol station, then another service way
instead of a two lanes residential one (second red circle) and finally
some steps (third circle). Blue line shows the correct route it should
have selected, obviously longer but I think better for a car. What is
not working here?
Regards
Carlos
4
13
Hi,
I have integrated Ben Konrath's Area POI patch into my code. I did the
following changes to Ben's code:
- Replaced the hard coded area to poi type mapping with the build in
rule sets. Shapes are checked against the point rules to add missing pois.
- Replaced the linear search (to avoid duplicated pois) with tile based
search
- Add buildings to polygons style
- Moved my helper classes to general directory
You have to add the --add-pois-to-areas to enable the Area POIs
generation. I'm not sure if we should generate a new rule set in the
style folder for this purpose. It works pretty good using the point
rules but it might be confusing.
Thanks Ben for providing the ray cast code to check for points in polygons.
Thanks
Berni.
Index: test/uk/me/parabola/mkgmap/general/PointInShapeTest.java
===================================================================
--- test/uk/me/parabola/mkgmap/general/PointInShapeTest.java (.../upstream/mkgmap) (revision 0)
+++ test/uk/me/parabola/mkgmap/general/PointInShapeTest.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -0,0 +1,289 @@
+/**
+ *
+ */
+package uk.me.parabola.mkgmap.general;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+/**
+ * @author ben
+ *
+ */
+public class PointInShapeTest {
+
+ MapShape square, triangle, line;
+ int squareSize = 4;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ // Square
+ List<Coord> points = Arrays.asList(
+ new Coord(0, 0),
+ new Coord(0, squareSize),
+ new Coord(squareSize, squareSize),
+ new Coord(squareSize, 0),
+ new Coord(0,0)
+ );
+ square = new MapShape();
+ square.setPoints(points);
+
+ // Triangle
+ points = Arrays.asList(
+ new Coord(0,0),
+ new Coord(4,4),
+ new Coord(8,0),
+ new Coord(0,0)
+ );
+ triangle = new MapShape();
+ triangle.setPoints(points);
+
+ // Line
+ points = Arrays.asList(
+ new Coord(2,5),
+ new Coord(12,1)
+ );
+ line = new MapShape();
+ line.setPoints(points);
+ }
+
+ @Test
+ public void testLinePointsInsideSquare() {
+
+ // inside square, 1 unit from corners
+ List<Coord> points = Arrays.asList(
+ new Coord(1, squareSize/2),
+ new Coord(squareSize/2, squareSize - 1),
+ new Coord(squareSize - 1, squareSize/2),
+ new Coord(squareSize/2, 1)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be inside square",
+ square.contains(coord));
+ }
+
+ // on the line
+ points = Arrays.asList(
+ new Coord(0, squareSize/2),
+ new Coord(squareSize/2, squareSize),
+ new Coord(squareSize, squareSize/2),
+ new Coord(squareSize/2, 0)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside square",
+ square.contains(coord));
+ }
+ }
+
+ @Test
+ public void testLinePointsOutsideSquare() {
+
+ // outside square, 1 unit from line
+ List<Coord> points = Arrays.asList(
+ new Coord(-1, squareSize/2),
+ new Coord(squareSize/2, squareSize + 1),
+ new Coord(squareSize + 1, squareSize/2),
+ new Coord(squareSize/2, -1)
+ );
+ for (Coord coord : points) {
+ assertFalse("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside square",
+ square.contains(coord));
+ }
+ }
+
+ @Test
+ public void testCornerPointsInsideSquare() {
+ // corner points
+ for (Coord cornerpoint : square.getPoints()) {
+ Coord co = new Coord(cornerpoint.getLatitude(), cornerpoint.getLongitude());
+ assertTrue("corner point (" + co.getLatitude() + ", " + co.getLongitude() + ") should be outside square",
+ square.contains(co));
+ }
+
+ // sub shape
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? -1 : 1;
+ int yadd = cornerpoint.getLongitude() > 0 ? -1 : 1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertTrue("point (" + x + ", " + y + ") should be inside square", square.contains(co));
+ }
+
+ // tests above / below corner points, on the outside edge
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? -1 : 1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude();
+ Coord co = new Coord(x, y);
+ assertTrue("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+
+ // tests to the right / left side of corner points, on square edge
+ for (Coord cornerpoint : square.getPoints()) {
+ int yadd = cornerpoint.getLongitude() > 0 ? -1 : 1;
+ int x = cornerpoint.getLatitude();
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertTrue("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+ }
+
+ @Test
+ public void testCornerPointsOutsideSquare() {
+
+ // tests above / below corner points, outside squate
+ for (Coord cornerpoint : square.getPoints()) {
+ int yadd = cornerpoint.getLongitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude();
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+
+ // tests to the right / left side of corner points, outside square
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude();
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+
+ // super shape
+ for (Coord cornerpoint : square.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? 1 : -1;
+ int yadd = cornerpoint.getLongitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside square", square.contains(co));
+ }
+ }
+
+
+ @Test
+ public void testLinePointsInsideTriangle() {
+ // inside triangle, above / below lines
+ List<Coord> points = Arrays.asList(
+ new Coord(2,1),
+ new Coord(6,1),
+ new Coord(4,1)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be inside triangle",
+ triangle.contains(coord));
+ }
+
+ // on lines
+ points = Arrays.asList(
+ new Coord(2,2),
+ new Coord(6,2),
+ new Coord(4,0)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+ }
+
+ @Test
+ public void testLinePointsOutsideTriangle() {
+ // outside triangle, above / below lines
+ List<Coord> points = Arrays.asList(
+ new Coord(2,3),
+ new Coord(6,3),
+ new Coord(4,-1)
+ );
+ for (Coord coord : points) {
+ assertFalse("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+ }
+
+ @Test
+ public void testCornerPointsInsideTriangle() {
+ // corner points
+ for (Coord cornerpoint : triangle.getPoints()) {
+ assertTrue("point (" + cornerpoint.getLatitude() + ", " + cornerpoint.getLongitude() + ") should be outside triangle",
+ triangle.contains(cornerpoint));
+ }
+
+ // sub shape
+ List<Coord> points = Arrays.asList(
+ new Coord(2,1),
+ new Coord(4,3),
+ new Coord(6,1)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be inside triangle",
+ triangle.contains(coord));
+ }
+
+ // beside points, on edge
+ points = Arrays.asList(
+ new Coord(1,0),
+ new Coord(7,0)
+ );
+ for (Coord coord : points) {
+ assertTrue("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+ }
+
+ @Test
+ public void testCornerPointsOutsideTriangle() {
+ // above points
+ for (Coord coord : triangle.getPoints()) {
+ Coord co = new Coord(coord.getLatitude(), coord.getLongitude() + 1);
+ assertFalse("point (" + co.getLatitude() + ", " + co.getLongitude() + ") should be outside triangle",
+ triangle.contains(co));
+ }
+
+ // outside triangle, beside / below lines
+ List<Coord> points = Arrays.asList(
+ new Coord(-1,0),
+ new Coord(0,-1),
+ new Coord(3,4),
+ new Coord(5,4),
+ new Coord(9,0),
+ new Coord(8,-1)
+ );
+ for (Coord coord : points) {
+ assertFalse("point (" + coord.getLatitude() + ", " + coord.getLongitude() + ") should be outside triangle",
+ triangle.contains(coord));
+ }
+
+ // super shape
+ for (Coord cornerpoint : triangle.getPoints()) {
+ int xadd = cornerpoint.getLatitude() > 0 ? 1 : -1;
+ int yadd = cornerpoint.getLongitude() > 0 ? 1 : -1;
+ int x = cornerpoint.getLatitude() + xadd;
+ int y = cornerpoint.getLongitude() + yadd;
+ Coord co = new Coord(x, y);
+ assertFalse("point (" + x + ", " + y + ") should be outside triangle", triangle.contains(co));
+ }
+
+ }
+
+ @Test
+ public void testLine() {
+ // midpoint
+ Coord co = new Coord(7,3);
+ assertFalse("point (" + co.getLatitude() + ", " + co.getLongitude() + ") should be outside line",
+ line.contains(co));
+
+ }
+}
Index: src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -236,6 +236,10 @@
public void setMapId(int id) {
mapId = id;
}
+
+ public void setPoiDisplayFlags(byte poiDisplayFlags) {
+ this.poiDisplayFlags = poiDisplayFlags;
+ }
public int getMapInfoSize() {
return mapInfoSize;
Index: src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/trergn/TREFile.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/trergn/TREFile.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -315,6 +315,10 @@
header.setBounds(area);
}
+ public void setPoiDisplayFlags(byte b) {
+ header.setPoiDisplayFlags(b);
+ }
+
public String[] getCopyrights() {
if (!isReadable())
throw new IllegalStateException("not open for reading");
Index: src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -16,6 +16,7 @@
*/
package uk.me.parabola.imgfmt.app.lbl;
+import java.util.Vector;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import uk.me.parabola.imgfmt.app.Label;
@@ -23,6 +24,94 @@
* @author Steve Ratcliffe
*/
public class POIRecord {
+
+ class SimpleStreetPhoneNumber // Helper Class to encode Street Phone Numbers
+ {
+ /**
+ Street and Phone numbers can be stored in two different ways in the poi record
+ Simple Number that only contain digits are coded in base 11 coding.
+ This helper class tries to code the given number. If the number contains other
+ chars like in 4a the coding fails and the caller has to use a Label instead
+ */
+
+ private byte encodedNumber[] = null;
+ private int encodedSize = 0;
+
+ public boolean set(String number)
+ {
+ int i = 0;
+ int j = 0;
+ int val = 0;
+
+ // remove sourounding whitespaces to increase chance for simple encoding
+
+ number = number.trim();
+
+ encodedNumber = new byte[(number.length()/2)+2];
+
+ while(i < number.length())
+ {
+ int c1 = 0;
+ int c2 = 0;
+
+ c1 = decodeChar(number.charAt(i));
+ i++;
+
+ if(i < number.length())
+ {
+ c2 = decodeChar(number.charAt(i));
+ i++;
+ }
+ else
+ c2 = 10;
+
+ if(c1 < 0 || c1 > 10 || c2 < 0 || c2 > 10) // Only 0-9 and - allowed
+ {
+ return false;
+ }
+
+ val = c1 * 11 + c2; // Encode as base 11
+
+ if(i < 3 || i >= number.length()) // first byte needs special marking with 0x80
+ val = val | 0x80; // If this is not set would be treated as label pointer
+
+ encodedNumber[j++] = (byte)val;
+ }
+
+ if((val & 0x80) == 0 || i < 3) // terminate string with 0x80 if not done
+ {
+ val = 0xF8;
+ encodedNumber[j++] = (byte)val;
+ }
+
+ encodedSize = j;
+
+ return true;
+ }
+
+ public void write(ImgFileWriter writer)
+ {
+ for(int i = 0; i < encodedSize; i++)
+ writer.put(encodedNumber[i]);
+ }
+
+ public boolean isUsed()
+ {
+ return (encodedSize > 0);
+ }
+
+ public int getSize()
+ {
+ return encodedSize;
+ }
+
+ private int decodeChar(char ch)
+ {
+ return (ch - '0');
+ }
+
+ }
+
public static final byte HAS_STREET_NUM = 0x01;
public static final byte HAS_STREET = 0x02;
public static final byte HAS_CITY = 0x04;
@@ -43,13 +132,16 @@
private int offset = -1;
private Label poiName;
- private int streetNumber;
+ private SimpleStreetPhoneNumber simpleStreetNumber = new SimpleStreetPhoneNumber();
+ private SimpleStreetPhoneNumber simplePhoneNumber = new SimpleStreetPhoneNumber();
+
private Label streetName;
private Label streetNumberName; // Used for numbers such as 221b
+ private Label complexPhoneNumber; // Used for numbers such as 221b
+
+ private City city = null;
+ private char zipIndex = 0;
- private char cityIndex ;
- private char zipIndex ;
-
private String phoneNumber;
public void setLabel(Label label) {
@@ -60,14 +152,35 @@
this.streetName = label;
}
+ public boolean setSimpleStreetNumber(String streetNumber)
+ {
+ return simpleStreetNumber.set(streetNumber);
+ }
+
+ public void setComplexStreetNumber(Label label)
+ {
+ streetNumberName = label;
+ }
+
+ public boolean setSimplePhoneNumber(String phone)
+ {
+ return simplePhoneNumber.set(phone);
+ }
+
+ public void setComplexPhoneNumber(Label label)
+ {
+ complexPhoneNumber = label;
+ }
+
+
public void setZipIndex(int zipIndex)
{
this.zipIndex = (char) zipIndex;
}
- public void setCityIndex(int cityIndex)
+ public void setCity(City city)
{
- this.cityIndex = (char) cityIndex;
+ this.city = city;
}
void write(ImgFileWriter writer, byte POIGlobalFlags, int realofs,
@@ -82,11 +195,21 @@
if (POIGlobalFlags != getPOIFlags())
writer.put(getWrittenPOIFlags(POIGlobalFlags));
+ if (streetNumberName != null)
+ {
+ int labOff = streetNumberName.getOffset();
+ writer.put((byte)((labOff & 0x7F0000) >> 16));
+ writer.putChar((char)(labOff & 0xFFFF));
+ }
+ else if (simpleStreetNumber.isUsed())
+ simpleStreetNumber.write(writer);
+
if (streetName != null)
writer.put3(streetName.getOffset());
- if (cityIndex > 0)
+ if (city != null)
{
+ char cityIndex = (char) city.getIndex();
if(numCities > 255)
writer.putChar(cityIndex);
else
@@ -100,44 +223,60 @@
else
writer.put((byte)zipIndex);
}
+
+ if (complexPhoneNumber != null)
+ {
+ int labOff = complexPhoneNumber.getOffset();
+ writer.put((byte)((labOff & 0x7F0000) >> 16));
+ writer.putChar((char)(labOff & 0xFFFF));
+ }
+ else if (simplePhoneNumber.isUsed())
+ simplePhoneNumber.write(writer);
}
byte getPOIFlags() {
byte b = 0;
if (streetName != null)
b |= HAS_STREET;
- if (cityIndex > 0)
+ if (simpleStreetNumber.isUsed() || streetNumberName != null)
+ b |= HAS_STREET_NUM;
+ if (city != null)
b |= HAS_CITY;
if (zipIndex > 0)
- b |= HAS_ZIP;
+ b |= HAS_ZIP;
+ if (simplePhoneNumber.isUsed() || complexPhoneNumber != null)
+ b |= HAS_PHONE;
return b;
}
byte getWrittenPOIFlags(byte POIGlobalFlags)
{
- int mask;
- int flag = 0;
- int j = 0;
+ int mask;
+ int flag = 0;
+ int j = 0;
- int usedFields = getPOIFlags();
+ int usedFields = getPOIFlags();
- /* the local POI flag is really tricky
- if a bit is not set in the global mask
- we have to skip this bit in the local mask.
- In other words the meaning of the local bits
- change influenced by the global bits */
+ /* the local POI flag is really tricky if a bit is not set in the global mask
+ we have to skip this bit in the local mask. In other words the meaning of the local bits
+ change influenced by the global bits */
+
+ for(byte i = 0; i < 6; i++)
+ {
+ mask = 1 << i;
- for (byte i = 0; i < 6; i++) {
- mask = 1 << i;
-
- if ((mask & POIGlobalFlags) == mask) {
- if ((mask & usedFields) == mask)
- flag |= (1 << j);
- j++;
+ if((mask & POIGlobalFlags) == mask)
+ {
+ if((mask & usedFields) == mask)
+ flag = flag | (1 << j);
+ j++;
+ }
+
}
- }
- return (byte) flag;
+ flag = flag | 0x80; // gpsmapedit asserts for this bit set
+
+ return (byte) flag;
}
/**
@@ -150,9 +289,17 @@
int size = 3;
if (POIGlobalFlags != getPOIFlags())
size += 1;
+ if (simpleStreetNumber.isUsed())
+ size += simpleStreetNumber.getSize();
+ if (streetNumberName != null)
+ size += 3;
+ if (simplePhoneNumber.isUsed())
+ size += simplePhoneNumber.getSize();
+ if (complexPhoneNumber != null)
+ size += 3;
if (streetName != null)
- size += 3;
- if (cityIndex > 0)
+ size += 3;
+ if (city != null)
{
/*
depending on how many cities are in the LBL block we have
@@ -160,9 +307,9 @@
*/
if(numCities > 255)
- size += 2;
+ size += 2;
else
- size += 1;
+ size += 1;
}
if (zipIndex > 0)
{
Index: src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/lbl/PlacesFile.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -20,6 +20,8 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import uk.me.parabola.imgfmt.app.Label;
@@ -33,7 +35,8 @@
public class PlacesFile {
private final Map<String, Country> countries = new LinkedHashMap<String, Country>();
private final Map<String, Region> regions = new LinkedHashMap<String, Region>();
- private final List<City> cities = new ArrayList<City>();
+ private final Map<String, City> cities = new LinkedHashMap<String, City>();
+ private final SortedMap<String, City> cityList = new TreeMap<String, City>();
private final Map<String, Zip> postalCodes = new LinkedHashMap<String, Zip>();
private final List<POIRecord> pois = new ArrayList<POIRecord>();
@@ -62,8 +65,12 @@
r.write(writer);
placeHeader.endRegions(writer.position());
- for (City c : cities)
+ for (String s : cityList.keySet())
+ {
+ City c = cityList.get(s);
c.write(writer);
+ }
+
placeHeader.endCity(writer.position());
int poistart = writer.position();
@@ -79,56 +86,122 @@
}
Country createCountry(String name, String abbr) {
- Country c = new Country(countries.size()+1);
-
+
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(name, c);
+ Label l = lblFile.newLabel(s);
+ c.setLabel(l);
+ countries.put(s, c);
+ }
return c;
}
Region createRegion(Country country, String name, String abbr) {
- Region r = new Region(country, regions.size()+1);
-
+
String s = abbr != null ? name + (char)0x1d + abbr : name;
- Label l = lblFile.newLabel(s);
- r.setLabel(l);
-
- regions.put(name, r);
+ String uniqueRegionName = s.toUpperCase().concat(Long.toString(country.getIndex()));
+
+ Region r = regions.get(uniqueRegionName);
+
+ if(r == null)
+ {
+ r = new Region(country, regions.size()+1);
+ Label l = lblFile.newLabel(s);
+ r.setLabel(l);
+ regions.put(uniqueRegionName, r);
+ }
return r;
}
- City createCity(Country country, String name) {
- City c = new City(country, cities.size()+1);
+ City createCity(Country country, String name, boolean unique) {
+
+ String uniqueCityName = name.toUpperCase().concat("_C").concat(Long.toString(country.getIndex()));
+
+ City c = null;
- Label l = lblFile.newLabel(name);
- c.setLabel(l); // label may be ignored if pointref is set
+ if(!unique)
+ c = cities.get(uniqueCityName);
+
+ if(c == null)
+ {
+ c = new City(country);
- cities.add(c);
+ Label l = lblFile.newLabel(name);
+ c.setLabel(l);
+
+ /*
+ Adding 0 in between is important to get right sort order !!!
+ We have to make sure that "Kirchdorf" gets sorted before "Kirchdorf am Inn"
+ If this order is not correct nuvi would not find right city
+ */
+
+ cityList.put(name + " 0" + c, c);
+ cities.put(uniqueCityName, c);
+ }
+
return c;
- }
+ }
- City createCity(Region region, String name) {
- City c = new City(region, cities.size()+1);
+ City createCity(Region region, String name, boolean unique) {
+
+ String uniqueCityName = name.toUpperCase().concat("_R").concat(Long.toString(region.getIndex()));
+
+ City c = null;
- Label l = lblFile.newLabel(name);
- c.setLabel(l); // label may be ignored if pointref is set
+ if(!unique)
+ c = cities.get(uniqueCityName);
+
+ if(c == null)
+ {
+ c = new City(region);
- cities.add(c);
+ Label l = lblFile.newLabel(name);
+ c.setLabel(l);
+
+ /*
+ Adding 0 in between is important to get right sort order !!!
+ We have to make sure that "Kirchdorf" gets sorted before "Kirchdorf am Inn"
+ If this order is not correct nuvi would not find right city
+ */
+
+ cityList.put(name + " 0" + c, c);
+ cities.put(uniqueCityName, c);
+ }
+
return c;
}
+ private void sortCities()
+ {
+ int index = 1;
+
+ for (String s : cityList.keySet())
+ {
+ City c = cityList.get(s);
+ c.setIndex(index++);
+ }
+ }
+
Zip createZip(String code) {
- Zip z = new Zip(postalCodes.size()+1);
+
+ Zip z = postalCodes.get(code);
+
+ if(z == null)
+ {
+ z = new Zip(postalCodes.size()+1);
- Label l = lblFile.newLabel(code);
- z.setLabel(l);
+ Label l = lblFile.newLabel(code);
+ z.setLabel(l);
- postalCodes.put(code, z);
+ postalCodes.put(code, z);
+ }
return z;
}
@@ -146,6 +219,9 @@
}
void allPOIsDone() {
+
+ sortCities();
+
poisClosed = true;
byte poiFlags = 0;
Index: src/uk/me/parabola/imgfmt/app/lbl/City.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/lbl/City.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/lbl/City.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -30,7 +30,7 @@
private static final int POINT_REF = 0x8000;
private static final int REGION_IS_COUNTRY = 0x4000;
- private final int index;
+ private int index = -1;
private final Region region;
private final Country country;
@@ -49,13 +49,13 @@
// null if the location is being specified.
private Label label;
- public City(Region region, int index) {
+ public City(Region region) {
this.region = region;
this.country = null;
this.index = index;
}
- public City(Country country, int index) {
+ public City(Country country) {
this.country = country;
this.region = null;
this.index = index;
@@ -83,9 +83,15 @@
}
public int getIndex() {
+ if (index == -1)
+ throw new IllegalStateException("Offset not known yet.");
return index;
}
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
public void setLabel(Label label) {
pointRef = false;
this.label = label;
Index: src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/lbl/LBLFile.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -147,14 +147,18 @@
return places.createRegion(country, region, abbr);
}
- public City createCity(Region region, String city) {
- return places.createCity(region, city);
+ public City createCity(Region region, String city, boolean unique) {
+ return places.createCity(region, city, unique);
}
- public City createCity(Country country, String city) {
- return places.createCity(country, city);
+ public City createCity(Country country, String city, boolean unique) {
+ return places.createCity(country, city, unique);
}
+ public Zip createZip(String code) {
+ return places.createZip(code);
+ }
+
public void allPOIsDone() {
places.allPOIsDone();
}
Index: src/uk/me/parabola/imgfmt/app/map/Map.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/map/Map.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/imgfmt/app/map/Map.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -225,6 +225,14 @@
treFile.addPolygonOverview(ov);
}
+ /**
+ * Set the point of interest flags.
+ * @param flags The POI flags.
+ */
+ public void setPoiDisplayFlags(int flags) {
+ treFile.setPoiDisplayFlags((byte) flags);
+ }
+
public void addMapObject(MapObject item) {
rgnFile.addMapObject(item);
}
Index: src/uk/me/parabola/mkgmap/build/Locator.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/Locator.java (.../upstream/mkgmap) (revision 0)
+++ src/uk/me/parabola/mkgmap/build/Locator.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2009 Bernhard Heibler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * The Locator tries to fill missing country, region, postal coude information
+ *
+ * The algorithm works like this:
+ *
+ * 1. Step: Go through all cities an check if they have useful country region info
+ * The best case is if the tags is_in:country and is_in:county are present thats easy.
+ * Some cities have is_in information that can be used. We check for three different
+ * formats:
+ *
+ * County, State, Country, Continent
+ * County, State, Country
+ * Continent, Country, State, County, ...
+ *
+ * In "openGeoDb countries" this info is pretty reliable since it was imported from a
+ * external db into osm. Other countries have very sparse is_in info.
+ *
+ * All this cities that have such info will end up in "city" list. All which lack
+ * such information in "location" list.
+ *
+ * 2. Step: Go through the "location" list and check if the is_in info has some relations
+ * to the cities we have info about.
+ *
+ * Especially hamlets often have no full is_in information. They only have one entry in
+ * is_in that points to the city they belong to. I will check if I can find the name
+ * of this city in the "City" list. If there are more with the same name I use the
+ * closest one. If we can't find the exact name I use fuzzy name search. Thats a
+ * workaround for german umlaute since sometimes there are used in the tags and
+ * sometimes there are written as ue ae oe.
+ *
+ * 3. Step: Do the same like in step 2 once again. This is used to support at least
+ * one level of recursion in is_in relations.
+ *
+ * If there is still no info found I use brute force and use the information from the
+ * next city. Has to be used for countries with poor is_in tagging.
+ *
+ * Author: Bernhard Heibler
+ * Create date: 02-Jan-2009
+ */
+
+package uk.me.parabola.mkgmap.build;
+
+import java.util.Collection;
+import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapPointFastFindMap;
+import uk.me.parabola.mkgmap.general.MapPointMultiMap;
+
+import java.util.Vector;
+
+public class Locator {
+
+ private final MapPointFastFindMap cityMap = new MapPointFastFindMap();
+ private final MapPointMultiMap fuzzyCityMap = new MapPointMultiMap();
+ private final java.util.Vector<MapPoint> placesMap = new Vector<MapPoint>();
+
+ private LocatorConfig locConfig = new LocatorConfig();
+
+ static double totalTime = 0;
+ static long totalFinds = 0;
+ private int autoFillLevel = 0;
+
+ public void addLocation(MapPoint p)
+ {
+ resolveIsInInfo(p); // Preprocess the is_in field
+
+ if(autoFillLevel < 1 && p.getCity() == null)
+ {
+ // Without autofill city name is the name of the tag
+ p.setCity(p.getName());
+ }
+
+ if(p.getCity() != null)
+ {
+ cityMap.put(p.getCity(), p);
+
+ fuzzyCityMap.put(fuzzyDecode(p.getCity()),p);
+
+ if(p.getName() != null && p.getCity().equals(p.getName()) == false) // Name variants ?
+ fuzzyCityMap.put(fuzzyDecode(p.getName()),p);
+ }
+ else
+ {
+ // All other places which do not seam to be a real city has to resolved later
+ placesMap.add(p);
+ }
+
+ }
+
+
+
+ public void setAutoFillLevel(int level)
+ {
+ autoFillLevel = level;
+ }
+
+ public void setDefaultCountry(String country, String abbr)
+ {
+ locConfig.setDefaultCountry(country, abbr);
+ }
+
+ public String fixCountryString(String country)
+ {
+ return locConfig.fixCountryString(country);
+ }
+
+ private String isCountry(String country)
+ {
+ return locConfig.isCountry(country);
+ }
+
+ public String getCountryCode(String country)
+ {
+ return locConfig.getCountryCode(country);
+ }
+
+ public int getPOIDispFlag(String country)
+ {
+ return locConfig.getPoiDispFlag(country);
+ }
+
+ private boolean isOpenGeoDBCountry(String country)
+ {
+ // Countries that have open geo db data in osm
+ // Right now this are only germany, austria and swizerland
+ return locConfig.isOpenGeoDBCountry(country);
+ }
+
+ private boolean isContinent(String continent)
+ {
+ return locConfig.isContinent(continent);
+ }
+
+
+ /**
+ * resolveIsInInfo tries to get country and region info out of the is_in field
+ * @param p Point to process
+ */
+ private void resolveIsInInfo(MapPoint p)
+ {
+ if(p.getCountry() != null)
+ p.setCountry(fixCountryString(p.getCountry()));
+
+ if(p.getCountry() != null && p.getRegion() != null && p.getCity() == null)
+ {
+ p.setCity(p.getName());
+ return;
+ }
+
+ if(p.getIsIn() != null)
+ {
+ String cityList[] = p.getIsIn().split(",");
+
+ //System.out.println(p.getIsIn());
+
+ // is_in content is not well defined so we try our best to get some info out of it
+ // Format 1 popular in Germany: "County,State,Country,Continent"
+
+ if(cityList.length > 1 &&
+ isContinent(cityList[cityList.length-1])) // Is last a continent ?
+ {
+ // The one before contient should be the country
+ p.setCountry(fixCountryString(cityList[cityList.length-2].trim()));
+
+ // aks the config which info to use for region info
+ int offset = locConfig.getRegionOffset(p.getCountry()) + 1;
+
+ if(cityList.length > offset)
+ p.setRegion(cityList[cityList.length-(offset+1)].trim());
+
+ }
+
+ // Format 2 other way round: "Continent,Country,State,County"
+
+ if(cityList.length > 1 && isContinent(cityList[0])) // Is first a continent ?
+ {
+ // The one before contient should be the country
+ p.setCountry(fixCountryString(cityList[1].trim()));
+
+ int offset = locConfig.getRegionOffset(p.getCountry()) + 1;
+
+ if(cityList.length > offset)
+ p.setRegion(cityList[offset].trim());
+ }
+
+ // Format like this "County,State,Country"
+
+ if(p.getCountry() == null && cityList.length > 0)
+ {
+ // I don't like to check for a list of countries but I don't want other stuff in country field
+
+ String countryStr = isCountry(cityList[cityList.length-1]);
+
+ if(countryStr != null)
+ {
+ p.setCountry(countryStr);
+
+ int offset = locConfig.getRegionOffset(countryStr) + 1;
+
+ if(cityList.length > offset)
+ p.setRegion(cityList[cityList.length-(offset+1)].trim());
+ }
+ }
+ }
+
+ if(p.getCountry() != null && p.getRegion() != null && p.getCity() == null)
+ {
+ // In OpenGeoDB Countries I don't want to mess up the info which city is a real independent
+ // Community in all other countries I just have to do it
+
+ if(isOpenGeoDBCountry(p.getCountry()) == false)
+ p.setCity(p.getName());
+ }
+ }
+
+ public MapPoint findNextPoint(MapPoint p)
+ {
+ long startTime = System.nanoTime();
+
+ MapPoint nextPoint = null;
+
+ nextPoint = cityMap.findNextPoint(p);
+
+ totalFinds++;
+ totalTime = totalTime + ((System.nanoTime() - startTime)/1e9);
+ return nextPoint;
+ }
+
+ public MapPoint findByCityName(MapPoint p)
+ {
+ MapPoint near = null;
+ Double minDist = Double.MAX_VALUE;
+ Collection <MapPoint> nextCityList = null;
+
+ if(p.getCity() == null)
+ return null;
+
+ nextCityList = cityMap.getList(p.getCity());
+
+ if(nextCityList != null)
+ {
+ for (MapPoint nextCity: nextCityList)
+ {
+ Double dist = p.getLocation().distance(nextCity.getLocation());
+
+ if(dist < minDist)
+ {
+ minDist = dist;
+ near = nextCity;
+ }
+ }
+ }
+
+ nextCityList = fuzzyCityMap.getList(fuzzyDecode(p.getCity()));
+
+ if(nextCityList != null)
+ {
+ for (MapPoint nextCity: nextCityList)
+ {
+ Double dist = p.getLocation().distance(nextCity.getLocation());
+
+ if(dist < minDist)
+ {
+ minDist = dist;
+ near = nextCity;
+ }
+ }
+ }
+
+ if(near != null && minDist < 30000) // Wrong hit more the 30 km away ?
+ return near;
+ else
+ return null;
+ }
+
+ private MapPoint findCity(MapPoint place, boolean fuzzy)
+ {
+ MapPoint near = null;
+ Double minDist = Double.MAX_VALUE;
+ Collection <MapPoint> nextCityList = null;
+
+ String isIn = place.getIsIn();
+
+ if(isIn != null)
+ {
+ String cityList[] = isIn.split(",");
+
+ // Go through the isIn string and check if we find a city with this name
+ // Lets hope we find the next bigger city
+
+ for(int i = 0; i < cityList.length; i++)
+ {
+ String biggerCityName=cityList[i].trim();
+
+
+ if(fuzzy == false)
+ nextCityList = cityMap.getList(biggerCityName);
+ else
+ nextCityList = fuzzyCityMap.getList(fuzzyDecode(biggerCityName));
+
+ if(nextCityList != null)
+ {
+ for (MapPoint nextCity: nextCityList)
+ {
+ Double dist = place.getLocation().distance(nextCity.getLocation());
+
+ if(dist < minDist)
+ {
+ minDist = dist;
+ near = nextCity;
+ }
+ }
+ }
+ }
+
+ if (autoFillLevel > 3) // Some debug output to find suspicios relations
+ {
+
+ if(near != null && minDist > 30000)
+ {
+ System.out.println("Locator: " + place.getName() + " is far away from " +
+ near.getName() + " " + (minDist/1000.0) + " km is_in" + place.getIsIn());
+ if(nextCityList != null)
+ System.out.println("Number of cities with this name: " + nextCityList.size());
+ }
+
+ //if(near != null && fuzzy)
+ //{
+ // System.out.println("Locator: " + place.getName() + " may belong to " +
+ // near.getName() + " is_in" + place.getIsIn());
+ //}
+ }
+ }
+
+ return near;
+ }
+
+ public void resolve() {
+
+ if(autoFillLevel < 0)
+ return; // Nothing to do if autofill is fulli disabled
+
+ if(autoFillLevel > 2)
+ {
+ System.out.println("\nLocator City Map contains " + cityMap.size() + " entries");
+ System.out.println("Locator Places Map contains " + placesMap.size() + " entries");
+ }
+
+ int runCount = 0;
+ int maxRuns = 2;
+ int unresCount;
+
+ do
+ {
+ unresCount=0;
+
+ for (int i = 0; i < placesMap.size(); i++)
+ {
+ MapPoint place = placesMap.get(i);
+
+ if(place != null)
+ {
+
+ // first lets try exact name
+
+ MapPoint near = findCity(place, false);
+
+
+ // if this didn't worked try to workaround german umlaute
+
+ if(near == null)
+ near = findCity(place, true);
+
+ if(autoFillLevel > 3 && near == null && (runCount + 1) == maxRuns)
+ {
+ if(place.getIsIn() != null)
+ System.out.println("Locator: CAN't locate " + place.getName() + " is_in " + place.getIsIn()
+ + " " + place.getLocation().toOSMURL());
+ }
+
+
+ if(near != null)
+ {
+ place.setCity(near.getCity());
+ place.setZip(near.getZip());
+ }
+ else if (autoFillLevel > 1 && (runCount + 1) == maxRuns)
+ {
+ // In the last resolve run just take info from the next known city
+ near = cityMap.findNextPoint(place);
+ }
+
+
+ if(near != null)
+ {
+ if(place.getRegion() == null)
+ place.setRegion(near.getRegion());
+
+ if(place.getCountry() == null)
+ place.setCountry(near.getCountry());
+
+ }
+
+ if(near == null)
+ unresCount++;
+
+ }
+ }
+
+ for (int i = 0; i < placesMap.size(); i++)
+ {
+ MapPoint place = placesMap.get(i);
+
+ if (place != null)
+ {
+ if( place.getCity() != null)
+ {
+ cityMap.put(place.getName(),place);
+ fuzzyCityMap.put(fuzzyDecode(place.getName()),place);
+ placesMap.set(i, null);
+ }
+ else if(autoFillLevel < 2 && (runCount + 1) == maxRuns)
+ {
+ place.setCity(place.getName());
+ cityMap.put(place.getName(),place);
+ }
+ }
+ }
+
+ runCount++;
+
+ if(autoFillLevel > 2)
+ System.out.println("Locator City Map contains " + cityMap.size() +
+ " entries after resolver run " + runCount + " Still unresolved " + unresCount);
+
+ }
+ while(unresCount > 0 && runCount < maxRuns);
+
+ }
+
+ public void printStat()
+ {
+ System.out.println("Locator Find called: " + totalFinds + " time");
+ System.out.println("Locator Find time: " + totalTime + " s");
+
+ cityMap.printStat();
+ }
+
+ private String fuzzyDecode(String stringToDecode)
+ {
+
+ if(stringToDecode == null)
+ return stringToDecode;
+
+ String decodeString = stringToDecode.toUpperCase().trim();
+
+ // German umlaut resolution
+ decodeString = decodeString.replaceAll("Ä","AE").replaceAll("Ü","UE").replaceAll("Ö","OE");
+
+ //if(decodeString.equals(stringToDecode) == false)
+ // System.out.println(stringToDecode + " -> " + decodeString);
+
+ return (decodeString);
+ }
+
+}
+
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/MapBuilder.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/build/MapBuilder.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -21,12 +21,12 @@
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.City;
import uk.me.parabola.imgfmt.app.lbl.Country;
+import uk.me.parabola.imgfmt.app.lbl.Zip;
+import uk.me.parabola.imgfmt.app.Label;
import uk.me.parabola.imgfmt.app.lbl.LBLFile;
import uk.me.parabola.imgfmt.app.lbl.POIRecord;
import uk.me.parabola.imgfmt.app.lbl.Region;
@@ -83,26 +83,55 @@
private static final int CLEAR_TOP_BITS = (32 - 15);
private final java.util.Map<MapPoint,POIRecord> poimap = new HashMap<MapPoint,POIRecord>();
- private final SortedMap<String, Object> sortedCities = new TreeMap<String, Object>();
+ private final java.util.Map<MapPoint,City> cityMap = new HashMap<MapPoint,City>();
+
private boolean doRoads;
+ private Locator locator = new Locator();
private Country country;
private Region region;
- private String countryName = "UNITED KINGDOM";
- private String countryAbbr = "GBR";
+ private String countryName = "COUNTRY";
+ private String countryAbbr = "ABC";
private String regionName;
private String regionAbbr;
+ private int locationAutofillLevel = 0;
+ private boolean poiAddresses = true;
+ private int poiDisplayFlags = 0;
public MapBuilder() {
regionName = null;
}
public void config(EnhancedProperties props) {
+
+ String autoFillPar;
+
countryName = props.getProperty("country-name", countryName);
countryAbbr = props.getProperty("country-abbr", countryAbbr);
regionName = props.getProperty("region-name", null);
regionAbbr = props.getProperty("region-abbr", null);
+
+ if(props.getProperty("no-poi-address", null) != null)
+ poiAddresses = false;
+
+ autoFillPar = props.getProperty("location-autofill", null);
+
+ if(autoFillPar != null)
+ {
+ try
+ {
+ locationAutofillLevel = Integer.parseInt(autoFillPar);
+ }
+ catch (Exception e)
+ {
+ locationAutofillLevel = 1;
+ }
+ }
+
+ locator.setAutoFillLevel(locationAutofillLevel);
+
+
}
/**
@@ -123,6 +152,7 @@
if(regionName != null)
region = lblFile.createRegion(country, regionName, regionAbbr);
+ processCities(map, src);
processPOIs(map, src);
//preProcessRoads(map, src);
processOverviews(map, src);
@@ -157,52 +187,211 @@
}
/**
- * First stage of handling POIs
+ * Processing of Cities
*
- * POIs need to be handled first, because we need the offsets
- * in the LBL file.
+ * Fills the city list in lbl block that is required for find by name
+ * It also builds up information that is required to get address info
+ * for the POIs
*
* @param map The map.
* @param src The map data.
*/
- private void processPOIs(Map map, MapDataSource src) {
+ private void processCities(Map map, MapDataSource src) {
LBLFile lbl = map.getLblFile();
- // gpsmapedit doesn't sort the city names so to be
- // friendly we generate the city objects in alphabetic
- // order - to do that we first build a map from city
- // name to the associated MapPoint - we don't want to
- // be fooled by duplicate names so suffix the name
- // with the object to make it unique
+ locator.setDefaultCountry(countryName, countryAbbr);
+
+ // collect the names of the cities
for (MapPoint p : src.getPoints()) {
if(p.isCity() && p.getName() != null)
- sortedCities.put(p.getName() + "@" + p, p);
+ locator.addLocation(p); // Put the city info the map for missing info
}
- // now loop through the sorted keys and retrieve
- // the MapPoint associated with the key - now we
- // can create the City object and remember it for later
- for (String s : sortedCities.keySet()) {
- MapPoint p = (MapPoint)sortedCities.get(s);
- City c;
- if(region != null)
- c = lbl.createCity(region, p.getName());
- else
- c = lbl.createCity(country, p.getName());
- sortedCities.put(s, c);
+ if(locationAutofillLevel > 0)
+ locator.resolve(); // Try to fill missing information that include search of next city
+
+ for (MapPoint p : src.getPoints())
+ {
+ if(p.isCity() && p.getName() != null)
+ {
+ Country thisCountry;
+ Region thisRegion;
+ City thisCity;
+
+ String CountryStr = p.getCountry();
+ String RegionStr = p.getRegion();
+
+ if(CountryStr != null)
+ thisCountry = lbl.createCountry(CountryStr, locator.getCountryCode(CountryStr));
+ else
+ thisCountry = country;
+
+ if(RegionStr != null)
+ {
+ thisRegion = lbl.createRegion(thisCountry,RegionStr, null);
+ }
+ else
+ thisRegion = region;
+
+ if(thisRegion != null)
+ thisCity = lbl.createCity(thisRegion, p.getName(), true);
+ else
+ thisCity = lbl.createCity(thisCountry, p.getName(), true);
+
+ cityMap.put(p, thisCity);
+ }
}
- // if point has a nearest city, create a POIRecord to
- // reference it
+ }
+
+ private void processPOIs(Map map, MapDataSource src) {
+
+ LBLFile lbl = map.getLblFile();
+ long poiAddrCountr = 0;
+ boolean checkedForPoiDispFlag = false;
+ boolean doAutofill;
+
for (MapPoint p : src.getPoints()) {
- MapPoint nearestCityPoint = p.getNearestCityPoint();
- if(nearestCityPoint != null && p.getName() != null) {
- POIRecord r = lbl.createPOI(p.getName());
- City nearestCity = (City)sortedCities.get(nearestCityPoint.getName() + "@" + nearestCityPoint);
- r.setCityIndex(nearestCity.getIndex());
+
+ if(p.isCity() == false &&
+ (p.isRoadNamePOI() || poiAddresses))
+ {
+ if(locationAutofillLevel > 0 || p.isRoadNamePOI())
+ doAutofill = true;
+ else
+ doAutofill = false;
+
+
+ String CountryStr = p.getCountry();
+ String RegionStr = p.getRegion();
+ String ZipStr = p.getZip();
+ String CityStr = p.getCity();
+ boolean guessed = false;
+
+ if(CityStr != null || ZipStr != null ||RegionStr != null || CountryStr != null)
+ poiAddrCountr++;
+
+ if(CountryStr != null)
+ CountryStr = locator.fixCountryString(CountryStr);
+
+ if(CountryStr == null || RegionStr == null || (ZipStr == null && CityStr == null))
+ {
+ MapPoint nextCity = locator.findByCityName(p);
+
+ if(doAutofill && nextCity == null)
+ nextCity = locator.findNextPoint(p);
+
+ if(nextCity != null)
+ {
+ guessed = true;
+
+ if (CountryStr == null) CountryStr = nextCity.getCountry();
+ if (RegionStr == null) RegionStr = nextCity.getRegion();
+
+ if(doAutofill)
+ {
+ if(ZipStr == null)
+ {
+ String CityZipStr = nextCity.getZip();
+
+ // Ignore list of Zips seperated by ;
+
+ if(CityZipStr != null && CityZipStr.indexOf(',') < 0)
+ ZipStr = CityZipStr;
+ }
+
+ if(CityStr == null) CityStr = nextCity.getCity();
+ }
+
+ }
+ }
+
+
+ if(CountryStr != null && checkedForPoiDispFlag == false)
+ {
+ // Different countries require different address notation
+
+ poiDisplayFlags = locator.getPOIDispFlag(CountryStr);
+ checkedForPoiDispFlag = true;
+ }
+
+
+ if(p.isRoadNamePOI() && CityStr != null)
+ {
+ // If it is road POI add city name and street name into address info
+ p.setStreet(p.getName());
+ p.setName(p.getName() + "/" + CityStr);
+ }
+
+ POIRecord r = lbl.createPOI(p.getName());
+
+ if(CityStr != null)
+ {
+ Country thisCountry;
+ Region thisRegion;
+ City city;
+
+ if(CountryStr != null)
+ thisCountry = lbl.createCountry(CountryStr, locator.getCountryCode(CountryStr));
+ else
+ thisCountry = country;
+
+ if(RegionStr != null)
+ thisRegion = lbl.createRegion(thisCountry,RegionStr, null);
+ else
+ thisRegion = region;
+
+ if(thisRegion != null)
+ city = lbl.createCity(thisRegion, CityStr, false);
+ else
+ city = lbl.createCity(thisCountry, CityStr, false);
+
+ r.setCity(city);
+
+ }
+
+ if (ZipStr != null)
+ {
+ Zip zip = lbl.createZip(ZipStr);
+ r.setZipIndex(zip.getIndex());
+ }
+
+ if(p.getStreet() != null)
+ {
+ Label streetName = lbl.newLabel(p.getStreet());
+ r.setStreetName(streetName);
+ }
+ else if (guessed == true && locationAutofillLevel > 0)
+ {
+ Label streetName = lbl.newLabel("FIX MY ADDRESS");
+ r.setStreetName(streetName);
+ }
+
+ if(p.getHouseNumber() != null)
+ {
+ if(r.setSimpleStreetNumber(p.getHouseNumber()) == false)
+ {
+ Label streetNumber = lbl.newLabel(p.getHouseNumber());
+ r.setComplexStreetNumber(streetNumber);
+ }
+ }
+
+ if(p.getPhone() != null)
+ {
+ if(r.setSimplePhoneNumber(p.getPhone()) == false)
+ {
+ Label phoneNumber = lbl.newLabel(p.getPhone());
+ r.setComplexPhoneNumber(phoneNumber);
+ }
+ }
+
poimap.put(p, r);
}
}
+
+ //System.out.println(poiAddrCountr + " POIs have address info");
+
lbl.allPOIsDone();
+
}
/**
@@ -369,6 +558,9 @@
// The bounds of the map.
map.setBounds(src.getBounds());
+ if(poiDisplayFlags != 0) // POI requested alterate address notation
+ map.setPoiDisplayFlags(poiDisplayFlags);
+
// You can add anything here.
// But there has to be something, otherwise the map does not show up.
//
@@ -461,7 +653,8 @@
// retrieve the City created earlier for
// this point and store the point info
// in it
- City c = (City)sortedCities.get(name + "@" + point);
+ City c = (City)cityMap.get(point);
+
if(pointIndex > 255) {
System.err.println("Can't set city point index for " + name + " (too many indexed points in division)\n");
} else {
Index: src/uk/me/parabola/mkgmap/build/LocatorConfig.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/LocatorConfig.java (.../upstream/mkgmap) (revision 0)
+++ src/uk/me/parabola/mkgmap/build/LocatorConfig.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2009 Bernhard Heibler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * The Locator tries to fill missing country, region, postal coude information
+ *
+ * To do so we analyse the is_in information and if this doesn't helps us we
+ * try to get info from the next known city
+ *
+ * Author: Bernhard Heibler
+ * Create date: 02-Jan-2009
+ */
+package uk.me.parabola.mkgmap.build;
+
+import org.w3c.dom.*;
+import javax.xml.parsers.*;
+import java.io.*;
+
+import java.util.HashMap;
+
+public class LocatorConfig {
+
+ private final java.util.Map<String,String> variantMap = new HashMap<String,String>();
+ private final java.util.Map<String,String> abrMap = new HashMap<String,String>();
+ private final java.util.Map<String,Boolean> geoDbMap = new HashMap<String,Boolean>();
+ private final java.util.Map<String,Integer> regOffsetMap = new HashMap<String,Integer>();
+ private final java.util.Map<String,Integer> poiDispFlagMap = new HashMap<String,Integer>();
+ private final java.util.Map<String,Boolean> continentMap = new HashMap<String,Boolean>();
+
+
+ public LocatorConfig()
+ {
+ loadConfig("/LocatorConfig.xml");
+ }
+
+ private void loadConfig(String fileName)
+ {
+ try
+ {
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+
+ InputStream inStream;
+
+ try
+ {
+ inStream = new FileInputStream("resources/" + fileName);
+ }
+ catch (Exception ex)
+ {
+ inStream = null;
+ }
+
+ if(inStream == null) // If not loaded from disk use from jar file
+ inStream = this.getClass().getResourceAsStream(fileName);
+
+ Document document = builder.parse(inStream);
+
+ Node rootNode = document.getDocumentElement();
+
+ if(rootNode.getNodeName().equals("locator"))
+ {
+ Node cNode = rootNode.getFirstChild();
+
+ while(cNode != null)
+ {
+ if(cNode.getNodeName().equals("continent"))
+ {
+ NamedNodeMap attr = cNode.getAttributes();
+ Node nameTag = null;
+
+ if(attr != null)
+ {
+ nameTag = attr.getNamedItem("name");
+ if(nameTag != null)
+ addContinent(nameTag.getNodeValue());
+ }
+
+ }
+
+ if(cNode.getNodeName().equals("country"))
+ {
+ NamedNodeMap attr = cNode.getAttributes();
+ Node nameTag = null;
+
+ if(attr != null)
+ {
+ nameTag = attr.getNamedItem("name");
+
+ Node abrTag = attr.getNamedItem("abr");
+
+ if(abrTag != null && nameTag != null)
+ addAbr(nameTag.getNodeValue(),abrTag.getNodeValue());
+
+ if(abrTag == null && nameTag != null)
+ addAbr(nameTag.getNodeValue(),"");
+
+ Node geoTag = attr.getNamedItem("geodb");
+
+ if(nameTag != null && geoTag != null)
+ {
+ if(geoTag.getNodeValue().equals("1"))
+ addOpenGeoDb(nameTag.getNodeValue());
+ }
+
+ Node regionOffsetTag = attr.getNamedItem("regionOffset");
+
+ if(regionOffsetTag != null && nameTag != null)
+ {
+ addRegionOffset(nameTag.getNodeValue(),Integer.parseInt(regionOffsetTag.getNodeValue()));
+ }
+
+ Node poiDispTag = attr.getNamedItem("poiDispFlag");
+
+ if(poiDispTag != null && nameTag != null)
+ {
+ addPoiDispTag(nameTag.getNodeValue(),Integer.decode(poiDispTag.getNodeValue()));
+ }
+ }
+
+ Node cEntryNode = cNode.getFirstChild();
+ while(cEntryNode != null)
+ {
+ if(cEntryNode.getNodeName().equals("variant"))
+ {
+ Node nodeText = cEntryNode.getFirstChild();
+
+ if(nodeText != null && nameTag != null)
+ addVariant(nameTag.getNodeValue(), nodeText.getNodeValue());
+
+ }
+ cEntryNode = cEntryNode.getNextSibling();
+ }
+ }
+
+ cNode = cNode.getNextSibling();
+ }
+ }
+ else
+ {
+ System.out.println(fileName + "contains invalid root tag " + rootNode.getNodeName());
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ //System.out.println("Something is wrong here");
+ }
+ return;
+ }
+
+ private void addVariant(String country, String variant)
+ {
+ String cStr = country.toUpperCase().trim();
+ String vStr = variant.toUpperCase().trim();
+
+ //System.out.println(vStr + " -> " + cStr);
+
+ variantMap.put(vStr,cStr);
+ }
+
+ private void addAbr(String country, String abr)
+ {
+ String cStr = country.toUpperCase().trim();
+ String aStr = abr.toUpperCase().trim();
+
+ //System.out.println(cStr + " -> " + aStr);
+
+ abrMap.put(cStr,aStr);
+ }
+
+ private void addRegionOffset(String country, Integer offset)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ //System.out.println(cStr + " -> " + offset);
+
+ regOffsetMap.put(cStr,offset);
+ }
+
+ private void addPoiDispTag(String country, Integer flag)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ //System.out.println(cStr + " -> " + flag);
+
+ poiDispFlagMap.put(cStr,flag);
+ }
+
+ private void addOpenGeoDb(String country)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ //System.out.println(cStr + " openGeoDb");
+
+ geoDbMap.put(cStr,true);
+
+ }
+
+ private void addContinent(String continent)
+ {
+ String cStr = continent.toUpperCase().trim();
+
+ //System.out.println(cStr + " continent");
+
+ continentMap.put(cStr,true);
+
+ }
+
+
+ public void setDefaultCountry(String country, String abbr)
+ {
+ addAbr(country, abbr);
+ }
+
+ public String fixCountryString(String country)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ String fixedString = variantMap.get(cStr);
+
+ if(fixedString != null)
+ return fixedString;
+ else
+ return(cStr);
+ }
+
+ public String isCountry(String country)
+ {
+ String cStr = fixCountryString(country);
+
+ if(getCountryCode(cStr) != null)
+ return cStr;
+ else
+ return null;
+
+ }
+
+ public String getCountryCode(String country)
+ {
+ String cStr = country.toUpperCase().trim();
+ return abrMap.get(cStr);
+ }
+
+ public int getRegionOffset(String country)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ Integer regOffset = regOffsetMap.get(cStr);
+
+ if(regOffset != null)
+ return regOffset;
+ else
+ return 1; // Default is 1 the next string after before country
+ }
+
+ public int getPoiDispFlag(String country)
+ {
+ String cStr = country.toUpperCase().trim();
+
+ Integer flag = poiDispFlagMap.get(cStr);
+
+ if(flag != null)
+ return flag;
+ else
+ return 0; // Default is 1 the next string after before country
+ }
+
+ public boolean isOpenGeoDBCountry(String country)
+ {
+ // Countries that have open geo db data in osm
+ // Right now this are only germany, austria and swizerland
+
+ String cStr = country.toUpperCase().trim();
+
+ if(geoDbMap.get(cStr) != null)
+ return true;
+
+ return false;
+ }
+
+ public boolean isContinent(String continent)
+ {
+ String s = continent.toUpperCase().trim();
+
+ if(continentMap.get(s) != null)
+ return(true);
+
+ return false;
+ }
+
+
+
+
+}
+
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -253,6 +253,11 @@
shape.setPoints(way.getPoints());
clipper.clipShape(shape, collector);
+
+ GType pointType = nodeRules.resolveType(way);
+
+ if(pointType != null)
+ shape.setPoiType(pointType.getType());
}
private void addPoint(Node node, GType gt) {
@@ -271,6 +276,50 @@
ms.setType(gt.getType());
ms.setMinResolution(gt.getMinResolution());
ms.setMaxResolution(gt.getMaxResolution());
+
+ // Now try to get some address info for POIs
+
+ String city = element.getTag("addr:city");
+ String zip = element.getTag("addr:postcode");
+ String street = element.getTag("addr:street");
+ String houseNumber = element.getTag("addr:housenumber");
+ String phone = element.getTag("phone");
+ String isIn = element.getTag("is_in");
+ String country = element.getTag("is_in:country");
+ String region = element.getTag("is_in:county");
+
+ if(country != null)
+ country = element.getTag("addr:country");
+
+ if(zip == null)
+ zip = element.getTag("openGeoDB:postal_codes");
+
+ if(city == null)
+ city = element.getTag("openGeoDB:sort_name");
+
+ if(city != null)
+ ms.setCity(city);
+
+ if(zip != null)
+ ms.setZip(zip);
+
+ if(street != null)
+ ms.setStreet(street);
+
+ if(houseNumber != null)
+ ms.setHouseNumber(houseNumber);
+
+ if(isIn != null)
+ ms.setIsIn(isIn);
+
+ if(phone != null)
+ ms.setPhone(phone);
+
+ if(country != null)
+ ms.setCountry(country);
+
+ if(region != null)
+ ms.setRegion(region);
}
void addRoad(Way way, GType gt) {
Index: src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -362,6 +362,23 @@
} catch (NumberFormatException e) {
endLevel = 0;
}
+ } else if (name.equals("ZipCode")) {
+ elem.setZip(recode(value));
+ } else if (name.equals("CityName")) {
+ elem.setCity(recode(value));
+ } else if (name.equals("StreetDesc")) {
+ elem.setStreet(recode(value));
+ } else if (name.equals("HouseNumber")) {
+ elem.setHouseNumber(recode(value));
+ } else if (name.equals("is_in")) {
+ elem.setIsIn(recode(value));
+ } else if (name.equals("Phone")) {
+ elem.setPhone(recode(value));
+ } else if (name.equals("CountryName")) {
+ elem.setCountry(recode(value));
+ } else if (name.equals("RegionName")) {
+ //System.out.println("RegionName " + value);
+ elem.setRegion(recode(value));
} else {
return false;
}
Index: src/uk/me/parabola/mkgmap/main/MapMaker.java
===================================================================
--- src/uk/me/parabola/mkgmap/main/MapMaker.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/main/MapMaker.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -36,6 +36,8 @@
import uk.me.parabola.mkgmap.general.LoadableMapDataSource;
import uk.me.parabola.mkgmap.general.MapLine;
import uk.me.parabola.mkgmap.general.MapPoint;
+import uk.me.parabola.mkgmap.general.MapShape;
+import uk.me.parabola.mkgmap.general.MapPointFastFindMap;
import uk.me.parabola.mkgmap.reader.plugin.MapReader;
/**
@@ -49,6 +51,7 @@
public String makeMap(CommandArgs args, String filename) {
try {
LoadableMapDataSource src = loadFromFile(args, filename);
+ makeAreaPOIs(args, src);
makeRoadNamePOIS(args, src);
return makeMap(args, src);
} catch (FormatException e) {
@@ -135,6 +138,44 @@
return src;
}
+ private void makeAreaPOIs(CommandArgs args, LoadableMapDataSource src) {
+ String s = args.getProperties().getProperty("add-pois-to-areas");
+ if (s != null) {
+
+ MapPointFastFindMap poiMap = new MapPointFastFindMap();
+
+ for (MapPoint point : src.getPoints())
+ {
+ if(point.isRoadNamePOI() == false) // Don't put road pois in this list
+ poiMap.put(null, point);
+ }
+
+ for (MapShape shape : src.getShapes()) {
+ String shapeName = shape.getName();
+
+ int pointType = shape.getPoiType();
+
+ // only make a point if the shape has a name and we know what type of point to make
+ if (pointType == 0)
+ continue;
+
+ // check if there is not already a poi in that shape
+
+ if(poiMap.findPointInShape(shape, pointType) == null)
+ {
+ MapPoint newPoint = new MapPoint();
+ newPoint.setName(shapeName);
+ newPoint.setType(pointType);
+ newPoint.setLocation(shape.getLocation()); // TODO use centriod
+ src.getPoints().add(newPoint);
+ log.info("created POI ", shapeName, "from shape");
+ }
+ }
+ }
+
+ }
+
+
void makeRoadNamePOIS(CommandArgs args, LoadableMapDataSource src) {
String rnp = args.getProperties().getProperty("road-name-pois", null);
// are road name POIS wanted?
@@ -277,26 +318,10 @@
}
String name = road.getName();
- MapPoint nearestCity = null;
- if(cities != null) {
- double shortestDistance = 10000000;
- for(MapPoint mp : cities) {
- double distance = coord.distance(mp.getLocation());
- if(distance < shortestDistance) {
- shortestDistance = distance;
- nearestCity = mp;
- }
- }
- }
-
MapPoint rnp = new MapPoint();
- if(nearestCity != null && nearestCity.getName() != null) {
- //rnp.setNearestCityPoint(nearestCity);
- name += "/" + nearestCity.getName();
- }
-
rnp.setName(name);
+ rnp.setRoadNamePOI(true);
rnp.setType(type);
rnp.setLocation(coord);
return rnp;
Index: src/uk/me/parabola/mkgmap/general/MapPointMultiMap.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapPointMultiMap.java (.../upstream/mkgmap) (revision 0)
+++ src/uk/me/parabola/mkgmap/general/MapPointMultiMap.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 Bernhard Heibler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This is multimap to store city information for the Address Locator
+ *
+ *
+ * Author: Bernhard Heibler
+ * Create date: 02-Jan-2009
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.Collection;
+
+public class MapPointMultiMap{
+
+ private final java.util.Map<String,Vector<MapPoint>> map = new HashMap<String,Vector<MapPoint>>();
+
+ public MapPoint put(String name, MapPoint p)
+ {
+ Vector<MapPoint> list;
+
+ list = map.get(name);
+
+ if(list == null){
+
+ list = new Vector<MapPoint>();
+ list.add(p);
+ map.put(name, list);
+ }
+ else
+ list.add(p);
+
+ return p;
+ }
+
+ public MapPoint get(String name)
+ {
+ Vector<MapPoint> list;
+
+ list = map.get(name);
+
+ if(list != null)
+ return list.elementAt(0);
+ else
+ return null;
+ }
+
+ public Collection<MapPoint> getList(String name)
+ {
+ return map.get(name);
+ }
+}
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java (.../upstream/mkgmap) (revision 0)
+++ src/uk/me/parabola/mkgmap/general/MapPointFastFindMap.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2009 Bernhard Heibler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This is multimap to store city information for the Address Locator
+ * tt provides also a fast tile based nearest point search function
+ *
+ *
+ * Author: Bernhard Heibler
+ * Create date: 02-Jan-2009
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Vector;
+import java.util.List;
+import uk.me.parabola.imgfmt.app.Coord;
+
+public class MapPointFastFindMap{
+
+ private final java.util.Map<String,Vector<MapPoint>> map = new HashMap<String,Vector<MapPoint>>();
+ private final java.util.Map<Long,Vector<MapPoint>> posMap = new HashMap<Long,Vector<MapPoint>>();
+ private final java.util.Vector<MapPoint> points = new Vector<MapPoint>();
+
+ private static final long POS_HASH_DIV = 8000; // the smaller -> more tiles
+ private static final long POS_HASH_MUL = 10000; // multiplicator for latitude to create hash
+
+ public MapPoint put(String name, MapPoint p)
+ {
+ Vector<MapPoint> list;
+
+ if(name != null)
+ {
+ list = map.get(name);
+
+ if(list == null){
+
+ list = new Vector<MapPoint>();
+ list.add(p);
+ map.put(name, list);
+ }
+ else
+ list.add(p);
+
+ points.add(p);
+ }
+
+ long posHash = getPosHashVal(p.getLocation().getLatitude(), p.getLocation().getLongitude());
+
+ list = posMap.get(posHash);
+
+ if(list == null)
+ {
+ list = new Vector<MapPoint>();
+ list.add(p);
+ posMap.put(posHash, list);
+ }
+ else
+ list.add(p);
+
+ return p;
+ }
+
+ public MapPoint get(String name)
+ {
+ Vector<MapPoint> list;
+
+ list = map.get(name);
+
+ if(list != null)
+ return list.elementAt(0);
+ else
+ return null;
+ }
+
+ public Collection<MapPoint> getList(String name)
+ {
+ return map.get(name);
+ }
+
+ public long size()
+ {
+ return points.size();
+ }
+
+ public Collection<MapPoint> values()
+ {
+ return points;
+ }
+
+ public MapPoint get(int index)
+ {
+ return points.get(index);
+ }
+
+ public MapPoint set(int index, MapPoint p)
+ {
+ return points.set(index, p);
+ }
+
+ public boolean remove(MapPoint p)
+ {
+ return points.remove(p);
+ }
+
+
+ public MapPoint findNextPoint(MapPoint p)
+ {
+ /* tile based search
+
+ to prevent expensive linear search over all points we put the points
+ into tiles. We just search the tiles the point is in linear and the
+ sourounding tiles. If we don't find a point we have to search further
+ arround the central tile
+
+ */
+
+ Vector<MapPoint> list;
+ double minDist = Double.MAX_VALUE;
+ MapPoint nextPoint = null;
+
+ if(posMap.size() < 1) // No point in list
+ return nextPoint;
+
+ long centLatitIdx = p.getLocation().getLatitude() / POS_HASH_DIV ;
+ long centLongiIdx = p.getLocation().getLongitude() / POS_HASH_DIV ;
+ long delta = 1;
+
+ long latitIdx;
+ long longiIdx;
+ long posHash;
+
+ do
+ {
+ // in the first step we only check our tile and the tiles sourinding us
+
+ for(latitIdx = centLatitIdx - delta; latitIdx <= centLatitIdx + delta; latitIdx++)
+ for(longiIdx = centLongiIdx - delta; longiIdx <= centLongiIdx + delta; longiIdx++)
+ {
+ if(delta < 2
+ || latitIdx == centLatitIdx - delta
+ || latitIdx == centLatitIdx + delta
+ || longiIdx == centLongiIdx - delta
+ || longiIdx == centLongiIdx + delta)
+ {
+
+ posHash = latitIdx * POS_HASH_MUL + longiIdx;
+
+ list = posMap.get(posHash);
+
+ if(list != null)
+ {
+
+ for (MapPoint actPoint: list)
+ {
+ double distance = actPoint.getLocation().distance(p.getLocation());
+
+ if(distance < minDist)
+ {
+ nextPoint = actPoint;
+ minDist = distance;
+
+ }
+ }
+ }
+ }
+ }
+ delta ++; // We have to look in tiles farer away
+ }
+ while(nextPoint == null);
+
+ return nextPoint;
+ }
+
+ public MapPoint findPointInShape(MapShape shape, int pointType)
+ {
+ Vector<MapPoint> list;
+ List<Coord> points = shape.getPoints();
+ MapPoint nextPoint = null;
+ long lastHashValue = -1;
+ long posHash;
+
+ if(posMap.size() < 1) // No point in list
+ return nextPoint;
+
+ for(int i=0; i < points.size(); i++)
+ {
+ posHash = getPosHashVal(points.get(i).getLatitude(),points.get(i).getLongitude());
+
+ if(posHash == lastHashValue) // Have we already checked this tile ?
+ continue;
+
+ lastHashValue = posHash;
+
+ list = posMap.get(posHash);
+
+ if(list != null)
+ {
+ for (MapPoint actPoint: list)
+ {
+ if(pointType == 0 || actPoint.getType() == pointType)
+ {
+ if(shape.contains( actPoint.getLocation()))
+ return actPoint;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private long getPosHashVal(long lat, long lon)
+ {
+ long latitIdx = lat / POS_HASH_DIV ;
+ long longiIdx = lon / POS_HASH_DIV ;
+
+ //System.out.println("LatIdx " + latitIdx + " LonIdx " + longiIdx);
+
+ return latitIdx * POS_HASH_MUL + longiIdx;
+ }
+
+ public void printStat()
+ {
+ System.out.println("Locator PosHashmap contains " + posMap.size() + " tiles");
+ }
+}
\ No newline at end of file
Index: src/uk/me/parabola/mkgmap/general/MapElement.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapElement.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/general/MapElement.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -15,6 +15,9 @@
*/
package uk.me.parabola.mkgmap.general;
+import java.util.Map;
+import java.util.HashMap;
+
import uk.me.parabola.imgfmt.app.Coord;
/**
@@ -29,6 +32,13 @@
private int minResolution = 24;
private int maxResolution = 24;
+
+ private String zipCode;
+ private String city;
+ private String region;
+ private String country;
+
+ private final Map<String, String> attributes = new HashMap<String, String>();
protected MapElement() {
}
@@ -53,9 +63,84 @@
}
public void setName(String name) {
- this.name = name;
+ if(name != null)
+ this.name = name.toUpperCase();
}
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ if(city != null)
+ this.city = city.toUpperCase();
+ }
+
+ public String getZip() {
+ return zipCode;
+ }
+
+ public void setZip(String zip) {
+ this.zipCode = zip;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ if(country != null)
+ this.country = country.toUpperCase();
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ if(region != null)
+ this.region = region.toUpperCase();
+ }
+
+ public String getStreet() {
+ return attributes.get("street");
+ }
+
+ public void setStreet(String street) {
+ attributes.put("street", street);
+ }
+
+ public String getPhone() {
+ return attributes.get("phone");
+ }
+
+ public void setPhone(String phone) {
+
+ if(phone.startsWith("00"))
+ {
+ phone = phone.replaceFirst("00","+");
+ }
+ attributes.put("phone", phone);
+ }
+
+ public String getHouseNumber() {
+ return attributes.get("houseNumber");
+ }
+
+ public void setHouseNumber(String houseNumber) {
+ attributes.put("houseNumber", houseNumber);
+ }
+
+ public String getIsIn() {
+ return attributes.get("isIn");
+ }
+
+ public void setIsIn(String isIn) {
+ if(isIn != null)
+ attributes.put("isIn", isIn.toUpperCase());
+ }
+
+
/**
* This is the type code that goes in the .img file so that the GPS device
* knows what to display.
Index: src/uk/me/parabola/mkgmap/general/MapPoint.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapPoint.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/general/MapPoint.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -27,6 +27,7 @@
public class MapPoint extends MapElement {
private Coord location;
private MapPoint nearestCityPoint;
+ private boolean isRoadNamePoi = false;
public MapPoint() {
}
@@ -63,11 +64,11 @@
return type >= 0x0100 && type <= 0x1100;
}
- public void setNearestCityPoint(MapPoint nearestCityPoint) {
- this.nearestCityPoint = nearestCityPoint;
+ public void setRoadNamePOI(boolean isRoadNamePoi) {
+ this.isRoadNamePoi = isRoadNamePoi;
}
- public MapPoint getNearestCityPoint() {
- return nearestCityPoint;
+ public boolean isRoadNamePOI() {
+ return this.isRoadNamePoi;
}
}
Index: src/uk/me/parabola/mkgmap/general/MapShape.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapShape.java (.../upstream/mkgmap) (revision 280)
+++ src/uk/me/parabola/mkgmap/general/MapShape.java (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -15,6 +15,11 @@
*/
package uk.me.parabola.mkgmap.general;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
/**
* A shape or polygon is just the same as a line really as far as I can tell.
* There are some things that you cannot do with them semantically.
@@ -23,6 +28,8 @@
*/
public class MapShape extends MapLine {// So top code can link objects from here
+ private int poiType = 0;
+
public MapShape() {
}
@@ -38,5 +45,158 @@
throw new IllegalArgumentException(
"can't set a direction on a polygon");
}
+
+ public void setPoiType(int type)
+ {
+ this.poiType = type;
+ }
+
+ public int getPoiType()
+ {
+ return this.poiType;
+ }
+
+ /**
+ * Checks if a point is contained within this shape. Points on the
+ * edge of the shape are considered inside.
+ *
+ * @param co point to check
+ * @return true if point is in shape, false otherwise
+ */
+ public boolean contains(Coord co) {
+ return contains(this.getPoints(), co, true);
+ }
+
+ /*
+ * Checks if a point is contained within a shape.
+ *
+ * @param points points that define the shape
+ * @param target point to check
+ * @param onLineIsInside if a point on the line should be considered inside the shape
+ * @return true if point is contained within the shape, false if the target point is outside the shape
+ */
+ private static boolean contains(List<Coord> points, Coord target, boolean onLineIsInside) {
+ // implementation of the Ray casting algorithm as described here:
+ // http://en.wikipedia.org/wiki/Point_in_polygon
+ // with inspiration from:
+ // http://www.visibone.com/inpoly/
+ boolean inside = false;
+ if (points.size() < 3)
+ return false;
+ // complete the shape if we're dealing with a MapShape that is not closed
+ Coord start = points.get(0);
+ Coord end = points.get(points.size() - 1);
+ if (!start.equals(end)) {
+ // make copy of the shape's geometry
+ List<Coord> pointsTemp = new ArrayList<Coord>(points.size() + 1);
+ for (Coord coord : points) {
+ pointsTemp.add(new Coord(coord.getLatitude(), coord.getLongitude()));
+ }
+ pointsTemp.add(new Coord(start.getLatitude(), start.getLongitude()));
+ points = pointsTemp;
+ }
+
+ int xtarget = target.getLatitude();
+ int ytarget = target.getLongitude();
+
+ for (int i = 0; i < points.size() - 1; i++) {
+
+ // apply transformation points to change target point to (0,0)
+ int x0 = points.get(i).getLatitude() - xtarget;
+ int y0 = points.get(i).getLongitude() - ytarget;
+ int x1 = points.get(i+1).getLatitude() - xtarget;
+ int y1 = points.get(i+1).getLongitude() - ytarget;
+
+ // ensure that x0 is smaller than x1 so that we can just check to see if the line intersects the y axis easily
+ if (x0 > x1) {
+ int xtemp = x0;
+ int ytemp = y0;
+ x0 = x1;
+ y0 = y1;
+ x1 = xtemp;
+ y1 = ytemp;
+ }
+
+ // use (0,0) as target because points already transformed
+ if (isPointOnLine(x0, y0, x1, y1, 0, 0))
+ return onLineIsInside;
+
+ // explanation of if statement
+ //
+ // (x0 < 0 && x1 >= 0):
+ // are the x values between the y axis? only include points from the right
+ // with this check so that corners aren't counted twice
+ //
+ // (y0 * (x1 - x0) > (y1 - y0) * x0):
+ // from y = mx + b:
+ // => b = y0 ((y1 - y0) / (x1 - x0)) * x0
+ // for intersection, b > 0
+ // from y = mx + b, b = y - mx
+ // => y - mx > 0
+ // => y0 - ((y1 - y0) / (x1 - x0)) * x0 > 0
+ // => y0 > ((y1 - y0) / (x1 - x0)) * x0
+ // from 'if (x0 > x1)', x1 >= x0
+ // => x1 - x0 >=0
+ // => y0 * (x1 - x0) > (y1 - y0) * x0
+ if ((x0 < 0 && x1 >= 0) && (y0 * (x1 - x0)) > ((y1 - y0) * x0))
+ inside = !inside;
+ }
+
+ return inside;
+ }
+
+ /*
+ * Checks if a point is on a line.
+ *
+ * @param x0 x value of first point in line
+ * @param y0 y value of first point in line
+ * @param x1 x value of second point in line
+ * @param y1 y value of second point in line
+ * @param xt x value of target point
+ * @param yt y value of target point
+ * @return return true if point is on the line, false if the point isn't on the line
+ */
+ private static boolean isPointOnLine(int x0, int y0, int x1, int y1, int xt, int yt) {
+ // this implementation avoids using doubles
+ // apply transformation points to change target point to (0,0)
+ x0 = x0 - xt;
+ y0 = y0 - yt;
+ x1 = x1 - xt;
+ y1 = y1 - yt;
+
+ // ensure that x0 is smaller than x1 so that we can just check to see if the line intersects the y axis easily
+ if (x0 > x1) {
+ int xtemp = x0;
+ int ytemp = y0;
+ x0 = x1;
+ y0 = y1;
+ x1 = xtemp;
+ y1 = ytemp;
+ }
+
+ // if a point is on the edge of shape (on a line), it's considered outside the shape
+ // special case if line is on y-axis
+ if (x0 == 0 && x1 == 0) {
+ // ensure that y0 is smaller than y1 so that we can just check if the line intersects the x axis
+ if (y0 > y1) {
+ int xtemp = x0;
+ int ytemp = y0;
+ x0 = x1;
+ y0 = y1;
+ x1 = xtemp;
+ y1 = ytemp;
+ }
+ // test to see if we have a vertical line touches x-axis
+ if (y0 <= 0 && y1 >= 0)
+ return true;
+ // checks if point is on the line, see comments in contain() for derivation of similar
+ // formula - left as an exercise to the reader ;)
+ } else if ((x0 <= 0 && x1 >= 0) && (y0 * (x1 - x0)) == ((y1 - y0) * x0)) {
+ return true;
+ }
+ return false;
+ }
+
+
}
Index: build.xml
===================================================================
--- build.xml (.../upstream/mkgmap) (revision 280)
+++ build.xml (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -78,8 +78,9 @@
<target name="build" depends="compile" >
<copy todir="${build.classes}">
<fileset dir="${resources}">
- <include name="*.csv"/>
+ <include name="*.csv"/>
<include name="*.properties"/>
+ <include name="*.xml"/>
<include name="**/*.trans"/>
<include name="styles/**"/>
<include name="help/**"/>
@@ -151,6 +152,7 @@
manifest="${resources}/MANIFEST.MF">
<include name="**/*.class"/>
<include name="*.csv"/>
+ <include name="*.xml"/>
<include name="*.properties"/>
<include name="**/*.trans"/>
<include name="styles/**"/>
Index: resources/styles/default/polygons
===================================================================
--- resources/styles/default/polygons (.../upstream/mkgmap) (revision 280)
+++ resources/styles/default/polygons (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -6,6 +6,8 @@
amenity=supermarket [0x08 resolution 21]
amenity=university [0x0a resolution 18]
+building=yes [0x13 resolution 18]
+
landuse=allotments [0x4e resolution 20]
landuse=cemetary [0x1a resolution 18]
landuse=cemetery [0x1a resolution 18]
Index: resources/LocatorConfig.xml
===================================================================
--- resources/LocatorConfig.xml (.../upstream/mkgmap) (revision 0)
+++ resources/LocatorConfig.xml (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<locator>
+ <country name="Deutschland" abr="DEU" geodb="1" regionOffset="3" poiDispFlag="0xc">
+ <variant>Bundesrepublik Deutschland</variant>
+ <variant>Germany</variant>
+ <variant>DE</variant>
+ </country>
+ <country name="Österreich" abr="AUT" geodb="1" poiDispFlag="0xc">
+ <variant>Austria</variant>
+ <variant>AT</variant>
+ </country>
+ <country name="Schweiz" abr="CHE" geodb="1" poiDispFlag="0xc">
+ <variant>Switzerland</variant>
+ <variant>CH</variant>
+ </country>
+ <country name="United Kingdom" abr="GBR">
+ <variant>UK</variant>
+ <variant>GB</variant>
+ </country>
+ <country name="Italia" abr="ITA" regionOffset="2">
+ <variant>Italy</variant>
+ <variant>IT</variant>
+ </country>
+ <country name="France" abr="FRA">
+ </country>
+ <continent name="Europe">
+ </continent>
+ <continent name="Africa">
+ </continent>
+ <continent name="Asia">
+ </continent>
+ <continent name="North America">
+ </continent>
+ <continent name="South America">
+ </continent>
+ <continent name="Oceania">
+ </continent>
+</locator>
Index: resources/help/en/options
===================================================================
--- resources/help/en/options (.../upstream/mkgmap) (revision 280)
+++ resources/help/en/options (.../work_poiaddr_area/mkgmap) (revision 280)
@@ -120,6 +120,11 @@
Generate a POI for each named road. By default, the POIs'
Garmin type code is 0x640a. If desired, a different type code
can be specified with this option.
+
+--add-pois-to-areas
+ Generate a POI for each area. The POIs are created after the style
+ is applied and only for polygon types that have a reasonable point
+ equivalent.
--tdbfile
Write a .tdb file.
@@ -134,6 +139,24 @@
same area, you can see through this map and see the lower map too.
Useful for contour line maps among other things.
+--no-poi-address
+ Disable address / phone information to POIs. Address info is read according to
+ the "Karlsruhe" tagging schema. Automatic filling of missing information could
+ be enabled using the "location-autofill" option.
+
+--location-autofill=''number''
+ Controls how country region info is gathered for cities / streets and pois
+
+ 0 (Default) The country region info is gathered by analysis of the cities is_in tags.
+ If no country region info is present the default passed default country region is used.
+
+ 1 Additional analysis of partial is_in info to get relations between hamlets and cities
+
+ 2 Brute force search for nearest city with info if all methods before failed. Warning
+ cities my end up in the wrong country/region.
+
+ 3 Enables debug output about suspicious relations that might cause wrong country region info
+
--version
Output program version.
6
9
The new splitter with the decimal split file (r25) shows some weird
behaviour with respect to the tile boundaries.
If run in the automatic split mode, the tile boundaries are shifted as can
be seen from the first attached screen shot. The inter tile boundaries are
fine however.
It gets even worse when a custom split file is used. Now there is an
overlap between adjacent tiles (see 2nd attachment).
-Wolfgang
2
4
Folks,
Robert heroically discovered why the inter-tile routing was not functioning at
all well and I believe it's now become quite useful so I have committed the
code to the trunk.
I appears to work fairly well in mapsource although I have found that for
long routes it gives up and draws a straight line even though it can route OK
if you add some intervening waypoints. So, more work required but it would
be great to get some feedback as to how it's currently performing
especially on real gps units.
Obviously, if you find this new code has broken the intra-tile routing, it
can be backed out.
All feedback welcome.
Cheers,
Mark
11
52
Hello,
I have noticed that when I view a map in Mapsource, and I zoom out to
a scale of 300 km or above, the entire map disappears. The problem is
worse on Mac OS X using Garmin RoadTrip, as RoadTrip does not display
tile boundaries.
I found that adjusting the "topBits" attribute of
OverviewMapDataSource.java changes this behaviour. If I set topBits =
11, the map can be displayed at scales of up to 1500 km. The comment
in the code above this attribute, "// TODO need to change this.",
seems to be a hint that this is not optimal. ;-) (Also, in my tests,
if I lowered topBits to a value below 11, the entire map would not be
displayed; with 11 the overview map is still not displayed at scale
values of 2000 or 3000 km. Obviously a more comprehensive solution
would be desirable.)
- Is this a known issue? Is this restriction deliberate?
I assume for this modification to be acceptable, the style files must
be adjusted so as to not display excessive detail at these zoom
levels. I have already done this in my custom style files: performance
is reasonable.
I am certainly not familiar with Java development in general, and
definitely not with this project in particular, so I imagine that my
modification will most likely not be suitable for general use.
However, I have included the diff output below for your consideration
anyway.
Your comments would be appreciated.
--- mkgmap-src/src/uk/me/parabola/mkgmap/reader/overview/
OverviewMapDataSource.java 2009-02-10 16:45:16.000000000 +0100
+++ mkgmap-trunk/src/uk/me/parabola/mkgmap/reader/overview/
OverviewMapDataSource.java 2009-02-21 18:04:15.000000000 +0100
@@ -45,7 +45,7 @@
// TODO need to change this.
private final int topLevel = 5;
- private final int topBits = 14;
+ private final int topBits = 11;
/**
* This is a fake source of data and is not read from a file, so
always
2
1