In trying to determine the cause of the problem that Felix has reported
when tiles use a lot of polygon styles, I have been looking at the code
that divides areas into "subdivisions". The attached patch (applies to
1170) makes a few changes in that department. It is not expected to fix
the polygon problem but it should be otherwise beneficial in that it
will reduce the number of subdivisions created.

Please do test this patch, especially if you are processing complex
maps as I don't want to commit it until it's had a good bashing.

I have processed all of GB and NL without problems.



diff --git a/src/uk/me/parabola/mkgmap/build/MapArea.java b/src/uk/me/parabola/mkgmap/build/MapArea.java
index 137de17..7fd0da0 100644
--- a/src/uk/me/parabola/mkgmap/build/MapArea.java
+++ b/src/uk/me/parabola/mkgmap/build/MapArea.java
@@ -24,8 +24,10 @@ import uk.me.parabola.imgfmt.app.trergn.Overview;
 import uk.me.parabola.log.Logger;
 import uk.me.parabola.mkgmap.filters.FilterConfig;
 import uk.me.parabola.mkgmap.filters.LineSizeSplitterFilter;
+import uk.me.parabola.mkgmap.filters.LineSplitterFilter;
 import uk.me.parabola.mkgmap.filters.MapFilterChain;
 import uk.me.parabola.mkgmap.filters.PolygonSizeSplitterFilter;
+import uk.me.parabola.mkgmap.filters.PolygonSplitterFilter;
 import uk.me.parabola.mkgmap.general.MapDataSource;
 import uk.me.parabola.mkgmap.general.MapElement;
 import uk.me.parabola.mkgmap.general.MapLine;
