osmdroid
osmdroid是一個開源項目,其目的是提供比安卓原生的MapView更為強大的地圖組件庫。osmdroid支持多種在線或者離線的瓦片地圖源以及地圖覆蓋管理器,用于繪制圖標(biāo)降铸、幾何圖形以及GPS定位住拭。
osmdroid相比于Android原生MapView的優(yōu)勢在于其豐富的瓦片地圖源和地圖覆蓋管理器了。相比于Arcgis Android Runtime SDK這種專業(yè)的GIS開發(fā)包在功能上的劣勢非常明顯柱嫌,但也有其優(yōu)勢也很明顯——輕量锋恬。一個使用了Arcgis Android Runtime SDK的APP,如果完整支持arm64-v8a编丘、armeabi-v7a与学、armeabi、x86的話嘉抓,apk文件至少60M索守,僅支持armeabi-v7a也在30M以上,而使用osmdroid的APP的APK通常只有幾M抑片。
ArcgisServer的地圖服務(wù)
Arcgis可以說是GIS領(lǐng)域最強大的軟件卵佛,沒有之一。Esri公司也是一家值得尊重的公司敞斋,一直在致力于GIS領(lǐng)域新技術(shù)的開發(fā)以及Arcgis和互聯(lián)網(wǎng)新科技的融合截汪。ArcgisServer提供了目前市場上最強大最豐富的的GIS領(lǐng)域的服務(wù),包括地圖服務(wù)植捎,瓦片服務(wù)衙解,矢量切片服務(wù),要素服務(wù)焰枢,分析服務(wù)蚓峦,幾何網(wǎng)絡(luò)服務(wù)等等等。
osmdroid主要是一個MapView医咨,矢量切片這種新技術(shù)完全不支持枫匾,瓦片服務(wù)本來就支持,只有地圖服務(wù)拟淮,osmdroid原本不支持干茉,但有潛力。這里說的潛力很泊,是因為Arcgis的地圖服務(wù)是通過export接口返回的一張圖片角虫,在數(shù)據(jù)源上與瓦片地圖沒有區(qū)別。
以瓦片的形式請求地圖服務(wù)
在ArcgisServer地圖服務(wù)的地圖請求鏈接一般形式如下:http://192.168.1.28:6080/arcgis/rest/services/NHCT/MapServer/export?bbox=114.36767578125,30.519681272749406,114.3731689453125,30.524413269923976&bboxSR=4326&size=256,256&format=png24&transparent=true&dpi=96&f=image委造,其中bbox表示請求的地圖的范圍戳鹅,size表示請求的圖片的大小,format表示請求的圖片的格式昏兆,transparent表示沒有數(shù)據(jù)的部分是否透明枫虏,如果format不為png時,transparent參數(shù)無效。f表示以圖片的形式返回隶债,另外還有json和html的形式腾它。
我們要以瓦片的形式請求地圖服務(wù),重點就在算出每個請求瓦片的bbox死讹,其邏輯代碼如下瞒滴。
public static BoundingBox tile2boundingBox(final int x, final int y, final int zoom)
{
BoundingBox bb = new BoundingBox(tile2lat(y, zoom), tile2lon(x + 1, zoom), tile2lat(y + 1, zoom), tile2lon(x, zoom));
return bb;
}
public static double tile2lon(int x, int z) {
return x / Math.pow(2.0, z) * 360.0 - 180;
}
public static double tile2lat(int y, int z) {
double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
return Math.toDegrees(Math.atan(Math.sinh(n)));
}
當(dāng)然如果是莫卡托投影的,就不是經(jīng)緯度了
public double[] getBoundingBox(int x, int y, int zoom) {
double tileSize = MAP_SIZE / Math.pow(2, zoom);
double minx = TILE_ORIGIN[ORIG_X] + x * tileSize;
double maxx = TILE_ORIGIN[ORIG_X] + (x + 1) * tileSize;
double miny = TILE_ORIGIN[ORIG_Y] - (y + 1) * tileSize;
double maxy = TILE_ORIGIN[ORIG_Y] - y * tileSize;
double[] bbox = new double[4];
bbox[MINX] = minx;
bbox[MINY] = miny;
bbox[MAXX] = maxx;
bbox[MAXY] = maxy;
return bbox;
}
然后照著請求瓦片一樣請求就可以了
@Override
public String getTileURLString(long pMapTileIndex) {
String baseUrl = getBaseUrl();
if (forceHttps)
baseUrl = baseUrl.replace("http://", "https://");
if (forceHttp)
baseUrl = baseUrl.replace("https://", "http://");
StringBuilder sb = new StringBuilder(baseUrl);
if (!baseUrl.endsWith("/"))
sb.append("/");
sb.append("export?").append("bbox=");
if (srs.equals("EPSG:900913")) {
double[] bbox = getBoundingBox(MapTileIndex.getX(pMapTileIndex), MapTileIndex.getY(pMapTileIndex), MapTileIndex.getZoom(pMapTileIndex));
sb.append(bbox[MINX]).append(",");
sb.append(bbox[MINY]).append(",");
sb.append(bbox[MAXX]).append(",");
sb.append(bbox[MAXY]);
} else {
BoundingBox boundingBox = tile2boundingBox(MapTileIndex.getX(pMapTileIndex), MapTileIndex.getY(pMapTileIndex), MapTileIndex.getZoom(pMapTileIndex));
sb.append(boundingBox.getLonWest()).append(",");
sb.append(boundingBox.getLatSouth()).append(",");
sb.append(boundingBox.getLonEast()).append(",");
sb.append(boundingBox.getLatNorth());
}
sb.append("&bboxSR=").append(srs.replace("EPSG:","")).append("&size=").append(getTileSizePixels()).append(",").append(getTileSizePixels());
sb.append("&format=png24").append("&transparent=true").append("&dpi=96").append("&f=image");
String str = sb.toString();
return str;
}
這個思路不是我的赞警,而是在osmdroid中自帶一個osmdroid-wms的子項目妓忍,我心想WMS和ArcgisServer的地圖服務(wù)原理一致,前者可以后者當(dāng)然也可以愧旦,所以就仔細閱讀了一下osmdroid-wms的源碼世剖,參照WMSTileSource類寫了一個ArcgisServer地圖服務(wù)的DataSource,核心代碼就是上面那些了笤虫。