add OverpassAPI loader
This commit is contained in:
parent
da53b02e8a
commit
b3f4ee444c
415
src/org/oscim/utils/overpass/OverpassAPIReader.java
Normal file
415
src/org/oscim/utils/overpass/OverpassAPIReader.java
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oscim.utils.overpass;
|
||||||
|
|
||||||
|
import static org.oscim.core.osm.TagGroup.EMPTY_TAG_GROUP;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 org.oscim.core.osm.TagGroup;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.JsonToken;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance with the specified geographical coordinates.
|
||||||
|
*
|
||||||
|
* @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 baseUrl
|
||||||
|
* (optional) The base url of the server (eg.
|
||||||
|
* http://www.openstreetmap.org/api/0.5).
|
||||||
|
*/
|
||||||
|
public OverpassAPIReader(final double left, final double right,
|
||||||
|
final double top, final double bottom, final String baseUrl,
|
||||||
|
final String query) {
|
||||||
|
|
||||||
|
String bbox = "(" + Math.min(top, bottom) + "," + Math.min(left, right)
|
||||||
|
+ "," + Math.max(top, bottom) + "," + Math.max(left, right)
|
||||||
|
+ ")";
|
||||||
|
|
||||||
|
this.query = 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
|
||||||
|
* <code>null</code>.
|
||||||
|
* @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<Bound> bounds = new ArrayList<Bound>();
|
||||||
|
private Map<Long, OSMNode> nodesById = new HashMap<Long, OSMNode>();
|
||||||
|
private Map<Long, OSMWay> waysById = new HashMap<Long, OSMWay>();
|
||||||
|
private Map<Long, OSMRelation> relationsById = new HashMap<Long, OSMRelation>();
|
||||||
|
private Map<OSMRelation, List<TmpRelation>> relationMembersForRelation =
|
||||||
|
new HashMap<OSMRelation, List<TmpRelation>>();
|
||||||
|
|
||||||
|
private final Collection<OSMNode> ownNodes = new ArrayList<OSMNode>(10000);
|
||||||
|
private final Collection<OSMWay> ownWays = new ArrayList<OSMWay>(1000);
|
||||||
|
private final Collection<OSMRelation> ownRelations = new ArrayList<OSMRelation>(
|
||||||
|
100);
|
||||||
|
|
||||||
|
public void parse(InputStream in) throws IOException {
|
||||||
|
JsonFactory jsonFactory = new JsonFactory();
|
||||||
|
try {
|
||||||
|
JsonParser jp = jsonFactory.createJsonParser(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;
|
||||||
|
TagGroup tags = EMPTY_TAG_GROUP;
|
||||||
|
|
||||||
|
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;
|
||||||
|
TagGroup tags = EMPTY_TAG_GROUP;
|
||||||
|
ArrayList<OSMNode> wayNodes = new ArrayList<OSMNode>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
TagGroup tags = EMPTY_TAG_GROUP;
|
||||||
|
ArrayList<TmpRelation> members = new ArrayList<TmpRelation>();
|
||||||
|
|
||||||
|
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 TagGroup parseTags(JsonParser jp) throws JsonParseException,
|
||||||
|
IOException {
|
||||||
|
|
||||||
|
Map<String, String> tagMap = null;
|
||||||
|
|
||||||
|
while (jp.nextToken() != JsonToken.END_OBJECT) {
|
||||||
|
String key = jp.getCurrentName();
|
||||||
|
jp.nextToken();
|
||||||
|
String val = jp.getText();
|
||||||
|
if (tagMap == null)
|
||||||
|
tagMap = new HashMap<String, String>(10);
|
||||||
|
|
||||||
|
tagMap.put(key, val);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (tagMap == null)
|
||||||
|
return EMPTY_TAG_GROUP;
|
||||||
|
|
||||||
|
return new TagGroup(tagMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(String msg) {
|
||||||
|
System.out.println(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public OSMData getData() {
|
||||||
|
|
||||||
|
String encoded;
|
||||||
|
try {
|
||||||
|
encoded = URLEncoder.encode(this.query, "utf-8");
|
||||||
|
} catch (UnsupportedEncodingException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Entry<OSMRelation, List<TmpRelation>> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user