--- src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElement.java
+++ src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryElement.java	2012/01/26 10:47:28
@@ -45,7 +45,7 @@
 	}
 	
 	public String toString() {
-		return isOuter() ? "outer" : "inner";
+		return (isOuter() ? "outer" : "inner") + " " + points;
 	}
 
 }
--- src/uk/me/parabola/mkgmap/reader/osm/boundary/Boundary.java
+++ src/uk/me/parabola/mkgmap/reader/osm/boundary/Boundary.java	2012/01/26 10:47:28
@@ -92,7 +92,7 @@
 	
 	public List<BoundaryElement> getBoundaryElements() {
 		if (bList == null) {
-			bList = BoundaryUtil.splitToElements(area);
+			bList = BoundaryUtil.splitToElements(area, tags.get("mkgmap:boundaryid"));
 		}
 		return bList;
 	}
--- src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java
+++ src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java	2012/01/26 10:47:28
@@ -22,7 +22,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -293,6 +292,11 @@
 	}
 
 	private void write(OutputStream stream, Boundary boundary) {
+		List<BoundaryElement> boundaryElements = boundary.getBoundaryElements();
+		if (boundaryElements.size() == 0){
+			log.error("boundary area is not usable " + boundary.getTags().get("mkgmap:boundaryid"));
+			return;
+		}
 		ByteArrayOutputStream oneItemStream = new ByteArrayOutputStream();
 		DataOutputStream dos = new DataOutputStream(oneItemStream);
 		try {
@@ -313,8 +317,6 @@
 					+ boundary.getTags().toString();
 
 			// write the number of boundary elements to create the multipolygon
-			List<BoundaryElement> boundaryElements = boundary
-					.getBoundaryElements();
 			dos.writeInt(boundaryElements.size());
 
 			// now write each element
--- src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
+++ src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java	2012/01/26 10:47:28
@@ -35,6 +35,7 @@
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.reader.osm.Tags;
 import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.util.GpxCreator;
 import uk.me.parabola.util.Java2DConverter;
 
 public class BoundaryUtil {
@@ -46,12 +47,13 @@
 		}
 	}
 	
-	public static List<BoundaryElement> splitToElements(Area area) {
+	public static List<BoundaryElement> splitToElements(Area area, String id) {
 		if (area.isEmpty()) {
 			return Collections.emptyList();
 		}
 
-		List<List<Coord>> areaElements = Java2DConverter.areaToShapes(area);
+		//List<List<Coord>> areaElements = Java2DConverter.areaToShapes(area);
+		List<List<Coord>> areaElements = Java2DConverter.verifiedAreaToShapes(area, id);
 
 		if (areaElements.isEmpty()) {
 			// this may happen if a boundary overlaps a raster tile in a very small area
@@ -59,7 +61,7 @@
 			log.debug("Area has no dimension. Area:",area.getBounds());
 			return Collections.emptyList();
 		}
-		
+
 		List<BoundaryElement> bElements = new ArrayList<BoundaryElement>();
 		for (List<Coord> singleElement : areaElements) {
 			if (singleElement.size() <= 3) {
@@ -67,7 +69,6 @@
 				continue;
 			}
 			Way w = new Way(0, singleElement);
-
 			boolean outer = w.clockwise();
 			bElements.add(new BoundaryElement(outer, singleElement));
 		}
@@ -84,7 +85,13 @@
 		// we need the other way round
 		Collections.reverse(bElements);
 
-		assert bElements.get(0).isOuter() : log.threadTag()+" first element is not outer. "+ bElements;
+		if (bElements.get(0).isOuter() == false){
+			log.error(" first element is not outer. "+ bElements.get(0));
+			//String fname = ".\\bnd_gpx\\invalid_" + id ;
+			//GpxCreator.createGpx(fname, bElements.get(0).getPoints());
+		}
+		assert bElements.get(0).isOuter() : log.threadTag()+" first element is not outer. " + bElements.get(0);
+
 		return bElements;
 	}
 
@@ -138,7 +145,7 @@
 						for (int i = 0; i < noOfTags; i++) {
 							String name = inpStream.readUTF();
 							String value = inpStream.readUTF();
-							tags.put(name, value);
+							tags.put(name, value.intern());
 						}
 
 						int noBElems = inpStream.readInt();
--- src/uk/me/parabola/util/FloatCoord.java
+++ src/uk/me/parabola/util/FloatCoord.java	2012/01/26 10:47:28
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2006 Steve Ratcliffe
+ * 
+ *  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.
+ * 
+ * 
+ * Author: Steve Ratcliffe
+ * Create date: 11-Dec-2006
+ */
+package uk.me.parabola.util;
+
+/**
+ * A point coordinate in unshifted map-units stored in float fields. 
+ * This is a helper class for the Java2DConverter, see also class Coord 
+ *
+ * @author GerdP
+ */
+public class FloatCoord {
+	private final float latitude;
+	private final float longitude;
+
+	/**
+	 * Construct from co-ordinates that are already in map-units.
+	 * @param latitude The latitude in map units.
+	 * @param longitude The longitude in map units.
+	 */
+	public FloatCoord(float latitude, float longitude) {
+		this.latitude = latitude;
+		this.longitude = longitude;
+	}
+
+	public float getLatitude() {
+		return latitude;
+	}
+
+	public float getLongitude() {
+		return longitude;
+	}
+
+	public int hashCode() {
+		// Use a factor for latitude to span over the whole integer range:
+		// max lat: 4194304
+		// max lon: 8388608
+		// max hashCode: 2118123520 < 2147483647 (Integer.MAX_VALUE)
+		return 503 * (int) latitude + (int) longitude;
+	}
+
+	public boolean equals(Object obj) {
+		if (obj == null || !(obj instanceof FloatCoord))
+			return false;
+		FloatCoord other = (FloatCoord) obj;
+		return latitude == other.latitude && longitude == other.longitude;
+	}
+	public String toString() {
+		return (latitude) + "/" + (longitude);
+	}
+
+}
--- src/uk/me/parabola/util/Java2DConverter.java
+++ src/uk/me/parabola/util/Java2DConverter.java	2012/01/26 10:45:41
@@ -213,7 +213,7 @@
 	 * Convert the area back into a list of polygons each represented by a list
 	 * of coords. It is possible that the area contains multiple discontiguous
 	 * polygons, so you may append more than one shape to the output list.<br/>
-	 * <b>Attention:</b> The outline of the polygon is has clockwise order whereas
+	 * <b>Attention:</b> The outline of the polygon has clockwise order whereas
 	 * holes in the polygon have counterclockwise order. 
 	 * 
 	 * @param area The area to be converted.
@@ -280,5 +280,156 @@
 
 		return outputs;
 	}
+	/**
+         * Convert the area back into a list of polygons each represented by a list
+         * of coords. It is possible that the area contains multiple discontiguous
+        * polygons, so you may append more than one shape to the output list.<br/>
+        * <b>Attention:</b> The outline of the polygon is has clockwise order whereas
+        * holes in the polygon have counterclockwise order. 
+        * 
+        * @param area The area to be converted.
+        * @return a list of closed polygons
+        */
+       public static List<List<Coord>> verifiedAreaToShapes(java.awt.geom.Area area, String id) {
+               List<List<Coord>> outputs = new ArrayList<List<Coord>>(4);
+
+               float[] res = new float[6];
+               PathIterator pit = area.getPathIterator(null);
+              List<FloatCoord> testCoords = null;
+               List<Coord> coords = null;
+
+               int iPrevLat = Integer.MIN_VALUE;
+               int iPrevLong = Integer.MIN_VALUE;
+
+               float maxLat = Float.MIN_VALUE,maxLon= Float.MIN_VALUE,minLat=Float.MAX_VALUE,minLon=Float.MAX_VALUE;
+               while (!pit.isDone()) {
+                       int type = pit.currentSegment(res);
+
+                       float lat = res[1];
+                       float lon = res[0];
+                       int iLat = Math.round(lat);
+                       int iLon = Math.round(lon);
+                       
+                       if (lat > maxLat ) maxLat = lat; 
+                       if (lat < minLat ) minLat = lat;
+                       if (lon > maxLon ) maxLon = lon; 
+                       if (lon < minLon ) minLon = lon; 
+
+                       switch (type) {
+                       case PathIterator.SEG_LINETO:
+                               if (iPrevLat != iLat || iPrevLong != iLon) {
+                                       testCoords.add(new FloatCoord(lat,lon));
+                                       coords.add(new Coord(iLat,iLon));
+                               }
+                               iPrevLat = iLat;
+                               iPrevLong = iLon;
+                               break;
+                       case PathIterator.SEG_MOVETO: 
+                       case PathIterator.SEG_CLOSE:
+                               if ((type == PathIterator.SEG_MOVETO && testCoords != null) || type == PathIterator.SEG_CLOSE) {
+                                       if (testCoords.size() > 2) {
+                                               if (testCoords.get(0).equals(testCoords.get(testCoords.size() - 1)) == false){
+                                                       testCoords.add(testCoords.get(0));
+                                                       coords.add(coords.get(0));
+                                               }
+                                               if (testCoords.size() > 3){
+                                                       String reason = new String();
+                                                       boolean isUsable = true;
+                                                       float width = maxLat-minLat;
+                                                       
+                                                       float height = maxLon-minLon;
+                                                       if (width <= 0 || height <= 0){
+                                                               isUsable = false;
+                                                               reason = "too_small";
+                                                       }
+                                                      long intAreaSize = 0;
+                                                       double realAreaSize = 0;
+                                                       float ratio = 1;
+                                                       if (isUsable){
+                                                               // calculate area size, onece with int, once with float precision.
+                                                               // If the results have different signs we cannot trust the 
+                                                               // algorithm in Way.clockwise()
+                                                               Coord p1 = coords.get(0);
+                                                               for(int i = 1; i < coords.size(); ++i) {
+                                                                       Coord p2 = coords.get(i);
+                                                                       intAreaSize += ((long)p1.getLongitude() * p2.getLatitude() - 
+                                                                                       (long)p2.getLongitude() * p1.getLatitude());
+                                                                       p1 = p2;
+                                                               }
+                                                               
+                                                               FloatCoord pf1 = testCoords.get(0);
+                                                               for(int i = 1; i < testCoords.size(); ++i) {
+                                                                       FloatCoord pf2 = testCoords.get(i);
+                                                                       realAreaSize += ((double)pf1.getLongitude() * pf2.getLatitude() - 
+                                                                                       (double)pf2.getLongitude() * pf1.getLatitude());
+                                                                       pf1 = pf2;
+                                                               }
+                                                               if (isUsable && (realAreaSize >= 0 && intAreaSize < 0 || realAreaSize < 0 && intAreaSize >= 0)){
+                                                                       isUsable = false;
+                                                                       reason = "undecided_inner_outer";
+                                                               }
+                                                               /*
+                                                               if (width > height) 
+                                                                       ratio = width/height;
+                                                               else
+                                                                       ratio = height/width;
+                                                               if (ratio > 10 && Math.abs(realAreaSize) < 10){
+                                                                       isUsable = false;
+                                                                       reason = "too_narrow";
+                                                               }
+                                                                */
+                                                       }
+                                                       /*
+                                                       double bboxAreaSize = (double) width * height;
+                                                       if (isUsable &&   Math.abs(realAreaSize) < 100
+                                                                       && bboxAreaSize > (50/ratio) * Math.abs(realAreaSize)){
+                                                               isUsable = false;
+                                                               reason = "too_spiky";
+                                                       }
+                                                       */
+
+                                                       
+                                                       if (isUsable)
+                                                               outputs.add(coords);
+                                                       else{
+                                                               //String fname = ".\\bnd_gpx\\del_" + id +  "_" + reason + "_" + Math.abs(intAreaSize);
+                                                               //System.out.println("area shape removed [" + reason + "] " + fname);
+								System.out.println("area shape removed [" + reason + "] " + id);
+                                                               //GpxCreator.createGpx(fname, coords);
+                                                       }
+                                               }
+                                       }
+                               }
+                               if (type == PathIterator.SEG_MOVETO){
+                                       testCoords = new ArrayList<FloatCoord>();
+                                       testCoords.add(new FloatCoord(lat,lon));
+                                       coords = new ArrayList<Coord>();
+                                       coords.add(new Coord(iLat,iLon));
+                                       iPrevLat = iLat;
+                                       iPrevLong = iLon;
+                               }
+                               else {
+                                       testCoords = null;
+                                       coords = null;
+                                       iPrevLat = Integer.MIN_VALUE;
+                                      iPrevLong = Integer.MIN_VALUE;
+                               }
+                               minLat = lat;
+                               minLon = lon;
+                               maxLat = lat;
+                               maxLon = lon;
+                               break;
+                       default:
+                               log.error("Unsupported path iterator type " + type
+                                               + ". This is an mkgmap error.");
+                       }
+
+                       pit.next();
+               }
+
+               return outputs;
+       }
+
+ }
+
 
-}
