Firstly, I would like to thank everyone who responded to my
"Understanding the sea" post. From those posts and my own study, I
finally worked out what it does. And yes, it works pretty well inasmuch
that it generates some useful polygons. The "sea sector" heuristic
doesn't work for me so I have been disabling it.

v2 - avoid generating sea poly when unclipped tile contains coastline
but the clipped tile contains no coastline.

---------

The problem is, the end result is "butt ugly". Our MP implementation
really can't do a good job on zillions of little islands. 

After frigging around for a couple of days trying to improve the
visual quality, I tried the obvious alternative technique of not using
a MP but, instead, just having a sea background and then put the land
on top using plain polygons. Guess what? It works very nicely as the
attached pics show. I now have a splendid map of the Baltic area (OK
it's weird at the edges but that's not a problem for now).

Here's the (future) commit comment for this patch:

    Provide an alternative to using a multipolygon when generating the
    sea. 
    The --generate-sea option can now take a comma separated list of
    values: 
    no-mp - don't generate the sea using a multipolygon - instead,
    generate a background sea polygon and then individual land polygons
    with tag natural=land. This requires a suitable land polygon type
    to be defined in the style file (suggested type is 0x010100) and
    the polygon must be defined in the TYP file as having a higher
    drawing level than the sea polygon type.
    
    no-sea-sectors - disable the generation of "sea sectors" when the
    coastline fails to reach the tile's boundary.
    
    With no values specified, the --generate-sea option should work as
    before.

Oh yes, this patch doesn't include it, but I am also disabling the DP
code for polygons as it makes them weird.

Cheers and thanks again for the helpful postings.

