package org.osmdroid.location; import java.net.URLEncoder; import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.oscim.core.BoundingBox; import org.oscim.core.GeoPoint; import org.osmdroid.utils.BonusPackHelper; import android.graphics.Bitmap; import android.util.Log; /** * POI Provider using Nominatim service. <br> * See https://wiki.openstreetmap.org/wiki/Nominatim<br> * and http://open.mapquestapi.com/nominatim/<br> * @author M.Kergall */ public class NominatimPOIProvider implements POIProvider { /* As the doc lacks a lot of features, source code may help: * https://trac.openstreetmap * .org/browser/applications/utils/nominatim/website/search.php featuretype= * to select on feature type (country, city, state, settlement)<br> * format=jsonv2 to get a place_rank<br> offset= to offset the result ?... * <br> polygon=1 to get the border of the poi as a polygon<br> nearlat & * nearlon = ???<br> routewidth/69 and routewidth/30 ???<br> */ public static final String MAPQUEST_POI_SERVICE = "http://open.mapquestapi.com/nominatim/v1/"; public static final String NOMINATIM_POI_SERVICE = "http://nominatim.openstreetmap.org/"; protected String mService; public NominatimPOIProvider() { mService = NOMINATIM_POI_SERVICE; } public void setService(String serviceUrl) { mService = serviceUrl; } @SuppressWarnings("deprecation") private StringBuffer getCommonUrl(String type, int maxResults) { StringBuffer urlString = new StringBuffer(mService); urlString.append("search?"); urlString.append("format=json"); urlString.append("&q=" + URLEncoder.encode(type)); urlString.append("&limit=" + maxResults); //urlString.append("&bounded=1"); // urlString.append("&addressdetails=0"); return urlString; } private String getUrlInside(BoundingBox bb, String type, int maxResults) { StringBuffer urlString = getCommonUrl(type, maxResults); urlString.append("&viewbox=" + bb.getMaxLongitude() + "," + bb.getMaxLatitude() + "," + bb.getMinLongitude() + "," + bb.getMinLatitude()); return urlString.toString(); } private String getUrlCloseTo(GeoPoint p, String type, int maxResults, double maxDistance) { int maxD = (int) (maxDistance * 1E6); BoundingBox bb = new BoundingBox(p.latitudeE6 + maxD, p.longitudeE6 + maxD, p.latitudeE6 - maxD, p.longitudeE6 - maxD); return getUrlInside(bb, type, maxResults); } /** * @param url * full URL request * @return the list of POI, of null if technical issue. */ public ArrayList<POI> getThem(String url) { Log.d(BonusPackHelper.LOG_TAG, "NominatimPOIProvider:get:" + url); String jString = BonusPackHelper.requestStringFromUrl(url); if (jString == null) { Log.e(BonusPackHelper.LOG_TAG, "NominatimPOIProvider: request failed."); return null; } try { JSONArray jPlaceIds = new JSONArray(jString); int n = jPlaceIds.length(); ArrayList<POI> pois = new ArrayList<POI>(n); Bitmap thumbnail = null; for (int i = 0; i < n; i++) { JSONObject jPlace = jPlaceIds.getJSONObject(i); POI poi = new POI(POI.POI_SERVICE_NOMINATIM); poi.id = jPlace.getString("osm_id"); // jPlace.optLong("osm_id"); poi.location = new GeoPoint(jPlace.getDouble("lat"), jPlace.getDouble("lon")); JSONArray bbox = jPlace.optJSONArray("boundingbox"); if (bbox != null) { try { poi.bbox = new BoundingBox(bbox.getDouble(0), bbox.getDouble(2), bbox.getDouble(1), bbox.getDouble(3)); } catch (Exception e) { Log.d("NominatimPOIProvider", "could not parse " + bbox); } //Log.d("NominatimPOIProvider", "bbox " + poi.bbox); } poi.category = jPlace.optString("class"); poi.type = jPlace.getString("type"); poi.description = jPlace.optString("display_name"); poi.thumbnailPath = jPlace.optString("icon", null); if (i == 0 && poi.thumbnailPath != null) { //first POI, and we have a thumbnail: load it thumbnail = BonusPackHelper.loadBitmap(poi.thumbnailPath); } poi.thumbnail = thumbnail; pois.add(poi); } return pois; } catch (JSONException e) { e.printStackTrace(); return null; } } /** * @param position * ... * @param type * an OpenStreetMap feature. See * http://wiki.openstreetmap.org/wiki/Map_Features or * http://code.google.com/p/osmbonuspack/source/browse/trunk/ * OSMBonusPackDemo/res/values/poi_tags.xml * @param maxResults * the maximum number of POI returned. Note that in any case, * Nominatim will have an absolute maximum of 100. * @param maxDistance * to the position, in degrees. Note that it is used to build a * bounding box around the position, not a circle. * @return the list of POI, null if technical issue. */ public ArrayList<POI> getPOICloseTo(GeoPoint position, String type, int maxResults, double maxDistance) { String url = getUrlCloseTo(position, type, maxResults, maxDistance); return getThem(url); } /** * @param boundingBox * ... * @param type * OpenStreetMap feature * @param maxResults * ... * @return list of POIs, null if technical issue. */ public ArrayList<POI> getPOIInside(BoundingBox boundingBox, String type, int maxResults) { String url = getUrlInside(boundingBox, type, maxResults); return getThem(url); } public ArrayList<POI> getPOI(String query, int maxResults) { String url = getCommonUrl(query, maxResults).toString(); return getThem(url); } /** * @param path * Warning: a long path may cause a failure due to the url to be * too long. Using a simplified route may help (see * Road.getRouteLow()). * @param type * OpenStreetMap feature * @param maxResults * ... * @param maxWidth * to the path. Certainly not in degrees. Probably in km. * @return list of POIs, null if technical issue. */ public ArrayList<POI> getPOIAlong(ArrayList<GeoPoint> path, String type, int maxResults, double maxWidth) { StringBuffer urlString = getCommonUrl(type, maxResults); urlString.append("&routewidth=" + maxWidth); urlString.append("&route="); boolean isFirst = true; for (GeoPoint p : path) { if (isFirst) isFirst = false; else urlString.append(","); String lat = Double.toString(p.getLatitude()); lat = lat.substring(0, Math.min(lat.length(), 7)); String lon = Double.toString(p.getLongitude()); lon = lon.substring(0, Math.min(lon.length(), 7)); urlString.append(lat + "," + lon); //limit the size of url as much as possible, as post method is not supported. } return getThem(urlString.toString()); } }