開放街圖OSM的公共圖資可以透過overpass-turbo介面查詢獲得。
若想利用Java程式碼查詢,可參考以下查詢範例。
其中,查詢指令可參考overpass-turbo範例指令,測試成功再代入程式。
/*
QueryOSM.java
展示如何用retrofit套件,同步及非同步(適用於Android),存取如下OSM圖資服務
http://overpass-api.de/api/interpreter?data=xxx
// 建立服務連線客戶端及請求內容
OverpassService requestClient = OverpassServiceProvider.get();
String request = composeRequest();
// 非同步查詢圖資,適用於手機平板Android平台
asyncRequest(requestClient, request);
// 同步查詢圖資,適用於桌機Application應用
OverpassQueryResult result = syncRequest(requestClient, request);
postProcess(result);
執行步驟:
javac QueryOSM.java
java QueryOSM
run:
[out:json][timeout:25];
(
node[tourism](25.1735, 121.446, 25.1775, 121.455);
relation[!highway][type!='route'][!boundary](25.1735, 121.446, 25.1775, 121.455);
);
out center;
end of asyncRequest()
21 elements...
1. id:4326372453, type:node, lat:25.1761808, lon:121.4490491, name:五虎碑, wheelchair:limited
2. id:4384988658, type:node, lat:25.1750071, lon:121.4522078, name:文錙藝術中心, wheelchair:yes
3. id:4492221396, type:node, lat:25.1736267, lon:121.4473809, name:三化牆
4. id:4492221397, type:node, lat:25.1744069, lon:121.4474037, name:地球村雕像, wheelchair:limited
5. id:4492221399, type:node, lat:25.1735175, lon:121.4484658, name:淡江大學花牆
6. id:4492221425, type:node, lat:25.1749949, lon:121.450678, name:閱讀的少女, wheelchair:yes
7. id:4502075211, type:node, lat:25.1751384, lon:121.4523232, name:旅者
8. id:4502075212, type:node, lat:25.1739938, lon:121.4505047, name:李雙澤紀念碑, wheelchair:yes
9. id:4502075213, type:node, lat:25.1761919, lon:121.4499374, name:福園金鷹銅雕, wheelchair:no
10. id:4502075222, type:node, lat:25.1738907, lon:121.4475716, name:驚聲銅像, wheelchair:limited
11. id:4507662408, type:node, lat:25.1741082, lon:121.4474671, name:溫馨, wheelchair:yes
12. id:5012978611, type:node, lat:25.1741784, lon:121.4507282, name:黃河母親, wheelchair:no
13. id:5072580167, type:node, lat:25.1769149, lon:121.4495309
14. id:5130535622, type:node, lat:25.1757202, lon:121.4496844, name:會文館, wheelchair:yes
15. id:5132288341, type:node, lat:25.1741586, lon:121.4508061
16. id:5132288342, type:node, lat:25.174208, lon:121.4475417
17. id:6050843218, type:node, lat:25.1770813, lon:121.449821
18. id:8991981256, type:node, lat:25.1750049, lon:121.4480033, name:淡江願景牆, wheelchair:yes
19. id:3974590, type:relation, lat:0.0, lon:0.0, type:multipolygon, name:操場
20. id:3983402, type:relation, lat:0.0, lon:0.0, type:multipolygon, name:松濤廣場
21. id:7530081, type:relation, lat:0.0, lon:0.0, type:multipolygon
Response{protocol=http/1.1, code=200, message=OK, url=http://overpass-api.de/api/interpreter?data=%5Bout%3Ajson%5D%5Btimeout%3A25%5D%3B%0A%28%0Anode%5Btourism%5D%2825.1735%2C%20121.446%2C%2025.1775%2C%20121.455%29%3B%0Arelation%5B%21highway%5D%5Btype%21%3D%27route%27%5D%5B%21boundary%5D%2825.1735%2C%20121.446%2C%2025.1775%2C%20121.455%29%3B%0A%29%3B%0Aout%20center%3B}
end of syncRequest()
21 elements...
1. id:4326372453, type:node, lat:25.1761808, lon:121.4490491, name:五虎碑, wheelchair:limited
2. id:4384988658, type:node, lat:25.1750071, lon:121.4522078, name:文錙藝術中心, wheelchair:yes
3. id:4492221396, type:node, lat:25.1736267, lon:121.4473809, name:三化牆
4. id:4492221397, type:node, lat:25.1744069, lon:121.4474037, name:地球村雕像, wheelchair:limited
5. id:4492221399, type:node, lat:25.1735175, lon:121.4484658, name:淡江大學花牆
6. id:4492221425, type:node, lat:25.1749949, lon:121.450678, name:閱讀的少女, wheelchair:yes
7. id:4502075211, type:node, lat:25.1751384, lon:121.4523232, name:旅者
8. id:4502075212, type:node, lat:25.1739938, lon:121.4505047, name:李雙澤紀念碑, wheelchair:yes
9. id:4502075213, type:node, lat:25.1761919, lon:121.4499374, name:福園金鷹銅雕, wheelchair:no
10. id:4502075222, type:node, lat:25.1738907, lon:121.4475716, name:驚聲銅像, wheelchair:limited
11. id:4507662408, type:node, lat:25.1741082, lon:121.4474671, name:溫馨, wheelchair:yes
12. id:5012978611, type:node, lat:25.1741784, lon:121.4507282, name:黃河母親, wheelchair:no
13. id:5072580167, type:node, lat:25.1769149, lon:121.4495309
14. id:5130535622, type:node, lat:25.1757202, lon:121.4496844, name:會文館, wheelchair:yes
15. id:5132288341, type:node, lat:25.1741586, lon:121.4508061
16. id:5132288342, type:node, lat:25.174208, lon:121.4475417
17. id:6050843218, type:node, lat:25.1770813, lon:121.449821
18. id:8991981256, type:node, lat:25.1750049, lon:121.4480033, name:淡江願景牆, wheelchair:yes
19. id:3974590, type:relation, lat:0.0, lon:0.0, type:multipolygon, name:操場
20. id:3983402, type:relation, lat:0.0, lon:0.0, type:multipolygon, name:松濤廣場
21. id:7530081, type:relation, lat:0.0, lon:0.0, type:multipolygon
end of main()
BUILD SUCCESSFUL (total time: 1 minute 2 seconds)
參考:
a. Retrofit 2 – Synchronous and asynchronous call example
https://howtodoinjava.com/retrofit2/retrofit-sync-async-calls/
b. https://github.com/zsoltk/overpasser
hu.supercluster.overpasser.adapter
OverpassQueryResult
OverpassQueryResult.Element
OverpassQueryResult.Element.Tags
OverpassService
c. 引用函數庫
compile/run:
okhttp-3.14.9.jar
okio-1.17.2.jar
converter-gson-2.10.2.jar
gson-2.8.5.jar
retrofit-2.10.2.jar
compile/run tests:
byte-buddy-1.11.3.jar
byte-buddy-agent-1.11.3.jar
mockito-core-3.11.2.jar
objenesis-3.2.jar
*/
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import hu.supercluster.overpasser.library.output.OutputFormat;
import hu.supercluster.overpasser.library.output.OutputModificator;
import hu.supercluster.overpasser.library.output.OutputOrder;
import hu.supercluster.overpasser.library.output.OutputVerbosity;
import hu.supercluster.overpasser.library.query.OverpassQuery;
import hu.supercluster.overpasser.adapter.OverpassQueryResult;
import hu.supercluster.overpasser.adapter.OverpassQueryResult.Element;
import hu.supercluster.overpasser.adapter.OverpassQueryResult.Element.Tags;
import hu.supercluster.overpasser.adapter.OverpassService;
import hu.supercluster.overpasser.adapter.OverpassServiceProvider;
import java.lang.reflect.Field;
import java.util.List;
/**
*
* @author seke
*/
public class QueryOSM {
// 可利用下址測試查詢指令
// http://overpass-turbo.eu/
public static String composeRequest()
{
/* 查詢範例1:
在(47.48047027491862,19.039797484874725,47.51331674014172,19.07404761761427)範圍內
列出所有非私人停車場
A. 查詢指令
["out":"json"]["timeout":"30"];
(
node
["amenity"="parking"]
["access"!="private"]
(47.48047027491862,19.039797484874725,47.51331674014172,19.07404761761427);
<;
);
out body center qt 100;
B. 組合查詢指令方法
String query = new OverpassQuery()
.format(OutputFormat.JSON)
.timeout(30)
.filterQuery()
.node()
.amenity("parking")
.tagNot("access", "private")
.boundingBox(
47.48047027491862, 19.039797484874725,
47.51331674014172, 19.07404761761427
)
.end()
.output(OutputVerbosity.BODY, OutputModificator.CENTER, OutputOrder.QT, 100)
.build()
;
*/
/* 查詢範例2:
在(25.1735, 121.446, 25.1775, 121.455)範圍內,撈取
非座椅設施,商店,觀光點,辦公室,繄急設施之節點
屬於大學設施之線條,關係
不屬於公路、路線、森林、邊界之線條,關係
列出其中心位置及相關屬性(標籤)
A. 查詢指令
[out:json][timeout:25];
// gather results
(
node[amenity][amenity!=bench](25.1735, 121.446, 25.1775, 121.455);
node[shop](25.1735, 121.446, 25.1775, 121.455);
node[tourism](25.1735, 121.446, 25.1775, 121.455);
node[office](25.1735, 121.446, 25.1775, 121.455);
node[emergency](25.1735, 121.446, 25.1775, 121.455);
//way[amenity="university"](25.1735, 121.446, 25.1775, 121.455);
relation[amenity="university"](25.1735, 121.446, 25.1775, 121.455);
way[!highway][type!="route"][landuse!="forest"][!boundary](25.1735, 121.446, 25.1775, 121.455);
relation[!highway][type!="route"][!boundary](25.1735, 121.446, 25.1775, 121.455);
);
// print results
out center;
---
註: 淡江大學之範圍為 25.1735, 121.446, 25.1775, 121.455
*/
String query = String.join("\n",
"[out:json][timeout:25];",
"(",
// "node[amenity][amenity!=bench](25.1735, 121.446, 25.1775, 121.455);",
// "node[shop](25.1735, 121.446, 25.1775, 121.455);",
"node[tourism](25.1735, 121.446, 25.1775, 121.455);",
// "node[office](25.1735, 121.446, 25.1775, 121.455);",
// "node[emergency](25.1735, 121.446, 25.1775, 121.455);",
// "relation[amenity='university'](25.1735, 121.446, 25.1775, 121.455);",
// "way[!highway][type!='route'][landuse!='forest'][!boundary](25.1735, 121.446, 25.1775, 121.455);",
"relation[!highway][type!='route'][!boundary](25.1735, 121.446, 25.1775, 121.455);",
");",
"out center;");
System.out.println(query);
return query;
}
public static void asyncRequest(OverpassService apiClient, String request)
{
//Call call = service.interpreter(query);
apiClient.interpreter(request).enqueue(new Callback()
{
@Override
public void onResponse(Call call, Response response)
{
if(response.isSuccessful()==false)
{
System.out.println("asyncRequest: response.isSuccessful(): false");
System.out.println(response.errorBody());
return;
}
OverpassQueryResult result = response.body();
postProcess(result);
}
public void onFailure(Call call, Throwable t) {
// DO failure handling
System.out.println("onFailure");
System.out.println(t.getLocalizedMessage());
}
});
System.out.println("end of asyncRequest()");
}
public static OverpassQueryResult syncRequest(OverpassService apiClient, String request)
{
OverpassQueryResult result = null;
Call callSync = apiClient.interpreter(request);
try
{
Response response = callSync.execute();
//OverpassQueryResult apiResponse = response.body();
//API response
System.out.println(response);
result = response.body();
}
catch (Exception ex)
{
ex.printStackTrace();
}
System.out.println("end of syncRequest()");
return result;
}
public static void postProcess(OverpassQueryResult result)
{
if(result==null) return;
// DO success handling
StringBuilder sb = new StringBuilder();
System.out.println(result.elements.size() + " elements...");
int count = 1;
for (Element p : result.elements)
{
sb.append(count); count++;
sb.append(String.format(". id:%s, type:%s, lat:%s, lon:%s", p.id, p.type, p.lat, p.lon));
Tags tags = p.tags;
for (Field f : tags.getClass().getFields()) {
f.setAccessible(true);
try
{
if (f.get(tags) != null) {
sb.append(String.format(", %s:%s", f.getName(), f.get(tags)));
}
}
catch (IllegalAccessException e)
{ // shouldn't happen because I used setAccessible
}
}
//if(p.tags. != null)
// sb.append(String.format("tags:%s", p.tags.name));
sb.append("\n");
}
System.out.println(sb.toString());
}
public static void main(String args[])
{
// 建立服務連線客戶端及請求內容
OverpassService requestClient = OverpassServiceProvider.get();
String request = composeRequest();
// 非同步請求
asyncRequest(requestClient, request);
// 同步請求
OverpassQueryResult result = syncRequest(requestClient, request);
postProcess(result);
System.out.println("end of main()");
}
}