package me.osm.gazetter.out; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import me.osm.gazetter.striper.FeatureTypes; import me.osm.gazetter.striper.GeoJsonWriter; import me.osm.gazetter.utils.LocatePoint; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Polygon; public class FeatureValueExctractorImpl implements FeatureValueExtractor { private static final String NEAREST_NEIGHBOURHOOD_ID = "nearest:neighbourhood.id"; private static final String NEAREST_NEIGHBOURHOOD = "nearest:neighbourhood"; private static final String NEAREST_CITY_ID = "nearest:city.id"; private static final String NEAREST_CITY = "nearest:city"; private static final String FULL_GEOMETRY = "full-geometry"; private static final String CENTROID = "centroid"; private static final String LAT = "lat"; private static final String LON = "lon"; private static final String OSM_TYPE = "osm-type"; private static final String OSM_TYPE_ID = "osm-type-id"; private static final String OSM_ID = "osm-id"; private static final String ID = "id"; private static final String TYPE = "type"; private static final String TAGS_JSON = "tags.json"; private static final String TAGS_HSTORE = "tags.hstore"; private static final String DESCRIPTION = "description"; private static final String WIKIPEDIA = "wikipedia"; private static final String NAME = "name"; private static final String VERBOSE_TYPE = "type-verbose"; private Set<String> supported = new HashSet<String>(Arrays.asList(ID, TYPE, OSM_ID, OSM_TYPE, LON, LAT, CENTROID, FULL_GEOMETRY, NEAREST_CITY, NEAREST_CITY_ID, NEAREST_NEIGHBOURHOOD, NEAREST_NEIGHBOURHOOD_ID, DESCRIPTION, WIKIPEDIA, TAGS_JSON, TAGS_HSTORE, OSM_TYPE_ID, VERBOSE_TYPE)); @Override public Object getValue(String key, JSONObject jsonObject) { try { String ftype = jsonObject.getString("ftype"); switch (key) { case ID: return jsonObject.getString(ID); case TYPE: return ftype; case OSM_ID: return jsonObject.getJSONObject(GeoJsonWriter.META).getLong(ID); case OSM_TYPE: return jsonObject.getJSONObject(GeoJsonWriter.META).getString("type"); case OSM_TYPE_ID: String type = String.valueOf(jsonObject.getJSONObject(GeoJsonWriter.META).getString("type").charAt(0)); String id = String.valueOf(jsonObject.getJSONObject(GeoJsonWriter.META).getLong(ID)); return type + id; case LON: if(FeatureTypes.HIGHWAY_FEATURE_TYPE.equals(ftype)) { LineString ls = GeoJsonWriter.getLineStringGeometry( jsonObject.getJSONObject(GeoJsonWriter.GEOMETRY) .getJSONArray(GeoJsonWriter.COORDINATES)); Coordinate c = new LocatePoint(ls, 0.5).getPoint(); return c.x; } else { return jsonObject.getJSONObject(GeoJsonWriter.GEOMETRY) .getJSONArray(GeoJsonWriter.COORDINATES).getDouble(0); } case LAT: if(FeatureTypes.HIGHWAY_FEATURE_TYPE.equals(ftype)) { LineString ls = GeoJsonWriter.getLineStringGeometry( jsonObject.getJSONObject(GeoJsonWriter.GEOMETRY) .getJSONArray(GeoJsonWriter.COORDINATES)); Coordinate c = new LocatePoint(ls, 0.5).getPoint(); return c.y; } else { return jsonObject.getJSONObject(GeoJsonWriter.GEOMETRY) .getJSONArray(GeoJsonWriter.COORDINATES).getDouble(1); } case CENTROID: if(FeatureTypes.HIGHWAY_FEATURE_TYPE.equals(ftype)) { LineString ls = GeoJsonWriter.getLineStringGeometry( jsonObject.getJSONObject(GeoJsonWriter.GEOMETRY) .getJSONArray(GeoJsonWriter.COORDINATES)); Coordinate c = new LocatePoint(ls, 0.5).getPoint(); return "SRID=4326;POINT (" + c.x + " " + c.y + ")"; } else { JSONArray coords = jsonObject.getJSONObject(GeoJsonWriter.GEOMETRY) .getJSONArray(GeoJsonWriter.COORDINATES); return "SRID=4326;POINT (" + coords.getDouble(0) + " " + coords.getDouble(1) + ")"; } case FULL_GEOMETRY: JSONObject fullGeometry = null; if(FeatureTypes.PLACE_POINT_FTYPE.equals(ftype)) { JSONObject matchedBoundary = jsonObject.optJSONObject("matchedBoundary"); if(matchedBoundary != null) { fullGeometry = matchedBoundary.getJSONObject(GeoJsonWriter.META).optJSONObject(GeoJsonWriter.FULL_GEOMETRY); } } else { JSONObject meta = jsonObject.getJSONObject(GeoJsonWriter.META); fullGeometry = meta.optJSONObject("fullGeometry"); } if(fullGeometry != null && "MultiPolygon".equals(fullGeometry.optString("type"))) { MultiPolygon polygon = GeoJsonWriter.getMultiPolygonGeometry(fullGeometry.getJSONArray("coordinates")); return "SRID=4326;" + polygon.toString(); } if(fullGeometry != null && "Polygon".equals(fullGeometry.optString("type"))) { Polygon polygon = GeoJsonWriter.getPolygonGeometry(fullGeometry.getJSONArray("coordinates")); return "SRID=4326;" + polygon.toString(); } else if(fullGeometry != null && "LineString".equals(fullGeometry.optString("type"))) { LineString ls = GeoJsonWriter.getLineStringGeometry(fullGeometry.getJSONArray("coordinates")); return "SRID=4326;" + ls.toString(); } break; case NEAREST_CITY: return jsonObject.getJSONObject("nearestCity").getJSONObject(GeoJsonWriter.PROPERTIES).optString("name"); case NEAREST_CITY_ID: return jsonObject.getJSONObject("nearestCity").getJSONObject(GeoJsonWriter.PROPERTIES).optString(ID); case NEAREST_NEIGHBOURHOOD: return jsonObject.getJSONObject("nearestNeighbour").getJSONObject(GeoJsonWriter.PROPERTIES).optString("name"); case NEAREST_NEIGHBOURHOOD_ID: return jsonObject.getJSONObject("nearestNeighbour").getJSONObject(GeoJsonWriter.PROPERTIES).optString(ID); case TAGS_JSON: return jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).toString(); case TAGS_HSTORE: return asHStore(jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES)); case DESCRIPTION: return jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).optString("description"); case WIKIPEDIA: return jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).optString("wikipedia"); case VERBOSE_TYPE: if(FeatureTypes.HIGHWAY_FEATURE_TYPE.equals(ftype) || FeatureTypes.POI_FTYPE.equals(ftype) || FeatureTypes.ADDR_POINT_FTYPE.equals(ftype)) { return ftype; } else if (FeatureTypes.PLACE_POINT_FTYPE.equals(ftype)) { String place = jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).optString("place"); if(StringUtils.isNoneBlank(place)) { return "place:" + place; } String boundary = jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).optString("admin_level"); if(StringUtils.isNoneBlank(boundary)) { return "boundary:" + boundary; } } return null; } } catch (Exception e) { return null; } if(key.equals(NAME)) { return jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).optString("name", null); } else if(key.contains(NAME)) { return jsonObject.getJSONObject(GeoJsonWriter.PROPERTIES).optString(key, null); } return null; } @SuppressWarnings("unchecked") public static String asHStore(JSONObject jsonObject) { List<String> pairs = new ArrayList<>(); for(String key : (Collection<String>)jsonObject.keySet()) { String val = jsonObject.get(key).toString(); pairs.add("\"" + key + "\"=>\"" + val + "\""); } return StringUtils.join(pairs, ","); } public static String asHStore(Map<String, String> tags) { List<String> pairs = new ArrayList<>(); for(Entry<String, String> tag : tags.entrySet()) { pairs.add("\"" + escape4Hstore(tag.getKey()) + "\"=>\"" + escape4Hstore(tag.getValue()) + "\""); } return StringUtils.join(pairs, ","); } private static String escape4Hstore(String string) { return StringUtils.replace(string, "$", "$"); } @Override public Collection<String> getSupportedKeys() { return supported; } @Override public boolean supports(String key) { return supported.contains(key); } }