I am thinking about how to handle boundary multipolygons and want get
some feedback and ideas from you.
There are two possible ways to use boundary information:
1. Draw the boundaries as lines
2. Draw the boundaries as polygons with different colours for different
administrative levels
I think the 2nd option cannot be realized (at the moment). I see no way
how to define a style that differently colours adjoining polygons with
rather identical tags (e.g. boundary=adminstrative, admin_level=2).
So let's concentrate on the 1st option.
One way may be part of different boundary relations. (admin_level=2&&
admin_level=3&& admin_level=4 ....). To be able to process all of them
with the style system the way must be duplicated for each relation.
The multipolygon handling of boundaries might work as follows:
For all ways (role=outer and inner) part of the boundary relation
- Clone the original way
- Tag the cloned way with the boundary information of the mp
- Remove all tags from the original way that are also contained in the
mp (with the same value)
- Split all closed ways (polygons) in two ways to ensure that only ways
are tagged with the boundary information
What do you think? If no one really complains I will start implementing
this (and expect that it will be accepted when I am ready :-).
In case other multipolygon type also require such a processing we might
add a config file in future which types are handled in this way. So this
is ready to be more generic.
WanMil
Why talking so long? Implementation was quite easy so please try this
patch and post what you think about this patch.
I will post v2 with some more comments in the source code if it should
be committed.
WanMil
Index: src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonToLineRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonToLineRelation.java
(revision 0)
+++ src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonToLineRelation.java
(revision 0)
@@ -0,0 +1,193 @@
+package uk.me.parabola.mkgmap.reader.osm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import uk.me.parabola.log.Logger;
+
+public class MultiPolygonToLineRelation extends Relation {
+ private static final Logger log = Logger
+ .getLogger(MultiPolygonToLineRelation.class);
+
+ private final Map<Long, Way> tileWayMap;
+ private final Map<Long, String> roleMap = new HashMap<Long, String>();
+
+ public MultiPolygonToLineRelation(Relation other, Map<Long, Way>
wayMap) {
+ this.tileWayMap = wayMap;
+
+ setId(other.getId());
+
+ if (log.isDebugEnabled()) {
+ log.debug("Construct multipolygon (lines) ",
toBrowseURL());
+ log.debug("Multipolygon tags:",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(),
el.toTagString());
+ }
+ addElement(role, el);
+ roleMap.put(el.getId(), role);
+ }
+
+ setName(other.getName());
+ copyTags(other);
+ }
+
+ @Override
+ public void processElements() {
+ log.info("Processing multipolygon (lines)", toBrowseURL());
+
+ // don't care about outer and inner declaration
+ ArrayList<Way> orgWays = new ArrayList<Way>();
+
+ for (Map.Entry<String, Element> r_e : getElements()) {
+ if (r_e.getValue() instanceof Way) {
+ orgWays.add((Way) r_e.getValue());
+ } else {
+ log.warn("Non way element",
r_e.getValue().getId(),
+ "in multipolygon", getId());
+ }
+ }
+
+ Way copyTagWay = new Way(FakeIdGenerator.makeFakeId());
+ if (useRelationTags()) {
+ log.debug("Use relation tags");
+ copyTagWay.copyTags(this);
+ // not interested in type=multipolygon
+ copyTagWay.deleteTag("type");
+ } else {
+ log.debug("Use tags from outer ways");
+ copyTagsFromOuterWays(orgWays, copyTagWay);
+ }
+ if (log.isDebugEnabled()) {
+ for (Entry<String, String> tag :
copyTagWay.getEntryIteratable()) {
+ log.debug("-", tag.getKey(), tag.getValue());
+ }
+ }
+
+ Iterable<Entry<String, String>> tags =
copyTagWay.getEntryIteratable();
+ if (tags.iterator().hasNext() == false) {
+ // no tag left
+ log.warn("Cannot process multipolygon", toBrowseURL(),
+ ". The mp does not contain unambiguous tags.");
+ cleanup();
+ return;
+ }
+
+ // duplicate all ways
+ List<Way> mpResult = new ArrayList<Way>();
+ for (Way way : orgWays) {
+ if (way.isClosed() && way.getPoints().size() > 2) {
+ Way clonedWay1 = new
Way(FakeIdGenerator.makeFakeId());
+ Way clonedWay2 = new
Way(FakeIdGenerator.makeFakeId());
+
+ // is that necessary?
+ clonedWay1.setName(way.getName());
+ clonedWay2.setName(way.getName());
+
+ int midPoint = way.getPoints().size() / 2;
+ clonedWay1.getPoints().addAll(
+ way.getPoints().subList(0, midPoint +
1));
+ clonedWay1.getPoints().addAll(
+ way.getPoints().subList(midPoint,
way.getPoints().size()));
+
+ mpResult.add(clonedWay1);
+ mpResult.add(clonedWay2);
+ } else {
+ Way clonedWay = way.copy();
+ clonedWay.setId(FakeIdGenerator.makeFakeId());
+ mpResult.add(clonedWay);
+ }
+
+ // remove all tags that are used by the polygon
+ for (Entry<String, String> wayTag :
way.getEntryIteratable()) {
+ String mpTagValue =
copyTagWay.getTag(wayTag.getKey());
+ if (wayTag.getValue().equals(mpTagValue)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Remove tag",
wayTag.getKey(), way
+
.getTag(wayTag.getKey()), "from way", way
+ .getId());
+ }
+ way.deleteTag(wayTag.getKey());
+ }
+ }
+ }
+
+ // copy the tags to the duplicated ways
+ // and put them to the way list
+ for (Way way : mpResult) {
+ way.copyTags(copyTagWay);
+ tileWayMap.put(way.getId(), way);
+ }
+
+ // log the resulting ways
+ if (log.isDebugEnabled()) {
+ log.info("Results:");
+ for (Way way : mpResult) {
+ log.debug("-", way.getId(), way.toTagString());
+ }
+ }
+
+ }
+
+ private void cleanup() {
+ roleMap.clear();
+ }
+
+ /**
+ * Checks if this multipolygon contains reasonable tags or if the tags
must
+ * be collected from the ways.
+ *
+ * @return <code>true</code> use the tags from the relation;
+ * <code>false</code> use the tags from the ways
+ */
+ private boolean useRelationTags() {
+ for (Entry<String, String> tag : this.getEntryIteratable()) {
+ // check if there is at least one tag
+ // not equal to type=multipolygon and boundary=...
+ if ("type".equals(tag.getKey()) == false
+ && "boundary".equals(tag.getKey()) ==
false) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isOuterWay(Way way) {
+ String role = roleMap.get(way.getId());
+ return (role == null || "outer".equals(role) ||
"exclave".equals(role));
+
+ }
+
+ private void copyTagsFromOuterWays(List<Way> allWays, Way resultWay) {
+ boolean firstWay = true;
+ for (Way mpWay : allWays) {
+ if (isOuterWay(mpWay) == false) {
+ // ignore all inner ways
+ continue;
+ }
+
+ if (firstWay) {
+ resultWay.copyTags(mpWay);
+ firstWay = false;
+ } else {
+ for (Entry<String, String> resultTag : resultWay
+ .getEntryIteratable()) {
+ // check if the tags are identical
+ if (resultTag.getValue().equals(
+
mpWay.getTag(resultTag.getKey())) == false) {
+ // remove the tag if they are
not identical
+
resultWay.deleteTag(resultTag.getKey());
+ }
+ }
+ }
+ }
+ }
+
+}
Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
(revision 1634)
+++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
(working copy)
@@ -49,6 +49,7 @@
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.MultiPolygonToLineRelation;
import uk.me.parabola.mkgmap.reader.osm.Node;
import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
import uk.me.parabola.mkgmap.reader.osm.Relation;
@@ -602,8 +603,15 @@
String type = currentRelation.getTag("type");
if (type != null) {
if ("multipolygon".equals(type)) {
- Area mpBbox = (bbox != null ? bbox :
((MapDetails) collector).getBounds());
- currentRelation = new
MultiPolygonRelation(currentRelation, wayMap, mpBbox);
+ if (currentRelation.getTag("boundary") != null)
{
+ currentRelation = new
MultiPolygonToLineRelation(
+ currentRelation,
wayMap);
+ } else {
+ Area mpBbox = (bbox != null ? bbox
+ : ((MapDetails)
collector).getBounds());
+ currentRelation = new
MultiPolygonRelation(currentRelation,
+ wayMap, mpBbox);
+ }
} else if("restriction".equals(type)) {
if(ignoreTurnRestrictions)
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev