Index: src/uk/me/parabola/imgfmt/Utils.java
===================================================================
--- src/uk/me/parabola/imgfmt/Utils.java	(revision 3781)
+++ src/uk/me/parabola/imgfmt/Utils.java	(working copy)
@@ -26,8 +26,10 @@
 import java.nio.ByteOrder;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.List;
 import java.util.zip.GZIPInputStream;
 
+import uk.me.parabola.imgfmt.app.Area;
 import uk.me.parabola.imgfmt.app.Coord;
 /**
  * Some miscellaneous functions that are used within the .img code.
@@ -382,6 +384,33 @@
 		
 		return (long)(lat30 & 0xffffffffL) << 32 | (lon30 & 0xffffffffL);
 	}
-	
+
+	/**
+	 * Calculate smallest area that contains all given points.
+	 * @param points
+	 * @return the area 
+	 * TODO: maybe add code for additional high-precision evaluation.
+	 */
+	public static Area getArea(List<Coord> points) {
+		int minLat = Integer.MAX_VALUE;
+		int minLong = Integer.MAX_VALUE;
+		int maxLat = Integer.MIN_VALUE;
+		int maxLong = Integer.MIN_VALUE;
+		for (Coord co : points) {
+			int lat = co.getLatitude();
+			if (lat < minLat)
+				minLat = lat;
+			if (lat > maxLat)
+				maxLat = lat;
+
+			int lon = co.getLongitude();
+			if (lon < minLong)
+				minLong = lon;
+			if (lon > maxLong)
+				maxLong = lon;
+		}
+		
+		return new Area(minLat, minLong, maxLat, maxLong); 
+	}
 }
 
Index: src/uk/me/parabola/imgfmt/app/Coord.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/Coord.java	(revision 3781)
+++ src/uk/me/parabola/imgfmt/app/Coord.java	(working copy)
@@ -857,5 +857,34 @@
 		double newLon = lon + Math.atan2(Math.sin(bearing) * Math.sin(angularDistance) * Math.cos(lat), Math.cos(angularDistance) - Math.sin(lat) * Math.sin(newLat));
 		return new Coord(Math.toDegrees(newLat), Math.toDegrees(newLon));
 	}
+
 	
+	/**
+	 * Calculates the shortest distance to a line segment and
+	 * returns the Coord that lies on the line segment.
+	 * @param spoint1 segment point 1
+	 * @param spoint2 segment point 2
+	 * @return the distance in meter
+	 */
+	public Coord closestToSegment(Coord spoint1, Coord spoint2) {
+		double dx = spoint2.getHighPrecLon() - spoint1.getHighPrecLon();
+		double dy = spoint2.getHighPrecLat() - spoint1.getHighPrecLat();
+
+		if ((dx == 0) && (dy == 0)) {
+			return spoint1;
+		}
+
+		double frac = ((this.getHighPrecLon() - spoint1.getHighPrecLon()) * dx
+				+ (this.getHighPrecLat() - spoint1.getHighPrecLat()) * dy) / (dx * dx + dy * dy);
+
+		if (frac <= 0) {
+			return spoint1;
+		} else if (frac >= 1) {
+			return spoint2;
+		} else {
+			return Coord.makeHighPrecCoord((int)(spoint1.getHighPrecLat()+ dy * frac),
+					 (int)(spoint1.getHighPrecLon() + dx * frac));
+		}
+	}
+	
 }
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/MapBuilder.java	(revision 3781)
+++ src/uk/me/parabola/mkgmap/build/MapBuilder.java	(working copy)
@@ -1147,7 +1147,7 @@
 		}
 		filters.addFilter(new RemoveObsoletePointsFilter());
 		// MapArea splitting should ensure PolygonSplitterFilter never does anything, because
-		// RoundCoordsFilter might move points slightly sutch that the result self-intersects
+		// RoundCoordsFilter might move points slightly such that the result self-intersects
 		filters.addFilter(new PolygonSplitterFilter(false));
 		filters.addFilter(new RemoveEmpty());
 		filters.addFilter(new LinePreparerFilter(div));
Index: src/uk/me/parabola/mkgmap/filters/ShapeMergeFilter.java
===================================================================
--- src/uk/me/parabola/mkgmap/filters/ShapeMergeFilter.java	(revision 3781)
+++ src/uk/me/parabola/mkgmap/filters/ShapeMergeFilter.java	(working copy)
@@ -22,6 +22,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+
+import uk.me.parabola.imgfmt.Utils;
 import uk.me.parabola.imgfmt.app.Area;
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.log.Logger;
@@ -405,7 +407,7 @@
 		public ShapeHelper(List<Coord> merged) {
 			this.points = merged;
 			areaTestVal = calcAreaSizeTestVal(points);
-			bounds = prep();
+			bounds = Utils.getArea(points);
 		}
 
 		public ShapeHelper(ShapeHelper other) {
@@ -426,28 +428,6 @@
 		public Area getBounds(){
 			return bounds;
 		}
-		/**
-		 * Calculates a unitless number that gives a value for the size
-		 * of the area and the direction (clockwise/ccw)
-		 * 
-		 */
-		Area prep() {
-			int minLat = Integer.MAX_VALUE;
-			int maxLat = Integer.MIN_VALUE;
-			int minLon = Integer.MAX_VALUE;
-			int maxLon = Integer.MIN_VALUE;
-			for (Coord co: points) {
-				if (co.getLatitude() > maxLat)
-					maxLat = co.getLatitude();
-				if (co.getLatitude() < minLat)
-					minLat = co.getLatitude();
-				if (co.getLongitude() > maxLon)
-					maxLon = co.getLongitude();
-				if (co.getLongitude() < minLon)
-					minLon = co.getLongitude();
-			}
-			return new Area(minLat, minLon, maxLat, maxLon);
-		}
 	}
 	public final static long SINGLE_POINT_AREA = 1L<<6 * 1L<<6;
 	
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonCutter.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonCutter.java	(revision 3781)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonCutter.java	(working copy)
@@ -13,24 +13,23 @@
 
 package uk.me.parabola.mkgmap.reader.osm;
 
