Hello,

Fix to my previous post: if a background polygon was over the node limit (255), 
it was truncated. I have addedDouglasPeuckerFilter to TdbBuilder to simplify 
the shape. MaximumPointsFilter class automatically increases maximum error 
distance of DouglasPeuckerFilter until node count fits to the limit. If it's 
not possible, bounding rectangle is used on the overview map.

András
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java
--- src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java	2011-01-15 11:26:01.000000000 +0100
+++ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java	2011-03-06 16:43:09.857759000 +0100
@@ -34,6 +34,8 @@
 import uk.me.parabola.mkgmap.general.MapShape;
 import uk.me.parabola.tdbfmt.DetailMapBlock;
 import uk.me.parabola.tdbfmt.TdbFile;
+import uk.me.parabola.mkgmap.main.Main;
+import uk.me.parabola.mkgmap.filters.DouglasPeuckerFilter;
 
 /**
  * Build the TDB file and the overview map.
@@ -153,6 +155,26 @@
 	 * @param finfo Information about an individual map.
 	 */
 	private void addToOverviewMap(FileInfo finfo) {
+
+		// check if this img has a background shape
+		MapShape bg = Main.backgrounds.get(finfo.getFilename());
+		if (bg != null) {
+			// simplify to fit in a Garmin polyline
+			MaximumPointsFilter filter = new MaximumPointsFilter(250);
+			if (!filter.applyFilter(bg.getPoints())) bg = null;
+		}
+
+		// check if simplification succeeded
+		if (bg != null) {
+
+			// use custom background
+			Area bbox = bg.getBounds();
+			overviewSource.addToBounds(new Coord(bbox.getMinLat(), bbox.getMinLong()));
+			overviewSource.addToBounds(new Coord(bbox.getMaxLat(), bbox.getMaxLong()));
+
+		} else {
+
+			// create a rectangle of bounds
 		Area bounds = finfo.getBounds();
 
 		//System.out.printf("overview shift %d\n", overviewSource.getShift());
@@ -196,9 +218,11 @@
 		points.add(start);
 
 		// Create the background rectangle
-		MapShape bg = new MapShape();
-		bg.setType(0x4a);
+			bg = new MapShape();
 		bg.setPoints(points);
+		}
+
+		bg.setType(0x4a);
 		bg.setMinResolution(10);
 		bg.setName(finfo.getDescription() + '\u001d' + finfo.getMapname());
 
@@ -271,4 +295,78 @@
 	public void setOverviewSource(OverviewMap overviewSource) {
 		this.overviewSource = overviewSource;
 	}
+
+	/**
+	 * DouglasPeuckerFilter with incrementing allowed error
+	 *
+	 * starts from minError
+	 * this value is multiplied with stepMultiplication and incremented with stepAddition
+	 * until point count is below treshold
+	 * or maxError is reached
+	 * or maxSteps is reached
+	 */
+
+	private class MaximumPointsFilter extends DouglasPeuckerFilter {
+
+		private int maxPoints;
+		private int maxSteps;
+		private double minError;
+		private double maxError;
+		private double stepAddition;
+		private double stepMultiplication;
+		private double finalError;
+		private int finalSteps;
+
+		MaximumPointsFilter(int maxPoints) {
+			super(0);
+			this.maxPoints = maxPoints;
+			minError = 1.0;
+			maxError = 10000.0;
+			stepAddition = 0.0;
+			stepMultiplication = 2.0;
+			maxSteps = 20;
+		}
+
+		void setMaxSteps (int maxSteps) {
+			this.maxSteps = maxSteps;
+		}
+
+		void setMinError (double minError) {
+			this.minError = minError;
+		}
+
+		void setMaxError (double maxError) {
+			this.maxError = maxError;
+		}
+
+		void setStepAddidion (double stepAddition) {
+			this.stepAddition = stepAddition;
+		}
+
+		void setStepMultiplication (double stepMultiplication) {
+			this.stepMultiplication = stepMultiplication;
+		}
+
+		double getFinalError () {
+			return finalError;
+		}
+
+		int getFinalSteps () {
+			return finalSteps;
+		}
+
+		boolean applyFilter(List<Coord> points) {
+			double curError = minError;
+			int curStep = 0;
+			while (points.size()>maxPoints && curError<maxError && curStep<maxSteps) {
+				finalError = curError;
+				finalSteps = curStep;
+				douglasPeucker(points, 0, points.size()-1, curError);
+				curError *= stepMultiplication;
+				curError += stepAddition;
+				curStep++;
+			}
+			return !(points.size()>maxPoints);
+		}
+	}
 }
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java
--- src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java	2010-12-20 21:31:30.000000000 +0100
+++ src/uk/me/parabola/mkgmap/general/LoadableMapDataSource.java	2011-03-06 11:29:45.984776000 +0100
@@ -88,4 +88,14 @@
 	 */
 	public String[] copyrightMessages();
 
