diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java index 55962bb..eeece9c 100644 --- a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java +++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5MapDataSource.java @@ -63,11 +63,10 @@ public class Osm5MapDataSource extends OsmMapDataSource { try { InputStream is = openFile(name); SAXParserFactory parserFactory = SAXParserFactory.newInstance(); - boolean ignoreBounds = getConfig().getProperty("ignore-osm-bounds", false); SAXParser parser = parserFactory.newSAXParser(); try { - Osm5XmlHandler handler = new Osm5XmlHandler(ignoreBounds); + Osm5XmlHandler handler = new Osm5XmlHandler(getConfig()); handler.setCollector(mapper); Runnable task = new Runnable() { public void run() { diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java index a94ac40..e26da92 100644 --- a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java +++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java @@ -19,6 +19,10 @@ package uk.me.parabola.mkgmap.reader.osm.xml; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import java.util.List; +import java.util.ArrayList; +import java.util.Set; +import java.util.HashSet; import uk.me.parabola.imgfmt.app.Area; import uk.me.parabola.imgfmt.app.Coord; @@ -31,6 +35,7 @@ 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.Way; +import uk.me.parabola.util.EnhancedProperties; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; @@ -53,6 +58,7 @@ class Osm5XmlHandler extends DefaultHandler { private Map wayMap = new LinkedHashMap(5000); private Map relationMap = new LinkedHashMap(); private final Map fakeIdMap = new HashMap(); + private final Map> namedWaysMap = new HashMap>(); private static final int MODE_NODE = 1; private static final int MODE_WAY = 2; @@ -71,11 +77,14 @@ class Osm5XmlHandler extends DefaultHandler { private Runnable endTask; private long nextFakeId = 1; + private final long FAKE_ID_BASE = (1L << 62); private final boolean ignoreBounds; + private final boolean makeRoadNamePOIS; - public Osm5XmlHandler(boolean ignoreBounds) { - this.ignoreBounds = ignoreBounds; + public Osm5XmlHandler(EnhancedProperties props) { + ignoreBounds = props.getProperty("ignore-osm-bounds", false); + makeRoadNamePOIS = props.getProperty("road-name-pois", false); } /** @@ -210,6 +219,16 @@ class Osm5XmlHandler extends DefaultHandler { } else if (mode == MODE_WAY) { if (qName.equals("way")) { + String wayName = currentWay.getTag("name"); + if(makeRoadNamePOIS && wayName != null) { + List l = namedWaysMap.get(wayName); + if(l == null) { + l = new ArrayList(); + namedWaysMap.put(wayName, l); + } + l.add(currentWay); + currentWay.setName(wayName); + } mode = 0; currentWay = null; // ways are processed at the end of the document, @@ -257,6 +276,11 @@ class Osm5XmlHandler extends DefaultHandler { * another exception. */ public void endDocument() throws SAXException { + + if(makeRoadNamePOIS) + for(List lw : findConnectedWaysWithSameName()) + makeRoadNamePOI(lw.get(lw.size() / 2)); + coordMap = null; for (Relation r : relationMap.values()) converter.convertRelation(r); @@ -376,11 +400,113 @@ class Osm5XmlHandler extends DefaultHandler { // if that fails, fake a (hopefully) unique value Long fakeIdVal = fakeIdMap.get(id); if(fakeIdVal == null) { - fakeIdVal = (1L << 62) + nextFakeId++; + fakeIdVal = makeFakeId(); fakeIdMap.put(id, fakeIdVal); } //System.out.printf("%s = 0x%016x\n", id, fakeIdVal); return fakeIdVal; } } + + private long makeFakeId() { + return FAKE_ID_BASE + nextFakeId++; + } + + + private boolean waysAreJoined(Way w1, Way w2) { + + if(w1 != w2) { + for(Coord c1 : w1.getPoints()) { + for(Coord c2 : w2.getPoints()) { + if(c1 == c2) + return true; + } + } + } + return false; + } + + // hairy function to build a set of lists - each list contains + // the ways that have the same name and are connected + + private Set> findConnectedWaysWithSameName() { + // wayGroups is a set to avoid duplicate groups + Set> wayGroups = new HashSet>(); + + // loop over the lists of ways that have the same name + for(List allWaysWithSameName : namedWaysMap.values()) { + // for each way that has the same name, keep track of it's group + Map> wayGroupMap = new HashMap>(); + + // loop over all of the ways with the same name + for(int i = 0; i < allWaysWithSameName.size(); ++i) { + boolean wayWasJoined = false; + for(int j = 0; j < allWaysWithSameName.size(); ++j) { + if(i != j) { + // see if these two ways are joined + Way wi = allWaysWithSameName.get(i); + Way wj = allWaysWithSameName.get(j); + if(waysAreJoined(wi, wj)) { + // yes, the're joined so put both in a group + // and associate the group with each way + wayWasJoined = true; + List group = wayGroupMap.get(wi); + if(group == null) { + group = wayGroupMap.get(wj); + if(group == null) { + group = new ArrayList(); + group.add(wi); + group.add(wj); + wayGroupMap.put(wi, group); + wayGroupMap.put(wj, group); + } + else { + group.add(wi); + wayGroupMap.put(wi, group); + } + } + else { + group.add(wj); + wayGroupMap.put(wj, group); + } + } + } + } + if(!wayWasJoined) { + // make a group with just one entry + Way wi = allWaysWithSameName.get(i); + Listgroup = new ArrayList(); + group.add(wi); + wayGroupMap.put(wi, group); + } + } + + // now add the new group(s) to the final result + for(List l : wayGroupMap.values()) + wayGroups.add(l); + } + return wayGroups; + } + + private void makeRoadNamePOI(Way way) { + List points = way.getPoints(); + int numPoints = points.size(); + Coord middleNodeCoord; + if((numPoints & 1) != 0) + middleNodeCoord = points.get(numPoints / 2); + else { + int i2 = numPoints / 2; + int i1 = i2 - 1; + middleNodeCoord = new Coord((points.get(i1).getLatitude() + + points.get(i2).getLatitude()) / 2, + (points.get(i1).getLongitude() + + points.get(i2).getLongitude()) / 2); + } + long fid = makeFakeId(); + Node middleNode = new Node(fid, middleNodeCoord); + nodeMap.put(fid, middleNode); + middleNode.addTag("name", way.getName()); + middleNode.addTag("place", "road_name_poi"); + // System.err.println("POI " + way.getName()); + } }