@@ -49,9 +51,9 @@ public class MapArea implements MapDataSource {
 	private static final int INITIAL_CAPACITY = 100;
 	private static final int MAX_RESOLUTION = 24;
 
-	private static final int POINT_KIND = 0;
-	private static final int LINE_KIND = 1;
-	private static final int SHAPE_KIND = 2;
+	public static final int POINT_KIND = 0;
+	public static final int LINE_KIND = 1;
+	public static final int SHAPE_KIND = 2;
 
 	// This is the initial area.
 	private final Area bounds;
@@ -247,27 +249,16 @@ public class MapArea implements MapDataSource {
 	 * @return An estimate of the max size that will be needed in the RGN file
 	 * for this sub-division.
 	 */
-	public int getSizeAtResolution(int res) {
-		int psize = 0;
-		int lsize = 0;
-		int ssize = 0;
+	public int[] getSizeAtResolution(int res) {
+		int[] sizes = new int[3];
 		
 		for (int i = 0; i <= res; i++) {
-
-			psize += pointSize[i];
-			lsize += lineSize[i];
-			ssize += shapeSize[i];
+			sizes[POINT_KIND] += pointSize[i];
+			sizes[LINE_KIND] += lineSize[i];
+			sizes[SHAPE_KIND] += shapeSize[i];
 		}
 
-		// Return the largest one as an overflow of any means that we have to
-		// split the area.
-		int size = psize;
-		if (lsize > size)
-			size = lsize;
-		if (ssize > size)
-			size = ssize;
-
-		return size;
+		return sizes;
 	}
 
 	/**
@@ -359,6 +350,13 @@ public class MapArea implements MapDataSource {
 	}
 
 	/**
+	 * Return number of shapes in this area.
+	 */
+	public int getNumShapes() {
+		return nActiveShapes;
+	}
+
+	/**
 	 * Return number of points in this area.
 	 */
 	public int getNumPoints() {
@@ -416,22 +414,20 @@ public class MapArea implements MapDataSource {
 			break;
 
 		case LINE_KIND:
-			if (res <= areaResolution)
-				nActiveLines++;
-
 			// Estimate the size taken by lines and shapes as a constant plus
 			// a factor based on the number of points.
 			n = ((MapLine) p).getPoints().size();
 			s = 11 + n * 2;
+			if (res <= areaResolution)
+				nActiveLines += 1 + ((n - 1) / LineSplitterFilter.MAX_POINTS_IN_LINE);
 			break;
 		case SHAPE_KIND:
-			if (res <= areaResolution)
-				nActiveShapes++;
-
 			// Estimate the size taken by lines and shapes as a constant plus
 			// a factor based on the number of points.
 			n = ((MapLine) p).getPoints().size();
 			s = 11 + n * 2;
+			if (res <= areaResolution)
+				nActiveShapes += 1 + ((n - 1) / PolygonSplitterFilter.MAX_POINT_IN_ELEMENT);
 			break;
 
 		default:
diff --git a/src/uk/me/parabola/mkgmap/build/MapSplitter.java b/src/uk/me/parabola/mkgmap/build/MapSplitter.java
index ac490df..487497d 100644
--- a/src/uk/me/parabola/mkgmap/build/MapSplitter.java
+++ b/src/uk/me/parabola/mkgmap/build/MapSplitter.java
@@ -43,15 +43,12 @@ class MapSplitter {
 
 	// The maximum region size.  Note that the offset to the start of a section
 	// has to fit into 16 bits, the end of the last section could be beyond the
-	// 16 bit limit, but we make sure that everything fits into under half the
-	// allowed space.  Really I'm not sure what the max actually is on real
-	// devices.
-	private static final int MAX_RGN_SIZE = 30 * 1024;
+	// 16 bit limit. Leave a little room for the region pointers
+	private static final int MAX_RGN_SIZE = 0xfff8;
 
 	// The maximum number of lines. NET points to lines in subdivision
 	// using bytes.
-	// Theoretical maximum about 0x100, which still gives errors.
-	private static final int MAX_NUM_LINES = 0xf0;
+	private static final int MAX_NUM_LINES = 0xff;
 
 	private static final int MAX_NUM_POINTS = 0xff;
 
@@ -94,7 +91,7 @@ class MapSplitter {
 		// in them.  For those that do, we further split them.  This is done
 		// recursively until everything fits.
 		List<MapArea> alist = new ArrayList<MapArea>();
-		addAreasToList(areas, alist);
+		addAreasToList(areas, alist, 0);
 
 		MapArea[] results = new MapArea[alist.size()];
 		return alist.toArray(results);
@@ -109,17 +106,38 @@ class MapSplitter {
 	 * @param alist The list that will finally contain the complete list of
 	 * map areas.
 	 */
-	private void addAreasToList(MapArea[] areas, List<MapArea> alist) {
+	private void addAreasToList(MapArea[] areas, List<MapArea> alist, int depth) {
 		int res = zoom.getResolution();
 		for (MapArea area : areas) {
-			if (area.getSizeAtResolution(res) > MAX_RGN_SIZE
-			    || area.getNumLines() > MAX_NUM_LINES
-			    || area.getNumPoints() > MAX_NUM_POINTS) {
+			Area bounds = area.getBounds();
+			int[] sizes = area.getSizeAtResolution(res);
+			if(log.isInfoEnabled()) {
+				String padding = "                                            ";
+				log.info(padding.substring(0, depth * 2) + 
+						 bounds.getWidth() + "x" + bounds.getHeight() +
+						 ", res = " + res +
+						 ", depth = " + depth +
+						 ", size = (" + sizes[0] + "," + sizes[1] + "," + sizes[2] + ")" +
+						 ", points = " + area.getNumPoints() +
+						 ", lines = " + area.getNumLines() +
+						 ", shapes = " + area.getNumShapes());
+			}
+
+			if ((sizes[MapArea.POINT_KIND] > MAX_RGN_SIZE &&
+				 (area.hasLines() || area.hasShapes())) ||
+				(((sizes[MapArea.POINT_KIND] + sizes[MapArea.LINE_KIND]) > MAX_RGN_SIZE) &&
+				 area.hasShapes()) ||
+			    area.getNumLines() > MAX_NUM_LINES ||
+			    area.getNumPoints() > MAX_NUM_POINTS) {
 				if (area.getBounds().getMaxDimention() > 100) {
 					if (log.isDebugEnabled())
 						log.debug("splitting area", area);
-					MapArea[] sublist = area.split(2, 2, res);
-					addAreasToList(sublist, alist);
+					MapArea[] sublist;
+					if(bounds.getWidth() > bounds.getHeight())
+						sublist = area.split(2, 1, res);
+					else
+						sublist = area.split(1, 2, res);
+					addAreasToList(sublist, alist, depth + 1);
 					continue;
 				} else {
 					log.warn("area too small to split", area);
diff --git a/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java b/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java
index 3ba4a74..921d9d4 100644
--- a/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java
+++ b/src/uk/me/parabola/mkgmap/filters/LineSplitterFilter.java
@@ -35,7 +35,7 @@ public class LineSplitterFilter implements MapFilter {
 	private static final Logger log = Logger.getLogger(LineSplitterFilter.class);
 	
 	// Not sure of the value, probably 255.  Say 250 here.
-	private static final int MAX_POINTS_IN_LINE = 250;
+	public static final int MAX_POINTS_IN_LINE = 250;
 
 	public void init(FilterConfig config) {
 	}
diff --git a/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java b/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java
index 6cf397b..71be5b1 100644
--- a/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java
+++ b/src/uk/me/parabola/mkgmap/filters/PolygonSplitterFilter.java
@@ -37,7 +37,7 @@ import java.util.List;
  * @author Steve Ratcliffe
  */
 public class PolygonSplitterFilter extends PolygonSplitterBase implements MapFilter {
-	private static final int MAX_POINT_IN_ELEMENT = 250;
+	public static final int MAX_POINT_IN_ELEMENT = 250;
 
 	/**
 	 * Split up polygons that have more than the max allowed number of points.
diff --git a/src/uk/me/parabola/mkgmap/general/MapLine.java b/src/uk/me/parabola/mkgmap/general/MapLine.java
index a30352b..d34d3be 100644
--- a/src/uk/me/parabola/mkgmap/general/MapLine.java
+++ b/src/uk/me/parabola/mkgmap/general/MapLine.java
@@ -64,9 +64,11 @@ public class MapLine extends MapElement {
 		Coord last = null;
 		for (Coord co : points) {
 			if (last != null && last.equals(co))
-				log.info("Line " + getName() + " has consecutive identical points at ", co.toDegreeString());
-			addToBounds(co);
-			last = co;
+				log.info("Line " + getName() + " has consecutive identical points at " + co.toDegreeString() + " (discarding)");
+			else {
+				addToBounds(co);
+				last = co;
+			}
 		}
 	}
 
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to