---
title: 百度地图与CAD图叠加显示
source: https://vjmap.com/guide/baidumap.html
---

# 百度地图与CAD图叠加显示


目前国内主要有以下三种坐标系：

WGS84：为一种大地坐标系，也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。如高德地图、腾讯地图.

GCJ02：又称火星坐标系，是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。如OpenStreetMap、天地图。

BD09：为百度坐标系，在GCJ02坐标系基础上再次加密。其中bd09ll表示百度经纬度坐标，bd09mc表示百度墨卡托米制坐标。

主流瓦片地图的地理坐标系可分以下几类：	

- Web墨卡托投影, 主要有谷歌地图、高德地图、腾讯地图、搜狗地图、必应地图、OpenStreetMap、ArcGIS online、MapQuest、超图、360地图

- 经纬度直投, 主要有谷歌地球、天地图（经纬直投）

- 百度墨卡托, 如百度地图

  如上所述，百度地图独立采用了一个自己的坐标系，称为百度坐标系，与众不同。那么怎么样在百度地图上面加载CAD图呢？

# 实现

## （1）百度地图叠加第三方标准图层

百度地图 JSAPI GL提供XYZLayer类支持加载EPSG3857 坐标系统的 WMS 图层、WMTS图层、TMS图层以及自定义栅格图层。 https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/trilateralLayer

其中WMS图层的示例示例代码如下

```js
// 创建位置点
    var map = new BMapGL.Map("allmap");
    var point = new BMapGL.Point(-99.41413316281799,39.82354027110903);
    map.centerAndZoom(point, 4);
    // tileUrlTemplate 包含OGC标准的WMS地图服务的GetMap接口的参数
    var wms = BMapGL.XYZLayer({
           tileUrlTemplate: 'https://ahocevar.com/geoserver/wms?REQUEST=GetMap&SERVICE=WMS&layers=topp:states&version=1.3.0&CRS=EPSG:3857&WIDTH=256&HEIGHT=256&FORMAT=image/png&TRANSPARENT=true&BBOX=[b] ',
    });
    map.addTileLayer(wms);
```

经过示例和文档发现，只要有服务支持EPSG3857的WMS服务就能通过百度地图的API把此图层做为一个第三方标准图层加载过来。

## （2）CAD的WMS图层实现

这个在之前的博文中介绍过。

`唯杰地图VJMAP`为`CAD`图或`自定义地图格式`WebGIS`可视化`显示开发提供的一站式解决方案，支持的格式如常用的`AutoCAD`的`DWG`格式文件、`GeoJSON`等常用`GIS`文件格式，它使用WebGL`矢量图块`和`自定义样式`呈现交互式地图, 提供了全新的`大数据可视化`、`实时流数据`可视化功能。

