Hi Ivan, It took me a little longer than expected (as I decided to revamp what was there) but I have a patch for you to try (attached).
This limits the size of the extended type elements to 32KB for each of the points/lines/shapes. I have no idea if that is a sensible limit but you can alter it by changing these lines in MapSplitter.java: // maximum allowed amounts of points/lines/shapes with extended types private static final int MAX_XT_POINTS_SIZE = 0x8000; private static final int MAX_XT_LINES_SIZE = 0x8000; private static final int MAX_XT_SHAPES_SIZE = 0x8000; I hope it solves the problem. Mark
diff --git a/src/uk/me/parabola/mkgmap/build/MapArea.java b/src/uk/me/parabola/mkgmap/build/MapArea.java index d668cda..d562fdb 100644 --- a/src/uk/me/parabola/mkgmap/build/MapArea.java +++ b/src/uk/me/parabola/mkgmap/build/MapArea.java @@ -51,9 +51,13 @@ public class MapArea implements MapDataSource { private static final int INITIAL_CAPACITY = 100; private static final int MAX_RESOLUTION = 24; - public static final int POINT_KIND = 0; - public static final int LINE_KIND = 1; - public 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; + public static final int XT_POINT_KIND = 3; + public static final int XT_LINE_KIND = 4; + public static final int XT_SHAPE_KIND = 5; + public static final int NUM_KINDS = 6; // This is the initial area. private final Area bounds; @@ -70,11 +74,8 @@ public class MapArea implements MapDataSource { private final List<MapLine> lines = new ArrayList<MapLine>(INITIAL_CAPACITY); private final List<MapShape> shapes = new ArrayList<MapShape>(INITIAL_CAPACITY); - // Counts of features available at different resolutions. - private final int[] pointSize = new int[MAX_RESOLUTION+1]; - private final int[] lineSize = new int[MAX_RESOLUTION+1]; - private final int[] shapeSize = new int[MAX_RESOLUTION+1]; - private final int[] elemCounts = new int[MAX_RESOLUTION+1]; + // amount of space required for the contents + private final int[] sizes = new int[NUM_KINDS]; private int nActivePoints; private int nActiveIndPoints; @@ -99,7 +100,7 @@ public class MapArea implements MapDataSource { for (MapPoint p : src.getPoints()) { points.add(p); - addSize(p, pointSize, POINT_KIND); + addSize(p, p.hasExtendedType()? XT_POINT_KIND : POINT_KIND); } addLines(src, resolution); addPolygons(src, resolution); @@ -116,7 +117,7 @@ public class MapArea implements MapDataSource { MapShape shape = (MapShape) element; shapes.add(shape); - addSize(element, shapeSize, SHAPE_KIND); + addSize(element, shape.hasExtendedType()? XT_SHAPE_KIND : SHAPE_KIND); } public void addElement(MapElement element) { @@ -149,7 +150,7 @@ public class MapArea implements MapDataSource { MapLine line = (MapLine) element; lines.add(line); - addSize(element, lineSize, LINE_KIND); + addSize(element, line.hasExtendedType()? XT_LINE_KIND : LINE_KIND); } public void addElement(MapElement element) { @@ -240,24 +241,12 @@ public class MapArea implements MapDataSource { /** * Get an estimate of the size of the RGN space that will be required to - * hold the points in this area. For points we can be fairly accurate, but - * we just guess an upper bound for lines and shapes since we don't know the - * exact size until later. + * hold the elements * - * @param res The resolution to test for. At lower resolutions, there are - * less elements so less room is needed. - * @return An estimate of the max size that will be needed in the RGN file - * for this sub-division. + * @return Estimates of the max size that will be needed in the RGN file + * for the points/lines/shapes in this sub-division. */ - public int[] getSizeAtResolution(int res) { - int[] sizes = new int[3]; - - for (int i = 0; i <= res; i++) { - sizes[POINT_KIND] += pointSize[i]; - sizes[LINE_KIND] += lineSize[i]; - sizes[SHAPE_KIND] += shapeSize[i]; - } - + public int[] getEstimatedSizes() { return sizes; } @@ -383,65 +372,64 @@ public class MapArea implements MapDataSource { * * @param p The element containing the minimum resolution that it will be * displayed at. - * @param sizes An array of sizes, this routine updates the correct one. * @param kind What kind of element this is KIND_POINT etc. */ - private void addSize(MapElement p, int[] sizes, int kind) { - - if(p.hasExtendedType()) { - // not applicable for elements with extended types - return; - } + private void addSize(MapElement p, int kind) { int res = p.getMinResolution(); if (res > MAX_RESOLUTION) return; - int s; int numPoints; int numElements; switch (kind) { case POINT_KIND: - if (res <= areaResolution) { - if(((MapPoint) p).isCity()) - nActiveIndPoints++; - else - nActivePoints++; + case XT_POINT_KIND: + if(res <= areaResolution) { + // Points are predictibly less than 9 bytes. + sizes[kind] += 9; + if(!p.hasExtendedType()) { + if(((MapPoint) p).isCity()) + nActiveIndPoints++; + else + nActivePoints++; + } } - - // Points are predictibly less than 9 bytes. - s = 9; break; case LINE_KIND: - // Estimate the size taken by lines and shapes as a constant plus - // a factor based on the number of points. - numPoints = ((MapLine) p).getPoints().size(); - numElements = 1 + ((numPoints - 1) / LineSplitterFilter.MAX_POINTS_IN_LINE); - s = numElements * 11 + numPoints * 4; - if (res <= areaResolution) - nActiveLines += numElements; + case XT_LINE_KIND: + if(res <= areaResolution) { + // Estimate the size taken by lines and shapes as a constant plus + // a factor based on the number of points. + numPoints = ((MapLine) p).getPoints().size(); + numElements = 1 + ((numPoints - 1) / LineSplitterFilter.MAX_POINTS_IN_LINE); + sizes[kind] += numElements * 11 + numPoints * 4; + if (!p.hasExtendedType()) + nActiveLines += numElements; + } break; + case SHAPE_KIND: - // Estimate the size taken by lines and shapes as a constant plus - // a factor based on the number of points. - numPoints = ((MapLine) p).getPoints().size(); - numElements = 1 + ((numPoints - 1) / PolygonSplitterFilter.MAX_POINT_IN_ELEMENT); - s = numElements * 11 + numPoints * 4; - if (res <= areaResolution) - nActiveShapes += numElements; + case XT_SHAPE_KIND: + if(res <= areaResolution) { + // Estimate the size taken by lines and shapes as a constant plus + // a factor based on the number of points. + numPoints = ((MapLine) p).getPoints().size(); + numElements = 1 + ((numPoints - 1) / PolygonSplitterFilter.MAX_POINT_IN_ELEMENT); + sizes[kind] += numElements * 11 + numPoints * 4; + if (!p.hasExtendedType()) + nActiveShapes += numElements; + } break; default: log.error("should not be here"); assert false; - s = 0; break; } - sizes[res] += s; - elemCounts[res]++; } /** @@ -452,7 +440,7 @@ public class MapArea implements MapDataSource { private void addPoint(MapPoint p) { points.add(p); addToBounds(p.getBounds()); - addSize(p, pointSize, POINT_KIND); + addSize(p, p.hasExtendedType()? XT_POINT_KIND : POINT_KIND); } /** @@ -463,7 +451,7 @@ public class MapArea implements MapDataSource { private void addLine(MapLine l) { lines.add(l); addToBounds(l.getBounds()); - addSize(l, lineSize, LINE_KIND); + addSize(l, l.hasExtendedType()? XT_LINE_KIND : LINE_KIND); } /** @@ -474,7 +462,7 @@ public class MapArea implements MapDataSource { private void addShape(MapShape s) { shapes.add(s); addToBounds(s.getBounds()); - addSize(s, shapeSize, SHAPE_KIND); + addSize(s, s.hasExtendedType()? XT_SHAPE_KIND : SHAPE_KIND); } /** diff --git a/src/uk/me/parabola/mkgmap/build/MapSplitter.java b/src/uk/me/parabola/mkgmap/build/MapSplitter.java index 0032307..3796507 100644 --- a/src/uk/me/parabola/mkgmap/build/MapSplitter.java +++ b/src/uk/me/parabola/mkgmap/build/MapSplitter.java @@ -52,6 +52,11 @@ class MapSplitter { private static final int MAX_NUM_POINTS = 0xff; + // maximum allowed amounts of points/lines/shapes with extended types + private static final int MAX_XT_POINTS_SIZE = 0x8000; + private static final int MAX_XT_LINES_SIZE = 0x8000; + private static final int MAX_XT_SHAPES_SIZE = 0x8000; + private final Zoom zoom; /** @@ -110,7 +115,7 @@ class MapSplitter { int res = zoom.getResolution(); for (MapArea area : areas) { Area bounds = area.getBounds(); - int[] sizes = area.getSizeAtResolution(res); + int[] sizes = area.getEstimatedSizes(); if(log.isInfoEnabled()) { String padding = depth + " "; log.info(padding.substring(0, (depth + 1) * 2) + @@ -126,7 +131,10 @@ class MapSplitter { (sizes[MapArea.POINT_KIND] > MAX_RGN_SIZE && (area.hasIndPoints() || area.hasLines() || area.hasShapes())) || (((sizes[MapArea.POINT_KIND] + sizes[MapArea.LINE_KIND]) > MAX_RGN_SIZE) && - area.hasShapes())) { + area.hasShapes()) || + sizes[MapArea.XT_POINT_KIND] > MAX_XT_POINTS_SIZE || + sizes[MapArea.XT_LINE_KIND] > MAX_XT_LINES_SIZE || + sizes[MapArea.XT_SHAPE_KIND] > MAX_XT_SHAPES_SIZE) { if (area.getBounds().getMaxDimention() > 100) { if (log.isDebugEnabled()) log.debug("splitting area", area);
_______________________________________________ mkgmap-dev mailing list mkgmap-dev@lists.mkgmap.org.uk http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev