/* * Copyright (C) 2006 - 2012. * * 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; import java.util.HashMap; import java.util.Map; import java.util.Set; import uk.me.parabola.imgfmt.app.Area; import uk.me.parabola.imgfmt.app.Coord; /** * Base class for OSM file handlers. * * @author Steve Ratcliffe */ public class OsmHandler { // Elements that are read are saved/further processed by these two classes. protected ElementSaver saver; protected OsmReadingHooks hooks; private final Map<String, Long> fakeIdMap = new HashMap<String, Long>(); private Map<String,Set<String>> deletedTags; private Map<String, String> usedTags; // Node references within a way protected long firstNodeRef; protected long lastNodeRef; protected boolean missingNodeRef; /** * Tag that is set to <code>true</code> if one or more tags are not loaded. * Only used for multipolygons yet. */ public static final String TAGS_INCOMPLETE_TAG = "mkgmap:tagsincomplete"; /** * Set a set of tags with values that are to be deleted on input. * For each key there is a set of values. If the value set is empty then * all tags with the given key are deleted. If the value set is not empty * then only tags with the given key that has one of the given values are * deleted. * * @param deletedTags A map of tag key, to a set of values to be deleted. */ public void setTagsToDelete(Map<String, Set<String>> deletedTags) { this.deletedTags = deletedTags; } /** * This sets a list of all the tags that are used in the system. * * Assuming this list is complete, no other tag can have an effect on the output * and can therefore be dropped on input. This reduces memory usage, sometimes * dramatically if there are many useless tags in the input. * * We keep a map of tag-name to tag-name. This allows us to keep only a single * copy of each string. This also results in a reasonable reduction in memory usage. * * @param used The complete set of tags that are used to form the output. */ public void setUsedTags(Set<String> used) { if (used == null || used.isEmpty()) { usedTags = null; return; } usedTags = new HashMap<String, String>(); for (String s : used) { if (s == null) { continue; } // intern the keys s = s.intern(); usedTags.put(s, s); } } /** * Some tags are dropped at the input stage. We drop tags that are not going * to be used and there is also an option to provide a file containing tags to * be dropped. * * @param key The tag key. * @param val The tag value. * @return Returns the tag key if this tag should be kept. Returns null if the tag * should be discarded. */ protected String keepTag(String key, String val) { if(deletedTags != null) { Set<String> vals = deletedTags.get(key); if(vals != null && (vals.isEmpty() || vals.contains(val))) { return null; } } // By returning the value stored in usedTags, instead of the key, we ensure // that the same string is always used so saving some memory. if (usedTags != null) return usedTags.get(key); return key; } /** * Actually set the bounding box. The boundary values are given. */ protected void setBBox(double minlat, double minlong, double maxlat, double maxlong) { Area bbox = new Area(minlat, minlong, maxlat, maxlong); saver.setBoundingBox(bbox); } /** * Convert an id as a string to a number. If the id is not a number, then create * a unique number instead. * @param id The id as a string. Does not have to be a numeric quantity. * @return A long id, either parsed from the input, or a unique id generated internally. */ protected long idVal(String id) { try { // attempt to parse id as a number return Long.parseLong(id); } catch (NumberFormatException e) { // if that fails, fake a (hopefully) unique value Long fakeIdVal = fakeIdMap.get(id); if(fakeIdVal == null) { fakeIdVal = FakeIdGenerator.makeFakeId(); fakeIdMap.put(id, fakeIdVal); } //System.out.printf("%s = 0x%016x\n", id, fakeIdVal); return fakeIdVal; } } public void setElementSaver(ElementSaver elementSaver) { this.saver = elementSaver; } public void setHooks(OsmReadingHooks plugin) { this.hooks = plugin; } /** * Common actions to take when creating a new way. * Reset some state and create the Way object. * @param id The osm id of the new way. * @return The new Way itself. */ protected Way startWay(long id) { firstNodeRef = 0; lastNodeRef = 0; missingNodeRef = false; return new Way(id); } /** * Common actions to take when a way has been completely read by the parser. * It is saved * @param way The way that was read. */ protected void endWay(Way way) { way.setClosedInOSM(firstNodeRef == lastNodeRef); way.setComplete(!missingNodeRef); saver.addWay(way); hooks.onAddWay(way); } /** * Add a coordinate point to the way. * @param way The Way. * @param id The coordinate id. */ protected void addCoordToWay(Way way, long id) { lastNodeRef = id; if (firstNodeRef == 0) firstNodeRef = id; Coord co = saver.getCoord(id); if (co != null) { hooks.onCoordAddedToWay(way, id, co); co = saver.getCoord(id); way.addPoint(co); } else { missingNodeRef = true; } } }