package de.blau.android.util; import java.util.HashMap; import java.util.Map; import android.util.Log; import de.blau.android.App; import de.blau.android.exception.OsmException; import de.blau.android.osm.Node; import de.blau.android.osm.StorageDelegator; import de.blau.android.osm.Tags; import de.blau.android.osm.Way; import de.blau.android.util.collections.MultiHashMap; public class ElementSearch { private static final String DEBUG_PLACE_TAG = "PlaceTagValues..."; private static final String DEBUG_STREET_TAG = "StreetTagValues..."; private static final double MAX_DISTANCE = 20000D; // this is just a very rough number to stop including stuff that is very far away private String[] streetNames = null; private Map<String, Long> idsByStreetNames = new HashMap<String, Long>(); private String[] placeNames = null; private Map<String, Long> idsByPlaceNames = new HashMap<String, Long>(); private Map<String, String> typeByPlaceNames = new HashMap<String, String>(); private final int[] location; private final boolean distanceFilter; public ElementSearch(final int[] location, boolean distanceFilter) { this.location = location; this.distanceFilter = distanceFilter; } /** * Get all distance sorted street-names in the area * @param location position we want the names nearby to * @return all street-names */ private String[] getStreetArray(final int[] location) { // build list of names with their closest distance to location final StorageDelegator delegator = App.getDelegator(); Map<String, Double> distancesByNames = new HashMap<String, Double>(); String[] nameTags = {Tags.KEY_NAME, Tags.KEY_OFFICIAL_NAME, Tags.KEY_ALT_NAME, Tags.KEY_NAME_LEFT, Tags.KEY_NAME_RIGHT}; for (Way way : delegator.getCurrentStorage().getWays()) { if (way.getTagWithKey(Tags.KEY_HIGHWAY) != null) { double distance = -1D; long iD = way.getOsmId(); for (String tag:nameTags) { // Log.d("StreetTagValueAutocompletionAdapter","Search for " + tag); String name = way.getTagWithKey(tag); if (name != null) { // Log.d("StreetTagValueAutocompletionAdapter","Name " + name); if (distance == -1D) { // only calc once distance = way.getDistance(location); if (distanceFilter && distance > MAX_DISTANCE) { break; } // Log.d("ElementSearch","distance " + distance); } if (distancesByNames.containsKey(name)) { // way already in list - keep shortest distance if (distance < distancesByNames.get(name)) { distancesByNames.put(name, distance); idsByStreetNames.put(name,Long.valueOf(iD)); } } else { distancesByNames.put(name, distance); idsByStreetNames.put(name,Long.valueOf(iD)); } } } } } // sort names by distance MultiHashMap<Double, String> retval = new MultiHashMap<Double, String>(true); // true == sorted for (String name : distancesByNames.keySet()) { retval.add(distancesByNames.get(name), name); } return retval.getValues().toArray(new String[retval.getValues().size()]); } public synchronized String[] getStreetNames() { if (streetNames == null) { streetNames = getStreetArray(location); } return streetNames; } public long getStreetId(String name) throws OsmException { if (streetNames == null) { streetNames = getStreetArray(location); } Log.d(DEBUG_STREET_TAG,"looking for " + name); Long iD = idsByStreetNames.get(name); if (iD != null) { return iD.longValue(); } else { throw new OsmException("way not found in adapter"); } } /** * Get all distance sorted place-names in the area * @param location * @return all place-names */ private String[] getPlaceArray(final int[] location) { // build list of names with their closest distance to location final StorageDelegator delegator = App.getDelegator(); Map<String, Double> distancesByName = new HashMap<String, Double>(); String[] nameTags = {Tags.KEY_NAME, Tags.KEY_OFFICIAL_NAME, Tags.KEY_ALT_NAME}; Log.d(DEBUG_PLACE_TAG,"searching for place ways..."); for (Way way : delegator.getCurrentStorage().getWays()) { if (way.getTagWithKey(Tags.KEY_PLACE) != null) { double distance = -1D; long iD = way.getOsmId(); for (String tag:nameTags) { String name = way.getTagWithKey(tag); if (name != null) { if (distance == -1D) { // only calc once distance = way.getDistance(location); if (distanceFilter && distance > MAX_DISTANCE) { break; } } if (distancesByName.containsKey(name)) { // way already in list - keep shortest distance if (distance < distancesByName.get(name)) { distancesByName.put(name, distance); idsByPlaceNames.put(name,Long.valueOf(iD)); typeByPlaceNames.put(name,Way.NAME); } } else { distancesByName.put(name, distance); idsByPlaceNames.put(name,Long.valueOf(iD)); typeByPlaceNames.put(name,Way.NAME); } } } } } Log.d(DEBUG_PLACE_TAG,"searching for place nodes..."); for (Node node : delegator.getCurrentStorage().getNodes()) { if (node.getTagWithKey(Tags.KEY_PLACE) != null) { double distance = -1D; long iD = node.getOsmId(); for (String tag:nameTags) { String name = node.getTagWithKey(tag); Log.d(DEBUG_PLACE_TAG,"adding " + name); if (name != null) { if (distance == -1D) { // only calc once distance = node.getDistance(location); if (distanceFilter && distance > MAX_DISTANCE) { break; } } if (distancesByName.containsKey(name)) { // way already in list - keep shortest distance if (distance < distancesByName.get(name)) { distancesByName.put(name, distance); idsByPlaceNames.put(name,Long.valueOf(iD)); typeByPlaceNames.put(name,Node.NAME); } } else { distancesByName.put(name, distance); idsByPlaceNames.put(name,Long.valueOf(iD)); typeByPlaceNames.put(name,Node.NAME); } } } } } // sort names by distance MultiHashMap<Double, String> retval = new MultiHashMap<Double, String>(true); for (String name : distancesByName.keySet()) { retval.add(distancesByName.get(name), name); } return retval.getValues().toArray(new String[retval.getValues().size()]); } public String[] getPlaceNames() { if (placeNames == null) { placeNames = getPlaceArray(location); } return placeNames; } public long getPlaceId(String name) throws OsmException { Log.d(DEBUG_PLACE_TAG,"looking for " + name); if (placeNames == null) { placeNames = getPlaceArray(location); } Long iD = idsByPlaceNames.get(name); if (iD != null) { return iD.longValue(); } else { throw new OsmException("object not found in adapter"); } } }