v1 suffered from the problem that ways were connected over the bbox edge. Now connections with minimum distance are preferred no matter if a way is closed to a polygon or if a way is joined to another unclosed way.

WanMil

The patch connects unclosed ways out of the bounding box. In some
situation this fixes a problem with multipolygons that are larger that
the tile.

WanMil

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)
@@ -324,11 +324,8 @@
         *            a list of ways
         */
        private void closeWays(ArrayList<JoinedWay> 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);
@@ -356,38 +353,6 @@
                                                        "are both outside the 
bbox. Closing it directly.");
                                        continue;
                                }
-
-                               
-                               // Check if the way can be closed with one 
additional point
-                               // outside the bounding box.
-                               // The additional point is combination of the 
coords of both endpoints.
-                               // It works if the lines from the endpoints to 
the additional point does
-                               // not cut the bounding box.
-                               // This can be removed when the splitter 
guarantees to provide logical complete
-                               // multi-polygons.
-                               Coord edgePoint1 = new Coord(p1.getLatitude(), 
p2
-                                               .getLongitude());
-                               Coord edgePoint2 = new Coord(p2.getLatitude(), 
p1
-                                               .getLongitude());
-
-                               if (lineCutsBbox(p1, edgePoint1) == false
-                                               && lineCutsBbox(edgePoint1, p2) 
== false) {
-                                       way.addPoint(edgePoint1);
-                                       way.closeWayArtificially();
-                                       log.info("Endpoints of way", way,
-                                                       "are both outside the 
bbox. Add point", edgePoint1,
-                                                       "and close it.");
-                                       continue;
-                               }
-                               if (lineCutsBbox(p1, edgePoint2) == false
-                                               && lineCutsBbox(edgePoint2, p2) 
== false) {
-                                       way.addPoint(edgePoint2);
-                                       way.closeWayArtificially();
-                                       log.info("Endpoints of way", way,
-                                                       "are both outside the 
bbox. Add point", edgePoint2,
-                                                       "and close it.");
-                                       continue;
-                               }
                        }
                        
                        Line2D closingLine = new 
Line2D.Float(p1.getLongitude(), p1
@@ -424,6 +389,129 @@
                        }
                }
        }
+       
+       private static class ConnectionData {
+               public Coord c1;
+               public Coord c2;
+               public JoinedWay w1;
+               public JoinedWay w2;
+               // sometimes the connection of both points cannot be done 
directly but with an intermediate point 
+               public Coord imC;
+               public double distance;
+       }
+       
+       private boolean connectUnclosedWays(List<JoinedWay> allWays) {
+               List<JoinedWay> unclosed = new ArrayList<JoinedWay>();
+
+               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<Coord, JoinedWay> outOfBboxPoints = new 
HashMap<Coord, JoinedWay>();
+                       
+                       // 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<ConnectionData> coordPairs = new 
ArrayList<ConnectionData>();
+                       ArrayList<Coord> coords = new 
ArrayList<Coord>(outOfBboxPoints.keySet());
+                       for (int i = 0; i < coords.size(); i++) {
+                               for (int j = i + 1; j < coords.size(); j++) {
+                                       ConnectionData cd = new 
ConnectionData();
+                                       cd.c1 = coords.get(i);
+                                       cd.c2 = coords.get(j);
+                                       cd.w1 = outOfBboxPoints.get(cd.c1);     
                                
+                                       cd.w2 = outOfBboxPoints.get(cd.c2);     
                                
+                                       
+                                       if (lineCutsBbox(cd.c1, cd.c2 )) {
+                                               // Check if the way can be 
closed with one additional point
+                                               // outside the bounding box.
+                                               // The additional point is 
combination of the coords of both endpoints.
+                                               // It works if the lines from 
the endpoints to the additional point does
+                                               // not cut the bounding box.
+                                               // This can be removed when the 
splitter guarantees to provide logical complete
+                                               // multi-polygons.
+                                               Coord edgePoint1 = new 
Coord(cd.c1.getLatitude(), cd.c2
+                                                               
.getLongitude());
+                                               Coord edgePoint2 = new 
Coord(cd.c2.getLatitude(), cd.c1
+                                                               
.getLongitude());
+
+                                               if (lineCutsBbox(cd.c1, 
edgePoint1) == false
+                                                               && 
lineCutsBbox(edgePoint1, cd.c2) == false) {
+                                                       cd.imC = edgePoint1;
+                                               } else if (lineCutsBbox(cd.c1, 
edgePoint2) == false
+                                                               && 
lineCutsBbox(edgePoint2, cd.c2) == false) {
+                                                       cd.imC = edgePoint1;
+                                               } else {
+                                                       // both endpoints are 
on opposite sides of the bounding box
+                                                       // automatically 
closing such points would create wrong polygons in most cases
+                                                       continue;
+                                               }
+                                               cd.distance = 
cd.c1.distance(cd.imC) + cd.imC.distance(cd.c2);
+                                       } else {
+                                               cd.distance = 
cd.c1.distance(cd.c2);
+                                       }
+                                       coordPairs.add(cd);
+                               }
+                       }
+                       
+                       if (coordPairs.isEmpty()) {
+                               log.debug("All potential connections cross the 
bbox. No connection possible.");
+                               return false;
+                       } else {
+                               // retrieve the connection with the minimum 
distance
+                               ConnectionData minCon = 
Collections.min(coordPairs,
+                                               new 
Comparator<ConnectionData>() {
+                                                       public int 
compare(ConnectionData o1,
+                                                                       
ConnectionData o2) {
+                                                               return 
Double.compare(o1.distance, o2.distance);
+                                                       }
+                                               });
+
+                               if (minCon.w1 == minCon.w2) {
+                                       log.debug("Close a gap in 
way",minCon.w1);
+                                       if (minCon.imC != null)
+                                               
minCon.w1.getPoints().add(minCon.imC);
+                                       minCon.w1.closeWayArtificially();
+                               } else {
+                                       log.debug("Connect", minCon.w1, "with", 
minCon.w2);
+
+                                       if 
(minCon.w1.getPoints().get(0).equals(minCon.c1)) {
+                                               
Collections.reverse(minCon.w1.getPoints());
+                                       }
+                                       if 
(minCon.w2.getPoints().get(0).equals(minCon.c2) == false) {
+                                               
Collections.reverse(minCon.w2.getPoints());
+                                       }
+
+                                       
minCon.w1.getPoints().addAll(minCon.w2.getPoints());
+                                       minCon.w1.addWay(minCon.w2);
+                                       allWays.remove(minCon.w2);
+                                       return true;
+                               }
+                       }
+               }
+               return false;
+       }
 
        /**
         * Removes all ways non closed ways from the given list (
@@ -619,6 +707,10 @@
                outerTags = new HashMap<String,String>();
                
                closeWays(polygons);
+               
+               while (connectUnclosedWays(polygons)) {
+                       closeWays(polygons);
+               }
                removeUnclosedWays(polygons);
 
                // now only closed ways are left => polygons only
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to