From 82f2f9af414a11a1d2cb415207c0f197f5a98d5b Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Thu, 22 Feb 2024 13:18:41 +0200 Subject: [PATCH 1/4] implement reverse geocoding to osm search channel --- .../search/OpenStreetMapSearchChannel.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java index da3415d134..2bccc0dcc2 100755 --- a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java +++ b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java @@ -1,6 +1,7 @@ package fi.nls.oskari.search; import fi.mml.portti.service.search.ChannelSearchResult; +import fi.mml.portti.service.search.IllegalSearchCriteriaException; import fi.mml.portti.service.search.SearchCriteria; import fi.mml.portti.service.search.SearchResultItem; import fi.nls.oskari.annotation.Oskari; @@ -42,6 +43,11 @@ public void init() { log.debug("ServiceURL set to " + serviceURL); } + @Override + public Capabilities getCapabilities() { + return Capabilities.COORD; + } + private String getUrl(SearchCriteria searchCriteria) throws UnsupportedEncodingException { Map params = new HashMap<>(); params.put("format", "json"); @@ -135,4 +141,79 @@ public ChannelSearchResult doSearch(SearchCriteria searchCriteria) { } return searchResultList; } + + private ChannelSearchResult createChannelSearchResult(JSONArray data, CoordinateReferenceSystem sourceCrs, CoordinateReferenceSystem targetCrs) { + ChannelSearchResult searchResultList = new ChannelSearchResult(); + try { + for (int i = 0; i < data.length(); i++) { + JSONObject dataItem = data.getJSONObject(i); + JSONObject address = dataItem.getJSONObject("address"); + SearchResultItem item = new SearchResultItem(); + item.setTitle(JSONHelper.getStringFromJSON(dataItem, "display_name", "")); + item.setDescription(JSONHelper.getStringFromJSON(dataItem, "display_name", "")); + item.setLocationTypeCode(JSONHelper.getStringFromJSON(dataItem, "class", "")); + item.setType(JSONHelper.getStringFromJSON(dataItem, "class", "")); + item.setRegion(JSONHelper.getStringFromJSON(address, "city", "")); + final double lat = dataItem.optDouble("lat"); + final double lon = dataItem.optDouble("lon"); + + // convert to map projection + final Point point = ProjectionHelper.transformPoint(lon, lat, sourceCrs, targetCrs); + if (point == null) { + continue; + } + + item.setLon(point.getLon()); + item.setLat(point.getLat()); + // FIXME: add more automation on result rank scaling + try { + item.setRank(100 * (int) Math.round(dataItem.getDouble("importance"))); + } catch (JSONException e) { + item.setRank(0); + } + searchResultList.addItem(item); + } + } catch(Exception e) { + log.error(e, "Failed to convert JSONArray to ChannelSearchResult"); + } + + return searchResultList; + } + @Override + public ChannelSearchResult reverseGeocode(SearchCriteria searchCriteria) throws IllegalSearchCriteriaException { + try { + String srs = searchCriteria.getSRS(); + if( srs == null ) { + srs = "EPSG:3067"; + } + + // Lon,lat (east coordinate is always first in transformation input and output + CoordinateReferenceSystem sourceCrs = CRS.decode(srs, true); + CoordinateReferenceSystem targetCrs = CRS.decode(SERVICE_SRS, true); + + // from source to wgs84 + final Point point = ProjectionHelper.transformPoint(searchCriteria.getLon(), searchCriteria.getLat(), sourceCrs, targetCrs); + + String url = "https://nominatim.openstreetmap.org/reverse?" + + "lat=" + point.getLat() + + "&lon=" + point.getLon() + + "&format=json" + + "&addressdetails=1" + + "&accept-language="+searchCriteria.getLocale(); + + HttpURLConnection connection = getConnection(url); + IOHelper.addIdentifierHeaders(connection); + String data = IOHelper.readString(connection); + log.debug("DATA: " + data); + JSONArray jsonData = new JSONArray(); + jsonData.put(JSONHelper.createJSONObject(data)); + + // convert back from wgs84 to map projection + return createChannelSearchResult(jsonData, targetCrs, sourceCrs); + + } catch (Exception e) { + log.error(e, "Failed to reverse geocode locations from register of OpenStreetMap"); + return null; + } + } } From 69c9339496438762008d6066e3d667e670be60fd Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Thu, 22 Feb 2024 14:58:33 +0200 Subject: [PATCH 2/4] read url from props and move creating results to a common method --- .../search/OpenStreetMapSearchChannel.java | 55 ++++++------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java index 2bccc0dcc2..9e89d4b45c 100755 --- a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java +++ b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java @@ -30,22 +30,25 @@ public class OpenStreetMapSearchChannel extends SearchChannel { /** logger */ private Logger log = LogFactory.getLogger(this.getClass()); private String serviceURL = null; + private String reverseGeocodeURL = null; public static final String ID = "OPENSTREETMAP_CHANNEL"; public final static String SERVICE_SRS = "EPSG:4326"; private static final String PROPERTY_SERVICE_URL = "search.channel.OPENSTREETMAP_CHANNEL.service.url"; + private static final String PROPERTY_SERVICE_REVERSE_GEOCODE_URL = "search.channel.OPENSTREETMAP_CHANNEL.reversegeocode.url"; private static final String PROPERTY_BBOX = "search.channel.OPENSTREETMAP_CHANNEL.search.bbox"; @Override public void init() { super.init(); serviceURL = PropertyUtil.get(PROPERTY_SERVICE_URL, "https://nominatim.openstreetmap.org/search"); - log.debug("ServiceURL set to " + serviceURL); + reverseGeocodeURL = PropertyUtil.get(PROPERTY_SERVICE_REVERSE_GEOCODE_URL, "https://nominatim.openstreetmap.org/reverse"); + log.debug("ServiceURL set to " + serviceURL + ", Reverse Geocode URL set to " + reverseGeocodeURL); } @Override public Capabilities getCapabilities() { - return Capabilities.COORD; + return Capabilities.BOTH; } private String getUrl(SearchCriteria searchCriteria) throws UnsupportedEncodingException { @@ -70,6 +73,15 @@ private String getUrl(SearchCriteria searchCriteria) throws UnsupportedEncodingE return IOHelper.constructUrl(serviceURL, params); } + private String getReverseGeocodeURL(SearchCriteria searchCriteria, Point point) throws UnsupportedEncodingException { + Map params = new HashMap<>(); + params.put("format", "json"); + params.put("addressdetails", "1"); + params.put("accept-language", searchCriteria.getLocale()); + params.put("lat", String.valueOf(point.getLat())); + params.put("lon", String.valueOf(point.getLon())); + return IOHelper.constructUrl(reverseGeocodeURL, params); + } /** * Returns the search raw results. * @param searchCriteria Search criteria. @@ -96,7 +108,7 @@ private JSONArray getData(SearchCriteria searchCriteria) throws Exception { * @return Search results. */ public ChannelSearchResult doSearch(SearchCriteria searchCriteria) { - ChannelSearchResult searchResultList = new ChannelSearchResult(); + ChannelSearchResult searchResultList = null; String srs = searchCriteria.getSRS(); if( srs == null ) { @@ -108,34 +120,7 @@ public ChannelSearchResult doSearch(SearchCriteria searchCriteria) { CoordinateReferenceSystem sourceCrs = CRS.decode(SERVICE_SRS, true); CoordinateReferenceSystem targetCrs = CRS.decode(srs, true); final JSONArray data = getData(searchCriteria); - for (int i = 0; i < data.length(); i++) { - JSONObject dataItem = data.getJSONObject(i); - JSONObject address = dataItem.getJSONObject("address"); - SearchResultItem item = new SearchResultItem(); - item.setTitle(JSONHelper.getStringFromJSON(dataItem, "display_name", "")); - item.setDescription(JSONHelper.getStringFromJSON(dataItem, "display_name", "")); - item.setLocationTypeCode(JSONHelper.getStringFromJSON(dataItem, "class", "")); - item.setType(JSONHelper.getStringFromJSON(dataItem, "class", "")); - item.setRegion(JSONHelper.getStringFromJSON(address, "city", "")); - final double lat = dataItem.optDouble("lat"); - final double lon = dataItem.optDouble("lon"); - - // convert to map projection - final Point point = ProjectionHelper.transformPoint(lon, lat, sourceCrs, targetCrs); - if (point == null) { - continue; - } - - item.setLon(point.getLon()); - item.setLat(point.getLat()); - // FIXME: add more automation on result rank scaling - try { - item.setRank(100 * (int) Math.round(dataItem.getDouble("importance"))); - } catch (JSONException e) { - item.setRank(0); - } - searchResultList.addItem(item); - } + searchResultList = createChannelSearchResult(data, sourceCrs, targetCrs); } catch (Exception e) { log.error(e, "Failed to search locations from register of OpenStreetMap"); } @@ -194,13 +179,7 @@ public ChannelSearchResult reverseGeocode(SearchCriteria searchCriteria) throws // from source to wgs84 final Point point = ProjectionHelper.transformPoint(searchCriteria.getLon(), searchCriteria.getLat(), sourceCrs, targetCrs); - String url = "https://nominatim.openstreetmap.org/reverse?" + - "lat=" + point.getLat() + - "&lon=" + point.getLon() + - "&format=json" + - "&addressdetails=1" + - "&accept-language="+searchCriteria.getLocale(); - + String url = getReverseGeocodeURL(searchCriteria, point); HttpURLConnection connection = getConnection(url); IOHelper.addIdentifierHeaders(connection); String data = IOHelper.readString(connection); From 1253784fabaf0599fd64698883fb183c40956f0a Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Thu, 22 Feb 2024 16:35:46 +0200 Subject: [PATCH 3/4] use getProperty --- .../fi/nls/oskari/search/OpenStreetMapSearchChannel.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java index 9e89d4b45c..c07453d399 100755 --- a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java +++ b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java @@ -34,15 +34,15 @@ public class OpenStreetMapSearchChannel extends SearchChannel { public static final String ID = "OPENSTREETMAP_CHANNEL"; public final static String SERVICE_SRS = "EPSG:4326"; - private static final String PROPERTY_SERVICE_URL = "search.channel.OPENSTREETMAP_CHANNEL.service.url"; - private static final String PROPERTY_SERVICE_REVERSE_GEOCODE_URL = "search.channel.OPENSTREETMAP_CHANNEL.reversegeocode.url"; + private static final String PROPERTY_SERVICE_URL = "service.url"; + private static final String PROPERTY_SERVICE_REVERSE_GEOCODE_URL = "reversegeocode.url"; private static final String PROPERTY_BBOX = "search.channel.OPENSTREETMAP_CHANNEL.search.bbox"; @Override public void init() { super.init(); - serviceURL = PropertyUtil.get(PROPERTY_SERVICE_URL, "https://nominatim.openstreetmap.org/search"); - reverseGeocodeURL = PropertyUtil.get(PROPERTY_SERVICE_REVERSE_GEOCODE_URL, "https://nominatim.openstreetmap.org/reverse"); + serviceURL = getProperty(PROPERTY_SERVICE_URL, "https://nominatim.openstreetmap.org/search"); + reverseGeocodeURL = getProperty(PROPERTY_SERVICE_REVERSE_GEOCODE_URL, "https://nominatim.openstreetmap.org/reverse"); log.debug("ServiceURL set to " + serviceURL + ", Reverse Geocode URL set to " + reverseGeocodeURL); } From 771ce19664067a02ee64abb130db7fcdbf0519b7 Mon Sep 17 00:00:00 2001 From: Pekka Helesuo Date: Thu, 22 Feb 2024 16:37:43 +0200 Subject: [PATCH 4/4] fall back to native srs prop if found --- .../search/OpenStreetMapSearchChannel.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java index c07453d399..7d452f55b3 100755 --- a/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java +++ b/service-search-opendata/src/main/java/fi/nls/oskari/search/OpenStreetMapSearchChannel.java @@ -31,6 +31,7 @@ public class OpenStreetMapSearchChannel extends SearchChannel { private Logger log = LogFactory.getLogger(this.getClass()); private String serviceURL = null; private String reverseGeocodeURL = null; + private String nativeSrsName = null; public static final String ID = "OPENSTREETMAP_CHANNEL"; public final static String SERVICE_SRS = "EPSG:4326"; @@ -43,6 +44,7 @@ public void init() { super.init(); serviceURL = getProperty(PROPERTY_SERVICE_URL, "https://nominatim.openstreetmap.org/search"); reverseGeocodeURL = getProperty(PROPERTY_SERVICE_REVERSE_GEOCODE_URL, "https://nominatim.openstreetmap.org/reverse"); + nativeSrsName = PropertyUtil.get("oskari.native.srs", "EPSG:3857"); log.debug("ServiceURL set to " + serviceURL + ", Reverse Geocode URL set to " + reverseGeocodeURL); } @@ -109,11 +111,7 @@ private JSONArray getData(SearchCriteria searchCriteria) throws Exception { */ public ChannelSearchResult doSearch(SearchCriteria searchCriteria) { ChannelSearchResult searchResultList = null; - - String srs = searchCriteria.getSRS(); - if( srs == null ) { - srs = "EPSG:3067"; - } + String srs = getSearchCriteriaSRS(searchCriteria); try { // Lon,lat (east coordinate is always first in transformation input and output @@ -167,11 +165,8 @@ private ChannelSearchResult createChannelSearchResult(JSONArray data, Coordinate @Override public ChannelSearchResult reverseGeocode(SearchCriteria searchCriteria) throws IllegalSearchCriteriaException { try { - String srs = searchCriteria.getSRS(); - if( srs == null ) { - srs = "EPSG:3067"; - } + String srs = getSearchCriteriaSRS(searchCriteria); // Lon,lat (east coordinate is always first in transformation input and output CoordinateReferenceSystem sourceCrs = CRS.decode(srs, true); CoordinateReferenceSystem targetCrs = CRS.decode(SERVICE_SRS, true); @@ -195,4 +190,13 @@ public ChannelSearchResult reverseGeocode(SearchCriteria searchCriteria) throws return null; } } + + private String getSearchCriteriaSRS(SearchCriteria searchCriteria) { + String srs = searchCriteria.getSRS(); + if( srs == null ) { + srs = nativeSrsName; + } + + return srs; + } }