在室外使用手机查询附近的兴趣点,采用的开源的osmdroid,实现POI的查询的几种开源方案:
1.采用FlickrPOIProvider实现:
POI Provider using Flickr service to get geolocalized photos.
@see http://www.flickr.com/services/api/flickr.photos.search.html
package org.osmdroid.bonuspack.location;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import android.util.Log;
/**
* POI Provider using Flickr service to get geolocalized photos.
* @see http://www.flickr.com/services/api/flickr.photos.search.html
* @author M.Kergall
*/
public class FlickrPOIProvider {
protected String mApiKey;
/**
* @param apiKey the registered API key to give to Flickr service.
* @see http://www.flickr.com/help/api/
*/
public FlickrPOIProvider(String apiKey){
mApiKey = apiKey;
}
private String getUrlInside(BoundingBoxE6 boundingBox, int maxResults){
StringBuffer url = new StringBuffer("http://api.flickr.com/services/rest/?method=flickr.photos.search");
url.append("&api_key="+mApiKey);
url.append("&bbox="+boundingBox.getLonWestE6()*1E-6);
url.append(","+boundingBox.getLatSouthE6()*1E-6);
url.append(","+boundingBox.getLonEastE6()*1E-6);
url.append(","+boundingBox.getLatNorthE6()*1E-6);
url.append("&has_geo=1");
url.append("&format=json&nojsoncallback=1");
url.append("&per_page="+maxResults);
//From Flickr doc: "Geo queries require some sort of limiting agent in order to prevent the database from crying."
//And min_date_upload is considered as a limiting agent. So:
url.append("&min_upload_date=2005/01/01");
//Ask to provide some additional attributes we will need:
url.append("&extras=geo,url_sq");
url.append("&sort=interestingness-desc");
return url.toString();
}
/*
public POI getPhoto(String photoId){
String url = "http://api.flickr.com/services/rest/?method=flickr.photos.getInfo"
+ "&api_key=" + mApiKey
+ "&photo_id=" + photoId
+ "&format=json&nojsoncallback=1";
Log.d(BonusPackHelper.LOG_TAG, "getPhoto:"+url);
String jString = BonusPackHelper.requestStringFromUrl(url);
if (jString == null) {
Log.e(BonusPackHelper.LOG_TAG, "FlickrPOIProvider: request failed.");
return null;
}
try {
POI poi = new POI(POI.POI_SERVICE_FLICKR);
JSONObject jRoot = new JSONObject(jString);
JSONObject jPhoto = jRoot.getJSONObject("photo");
JSONObject jLocation = jPhoto.getJSONObject("location");
poi.mLocation = new GeoPoint(
jLocation.getDouble("latitude"),
jLocation.getDouble("longitude"));
poi.mId = Long.parseLong(photoId);
JSONObject jTitle = jPhoto.getJSONObject("title");
poi.mType = jTitle.getString("_content");
JSONObject jDescription = jPhoto.getJSONObject("description");
poi.mDescription = jDescription.getString("_content");
//truncate description if too long:
if (poi.mDescription.length() > 300){
poi.mDescription = poi.mDescription.substring(0, 300) + " (...)";
}
String farm = jPhoto.getString("farm");
String server = jPhoto.getString("server");
String secret = jPhoto.getString("secret");
JSONObject jOwner = jPhoto.getJSONObject("owner");
String nsid = jOwner.getString("nsid");
poi.mThumbnailPath = "http://farm"+farm+".staticflickr.com/"+server+"/"+photoId+"_"+secret+"_s.jpg";
poi.mUrl = "http://www.flickr.com/photos/"+nsid+"/"+photoId;
return poi;
}catch (JSONException e) {
e.printStackTrace();
return null;
}
}
*/
/**
* @param fullUrl
* @return the list of POI
*/
public ArrayList<POI> getThem(String fullUrl){
//for local debug: fullUrl = "http://10.0.2.2/flickr_mockup.json";
Log.d(BonusPackHelper.LOG_TAG, "FlickrPOIProvider:get:"+fullUrl);
String jString = BonusPackHelper.requestStringFromUrl(fullUrl);
if (jString == null) {
Log.e(BonusPackHelper.LOG_TAG, "FlickrPOIProvider: request failed.");
return null;
}
try {
JSONObject jRoot = new JSONObject(jString);
JSONObject jPhotos = jRoot.getJSONObject("photos");
JSONArray jPhotoArray = jPhotos.getJSONArray("photo");
int n = jPhotoArray.length();
ArrayList<POI> pois = new ArrayList<POI>(n);
for (int i=0; i<n; i++){
JSONObject jPhoto = jPhotoArray.getJSONObject(i);
String photoId = jPhoto.getString("id");
POI poi = new POI(POI.POI_SERVICE_FLICKR);
poi.mLocation = new GeoPoint(
jPhoto.getDouble("latitude"),
jPhoto.getDouble("longitude"));
poi.mId = Long.parseLong(photoId);
poi.mType = jPhoto.getString("title");
poi.mThumbnailPath = jPhoto.getString("url_sq");
String owner = jPhoto.getString("owner");
poi.mUrl = "http://www.flickr.com/photos/"+owner+"/"+photoId;
pois.add(poi);
}
int total = jPhotos.getInt("total");
Log.d(BonusPackHelper.LOG_TAG, "done:"+n+" got, on a total of:"+total);
return pois;
}catch (JSONException e) {
e.printStackTrace();
return null;
}
}
/**
* @param boundingBox
* @param maxResults
* @return list of POI, Flickr photos inside the bounding box. Null if technical issue.
*/
public ArrayList<POI> getPOIInside(BoundingBoxE6 boundingBox, int maxResults){
String url = getUrlInside(boundingBox, maxResults);
return getThem(url);
}
}
2。采用GeoNames services实现:
package org.osmdroid.bonuspack.location;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.bonuspack.utils.HttpConnection;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
/**
* POI Provider using GeoNames services.
* Currently, "find Nearby Wikipedia" and "Wikipedia Articles in Bounding Box" services.
* @see http://www.geonames.org
* @author M.Kergall
*/
public class GeoNamesPOIProvider {
protected String mUserName;
/**
* @param account the registered "username" to give to GeoNames service.
* @see http://www.geonames.org/login
*/
public GeoNamesPOIProvider(String account){
mUserName = account;
}
private String getUrlCloseTo(GeoPoint p, int maxResults, double maxDistance){
StringBuffer url = new StringBuffer("http://api.geonames.org/findNearbyWikipediaJSON?");
url.append("lat="+p.getLatitudeE6()*1E-6);
url.append("&lng="+p.getLongitudeE6()*1E-6);
url.append("&maxRows="+maxResults);
url.append("&radius="+maxDistance); //km
url.append("&lang="+Locale.getDefault().getLanguage());
url.append("&username="+mUserName);
return url.toString();
}
private String getUrlInside(BoundingBoxE6 boundingBox, int maxResults){
StringBuffer url = new StringBuffer("http://api.geonames.org/wikipediaBoundingBoxJSON?");
url.append("south="+boundingBox.getLatSouthE6()*1E-6);
url.append("&north="+boundingBox.getLatNorthE6()*1E-6);
url.append("&east="+boundingBox.getLonEastE6()*1E-6);
url.append("&west="+boundingBox.getLonWestE6()*1E-6);
url.append("&maxRows="+maxResults);
url.append("&lang="+Locale.getDefault().getLanguage());
url.append("&username="+mUserName);
return url.toString();
}
/**
* @param fullUrl
* @return the list of POI
*/
public ArrayList<POI> getThem(String fullUrl){
Log.d(BonusPackHelper.LOG_TAG, "GeoNamesPOIProvider:get:"+fullUrl);
String jString = BonusPackHelper.requestStringFromUrl(fullUrl);
if (jString == null) {
Log.e(BonusPackHelper.LOG_TAG, "GeoNamesPOIProvider: request failed.");
return null;
}
try {
JSONObject jRoot = new JSONObject(jString);
JSONArray jPlaceIds = jRoot.getJSONArray("geonames");
int n = jPlaceIds.length();
ArrayList<POI> pois = new ArrayList<POI>(n);
for (int i=0; i<n; i++){
JSONObject jPlace = jPlaceIds.getJSONObject(i);
POI poi = new POI(POI.POI_SERVICE_GEONAMES_WIKIPEDIA);
poi.mLocation = new GeoPoint(jPlace.getDouble("lat"),
jPlace.getDouble("lng"));
poi.mCategory = jPlace.optString("feature");
poi.mType = jPlace.getString("title");
poi.mDescription = jPlace.optString("summary");
poi.mThumbnailPath = jPlace.optString("thumbnailImg", null);
/* This makes loading too long.
* Thumbnail loading will be done only when needed, with POI.getThumbnail()
if (poi.mThumbnailPath != null){
poi.mThumbnail = BonusPackHelper.loadBitmap(poi.mThumbnailPath);
}
*/
poi.mUrl = jPlace.optString("wikipediaUrl", null);
if (poi.mUrl != null)
poi.mUrl = "http://" + poi.mUrl;
poi.mRank = jPlace.optInt("rank", 0);
//other attributes: distance?
pois.add(poi);
}
Log.d(BonusPackHelper.LOG_TAG, "done");
return pois;
}catch (JSONException e) {
e.printStackTrace();
return null;
}
}
//XML parsing seems 2 times slower than JSON parsing
public ArrayList<POI> getThemXML(String fullUrl){
Log.d(BonusPackHelper.LOG_TAG, "GeoNamesPOIProvider:get:"+fullUrl);
HttpConnection connection = new HttpConnection();
connection.doGet(fullUrl);
InputStream stream = connection.getStream();
if (stream == null){
return null;
}
GeoNamesXMLHandler handler = new GeoNamesXMLHandler();
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(stream, handler);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
connection.close();
Log.d(BonusPackHelper.LOG_TAG, "done");
return handler.mPOIs;
}
/**
* @param position
* @param maxResults
* @param maxDistance in km. 20 km max for the free service.
* @return list of POI, Wikipedia entries close to the position. Null if technical issue.
*/
public ArrayList<POI> getPOICloseTo(GeoPoint position,
int maxResults, double maxDistance){
String url = getUrlCloseTo(position, maxResults, maxDistance);
return getThem(url);
}
/**
* @param boundingBox
* @param maxResults
* @return list of POI, Wikipedia entries inside the bounding box. Null if technical issue.
*/
public ArrayList<POI> getPOIInside(BoundingBoxE6 boundingBox, int maxResults){
String url = getUrlInside(boundingBox, maxResults);
return getThem(url);
}
}
class GeoNamesXMLHandler extends DefaultHandler {
private String mString;
double mLat, mLng;
POI mPOI;
ArrayList<POI> mPOIs;
public GeoNamesXMLHandler() {
mPOIs = new ArrayList<POI>();
}
@Override public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if (localName.equals("entry")){
mPOI = new POI(POI.POI_SERVICE_GEONAMES_WIKIPEDIA);
}
mString = new String();
}
@Override public void characters(char[] ch, int start, int length)
throws SAXException {
String chars = new String(ch, start, length);
mString = mString.concat(chars);
}
@Override public void endElement(String uri, String localName, String name)
throws SAXException {
if (localName.equals("lat")) {
mLat = Double.parseDouble(mString);
} else if (localName.equals("lng")) {
mLng = Double.parseDouble(mString);
} else if (localName.equals("feature")){
mPOI.mCategory = mString;
} else if (localName.equals("title")){
mPOI.mType = mString;
} else if (localName.equals("summary")){
mPOI.mDescription = mString;
} else if (localName.equals("thumbnailImg")){
if (mString != null && !mString.equals(""))
mPOI.mThumbnailPath = mString;
} else if (localName.equals("wikipediaUrl")){
if (mString != null && !mString.equals(""))
mPOI.mUrl = "http://" + mString;
} else if (localName.equals("rank")){
mPOI.mRank = Integer.parseInt(mString);
} else if (localName.equals("entry")) {
mPOI.mLocation = new GeoPoint(mLat, mLng);
mPOIs.add(mPOI);
};
}
}
3.采用 Nominatim service
package org.osmdroid.bonuspack.location;
import java.net.URLEncoder;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
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 {
/*
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;
}
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");
return urlString;
}
private String getUrlInside(BoundingBoxE6 bb, String type, int maxResults){
StringBuffer urlString = getCommonUrl(type, maxResults);
urlString.append("&viewbox="+bb.getLonWestE6()*1E-6+","
+bb.getLatNorthE6()*1E-6+","
+bb.getLonEastE6()*1E-6+","
+bb.getLatSouthE6()*1E-6);
return urlString.toString();
}
private String getUrlCloseTo(GeoPoint p, String type,
int maxResults, double maxDistance){
int maxD = (int)(maxDistance*1E6);
BoundingBoxE6 bb = new BoundingBoxE6(p.getLatitudeE6()+maxD,
p.getLongitudeE6()+maxD,
p.getLatitudeE6()-maxD,
p.getLongitudeE6()-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.mId = jPlace.optLong("osm_id");
poi.mLocation = new GeoPoint(jPlace.getDouble("lat"),
jPlace.getDouble("lon"));
poi.mCategory = jPlace.optString("class");
poi.mType = jPlace.getString("type");
poi.mDescription = jPlace.optString("display_name");
poi.mThumbnailPath = jPlace.optString("icon", null);
if (i==0 && poi.mThumbnailPath != null) {
//first POI, and we have a thumbnail: load it
thumbnail = BonusPackHelper.loadBitmap(poi.mThumbnailPath);
}
poi.mThumbnail = 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(BoundingBoxE6 boundingBox, String type, int maxResults){
String url = getUrlInside(boundingBox, type, maxResults);
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.getLatitudeE6()*1E-6);
lat = lat.substring(0, Math.min(lat.length(), 7));
String lon = Double.toString(p.getLongitudeE6()*1E-6);
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());
}
}
4.采用PicasaPOIProvider实现:
package org.osmdroid.bonuspack.location;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.osmdroid.bonuspack.utils.BonusPackHelper;
import org.osmdroid.bonuspack.utils.HttpConnection;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
/**
* POI Provider using Picasa service.
* @see https://developers.google.com/picasa-web/docs/2.0/reference
* @author M.Kergall
*/
public class PicasaPOIProvider {
String mAccessToken;
/**
* @param accessToken the account to give to the service. Null for public access.
* @see https://developers.google.com/picasa-web/docs/2.0/developers_guide_protocol#CreatingAccount
*/
public PicasaPOIProvider(String accessToken){
mAccessToken = accessToken;
}
private String getUrlInside(BoundingBoxE6 boundingBox, int maxResults){
StringBuffer url = new StringBuffer("http://picasaweb.google.com/data/feed/api/all?");
url.append("bbox="+boundingBox.getLonWestE6()*1E-6);
url.append(","+boundingBox.getLatSouthE6()*1E-6);
url.append(","+boundingBox.getLonEastE6()*1E-6);
url.append(","+boundingBox.getLatNorthE6()*1E-6);
url.append("&max-results="+maxResults);
url.append("&thumbsize=64c"); //thumbnail size: 64, cropped.
url.append("&fields=entry(title,summary,media:group,gphoto:id,georss:where,link)");
if (mAccessToken != null){
//TODO: warning: not tested...
url.append("&access_token="+mAccessToken);
}
return url.toString();
}
public ArrayList<POI> getThem(String fullUrl){
Log.d(BonusPackHelper.LOG_TAG, "PicasaPOIProvider:get:"+fullUrl);
HttpConnection connection = new HttpConnection();
connection.doGet(fullUrl);
InputStream stream = connection.getStream();
if (stream == null){
return null;
}
PicasaXMLHandler handler = new PicasaXMLHandler();
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.getXMLReader().setFeature("http://xml.org/sax/features/namespaces", false);
parser.getXMLReader().setFeature("http://xml.org/sax/features/namespace-prefixes", true);
parser.parse(stream, handler);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
connection.close();
Log.d(BonusPackHelper.LOG_TAG, "done");
return handler.mPOIs;
}
/**
* @param boundingBox
* @param maxResults
* @return list of POI, Picasa photos inside the bounding box. Null if technical issue.
*/
public ArrayList<POI> getPOIInside(BoundingBoxE6 boundingBox, int maxResults){
String url = getUrlInside(boundingBox, maxResults);
return getThem(url);
}
}
class PicasaXMLHandler extends DefaultHandler {
private String mString;
double mLat, mLng;
POI mPOI;
ArrayList<POI> mPOIs;
public PicasaXMLHandler() {
mPOIs = new ArrayList<POI>();
}
@Override public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (qName.equals("entry")){
mPOI = new POI(POI.POI_SERVICE_PICASA);
} else if(qName.equals("media:thumbnail")){
mPOI.mThumbnailPath = attributes.getValue("url");
} else if (qName.equals("link")){
String rel = attributes.getValue("rel");
if ("http://schemas.google.com/photos/2007#canonical".equals(rel)){
mPOI.mUrl = attributes.getValue("href");
}
}
mString = new String();
}
@Override public void characters(char[] ch, int start, int length)
throws SAXException {
String chars = new String(ch, start, length);
mString = mString.concat(chars);
}
@Override public void endElement(String uri, String localName, String qName)
throws SAXException {
if (qName.equals("gml:pos")) {
String[] coords = mString.split(" ");
mLat = Double.parseDouble(coords[0]);
mLng = Double.parseDouble(coords[1]);
} else if (qName.equals("gphoto:id")){
mPOI.mId = Long.parseLong(mString);
} else if (qName.equals("media:title")){
mPOI.mType = mString;
} else if (qName.equals("summary")){
mPOI.mDescription = mString;
} else if (qName.equals("entry")) {
mPOI.mLocation = new GeoPoint(mLat, mLng);
mPOIs.add(mPOI);
mPOI = null;
};
}
}
5.采用基于 OpenStreetMap data and Nominatim 的API
package org.osmdroid.bonuspack.location;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.osmdroid.bonuspack.utils.BonusPackHelper;
import android.content.Context;
import android.location.Address;
import android.util.Log;
/**
* Implements an equivalent to Android Geocoder class, based on OpenStreetMap data and Nominatim API. <br>
* See http://wiki.openstreetmap.org/wiki/Nominatim
* or http://open.mapquestapi.com/nominatim/
* @author M.Kergall
*/
public class GeocoderNominatim {
public static final String NOMINATIM_SERVICE_URL = "http://nominatim.openstreetmap.org/";
public static final String MAPQUEST_SERVICE_URL = "http://open.mapquestapi.com/nominatim/v1/";
protected Locale mLocale;
protected String mServiceUrl;
protected void init(Context context, Locale locale){
mLocale = locale;
setService(NOMINATIM_SERVICE_URL); //default service
}
public GeocoderNominatim(Context context, Locale locale){
init(context, locale);
}
public GeocoderNominatim(Context context){
init(context, Locale.getDefault());
}
static public boolean isPresent(){
return true;
}
/**
* Specify the url of the Nominatim service provider to use.
* Can be one of the predefined (NOMINATIM_SERVICE_URL or MAPQUEST_SERVICE_URL),
* or another one, your local instance of Nominatim for instance.
*/
public void setService(String serviceUrl){
mServiceUrl = serviceUrl;
}
/**
* Build an Android Address object from the Nominatim address in JSON format.
* Current implementation is mainly targeting french addresses,
* and will be quite basic on other countries.
*/
protected Address buildAndroidAddress(JSONObject jResult) throws JSONException{
Address gAddress = new Address(mLocale);
gAddress.setLatitude(jResult.getDouble("lat"));
gAddress.setLongitude(jResult.getDouble("lon"));
JSONObject jAddress = jResult.getJSONObject("address");
int addressIndex = 0;
if (jAddress.has("road")){
gAddress.setAddressLine(addressIndex++, jAddress.getString("road"));
gAddress.setThoroughfare(jAddress.getString("road"));
}
if (jAddress.has("suburb")){
//gAddress.setAddressLine(addressIndex++, jAddress.getString("suburb"));
//not kept => often introduce "noise" in the address.
gAddress.setSubLocality(jAddress.getString("suburb"));
}
if (jAddress.has("postcode")){
gAddress.setAddressLine(addressIndex++, jAddress.getString("postcode"));
gAddress.setPostalCode(jAddress.getString("postcode"));
}
if (jAddress.has("city")){
gAddress.setAddressLine(addressIndex++, jAddress.getString("city"));
gAddress.setLocality(jAddress.getString("city"));
} else if (jAddress.has("town")){
gAddress.setAddressLine(addressIndex++, jAddress.getString("town"));
gAddress.setLocality(jAddress.getString("town"));
} else if (jAddress.has("village")){
gAddress.setAddressLine(addressIndex++, jAddress.getString("village"));
gAddress.setLocality(jAddress.getString("village"));
}
if (jAddress.has("county")){ //France: departement
gAddress.setSubAdminArea(jAddress.getString("county"));
}
if (jAddress.has("state")){ //France: region
gAddress.setAdminArea(jAddress.getString("state"));
}
if (jAddress.has("country")){
gAddress.setAddressLine(addressIndex++, jAddress.getString("country"));
gAddress.setCountryName(jAddress.getString("country"));
}
if (jAddress.has("country_code"))
gAddress.setCountryCode(jAddress.getString("country_code"));
/* Other possible OSM tags in Nominatim results not handled yet:
* subway, golf_course, bus_stop, parking,...
* house, house_number, building
* city_district (13e Arrondissement)
* road => or highway, ...
* sub-city (like suburb) => locality, isolated_dwelling, hamlet ...
* state_district
*/
return gAddress;
}
public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
throws IOException {
String url = mServiceUrl
+ "reverse?"
+ "format=json"
+ "&accept-language=" + mLocale.getLanguage()
//+ "&addressdetails=1"
+ "&lat=" + latitude
+ "&lon=" + longitude;
Log.d(BonusPackHelper.LOG_TAG, "GeocoderNominatim::getFromLocation:"+url);
String result = BonusPackHelper.requestStringFromUrl(url);
//Log.d("NOMINATIM", result);
if (result == null)
throw new IOException();
try {
JSONObject jResult = new JSONObject(result);
Address gAddress = buildAndroidAddress(jResult);
List<Address> list = new ArrayList<Address>();
list.add(gAddress);
return list;
} catch (JSONException e) {
throw new IOException();
}
}
public List<Address> getFromLocationName(String locationName, int maxResults,
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude)
throws IOException {
String url = mServiceUrl
+ "search?"
+ "format=json"
+ "&accept-language=" + mLocale.getLanguage()
+ "&addressdetails=1"
+ "&limit=" + maxResults
+ "&q=" + URLEncoder.encode(locationName);
if (lowerLeftLatitude != 0.0 && lowerLeftLongitude != 0.0){
//viewbox = left, top, right, bottom:
url += "&viewbox=" + lowerLeftLongitude
+ "," + upperRightLatitude
+ "," + upperRightLongitude
+ "," + lowerLeftLatitude
+ "&bounded=1";
}
Log.d(BonusPackHelper.LOG_TAG, "GeocoderNominatim::getFromLocationName:"+url);
String result = BonusPackHelper.requestStringFromUrl(url);
//Log.d(BonusPackHelper.LOG_TAG, result);
if (result == null)
throw new IOException();
try {
JSONArray jResults = new JSONArray(result);
List<Address> list = new ArrayList<Address>();
for (int i=0; i<jResults.length(); i++){
JSONObject jResult = jResults.getJSONObject(i);
Address gAddress = buildAndroidAddress(jResult);
list.add(gAddress);
}
return list;
} catch (JSONException e) {
throw new IOException();
}
}
public List<Address> getFromLocationName(String locationName, int maxResults)
throws IOException {
return getFromLocationName(locationName, maxResults, 0.0, 0.0, 0.0, 0.0);
}
}