唯杰地图 logo唯杰地图
VJMAP
EN

internet-basemap-align

vjmap/references/coord/internet-basemap-align.md 7.8 KB161 行
原文

本文回答:CAD 图叠到天地图 / 高德 / 百度 / OSM 时坐标偏移的原因、自动叠加、四参数叠加。

一、叠加的两种场景

  1. CAD 为底图:互联网瓦片作为 WMS 图层被 vjmap 后端转换后适配到 CAD 坐标。
  2. 互联网为底图:CAD 通过 vjmap 的 WMS 服务(svc.wmsTileUrl)适配到互联网瓦片。

无论哪种,都要解决"CAD 坐标系" ↔ "互联网地图坐标系"的转换。

二、两类 CAD 图

类型 标志 处理
有 EPSG(国家 2000 / 西安 80 / 北京 54 等) 坐标是 6 位或 8 位 自动叠加:通过 svc.webMapUrl({srs: "EPSG:xxx"}) / svc.wmsTileUrl({srs, crs})
没有坐标系(商铺平面图等局部图) 坐标通常是 [0..1000] 这种小值 四参数叠加:人为指定 2+ 对公共点

三、自动叠加(有 EPSG 的 CAD 图)

// 以 CAD 为底图,叠加高德
const tileUrl = svc.webMapUrl({
  tileCrs: "gcj02",                // 高德用火星坐标
  tileUrl: [
    "https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
  ],
  tileSize: 256,
  tileRetina: 1,
  tileMaxZoom: 18,
  tileShards: "1,2,3,4",
  tileFlipY: false,
  mapbounds: res.bounds,
  srs: "EPSG:4527",                // 2000 坐标系 3 度带 39 带
  // 若 X 只有 6 位没带号,要加带号补齐(39 带:前缀 39000000)
  fourParameterBefore: "39000000,0,1,0"
});
map.addSource("basemap-src", { type: "raster", tiles: [tileUrl], tileSize: 256 });
map.addLayer({ id: "basemap", type: "raster", source: "basemap-src" });
map.moveLayer("basemap", map.getStyle().layers[0].id);    // 放到最底
  • 天地图:tileCrs: "wgs84"。
  • 其他 XYZ:tileCrs: "wgs84" / "gcj02" 按实际情况。
  • ⚠️ tileCrs 在 d.ts 里只声明 "gcj02" | "wgs84"(注释"bd09 暂不支持"),但服务端瓦片代理已有 tileCrs:"bd09" 分支(官方示例未使用);TS 工程需断言类型,生产使用前请自行验证。稳妥叠百度的方式仍是 §七"互联网为底图 + wmsTileUrl"方向,配 webMapType: "BD09LL"。

webMapUrl 完整参数(Service.d.ts 签名核实):tileCrs?、tileUrl: string|string[](必填)、tileSize?、tileRetina?、tileMaxZoom?、tileShards?、tileToken?: string|string[]、tileFlipY?、mapbounds?(GeoBounds 也可,模板序列化时走 toString() → "x1,y1,x2,y2")、fourParameterBefore?、fourParameterAfter?、srs?。

四、四参数叠加(无坐标系的 CAD 图)

// 1) CAD 上拾取若干点
const 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])
];

// 2) 在百度地图上拾取对应点(百度坐标)
const 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])
];

// 3) 百度 -> EPSG:3857
const epsg3857Points = webPoints.map(w =>
  vjmap.geoPoint(
    vjmap.transform.convert(w, vjmap.transform.CRSTypes.BD09, vjmap.transform.CRSTypes.EPSG3857)
  )
);

// 4) 计算四参数
const param = vjmap.coordTransfromGetFourParamter(epsg3857Points, cadPoints, false);
const fourparam = [param.dx, param.dy, param.scale, param.rotate];

// 5) 构造 WMS URL(bbox 不传时默认自动带 {bbox-epsg-3857} 模板占位,无需手写)
const wmsUrl = svc.wmsTileUrl({
  mapid: "yourMapId",
  layers: "",
  srs: "EPSG:3857",
  fourParameter: fourparam,
  transparent: true
});

四之二、⚠️ srs/crs/tileCrs 在三个 API 里语义各不相同

