Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (revision 1471) +++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (working copy) @@ -1,8 +1,10 @@ package uk.me.parabola.mkgmap.reader.osm; import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.geom.Area; import java.awt.geom.Line2D; -import java.util.AbstractMap; +import java.awt.geom.PathIterator; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -26,8 +28,6 @@ private static final Logger log = Logger .getLogger(MultiPolygonRelation.class); - // private final List outerSegments = new ArrayList(); - // private final List innerSegments = new ArrayList(); private final Map myWayMap; private final ArrayList containsMatrix = new ArrayList(); @@ -54,25 +54,26 @@ public MultiPolygonRelation(Relation other, Map wayMap) { myWayMap = wayMap; setId(other.getId()); + for (Map.Entry pair : other.getElements()) { String role = pair.getKey(); Element el = pair.getValue(); addElement(role, el); - - // if (role != null && el instanceof Way) { - // Way way = (Way) el; - // if ("outer".equals(role)) { - // outerSegments.add(way); - // } else if ("inner".equals(role)) { - // innerSegments.add(way); - // } - // } } setName(other.getName()); copyTags(other); } + private String getRole(Element element) { + for (Map.Entry r_e : getElements()) { + if (r_e.getValue() == element) { + return r_e.getKey(); + } + } + return null; + } + /** * Combine a list of way segments to a list of maximally joined ways * @@ -80,7 +81,7 @@ * a list of closed or unclosed ways * @return a list of closed ways */ - private ArrayList joinWays(List> segments) { + private ArrayList joinWays(List segments) { // this method implements RA-1 to RA-4 // TODO check if the closed polygon is valid and implement a // backtracking algorithm to get other combinations @@ -93,14 +94,11 @@ // go through all segments and categorize them to closed and unclosed // list ArrayList unclosedWays = new ArrayList(); - for (Map.Entry orgSegment : segments) { - String role = orgSegment.getKey(); - Way way = orgSegment.getValue(); - - if (way.isClosed()) { - joinedWays.add(new JoinedWay(role, way)); + for (Way orgSegment : segments) { + if (orgSegment.isClosed()) { + joinedWays.add(new JoinedWay(orgSegment)); } else { - unclosedWays.add(new JoinedWay(role, way)); + unclosedWays.add(new JoinedWay(orgSegment)); } } @@ -127,7 +125,6 @@ continue; } - // TODO: compare roles too // use == or equals as comparator?? if (joinWay.getPoints().get(0) == tempWay.getPoints().get(0)) { for (Coord point : tempWay.getPoints().subList(1, @@ -208,11 +205,9 @@ log.warn("Unclosed polygons in multipolygon relation " + getId() + ":"); } - for (Map.Entry rw : tempWay.getOriginalRoleWays()) { - String role = rw.getKey(); - Way way = rw.getValue(); - log.warn(" - way:", way.getId(), "role:", role, - "osm:", way.toBrowseURL()); + for (Way orgWay : tempWay.getOriginalWays()) { + log.warn(" - way:", orgWay.getId(), "role:", + getRole(orgWay), "osm:", orgWay.toBrowseURL()); } it.remove(); @@ -277,19 +272,16 @@ * ways with the role "inner" to the way with the role "outer" */ public void processElements() { - ArrayList> allWays = - new ArrayList>(); - - for (Map.Entry r_el : getElements()) { - String role = r_el.getKey(); - Element element = r_el.getValue(); + // don't care about outer and inner declaration + // because this is a first + ArrayList allWays = new ArrayList(); - if (element instanceof Way) { - allWays.add(new AbstractMap.SimpleEntry - (role, (Way) element)); + for (Map.Entry r_e : getElements()) { + if (r_e.getValue() instanceof Way) { + allWays.add((Way) r_e.getValue()); } else { - log.warn("Non way element", element.getId(), "in multipolygon", - getId()); + log.warn("Non way element", r_e.getValue().getId(), + "in multipolygon", getId()); } } @@ -297,23 +289,6 @@ removeUnclosedWays(rings); // now we have closed ways == rings only - /* - * ===== start considering outer and inner ways ==== - * ArrayList joinedOuterWays = joinWays(outerWays); - * ArrayList joinedInnerWays = joinWays(innerWays); - * - * removeUnclosedWays(joinedOuterWays); - * removeUnclosedWays(joinedInnerWays); - * - * // at this point we don't care about outer and inner // in the end we - * will compare if outer and inner tags are matching // what we detect - * here and issue some warnings and errors ArrayList - * completeJoinedWays = new ArrayList(); - * completeJoinedWays.addAll(joinedOuterWays); - * completeJoinedWays.addAll(joinedInnerWays); ===== end considering - * outer and inner ways ==== - */ - // check if we have at least one ring left if (rings.isEmpty()) { // do nothing @@ -341,7 +316,7 @@ // QA: check that all ways carry the role "outer/inner" and // issue // warnings - checkRoles(currentRing.ring.getOriginalRoleWays(), + checkRoles(currentRing.ring.getOriginalWays(), (currentRing.outer ? "outer" : "inner")); // this ring is now processed and should not be used by any @@ -371,46 +346,44 @@ || hasUsefulTags(currentRing.ring); if (processRing) { - // now construct the ring polygon with its holes + + List innerWays = new ArrayList(holes.size()); for (RingStatus holeRingStatus : holes) { - int[] insert = findCpa(currentRing.ring.getPoints(), - holeRingStatus.ring.getPoints()); - if (insert[0] >= 0 && insert[1] >= 0) { - insertPoints(currentRing.ring, holeRingStatus.ring, - insert[0], insert[1]); + innerWays.add(holeRingStatus.ring); + } + + List singularOuterPolygons = processRing(currentRing.ring, + innerWays); + + // check if the original way has been changed + if (singularOuterPolygons.size() == 1 + && singularOuterPolygons.get(0) == currentRing.ring) { + if (currentRing.ring.getOriginalWays().size() == 1) { + singularOuterPolygons = Collections + .singletonList(currentRing.ring + .getOriginalWays().get(0)); } else { - // this must not happen - log.error("Cannot find cpa in multipolygon " - + toBrowseURL()); + singularOuterPolygons = Collections + .singletonList((Way) currentRing.ring); + currentRing.ring.removeOriginalTags(); } + } else { + // remove all tags so that the original way does not + // appear twice in the map + currentRing.ring.removeAllTagsDeep(); } boolean useRelationTags = currentRing.outer && hasUsefulTags(this); - if (useRelationTags) { // the multipolygon contains tags that overwhelm the - // tags - // out the outer ring - currentRing.ring.copyTags(this); - } else { - // the multipolygon does not contain any relevant tag - // use the segments of the ring and merge the tags - for (Map.Entry roleway : currentRing.ring.getOriginalRoleWays()) { - String role = roleway.getKey(); - Way ringSegment = roleway.getValue(); - // TODO uuh, this is bad => the last of the - // ring segments win - // => any better idea? - for (Map.Entry outSegmentTag : ringSegment - .getEntryIteratable()) { - currentRing.ring.addTag(outSegmentTag.getKey(), - outSegmentTag.getValue()); - } + // tags of the outer ring + for (Way p : singularOuterPolygons) { + p.copyTags(this); } } - polygonResults.add(currentRing.ring); + polygonResults.addAll(singularOuterPolygons); } } @@ -429,16 +402,220 @@ // the polygonResults contain all polygons that should be used in the // map - // TODO remove the input stuff? inner ways and outer segments? + log.warn(toBrowseURL()); + StringBuilder sb = new StringBuilder(); for (Way resultWay : polygonResults) { + sb.append("Way: " + resultWay.getId() + " Points: " + + resultWay.getPoints().size() + " Closed: " + + resultWay.isClosed() + " Tags: "); + for (Map.Entry entry : resultWay + .getEntryIteratable()) { + sb.append(entry.getKey() + "=" + entry.getValue() + "; "); + } + log.warn(sb.toString()); + sb.setLength(0); myWayMap.put(resultWay.getId(), resultWay); } } + private List processRing(Way outerWay, List innerWays) { + if (innerWays == null || innerWays.isEmpty()) { + return Collections.singletonList(outerWay); + } + // this list contains all non overlapping and singular areas + // of the outer way + List outerAreas = new ArrayList(); + + // 1st create an Area object of the outerWay and put it to the list + outerAreas.add(wayToArea(outerWay)); + + for (Way innerWay : innerWays) { + Area innerArea = wayToArea(innerWay); + + List outerAfterThisStep = new ArrayList(); + for (Area outerArea : outerAreas) { + // check if this outerArea is probably intersected by the inner area + // to save computation time in case it is not + if (outerArea.getBounds().createIntersection( + innerArea.getBounds()).isEmpty()) { + outerAfterThisStep.add(outerArea); + continue; + } + + // cut the hole + outerArea.subtract(innerArea); + if (outerArea.isEmpty()) { + // this outer area space can be abandoned + } else if (outerArea.isSingular()) { + // the area is singular + // => no further splits necessary + outerAfterThisStep.add(outerArea); + } else { + // 1st cut in two halfs in the middle of the inner area + + // Cut the bounding box into two rectangles + Rectangle r1; + Rectangle r2; + + // Get the bounds of this polygon + Rectangle innerBounds = innerArea.getBounds(); + Rectangle outerBounds = outerArea.getBounds(); + if (outerBounds.width > outerBounds.height) { + int cutWidth = (innerBounds.x - outerBounds.x) + + innerBounds.width / 2; + r1 = new Rectangle(outerBounds.x, outerBounds.y, + cutWidth, outerBounds.height); + r2 = new Rectangle(outerBounds.x + cutWidth, + outerBounds.y, outerBounds.width - cutWidth, + outerBounds.height); + } else { + int cutHeight = (innerBounds.y - outerBounds.y) + + innerBounds.height / 2; + r1 = new Rectangle(outerBounds.x, outerBounds.y, + outerBounds.width, cutHeight); + r2 = new Rectangle(outerBounds.x, outerBounds.y + + cutHeight, outerBounds.width, + outerBounds.height - cutHeight); + } + + // Now find the intersection of these two boxes with the + // original + // polygon. This will make two new areas, and each area will + // be one + // (or more) polygons. + Area a1 = outerArea; + Area a2 = (Area) a1.clone(); + a1.intersect(new Area(r1)); + a2.intersect(new Area(r2)); + + outerAfterThisStep.addAll(areaToSingularAreas(a1)); + outerAfterThisStep.addAll(areaToSingularAreas(a2)); + } + } + outerAreas = outerAfterThisStep; + } + + List outerWays = new ArrayList(outerAreas.size()); + for (Area area : outerAreas) { + Way w = singularAreaToWay(area, FakeIdGenerator.getFakeId()); + w.copyTags(outerWay); + outerWays.add(w); + } + + return outerWays; + } + + private List areaToSingularAreas(Area area) { + if (area.isEmpty()) { + return Collections.emptyList(); + } else if (area.isSingular()) { + return Collections.singletonList(area); + } else { + List singularAreas = new ArrayList(); + + // all ways in the area MUST define outer areas + // it is not possible that one of the areas define an inner segment + + float[] res = new float[6]; + PathIterator pit = area.getPathIterator(null); + float[] prevPoint = new float[6]; + + Polygon p = null; + while (!pit.isDone()) { + int type = pit.currentSegment(res); + + switch (type) { + case PathIterator.SEG_LINETO: + if (Arrays.equals(res, prevPoint) == false) { + p.addPoint(Math.round(res[0]), Math.round(res[1])); + } + break; + case PathIterator.SEG_CLOSE: + p.addPoint(p.xpoints[0], p.ypoints[0]); + Area a = new Area(p); + if (a.isEmpty() == false) { + singularAreas.add(a); + } + p = null; + break; + case PathIterator.SEG_MOVETO: + if (p != null) { + Area a2 = new Area(p); + if (a2.isEmpty() == false) { + singularAreas.add(a2); + } + } + p = new Polygon(); + p.addPoint(Math.round(res[0]), Math.round(res[1])); + break; + default: + log.warn(toBrowseURL(), "Unsupported path iterator type" + + type, ". This is an mkgmap error."); + } + + System.arraycopy(res, 0, prevPoint, 0, 6); + pit.next(); + } + return singularAreas; + } + } + + private Area wayToArea(Way way) { + Polygon polygon = new Polygon(); + for (Coord co : way.getPoints()) { + polygon.addPoint(co.getLongitude(), co.getLatitude()); + } + return new Area(polygon); + } + + private Way singularAreaToWay(Area area, long wayId) { + if (area.isSingular() == false) { + log + .warn( + "singularAreaToWay called with non singular area. Multipolygon ", + toBrowseURL()); + } + if (area.isEmpty()) { + log.warn("Empty area.", toBrowseURL()); + return null; + } + + Way w = null; + + float[] res = new float[6]; + PathIterator pit = area.getPathIterator(null); + + while (!pit.isDone()) { + int type = pit.currentSegment(res); + + // System.out.println("T" + type + " " + res[0] + "," + res[1] + " " + // + res[2] + "," + res[3] + " " + res[4] + "," + res[5]); + + switch (type) { + case PathIterator.SEG_MOVETO: + w = new Way(wayId); + w.addPoint(new Coord(Math.round(res[1]), Math.round(res[0]))); + break; + case PathIterator.SEG_LINETO: + w.addPoint(new Coord(Math.round(res[1]), Math.round(res[0]))); + break; + case PathIterator.SEG_CLOSE: + w.addPoint(w.getPoints().get(0)); + return w; + default: + log.warn(toBrowseURL(), + "Unsupported path iterator type" + type, + ". This is an mkgmap error."); + } + pit.next(); + } + return w; + } + private boolean hasUsefulTags(JoinedWay way) { - for (Map.Entry segment : way.getOriginalRoleWays()) { - if (hasUsefulTags(segment.getValue())) { + for (Way segment : way.getOriginalWays()) { + if (hasUsefulTags(segment)) { return true; } } @@ -461,14 +638,12 @@ * @param wayList * @param checkRole */ - private void checkRoles(List> wayList, - String checkRole) { + private void checkRoles(List wayList, String checkRole) { // QA: check that all ways carry the role "inner" and issue warnings - for (Map.Entry rw : wayList) { - String role = rw.getKey(); - Way way = rw.getValue(); - if (!checkRole.equals(role) == false) { - log.warn("Way", way.getId(), "carries role", role, + for (Way tempWay : wayList) { + String realRole = getRole(tempWay); + if (checkRole.equals(realRole) == false) { + log.warn("Way", tempWay.getId(), "carries role", realRole, "but should carry role", checkRole); } } @@ -499,9 +674,60 @@ } } } - } + // 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"); + // } + /** * Checks if the ring with ringIndex1 contains the ring with ringIndex2. * @@ -573,213 +799,63 @@ } /** - * Insert Coordinates into the outer way. - * - * @param outer - * the outer way - * @param inner - * Way to be inserted - * @param out - * Coordinates will be inserted after this point in the outer - * way. - * @param in - * Points will be inserted starting at this index, then from - * element 0 to (including) this element; + * This is a helper class that stores that gives access to the original + * segments of a joined way. */ - private void insertPoints(Way outer, Way inner, int out, int in) { - // TODO this algorithm may generate a self intersecting polygon - // because it does not consider the direction of both ways - // don't know if that's a problem - - List outList = outer.getPoints(); - List inList = inner.getPoints(); - int index = out + 1; - for (int i = in; i < inList.size(); i++) { - outList.add(index++, inList.get(i)); - } - for (int i = 0; i < in; i++) { - outList.add(index++, inList.get(i)); - } + private static class JoinedWay extends Way { + private final List originalWays; - // Investigate and see if we can do the first alternative here by - // changing the polygon splitter. If not then always do the alternative - // and remove unused code. - if (outer.getPoints().size() < 0 /* Always use alternative method for now */) { - outList.add(index++, inList.get(in)); - outList.add(index, outList.get(out)); - } else { - // we shift the nodes to avoid duplicate nodes (large areas only) - int oLat = outList.get(out).getLatitude(); - int oLon = outList.get(out).getLongitude(); - int iLat = inList.get(in).getLatitude(); - int iLon = inList.get(in).getLongitude(); - if (Math.abs(oLat - iLat) > Math.abs(oLon - iLon)) { - int delta = (oLon > iLon) ? -1 : 1; - outList.add(index++, new Coord(iLat + delta, iLon)); - outList.add(index, new Coord(oLat + delta, oLon)); - } else { - int delta = (oLat > iLat) ? 1 : -1; - outList.add(index++, new Coord(iLat, iLon + delta)); - outList.add(index, new Coord(oLat, oLon + delta)); - } + public JoinedWay(Way originalWay) { + super(FakeIdGenerator.getFakeId(), new ArrayList(originalWay + .getPoints())); + this.originalWays = new ArrayList(); + addWay(originalWay); } - } - private static final class DistIndex implements Comparable { - int index1; - int index2; - double distance; - - public DistIndex(int index1, int index2, double distance) { - super(); - this.index1 = index1; - this.index2 = index2; - this.distance = distance; + public void addPoint(int index, Coord point) { + getPoints().add(index, point); } - @Override - public int compareTo(DistIndex o) { - if (distance < o.distance) - return -1; - else if (distance > o.distance) { - return 1; + public void addWay(Way way) { + if (way instanceof JoinedWay) { + for (Way w : ((JoinedWay) way).getOriginalWays()) { + addWay(w); + } } else { - return 0; - } - } - } - - /** - * find the Closest Point of Approach between two coordinate-lists This will - * probably be moved to a Utils class. Note: works only if l2 lies into l1. - * - * @param l1 - * First list of points. - * @param l2 - * Second list of points. - * @return The first element is the index in l1, the second in l2 which are - * the closest together. - */ - private static int[] findCpa(List l1, List l2) { - // calculate and sort all distances first before - // to avoid the very costly calls of intersect - // Limit the size of this list to 500000 entries to - // avoid extreme memory consumption - int maxEntries = 500000; - ArrayList distList = new ArrayList(Math.min(l1 - .size() - * l2.size(), maxEntries)); - - DistIndex minDistance = null; - - int index1 = 0; - for (Coord c1 : l1) { - int index2 = 0; - for (Coord c2 : l2) { - double distance = c1.distanceInDegreesSquared(c2); - distList.add(new DistIndex(index1, index2, distance)); - index2++; - - if (distList.size() == maxEntries) { - Collections.sort(distList); - for (DistIndex newDistance : distList) { - if (minDistance == null - || minDistance.distance > newDistance.distance) { - // this is a new minimum - // test if a line between c1 and c2 intersects - // the outer polygon l1. - if (intersects(l1, l1.get(newDistance.index1), l2 - .get(newDistance.index2)) == false) { - minDistance = newDistance; - break; - } - } else { - break; - } - } - distList.clear(); + this.originalWays.add(way); + addTagsOf(way); + if (getName() == null && way.getName() != null) { + setName(way.getName()); } } - index1++; + log.debug("Joined", this.getId(), "with", way.getId()); } - Collections.sort(distList); - for (DistIndex newDistance : distList) { - if (minDistance == null - || minDistance.distance > newDistance.distance) { - // this is a new minimum - // test if a line between c1 and c2 intersects - // the outer polygon l1. - if (intersects(l1, l1.get(newDistance.index1), l2 - .get(newDistance.index2)) == false) { - minDistance = newDistance; - break; + private void addTagsOf(Way way) { + for (Map.Entry tag : way.getEntryIteratable()) { + if (getTag(tag.getKey()) == null) { + addTag(tag.getKey(), tag.getValue()); } - } else { - break; } } - if (minDistance == null) { - // this should not happen - return new int[] { -1, -1 }; - } else { - return new int[] { minDistance.index1, minDistance.index2 }; + public List getOriginalWays() { + return originalWays; } - } - - private static boolean intersects(List lc, Coord lp1, Coord lp2) { - Coord c11 = null; - Coord c12 = null; - for (Coord c : lc) { - c12 = c11; - c11 = c; - if (c12 == null) { - continue; - } - // in case the line intersects in a well known point this is not an - // inline intersection - if (c11.equals(lp1) || c11.equals(lp2) || c12.equals(lp1) - || c12.equals(lp2)) { - continue; - } - - if (Line2D.linesIntersect(c11.getLatitude(), c11.getLongitude(), - c12.getLatitude(), c12.getLongitude(), lp1.getLatitude(), - lp1.getLongitude(), lp2.getLatitude(), lp2.getLongitude())) { - return true; - } + public void removeAllTagsDeep() { + removeOriginalTags(); + removeAllTags(); } - return false; - } - /** - * This is a helper class that stores that gives access to the original - * segments of a joined way. - */ - private static class JoinedWay extends Way { - private final List> originalRoleWays; - - public JoinedWay(String role, Way originalWay) { - super(-originalWay.getId(), new ArrayList(originalWay - .getPoints())); - this.originalRoleWays = new ArrayList>(); - this.originalRoleWays.add(new AbstractMap.SimpleEntry - (role, originalWay)); - } - - public void addPoint(int index, Coord point) { - getPoints().add(index, point); - } - - public void addWay(JoinedWay way) { - originalRoleWays.addAll(way.originalRoleWays); - log.debug("Joined", this.getId(), "with", way.getId()); - } - - public List> getOriginalRoleWays() { - return originalRoleWays; + public void removeOriginalTags() { + for (Way w : getOriginalWays()) { + if (w instanceof JoinedWay) { + ((JoinedWay) w).removeAllTagsDeep(); + } else { + w.removeAllTags(); + } + } } } Index: src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java (revision 0) +++ src/uk/me/parabola/mkgmap/reader/osm/FakeIdGenerator.java (revision 0) @@ -0,0 +1,24 @@ +package uk.me.parabola.mkgmap.reader.osm; + +import java.util.concurrent.atomic.AtomicLong; + +public class FakeIdGenerator { + + public static final long START_ID = 1L << 62; + + private static final AtomicLong fakeId = new AtomicLong(START_ID); + + /** + * Retrieves a unique id that can be used to fake OSM ids. + * + * @return a unique id + */ + public static long getFakeId() { + return fakeId.incrementAndGet(); + } + + public static boolean isFakeId(long id) { + return id >= START_ID; + } + +} Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java =================================================================== --- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java (revision 1471) +++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java (working copy) @@ -46,6 +46,7 @@ import uk.me.parabola.mkgmap.general.RoadNetwork; import uk.me.parabola.mkgmap.reader.osm.CoordPOI; import uk.me.parabola.mkgmap.reader.osm.Element; +import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator; import uk.me.parabola.mkgmap.reader.osm.GeneralRelation; import uk.me.parabola.mkgmap.reader.osm.MultiPolygonRelation; import uk.me.parabola.mkgmap.reader.osm.Node; @@ -104,8 +105,6 @@ private Area bbox; private Runnable endTask; - private long nextFakeId = 1; - private final boolean reportUndefinedNodes; private final boolean makeOppositeCycleways; private final boolean makeCycleways; @@ -1053,7 +1052,7 @@ } public long makeFakeId() { - return (1L << 62) + nextFakeId++; + return FakeIdGenerator.getFakeId(); } private long idVal(String id) {