Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (revision 1502) +++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (working copy) @@ -1,6 +1,7 @@ package uk.me.parabola.mkgmap.reader.osm; -import java.awt.*; +import java.awt.Polygon; +import java.awt.Rectangle; import java.awt.geom.Area; import java.awt.geom.Line2D; import java.awt.geom.PathIterator; @@ -8,6 +9,7 @@ import java.util.Arrays; import java.util.BitSet; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -16,6 +18,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; +import sun.awt.image.IntegerComponentRaster; import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.log.Logger; @@ -337,7 +340,7 @@ log.info("from", way.getPoints().get(0).toOSMURL()); log.info("to", way.getPoints().get(way.getPoints().size() - 1) .toOSMURL()); - // mark this ways as artificially closed + // mark this ways as artifically closed way.closeWayArtificial(); } } @@ -357,8 +360,9 @@ JoinedWay tempWay = it.next(); if (tempWay.isClosed() == false) { if (first) { - log.warn( - "Cannot join the following ways to closed polygons. MP-Relation", + log + .warn( + "Cannot join the following ways to closed polygons. MP-Relation", toBrowseURL()); } logWayURLs(Level.WARNING, "- way:", tempWay); @@ -810,7 +814,9 @@ */ private Way singularAreaToWay(Area area, long wayId) { if (area.isSingular() == false) { - log.warn("singularAreaToWay called with non singular area. Multipolygon ", + log + .warn( + "singularAreaToWay called with non singular area. Multipolygon ", toBrowseURL()); } if (area.isEmpty()) { @@ -870,6 +876,9 @@ /** * This is a QA method. All ways of the given wayList are checked if they * they carry the checkRole. If not a warning is logged. + * + * @param wayList + * @param checkRole */ private void checkRoles(List wayList, String checkRole) { // QA: check that all ways carry the role "inner" and issue warnings @@ -886,28 +895,32 @@ * Creates a matrix which polygon contains which polygon. A polygon does not * contain itself. * - * @param poplygonList + * @param polygonList * a list of polygons */ - private void createContainsMatrix(List poplygonList) { + private void createContainsMatrix(List polygonList) { + if (polygonList.size() > 10) { + createContainsMatrixForBigLists(polygonList); + return; + } containsMatrix = new ArrayList(); - for (int i = 0; i < poplygonList.size(); i++) { + for (int i = 0; i < polygonList.size(); i++) { containsMatrix.add(new BitSet()); } // mark which ring contains which ring - for (int i = 0; i < poplygonList.size(); i++) { - JoinedWay tempRing = poplygonList.get(i); + for (int i = 0; i < polygonList.size(); i++) { + JoinedWay tempRing = polygonList.get(i); BitSet bitSet = containsMatrix.get(i); - for (int j = 0; j < poplygonList.size(); j++) { - boolean contains; + for (int j = 0; j < polygonList.size(); j++) { + boolean contains = false; if (i == j) { // this is special: a way does not contain itself for // our usage here contains = false; } else { - contains = contains(tempRing, poplygonList.get(j)); + contains = contains(tempRing, polygonList.get(j)); } if (contains) { @@ -928,57 +941,65 @@ * this is an alternative createContainsMatrix method seems to speed up only * if lots of inner ways are in the mulitpolygon */ - // private void createContainsMatrix(List wayList) { - // long t1 = System.currentTimeMillis(); - // - // for (int i = 0; i < wayList.size(); i++) { - // containsMatrix.add(new BitSet()); - // } - // - // // use this matrix to check which matrix element has been - // // calculated - // ArrayList finishedMatrix = new ArrayList(wayList.size()); - // - // for (int i = 0; i < wayList.size(); i++) { - // BitSet matrixRow = new BitSet(); - // // an element does not contain itself - // matrixRow.set(i); - // finishedMatrix.add(matrixRow); - // } - // - // for (int rowIndex = 0; rowIndex < wayList.size(); rowIndex++) { - // Way potentialOuterRing = wayList.get(rowIndex); - // BitSet containsColumns = containsMatrix.get(rowIndex); - // BitSet finishedCol = finishedMatrix.get(rowIndex); - // - // // get all non calculated columns of the matrix - // for (int colIndex = finishedCol.nextClearBit(0); colIndex >= 0 && - // colIndex < wayList.size(); colIndex = finishedCol - // .nextClearBit(colIndex + 1)) { - // - // boolean contains = contains(potentialOuterRing, wayList.get(colIndex)); - // - // if (contains) { - // containsColumns.set(colIndex); - // - // // we also know that the inner ring does not contain the outer ring - // // so we can set the finished bit for this matrix element - // finishedMatrix.get(colIndex).set(rowIndex); - // - // // additionally we know that the outer ring contains all rings - // // that are contained by the inner ring - // containsColumns.or(containsMatrix.get(colIndex)); - // finishedCol.or(containsColumns); - // } - // - // // this matrix element is calculated now - // finishedCol.set(colIndex); - // } - // } - // - // long t2 = System.currentTimeMillis(); - // log.warn("createMatrix",(t2-t1),"ms"); - // } + private void createContainsMatrixForBigLists(List wayList) { + long t1 = System.currentTimeMillis(); + + log.debug("createContainsMatrix listSize:",wayList.size()); + containsMatrix = new ArrayList(wayList.size()); + for (int i = 0; i < wayList.size(); i++) { + containsMatrix.add(new BitSet()); + } + + // use this matrix to check which matrix element has been + // calculated + ArrayList finishedMatrix = new ArrayList(wayList.size()); + + for (int i = 0; i < wayList.size(); i++) { + BitSet matrixRow = new BitSet(); + // an element does not contain itself + matrixRow.set(i); + finishedMatrix.add(matrixRow); + } + + for (int rowIndex = 0; rowIndex < wayList.size(); rowIndex++) { + JoinedWay potentialOuterRing = wayList.get(rowIndex); + BitSet containsColumns = containsMatrix.get(rowIndex); + BitSet finishedCol = finishedMatrix.get(rowIndex); + + log.debug("check polygon",rowIndex); + + + // get all non calculated columns of the matrix + for (int colIndex = finishedCol.nextClearBit(0); colIndex >= 0 + && colIndex < wayList.size(); colIndex = finishedCol + .nextClearBit(colIndex + 1)) { + + boolean contains = contains(potentialOuterRing, wayList + .get(colIndex)); + + if (contains) { + containsColumns.set(colIndex); + + // we also know that the inner ring does not contain the + // outer ring + // so we can set the finished bit for this matrix element + finishedMatrix.get(colIndex).set(rowIndex); + + // additionally we know that the outer ring contains all + // rings + // that are contained by the inner ring + containsColumns.or(containsMatrix.get(colIndex)); + finishedCol.or(containsColumns); + } + + // this matrix element is calculated now + finishedCol.set(colIndex); + } + } + + long t2 = System.currentTimeMillis(); + log.warn("createMatrix for", wayList.size(),"polygons took", (t2 - t1), "ms"); + } /** * Checks if the ring with ringIndex1 contains the ring with ringIndex2. @@ -994,7 +1015,7 @@ * * @param ring1 * a closed way - * @param ring2 A second closed way. + * @param ring2 * @return true if ring1 contains ring2 */ private boolean contains(JoinedWay ring1, JoinedWay ring2) { @@ -1012,26 +1033,57 @@ // way2 return false; } + // TODO check if p0 is on any of the lines of ring2 // check all lines of way1 and way2 for intersections Iterator it2 = ring2.getPoints().iterator(); Coord p2_1 = it2.next(); + Coord p2_2 = null; while (it2.hasNext()) { - Coord p2_2 = p2_1; + p2_2 = p2_1; p2_1 = it2.next(); + int lonMin = Math.min(p2_1.getLongitude(), p2_2.getLongitude()); + int lonMax = Math.max(p2_1.getLongitude(), p2_2.getLongitude()); + int latMin = Math.min(p2_1.getLatitude(), p2_2.getLatitude()); + int latMax = Math.max(p2_1.getLatitude(), p2_2.getLatitude()); +// Rectangle bbox2 = new Rectangle(lonMin, latMin, lonMax-lonMin, latMax-latMin); + Iterator it1 = ring1.getPoints().iterator(); Coord p1_1 = it1.next(); + Coord p1_2 = null; + + int lonStatus = p1_1.getLongitude() lonMax ? 1 : 0; + int latStatus = p1_1.getLatitude() latMax ? 1 : 0; + while (it1.hasNext()) { - Coord p1_2 = p1_1; + p1_2 = p1_1; p1_1 = it1.next(); - boolean intersects = Line2D.linesIntersect(p1_1.getLongitude(), + int changes = 0; + if (lonStatus < 0 && p1_1.getLongitude() < lonMin) { + } else if (lonStatus > 0 && p1_1.getLongitude() > lonMax) { + } else { + changes++; + lonStatus = p1_1.getLongitude() lonMax ? 1 : 0; + } + if (latStatus < 0 && p1_1.getLatitude() < latMin) { + } else if (latStatus > 0 && p1_1.getLatitude() > latMax) { + } else { + changes++; + latStatus = p1_1.getLatitude() latMax ? 1 : 0; + } + + boolean intersects = + ((lonStatus == 0 && latStatus==0) || changes == 2) + && Line2D.linesIntersect(p1_1.getLongitude(), p1_1.getLatitude(), p1_2.getLongitude(), p1_2 .getLatitude(), p2_1.getLongitude(), p2_1 .getLatitude(), p2_2.getLongitude(), p2_2 .getLatitude()); + // TODO check if one of the points only touches the other ring + if (intersects) { if ((ring1.isClosedArtificially() && it1.hasNext() == false) || (ring2.isClosedArtificially() && it2.hasNext() == false)) { @@ -1079,7 +1131,7 @@ */ private static class JoinedWay extends Way { private final List originalWays; - private boolean closedArtifical; + private boolean closedArtifical = false; public JoinedWay(Way originalWay) { super(FakeIdGenerator.makeFakeId(), new ArrayList( @@ -1145,6 +1197,7 @@ } } + @Override public String toString() { StringBuilder sb = new StringBuilder(200); sb.append(getId()); @@ -1175,6 +1228,7 @@ JoinedWay ring; public RingStatus(boolean outer, int index, JoinedWay ring) { + super(); this.outer = outer; this.index = index; this.ring = ring;