-import java.awt.geom.Area;
-import java.awt.geom.Path2D;
-import java.awt.geom.Rectangle2D;
+import java.awt.geom.Line2D;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Queue;
 
 import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
 import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.Area;
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.log.Logger;
-import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation.JoinedWay;
-import uk.me.parabola.util.Java2DConverter;
+import uk.me.parabola.mkgmap.filters.ShapeMergeFilter;
+//import uk.me.parabola.util.GpxCreator;
+import uk.me.parabola.util.ShapeSplitter;
 
 /**
  * Methods to cut an MP-relation so that holes are connected with the outer way(s).
@@ -43,18 +42,23 @@
 public class MultiPolygonCutter {
 	private static final Logger log = Logger.getLogger(MultiPolygonCutter.class);
 	private final MultiPolygonRelation rel;
-	private final Area tileArea;
+	private final uk.me.parabola.imgfmt.app.Area tileBounds;
+	private long cntDistCalc = 0;
+	private long cntMinDistChange = 0;
+	private final Long2ObjectOpenHashMap<Coord> coordPool = new Long2ObjectOpenHashMap<>();
 
 	/**
 	 * Create cutter for a given MP-relation and tile
 	 * @param multiPolygonRelation the MP-relation
-	 * @param tileArea the java area of the tile
+	 * @param tileBounds the java area of the tile
 	 */
