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