Hi,
the patch removes tags from ways not until all multipolygons are
processed. This fixes some problems if one way is a member of multiple
multipolygons and the multipolygons take their tags from their ways.
This is a result of the thread
http://www.mkgmap.org.uk/pipermail/mkgmap-dev/2010q3/008730.html.
The second patch fixes some problem of the first patch including an
additional algorithm to automatically close ways having both endpoints
outside the bounding box.
Have fun!
WanMil
Index: src/uk/me/parabola/mkgmap/reader/osm/Element.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/Element.java (revision 1667)
+++ src/uk/me/parabola/mkgmap/reader/osm/Element.java (working copy)
@@ -66,9 +66,9 @@
this.id = id;
}
- String toTagString() {
+ public String toTagString() {
if (tags == null)
- return "";
+ return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
@@ -76,7 +76,9 @@
sb.append(nameval);
sb.append(',');
}
- sb.setLength(sb.length()-1);
+ if (sb.length() > 1) {
+ sb.setLength(sb.length()-1);
+ }
sb.append(']');
return sb.toString();
}
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (revision 1667)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java (working copy)
@@ -20,6 +20,7 @@
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
+import java.util.Map.Entry;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
@@ -46,7 +47,9 @@
private final uk.me.parabola.imgfmt.app.Area bbox;
private Area bboxArea;
-
+
+ private final Map<Long, Set<String>> wayRemoveTags;
+
/**
* A point that has a lower or equal squared distance from
* a line is treated as if it lies one the line.<br/>
@@ -72,30 +75,37 @@
* The relation to base this one on.
* @param wayMap
* Map of all ways.
+ * @param wayRemoveTags
+ * Marks which tags should be removed from a way after the
+ * complete multipolygon processing has finished
+ * @param bbox
+ * The bounding box of the tile
*/
- public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap,
+ public MultiPolygonRelation(Relation other, Map<Long, Way> wayMap,
+ Map<Long, Set<String>> wayRemoveTags,
uk.me.parabola.imgfmt.app.Area bbox) {
this.tileWayMap = wayMap;
this.bbox = bbox;
+ this.wayRemoveTags = wayRemoveTags;
setId(other.getId());
+ setName(other.getName());
+ copyTags(other);
if (log.isDebugEnabled()) {
- log.debug("Construct multipolygon", toBrowseURL());
+ log.debug("Construct multipolygon", toBrowseURL(), toTagString());
}
for (Map.Entry<String, Element> pair : other.getElements()) {
String role = pair.getKey();
Element el = pair.getValue();
if (log.isDebugEnabled()) {
- log.debug(" ", role, el.toBrowseURL());
+ log.debug(" ", role, el.toBrowseURL(), el.toTagString());
}
addElement(role, el);
roleMap.put(el.getId(), role);
}
- setName(other.getName());
- copyTags(other);
}
public boolean isBoundaryRelation() {
@@ -334,20 +344,61 @@
}
Coord p1 = way.getPoints().get(0);
Coord p2 = way.getPoints().get(way.getPoints().size() - 1);
-
- // check if both endpoints are outside the bounding box
- // and if they are on the same side of the bounding box
- if ((p1.getLatitude() <= bbox.getMinLat() && p2.getLatitude() <= bbox.getMinLat())
- || (p1.getLatitude() >= bbox.getMaxLat() && p2.getLatitude() >= bbox.getMaxLat())
- || (p1.getLongitude() <= bbox.getMinLong() && p2.getLongitude() <= bbox.getMinLong())
- || (p1.getLongitude() >= bbox.getMaxLong() && p2.getLongitude() >= bbox.getMaxLong())) {
- // they are on the same side outside of the bbox
- // so just close them without worrying about if
- // they intersect itself because the intersection also
- // is outside the bbox
- way.closeWayArtificially();
- log.info("Endpoints of way",way,"are both outside the bbox. Closing it directly.");
- continue;
+
+ if (bbox.insideBoundary(p1) == false
+ && bbox.insideBoundary(p2) == false) {
+ // both points lie outside the bbox or on the bbox
+
+ // check if both points are on the same side of the bounding box
+ if ((p1.getLatitude() <= bbox.getMinLat() && p2.getLatitude() <= bbox
+ .getMinLat())
+ || (p1.getLatitude() >= bbox.getMaxLat() && p2
+ .getLatitude() >= bbox.getMaxLat())
+ || (p1.getLongitude() <= bbox.getMinLong() && p2
+ .getLongitude() <= bbox.getMinLong())
+ || (p1.getLongitude() >= bbox.getMaxLong() && p2
+ .getLongitude() >= bbox.getMaxLong())) {
+ // they are on the same side outside of the bbox
+ // so just close them without worrying about if
+ // they intersect itself because the intersection also
+ // is outside the bbox
+ way.closeWayArtificially();
+ log.info("Endpoints of way", way,
+ "are both outside the bbox. Closing it directly.");
+ continue;
+ }
+
+
+ // Check if the way can be closed with one additional point
+ // outside the bounding box.
+ // The additional point is combination of the coords of both endpoints.
+ // It works if the lines from the endpoints to the additional point does
+ // not cut the bounding box.
+ // This can be removed when the splitter guarantees to provide logical complete
+ // multipolygons.
+ Coord edgePoint1 = new Coord(p1.getLatitude(), p2
+ .getLongitude());
+ Coord edgePoint2 = new Coord(p2.getLatitude(), p1
+ .getLongitude());
+
+ if (lineCutsBbox(p1, edgePoint1) == false
+ && lineCutsBbox(edgePoint1, p2) == false) {
+ way.addPoint(edgePoint1);
+ way.closeWayArtificially();
+ log.info("Endpoints of way", way,
+ "are both outside the bbox. Add point", edgePoint1,
+ "and close it.");
+ continue;
+ }
+ if (lineCutsBbox(p1, edgePoint2) == false
+ && lineCutsBbox(edgePoint2, p2) == false) {
+ way.addPoint(edgePoint2);
+ way.closeWayArtificially();
+ log.info("Endpoints of way", way,
+ "are both outside the bbox. Add point", edgePoint2,
+ "and close it.");
+ continue;
+ }
}
Line2D closingLine = new Line2D.Float(p1.getLongitude(), p1
@@ -722,12 +773,8 @@
// has been replaced by the new cut polygon
// the original way should not appear
// so we remove all tags
- currentPolygon.polygon.removeAllTagsDeep();
- } else {
- // remove all polygons tags from the original ways
- // sometimes the ways seem to be auto-closed later on
- // in mkgmap
- currentPolygon.polygon.removePolygonTagsInOrgWays();
+ removeTagInOrgWays(currentPolygon.polygon, null, null);
+ currentPolygon.polygon.removeAllTags();
}
boolean useRelationTags = currentPolygon.outer
@@ -735,6 +782,8 @@
if (useRelationTags) {
// the multipolygon contains tags that overwhelm the
// tags of the outer polygon
+ removeTagsInOrgWays(this, currentPolygon.polygon);
+
for (Way p : singularOuterPolygons) {
p.copyTags(this);
p.deleteTag("type");
@@ -1256,6 +1305,10 @@
private boolean hasPolygonTags(Element element) {
for (Map.Entry<String, String> tagEntry : element.getEntryIteratable()) {
+ if ("natural".equals(tagEntry.getKey()) && "coastline".equals(tagEntry.getValue())) {
+ // ignore natural=coastline because this is not a real polygon tag
+ continue;
+ }
if (polygonTags.contains(tagEntry.getKey())) {
return true;
}
@@ -1272,7 +1325,7 @@
*/
private void createContainsMatrix(List<JoinedWay> polygonList) {
containsMatrix = new ArrayList<BitSet>();
- for (JoinedWay aPolygonList : polygonList) {
+ for (int i = 0; i < polygonList.size(); i++) {
containsMatrix.add(new BitSet());
}
@@ -1404,7 +1457,7 @@
// bounding box => polygon1 does not contain polygon2
//allOnLine = false;
return false;
- }
+ }
}
}
@@ -1600,7 +1653,18 @@
}
return false;
}
-
+
+ private boolean lineCutsBbox(Coord p1_1, Coord p1_2) {
+ Coord nw = new Coord(bbox.getMaxLat(), bbox.getMinLong());
+ Coord sw = new Coord(bbox.getMinLat(), bbox.getMinLong());
+ Coord se = new Coord(bbox.getMinLat(), bbox.getMaxLong());
+ Coord ne = new Coord(bbox.getMaxLat(), bbox.getMaxLong());
+ return linesCutEachOther(nw, sw, p1_1, p1_2)
+ || linesCutEachOther(sw, se, p1_1, p1_2)
+ || linesCutEachOther(se, ne, p1_1, p1_2)
+ || linesCutEachOther(ne, nw, p1_1, p1_2);
+ }
+
/**
* Check if the line p1_1 to p1_2 cuts line p2_1 to p2_2 in two pieces and vice versa.
* This is a form of intersection check where it is allowed that one line ends on the
@@ -1642,7 +1706,7 @@
return false;
}
- return false;
+ return true;
}
private List<JoinedWay> getWaysFromPolygonList(BitSet selection) {
@@ -1680,6 +1744,82 @@
}
}
+ /**
+ * Marks all tags of the original ways of the given JoinedWay that are also
+ * contained in the given tagElement for removal.
+ *
+ * @param tagElement
+ * an element contains the tags to be removed
+ * @param way
+ * a joined way
+ */
+ private void removeTagsInOrgWays(Element tagElement, JoinedWay way) {
+ for (Entry<String, String> tag : tagElement.getEntryIteratable()) {
+ removeTagInOrgWays(way, tag.getKey(), tag.getValue());
+ }
+ }
+
+ /**
+ * Mark the given tag of all original ways of the given JoinedWay.
+ *
+ * @param way
+ * a joined way
+ * @param tagname
+ * the tag to be removed (<code>null</code> means remove all
+ * tags)
+ * @param tagvalue
+ * the value of the tag to be removed (<code>null</code> means
+ * don't check the value)
+ */
+ private void removeTagInOrgWays(JoinedWay way, String tagname,
+ String tagvalue) {
+ for (Way w : way.getOriginalWays()) {
+ if (w instanceof JoinedWay) {
+ // remove the tags recursively
+ removeTagInOrgWays((JoinedWay) w, tagname, tagvalue);
+ continue;
+ }
+
+ boolean remove = false;
+ if (tagname == null) {
+ // remove all tags
+ remove = true;
+ } else if (tagvalue == null) {
+ // remove the tag without comparing the value
+ remove = w.getTag(tagname) != null;
+ } else if (tagvalue.equals(w.getTag(tagname))) {
+ remove = true;
+ }
+
+ if (remove) {
+ Set<String> tagListToRemove = this.wayRemoveTags.get(w.getId());
+ if (tagListToRemove == null) {
+ tagListToRemove = new TreeSet<String>();
+ wayRemoveTags.put(w.getId(), tagListToRemove);
+ }
+ if (tagname == null) {
+ // remove all tags
+ if (log.isDebugEnabled())
+ log.debug("Will remove all tags from", w.getId(), w
+ .toTagString());
+ for (Entry<String, String> tag : w.getEntryIteratable()) {
+ tagListToRemove.add(tag.getKey());
+ if (log.isDebugEnabled())
+ log.debug("Will remove", tag.getKey() + "="
+ + tag.getValue(), "from way", w.getId(), w
+ .toTagString());
+ }
+ } else {
+ tagListToRemove.add(tagname);
+ if (log.isDebugEnabled())
+ log.debug("Will remove", tagname + "="
+ + w.getTag(tagname), "from way", w.getId(), w
+ .toTagString());
+ }
+ }
+ }
+ }
+
private static final boolean joinWayTagMerge = false;
/**
@@ -1816,34 +1956,6 @@
return originalWays;
}
- public void removePolygonTagsInOrgWays() {
- for (Way w : getOriginalWays()) {
- for (String polygonTag : polygonTags) {
- w.deleteTag(polygonTag);
- }
- }
- }
-
- public void removeAllTagsDeep() {
- removeOriginalTags();
- removeAllTags();
- }
-
- public void removeOriginalTags() {
- for (Way w : getOriginalWays()) {
- if (w instanceof JoinedWay) {
- ((JoinedWay) w).removeAllTagsDeep();
- } else {
- log.info("Before remove",w.toTagString());
- for (Map.Entry<String, String> wayTag : w
- .getEntryIteratable()) {
- w.deleteTag(wayTag.getKey());
- }
- log.info("After remove",w.toTagString());
- }
- }
- }
-
public String toString() {
StringBuilder sb = new StringBuilder(200);
sb.append(getId());
Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java (revision 1667)
+++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java (working copy)
@@ -35,6 +35,7 @@
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
+import java.util.Map.Entry;
import uk.me.parabola.imgfmt.MapFailedException;
import uk.me.parabola.imgfmt.app.Area;
@@ -124,6 +125,8 @@
private HashMap<String,Set<String>> deletedTags;
private Map<String, String> usedTags;
+
+ private final Map<Long,Set<String>> mpWayRemoveTags = new HashMap<Long,Set<String>>();
public Osm5XmlHandler(EnhancedProperties props) {
if(props.getProperty("make-all-cycleways", false)) {
@@ -603,7 +606,7 @@
if (type != null) {
if ("multipolygon".equals(type)) {
Area mpBbox = (bbox != null ? bbox : ((MapDetails) collector).getBounds());
- currentRelation = new MultiPolygonRelation(currentRelation, wayMap, mpBbox);
+ currentRelation = new MultiPolygonRelation(currentRelation, wayMap, mpWayRemoveTags, mpBbox);
} else if("restriction".equals(type)) {
if(ignoreTurnRestrictions)
@@ -680,6 +683,20 @@
if (generateSea)
generateSeaPolygon(shoreline);
+ for (Entry<Long,Set<String>> wayTagsRemove : mpWayRemoveTags.entrySet()) {
+ Way w = wayMap.get(wayTagsRemove.getKey());
+ if (w==null) {
+ log.debug("Cannot find way",wayTagsRemove.getKey(),"to remove tags by multipolygon processing.");
+ continue;
+ }
+ log.debug("Remove tags",wayTagsRemove.getValue(),"from way",w.getId(), w.toTagString());
+ for (String tagname : wayTagsRemove.getValue()) {
+ w.deleteTag(tagname);
+ }
+ log.debug("After removal",w.getId(), w.toTagString());
+ }
+ mpWayRemoveTags.clear();
+
for (Relation r : relationMap.values())
converter.convertRelation(r);
@@ -1253,6 +1270,7 @@
log.debug("Generate seabounds relation "+multiId);
seaRelation = new GeneralRelation(multiId);
seaRelation.addTag("type", "multipolygon");
+ seaRelation.addTag("natural", "sea");
}
List<Way> islands = new ArrayList<Way>();
@@ -1576,7 +1594,7 @@
if(generateSeaUsingMP) {
Area mpBbox = (bbox != null ? bbox : ((MapDetails) collector).getBounds());
- seaRelation = new MultiPolygonRelation(seaRelation, wayMap, mpBbox);
+ seaRelation = new MultiPolygonRelation(seaRelation, wayMap, mpWayRemoveTags, mpBbox);
relationMap.put(multiId, seaRelation);
seaRelation.processElements();
}
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev