近日项目需要,需要使用腾讯地图SDK进行二次开发,加载Geoserver发布的影像图层。现在就将加载过程记录一下。注:以腾讯地图官方文档为参考。
最终的效果:
首先需要在腾讯地图官网申请KEY值,申请过程请看官方文档中的介绍。加载图层的主要文档在Android地图SDK文档中“自定义瓦片层”章节。
首先准备一个实体类和一个工具类。
PositionModel:
public class PositionModel {
private double wgLat;
private double wgLon;
public PositionModel(double wgLat, double wgLon) {
setWgLat(wgLat);
setWgLon(wgLon);
}
public double getWgLat() {
return wgLat;
}
public void setWgLat(double wgLat) {
this.wgLat = wgLat;
}
public double getWgLon() {
return wgLon;
}
public void setWgLon(double wgLon) {
this.wgLon = wgLon;
}
@Override
public String toString() {
return wgLat + "," + wgLon;
}
}
PositionUtil:
public class PositionUtil {
public static final String BAIDU_LBS_TYPE = "bd09ll";
public static double pi = 3.1415926535897932384626;
public static double a = 6378245.0;
public static double ee = 0.00669342162296594323;
/**
* * 火星坐标系 (GCJ-02) to 84 * * @param longitude * @param latitude * @return
*/
public static PositionModel gcj_To_Gps84(double lat, double lon) {
PositionModel gps = transform(lat, lon);
double lontitude = lon * 2 - gps.getWgLon();
double latitude = lat * 2 - gps.getWgLat();
return new PositionModel(latitude, lontitude);
}
public static boolean outOfChina(double lat, double lon) {
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
}
public static PositionModel transform(double lat, double lon) {
if (outOfChina(lat, lon)) {
return new PositionModel(lat, lon);
}
double dLat = transformLat(lon - 105.0, lat - 35.0);
double dLon = transformLon(lon - 105.0, lat - 35.0);
double radLat = lat / 180.0 * pi;
double magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return new PositionModel(mgLat, mgLon);
}
public static double transformLat(double x, double y) {
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
+ 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
return ret;
}
public static double transformLon(double x, double y) {
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
* Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
* pi)) * 2.0 / 3.0;
return ret;
}
}
接下来写一个MyTileProvider类继承腾讯地图的UrlTileProvider类。
public class MyTileProvider extends UrlTileProvider {
private String mRootUrl;
//默认瓦片大小
private static int titleSize = 256;//a=6378137±2(m)
//基本参数
private final double initialResolution= 156543.03392804062;//2*Math.PI*6378137/titleSize;
private final double originShift = 20037508.342789244;//2*Math.PI*6378137/2.0; 周长的一半
private final double HALF_PI = Math.PI / 2.0;
private final double RAD_PER_DEGREE = Math.PI / 180.0;
private final double HALF_RAD_PER_DEGREE = Math.PI / 360.0;
private final double METER_PER_DEGREE = originShift / 180.0;//一度多少米
private final double DEGREE_PER_METER = 180.0 / originShift;//一米多少度
public MyTileProvider(){
super(titleSize,titleSize);
//地址写自己的服务地址
mRootUrl ="http://xxx.xxx.xx.xx:xxxx/geoserver/ksh/wms?service=WMS&version=1.1.0&request=GetMap&layers=ksh:xmh-2020-1m&styles=&width=650&height=768&srs=EPSG:3857&TRANSPARENT=TRUE&format=image%2Fpng&bbox=";//png
}
public MyTileProvider(int i, int i1) {
super(i, i1);
}
@Override
public URL getTileUrl(int x, int y, int zoom) {
try {
String url = mRootUrl + TitleBounds(x, y, zoom);
URL l=new URL(url);
LogUtils.e("mRootUrl:"+l);
return new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
/**
* @Date: 2020/10/14 15:20
* @Author: zhj
* @Description: 检查当前瓦片地址是否有数据
*/
private boolean checkTileExists(int x, int y, int zoom) {
int minZoom = 12;
int maxZoom = 16;
if ((zoom < minZoom || zoom > maxZoom)) {
return false;
}
return true;
}
/**
* 根据像素、等级算出坐标
*
* @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);
PositionModel position1 = PositionUtil.gcj_To_Gps84(minY,minX);
minX = position1.getWgLon();
minY = position1.getWgLat();
PositionModel position2 = PositionUtil.gcj_To_Gps84(maxY,maxX);
maxX = position2.getWgLon();
maxY = position2.getWgLat();
minX=Lon2Meter(minX);
minY=Lat2Meter(minY);
maxX=Lon2Meter(maxX);
maxY=Lat2Meter(maxY);
return minX + "," + Double.toString(minY) + "," + Double.toString(maxX) + "," + Double.toString(maxY);
}
/**
* 计算分辨率
*
* @param zoom
* @return
*/
private double Resolution(int zoom) {
return initialResolution / (Math.pow(2, zoom));
}
/**
* X米转经纬度
*/
private double Meters2Lon(double mx) {
double lon = mx * DEGREE_PER_METER;
return lon;
}
/**
* Y米转经纬度
*/
private double Meters2Lat(double my) {
double lat = my * DEGREE_PER_METER;
lat = 180.0 / Math.PI * (2 * Math.atan(Math.exp(lat * RAD_PER_DEGREE)) - HALF_PI);
return lat;
}
/**
* X经纬度转米
*/
private double Lon2Meter(double lon) {
double mx = lon * METER_PER_DEGREE;
return mx;
}
/**
* Y经纬度转米
*/
private double Lat2Meter(double lat) {
double my = Math.log(Math.tan((90 + lat) * HALF_RAD_PER_DEGREE)) / (RAD_PER_DEGREE);
my = my * METER_PER_DEGREE;
return my;
}
}
注意填写自己服务地址的时候,有可能需要对URL路径做些改变。
①加载的图层服务需要是png格式;
②注意坐标系需要改成EPSG:3857,其他坐标系加载不上;
③如果加载的瓦片图层除了需要的影像外,其他的部分都会白色的瓦片,这就需要在URL中添加“TRANSPARENT=TRUE”;
④需要把URL中原来bbox=之后的坐标值全删掉,并且剪切“bbox=”到URL的最后,以为在上述程序中将原有的坐标转化成需要的坐标,然后拼接到bbox后面了。
添加瓦片图层到地图上。
public TileOverlay addMyTileProvider(TencentMap map){
MyTileProvider provider = new MyTileProvider();
options = new TileOverlayOptions();
options.diskCacheDir("/map/") //设置瓦片缓存目录
.betterQuality(true) //设置瓦片图片质量
.zIndex(10) //设置瓦片压盖级别
.tileProvider(provider);
tileOverlay=map.addTileOverlay(options);
return tileOverlay;
}
注意需要定义titleOverlay。
private TileOverlay tileOverlay;
private TileOverlayOptions options;
然后调用该方法即可。
addMyTileProvider(tencentMap);
tencentMap是获取的腾讯地图控件。
TencentMap tencentMap=mainMap.getMap();
最后记录一下,怎么删除图层。
直接使用这个方法即可。
tileOverlay.remove();
注:titleOverlay需要先获取值,即添加瓦片方法中的tileOverlay=map.addTileOverlay(options)。
然后才可以调用该方法。