效果图(灰色两块为自定义瓦片):
需求:在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;
}