logo separator

[mkgmap-dev] [PATCH] POI Address + Area POIs v7 R942

From Ben Konrath ben at bagu.org on Tue Mar 3 20:17:45 GMT 2009

Hi Berni,

I've tested out the POI branch and things are working for me, thanks! A 
small patch is attached to fix an outdated comment.

Cheers, Ben

Ben Konrath wrote:
>  Hi Berni,
> 
> Thanks for picking up my patch and for the improvements! :-) I noticed
> that it was just committed to the poi branch so I'll give it test and
> report back when I have some free time on Monday.
> 
> Cheers, Ben
> 
> On Sat, Feb 28, 2009 at 2:39 PM, Bernhard Heibler <bernhard at heibler.de> wrote:
>> 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.
>>
>>
>> _______________________________________________
>> mkgmap-dev mailing list
>> mkgmap-dev at lists.mkgmap.org.uk
>> http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev
>>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: mkgmap-poi-branch-comment-update.patch
Url: http://lists.mkgmap.org.uk/pipermail/mkgmap-dev/attachments/20090303/f81cd53e/attachment.pl 


More information about the mkgmap-dev mailing list