org.oscim.utils.overpass.OverpassAPIReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm-extras Show documentation
Show all versions of vtm-extras Show documentation
OpenGL vector map library - running on Android, iOS, Desktop and browser.
/*
* Copyright 2013 Hannes Janetzek
* Copyright 2016 devemux86
* Copyright 2019 Gustl22
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
package org.oscim.utils.overpass;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.core.osm.Bound;
import org.oscim.core.osm.OsmData;
import org.oscim.core.osm.OsmElement;
import org.oscim.core.osm.OsmMember;
import org.oscim.core.osm.OsmNode;
import org.oscim.core.osm.OsmRelation;
import org.oscim.core.osm.OsmWay;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
public class OverpassAPIReader {
private static final String OVERPASS_API = "http://city.informatik.uni-bremen.de/oapi/interpreter";
private static final int RESPONSECODE_OK = 200;
/**
* The timeout we use for the HttpURLConnection.
*/
private static final int TIMEOUT = 15000;
/**
* The base url of the server. Defaults to.
* "http://www.openstreetmap.org/api/0.5".
*/
private final String myBaseUrl = OVERPASS_API;
/**
* The http connection used to retrieve data.
*/
private HttpURLConnection myActiveConnection;
/**
* The stream providing response data.
*/
private InputStream responseStream;
private final String query;
public OverpassAPIReader() {
this.query = null;
}
/**
* Creates a new instance with the specified geographical coordinates.
*/
public OverpassAPIReader(final double left, final double right,
final double top, final double bottom,
final String query) {
this.query = query(left, right, top, bottom, query);
}
/**
* @param left The longitude marking the left edge of the bounding box.
* @param right The longitude marking the right edge of the bounding box.
* @param top The latitude marking the top edge of the bounding box.
* @param bottom The latitude marking the bottom edge of the bounding box.
* @param query The prepared query.
* @return the processed query with specified bounding box
*/
public static String query(final double left, final double right,
final double top, final double bottom,
final String query) {
String bbox = "(" + Math.min(top, bottom) + "," + Math.min(left, right)
+ "," + Math.max(top, bottom) + "," + Math.max(left, right)
+ ")";
return query.replaceAll("\\{\\{bbox\\}\\}", bbox);
}
/**
* Open a connection to the given url and return a reader on the input
* stream from that connection.
*
* @param pUrlStr The exact url to connect to.
* @return An reader reading the input stream (servers answer) or
* null
.
* @throws IOException on io-errors
*/
private InputStream getInputStream(final String pUrlStr) throws IOException {
URL url;
int responseCode;
String encoding;
url = new URL(pUrlStr);
myActiveConnection = (HttpURLConnection) url.openConnection();
myActiveConnection.setRequestProperty("Accept-Encoding",
"gzip, deflate");
responseCode = myActiveConnection.getResponseCode();
if (responseCode != RESPONSECODE_OK) {
String message;
String apiErrorMessage;
apiErrorMessage = myActiveConnection.getHeaderField("Error");
if (apiErrorMessage != null) {
message = "Received API HTTP response code " + responseCode
+ " with message \"" + apiErrorMessage
+ "\" for URL \"" + pUrlStr + "\".";
} else {
message = "Received API HTTP response code " + responseCode
+ " for URL \"" + pUrlStr + "\".";
}
throw new IOException(message);
}
myActiveConnection.setConnectTimeout(TIMEOUT);
encoding = myActiveConnection.getContentEncoding();
responseStream = myActiveConnection.getInputStream();
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
responseStream = new GZIPInputStream(responseStream);
} else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
responseStream = new InflaterInputStream(responseStream,
new Inflater(true));
}
return responseStream;
}
class TmpRelation {
Long id;
String type;
String role;
}
private final List bounds = new ArrayList();
private Map nodesById = new HashMap();
private Map waysById = new HashMap();
private Map relationsById = new HashMap();
private Map> relationMembersForRelation =
new HashMap>();
private final Collection ownNodes = new ArrayList(10000);
private final Collection ownWays = new ArrayList(1000);
private final Collection ownRelations = new ArrayList(
100);
public void parse(InputStream in) throws IOException {
JsonFactory jsonFactory = new JsonFactory();
try {
JsonParser jp = jsonFactory.createParser(in);
JsonToken t;
while ((t = jp.nextToken()) != null) {
if (t == JsonToken.START_OBJECT) {
jp.nextToken();
String name = jp.getCurrentName();
jp.nextToken();
if ("type".equals(name)) {
String type = jp.getText();
if ("node".equals(type))
parseNode(jp);
else if ("way".equals(type))
parseWay(jp);
else if ("relation".equals(type))
parseRelation(jp);
}
}
}
} catch (JsonParseException e) {
e.printStackTrace();
}
}
private void parseNode(JsonParser jp) throws JsonParseException,
IOException {
long id = 0;
double lat = 0, lon = 0;
TagSet tags = null;
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if ("id".equals(name))
id = jp.getLongValue();
else if ("lat".equals(name))
lat = jp.getDoubleValue();
else if ("lon".equals(name))
lon = jp.getDoubleValue();
else if ("tags".equals(name))
tags = parseTags(jp);
}
// log("node: "+id + " "+ lat + " " + lon);
OsmNode node = new OsmNode(lat, lon, tags, id);
ownNodes.add(node);
nodesById.put(Long.valueOf(id), node);
}
private void parseWay(JsonParser jp) throws JsonParseException, IOException {
long id = 0;
TagSet tags = null;
ArrayList wayNodes = new ArrayList();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if ("id".equals(name))
id = jp.getLongValue();
else if ("nodes".equals(name)) {
while (jp.nextToken() != JsonToken.END_ARRAY) {
Long nodeId = Long.valueOf(jp.getLongValue());
OsmNode node = nodesById.get(nodeId);
if (node != null)
// log("missing node " + nodeId);
// else
wayNodes.add(node);
}
} else if ("tags".equals(name))
tags = parseTags(jp);
}
// log("way: "+ id + " " + wayNodes.size());
OsmWay way = new OsmWay(tags, id, wayNodes);
ownWays.add(way);
waysById.put(Long.valueOf(id), way);
}
private void parseRelation(JsonParser jp) throws JsonParseException,
IOException {
long id = 0;
TagSet tags = null;
ArrayList members = new ArrayList();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String name = jp.getCurrentName();
jp.nextToken();
if ("id".equals(name))
id = jp.getLongValue();
else if ("members".equals(name)) {
while (jp.nextToken() != JsonToken.END_ARRAY) {
TmpRelation member = new TmpRelation();
while (jp.nextToken() != JsonToken.END_OBJECT) {
name = jp.getCurrentName();
jp.nextToken();
if ("type".equals(name))
member.type = jp.getText();
else if ("ref".equals(name))
member.id = Long.valueOf(jp.getLongValue());
else if ("role".equals(name))
member.role = jp.getText();
}
members.add(member);
}
} else if ("tags".equals(name))
tags = parseTags(jp);
}
OsmRelation relation = new OsmRelation(tags, id, members.size());
ownRelations.add(relation);
relationsById.put(Long.valueOf(id), relation);
relationMembersForRelation.put(relation, members);
}
private static TagSet parseTags(JsonParser jp) throws JsonParseException,
IOException {
TagSet tags = null;
while (jp.nextToken() != JsonToken.END_OBJECT) {
String key = jp.getCurrentName();
jp.nextToken();
String val = jp.getText();
if (tags == null)
tags = new TagSet(4);
tags.add(new Tag(key, val, false));
}
return tags;
}
private static void log(String msg) {
System.out.println(msg);
}
public void parseInputStream() {
String encoded;
try {
encoded = URLEncoder.encode(this.query, "utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
return;
}
System.out.println(myBaseUrl + "?data=" + encoded);
InputStream inputStream = null;
try {
inputStream = getInputStream(myBaseUrl + "?data=[out:json];" + encoded);
parse(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null)
try {
inputStream.close();
} catch (IOException e) {
//...
}
inputStream = null;
}
}
public OsmData getData() {
for (Entry> entry : relationMembersForRelation
.entrySet()) {
OsmRelation relation = entry.getKey();
for (TmpRelation member : entry.getValue()) {
OsmElement memberObject = null;
if ("node".equals(member)) {
memberObject = nodesById.get(member.id);
} else if ("way".equals(member)) {
memberObject = waysById.get(member.id);
} else if ("relation".equals(member)) {
memberObject = relationsById.get(member.id);
} else {
// log("missing relation " + member.id);
continue;
}
if (memberObject != null) {
OsmMember ownMember = new OsmMember(member.role,
memberObject);
relation.relationMembers.add(ownMember);
}
}
}
/*log("nodes: " + ownNodes.size() + " ways: " + ownWays.size()
+ " relations: " + ownRelations.size());*/
// give up references to original collections
nodesById = null;
waysById = null;
relationsById = null;
relationMembersForRelation = null;
return new OsmData(bounds, ownNodes, ownWays, ownRelations);
}
}