+	/**
+	 * Gets background polygon shape.
+	 * Filled by MapDetails.addShape() with Type=0x4b polygons.
+	 * Used by MapMaker which stores this in Main.backgrounds.
+	 * Later used by TdbBuilder for overview map.
+	 *
+	 * @return MapShape
+	 */
+	public MapShape getBackground();
+
 }
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/general/MapDetails.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/general/MapDetails.java
--- src/uk/me/parabola/mkgmap/general/MapDetails.java	2010-02-18 21:39:57.000000000 +0100
+++ src/uk/me/parabola/mkgmap/general/MapDetails.java	2011-03-06 11:32:54.551698000 +0100
@@ -30,6 +30,7 @@
 import uk.me.parabola.imgfmt.app.trergn.PolygonOverview;
 import uk.me.parabola.imgfmt.app.trergn.PolylineOverview;
 import uk.me.parabola.util.EnhancedProperties;
+import uk.me.parabola.mkgmap.main.Main;
 
 /**
  * The map features that we are going to map are collected here.
@@ -41,6 +42,9 @@
 	private final List<MapShape> shapes = new ArrayList<MapShape>();
 	private final List<MapPoint> points = new ArrayList<MapPoint>();
 
+	// Background polygon shape
+	public MapShape background;
+
 	private int minLat = Utils.toMapUnit(180.0);
 	private int minLon = Utils.toMapUnit(180.0);
 	private int maxLat = Utils.toMapUnit(-180.0);
@@ -104,8 +108,12 @@
 			type = shape.getType();
 		else
 			type = shape.getType() << 8;
-		if (type != 0x4b00)
+		if (type != 0x4b00) {
 			updateOverview(shapeOverviews, type, shape.getMinResolution());
+		} else {
+			// store background polygon for overview map
+			background = shape;
+		}
 
 		shapes.add(shape);
 	}
@@ -204,4 +212,8 @@
 		if (prev == null || minResolution < prev)
 			overviews.put(type, minResolution);
 	}
+
+	public MapShape getBackground () {
+		return background;
+	}
 }
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/main/Main.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/main/Main.java
--- src/uk/me/parabola/mkgmap/main/Main.java	2010-09-24 21:13:42.000000000 +0200
+++ src/uk/me/parabola/mkgmap/main/Main.java	2011-03-06 11:40:09.707234000 +0100
@@ -58,6 +58,7 @@
 import uk.me.parabola.mkgmap.reader.osm.Style;
 import uk.me.parabola.mkgmap.reader.osm.StyleInfo;
 import uk.me.parabola.mkgmap.reader.overview.OverviewMapDataSource;
+import uk.me.parabola.mkgmap.general.MapShape;
 
 /**
  * The new main program.  There can be many file names to process and there can
@@ -75,6 +76,10 @@
 	private final List<Combiner> combiners = new ArrayList<Combiner>();
 
 	private final Map<String, MapProcessor> processMap = new HashMap<String, MapProcessor>();
+
+	// background polygons for maps
+	public static Map<String, MapShape> backgrounds = new HashMap<String, MapShape>();
+
 	private String styleFile = "classpath:styles";
 	private boolean verbose;
 
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/main/MapMaker.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/main/MapMaker.java
--- src/uk/me/parabola/mkgmap/main/MapMaker.java	2010-12-21 20:32:55.000000000 +0100
+++ src/uk/me/parabola/mkgmap/main/MapMaker.java	2011-03-06 11:04:01.055801000 +0100
@@ -42,6 +42,7 @@
 import uk.me.parabola.mkgmap.general.MapShape;
 import uk.me.parabola.mkgmap.reader.plugin.MapReader;
 import uk.me.parabola.util.Sortable;
+import uk.me.parabola.mkgmap.reader.MapperBasedMapDataSource;
 
 /**
  * Main routine for the command line map-making utility.
@@ -98,6 +99,10 @@
 
 			// Collect information on map complete.
 			String outName = map.getFilename();
+
+			// store background polygon for the filename
+			Main.backgrounds.put(outName, src.getBackground());
+
 			log.info("finished making map", outName, "closing");
 			map.close();
 			return outName;
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java
--- src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java	2010-02-02 11:24:13.000000000 +0100
+++ src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java	2011-03-06 11:41:05.394692000 +0100
@@ -84,6 +84,10 @@
 		return mapper.getOverviews();
 	}
 
+	public MapShape getBackground() {
+		return mapper.getBackground();
+	}
+
 	public List<MapPoint> getPoints() {
 		return mapper.getPoints();
 	}
diff -uNrb mkgmap-r1846-0221/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java mkgmap-r1846-mod/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
--- src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java	2010-02-18 21:39:57.000000000 +0100
+++ src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java	2011-03-06 10:24:50.702588000 +0100
@@ -70,12 +70,21 @@
 		// We use one level of zoom for the overview map and it has a level
 		// that is greater than that of the maps that go to make it up.
 		// (An extra invisible level will be added as always).
+
 		LevelInfo info = new LevelInfo(topLevel + 1, topBits - 1);
 
 		LevelInfo[] levels = new LevelInfo[1];
 		levels[0] = info;
 
-		return levels;
+		// overriding levels with custom settings
+		LevelInfo[] levels_custom = new LevelInfo[] {
+				new LevelInfo(6, 18),
+				new LevelInfo(5, 20),
+				new LevelInfo(4, 22),
+				new LevelInfo(3, 24),
+		};
+
+		return levels_custom;
 	}
 
 	/**

_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to