-	public MultiPolygonCutter(MultiPolygonRelation multiPolygonRelation, Area tileArea) {
+	public MultiPolygonCutter(MultiPolygonRelation multiPolygonRelation, uk.me.parabola.imgfmt.app.Area tileBounds) {
 		rel = multiPolygonRelation;
-		this.tileArea = tileArea;
+		this.tileBounds = tileBounds;
 	}
 
+	
+
 	/**
 	 * Cut out all inner polygons from the outer polygon. This will divide the outer
 	 * polygon in several polygons.
@@ -67,32 +71,20 @@
 	 * @return a list of polygons that make the outer polygon cut by the inner
 	 *         polygons
 	 */
-	public List<Way> cutOutInnerPolygons(Way outerPolygon, List<Way> innerPolygons) {
-		if (innerPolygons.isEmpty()) {
-			Way outerWay = new JoinedWay(outerPolygon);
-			if (log.isDebugEnabled()) {
-				log.debug("Way", outerPolygon.getId(), "splitted to way", outerWay.getId());
-			}
-			return Collections.singletonList(outerWay);
-		}
-
-		// use the java.awt.geom.Area class because it's a quick
-		// implementation of what's needed
-
+	public List<Way> cutOutInnerPolygons(Way outerPolygon, List<Way> startInnerPolygons) {
 		// this list contains all non overlapping and singular areas
 		// of the outerPolygon
-		Queue<AreaCutData> areasToCut = new LinkedList<>();
-		Collection<Area> finishedAreas = new ArrayList<>(innerPolygons.size());
-		
+		Queue<AreaCutData> areasToCut = new LinkedList<AreaCutData>();
+		Collection<MyShape> finishedAreas = new ArrayList<>(startInnerPolygons.size());
+
 		// create a list of Area objects from the outerPolygon (clipped to the bounding box)
-		List<Area> outerAreas = createAreas(outerPolygon, true);
-		
+		List<MyShape> outerAreas = clip(outerPolygon, true);
+
 		// create the inner areas
-		List<Area> innerAreas = new ArrayList<>(innerPolygons.size()+2);
-		for (Way innerPolygon : innerPolygons) {
-			// don't need to clip to the bounding box because 
-			// these polygons are just used to cut out holes
-			innerAreas.addAll(createAreas(innerPolygon, false));
+		List<MyShape> innerAreas = new ArrayList<>(startInnerPolygons.size() + 2);
+		for (Way innerPolygon : startInnerPolygons) {
+			List<MyShape> inner = clip(innerPolygon, false);
+			innerAreas.addAll(inner);
 		}
 
 		// initialize the cut data queue
@@ -109,18 +101,16 @@
 			areasToCut.add(initialCutData);
 		} else {
 			// multiple outer areas
-			for (Area outerArea : outerAreas) {
+			for (MyShape outerArea : outerAreas) {
 				AreaCutData initialCutData = new AreaCutData();
 				initialCutData.outerArea = outerArea;
-				initialCutData.innerAreas = new ArrayList<>(innerAreas
-						.size());
-				for (Area innerArea : innerAreas) {
-					if (outerArea.getBounds2D().intersects(
-						innerArea.getBounds2D())) {
+				initialCutData.innerAreas = new ArrayList<>(innerAreas.size());
+				for (MyShape innerArea : innerAreas) {
+					if (outerArea.getBounds().intersects(innerArea.getBounds())) {
 						initialCutData.innerAreas.add(innerArea);
 					}
 				}
-				
+
 				if (initialCutData.innerAreas.isEmpty()) {
 					// this is either an error
 					// or the outer area has been cut into pieces on the tile bounds
@@ -131,623 +121,370 @@
 			}
 		}
 
-		while (!areasToCut.isEmpty()) {
+		List<Way> outerWays = new ArrayList<Way>(finishedAreas.size());
+		for (MyShape shape : finishedAreas) {
+			Way w = shape.createWay(rel.getId());
+			if (w != null) {
+				
+				w.copyTags(outerPolygon);
+				outerWays.add(w);
+				if (log.isDebugEnabled()) {
+					log.debug("Way", outerPolygon.getId(), "split to way", w.getId());
+				}
+//				GpxCreator.createGpx("e:/ld/way"+ n++, w.getPoints());
+			}
+		}
+
+		while (areasToCut.isEmpty() == false){
 			AreaCutData areaCutData = areasToCut.poll();
-			CutPoint cutPoint = calcNextCutPoint(areaCutData);
-			
-			if (cutPoint == null) {
-				finishedAreas.add(areaCutData.outerArea);
-				continue;
+			List<Coord> outerPoints = areaCutData.outerArea.points;
+			List<List<Coord>> innerPolygons = new ArrayList<List<Coord>>();
+
+			for (MyShape inner: areaCutData.innerAreas){
+				innerPolygons.add(inner.points);
 			}
-			
-			assert cutPoint.getNumberOfAreas() > 0 : "Number of cut areas == 0 in mp " + rel.getId();
-			
-			// cut out the holes
-			if (cutPoint.getAreas().size() == 1)
-				areaCutData.outerArea.subtract(cutPoint.getAreas().get(0));
-			else {
-				// first combine the areas that should be subtracted
-				Path2D.Double path = new Path2D.Double();
-				for (Area cutArea : cutPoint.getAreas()) {
-					path.append(cutArea, false);
-				}
-				Area combinedCutAreas = new Area(path);
-				areaCutData.outerArea.subtract(combinedCutAreas);
+			int numInner = innerPolygons.size();
+			Connector[] best = new Connector[numInner]; 
+			System.out.println("starting to connect " + numInner + " inner shapes to outer shape with " + outerPoints.size() + " points.");
+			for (int i = 0; i < numInner; i++){
+				best[i] = new Connector();
+				best[i].coShape = innerPolygons.get(i);
+				best[i].coShapePosInList = i;
 			}
-				
-			if (areaCutData.outerArea.isEmpty()) {
-				// this outer area space can be abandoned
-				continue;
-			} 
-			
-			// the inner areas of the cut point have been processed
-			// they are no longer needed
-			for (Area cutArea : cutPoint.getAreas()) {
-				ListIterator<Area> areaIter = areaCutData.innerAreas.listIterator();
-				while (areaIter.hasNext()) {
-					Area a = areaIter.next();
-					if (a == cutArea) {
-						areaIter.remove();
-						break;
+
+//			GpxCreator.createGpx("e:/ld/outer_", outerPoints);
+			for (int i = 0; i < numInner; i++) {
+				List<Coord> innerShape = best[i].coShape;
+				for (int j = 0; j < innerShape.size(); j++){
+					for (int k = 0; k + 1 < outerPoints.size(); k++) {
+						checkDist(best[i], innerShape, j, outerPoints, k);
 					}
 				}
 			}
-			// remove all does not seem to work. It removes more than the identical areas.
-//			areaCutData.innerAreas.removeAll(cutPoint.getAreas());
+			if (numInner > 1){
+				// allow direct connections of inner polygons
+				for (int i = 0; i < numInner; i++) {
+					// sort to have those inner polygons first that are closest to the outer shape
+					Arrays.sort(best, i, numInner);
+					List<Coord> innerShape1 = best[i].coShape;
 
-			if (areaCutData.outerArea.isSingular()) {
-				// the area is singular
-				// => no further splits necessary
-				if (areaCutData.innerAreas.isEmpty()) {
-					// this area is finished and needs no further cutting
-					finishedAreas.add(areaCutData.outerArea);
-				} else {
-					// read this area to further processing
-					areasToCut.add(areaCutData);
+					for (int j = 0; j + 1 < innerShape1.size(); j++) {
+						for (int k = i + 1; k < numInner; k++) {
+							if (best[k].distSqLine <= 0.0)
+								continue;
+							List<Coord> innerShape2 = best[k].coShape;
+							for (int l = 0; l < innerShape2.size(); l++){
+								checkDist(best[k], innerShape2, l, innerShape1, j);
+								if (best[k].distSqLine == 0.0)
+									break;
+							}
+						}
+					}
 				}
-			} else {
-				// we need to cut the area into two halves to get singular areas
-				Rectangle2D r1 = cutPoint.getCutRectangleForArea(areaCutData.outerArea, true);
-				Rectangle2D r2 = cutPoint.getCutRectangleForArea(areaCutData.outerArea, false);
+			}
+			System.out.println("dist calcs: " + cntDistCalc+ " changes: " + cntMinDistChange);
+			// calculate the coords for the connection
+			for (int i = 0; i < best.length; i++){
+				Connector connector = best[i];
+				int shapeId = connector.coShapePosInList;
+				
+				Coord nextToP1 = connector.sp1.shape.get(connector.sp1.idx + 1);
+				if (connector.p2 != nextToP1) {
+					// a point was added between p1 and p2, recalculate positions 
+					Coord stop = connector.p2;
+					connector.distSqLine = Double.MAX_VALUE;
+					for (int k = connector.sp1.idx; k < connector.sp1.shape.size(); k++) {
+						if (connector.sp1.shape.get(k) == stop)
+							break;
+						checkDist(connector, connector.coShape, connector.coPosInInnerShape, connector.sp1.shape, k);
+					}
+				}
+				
+				connector.closestPoint = connector.co.closestToSegment(connector.p1, connector.p2);
+//				GpxCreator.createGpx("e:/ld/inner_" + shapeId,connector.coShape);
+				if (connector.closestPoint != connector.p1 && connector.closestPoint != connector.p2){
+					List<Coord> shape = connector.sp1.shape;
+					int oldPosInShape = connector.sp1.idx;
 
-				// Now find the intersection of these two boxes with the
-				// original polygon. This will make two new areas, and each
-				// area will be one (or more) polygons.
-				Area a1 = new Area(r1); 
-				Area a2 = new Area(r2);
-				a1.intersect(areaCutData.outerArea);
-				a2.intersect(areaCutData.outerArea);
-				if (areaCutData.innerAreas.isEmpty()) {
-					finishedAreas.addAll(Java2DConverter.areaToSingularAreas(a1));
-					finishedAreas.addAll(Java2DConverter.areaToSingularAreas(a2));
-				} else {
-					ArrayList<Area> cuttedAreas = new ArrayList<>();
-					cuttedAreas.addAll(Java2DConverter.areaToSingularAreas(a1));
-					cuttedAreas.addAll(Java2DConverter.areaToSingularAreas(a2));
-					
-					for (Area nextOuterArea : cuttedAreas) {
-						ArrayList<Area> nextInnerAreas = null;
-						// go through all remaining inner areas and check if they
-						// must be further processed with the nextOuterArea 
-						for (Area nonProcessedInner : areaCutData.innerAreas) {
-							if (nextOuterArea.intersects(nonProcessedInner.getBounds2D())) {
-								if (nextInnerAreas == null) {
-									nextInnerAreas = new ArrayList<>();
-								}
-								nextInnerAreas.add(nonProcessedInner);
+					shape.add(oldPosInShape + 1, connector.closestPoint);
+//					GpxCreator.createGpx("e:/ld/mod_shape" + shapeId, shape);
+					// shape was changed, update postions
+					for (int j = 0; j < best.length; j++) {
+						if (best[j].coShape == connector.sp1.shape){
+							if (best[j].coPosInInnerShape > oldPosInShape){
+								best[j].coPosInInnerShape++;
 							}
+
 						}
-						
-						if (nextInnerAreas == null || nextInnerAreas.isEmpty()) {
-							finishedAreas.add(nextOuterArea);
-						} else {
-							AreaCutData outCutData = new AreaCutData();
-							outCutData.outerArea = nextOuterArea;
-							outCutData.innerAreas= nextInnerAreas;
-							areasToCut.add(outCutData);
+						if (best[j].sp1.shape == connector.sp1.shape){
+							if (best[j].sp1.idx > oldPosInShape){
+								best[j].sp1.idx++;
+							}
 						}
 					}
+
 				}
+				connector.closest = new ShapePos(connector.sp1);
+				if (connector.closestPoint != connector.p1)
+					connector.closest.idx++;
+				ConnectCoord cnCo = new ConnectCoord(connector);
+				cnCo.origCoord = connector.closest.shape.get(connector.closest.idx);
+				connector.closest.shape.set(connector.closest.idx, cnCo);
 			}
-			
-		}
-		
-		// convert the java.awt.geom.Area back to the mkgmap way
-		List<Way> cuttedOuterPolygon = new ArrayList<>(finishedAreas.size());
-		Long2ObjectOpenHashMap<Coord> commonCoordMap = new Long2ObjectOpenHashMap<>();
-		for (Area area : finishedAreas) {
-			Way w = singularAreaToWay(area, rel.getOriginalId());
-			if (w != null) {
-				w.setFakeId();
-				// make sure that equal coords are changed to identical coord instances
-				// this allows merging in the ShapeMerger
-				int n = w.getPoints().size();
-				for (int i = 0; i < n; i++){
-					Coord p = w.getPoints().get(i);
-					long key = Utils.coord2Long(p);
-					Coord replacement = commonCoordMap.get(key);
-					if (replacement == null)
-						commonCoordMap.put(key, p);
-					else {
-						assert p.highPrecEquals(replacement);
-						w.getPoints().set(i, replacement);
+
+			List<Coord> outer = new ArrayList<Coord>();
+
+			List<Coord> currShape = outerPoints;
+			int currPos = 0;
+			int currUsed = 0;
+			boolean done = false;
+			int num = 0;
+			LinkedList<ShapePos> stack = new LinkedList<ShapePos>(); 
+			while (!done){
+				int startPos = currPos;
+				while (currPos < currShape.size()){
+					Coord co = null;
+					while (currPos < currShape.size()
+							&& (co = currShape.get(currPos)) instanceof ConnectCoord == false) {
+						currPos++;
+						currUsed++;
+						if (currUsed >= currShape.size()){
+							break;
+						}
 					}
+					if (currPos != startPos){
+						int oldSize = outer.size();
+						if (currPos >= currShape.size()){
+							outer.addAll(currShape.subList(startPos, currPos-1));
+							currUsed--;
+						} else 
+							outer.addAll(currShape.subList(startPos, currPos));
+//						if (outer.size() != oldSize)
+//							GpxCreator.createGpx("e:/ld/part_" + ++num, outer);
+//						GpxCreator.createGpx("e:/ld/last_" + num, Collections.singletonList(outer.get(outer.size()-1)));
+					}
+
+					if (co != null){
+						if (co instanceof ConnectCoord){
+//							System.out.println(co);
+
+							ShapePos sp = new ShapePos(currShape, currPos, currUsed);
+							outer.add(new Coord(co));
+//							GpxCreator.createGpx("e:/ld/partx1_" + ++num, outer);
+//							GpxCreator.createGpx("e:/ld/last_" + num, Collections.singletonList(outer.get(outer.size()-1)));
+							stack.push(sp);
+							ConnectCoord cnCo = (ConnectCoord) co;
+							currShape = cnCo.nextShape;
+							currPos = cnCo.startSearch;
+							currUsed = 0; 
+//							System.out.println("using connectCoord for inner shape no. " + cnCo.cn.coShapePosInList);
+							while (cnCo.pointInNextShape.equals(currShape.get(currPos)) == false){
+								currPos++;
+							}
+
+							startPos = currPos;
+						}
+					}
+					if (currUsed >= currShape.size())
+						break;
 				}
-				w.copyTags(outerPolygon);
-				cuttedOuterPolygon.add(w);
-				if (log.isDebugEnabled()) {
-					log.debug("Way", outerPolygon.getId(), "splitted to way", w.getId());
+				if (currPos >= currShape.size()){
+					currPos = 0; 
 				}
-			}
-		}
+				if (currUsed >= currShape.size()){
+					if (stack.isEmpty())
+						done = true;
+					else {
+						ShapePos sp = stack.poll();
+						currPos = sp.idx;
+						currShape = sp.shape;
+						currUsed = sp.used;
+						Coord co = currShape.get(currPos);
+						assert co instanceof ConnectCoord;
 
-		return cuttedOuterPolygon;
-	}
-	
-	private static CutPoint calcNextCutPoint(AreaCutData areaData) {
-		if (areaData.innerAreas == null || areaData.innerAreas.isEmpty()) {
-			return null;
-		}
-		
-		Rectangle2D outerBounds = areaData.outerArea.getBounds2D();
-		
-		if (areaData.innerAreas.size() == 1) {
-			// make it short if there is only one inner area
-			CutPoint cutPoint1 = new CutPoint(CoordinateAxis.LATITUDE, outerBounds);
-			cutPoint1.addArea(areaData.innerAreas.get(0));
-			CutPoint cutPoint2 = new CutPoint(CoordinateAxis.LONGITUDE, outerBounds);
-			cutPoint2.addArea(areaData.innerAreas.get(0));
-			if (cutPoint1.compareTo(cutPoint2) > 0) {
-				return cutPoint1;
-			} else {
-				return cutPoint2;
-			}
-			
-		}
-		
-		ArrayList<Area> innerStart = new ArrayList<>(areaData.innerAreas);
-		
-		// first try to cut out all polygons that intersect the boundaries of the outer polygon
-		// this has the advantage that the outer polygon need not be split into two halves
-		for (CoordinateAxis axis : CoordinateAxis.values()) {
-			CutPoint edgeCutPoint = new CutPoint(axis, outerBounds);
+						ConnectCoord cnCo = (ConnectCoord) co;
+						currShape.set(currPos, cnCo.origCoord);
 
-			// go through the inner polygon list and use all polygons that intersect the outer polygons bbox at the start
-			Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
-			for (Area anInnerStart : innerStart) {
-				if (axis.getStart30(anInnerStart) <= axis.getStart30(outerBounds)) {
-					// found a touching area
-					edgeCutPoint.addArea(anInnerStart);
-				} else {
-					break;
+						outer.add(new Coord(currShape.get(currPos)));
+//						GpxCreator.createGpx("e:/ld/partx2_" + ++num, outer);
+//						GpxCreator.createGpx("e:/ld/last_" + num, Collections.singletonList(outer.get(outer.size()-1)));
+						if((cnCo.origCoord instanceof ConnectCoord) == false){
+							currPos++;
+							currUsed++;
+						}
+					}
 				}
+
 			}
-			if (edgeCutPoint.getNumberOfAreas() > 0) {
-				// there at least one intersecting inner polygon
-				return edgeCutPoint;
+			Way outerWay = new Way(FakeIdGenerator.makeFakeId(), outer);
+			outerWay.copyTags(outerPolygon);
+//			GpxCreator.createGpx("e:/ld/way_" + outerWay.getId(), outerWay.getPoints());
+
+			if (log.isDebugEnabled()) {
+				log.debug("Way", outerWay.getId(), "split to way", outerWay.getId());
 			}
-			
-			Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_STOP: COMP_LAT_STOP));
-			// go through the inner polygon list and use all polygons that intersect the outer polygons bbox at the stop
-			for (Area anInnerStart : innerStart) {
-				if (axis.getStop30(anInnerStart) >= axis.getStop30(outerBounds)) {
-					// found a touching area
-					edgeCutPoint.addArea(anInnerStart);
-				} else {
-					break;
-				}
-			}
-			if (edgeCutPoint.getNumberOfAreas() > 0) {
-				// there at least one intersecting inner polygon
-				return edgeCutPoint;
-			}
+			outerWays.add(outerWay);
 		}
-		
-		
-		ArrayList<CutPoint> bestCutPoints = new ArrayList<>(CoordinateAxis.values().length);
-		for (CoordinateAxis axis : CoordinateAxis.values()) {
-			CutPoint bestCutPoint = new CutPoint(axis, outerBounds);
-			CutPoint currentCutPoint = new CutPoint(axis, outerBounds);
 
-			Collections.sort(innerStart, (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START: COMP_LAT_START));
+		return outerWays;
+	}
 
-			for (Area anInnerStart : innerStart) {
-				currentCutPoint.addArea(anInnerStart);
+	private void checkDist(Connector connector, List<Coord> inner, int posInner, List<Coord> shape2, int posInShape2) {
+		Coord pInner = inner.get(posInner);
+		Coord p1 = shape2.get(posInShape2);
+		Coord p2 = shape2.get(posInShape2 + 1);
+		double distSq = Line2D.ptSegDistSq(p1.getHighPrecLon(), p1.getHighPrecLat(), p2.getHighPrecLon(),
+				p2.getHighPrecLat(), pInner.getHighPrecLon(), pInner.getHighPrecLat());
 
-				if (currentCutPoint.compareTo(bestCutPoint) > 0) {
-					bestCutPoint = currentCutPoint.duplicate();
-				}
-			}
-			bestCutPoints.add(bestCutPoint);
+		++cntDistCalc;
+		if (distSq < connector.distSqLine) {
+			++cntMinDistChange;
+			connector.distSqLine = distSq;
+			connector.co = pInner;
+			connector.coShape = inner;
+			connector.p1 = p1;
+			connector.p2 = p2;
+			connector.coPosInInnerShape = posInner;
+			connector.sp1 = new ShapePos(shape2, posInShape2, 0);
 		}
-
-		return Collections.max(bestCutPoints);
-		
 	}
 
 	/**
-	 * Create the areas that are enclosed by the way. Usually the result should
-	 * only be one area but some ways contain intersecting lines. To handle these
-	 * erroneous cases properly the method might return a list of areas.
-	 * 
-	 * @param w a closed way
-	 * @param clipBbox true if the areas should be clipped to the bounding box; false else
-	 * @return a list of enclosed ares
+	 * Clip closed way to tile boundaries.
+	 * @param way the way to clip
+	 * @param outer set to true if this is an outer way 
+	 * @return the shapes inside the clipping bounds
 	 */
-	private List<Area> createAreas(Way w, boolean clipBbox) {
-		Area area = Java2DConverter.createArea(w.getPoints());
-		if (clipBbox && !tileArea.contains(area.getBounds2D())) {
-			// the area intersects the bounding box => clip it
-			area.intersect(tileArea);
+	private List<MyShape> clip(Way way, boolean outer) {
+		List<List<Coord>> clipped = ShapeSplitter.clipToBounds(way.getPoints(), tileBounds, coordPool);
+		List<MyShape> result = new ArrayList<>();
+		for (List<Coord> points : clipped) {
+			long testVal = ShapeMergeFilter.calcAreaSizeTestVal(points);
+			if (testVal == 0)
+				continue;
+			if (outer && testVal > 0 || !outer && testVal < 0)
+				Collections.reverse(points);
+			result.add(new MyShape(points));
 		}
-		List<Area> areaList = Java2DConverter.areaToSingularAreas(area);
-		if (log.isDebugEnabled()) {
-			log.debug("Bbox clipped way",w.getId()+"=>",areaList.size(),"distinct area(s).");
-		}
-		return areaList;
+		return result;
 	}
-
+	
 	/**
-	 * Convert an area to an mkgmap way. The caller must ensure that the area is singular.
-	 * Otherwise only the first part of the area is converted.
-	 * 
-	 * @param area
-	 *            the area
-	 * @param wayId
-	 *            the wayid for the new way
-	 * @return a new mkgmap way
+	 * Helper structure to combine one outer polygon with the possible
+	 * inner areas. 
+	 * @author Gerd Petermann
+	 *
 	 */
-	private Way singularAreaToWay(Area area, long wayId) {
-		List<Coord> points = Java2DConverter.singularAreaToPoints(area);
-		if (points == null || points.isEmpty()) {
-			if (log.isDebugEnabled()) {
-				log.debug("Empty area", wayId + ".", rel.toBrowseURL());
-			}
-			return null;
-		}
-
-		return new Way(wayId, points);
-	}
 	private static class AreaCutData {
-		Area outerArea;
-		List<Area> innerAreas;
+		MyShape outerArea;
+		List<MyShape> innerAreas;
 	}
 
-	private static final int CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD = 1<<(11 + Coord.DELTA_SHIFT);
-	private static final int CUT_POINT_CLASSIFICATION_BAD_THRESHOLD = 1<< (8 + Coord.DELTA_SHIFT);
-	private static class CutPoint implements Comparable<CutPoint>{
-		private int startPoint30 = Integer.MAX_VALUE; // 30 bits precision map units
-		private int stopPoint30 = Integer.MIN_VALUE;  // 30 bits precision map units
-		private Integer cutPoint30 = null; // 30 bits precision map units
-		private final LinkedList<Area> areas;
-		private final Comparator<Area> comparator;
-		private final CoordinateAxis axis;
-		private Rectangle2D bounds;
-		private final Rectangle2D outerBounds;
-		private Double minAspectRatio;
+	/**
+	 * Helper class 
+	 * @author Gerd Petermann
+	 *
+	 */
+	private static class Connector implements Comparable<Object>{
+		double distSqLine;
+		Coord co;	// nearest point to
+		Coord p1, p2; // line segment
+		Coord closestPoint;
+		List<Coord> coShape;
+		int coShapePosInList; // debugging aid
+		int coPosInInnerShape;
+		ShapePos sp1;
+		ShapePos closest;
 
-		public CutPoint(CoordinateAxis axis, Rectangle2D outerBounds) {
-			this.axis = axis;
-			this.outerBounds = outerBounds;
-			this.areas = new LinkedList<>();
-			this.comparator = (axis == CoordinateAxis.LONGITUDE ? COMP_LONG_STOP : COMP_LAT_STOP);
+		public Connector(){
+			distSqLine = Double.MAX_VALUE;
 		}
-		
-		public CutPoint duplicate() {
-			CutPoint newCutPoint = new CutPoint(this.axis, this.outerBounds);
-			newCutPoint.areas.addAll(areas);
-			newCutPoint.startPoint30 = startPoint30;
-			newCutPoint.stopPoint30 = stopPoint30;
-			return newCutPoint;
-		}
 
-		private boolean isGoodCutPoint() {
-			// It is better if the cutting line is on a multiple of 2048. 
-			// Otherwise MapSource and QLandkarteGT paints gaps between the cuts
-			return getCutPoint30() % CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD == 0;
+		public String toString(){
+			return (coShapePosInList + " with " + coShape.size() + " -> " + distSqLine);
 		}
-		
-		private boolean isBadCutPoint() {
-			int d1 = getCutPoint30() - startPoint30;
-			int d2 = stopPoint30 - getCutPoint30();
-			return Math.min(d1, d2) < CUT_POINT_CLASSIFICATION_BAD_THRESHOLD;
-		}
-		
-		private boolean isStartCut() {
-			return (startPoint30 <= axis.getStart30(outerBounds));
-		}
-		
-		private boolean isStopCut() {
-			return (stopPoint30 >= axis.getStop30(outerBounds));
-		}
-		
-		/**
-		 * Calculates the point where the cut should be applied.
-		 * @return the point of cut
-		 */
-		private int getCutPoint30() {
-			if (cutPoint30 != null) {
-				// already calculated => just return it
-				return cutPoint30;
-			}
-			
-			if (startPoint30 == stopPoint30) {
-				// there is no choice => return the one possible point 
-				cutPoint30 = startPoint30;
-				return cutPoint30;
-			}
-			
-			if (isStartCut()) {
-				// the polygons can be cut out at the start of the sector
-				// thats good because the big polygon need not to be cut into two halves
-				cutPoint30 = startPoint30;
-				return cutPoint30;
-			}
-			
-			if (isStopCut()) {
-				// the polygons can be cut out at the end of the sector
-				// thats good because the big polygon need not to be cut into two halves
-				cutPoint30 = startPoint30;
-				return cutPoint30;
-			}
-			
-			// try to cut with a good aspect ratio so try the middle of the polygon to be cut
-			int midOuter30 = axis.getStart30(outerBounds)+(axis.getStop30(outerBounds) - axis.getStart30(outerBounds)) / 2;
-			cutPoint30 = midOuter30;
-
-			if (midOuter30 < startPoint30) {
-				// not possible => the start point is greater than the middle so correct to the startPoint
-				cutPoint30 = startPoint30;
-				
-				if (((cutPoint30 & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1)) + CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD) <= stopPoint30) {
-					cutPoint30 = ((cutPoint30 & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1)) + CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD);
-				}
-				
-			} else if (midOuter30 > stopPoint30) {
-				// not possible => the stop point is smaller than the middle so correct to the stopPoint
-				cutPoint30 = stopPoint30;
-
-				if ((cutPoint30 & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1))  >= startPoint30) {
-					cutPoint30 = (cutPoint30 & ~(CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD-1));
-				}
-			}
-			
-			
-			// try to find a cut point that is a multiple of 2048 to 
-			// avoid that gaps are painted by MapSource and QLandkarteGT
-			// between the cutting lines
-			int cutMod = cutPoint30 % CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD;
-			if (cutMod == 0) {
-				return cutPoint30;
-			}
-			
-			int cut1 = (cutMod > 0 ? cutPoint30-cutMod : cutPoint30  - CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD- cutMod);
-			if (cut1 >= startPoint30 && cut1 <= stopPoint30) {
-				cutPoint30 = cut1;
-				return cutPoint30;
-			}
-			
-			int cut2 = (cutMod > 0 ? cutPoint30 + CUT_POINT_CLASSIFICATION_GOOD_THRESHOLD -cutMod : cutPoint30 - cutMod);
-			if (cut2 >= startPoint30 && cut2 <= stopPoint30) {
-				cutPoint30 = cut2;
-				return cutPoint30;
-			}
-			
-			return cutPoint30;
-		}
-
-		public Rectangle2D getCutRectangleForArea(Area toCut, boolean firstRect) {
-			return getCutRectangleForArea(toCut.getBounds2D(), firstRect);
-		}
-		
-		public Rectangle2D getCutRectangleForArea(Rectangle2D areaRect, boolean firstRect) {
-			double cp = (double)  getCutPoint30() / (1<<Coord.DELTA_SHIFT);
-			if (axis == CoordinateAxis.LONGITUDE) {
-				double newWidth = cp-areaRect.getX();
-				if (firstRect) {
-					return new Rectangle2D.Double(areaRect.getX(), areaRect.getY(), newWidth, areaRect.getHeight()); 
-				} else {
-					return new Rectangle2D.Double(areaRect.getX()+newWidth, areaRect.getY(), areaRect.getWidth()-newWidth, areaRect.getHeight()); 
-				}
-			} else {
-				double newHeight = cp-areaRect.getY();
-				if (firstRect) {
-					return new Rectangle2D.Double(areaRect.getX(), areaRect.getY(), areaRect.getWidth(), newHeight); 
-				} else {
-					return new Rectangle2D.Double(areaRect.getX(), areaRect.getY()+newHeight, areaRect.getWidth(), areaRect.getHeight()-newHeight); 
-				}
-			}
-		}
-		
-		public List<Area> getAreas() {
-			return areas;
-		}
-
-		public void addArea(Area area) {
-			// remove all areas that do not overlap with the new area
-			while (!areas.isEmpty() && axis.getStop30(areas.getFirst()) < axis.getStart30(area)) {
-				// remove the first area
-				areas.removeFirst();
-			}
-
-			areas.add(area);
-			Collections.sort(areas, comparator);
-			startPoint30 = axis.getStart30(Collections.max(areas,
-				(axis == CoordinateAxis.LONGITUDE ? COMP_LONG_START
-						: COMP_LAT_START)));
-			stopPoint30 = axis.getStop30(areas.getFirst());
-			
-			// reset the cached value => need to be recalculated the next time they are needed
-			bounds = null;
-			cutPoint30 = null;
-			minAspectRatio = null;
-		}
-
-		public int getNumberOfAreas() {
-			return this.areas.size();
-		}
-
-		/**
-		 * Retrieves the minimum aspect ratio of the outer bounds after cutting.
-		 * 
-		 * @return minimum aspect ratio of outer bound after cutting
-		 */
-		public double getMinAspectRatio() {
-			if (minAspectRatio == null) {
-				// first get the left/upper cut
-				Rectangle2D r1 = getCutRectangleForArea(outerBounds, true);
-				double s1_1 = CoordinateAxis.LATITUDE.getSizeOfSide(r1);
-				double s1_2 = CoordinateAxis.LONGITUDE.getSizeOfSide(r1);
-				double ar1 = Math.min(s1_1, s1_2) / Math.max(s1_1, s1_2);
-
-				// second get the right/lower cut
-				Rectangle2D r2 = getCutRectangleForArea(outerBounds, false);
-				double s2_1 = CoordinateAxis.LATITUDE.getSizeOfSide(r2);
-				double s2_2 = CoordinateAxis.LONGITUDE.getSizeOfSide(r2);
-				double ar2 = Math.min(s2_1, s2_2) / Math.max(s2_1, s2_2);
-
-				// get the minimum
-				minAspectRatio = Math.min(ar1, ar2);
-			}
-			return minAspectRatio;
-		}
-		
-		public int compareTo(CutPoint o) {
-			if (this == o) {
+		@Override
+		public int compareTo(Object o) {
+			if (this == o)
 				return 0;
-			}
-			// prefer a cut at the boundaries
-			if (isStartCut() && o.isStartCut() == false) {
+			double d = this.distSqLine - ((Connector) o).distSqLine;
+			if (d > 0)
 				return 1;
-			} 
-			else if (isStartCut() == false && o.isStartCut()) {
+			else if (d <  0)
 				return -1;
-			}
-			else if (isStopCut() && o.isStopCut() == false) {
-				return 1;
-			}
-			else if (isStopCut() == false && o.isStopCut()) {
-				return -1;
-			}
-			
-			// handle the special case that a cut has no area
-			if (getNumberOfAreas() == 0) {
-				if (o.getNumberOfAreas() == 0) {
-					return 0;
-				} else {
-					return -1;
-				}
-			} else if (o.getNumberOfAreas() == 0) {
-				return 1;
-			}
-			
-			if (isBadCutPoint() != o.isBadCutPoint()) {
-				if (isBadCutPoint()) {
-					return -1;
-				} else
-					return 1;
-			}
-			
-			double dAR = getMinAspectRatio() - o.getMinAspectRatio();
-			if (dAR != 0) {
-				return (dAR > 0 ? 1 : -1);
-			}
-			
-			if (isGoodCutPoint() != o.isGoodCutPoint()) {
-				if (isGoodCutPoint())
-					return 1;
-				else
-					return -1;
-			}
-			
-			// prefer the larger area that is split
-			double ss1 = axis.getSizeOfSide(getBounds2D());
-			double ss2 = o.axis.getSizeOfSide(o.getBounds2D());
-			if (ss1-ss2 != 0)
-				return Double.compare(ss1,ss2); 
 
-			int ndiff = getNumberOfAreas()-o.getNumberOfAreas();
-			return ndiff;
-
+			return 0;
 		}
-
-		private Rectangle2D getBounds2D() {
-			if (bounds == null) {
-				// lazy init
-				bounds = new Rectangle2D.Double();
-				for (Area a : areas)
-					bounds.add(a.getBounds2D());
-			}
-			return bounds;
-		}
-
-		public String toString() {
-			return axis +" "+getNumberOfAreas()+" "+startPoint30+" "+stopPoint30+" "+getCutPoint30();
-		}
 	}
 
-	private static enum CoordinateAxis {
-		LATITUDE(false), LONGITUDE(true);
+	private static class ShapePos{
+		List<Coord> shape;
+		int idx;
+		int used;
 
-		private CoordinateAxis(boolean useX) {
-			this.useX = useX;
+		public ShapePos(List<Coord> shape, int pos, int used) {
+			this.shape = shape;
+			this.idx = pos;
+			this.used = used;
 		}
 
-		private final boolean useX;
-
-		public int getStart30(Area area) {
-			return getStart30(area.getBounds2D());
+		public ShapePos(ShapePos other) {
+			this.shape = other.shape;
+			this.idx = other.idx;
+			this.used = other.used;
 		}
 
-		public int getStart30(Rectangle2D rect) {
-			double val = (useX ? rect.getX() : rect.getY());
-			return (int)Math.round(val * (1<<Coord.DELTA_SHIFT));
+		public boolean equals(Object other){
+			if (this == other)
+				return true;
+			if (other instanceof ShapePos){
+				ShapePos o = (ShapePos) other;
+				if (shape == o.shape && idx == o.idx)
+					return true;
+			}
+			return false;
 		}
 
-		public int getStop30(Area area) {
-			return getStop30(area.getBounds2D());
+		@Override
+		public int hashCode() {
+			return shape.hashCode() | idx;
 		}
+	}
 
-		public int getStop30(Rectangle2D rect) {
-			double val = (useX ? rect.getMaxX() : rect.getMaxY());
-			return (int)Math.round(val * (1<<Coord.DELTA_SHIFT));
+	private static class ConnectCoord extends Coord{
+//		final Connector cn;
+		final List<Coord> nextShape;
+		final Coord pointInNextShape;
+		final int startSearch;
+		Coord origCoord;
+
+		ConnectCoord (Connector cn){
+			super(cn.closestPoint);
+//			this.cn = cn;
+			this.nextShape = cn.coShape;
+			this.pointInNextShape = cn.co;
+			this.startSearch = cn.coPosInInnerShape;
 		}
-		
-		public double getSizeOfSide(Rectangle2D rect) {
-			if (useX) {
-				int lat30 = (int)Math.round(rect.getY() * (1<<Coord.DELTA_SHIFT));
-				Coord c1 = Coord.makeHighPrecCoord(lat30, getStart30(rect));
-				Coord c2 = Coord.makeHighPrecCoord(lat30, getStop30(rect));
-				return c1.distance(c2);
-			} else {
-				int lon30 = (int)Math.round(rect.getX() * (1<<Coord.DELTA_SHIFT));
-				Coord c1 = Coord.makeHighPrecCoord(getStart30(rect), lon30);
-				Coord c2 = Coord.makeHighPrecCoord(getStop30(rect), lon30);
-				return c1.distance(c2);
-			}
-		}
 	}
 	
-	private static final AreaComparator COMP_LONG_START = new AreaComparator(
-			true, CoordinateAxis.LONGITUDE);
-	private static final AreaComparator COMP_LONG_STOP = new AreaComparator(
-			false, CoordinateAxis.LONGITUDE);
-	private static final AreaComparator COMP_LAT_START = new AreaComparator(
-			true, CoordinateAxis.LATITUDE);
-	private static final AreaComparator COMP_LAT_STOP = new AreaComparator(
-			false, CoordinateAxis.LATITUDE);
+	private static class MyShape {
+		final List<Coord> points;
+		final Area bounds;
 
-	private static class AreaComparator implements Comparator<Area> {
+		public MyShape(List<Coord> points) {
+			this.points = points;
+			this.bounds = Utils.getArea(points);
+		}
 
-		private final CoordinateAxis axis;
-		private final boolean startPoint;
-
-		public AreaComparator(boolean startPoint, CoordinateAxis axis) {
-			this.startPoint = startPoint;
-			this.axis = axis;
+		public Way createWay(long relId) {
+			Way way =  new Way(relId, points);
+			way.setFakeId();
+			return way;
 		}
 
-		public int compare(Area o1, Area o2) {
-			if (o1 == o2) {
-				return 0;
-			}
-
-			if (startPoint) {
-				int cmp = axis.getStart30(o1) - axis.getStart30(o2);
-				if (cmp == 0) {
-					return axis.getStop30(o1) - axis.getStop30(o2);
-				} else {
-					return cmp;
-				}
-			} else {
-				int cmp = axis.getStop30(o1) - axis.getStop30(o2);
-				if (cmp == 0) {
-					return axis.getStart30(o1) - axis.getStart30(o2);
-				} else {
-					return cmp;
-				}
-			}
+		public Area getBounds() {
+			return bounds;
 		}
-
+		
 	}
 }
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java	(revision 3781)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java	(working copy)
@@ -982,8 +982,7 @@
 			if (processPolygon) {
 				List<Way> singularOuterPolygons;
 				if (holes.isEmpty()) {
-					singularOuterPolygons = Collections
-							.singletonList((Way) new JoinedWay(currentPolygon.polygon));
+					singularOuterPolygons = Collections.singletonList((Way) new JoinedWay(currentPolygon.polygon));
 				} else {
 					List<Way> innerWays = new ArrayList<>(holes.size());
 					for (PolygonStatus polygonHoleStatus : holes) {
@@ -990,7 +989,7 @@
 						innerWays.add(polygonHoleStatus.polygon);
 					}
 
-					MultiPolygonCutter cutter = new MultiPolygonCutter(this, tileArea);
+					MultiPolygonCutter cutter = new MultiPolygonCutter(this, tileBounds);
 					singularOuterPolygons = cutter.cutOutInnerPolygons(currentPolygon.polygon, innerWays);
 				}
 				
