效果圖(灰色兩塊為自定義瓦片):
需求:在Android高德地圖上需要加載wms服務,用於顯示自己繪制的瓦片地圖。
由於需要在指定的位置添加一小塊瓦片地圖,所以在制作瓦片地圖時需要參照高德地圖底圖作為參照進行圖形繪制,但是因為網上沒有找到具體可以參考的高德地圖底圖,本文采用天地圖作為參照地圖進行繪制,繪制后再通過經緯度坐標轉換為高德地圖對應的經緯度(網上有對應的轉換代碼)。
1、在ArcGis10.2中繪制瓦片地圖保存為shapefile文件格式
本文采用ArcGis10.2進行瓦片地圖的繪制,繪制前需要設置投影坐標系為EPSG:3857即墨卡托投影坐標系(900913),高德地圖也正是采用此坐標系統,本地采用 “聚合天地圖DOM瓦片地圖服務http://www.scgis.net.cn/imap/iMapServer/defaultRest/services/newtianditudom/WMS”作為底圖在其上進行繪制並導出shapefile文件。
繪制后的圖形如下:
2、通過GeoServer加載shapefile文件並發布wms服務。
關於部署GeoServer.war這個步驟請自行百度,圖中展示了發布wms的幾個關鍵步驟:
完成上面幾個步驟后就發布好了wms服務,地址為:http://localhost:8088/geoserver/hbgeo/wms?service=WMS&version=1.1.0&request=GetMap&layers=hbgeo:New_Shapefile2&
styles=&bbox=1.0842895202208204E7,4378002.325541817,1.1215106468992202E7,4638208.485151819
&width=768&height=536&srs=EPSG:3857&format=application/openlayers
注意此處地址對於android開發我們只需要精簡一下參數就可以了,bbox的值去掉(投影范圍有專門的計算方法往文章后面看),format需要改為image%2Fpng(即瓦片.png圖片格式),width/height默認為256也可以去掉,最后得到的地址為:
http://192.168.58.226:8088/geoserver/hbgeo/wms?LAYERS=hbgeo:New_Shapefile2&FORMAT=image%2Fpng
&TRANSPARENT=TRUE&SERVICE=WMS&VERSION=1.1.1
&REQUEST=GetMap&STYLES=&SRS=EPSG:3857&BBOX=
到此為止wms服務地址已經准備好了,接下來只需要調用高德地圖SDK中加載瓦片地圖的方法即可,其中涉及到投影坐標的范圍即bbox計算。
3、調用高德地圖sdk加載瓦片地址
對於坐標系及瓦片地圖加載原理可以參看里面的章節:http://weilin.me/ol3-primer/ch05/05-03.html
bbox覆蓋范圍求解:
請參考https://github.com/yxj1990/eye/wiki/%E5%85%B3%E4%BA%8E%E9%AB%98%E5%BE%B7API%
E5%8A%A0%E8%BD%BDwms%E5%9C%B0%E5%9B%BE%E6%9C%8D%E5%8A%A1%E5%9D%90%E6%A0%87
%E5%81%8F%E7%A7%BB%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88
思路: (1)在墨卡托投影系中先根據行列號求出瓦片的范圍(米); (2)將瓦片范圍轉換為度; (3)利用高德api轉換工具求出正常坐標和高德坐標的差; (4)在(2)的坐標加上差值得到正確坐標,即可獲取到正確的瓦片。
調用高德地圖sdk加載WMS服務地址核心片段:
TileOverlay scopeTileOverlay;
int titleSize = 256;
double initialResolution = 156543.03392804062;//2*Math.PI*6378137/titleSize;//
double originShift = 20037508.342789244;//2*Math.PI*6378137/2.0;//
String url = "";
/**
* 添加wms圖層
*/
protected void addScope() {
url = "http://192.168.58.226:8088/geoserver/hbgeo/wms?LAYERS=hbgeo:New_Shapefile2&FORMAT=image%2Fpng&TRANSPARENT=TRUE&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&SRS=EPSG:3857&BBOX=";
TileProvider tileProvider = new UrlTileProvider(256, 256) {
@Override
public URL getTileUrl(int x, int y, int zoom) {
try {
System.out.println(x + "/" + y + "/" + zoom + "=====>" + url + TitleBounds(x, y, zoom));
return new URL(url + TitleBounds(x, y, zoom));
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
};
if (tileProvider != null) {
scopeTileOverlay = aMap.addTileOverlay(new TileOverlayOptions()
.tileProvider(tileProvider)
.diskCacheDir("/storage/amap/cache").diskCacheEnabled(true)
.diskCacheSize(100));
}
}
/**
* 根據像素、等級算出坐標
*
* @param p
* @param zoom
* @return
*/
private double Pixels2Meters(int p, int zoom) {
return p * Resolution(zoom) - originShift;
}
/**
* 根據瓦片的x/y等級返回瓦片范圍
*
* @param tx
* @param ty
* @param zoom
* @return
*/
private String TitleBounds(int tx, int ty, int zoom) {
double minX = Pixels2Meters(tx * titleSize, zoom);
double maxY = -Pixels2Meters(ty * titleSize, zoom);
double maxX = Pixels2Meters((tx + 1) * titleSize, zoom);
double minY = -Pixels2Meters((ty + 1) * titleSize, zoom);
//轉換成經緯度
minX = Meters2Lon(minX);
minY = Meters2Lat(minY);
maxX = Meters2Lon(maxX);
maxY = Meters2Lat(maxY);
//經緯度轉換米
// minX=Lon2Meter(minX);
// minY=Lat2Meter(minY);
// maxX=Lon2Meter(maxX);
// maxY=Lat2Meter(maxY);
//坐標轉換工具類構造方法 GPS( WGS-84) 轉 為高德地圖需要的坐標
CoordinateConverter converter = new CoordinateConverter(this);
converter.from(CoordinateConverter.CoordType.GPS);
converter.coord(new LatLng(minY, minX));
LatLng min = converter.convert();
converter.coord(new LatLng(maxY, maxX));
LatLng max = converter.convert();
minX = Lon2Meter(-min.longitude + 2 * minX);
minY = Lat2Meter(-min.latitude + 2 * minY);
maxX = Lon2Meter(-max.longitude + 2 * maxX);
maxY = Lat2Meter(-max.latitude + 2 * maxY);
return Double.toString(minX) + "," + Double.toString(minY) + "," + Double.toString(maxX) + "," + Double.toString(maxY) + "&WIDTH=256&HEIGHT=256";
}
/**
* 計算分辨率
*
* @param zoom
* @return
*/
private double Resolution(int zoom) {
return initialResolution / (Math.pow(2, zoom));
}
/**
* X米轉經緯度
*/
private double Meters2Lon(double mx) {
double lon = (mx / originShift) * 180.0;
return lon;
}
/**
* Y米轉經緯度
*/
private double Meters2Lat(double my) {
double lat = (my / originShift) * 180.0;
lat = 180.0 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);
return lat;
}
/**
* X經緯度轉米
*/
private double Lon2Meter(double lon) {
double mx = lon * originShift / 180.0;
return mx;
}
/**
* Y經緯度轉米
*/
private double Lat2Meter(double lat) {
double my = Math.log(Math.tan((90 + lat) * Math.PI / 360.0)) / (Math.PI / 180.0
);
my = my * originShift / 180.0;
return my;
}