Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (revision 1952) +++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (working copy) @@ -3,6 +3,7 @@ import java.awt.*; import java.awt.geom.Area; import java.awt.geom.Line2D; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; @@ -324,11 +325,8 @@ * a list of ways */ private void closeWays(ArrayList wayList) { - // this is a VERY simple algorithm to close the ways - // need to be improved - for (JoinedWay way : wayList) { - if (way.isClosed() || way.getPoints().size() <= 3) { + if (way.isClosed() || way.getPoints().size() < 3) { continue; } Coord p1 = way.getPoints().get(0); @@ -424,6 +422,93 @@ } } } + + private boolean connectUnclosedWays(List allWays) { + List unclosed = new ArrayList(); + + for (JoinedWay w : allWays) { + if (w.isClosed() == false) { + unclosed.add(w); + } + } + // try to connect ways lying outside or on the bbox + if (unclosed.size() >= 2) { + log.debug("Checking",unclosed.size(),"unclosed ways for connections outside the bbox"); + Map outOfBboxPoints = new HashMap(); + + // check all ways for endpoints outside or on the bbox + for (JoinedWay w : unclosed) { + Coord c1 = w.getPoints().get(0); + if (bbox.insideBoundary(c1)==false) { + log.debug("Point",c1,"of way",w.getId(),"outside bbox"); + outOfBboxPoints.put(c1, w); + } + + Coord c2 = w.getPoints().get(w.getPoints().size()-1); + if (bbox.insideBoundary(c2)==false) { + log.debug("Point",c2,"of way",w.getId(),"outside bbox"); + outOfBboxPoints.put(c2, w); + } + } + + if (outOfBboxPoints.size() < 2) { + log.debug(outOfBboxPoints.size(),"point outside the bbox. No connection possible."); + return false; + } + + List> coordPairs = new ArrayList>(); + ArrayList coords = new ArrayList(outOfBboxPoints.keySet()); + for (int i = 0; i < coords.size(); i++) { + for (int j = i + 1; j < coords.size(); j++) { + Coord c1 = coords.get(i); + Coord c2 = coords.get(j); + if (lineCutsBbox(c1, c2) == false) { + coordPairs.add(new AbstractMap.SimpleEntry( + c1, c2)); + } + } + } + + // sort the point pairs by distance + Collections.sort(coordPairs, new Comparator>() { + public int compare(Entry o1, + Entry o2) { + double d1 = o1.getKey().distance(o1.getValue()); + double d2 = o2.getKey().distance(o2.getValue()); + return Double.compare(d1, d2); + } + }); + + if (coordPairs.isEmpty()) { + log.debug("All potential connections cross the bbox. No connection possible."); + } else { + Entry closestGap = coordPairs.get(0); + + JoinedWay w1 = outOfBboxPoints.get(closestGap.getKey()); + JoinedWay w2 = outOfBboxPoints.get(closestGap.getValue()); + log.debug("Connect", w1, "with", w2); + + if (w1 == w2) { + log.error("Cannot connect the a way to itself "+w1); + } else { + + if (w1.getPoints().get(0).equals(closestGap.getKey())) { + Collections.reverse(w1.getPoints()); + } + if (w2.getPoints().get(0).equals(closestGap.getValue()) == false) { + Collections.reverse(w2.getPoints()); + } + + w1.getPoints().addAll(w2.getPoints()); + w1.addWay(w2); + allWays.remove(w2); + return true; + } + } + + } + return false; + } /** * Removes all ways non closed ways from the given list ( @@ -619,6 +704,10 @@ outerTags = new HashMap(); closeWays(polygons); + + while (connectUnclosedWays(polygons)) { + closeWays(polygons); + } removeUnclosedWays(polygons); // now only closed ways are left => polygons only