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 tileWayMap; + private final Map roleMap = new HashMap(); + + public MultiPolygonToLineRelation(Relation other, Map wayMap) { + this.tileWayMap = wayMap; + + setId(other.getId()); + + if (log.isDebugEnabled()) { + log.debug("Construct multipolygon (lines) ", toBrowseURL()); + log.debug("Multipolygon tags:",toTagString()); + } + + for (Map.Entry 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 orgWays = new ArrayList(); + + for (Map.Entry 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 tag : copyTagWay.getEntryIteratable()) { + log.debug("-", tag.getKey(), tag.getValue()); + } + } + + Iterable> 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 mpResult = new ArrayList(); + 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 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 true use the tags from the relation; + * false use the tags from the ways + */ + private boolean useRelationTags() { + for (Entry 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 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 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)