Index: src/uk/me/parabola/imgfmt/app/Coord.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/Coord.java	(revision 2047)
+++ src/uk/me/parabola/imgfmt/app/Coord.java	(working copy)
@@ -100,7 +100,7 @@
 	}
 
 	public int hashCode() {
-		return latitude+longitude;
+		return 503*latitude + longitude;
 	}
 
 	public boolean equals(Object obj) {
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -554,13 +554,6 @@
 		shape.setPoints(way.getPoints());
 
 		clipper.clipShape(shape, collector);
-		
-		nodeRules.resolveType(way, new TypeResult() {
-			public void add(Element el, GType type) {
-				if(type != null)
-			shape.setPoiType(type.getType());
-			}
-		});
 	}
 
 	private void addPoint(Node node, GType gt) {
Index: src/uk/me/parabola/mkgmap/reader/osm/ElementSaver.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/ElementSaver.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/reader/osm/ElementSaver.java	(working copy)
@@ -14,6 +14,7 @@
 
 import java.util.AbstractMap;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
@@ -550,6 +551,10 @@
 		return wayMap;
 	}
 
+	public Map<Long, Relation> getRelations() {
+		return relationMap;
+	}
+	
 	/**
 	 * Get the bounding box.  This is either the one that was explicitly included in the input
 	 * file, or if none was given, the calculated one.
Index: src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java	(working copy)
@@ -56,6 +56,7 @@
 			new RoutingHook(),
 			new HighwayHooks(),
 			new LocationHook(),
+			new Areas2POIHook(),
 	};
 	protected OsmConverter converter;
 	private final Set<String> usedTags = new HashSet<String>();
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java	(working copy)
@@ -1,6 +1,7 @@
 package uk.me.parabola.mkgmap.reader.osm;
 
-import java.awt.*;
+import java.awt.Polygon;
+import java.awt.Rectangle;
 import java.awt.geom.Area;
 import java.awt.geom.Line2D;
 import java.util.ArrayList;
@@ -15,9 +16,9 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Queue;
 import java.util.Set;
+import java.util.Map.Entry;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.logging.Level;
 
@@ -40,6 +41,9 @@
 	public static final String STYLE_FILTER_LINE = "polyline";
 	public static final String STYLE_FILTER_POLYGON = "polygon";
 	
+	/** A tag that is set with value true on each polygon that is created by the mp processing */
+	public static final String MP_CREATED_TAG = "mkgmap:mp_created";
+	
 	private final Map<Long, Way> tileWayMap;
 	private final Map<Long, String> roleMap = new HashMap<Long, String>();
 	private Map<Long, Way> mpPolygons = new HashMap<Long, Way>();
@@ -49,12 +53,17 @@
 	protected ArrayList<JoinedWay> polygons;
 	protected Set<JoinedWay> intersectingPolygons;
 	
+	protected double largestSize;
+	protected JoinedWay largestOuterPolygon;
+	
 	protected Set<Way> outerWaysForLineTagging;
 	protected Map<String, String> outerTags;
 
 	private final uk.me.parabola.imgfmt.app.Area bbox;
 	protected Area bboxArea;
 	
+	private Coord cOfG = null;
+	
 	/** 
 	 * A point that has a lower or equal squared distance from 
 	 * a line is treated as if it lies one the line.<br/>
@@ -101,6 +110,19 @@
 	}
 	
 
+	/**
+	 * Retrieves the center point of this multipolygon. This is set in the 
+	 * {@link #processElements()} methods so it returns <code>null</code> 
+	 * before that. It can also return <code>null</code> in case the 
+	 * multipolygon could not be processed.<br/>
+	 * The returned point may lie outside the multipolygon area. It is just
+	 * the center point of it.
+	 * 
+	 * @return the center point of this multipolygon (maybe <code>null</code>)
+	 */
+	public Coord getCofG() {
+		return cOfG;
+	}
 	
 	/**
 	 * Retrieves the mp role of the given element.
@@ -893,6 +915,20 @@
 				outerWaysForLineTagging.addAll(currentPolygon.polygon.getOriginalWays());
 			}
 			
+			// calculate the size of the polygon
+			double outerAreaSize = currentPolygon.polygon.getSizeOfArea();
+			if (outerAreaSize > largestSize) {
+				// subtract the holes
+				for (PolygonStatus hole : holes) {
+					outerAreaSize -= hole.polygon.getSizeOfArea();
+				}
+				// is it still larger than the largest known polygon?
+				if (outerAreaSize > largestSize) {
+					largestOuterPolygon = currentPolygon.polygon;
+					largestSize = outerAreaSize;
+				}
+			}
+			
 			// check if the polygon is an outer polygon or 
 			// if there are some holes
 			boolean processPolygon = currentPolygon.outer
@@ -955,7 +991,8 @@
 					
 						// mark this polygons so that only polygon style rules are applied
 						mpWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_POLYGON);
-					
+						mpWay.addTag(MP_CREATED_TAG, "true");
+						
 						getMpPolygons().put(mpWay.getId(), mpWay);
 					}
 				}
@@ -996,6 +1033,14 @@
 			}
 		}
 
+		if (hasTags(this) == false) {
+			// add tags to the multipolygon that are taken from the outer ways
+			// they may be required by some hooks (e.g. Area2POIHook)
+			for (Entry<String, String> tags : outerTags.entrySet()) {
+				addTag(tags.getKey(), tags.getValue());
+			}
+		}
+		
 		// Go through all original outer ways, create a copy, tag them
 		// with the mp tags and mark them only to be used for polyline processing
 		// This enables the style file to decide if the polygon information or
@@ -1004,6 +1049,7 @@
 			Way lineTagWay =  new Way(FakeIdGenerator.makeFakeId(), orgOuterWay.getPoints());
 			lineTagWay.setName(orgOuterWay.getName());
 			lineTagWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_LINE);
+			lineTagWay.addTag(MP_CREATED_TAG, "true");
 			for (Entry<String,String> tag : outerTags.entrySet()) {
 				lineTagWay.addTag(tag.getKey(), tag.getValue());
 				
@@ -1025,6 +1071,22 @@
 	protected void postProcessing() {
 		// copy all polygons created by the multipolygon algorithm to the global way map
 		tileWayMap.putAll(mpPolygons);
+		
+		if (largestOuterPolygon != null) {
+			// check if the mp contains a node with role "label" 
+			for (Map.Entry<String, Element> r_e : getElements()) {
+				if (r_e.getValue() instanceof Node && "label".equals(r_e.getKey())) {
+					// yes => use the label node as reference point
+					cOfG = ((Node)r_e.getValue()).getLocation();
+					break;
+				} 
+			}
+			
+			if (cOfG == null) {
+				// use the center of the largest polygon as reference point
+				cOfG = largestOuterPolygon.getCofG();
+			}
+		}
 	}
 	
 	private void runIntersectionCheck(BitSet unfinishedPolys) {
@@ -1154,7 +1216,8 @@
 		taggedInnerPolygons = null;
 		outerPolygons = null;
 		taggedOuterPolygons = null;
-
+		
+		largestOuterPolygon = null;
 	}
 
 	private CutPoint calcNextCutPoint(AreaCutData areaData) {
@@ -1949,6 +2012,7 @@
 			Way lineTagWay =  new Way(FakeIdGenerator.makeFakeId(), orgOuterWay.getPoints());
 			lineTagWay.setName(orgOuterWay.getName());
 			lineTagWay.addTag(STYLE_FILTER_TAG, STYLE_FILTER_LINE);
+			lineTagWay.addTag(MP_CREATED_TAG, "true");
 			for (Entry<String,String> tag : tags.entrySet()) {
 				lineTagWay.addTag(tag.getKey(), tag.getValue());
 				
@@ -2234,6 +2298,20 @@
 		public List<Way> getOriginalWays() {
 			return originalWays;
 		}
+		
+		/**
+		 * Retrieves a measurement of the area covered by this polygon. The 
+		 * returned value has no unit. It is just a rough comparable value
+		 * because it uses a rectangular coordinate system without correction.
+		 * @return size of the covered areas (0 if the way is not closed)
+		 */
+		public double getSizeOfArea() {
+			if (isClosed()==false) {
+				return 0;
+			}
+
+			return SeaPolygonRelation.calcArea(getPoints());
+		}
 
 		public String toString() {
 			StringBuilder sb = new StringBuilder(200);
Index: src/uk/me/parabola/mkgmap/reader/osm/SeaPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/SeaPolygonRelation.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/reader/osm/SeaPolygonRelation.java	(working copy)
@@ -180,7 +180,7 @@
 		seaCoords.clear();
 	}
 
-	private double calcArea(List<Coord> polygon) {
+	public static double calcArea(List<Coord> polygon) {
 		Way w = new Way(0, polygon);
 		if (w.clockwise() == false) {
 			polygon = new ArrayList<Coord>(polygon);
Index: src/uk/me/parabola/mkgmap/reader/osm/Areas2POIHook.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/Areas2POIHook.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/reader/osm/Areas2POIHook.java	(revision 0)
@@ -0,0 +1,127 @@
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class Areas2POIHook extends OsmReadingHooksAdaptor {
+	private static final Logger log = Logger.getLogger(Areas2POIHook.class);
+
+	private ElementSaver saver;
+	
+	/** Name of the bool tag that is set to true if a POI is created from an area */
+	public static final String AREA2POI_TAG = "mkgmap:area2poi";
+	
+	public Areas2POIHook() {
+	}
+
+	public boolean init(ElementSaver saver, EnhancedProperties props) {
+		if (props.containsKey("add-pois-to-areas") == false) {
+			log.info("Disable Areas2POIHook because add-pois-to-areas option is not set.");
+			return false;
+		}
+		
+		this.saver = saver;
+		
+		return true;
+	}
+	
+	public void end() {
+		addPOIsToWays();
+		addPOIsToMPs();
+	}
+	
+	private void addPOIsToWays() {
+		Set<Coord> labelCoords = new HashSet<Coord>(); 
+		
+		// save all coords with building=entrance to a map
+		// so that ways use this coord as its labeling point
+		for (Node n : saver.getNodes().values()) {
+			if ("entrance".equals(n.getTag("building"))) {
+				labelCoords.add(n.getLocation());
+			}
+		}
+		
+		log.debug("Found", labelCoords.size(), "label coords");
+		
+		int ways2POI = 0;
+		
+		for (Way w : saver.getWays().values()) {
+			// check if it is an area
+			if (w.isClosed() == false) {
+				continue;
+			}
+
+			if (w.getTagCount() == 0) {
+				continue;
+			}
+			
+			// do not add POIs for polygons created by multipolygon processing
+			if (w.isBoolTag(MultiPolygonRelation.MP_CREATED_TAG)) {
+				log.debug("MP processed: Do not create POI for", w.toTagString());
+				continue;
+			}
+			
+			// get the coord where the poi is placed
+			Coord poiCoord = null;
+			// do we have some labeling coords?
+			if (labelCoords.size() > 0) {
+				// go through all points of the way and check if one of the coords
+				// is a labeling coord
+				for (Coord c : w.getPoints()) {
+					if (labelCoords.contains(c)) {
+						// this coord is a labeling coord
+						// use it for the current way
+						poiCoord = c;
+						break;
+					}
+				}
+			}
+			if (poiCoord == null) {
+				// did not find any label coord
+				// use the common center point of the area
+				poiCoord = w.getCofG();
+			}
+			
+			Node poi = new Node(FakeIdGenerator.makeFakeId(), poiCoord);
+			poi.copyTags(w);
+			poi.deleteTag(MultiPolygonRelation.STYLE_FILTER_TAG);
+			poi.addTag(AREA2POI_TAG, "true");
+			log.debug("Create POI",poi.toTagString(),"from",w.getId(),w.toTagString());
+			saver.addNode(poi);
+			ways2POI++;
+		}
+		
+		log.info(ways2POI, "POIs from single areas created");
+	}
+
+	private void addPOIsToMPs() {
+		int mps2POI = 0;
+		for (Relation r : saver.getRelations().values()) {
+			
+			// create POIs for multipolygon relations only
+			if (r instanceof MultiPolygonRelation == false) {
+				continue;
+			}
+			
+			Coord point = ((MultiPolygonRelation)r).getCofG();
+			if (point == null) {
+				continue;
+			}
+			
+			Node poi = new Node(FakeIdGenerator.makeFakeId(), point);
+			poi.copyTags(r);
+			// remove the type tag which makes only sense for relations
+			poi.deleteTag("type");
+			poi.addTag(AREA2POI_TAG, "true");
+			log.debug("Create POI",poi.toTagString(),"from mp",r.getId(),r.toTagString());
+			saver.addNode(poi);
+			mps2POI++;
+		}
+		log.info(mps2POI, "POIs from multipolygons created");
+	}
+
+}
Index: src/uk/me/parabola/mkgmap/general/MapShape.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapShape.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/general/MapShape.java	(working copy)
@@ -28,8 +28,6 @@
  */
 public class MapShape extends MapLine {// So top code can link objects from here
 
-	private int poiType;
-	
 	public MapShape() {
 	}
 
@@ -46,16 +44,6 @@
 				"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.
Index: src/uk/me/parabola/mkgmap/main/MapMaker.java
===================================================================
--- src/uk/me/parabola/mkgmap/main/MapMaker.java	(revision 2047)
+++ src/uk/me/parabola/mkgmap/main/MapMaker.java	(working copy)
@@ -39,7 +39,6 @@
 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.MapPointFastFindMap;
 import uk.me.parabola.mkgmap.general.MapRoad;
 import uk.me.parabola.mkgmap.general.MapShape;
 import uk.me.parabola.mkgmap.reader.plugin.MapReader;
@@ -58,8 +57,6 @@
 			LoadableMapDataSource src = loadFromFile(args, filename);
 			sort = args.getSort();
 
-			log.info("Making Area POIs for", filename);
-			makeAreaPOIs(args, src);			
 			log.info("Making Road Name POIs for", filename);
 			makeRoadNamePOIS(args, src);
 			return makeMap(args, src);
@@ -150,80 +147,6 @@
 		return src;
 	}
 
-	private void makeAreaPOIs(CommandArgs args, LoadableMapDataSource src) {
-		String s = args.get("add-pois-to-areas", null);
-		if (s != null) {
-			
-			MapPointFastFindMap poiMap = new MapPointFastFindMap();
-
-			for (MapPoint point : src.getPoints()) 
-			{
-				if(!point.isRoadNamePOI()) // 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;
-
-				
-				// We don't want to add unnamed cities !!
-				if(MapPoint.isCityType(pointType) && shapeName == null)
-					continue;
-				
-				// check if there is not already a poi in that shape 
-							
-				if(poiMap.findPointInShape(shape, pointType, shapeName) == null) {
-					MapPoint newPoint = new MapPoint();
-					
-					newPoint.setName(shapeName);
-					newPoint.setType(pointType);
-
-					copyAddressInformation(shape, newPoint);
-
-					newPoint.setLocation(shape.getLocation()); // TODO use centroid
-
-					src.getPoints().add(newPoint);
-
-					log.info("created POI ", shapeName, "from shape");
-				}
-			}
-		}
-
-	}
-
-	/**
-	 * Copy the address information from a shape to a POI.  Used when creating
-	 * POIs from areas.
-	 *
-	 * @param shape The shape which contains the address information.
-	 * @param newPoint The new point that will receive the address information.
-	 */
-	private void copyAddressInformation(MapShape shape, MapPoint newPoint) {
-		if (shape.getStreet() != null)
-			newPoint.setStreet(shape.getStreet());
-		if (shape.getCity() != null)
-			newPoint.setCity(shape.getCity());
-		if (shape.getZip() != null)
-			newPoint.setZip(shape.getZip());
-		if (shape.getCountry() != null)
-			newPoint.setCountry(shape.getCountry());
-		if (shape.getRegion() != null)
-			newPoint.setRegion(shape.getRegion());
-		if (shape.getPhone() != null)
-			newPoint.setPhone(shape.getPhone());
-		if (shape.getHouseNumber() != null)
-			newPoint.setHouseNumber(shape.getHouseNumber());
-		if (shape.getIsIn() != null)
-			newPoint.setIsIn(shape.getIsIn());
-	}
-
-
 	void makeRoadNamePOIS(CommandArgs args, LoadableMapDataSource src) {
 		String rnp = args.get("road-name-pois", null);
 		// are road name POIS wanted?
