I have made some improvements to the multipolygon branch.
Changes:
* Polygons with inner polygons are now divided into several polygons.
It's much faster and the PolygonSplitter cannot destroy them any more.
* Improved tag handling. The tags from original ways are removed. This
has the disadvantage that non polygon tags like highway are destroyed.
This must be fixed within one of the next patches.
* Added a FakeIdGenerator that creates unique fake ids for elements
created by mkgmap. The Osm5XmlHandler has been adapted to that.
As before I am happy about any (good and bad) feedback!!
WanMil
Note: The code is not ready for the trunk. Some documentation and better
method naming will be applied in one of the next patch.
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<Way> outerSegments = new ArrayList<Way>();
- // private final List<Way> innerSegments = new ArrayList<Way>();
private final Map<Long, Way> myWayMap;
private final ArrayList<BitSet> containsMatrix = new
ArrayList<BitSet>();
@@ -54,25 +54,26 @@
public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap) {
myWayMap = wayMap;
setId(other.getId());
+
for (Map.Entry<String, Element> 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<String, Element> 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<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 +94,11 @@
// 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) {
+ 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<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();
@@ -277,19 +272,16 @@
* 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>>();
-
- 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
+ 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());
}
}
@@ -297,23 +289,6 @@
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
@@ -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<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]);
+ innerWays.add(holeRingStatus.ring);
+ }
+
+ List<Way> 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<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);
}
}
@@ -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<String, String> entry : resultWay
+ .getEntryIteratable()) {
+ sb.append(entry.getKey() + "=" +
entry.getValue() + "; ");
+ }
+ log.warn(sb.toString());
+ sb.setLength(0);
myWayMap.put(resultWay.getId(), resultWay);
}
}
+ private List<Way> processRing(Way outerWay, List<Way> innerWays) {
+ if (innerWays == null || innerWays.isEmpty()) {
+ return Collections.singletonList(outerWay);
+ }
+ // 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
+ outerAreas.add(wayToArea(outerWay));
+
+ for (Way innerWay : innerWays) {
+ Area innerArea = wayToArea(innerWay);
+
+ 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.getFakeId());
+ 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 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<String,Way> 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<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);
}
}
@@ -499,9 +674,60 @@
}
}
}
-
}
+ // 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.
*
@@ -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<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;
- // 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<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;
+ private void addTagsOf(Way way) {
+ for (Map.Entry<String, String> 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<Way> getOriginalWays() {
+ return originalWays;
}
- }
-
- 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;
- }
+ 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<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 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<Map.Entry<String, Way>> 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) {
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev