osmdroid
osmdroid是一個(gè)開源項(xiàng)目,其目的是提供比安卓原生的MapView更為強(qiáng)大的地圖組件庫。osmdroid支持多種在線或者離線的瓦片地圖源以及地圖覆蓋管理器,用于繪制圖標(biāo)、幾何圖形以及GPS定位。
osmdroid相比于Android原生MapView的優(yōu)勢(shì)在于其豐富的瓦片地圖源和地圖覆蓋管理器了。相比于Arcgis Android Runtime SDK這種專業(yè)的GIS開發(fā)包在功能上的劣勢(shì)非常明顯,但也有其優(yōu)勢(shì)也很明顯——輕量。一個(gè)使用了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)域最強(qiáng)大的軟件,沒有之一。Esri公司也是一家值得尊重的公司,一直在致力于GIS領(lǐng)域新技術(shù)的開發(fā)以及Arcgis和互聯(lián)網(wǎng)新科技的融合。ArcgisServer提供了目前市場(chǎng)上最強(qiáng)大最豐富的的GIS領(lǐng)域的服務(wù),包括地圖服務(wù),瓦片服務(wù),矢量切片服務(wù),要素服務(wù),分析服務(wù),幾何網(wǎng)絡(luò)服務(wù)等等等。
osmdroid主要是一個(gè)MapView,矢量切片這種新技術(shù)完全不支持,瓦片服務(wù)本來就支持,只有地圖服務(wù),osmdroid原本不支持,但有潛力。這里說的潛力,是因?yàn)锳rcgis的地圖服務(wù)是通過export接口返回的一張圖片,在數(shù)據(jù)源上與瓦片地圖沒有區(qū)別。
以瓦片的形式請(qǐng)求地圖服務(wù)
在ArcgisServer地圖服務(wù)的地圖請(qǐng)求鏈接一般形式如下: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表示請(qǐng)求的地圖的范圍,size表示請(qǐng)求的圖片的大小,format表示請(qǐng)求的圖片的格式,transparent表示沒有數(shù)據(jù)的部分是否透明,如果format不為png時(shí),transparent參數(shù)無效。f表示以圖片的形式返回,另外還有json和html的形式。
我們要以瓦片的形式請(qǐng)求地圖服務(wù),重點(diǎn)就在算出每個(gè)請(qǐng)求瓦片的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;
}
然后照著請(qǐng)求瓦片一樣請(qǐng)求就可以了
@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;
}
這個(gè)思路不是我的,而是在osmdroid中自帶一個(gè)osmdroid-wms的子項(xiàng)目,我心想WMS和ArcgisServer的地圖服務(wù)原理一致,前者可以后者當(dāng)然也可以,所以就仔細(xì)閱讀了一下osmdroid-wms的源碼,參照WMSTileSource類寫了一個(gè)ArcgisServer地圖服務(wù)的DataSource,核心代碼就是上面那些了。