唯杰地图[https://vjmap.com/](https://vjmap.com/)无需转换可直接打开CAD的DWG格式的图形，并提供了WMS服务接口。

其接口文档为:

```typescript

/**
 * wms服务url地址接口
 */
export  interface IWmsTileUrl {
    /** 地图ID(为空时采用当前打开的mapid)， 为数组时表时同时请求多个. */
    mapid?: string | string[];
    /** 地图版本(为空时采用当前打开的地图版本). */
    version?: string | string[];
    /** 图层名称（为空时采用当前打开的地图图层名称). */
    layers?: string | string[];
    /** 范围，缺省{bbox-epsg-3857}. (如果要获取地图cad一个范围的wms数据无需任何坐标转换，将此范围填cad范围,srs,crs,mapbounds填为空).*/
    bbox?: string;
    /** 当前坐标系,缺省(EPSG:3857). */
    srs?: string;
    /** cad图的坐标系，为空的时候由元数据坐标系决定. */
    crs?: string | string[];
    /** 地理真实范围，如有值时,srs将不起作用 */
    mapbounds?: string;
    /** 宽. */
    width?: number;
    /** 高. */
    height?: number;
    /** 是否透明. */
    transparent?: boolean;
    /** 四参数(x偏移,y偏移,缩放，旋转弧度)，可选，对坐标最后进行修正*/
    fourParameter?: string | string[];
    /** 是否是矢量瓦片. */
    mvt?: boolean;
    /** 是否考虑旋转，在不同坐标系中转换是需要考虑。默认自动考虑是否需要旋转. */
    useImageRotate?: boolean;
    /** 旋转时图像处理算法. 1或2,默认自动选择（旋转时有用）*/
    imageProcessAlg?: number;
    /** 当前互联网底图地图类型 WGS84(84坐标，如天地图，osm), GCJ02(火星坐标，如高德，腾讯地图)， BD09LL(百度经纬度坐标，如百度地图)， BD09MC(百度墨卡托米制坐标，如百度地图)*/
    webMapType?: "WGS84" | "GCJ02" | "BD09LL" | "BD09MC";
}

```

## （3） 实现

我们只要确定CAD图是哪个坐标系即可。因为百度wms的坐标系是EPSG3857,所以上面WMS图层的webMapType参数采用默认的WGS84坐标就可以了。

```js

let cadEpsg = "EPSG:4544";// cad图的espg代号
// 增加cad的wms图层
let wmsUrl = svc.wmsTileUrl({
    mapid: mapId, // 地图id
    layers: layer, // 图层名称
    bbox: '', // bbox这里不需要
    srs: "EPSG:3857", 
    crs: cadEpsg
})
// tileUrlTemplate 包含OGC标准的WMS地图服务的GetMap接口的参数
wmsLayer = BMapGL.XYZLayer({
    tileUrlTemplate: wmsUrl + '&BBOX=[b] ',
    useThumbData: false
});
map.addTileLayer(wmsLayer);
```

效果如下图：

![image-20220924213028012](https://vjmap.com/blogimages/image-20220924213028012.png)

从叠加效果来看，和百度地图能按实际坐标叠加到一起。

# 其他

## (1) 没有坐标系的CAD图怎么叠加

上面叠加的图是有坐标系的。然而实际中有些图是没有坐标系的。如一个小区或商铺的平面图，那这种没有坐标系的CAD图怎么叠加到百度地图上呢？就这需要人为的指定公共点。步骤为在CAD图找二个及以上的点，同时在百度地图上相对应的位置也找同样的位置点，通过这些公共点计算出坐标转换的关系去进行叠加。而在唯杰地图的WMS图层中是支持四参数计算的。

根据公共点提供的WMS图层的示例代码为:

```js

// cad上面的点坐标
let cadPoints = [
    vjmap.geoPoint([587464448.8435846, 3104003685.208661,]),
    vjmap.geoPoint([587761927.7224838, 3104005967.655292]),
    vjmap.geoPoint([587463688.0280377, 3103796743.3798513]),
    vjmap.geoPoint([587760406.0913897, 3103793700.1176634])
];


// 在互联网图上面拾取的与上面的点一一对应的坐标(百度坐标)
let webPoints = [
    vjmap.geoPoint([116.49738632967344,39.969244215079016]),
    vjmap.geoPoint([116.50000171663382,39.96753915494187]),
    vjmap.geoPoint([116.49843968869915,39.96613594214925]),
    vjmap.geoPoint([116.49581440721418,39.967790723887404])
]

// 通过坐标参数求出四参数
let epsg3857Points = webPoints.map(w => vjmap.geoPoint(vjmap.transform.convert(w, vjmap.transform.CRSTypes.BD09, vjmap.transform.CRSTypes.EPSG3857)));
let param = vjmap.coordTransfromGetFourParamter(epsg3857Points, cadPoints , false); // 这里考虑旋转
let fourparam = [param.dx, param.dy, param.scale, param.rotate]

// wms图层地址
const getCadWmsUrl = (transparent) => {
    let wmsUrl = svc.wmsTileUrl({
        mapid: mapId, // 地图id
        layers: layer, // 图层名称
        bbox: '', // bbox这里不需要
        srs: "EPSG:3857", //
        fourParameter: fourparam,
        transparent: transparent,
        backgroundColor: 'rgba(240, 255, 255)' // 不透明时有效
    })
    return wmsUrl
}

```

通过上面的示例我们发现，其实只要有公共点，使用方法与有坐标系的WMS是差不多的。只是多了一个公共点计算完后成的得到的`四参数` `fourParameter`这个属性。

我们对一个没有坐标系的CAD图，随便在百度地图上叠加了几个公共点，叠加效果如下

![image-20220924213906133](https://vjmap.com/blogimages/image-20220924213906133.png)

## (2) 百度地图叠加的WMS图层如果是透明色，则颜色会发生变化 

在叠加WMS到百度地图的过程中，发现叠加的CAD图和之前的CAD图颜色不太一致，如下图所示

![image-20220924214415039](https://vjmap.com/blogimages/image-20220924214415039.png)

而在之前和高德和cesium中通过WMS叠加，没有发现这个问题。真是百思不得其解。翻阅了百度地图的文档也没有发现原因。可能和百度地图的渲染绘制有关，百度地图在线提供的WMS示例都是没有透明度叠加的。没办法的情况下只能采用下策，把WMS图层做为一个不透明的图层叠加到百度地图中。具体代码为:

```js
let wmsUrl = svc.wmsTileUrl({
    mapid: mapId, // 地图id
    layers: layer, // 图层名称
    bbox: '', // bbox这里不需要
    srs: "EPSG:3857", //
    fourParameter: fourparam,
    transparent: false, // 这里透明度要改成false，表示不透明背景
    backgroundColor: 'rgba(240, 255, 255)' // 不透明时有效，设置不透明背景色
})
```

最终叠加的效果如下图所示

![image-20220924214830000](https://vjmap.com/blogimages/image-20220924214830000.png)

设置成不透明色后，CAD图的颜色确实和原来的颜色一样的了。美中不足的是因为设置了不透明，所以看不到CAD图覆盖的百度地图下面区域的内容了。

 ## (3) GIS数据和WMS图层对应问题

因为上面的原因，如果设置了不透明，无法看到CAD图覆盖的百度地图下面区域的内容，所以想通过另外一个办法，就是把CAD的数据做为GIS中的geojson数据格式，通过百度地图SDK来进行前端绘制。

在百度地图SDK中提供了加载GeoJSON图层的方法。

地理数据多使用GeoJSON形式存储表达，百度地图JS API GL提供两种不同的方式支持开发者加载自己的GeoJSON数据：

1.提供GeoJSONParse类，满足用户将geojson数据解析为符合百度地图坐标的Overlay数据，用户可得到Overlay属性、坐标数据，进行覆盖物实例化或者其他处理。

2.提供GeoJSONLayer类，满足用户将geojson数据直接解析为覆盖物的图层，并进行交互操作

[https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/geoJsonLayer](https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/geoJsonLayer)

而在唯杰地图中也可以通过查询的方式，把CAD的数据转为geojson数据，再把geojson转成百度地图所要求的坐标格式即可。

最后代码如下

```js
// 在唯杰地图中通过查询获取CAD图的geojson数据
async function queryData(svc, cadPrj) {
    let res = await svc.conditionQueryFeature({
        condition: ``, // 只需要写sql语句where后面的条件内容,字段内容请参考文档"服务端条件查询和表达式查询"
        fields: "",
        includegeom: true, // 是否返回几何数据,为了性能问题，realgeom为false时，如果返回条数大于1.只会返回每个实体的外包矩形，如果条数为1的话，会返回此实体的真实geojson；realgeom为true时每条都会返回实体的geojson
        realgeom: true,
        limit: 100000 //设置很大,不传的话，默认只能取100条
    }, pt => {
        // 查询到的每个点进行坐标处理回调
        let cadPoint = cadPrj.fromMercator(pt);// 转成cad的坐标
        return cadToWebCoordinate(cadPoint); // 把cad的坐标转成当前地图的经纬度坐标
    })

    if (res && res.result && res.result.length > 0) {
        let features = [];
        for (let ent of res.result) {
            if (ent.geom && ent.geom.geometries) {
                let clr = vjmap.entColorToHtmlColor(ent.color);
                for (let g = 0; g < ent.geom.geometries.length; g++) {
                    features.push({
                        id: ent.id,
                        type: "Feature",
                        properties: {
                            objectid: ent.objectid + "_" + g,
                            color: clr
                        },
                        geometry: ent.geom.geometries[g]
                    })
                }
            }
        }

        let geom = {
            type: "FeatureCollection",
            features: features
        };

        return geom;
    }
}
// 通过百度地图的sdk加载Geojson图层
function addGeoJsonData(map, data) {
    var region = data;

    // https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/geoJsonLayer
    var cadLayer = new BMapGL.GeoJSONLayer('cad-child', {
        reference: 'WGS84',
        dataSource: region,
        level: -10,
        polygonStyle: function (properties) {
            var index = properties.join || 0;
            return {
                fillColor: properties.color
            }
        },
        polylineStyle: function (properties) {
            return {
                strokeColor: properties.color
            }
        },
        markerStyle: function (properties) {
            return {
            }
        }
    });
    
    map.addGeoJSONLayer(cadLayer, {
        maxZoom: 24
    });
    return cadLayer;
}

```

最终效果如下

![image-20220924215904227](https://vjmap.com/blogimages/image-20220924215904227.png)

通过GeoJSON的方式，不光能实现透明显示，还能在前端进行交互，如悬浮高亮，点击查询等。缺点就是geojson数据量大，加载速度慢，同时前端渲染也费性能。

最后把WMS图层和GeoJson同时显示，看下什么效果呢？按理说应该是完全叠加在一起才对。

![image-20220924220238525](https://vjmap.com/blogimages/image-20220924220238525.png)

![image-20220924220402978](https://vjmap.com/blogimages/image-20220924220402978.png)

通过WMS图层和GeoJson同时显示，我们发现这两个图层之间存在偏移，当地图移动后级别放大后，又差不多能对应到一起。而在高德（GCJ02火星坐标系）和天地图(WGS84坐标系)的叠加中，WMS图层和GeoJson是能完全叠加对应上的。所以具体原因也百思不得其解，难道是百度地图对WMS图层做了什么特殊处理吗？

# 结论

通过上面的测试，我们实现了在百度地图中通过WMS的方式加载CAD图，对于无坐标系的CAD图，也可以通过四参数进行叠加。同时也可以通过GeoJSON图层的方式来加载CAD的GIS数据展示。在线体验地址为

[百度地图SDK中加载CAD图](https://vjmap.com/demo/#/demo/map/web/09baiduCadLayer) https://vjmap.com/demo/#/demo/map/web/09baiduCadLayer

[百度地图SDK公共点加载CAD图](https://vjmap.com/demo/#/demo/map/web/09baiduCadLayerFourparam) https://vjmap.com/demo/#/demo/map/web/09baiduCadLayerFourparam

遇到的坑至今没找到原因的有：

（1）如果把CAD图层通过WMS做为透明图层叠加的时候，颜色会发生变化，原因未知。

（2）同样的坐标转换，通过WMS叠加CAD图和通过Geojson展示CAD图存在偏移，当地图移动后级别放大后，又差不多能对应到一起。原因未知。