API srs crs tileCrs
svc.wmsTileUrl(CAD 叠到互联网底图) 底图坐标系 EPSG:3857 CAD 图的 EPSG —
svc.webMapUrl(互联网瓦片衬到 CAD 底图下) CAD 图的 EPSG — 瓦片商坐标系(gcj02/wgs84;bd09 仅服务端实现、d.ts 未声明)
svc.cmdTransform(点坐标换算) 源坐标系 目标坐标系 —

同一个 EPSG(如 EPSG:4509)在 wmsTileUrl 里写给 crs、在 webMapUrl 里写给 srs、在 cmdTransform 里作源/目标——参数名相同语义不同,极易搞反。

wmsTileUrl 底图是高德/腾讯时加 webMapType: "GCJ02"——服务端出图顺带做 WGS84→GCJ02 加偏;天地图/OSM 不加。

四之三、后台查询结果叠到互联网底图

在互联网底图上查某张 CAD 图:result[i].geom 转出的是该 CAD 图的渲染经纬度(对这张互联网底图没有意义)。正确链路:

// 1) 查询要 CAD 坐标(toMapCoordinate:true 时 .geom 不生成,读 .geojson)
//    查非当前图:geom/layer 须显式给,否则沿用当前图的打开方式与样式名(静默 {} 或 not support query type!)
const res = await svc.conditionQueryFeature({ mapid, condition:"...",
  geom:true, layer: await svc.getStyleLayerName(mapid),
  toMapCoordinate:true, includegeom:true, realgeom:true });
const cadGj = JSON.parse(res.result[0].geojson);              // CAD 坐标

// 2) CAD → WGS84(cmdTransform 逐点;GeoJSON 要拆点转完再拼回,它只收 GeoPoint)
//    无 EPSG 的局部图:cmdTransform("EPSG:4326","EPSG:4326", pt, "dx,dy,s,r") 走四参数

// 3) WGS84 → 底图系:高德底图 convert(WGS84→GCJ02),天地图直接用
map.addSource('hl', { type:'geojson', data: gj });

五、常见偏移原因清单

现象 原因 修复
整体平移几百米 用 WGS84 给了高德/百度 转 GCJ02/BD09,或调整 tileCrs
百度图叠加小区平面图对不上 局部图无 EPSG,没做四参数 走 [四参数叠加]
2000 坐标 CAD 叠到 OSM 整体偏 前缀带号没加或 EPSG 错 确认 3 度带/6 度带,fourParameterBefore: "39000000,0,1,0"
叠加某些区域准确、另一区域偏 投影非线性误差 增加公共点数量(≥ 3 或 4);或用 proj4 做更准确的非线性变换
高层级(zoom > 18)才偏 tile 精度或 retina 配置错 设置 tileMaxZoom / tileRetina 正确
查询结果在互联网底图上"完全看不到" .geom 是 CAD 图的渲染经纬度不是底图经纬度 见 §四之三:toMapCoordinate:true + cmdTransform 链路

六、WMS 叠加原理

svc.wmsTileUrl 会让 vjmap 服务端根据 srs/crs/fourParameter 算出 bbox → 从 CAD 空间生成 tile。前端只要按标准 raster source 方式配置。

参考示例:百度地图与 CAD 叠加、高德叠加。

七、以"互联网底图 + CAD 叠加"为基准

const svc = new vjmap.Service(url, token);
const prj = new vjmap.LnglatProjection();
const map = new vjmap.Map({
  style: { /* 天地图/高德 tile */ },
  center: [116.391, 39.907],
  zoom: 11
});
map.attach(svc, prj);
await map.onLoad();

// 加 CAD WMS 图层
const wmsUrl = svc.wmsTileUrl({
  mapid: "yourCadMapId",
  layers: "",
  srs: "EPSG:3857",
  transparent: true
  // ⚠️ backgroundColor 只在 transparent:false 时才生效(SDK 源码:不透明才拼该参数),
  //    透明叠加时传了也会被忽略
});
map.addSource("cad-src", { type: "raster", tiles: [wmsUrl], tileSize: 256 });
// ⚠️ wmsTileUrl 输出默认已含 &bbox={bbox-epsg-3857},不要再手工拼 &BBOX=(会重复参数)
map.addLayer({ id: "cad-layer", type: "raster", source: "cad-src" });