Attached you find a 4th patch (mp branch) to improve multipolygon
handling (don't bother about my counting - I haven't posted all patches ;-)
Changes:
* Inner and outer tags are now considered. The last patches
autogenerated the relationships which did make problems on tile
boundaries if the multipolygon wasn't contained completely .
* Simple closing algorithm of polygons if they are not closed. This
improves the handling on the tile boundaries.
* Improved tag handling
Please commit this to the mp branch. I will post another patch which is
ready for the trunk (less debug statements).
To all: please check this patch and post all problems.
WanMil
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 makeFakeId() {
+ return fakeId.incrementAndGet();
+ }
+
+ public static boolean isFakeId(long id) {
+ return id >= START_ID;
+ }
+
+}
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
(revision 1475)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
(working copy)
@@ -1,12 +1,15 @@
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;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -26,9 +29,11 @@
private static final Logger log = Logger
.getLogger(MultiPolygonRelation.class);
- // private final List<Way> outerSegments = new ArrayList<Way>();
- // private final List<Way> innerSegments = new ArrayList<Way>();
private final Map<Long, Way> myWayMap;
+ private final Map<Long, String> roleMap = new HashMap<Long, String>();
+
+ private final uk.me.parabola.imgfmt.app.Area bbox;
+ private final java.awt.geom.Area awtBbox;
private final ArrayList<BitSet> containsMatrix = new
ArrayList<BitSet>();
@@ -39,7 +44,7 @@
private ArrayList<JoinedWay> rings;
private static final List<String> relationTags =
Arrays.asList("boundary",
- "natural", "landuse", "building", "waterway");
+ "natural", "landuse", "land_area", "building",
"waterway");
/**
* Create an instance based on an existing relation. We need to do this
@@ -51,28 +56,108 @@
* @param wayMap
* Map of all ways.
*/
- public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap) {
+ public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap,
+ uk.me.parabola.imgfmt.app.Area bbox) {
myWayMap = wayMap;
+ this.bbox = bbox;
+
+ List<Coord> points = new ArrayList<Coord>(5);
+ points.add(new Coord(bbox.getMinLat(), bbox.getMinLong()));
+ points.add(new Coord(bbox.getMaxLat(), bbox.getMinLong()));
+ points.add(new Coord(bbox.getMaxLat(), bbox.getMaxLong()));
+ points.add(new Coord(bbox.getMinLat(), bbox.getMaxLong()));
+ points.add(new Coord(bbox.getMinLat(), bbox.getMinLong()));
+ awtBbox = createArea(points);
+
setId(other.getId());
+
for (Map.Entry<String, Element> pair : other.getElements()) {
String role = pair.getKey();
Element el = pair.getValue();
+ log.debug(" ", role, el.toBrowseURL());
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);
- // }
- // }
+ roleMap.put(el.getId(), role);
}
setName(other.getName());
copyTags(other);
}
+ private String getRole(Element element) {
+ String role = roleMap.get(element.getId());
+ if (role != null) {
+ return role;
+ }
+
+ for (Map.Entry<String, Element> r_e : getElements()) {
+ if (r_e.getValue() == element) {
+ return r_e.getKey();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Try to join the two ways.
+ *
+ * @param w1
+ * first way
+ * @param w2
+ * second way
+ * @param checkOnly
+ * <code>true</code> checks only and does not perform the
join
+ * operation
+ * @return <code>true</code> if w2 way (or could) be joined to w1
+ */
+ private boolean joinWays(JoinedWay joinWay, JoinedWay tempWay,
+ boolean checkOnly) {
+ // use == or equals as comparator??
+ if (joinWay.getPoints().get(0) == tempWay.getPoints().get(0)) {
+ if (checkOnly == false) {
+ for (Coord point :
tempWay.getPoints().subList(1,
+ tempWay.getPoints().size())) {
+ joinWay.addPoint(0, point);
+ }
+ joinWay.addWay(tempWay);
+ }
+ return true;
+ } else if (joinWay.getPoints().get(joinWay.getPoints().size() -
1) == tempWay
+ .getPoints().get(0)) {
+ if (checkOnly == false) {
+ for (Coord point :
tempWay.getPoints().subList(1,
+ tempWay.getPoints().size())) {
+ joinWay.addPoint(point);
+ }
+ joinWay.addWay(tempWay);
+ }
+ return true;
+ } else if (joinWay.getPoints().get(0) ==
tempWay.getPoints().get(
+ tempWay.getPoints().size() - 1)) {
+ if (checkOnly == false) {
+ int insertIndex = 0;
+ for (Coord point :
tempWay.getPoints().subList(0,
+ tempWay.getPoints().size() -
1)) {
+ joinWay.addPoint(insertIndex, point);
+ insertIndex++;
+ }
+ joinWay.addWay(tempWay);
+ }
+ return true;
+ } else if (joinWay.getPoints().get(joinWay.getPoints().size() -
1) == tempWay
+ .getPoints().get(tempWay.getPoints().size() -
1)) {
+ if (checkOnly == false) {
+ int insertIndex = joinWay.getPoints().size();
+ for (Coord point :
tempWay.getPoints().subList(0,
+ tempWay.getPoints().size() -
1)) {
+ joinWay.addPoint(insertIndex, point);
+ }
+ joinWay.addWay(tempWay);
+ }
+ return true;
+ }
+ return false;
+ }
+
/**
* Combine a list of way segments to a list of maximally joined ways
*
@@ -80,7 +165,7 @@
* a list of closed or unclosed ways
* @return a list of closed ways
*/
- private ArrayList<JoinedWay> joinWays(List<Map.Entry<String,Way>>
segments) {
+ private ArrayList<JoinedWay> joinWays(List<Way> 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 +178,13 @@
// go through all segments and categorize them to closed and
unclosed
// list
ArrayList<JoinedWay> unclosedWays = new ArrayList<JoinedWay>();
- for (Map.Entry<String,Way> orgSegment : segments) {
- String role = orgSegment.getKey();
- Way way = orgSegment.getValue();
-
- if (way.isClosed()) {
- joinedWays.add(new JoinedWay(role, way));
+ for (Way orgSegment : segments) {
+ JoinedWay jw = new JoinedWay(orgSegment);
+ roleMap.put(jw.getId(), getRole(orgSegment));
+ if (orgSegment.isClosed()) {
+ joinedWays.add(jw);
} else {
- unclosedWays.add(new JoinedWay(role, way));
+ unclosedWays.add(jw);
}
}
@@ -116,6 +200,11 @@
boolean joined = false;
+ // if we have a way that could be joined but which has
a wrong role
+ // then store it here and check in the end if it's
working
+ JoinedWay wrongRoleWay = null;
+ String joinRole = getRole(joinWay);
+
// go through all ways and check if there is a way that
can be
// joined with it
// in this case join the two ways
@@ -127,45 +216,47 @@
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,
-
tempWay.getPoints().size())) {
- joinWay.addPoint(0, point);
- }
- joined = true;
- } else if (joinWay.getPoints().get(
- joinWay.getPoints().size() - 1)
== tempWay.getPoints()
- .get(0)) {
- for (Coord point :
tempWay.getPoints().subList(1,
-
tempWay.getPoints().size())) {
- joinWay.addPoint(point);
- }
- joined = true;
- } else if (joinWay.getPoints().get(0) ==
tempWay.getPoints()
- .get(tempWay.getPoints().size()
- 1)) {
- int insertIndex = 0;
- for (Coord point :
tempWay.getPoints().subList(0,
-
tempWay.getPoints().size() - 1)) {
- joinWay.addPoint(insertIndex,
point);
- insertIndex++;
- }
- joined = true;
- } else if (joinWay.getPoints().get(
- joinWay.getPoints().size() - 1)
== tempWay.getPoints()
- .get(tempWay.getPoints().size()
- 1)) {
- int insertIndex =
joinWay.getPoints().size();
- for (Coord point :
tempWay.getPoints().subList(0,
-
tempWay.getPoints().size() - 1)) {
- joinWay.addPoint(insertIndex,
point);
+ String tempRole = getRole(tempWay);
+ // if a role is null then it is used as
universal
+ // check if the roles of the ways are matching
+ if (joinRole == null || joinRole.equals("") ||
tempRole == null
+ || tempRole.equals("") ||
joinRole.equals(tempRole)) {
+ // the roles are matching => try to
join both ways
+ joined = joinWays(joinWay, tempWay,
false);
+ } else {
+ // the roles are not matching => test
if both ways would
+ // join
+
+ // as long as we don't have an
alternative way with wrong
+ // role
+ // or if the alternative way is shorter
then check if
+ // the way with the wrong role could be
joined
+ if (wrongRoleWay == null
+ ||
wrongRoleWay.getPoints().size() < tempWay
+
.getPoints().size()) {
+ if (joinWays(joinWay, tempWay,
true)) {
+ // save this way =>
maybe we will use it in the end
+ // if we don't find any
other way
+ wrongRoleWay = tempWay;
+ }
}
- joined = true;
}
if (joined) {
+ // we have joined the way
unclosedWays.remove(tempWay);
- joinWay.addWay(tempWay);
+ break;
+ }
+ }
+
+ if (joined == false && wrongRoleWay != null) {
+ log.warn("Join ways with different roles. " +
toBrowseURL());
+ log.warn("Way1:", joinWay, "Role:",
getRole(joinWay));
+ log.warn("Way2:", wrongRoleWay, "Role:",
getRole(wrongRoleWay));
+ joined = joinWays(joinWay, wrongRoleWay, false);
+ if (joined) {
+ // we have joined the way
+ unclosedWays.remove(wrongRoleWay);
break;
}
}
@@ -191,6 +282,51 @@
return joinedWays;
}
+ 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) {
+ continue;
+ }
+ Coord p1 = way.getPoints().get(0);
+ Coord p2 = way.getPoints().get(way.getPoints().size() -
1);
+ Line2D closingLine = new
Line2D.Float(p1.getLongitude(), p1
+ .getLatitude(), p2.getLongitude(),
p2.getLatitude());
+
+ boolean intersects = false;
+ Coord lastPoint = null;
+ // don't use the first and the last point
+ // the closing line can intersect only in one point or
complete.
+ // Both isn't interesting for this check
+ for (Coord thisPoint : way.getPoints().subList(1,
+ way.getPoints().size() - 1)) {
+ if (lastPoint != null) {
+ if
(closingLine.intersectsLine(lastPoint.getLongitude(),
+
lastPoint.getLatitude(), thisPoint.getLongitude(),
+
thisPoint.getLatitude())) {
+ intersects = true;
+ break;
+ }
+ }
+ lastPoint = thisPoint;
+ }
+
+ if (intersects == false) {
+ // close the polygon
+ // the new way segment does not intersect the
rest of the
+ // polygon
+ log.info("Closing way", way);
+ log.info("from",
way.getPoints().get(0).toOSMURL());
+ log.info("to",
way.getPoints().get(way.getPoints().size() - 1)
+ .toOSMURL());
+ way.closeWayArtificial();
+ }
+ }
+
+ }
+
/**
* Removes all ways non closed ways from the given list (
* <code>{...@link Way#isClosed()} == false</code>)
@@ -208,11 +344,9 @@
log.warn("Unclosed polygons in
multipolygon relation "
+ getId() + ":");
}
- for (Map.Entry<String,Way> 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();
@@ -221,9 +355,19 @@
}
}
+ private BitSet findOutmostRings(BitSet candidates, BitSet roleFilter) {
+ BitSet realCandidates = ((BitSet) candidates.clone());
+ realCandidates.and(roleFilter);
+ log.debug("Checkmatrix",realCandidates);
+ BitSet result = findOutmostRings(realCandidates);
+ log.debug("Outmost",result);
+ return result;
+ }
+
/**
- * Finds all rings that are not contained by any other rings. All rings
with
- * index given by <var>candidates</var> are used.
+ * Finds all rings that are not contained by any other rings and that
match
+ * to the given role. All rings with index given by
<var>candidates</var>
+ * are used.
*
* @param candidates
* indexes of the rings that should be used
@@ -277,43 +421,26 @@
* ways with the role "inner" to the way with the role "outer"
*/
public void processElements() {
- ArrayList<Map.Entry<String,Way>> allWays =
- new ArrayList<Map.Entry<String,Way>>();
+ log.info("processing", toBrowseURL());
- for (Map.Entry<String,Element> 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 try
+ ArrayList<Way> allWays = new ArrayList<Way>();
- if (element instanceof Way) {
- allWays.add(new
AbstractMap.SimpleEntry<String,Way>
- (role, (Way) element));
+ for (Map.Entry<String, Element> 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());
}
}
rings = joinWays(allWays);
+ closeWays(rings);
removeUnclosedWays(rings);
// now we have closed ways == rings only
- /*
- * ===== start considering outer and inner ways ====
- * ArrayList<JoinedWay> joinedOuterWays = joinWays(outerWays);
- * ArrayList<JoinedWay> 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<JoinedWay>
- * completeJoinedWays = new ArrayList<JoinedWay>();
- * 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
@@ -327,11 +454,36 @@
BitSet unfinishedRings = new BitSet(rings.size());
unfinishedRings.set(0, rings.size());
- Queue<RingStatus> ringWorkingQueue = new
LinkedBlockingQueue<RingStatus>();
+ // create bitsets which rings belong to the outer and to the
inner role
+ BitSet innerRings = new BitSet();
+ BitSet outerRings = new BitSet();
+ int wi = 0;
+ for (Way w : rings) {
+ String role = getRole(w);
+ if ("inner".equals(role)) {
+ innerRings.set(wi);
+ } else if ("outer".equals(role)) {
+ outerRings.set(wi);
+ } else {
+ // unknown role => it could be both
+ innerRings.set(wi);
+ outerRings.set(wi);
+ }
+ wi++;
+ }
- BitSet outmostRings = findOutmostRings(unfinishedRings);
+ Queue<RingStatus> ringWorkingQueue = new
LinkedBlockingQueue<RingStatus>();
- ringWorkingQueue.addAll(getRingStatus(outmostRings, true));
+ BitSet outmostRings = findOutmostRings(unfinishedRings,
outerRings);
+ if (outmostRings.isEmpty()) {
+ // there's no outmost outer ring
+ // maybe this is a tile problem
+ // try to continue with the inner ring
+ outmostRings = findOutmostRings(unfinishedRings,
innerRings);
+ ringWorkingQueue.addAll(getRingStatus(outmostRings,
false));
+ } else {
+ ringWorkingQueue.addAll(getRingStatus(outmostRings,
true));
+ }
while (ringWorkingQueue.isEmpty() == false) {
@@ -339,9 +491,8 @@
RingStatus currentRing = ringWorkingQueue.poll();
// QA: check that all ways carry the role "outer/inner"
and
- // issue
- // warnings
- checkRoles(currentRing.ring.getOriginalRoleWays(),
+ // issue warnings
+ checkRoles(currentRing.ring.getOriginalWays(),
(currentRing.outer ? "outer" :
"inner"));
// this ring is now processed and should not be used by
any
@@ -358,7 +509,8 @@
// get the holes
// these are all rings that are in the main ring
// and that are not contained by any other ring
- BitSet holeIndexes = findOutmostRings(ringContains);
+ BitSet holeIndexes = findOutmostRings(ringContains,
+ (currentRing.outer ? innerRings :
outerRings));
ArrayList<RingStatus> holes = getRingStatus(holeIndexes,
!currentRing.outer);
@@ -371,46 +523,40 @@
|| hasUsefulTags(currentRing.ring);
if (processRing) {
- // now construct the ring polygon with its holes
+
+ List<Way> innerWays = new
ArrayList<Way>(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]);
- } else {
- // this must not happen
- log.error("Cannot find cpa in
multipolygon "
- +
toBrowseURL());
- }
+ innerWays.add(holeRingStatus.ring);
+ }
+
+ List<Way> singularOuterPolygons =
processRing(currentRing.ring,
+ innerWays);
+
+ if (currentRing.ring.getOriginalWays().size()
== 1) {
+ // the original way was a closed
polygon which
+ // has been replaced by the new cutted
polygon
+ // the original way should not appear
+ // so we remove all tags
+ currentRing.ring.removeAllTagsDeep();
+ } else {
+ // the ring has been composed by
several ways
+ // they may contain line tags
+ // however all polygon tags are not
processed
+ // because they are only lines and not
polygons
+ // so we don't have to remove any tag
}
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<String,Way> 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<String, String>
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);
}
}
@@ -427,18 +573,241 @@
}
}
+ // log.info("Result");
+ // StringBuilder sb = new StringBuilder();
+ // for (Way resultWay : polygonResults) {
+ // sb.append("Way: " + resultWay.getId() + " Points: "
+ // + resultWay.getPoints().size() + " Closed: "
+ // + resultWay.isClosed() + " Tags: ");
+ // for (Map.Entry<String, String> entry : resultWay
+ // .getEntryIteratable()) {
+ // sb.append(entry.getKey() + "=" + entry.getValue() + "; ");
+ // }
+ // log.info(sb.toString());
+ // sb.setLength(0);
+ // }
+
// the polygonResults contain all polygons that should be used
in the
// map
- // TODO remove the input stuff? inner ways and outer segments?
- for (Way resultWay : polygonResults) {
- myWayMap.put(resultWay.getId(), resultWay);
+ for (Way mpWay : polygonResults) {
+ // store the ways generated by the multipolygon code
+ // to the way map
+ myWayMap.put(mpWay.getId(), mpWay);
+ }
+
+ cleanup();
+ }
+
+ private void cleanup() {
+ roleMap.clear();
+ containsMatrix.clear();
+ rings.clear();
+ polygonResults.clear();
+ }
+
+ private List<Way> processRing(Way outerWay, List<Way> innerWays) {
+ // this list contains all non overlapping and singular areas
+ // of the outer way
+ List<Area> outerAreas = new ArrayList<Area>();
+
+ // 1st create an Area object of the outerWay and put it to the
list
+ // this must be clipped by the bounding box
+ Area oa = createArea(outerWay.getPoints());
+ // the polygons will be later clipped in the style converter
+ // so it is not necessary to clip it here
+ // oa.intersect(awtBbox);
+ outerAreas.add(oa);
+
+ for (Way innerWay : innerWays) {
+ Area innerArea = createArea(innerWay.getPoints());
+
+ List<Area> outerAfterThisStep = new ArrayList<Area>();
+ 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<Way> outerWays = new ArrayList<Way>(outerAreas.size());
+ for (Area area : outerAreas) {
+ Way w = singularAreaToWay(area,
FakeIdGenerator.makeFakeId());
+ if (w != null) {
+ w.copyTags(outerWay);
+ outerWays.add(w);
+ }
+ }
+
+ return outerWays;
+ }
+
+ private List<Area> areaToSingularAreas(Area area) {
+ if (area.isEmpty()) {
+ return Collections.emptyList();
+ } else if (area.isSingular()) {
+ return Collections.singletonList(area);
+ } else {
+ List<Area> singularAreas = new ArrayList<Area>();
+
+ // 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 Polygon createPolygon(List<Coord> points) {
+ Polygon polygon = new Polygon();
+ for (Coord co : points) {
+ polygon.addPoint(co.getLongitude(), co.getLatitude());
}
+ return polygon;
+ }
+ private Area createArea(List<Coord> points) {
+ return new Area(createPolygon(points));
+ }
+
+ 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.debug("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);
+
+ 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<String,Way> segment : way.getOriginalRoleWays())
{
- if (hasUsefulTags(segment.getValue())) {
+ for (Way segment : way.getOriginalWays()) {
+ if (hasUsefulTags(segment)) {
return true;
}
}
@@ -461,14 +830,12 @@
* @param wayList
* @param checkRole
*/
- private void checkRoles(List<Map.Entry<String,Way>> wayList,
- String checkRole) {
+ private void checkRoles(List<Way> wayList, String checkRole) {
// QA: check that all ways carry the role "inner" and issue
warnings
- for (Map.Entry<String,Way> 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);
}
}
@@ -481,7 +848,7 @@
// mark which ring contains which ring
for (int i = 0; i < wayList.size(); i++) {
- Way tempRing = wayList.get(i);
+ JoinedWay tempRing = wayList.get(i);
BitSet bitSet = containsMatrix.get(i);
for (int j = 0; j < wayList.size(); j++) {
@@ -499,9 +866,69 @@
}
}
}
-
+
+ log.debug("Containsmatrix");
+ for (BitSet b : containsMatrix) {
+ log.debug(b);
+ }
}
+ /*
+ * this is an alternative createContainsMatrix method seems to speed up
only
+ * if lots of inner ways are in the mulitpolygon
+ */
+ // private void createContainsMatrix(List<JoinedWay> 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<BitSet> finishedMatrix = new
ArrayList<BitSet>(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.
*
@@ -521,20 +948,17 @@
* @param ring2
* @return true if ring1 contains ring2
*/
- private boolean contains(Way ring1, Way ring2) {
+ private boolean contains(JoinedWay ring1, JoinedWay ring2) {
// TODO this is a simple algorithm
// might be improved
if (ring1.isClosed() == false) {
return false;
}
- Polygon p = new Polygon();
- for (Coord c : ring1.getPoints()) {
- p.addPoint(c.getLatitude(), c.getLongitude());
- }
+ Polygon p = createPolygon(ring1.getPoints());
Coord p0 = ring2.getPoints().get(0);
- if (p.contains(p0.getLatitude(), p0.getLongitude()) == false) {
+ if (p.contains(p0.getLongitude(), p0.getLatitude()) == false) {
// we have one point that is not in way1 => way1 does
not contain
// way2
return false;
@@ -555,14 +979,22 @@
p1_2 = p1_1;
p1_1 = it1.next();
- boolean intersects =
Line2D.linesIntersect(p1_1.getLatitude(),
- p1_1.getLongitude(),
p1_2.getLatitude(), p1_2
-
.getLongitude(), p2_1.getLatitude(), p2_1
-
.getLongitude(), p2_2.getLatitude(), p2_2
-
.getLongitude());
+ boolean intersects =
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());
if (intersects) {
- return false;
+ if ((ring1.isClosedArtificially() &&
it1.hasNext() == false)
+ ||
(ring2.isClosedArtificially() && it2.hasNext() == false)) {
+ // don't care about this
intersection
+ // one of the rings is closed
by this mp code and the
+ // closing way causes the
intersection
+ log.warn("Way",ring1,"may
contain way",ring2,". Ignoring artificial generated intersection.");
+ } else {
+ return false;
+ }
}
}
}
@@ -573,213 +1005,96 @@
}
/**
- * 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<Coord> outList = outer.getPoints();
- List<Coord> 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<Way> originalWays;
+ private boolean closedArtifical = false;
- // 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.makeFakeId(), new
ArrayList<Coord>(originalWay
+ .getPoints()));
+ this.originalWays = new ArrayList<Way>();
+ addWay(originalWay);
}
- }
-
- private static final class DistIndex implements Comparable<DistIndex> {
- 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<Coord> l1, List<Coord> 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<DistIndex> distList = new
ArrayList<DistIndex>(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;
- }
- } else {
- break;
- }
+ public void closeWayArtificial() {
+ addPoint(getPoints().get(0));
+ closedArtifical = true;
}
- if (minDistance == null) {
- // this should not happen
- return new int[] { -1, -1 };
- } else {
- return new int[] { minDistance.index1,
minDistance.index2 };
+ public boolean isClosedArtificially() {
+ return closedArtifical;
}
- }
- private static boolean intersects(List<Coord> 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;
+ private void addTagsOf(Way way) {
+ for (Map.Entry<String, String> tag :
way.getEntryIteratable()) {
+ if (getTag(tag.getKey()) == null) {
+ addTag(tag.getKey(), tag.getValue());
+ }
}
}
- 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<Map.Entry<String,Way>> originalRoleWays;
-
- public JoinedWay(String role, Way originalWay) {
- super(-originalWay.getId(), new
ArrayList<Coord>(originalWay
- .getPoints()));
- this.originalRoleWays = new
ArrayList<Map.Entry<String,Way>>();
- this.originalRoleWays.add(new
AbstractMap.SimpleEntry<String,Way>
-
(role, originalWay));
+ public List<Way> getOriginalWays() {
+ return originalWays;
}
- public void addPoint(int index, Coord point) {
- getPoints().add(index, point);
+ public void removeAllTagsDeep() {
+ removeOriginalTags();
+ removeAllTags();
}
- public void addWay(JoinedWay way) {
- originalRoleWays.addAll(way.originalRoleWays);
- log.debug("Joined", this.getId(), "with", way.getId());
+ public void removeOriginalTags() {
+ for (Way w : getOriginalWays()) {
+ if (w instanceof JoinedWay) {
+ ((JoinedWay) w).removeAllTagsDeep();
+ } else {
+ w.removeAllTags();
+ }
+ }
}
- public List<Map.Entry<String, Way>> getOriginalRoleWays() {
- return originalRoleWays;
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(200);
+ sb.append(getId());
+ sb.append("[");
+ sb.append(getPoints().size());
+ sb.append("P : (");
+ boolean first = true;
+ for (Way w : getOriginalWays()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(",");
+ }
+ sb.append(w.getId());
+ sb.append("[");
+ sb.append(w.getPoints().size());
+ sb.append("P]");
+ }
+ sb.append(")");
+ return sb.toString();
}
}
Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
(revision 1475)
+++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
(working copy)
@@ -20,9 +20,8 @@
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.InputStreamReader;
import java.io.IOException;
-
+import java.io.InputStreamReader;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
@@ -37,6 +36,12 @@
import java.util.SortedMap;
import java.util.TreeMap;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.Exit;
@@ -46,6 +51,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;
@@ -55,12 +61,6 @@
import uk.me.parabola.mkgmap.reader.osm.Way;
import uk.me.parabola.util.EnhancedProperties;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
/**
* Reads and parses the OSM XML format.
*
@@ -104,8 +104,6 @@
private Area bbox;
private Runnable endTask;
- private long nextFakeId = 1;
-
private final boolean reportUndefinedNodes;
private final boolean makeOppositeCycleways;
private final boolean makeCycleways;
@@ -545,8 +543,10 @@
private void endRelation() {
String type = currentRelation.getTag("type");
if (type != null) {
- if ("multipolygon".equals(type))
- currentRelation = new
MultiPolygonRelation(currentRelation, wayMap);
+ if ("multipolygon".equals(type)) {
+ Area mpbbox = (bbox == null ?
mapper.getBounds() : bbox);
+ currentRelation = new
MultiPolygonRelation(currentRelation, wayMap, mpbbox);
+ }
else if("restriction".equals(type)) {
if(ignoreTurnRestrictions)
@@ -570,7 +570,7 @@
currentRelation = null;
}
}
-
+
/**
* Receive notification of the end of the document.
*
@@ -581,7 +581,7 @@
* another exception.
*/
public void endDocument() throws SAXException {
-
+
for (Node e : exits) {
String refTag = Exit.TAG_ROAD_REF;
if(e.getTag(refTag) == null) {
@@ -1052,10 +1052,6 @@
super.fatalError(e);
}
- public long makeFakeId() {
- return (1L << 62) + nextFakeId++;
- }
-
private long idVal(String id) {
try {
// attempt to parse id as a number
@@ -1065,7 +1061,7 @@
// if that fails, fake a (hopefully) unique value
Long fakeIdVal = fakeIdMap.get(id);
if(fakeIdVal == null) {
- fakeIdVal = makeFakeId();
+ fakeIdVal = FakeIdGenerator.makeFakeId();
fakeIdMap.put(id, fakeIdVal);
}
//System.out.printf("%s = 0x%016x\n", id, fakeIdVal);
@@ -1090,7 +1086,7 @@
log.info("clipping " + segment);
toBeRemoved.add(segment);
for (List<Coord> pts : clipped) {
- long id = makeFakeId();
+ long id = FakeIdGenerator.makeFakeId();
Way shore = new Way(id, pts);
toBeAdded.add(shore);
}
@@ -1117,7 +1113,7 @@
// polygon so that the tile's background colour
will
// match the land colour on the tiles that do
contain
// some sea
- long landId = makeFakeId();
+ long landId = FakeIdGenerator.makeFakeId();
Way land = new Way(landId);
land.addPoint(nw);
land.addPoint(sw);
@@ -1131,7 +1127,7 @@
return;
}
- long multiId = makeFakeId();
+ long multiId = FakeIdGenerator.makeFakeId();
Relation seaRelation = null;
if(generateSeaUsingMP) {
seaRelation = new GeneralRelation(multiId);
@@ -1223,7 +1219,7 @@
}
}
else if(allowSeaSectors) {
- seaId = makeFakeId();
+ seaId = FakeIdGenerator.makeFakeId();
sea = new Way(seaId);
sea.getPoints().addAll(points);
sea.addPoint(new
Coord(pEnd.getLatitude(), pStart.getLongitude()));
@@ -1249,7 +1245,7 @@
}
}
if (generateSeaBackground) {
- seaId = makeFakeId();
+ seaId = FakeIdGenerator.makeFakeId();
sea = new Way(seaId);
sea.addPoint(nw);
sea.addPoint(sw);
@@ -1266,7 +1262,7 @@
// now construct inner ways from these segments
NavigableSet<EdgeHit> hits = (NavigableSet<EdgeHit>)
hitMap.keySet();
while (!hits.isEmpty()) {
- long id = makeFakeId();
+ long id = FakeIdGenerator.makeFakeId();
Way w = new Way(id);
wayMap.put(id, w);
@@ -1332,7 +1328,8 @@
}
if(generateSeaUsingMP) {
- seaRelation = new MultiPolygonRelation(seaRelation,
wayMap);
+ Area mpbbox = (bbox == null ? mapper.getBounds() :
bbox);
+ seaRelation = new MultiPolygonRelation(seaRelation,
wayMap, mpbbox);
relationMap.put(multiId, seaRelation);
seaRelation.processElements();
}
@@ -1451,8 +1448,8 @@
log.info("merging: ", ways.size(),
w1.getId(), w2.getId());
List<Coord> points2 = w2.getPoints();
Way wm;
- if (w1.getId() < (1L << 62)) {
- wm = new Way(makeFakeId());
+ if
(FakeIdGenerator.isFakeId(w1.getId())) {
+ wm = new
Way(FakeIdGenerator.makeFakeId());
ways.remove(w1);
ways.add(wm);
wm.getPoints().addAll(points1);
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev