首先说一下我的需求,需要将百度地图绘制的相交圆做并集处理(如下图所示),可能是我比较 low,并没有在百度地图的 API 上找到这样的方法,如果有哪位大佬知道怎么使用百度地图直接实现,或者更简单的办法,请留言告诉我,不胜感激。
然后,我就想到了根据坐标点在 arcgis
上先处理,生成 shape
文件后,通过百度地图的 叠加自定义图层 案例,结合网上的教程,成功实现。让人操蛋的是,墙内的博客都是一个抄一个的,当你遇到问题的时候,百度一下你能发现一串博客内容都是一样的,就像我百度 百度地图加载 wms
你都能找到这段代码,不能说毫无关联,只能说一模一样。
tileLayer.getTilesUrl = function(tileCoord, zoom) {
var x = tileCoord.x;
var y = tileCoord.y;
//console.log("X: " + x + " Y : " + y + " Z: " + zoom);
//下面这一段代码和上面的代码效果一模一样!!!利用的公瑾提供的一个js实现坐标转换,地址为:https://github.com/FreeGIS/coordtransform
var res = resolutions[zoom];
var tileWidth = 256;
var minx = x * tileWidth * res;
var miny = y * tileWidth * res;
var maxx = (x + 1) * tileWidth * res;
var maxy = (y + 1) * tileWidth * res;
var bottomLeft = coordtransform.BD_MKT2WGS(minx, miny); //百度墨卡托坐标-》百度经纬度坐标
var topRight = coordtransform.BD_MKT2WGS(maxx, maxy);
bottomLeft = coordtransform.BD2WGS(bottomLeft[0], bottomLeft[1])
topRight = coordtransform.BD2WGS(topRight[0], topRight[1])
var bbox2 = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]]; //计算出bbox
console.log(bbox2);
//根据geoserver WMS服务的规则设置URL
//
var url = 'http://localhost:2000/geoserver/huangong/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=true&tiled=true&STYLES&LAYERS=huangong%3Apng-qingping&tilesOrigin=104.069%2C31.489&WIDTH=256&HEIGHT=256&SRS=EPSG%3A4326&BBOX=' +
//var url = 'http://localhost:8080/geoserver/fsum/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image/png&LAYERS=fsum:T_UM_MAP_DISTRICT_GEOMETRY&TRANSPARENT=true&tiled=true&SRS=EPSG:4326&WIDTH=256&HEIGHT=256&BBOX=' +
bbox2.join(',');
//console.log(bbox.join(','));
return url;
}
其中使用到的 coordtransform.BD_MKT2WGS(lon, lat);
和 coordtransform.BD2WGS(lon, lat)
这两个方法就是没有人贴出来,兴致冲冲的以为自己即将实现图层加载的时候发现,没有这两个方法,难过吧。
好了,废话就说到这里,下面讲讲我是怎么实现的。
将图层发布到 GeoServer
EPSG:3857 Pseudo Mercator
是用于在 Google 地图,OpenStreetMap 等呈现地图的投影坐标系,像国内的互联网地图如百度、高德、腾讯也是使用的这一坐标系。因此,我的操作是根据坐标,使用 arcgis 绘制出半径为 500
的缓冲区,采用 EPSG:3857
坐标系保存成 Shape 文件,发布到 GeoServer。
然后新建 GeoServer 的 Style,我这里的操作比较简单,就是将 polygon 的样式复制过来,将 Fill
的颜色改为透明色 transparent
,保存为 my_polygon,如下:
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- a Named Layer is the basic building block of an SLD document -->
<NamedLayer>
<Name>default_polygon</Name>
<UserStyle>
<!-- Styles can have names, titles and abstracts -->
<Title>Default Polygon</Title>
<Abstract>A sample style that draws a polygon</Abstract>
<!-- FeatureTypeStyles describe how to render different features -->
<!-- A FeatureTypeStyle for rendering polygons -->
<FeatureTypeStyle>
<Rule>
<Name>rule1</Name>
<Title>Gray Polygon with Black Outline</Title>
<Abstract>A polygon with a gray fill and a 1 pixel black outline</Abstract>
<PolygonSymbolizer>
<Fill>
<CssParameter name="fill">transparent</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#000000</CssParameter>
<CssParameter name="stroke-width">1</CssParameter>
</Stroke>
</PolygonSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
发布图层的时候选择 my_polygon
就好了。
加载图层
let resolutions = []
for (let i = 0; i < 19; i++) {
resolutions[i] = Math.pow(2, 18 - i);
}
let tileLayer = new BMap.TileLayer({
isTransparentPng: true
});
tileLayer.getTilesUrl = function(tileCoord, zoom) {
let x = tileCoord.x;
let y = tileCoord.y;
let res = resolutions[zoom];
let tileWidth = 256;
let minx = x * tileWidth * res;
let miny = y * tileWidth * res;
let maxx = (x + 1) * tileWidth * res;
let maxy = (y + 1) * tileWidth * res;
// 百度墨卡托坐标 ->百度经纬度坐标
let bottomLeft = CoordinateTransform.BD_MKT2WGS(minx, miny);
let topRight = CoordinateTransform.BD_MKT2WGS(maxx, maxy);
// 计算出bbox
let bbox2 = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]];
return 'http://localhost:8080/geoserver/test/wms?' +
'SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&' +
'TRANSPARENT=true&tiled=true&STYLES&LAYERS=test%3AExport_Output_2&WIDTH=256&HEIGHT=256&SRS=EPSG%3A3857&BBOX=' +
bbox2.join(',');
}
map.addTileLayer(tileLayer);
- 由于我发布的是
EPSG:3857
,所以 url 中SRS
也改为SRS=EPSG%3A3857
坐标转换文件 CoordinateTransform.js
/**
* Created by Daniel on 2016/7/27.
*
* 提供了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
*
* 会有偏差,但是偏差在可接受范围之内
*/
(function(root, factory) {
root.CoordinateTransform = factory();
}(this, function() {
var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
var PI = 3.1415926535897932384626;
var a = 6378245.0;
var ee = 0.00669342162296594323;
var MCBAND = [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0];
var MC2LL = [
[1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 17337981.2],
[-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 10260144.86],
[-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37],
[-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06],
[3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, 23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4],
[2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, 7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, 0.00010322952773, -0.00000323890364, 826088.5]
];
/**
* 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
* 即 百度 转 谷歌、高德
* @param bd_lon
* @param bd_lat
* @returns {[]} GCJ-02 坐标:[经度,纬度]
*/
var transformBD09ToGCJ02 = function(bd_lon, bd_lat) {
var x = bd_lon - 0.0065;
var y = bd_lat - 0.006;
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
var gg_lng = z * Math.cos(theta);
var gg_lat = z * Math.sin(theta);
return [gg_lng, gg_lat]
};
/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
* 即谷歌、高德 转 百度
* @param lng
* @param lat
* @returns {[]} BD-09 坐标:[经度,纬度]
*/
var transformGCJ02ToBD09 = function(lng, lat) {
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
var bd_lng = z * Math.cos(theta) + 0.0065;
var bd_lat = z * Math.sin(theta) + 0.006;
return [bd_lng, bd_lat]
};
/**
* WGS84转GCj02
* @param lng
* @param lat
* @returns {[]} GCj02 坐标:[经度,纬度]
*/
var transformWGS84ToGCJ02 = function(lng, lat) {
if (outOfChina(lng, lat)) {
return [lng, lat]
} else {
var dLat = transformLat(lng - 105.0, lat - 35.0);
var dLng = transformLng(lng - 105.0, lat - 35.0);
var radLat = lat / 180.0 * PI;
var magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
var sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
var mgLat = lat + dLat;
var mgLng = lng + dLng;
return [mgLng, mgLat]
}
};
/**
* GCJ02 转换为 WGS84
* @param lng
* @param lat
* @returns {[]} WGS84 坐标:[经度,纬度]
*/
var transformGCJ02ToWGS84 = function(lng, lat) {
if (outOfChina(lng, lat)) {
return [lng, lat]
} else {
var dLat = transformLat(lng - 105.0, lat - 35.0);
var dLng = transformLng(lng - 105.0, lat - 35.0);
var radLat = lat / 180.0 * PI;
var magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
var sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
var mgLat = lat + dLat;
var mgLng = lng + dLng;
return [lng * 2 - mgLng, lat * 2 - mgLat]
}
};
var transformLonLatToMecator = function(lng, lat) {
let earthRad = 6378137.0;
let x = lng * Math.PI / 180 * earthRad;
let a = lat * Math.PI / 180;
let y = earthRad / 2 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
return [x, y]; //[12727039.383734727, 3579066.6894065146]
}
/**
* 百度坐标BD09 转 WGS84
*
* @param lng 经度
* @param lat 纬度
* @return {[]} WGS84 坐标:[经度,纬度]
*/
var transformBD09ToWGS84 = function(lng, lat) {
var lngLat = transformBD09ToGCJ02(lng, lat);
return transformGCJ02ToWGS84(lngLat[0], lngLat[1]);
};
/**
* WGS84 转 百度坐标BD09
*
* @param lng 经度
* @param lat 纬度
* @return {[]} BD09 坐标:[经度,纬度]
*/
var transformWGS84ToBD09 = function(lng, lat) {
var lngLat = transformWGS84ToGCJ02(lng, lat);
return transformGCJ02ToBD09(lngLat[0], lngLat[1]);
};
var transformLat = function(lng, lat) {
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
return ret
};
var transformLng = function(lng, lat) {
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
return ret
};
/**
* 判断是否在国内,不在国内则不做偏移
* @param lng
* @param lat
* @returns {boolean}
*/
var outOfChina = function(lng, lat) {
return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
};
var BD_MKT2WGS = function BD_MKT2WGS(lng, lat) {
var cF = null;
lng = Math.abs(lng);
lat = Math.abs(lat);
for (var cE = 0; cE < MCBAND.length; cE++) {
if (lat >= MCBAND[cE]) {
cF = MC2LL[cE];
break;
}
}
lng = cF[0] + cF[1] * Math.abs(lng);
var cC = Math.abs(lat) / cF[9];
lat = cF[2] + cF[3] * cC + cF[4] * cC * cC + cF[5] * cC * cC * cC + cF[6] * cC * cC * cC * cC + cF[7] * cC * cC * cC * cC * cC + cF[8] * cC * cC * cC * cC * cC * cC;
lng *= (lng < 0 ? -1 : 1);
lat *= (lat < 0 ? -1 : 1);
return [lng, lat];
}
return {
transformBD09ToWGS84: transformBD09ToWGS84,
transformWGS84ToBD09: transformWGS84ToBD09,
transformGCJ02ToWGS84: transformGCJ02ToWGS84,
transformWGS84ToGCJ02: transformWGS84ToGCJ02,
transformBD09ToGCJ02: transformBD09ToGCJ02,
transformGCJ02ToBD09: transformGCJ02ToBD09,
transformLonLatToMecator: transformLonLatToMecator,
BD_MKT2WGS: BD_MKT2WGS
}
}));
BD_MKT2WGS(lon, lat)
方法就在里面。