-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1741 from laurentg/bano-geocoder
Bano geocoder
- Loading branch information
Showing
3 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
src/main/java/org/opentripplanner/geocoder/bano/BanoGeocoder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* This program is free software: you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public License | ||
as published by the Free Software Foundation, either version 3 of | ||
the License, or (at your option) any later version. | ||
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. | ||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
|
||
package org.opentripplanner.geocoder.bano; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.net.URI; | ||
import java.net.URL; | ||
import java.net.URLConnection; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import javax.ws.rs.core.UriBuilder; | ||
|
||
import org.geojson.Feature; | ||
import org.geojson.FeatureCollection; | ||
import org.geojson.GeoJsonObject; | ||
import org.geojson.Point; | ||
import org.opentripplanner.geocoder.Geocoder; | ||
import org.opentripplanner.geocoder.GeocoderResult; | ||
import org.opentripplanner.geocoder.GeocoderResults; | ||
|
||
import com.fasterxml.jackson.databind.DeserializationFeature; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.vividsolutions.jts.geom.Envelope; | ||
|
||
/** | ||
* A geocoder using the data.gouv.fr API of BANO (Base Nationale d'Adresse Ouverte), the official | ||
* open-data address source covering the whole of France. | ||
* | ||
* The returned data is rather simple to use, as it returns a GeoJSON features collection. | ||
* | ||
* Obviously, this geocoder will only work in France. | ||
* | ||
* @author laurent | ||
*/ | ||
public class BanoGeocoder implements Geocoder { | ||
|
||
private static final String BANO_URL = "http://api.adresse.data.gouv.fr/search/"; | ||
|
||
private static final int CLAMP_RESULTS = 10; | ||
|
||
private ObjectMapper mapper; | ||
|
||
public BanoGeocoder() { | ||
mapper = new ObjectMapper(); | ||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); | ||
} | ||
|
||
/** | ||
*/ | ||
@Override | ||
public GeocoderResults geocode(String address, Envelope bbox) { | ||
|
||
try { | ||
URL banoUrl = getBanoGeocoderUrl(address, bbox); | ||
URLConnection conn = banoUrl.openConnection(); | ||
InputStream in = conn.getInputStream(); | ||
FeatureCollection featureCollection = mapper.readValue(in, FeatureCollection.class); | ||
in.close(); | ||
|
||
List<GeocoderResult> geocoderResults = new ArrayList<GeocoderResult>(); | ||
for (Feature feature : featureCollection.getFeatures()) { | ||
GeoJsonObject geom = feature.getGeometry(); | ||
if (geom instanceof Point) { | ||
Point p = (Point) geom; | ||
GeocoderResult res = new GeocoderResult(); | ||
res.setLat(p.getCoordinates().getLatitude()); | ||
res.setLng(p.getCoordinates().getLongitude()); | ||
res.setDescription(feature.getProperties().get("label").toString()); | ||
/* | ||
* Note: We also have here as properties a break-down of other details, such as | ||
* the house number, street, city, postcode... Can be useful if needed. | ||
*/ | ||
geocoderResults.add(res); | ||
} else { | ||
// Should not happen according to the API | ||
} | ||
} | ||
return new GeocoderResults(geocoderResults); | ||
|
||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return new GeocoderResults(e.getLocalizedMessage()); | ||
} | ||
} | ||
|
||
private URL getBanoGeocoderUrl(String address, Envelope bbox) throws IOException { | ||
UriBuilder uriBuilder = UriBuilder.fromUri(BANO_URL); | ||
uriBuilder.queryParam("q", address); | ||
uriBuilder.queryParam("limit", CLAMP_RESULTS); | ||
if (bbox != null) { | ||
uriBuilder.queryParam("lat", bbox.centre().y); | ||
uriBuilder.queryParam("lon", bbox.centre().x); | ||
} | ||
URI uri = uriBuilder.build(); | ||
return new URL(uri.toString()); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
src/test/java/org/opentripplanner/geocoder/bano/BanoGeocoderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* This program is free software: you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public License | ||
as published by the Free Software Foundation, either version 3 of | ||
the License, or (at your option) any later version. | ||
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. | ||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
|
||
package org.opentripplanner.geocoder.bano; | ||
|
||
import org.junit.Test; | ||
import org.opentripplanner.common.geometry.SphericalDistanceLibrary; | ||
import org.opentripplanner.geocoder.GeocoderResult; | ||
import org.opentripplanner.geocoder.GeocoderResults; | ||
|
||
import com.vividsolutions.jts.geom.Envelope; | ||
|
||
public class BanoGeocoderTest { | ||
|
||
/** | ||
* TODO -- This unit-test rely on an on-line API to be up and running, which may not be the case | ||
* if a network connection is not active or the server is down. | ||
*/ | ||
@Test | ||
public void testOnLine() throws Exception { | ||
|
||
BanoGeocoder banoGeocoder = new BanoGeocoder(); | ||
// The Presidential palace of the French Republic is not supposed to move often | ||
Envelope bbox = new Envelope(); | ||
bbox.expandToInclude(2.25, 48.8); | ||
bbox.expandToInclude(2.35, 48.9); | ||
GeocoderResults results = banoGeocoder.geocode("55 Rue du Faubourg Saint-Honoré", bbox); | ||
|
||
assert (results.getResults().size() >= 1); | ||
|
||
boolean found = false; | ||
for (GeocoderResult result : results.getResults()) { | ||
if ("55 Rue du Faubourg Saint-Honoré 75008 Paris".equals(result.getDescription())) { | ||
double dist = SphericalDistanceLibrary.getInstance().distance(result.getLat(), | ||
result.getLng(), 48.870637, 2.316939); | ||
assert (dist < 100); | ||
found = true; | ||
} | ||
} | ||
assert (found); | ||
|
||
} | ||
|
||
} |