百度地图如何成功加载 GeoServer 的 WMS 图层

2021-06-29  本文已影响0人  Edwinpanzzz

首先说一下我的需求,需要将百度地图绘制的相交圆做并集处理(如下图所示),可能是我比较 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 坐标系自动填充 EPSG:3857

然后新建 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 就好了。

image.png

加载图层

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);

坐标转换文件 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) 方法就在里面。

上一篇下一篇

猜你喜欢

热点阅读