Index: src/uk/me/parabola/mkgmap/build/Locator.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/Locator.java	(revision 2239)
+++ src/uk/me/parabola/mkgmap/build/Locator.java	(working copy)
@@ -14,20 +14,25 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.general.MapPoint;
-import uk.me.parabola.mkgmap.general.MapPointFastFindMap;
+import uk.me.parabola.mkgmap.general.MapPointKdTree;
 import uk.me.parabola.mkgmap.reader.osm.Tags;
 import uk.me.parabola.util.EnhancedProperties;
 
 public class Locator {
 	private static final Logger log = Logger.getLogger(Locator.class);
 
-	private final MapPointFastFindMap cityMap  					= new MapPointFastFindMap();
+    /** hash map to collect equally named MapPoints*/ 
+    private final Map<String, ArrayList<MapPoint>> cityMap  = new HashMap<String, ArrayList<MapPoint>>();
+	
+	private final MapPointKdTree cityFinder = new MapPointKdTree();
 	private final List<MapPoint> placesMap  =  new ArrayList<MapPoint>();
 
 	/** Contains the tags defined by the option name-tag-list */
@@ -70,7 +75,7 @@
 			if (log.isDebugEnabled())
 				log.debug(p.getCity(),p.getRegion(),p.getCountry());
 			// Must use p.getName() here because p.getCity() contains the city name of the preprocessed cities
-			cityMap.put(p.getName(), p);
+			add(p.getName(), p);
 		}
 		else
 		{
@@ -244,7 +249,7 @@
 	
 	public MapPoint findNextPoint(MapPoint p)
 	{
-		return cityMap.findNextPoint(p);
+		return cityFinder.findNextPoint(p);
 	}
 	
 	public MapPoint findNearbyCityByName(MapPoint p) {
@@ -252,7 +257,7 @@
 		if (p.getCity() == null)
 			return null;
 
-		Collection<MapPoint> nextCityList = cityMap.getList(p.getCity());
+		Collection<MapPoint> nextCityList = cityMap.get(p.getCity());
 		if (nextCityList == null) {
 			return null;
 		}
@@ -296,8 +301,7 @@
 		for (String cityCandidate : cityList) {
 			cityCandidate = cityCandidate.trim();
 
-			Collection<MapPoint> candidateCityList = cityMap
-					.getList(cityCandidate);
+			Collection<MapPoint> candidateCityList = cityMap.get(cityCandidate);
 			if (candidateCityList != null) {
 				if (nextCityList == null) {
 					nextCityList = new ArrayList<MapPoint>();
@@ -340,6 +344,7 @@
 		
 		log.info("Locator City   Map contains", cityMap.size(), "entries");
 		log.info("Locator Places Map contains", placesMap.size(), "entries");
+		log.info("Locator Finder KdTree contains", cityFinder.size(), "entries");
 
 		int runCount = 0;
 		int maxRuns = 2;
@@ -369,7 +374,7 @@
 					} else if (locationAutofill.contains("nearest") && (runCount + 1) == maxRuns) {
 						// In the last resolve run just take info from the next
 						// known city
-						near = cityMap.findNextPoint(place);
+						near = cityFinder.findNextPoint(place);
 						if (near != null && near.getCountry() != null) {
 							if (place.getCity() == null)
 								place.setCity(place.getName());
@@ -395,11 +400,11 @@
 
 				if (place != null) {
 					if (place.getCity() != null) {
-						cityMap.put(place.getName(), place);
+						add(place.getName(), place);
 						placesMap.set(i, null);
 					} else if ((runCount + 1) == maxRuns) {
 						place.setCity(place.getName());
-						cityMap.put(place.getName(), place);
+						add(place.getName(), place);
 					}
 				}
 			}
@@ -413,5 +418,32 @@
 		} while (unresCount > 0 && runCount < maxRuns);
 
 	}
+	
+	/**
+	 * Add MapPoint to cityMap and cityFinder
+	 *  
+	 * @param name Name that is used to find the city
+	 * @param p the MapPoint
+	 */
+	private void add(String name, MapPoint p){
+		ArrayList<MapPoint> list;
+		
+		if(name != null)
+		{
+			list = cityMap.get(name);
+		
+			if(list == null){
+				list = new ArrayList<MapPoint>();
+				list.add(p);		
+				cityMap.put(name, list);
+			}
+			else
+				list.add(p);
+			
+			// add point to the kd-tree
+			cityFinder.add(p);
+		}
+		
+	}
 }
 
Index: src/uk/me/parabola/mkgmap/general/MapPointKdTree.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapPointKdTree.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/general/MapPointKdTree.java	(working copy)
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2012.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * 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.
+ */
+
+package uk.me.parabola.mkgmap.general;
+
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.mkgmap.general.MapPoint;
+
+
+/**
+ * A kd-tree (2D) implementation to solve the nearest neighbor problem.
+ * The tree is not explicitly balanced.
+ * 
+ * @author GerdP
+ *
+ */
+public class MapPointKdTree {
+	private static class KdNode {
+		MapPoint point;
+		KdNode left;
+		KdNode right;
+
+		KdNode(MapPoint p) {
+			point = p;
+		}
+	}
+	// the tree root
+    private KdNode root;
+    // number of saved MapPoint objects  
+    private int size;
+
+    // helpers 
+    private MapPoint nextPoint ;
+    private double minDist;
+
+    /**
+     *  create an empty tree
+     */
+	public MapPointKdTree() {
+		root = null;
+	}
+
+	public long size()
+	{
+		return size;
+	}
+
+	
+	/**
+	 * Start the add action with the root
+	 * @param toAdd
+	 */
+	public void add(MapPoint toAdd) {
+		size++;
+		root = add(toAdd, root, 0);
+	}
+
+	/**
+	 * Recursive routine to find the right place for inserting 
+	 * into the tree.  
+	 * @param toAdd
+	 * @param tree
+	 * @param level
+	 * @return
+	 */
+    private KdNode add( MapPoint toAdd, KdNode tree, int level ){
+        if( tree == null )
+            tree = new KdNode( toAdd );
+        else if (level % 2 == 1){
+        	if (toAdd.getLocation().getLongitude() < tree.point.getLocation().getLongitude())
+        		tree.left = add(toAdd, tree.left, 1-level);
+        	else 
+        		tree.right = add(toAdd, tree.right, 1-level);
+        }
+        else {
+        	if (toAdd.getLocation().getLatitude() < tree.point.getLocation().getLatitude())
+        		tree.left = add(toAdd, tree.left, 1-level);
+        	else 
+        		tree.right = add(toAdd, tree.right, 1-level);
+        	
+        }
+        return tree;
+    }
+    
+	public MapPoint findNextPoint(MapPoint p) {
+		minDist = Double.MAX_VALUE;
+		nextPoint = null;
+		return findNextPoint(p,root,0,0);
+	}
+
+	private MapPoint findNextPoint(MapPoint p, KdNode tree, int level, int depth) {
+		int dir = 0;
+		if (tree == null)
+			return nextPoint;
+		//System.out.println("t("+depth+") " + tree.point.getLocation() + " " + nextPoint == null? "null":nextPoint.getLocation().toString());
+		
+		
+		if (tree.left == null && tree.right == null){
+			double dist = tree.point.getLocation().distanceInDegreesSquared(p.getLocation());
+			if (dist < minDist){
+				nextPoint = tree.point;
+				minDist = dist;
+			}
+			return nextPoint;
+		}
+		else if (level % 2 == 1){
+			if (p.getLocation().getLongitude() < tree.point.getLocation().getLongitude()){
+				dir = -1;
+				nextPoint = findNextPoint(p, tree.left, 1-level, depth+1);
+			}
+			else {
+				dir = 1;
+				nextPoint = findNextPoint(p, tree.right, 1-level, depth+1);
+			}
+		}
+		else {
+			if (p.getLocation().getLatitude() < tree.point.getLocation().getLatitude()){
+				dir = -1;
+				nextPoint = findNextPoint(p, tree.left, 1-level, depth+1);
+			}
+			else {
+				dir = 1;
+				nextPoint = findNextPoint(p, tree.right, 1-level, depth+1);
+			}
+		}
+		
+		double dist = tree.point.getLocation().distanceInDegreesSquared(p.getLocation());
+		if (dist < minDist){
+			nextPoint = tree.point;
+			minDist = dist;
+		}
+		// do we have to search the other part of the tree?
+		Coord test;
+		if (level % 2 == 1)
+			test = new Coord(p.getLocation().getLatitude(),tree.point.getLocation().getLongitude());
+		else
+			test = new Coord(tree.point.getLocation().getLatitude(),p.getLocation().getLongitude());
+		if (test.distanceInDegreesSquared(p.getLocation()) < minDist){
+			if (dir > 0) 
+				nextPoint = findNextPoint(p, tree.left, 1-level, depth+1);
+			else
+				nextPoint = findNextPoint(p, tree.right, 1-level, depth+1);
+		}
+		return nextPoint;
+	}
+} 
Index: test/uk/me/parabola/mkgmap/general/MapPointKdTreeTest.java
===================================================================
--- test/uk/me/parabola/mkgmap/general/MapPointKdTreeTest.java	(revision 0)
+++ test/uk/me/parabola/mkgmap/general/MapPointKdTreeTest.java	(working copy)
@@ -0,0 +1,47 @@
+package uk.me.parabola.mkgmap.general;
+
+import static org.junit.Assert.assertFalse;
+import org.junit.Test;
+
+import uk.me.parabola.imgfmt.app.Coord;
+
+public class MapPointKdTreeTest {
+
+	@Test
+	public void TestFindNextPoint(){
+        MapPointKdTree t = new MapPointKdTree( );
+        
+        int [][]test = {{70,20},{50,40}, {90,60}, {20,30}, {40,70}, {80,10}, {-10,20}, {-30,-40} }  ;
+        Coord []testCoords = new Coord[test.length]; 
+        
+        for( int i = 0; i < test.length; i++ )
+        {
+        	MapPoint p = new MapPoint();
+        	testCoords[i] = new Coord(test[i][0],test[i][1]);
+        	p.setLocation(testCoords[i]);
+        	t.add(p);
+        }
+        // compare naive search result with kd--tree result
+        MapPoint toFind = new MapPoint();
+        for (int x = -100; x < 100; x++){
+        	for (int y = -100; y < 100; y++){
+        		Coord co = new Coord(x,y);
+        		double minDist = Double.MAX_VALUE;
+        		//Coord nearest = null;
+        		for (int i = 0; i<testCoords.length; i++){
+        			Double dist =  testCoords[i].distanceInDegreesSquared(co);
+        			if (dist < minDist){
+        				//nearest = testCoords[i];
+        				minDist = dist;
+        			}
+        		}
+        		toFind.setLocation(co);
+        		MapPoint next = t.findNextPoint(toFind);
+    			double dist =  next.getLocation().distanceInDegreesSquared(co);
+    			double delta = Math.abs(dist - minDist); 
+    			// if this test fails because 
+        		assertFalse("delta should be 0.0: " + delta, delta != 0.0);
+        	}
+        }
+	}
+}
