/* * Copyright (C) 2006, 2011. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 or * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ package uk.me.parabola.mkgmap.reader.osm.boundary; import java.util.ArrayList; import java.util.Collections; import java.util.Map.Entry; import uk.me.parabola.log.Logger; import uk.me.parabola.mkgmap.build.Locator; import uk.me.parabola.mkgmap.reader.osm.Element; import uk.me.parabola.mkgmap.reader.osm.ElementSaver; import uk.me.parabola.mkgmap.reader.osm.Node; import uk.me.parabola.mkgmap.reader.osm.OsmConverter; import uk.me.parabola.mkgmap.reader.osm.Relation; import uk.me.parabola.mkgmap.reader.osm.Tags; import uk.me.parabola.mkgmap.reader.osm.Way; import uk.me.parabola.util.EnhancedProperties; /** * This saver only keeps ways with <code>natural=coastline</code> tags. This is * used for loading of extra coastline files. * * @author WanMil */ public class BoundaryElementSaver extends ElementSaver { private static final Logger log = Logger.getLogger(BoundaryElementSaver.class); private final static Locator locator = new Locator(); private final BoundarySaver saver; public BoundaryElementSaver(EnhancedProperties args, BoundarySaver saver) { super(args); this.saver = saver; } /** * Checks if the given element is an administrative boundary or a * postal code area. * @param element an element * @return <code>true</code> administrative boundary or postal code; * <code>false</code> element cannot be used for precompiled bounds */ public static boolean isBoundary(Element element) { if (element instanceof Relation) { String type = element.getTag("type"); if ("boundary".equals(type) || "multipolygon".equals(type)) { String boundaryVal = element.getTag("boundary"); if ("administrative".equals(boundaryVal)) { // for boundary=administrative the admin_level must be set if (element.getTag("admin_level") == null) { return false; } // Check for admin_level==2 if the name is known in the LocatorConfig.xml. // This should abandon all non country admin_level 2 boundaries if (element.getTag("admin_level").equals("2")) { Tags copyTags = new Tags(); for (Entry<String,String> tag : element.getTagEntryIterator()) { copyTags.put(tag.getKey(), tag.getValue()); } String iso = locator.getCountryISOCode(copyTags); if (iso == null) { log.warn("Ignore admin_level 2 element:", element.toBrowseURL(), element.toTagString()); return false; } } // and a name must be set (check only for a tag containing name for (Entry<String,String> tag : element.getTagEntryIterator()) { if (tag.getKey().contains("name")) { return true; } } // does not contain a name tag => do not use it return false; } else if ("postal_code".equals(boundaryVal)) { // perform a positive check // is postal_code set? if (element.getTag("postal_code") != null) { return true; } // and a name must be set (check only for a tag containing name for (Entry<String,String> tag : element.getTagEntryIterator()) { if (tag.getKey().contains("name")) { return true; } } // does not contain a name tag => do not use it return false; } else if (element.getTag("postal_code") != null){ return true; } else { return false; } } else { return false; } } else if (element instanceof Way) { Way w = (Way) element; // a single way must be closed if (w.isClosedInOSM() == false) { return false; } // the boundary tag must be "administrative" or "postal_code" String boundaryVal = element.getTag("boundary"); if ("administrative".equals(boundaryVal)) { // for boundary=administrative the admin_level must be set if (element.getTag("admin_level") == null) { return false; } // Check for admin_level==2 if the name is known in the LocatorConfig.xml. // This should abandon all non country admin_level 2 boundaries if (element.getTag("admin_level").equals("2")) { Tags copyTags = new Tags(); for (Entry<String,String> tag : element.getTagEntryIterator()) { copyTags.put(tag.getKey(), tag.getValue()); } String iso = locator.getCountryISOCode(copyTags); if (iso == null) { log.warn("Ignore admin_level 2 element:", element.toBrowseURL(), element.toTagString()); return false; } } // and a name must be set (check only for a tag containing name) for (Entry<String,String> tag : element.getTagEntryIterator()) { if (tag.getKey().contains("name")) { return true; } } // does not contain a name tag => do not use it return false; } else if ( "postal_code".equals(boundaryVal)) { // the name tag must be set for it return element.getTag("name") != null; } else if (element.getTag("postal_code") != null) { // postal_code as tag return true; } else { return false; } } else { return false; } } public void addRelation(Relation rel) { if (isBoundary(rel)) { BoundaryRelation bRel = (BoundaryRelation) createMultiPolyRelation(rel); bRel.processElements(); Boundary b = bRel.getBoundary(); if (b != null) saver.addBoundary(b); } else { log.warn("Relation is not processed due to missing tags:", rel.getId(), rel.toTagString()); } } public void deferRelation(long id, Relation rel, String role) { return; } public Relation createMultiPolyRelation(Relation rel) { return new BoundaryRelation(rel, wayMap, getBoundingBox()); } public void addNode(Node node) { return; } public void convert(OsmConverter converter) { nodeMap = null; converter.setBoundingBox(getBoundingBox()); ArrayList<Relation> relations = new ArrayList<Relation>( relationMap.values()); relationMap = null; Collections.reverse(relations); for (int i = relations.size() - 1; i >= 0; i--) { converter.convertRelation(relations.get(i)); relations.remove(i); } for (Way w : wayMap.values()) converter.convertWay(w); wayMap = null; converter.end(); relationMap = null; } }