Index: src/uk/me/parabola/splitter/Area.java
===================================================================
--- src/uk/me/parabola/splitter/Area.java	(revision 597)
+++ src/uk/me/parabola/splitter/Area.java	(working copy)
@@ -229,4 +229,11 @@
 		this.isPseudoArea = isPseudoArea;
 	}
 
+	public Area increase(int delta) {
+		return new Area(Math.max(minLat - delta, Utils.MIN_LAT_MAP_UNITS),
+				Math.max(minLong - delta, Utils.MIN_LON_MAP_UNITS), 
+				Math.min(maxLat + delta, Utils.MAX_LAT_MAP_UNITS),
+				Math.min(maxLong + delta, Utils.MAX_LON_MAP_UNITS));
+	}
+
 }
Index: src/uk/me/parabola/splitter/AreaList.java
===================================================================
--- src/uk/me/parabola/splitter/AreaList.java	(revision 597)
+++ src/uk/me/parabola/splitter/AreaList.java	(working copy)
@@ -13,6 +13,7 @@
 package uk.me.parabola.splitter;
 
 import java.awt.Point;
+import java.awt.geom.Path2D;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
@@ -24,8 +25,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -271,28 +276,55 @@
 	public void setAreaNames() {
 		CityFinder cityFinder = null;
 		if (geoNamesFile != null){
+			// calculate covered area
+			Path2D path = new Path2D.Double();
+			for (Area area : getAreas()) {
+				path.append(area.getJavaArea(), false);
+			}
+			java.awt.geom.Area covered = new java.awt.geom.Area(path);
+			
 			CityLoader cityLoader = new CityLoader(true);
 			List<City> cities = cityLoader.load(geoNamesFile);
 			if (cities == null)
 				return;
-
+			cities.removeIf(c -> !covered.contains(c.getLon(), c.getLat()));
+			if (cities.isEmpty())
+				return;
 			cityFinder = new DefaultCityFinder(cities);
+		} else {
+			areas.forEach(a -> a.setName(description));
+			return;
 		}
-		for (Area area : getAreas()) {
-			area.setName(description);
-			if (cityFinder == null)
-				continue;
-
-			// Decide what to call the area
-			Set<City> found = cityFinder.findCities(area);
-			City bestMatch = null;
-			for (City city : found) {
-				if (bestMatch == null || city.getPopulation() > bestMatch.getPopulation()) {
-					bestMatch = city;
+		
+		Map<String, Integer> usedCities = new HashMap<>(areas.size());
+		List<Area> todo = new ArrayList<>(areas);
+		int shift = 0;
+		while (!todo.isEmpty() && shift <= 30) {
+			for (Area area : todo) {
+				// Decide what to call the area
+				Area searchArea = shift > 0 ? area.increase(1 << shift) : area;
+				City bestMatch = null;
+				for (City city : cityFinder.findCities(searchArea)) {
+					if (bestMatch == null || city.getPopulation() > bestMatch.getPopulation()) {
+						bestMatch = city;
+					}
 				}
-			}
-			if (bestMatch != null)
-				area.setName(bestMatch.getCountryCode() + '-' + bestMatch.getName());
+				if (bestMatch != null) {
+					// we found a name. make it unique.
+					String name = bestMatch.getCountryCode() + '-' + bestMatch.getName();
+					Integer count = usedCities.get(name);
+					String suffix = "";
+					if (count == null) {
+						usedCities.put(name, 1);
+					} else {
+						suffix = "#" + count;
+						usedCities.put(name, count + 1);
+					}
+					area.setName(name + suffix);
+				}
+			} 
+			shift++;
+			todo.removeIf(a -> a.getName() != null);
 		}
 	}
 