Mark
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
index acc5cf9..b347ed6 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
@@ -111,6 +111,8 @@ class Osm5XmlHandler extends DefaultHandler {
 	private final boolean linkPOIsToWays;
 	private final boolean routing;
 	private final boolean generateSea;
+	private boolean generateSeaUsingMP = true;
+	private boolean allowSeaSectors = true;
 	private final Double minimumArcLength;
 	private final String frigRoundabouts;
 
@@ -126,7 +128,16 @@ class Osm5XmlHandler extends DefaultHandler {
 		}
 		linkPOIsToWays = props.getProperty("link-pois-to-ways", false);
 		ignoreBounds = props.getProperty("ignore-osm-bounds", false);
-		generateSea = props.getProperty("generate-sea", false);
+		String gs = props.getProperty("generate-sea", null);
+		generateSea = gs != null;
+		if(generateSea) {
+			for(String o : gs.split(",")) {
+				if("no-mp".equals(o))
+					generateSeaUsingMP = false;
+				else if("no-sea-sectors".equals(o))
+					allowSeaSectors = false;
+			}
+		}
 		routing = props.containsKey("route");
 		String rsa = props.getProperty("remove-short-arcs", null);
 		if(rsa != null)
@@ -465,8 +476,10 @@ class Osm5XmlHandler extends DefaultHandler {
 				if("motorway".equals(highway) ||
 				   "trunk".equals(highway))
 					motorways.add(currentWay);
-				if(generateSea && "coastline".equals(currentWay.getTag("natural")))
-				    shoreline.add(currentWay);
+				if(generateSea && "coastline".equals(currentWay.getTag("natural"))) {
+					currentWay.deleteTag("natural");
+					shoreline.add(currentWay);
+				}
 				currentNodeInWay = null;
 				currentWayStartsWithFIXME = false;
 				currentWay = null;
@@ -553,7 +566,7 @@ class Osm5XmlHandler extends DefaultHandler {
 
 		coordMap = null;
 
-		if (generateSea)
+		if (shoreline.size() > 0)
 		    generateSeaPolygon(shoreline);
 
 		for (Relation r : relationMap.values())
@@ -995,6 +1008,10 @@ class Osm5XmlHandler extends DefaultHandler {
 		super.fatalError(e);
 	}
 
+	public long makeFakeId() {
+		return (1L << 62) + nextFakeId++;
+	}
+
 	private long idVal(String id) {
 		try {
 			// attempt to parse id as a number
@@ -1004,7 +1021,7 @@ class Osm5XmlHandler extends DefaultHandler {
 			// if that fails, fake a (hopefully) unique value
 			Long fakeIdVal = fakeIdMap.get(id);
 			if(fakeIdVal == null) {
-				fakeIdVal = (1L << 62) + nextFakeId++;
+				fakeIdVal = makeFakeId();
 				fakeIdMap.put(id, fakeIdVal);
 			}
 			//System.out.printf("%s = 0x%016x\n", id, fakeIdVal);
@@ -1013,10 +1030,6 @@ class Osm5XmlHandler extends DefaultHandler {
 	}
 
 	private void generateSeaPolygon(List<Way> shoreline) {
-		// don't do anything if there is no shoreline
-		if (shoreline.isEmpty())
-			return;
-
 		Area seaBounds;
 		if (bbox != null)
 			seaBounds = bbox;
@@ -1033,7 +1046,7 @@ class Osm5XmlHandler extends DefaultHandler {
 				log.info("clipping " + segment);
 				toBeRemoved.add(segment);
 				for (List<Coord> pts : clipped) {
-					long id = (1L << 62) + nextFakeId++;
+					long id = makeFakeId();
 					Way shore = new Way(id, pts);
 					toBeAdded.add(shore);
 				}
@@ -1043,6 +1056,10 @@ class Osm5XmlHandler extends DefaultHandler {
 		shoreline.removeAll(toBeRemoved);
 		shoreline.addAll(toBeAdded);
 
+		// don't do anything if there is no shoreline
+		if (shoreline.isEmpty())
+			return;
+
 		log.info("generating sea, seaBounds=", seaBounds);
 		int minLat = seaBounds.getMinLat();
 		int maxLat = seaBounds.getMaxLat();
@@ -1053,9 +1070,12 @@ class Osm5XmlHandler extends DefaultHandler {
 		Coord sw = new Coord(maxLat, minLong);
 		Coord se = new Coord(maxLat, maxLong);
 
-		long multiId = (1L << 62) + nextFakeId++;
-		Relation seaRelation = new GeneralRelation(multiId);
-		seaRelation.addTag("type", "multipolygon");
+		long multiId = makeFakeId();
+		Relation seaRelation = null;
+		if(generateSeaUsingMP) {
+			seaRelation = new GeneralRelation(multiId);
+			seaRelation.addTag("type", "multipolygon");
+		}
 
 		List<Way> islands = new ArrayList<Way>();
 
@@ -1083,7 +1103,12 @@ class Osm5XmlHandler extends DefaultHandler {
 		// create a "inner" way for each island
 		for (Way w : islands) {
 			log.info("adding island " + w);
-			seaRelation.addElement("inner", w);
+			if(generateSeaUsingMP)
+				seaRelation.addElement("inner", w);
+			else {
+				w.addTag("natural", "land");
+				wayMap.put(w.getId(), w);
+			}
 		}
 
 		boolean generateSeaBackground = true;
@@ -1129,10 +1154,15 @@ class Osm5XmlHandler extends DefaultHandler {
 				if (nearlyClosed) {
 					// close the way
 					points.add(pStart);
-					seaRelation.addElement("inner", w);
+					if(generateSeaUsingMP)
+						seaRelation.addElement("inner", w);
+					else {
+						w.addTag("natural", "land");
+						wayMap.put(w.getId(), w);
+					}
 				}
-				else {
-					seaId = (1L << 62) + nextFakeId++;
+				else if(allowSeaSectors) {
+					seaId = makeFakeId();
 					sea = new Way(seaId);
 					sea.getPoints().addAll(points);
 					sea.addPoint(new Coord(pEnd.getLatitude(), pStart.getLongitude()));
@@ -1140,7 +1170,8 @@ class Osm5XmlHandler extends DefaultHandler {
 					sea.addTag("natural", "sea");
 					log.info("sea: ", sea);
 					wayMap.put(seaId, sea);
-					seaRelation.addElement("outer", sea);
+					if(generateSeaUsingMP)
+						seaRelation.addElement("outer", sea);
 					generateSeaBackground = false;
 				}
 			}
@@ -1151,7 +1182,7 @@ class Osm5XmlHandler extends DefaultHandler {
 			}
 		}
 		if (generateSeaBackground) {
-			seaId = (1L << 62) + nextFakeId++;
+			seaId = makeFakeId();
 			sea = new Way(seaId);
 			sea.addPoint(nw);
 			sea.addPoint(sw);
@@ -1161,13 +1192,14 @@ class Osm5XmlHandler extends DefaultHandler {
 			sea.addTag("natural", "sea");
 			log.info("sea: ", sea);
 			wayMap.put(seaId, sea);
-			seaRelation.addElement("outer", sea);
+			if(generateSeaUsingMP)
+				seaRelation.addElement("outer", sea);
 		}
 
 		// now construct inner ways from these segments
 		NavigableSet<EdgeHit> hits = (NavigableSet<EdgeHit>) hitMap.keySet();
 		while (!hits.isEmpty()) {
-			long id = (1L << 62) + nextFakeId++;
+			long id = makeFakeId();
 			Way w = new Way(id);
 			wayMap.put(id, w);
 
@@ -1224,12 +1256,19 @@ class Osm5XmlHandler extends DefaultHandler {
 				w.getPoints().add(w.getPoints().get(0));
 			log.info("adding non-island landmass, hits.size()=" + hits.size());
 			//w.addTag("highway", "motorway");
-			seaRelation.addElement("inner", w);
+			if(generateSeaUsingMP)
+				seaRelation.addElement("inner", w);
+			else {
+				w.addTag("natural", "land");
+				wayMap.put(w.getId(), w);
+			}
 		}
 
-		seaRelation = new MultiPolygonRelation(seaRelation, wayMap);
-		relationMap.put(multiId, seaRelation);
-		seaRelation.processElements();
+		if(generateSeaUsingMP) {
+			seaRelation = new MultiPolygonRelation(seaRelation, wayMap);
+			relationMap.put(multiId, seaRelation);
+			seaRelation.processElements();
+		}
 	}
 
 	/**
@@ -1346,11 +1385,12 @@ class Osm5XmlHandler extends DefaultHandler {
 					List<Coord> points2 = w2.getPoints();
 					Way wm;
 					if (w1.getId() < (1L << 62)) {
-						wm = new Way((1L << 62) + nextFakeId++);
+						wm = new Way(makeFakeId());
 						ways.remove(w1);
 						ways.add(wm);
 						wm.getPoints().addAll(points1);
 						beginMap.put(points1.get(0), wm);
+						wm.copyTags(w1);
 					}
 					else {
 						wm = w1;
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to