唯杰地图 logo唯杰地图
VJMAP
EN

concepts

vjmap/references/coord/concepts.md 5.8 KB114 行
原文

本文回答:几何坐标 / 渲染经纬度 / 真实经纬度 / 墨卡托 / UCS / WCS 的区别与边界。

一、三种坐标层次

名称 数值范围 何时出现 备注
CAD 几何坐标 任意(可达 10^8) DWG 中实际点、业务保存值 单位米,笛卡尔直角坐标
渲染经纬度 [-180, 180] × [-85.0511, 85.0511] map.toLngLat 输出、所有 addSource/Marker/Popup 的坐标 WebGL 渲染引擎使用的绘制坐标
真实经纬度 [-180, 180] × [-85.0511, 85.0511] 互联网底图实际地理坐标、LnglatProjection 仅当底图是互联网地图时,渲染经纬度 == 真实经纬度

二、为什么要有渲染经纬度?

CAD 图的坐标常常很大(上亿),直接交给 WebGL 渲染会浮点精度塌陷;而底层渲染器的世界观是经纬度 (-180..180, -85..85)。vjmap 在 GeoProjection 里建立一张"线性仿射"映射:

  • GeoBounds 左下角 ↔ (-180, -85.0511)(Web 墨卡托纬度极限)
  • GeoBounds 右上角 ↔ (180, 85.0511)

这样渲染器只处理一个合理量级的坐标,CAD 几何可以任意大。注意这是线性映射但整体是非线性(经纬度投影自身非线性),所以几何计算请在 CAD 侧做。

示例(sys_cad2000,CGCS2000 图):map.toLngLat(bounds.center) 恰好得 [0,0],整张图只落在几度的小范围内——CAD 底图的"渲染经纬度"就是归一化渲染坐标,看上去像真经纬度实则没有任何地理意义。

三、互联网底图的差别

当底图是互联网地图(OSM、天地图、高德……),prj 建议用:

const prj = new vjmap.LnglatProjection();

它的 toLngLat([lng, lat]) 直接返回 [lng, lat]。此时"渲染经纬度"就是真实经纬度——所有 GIS 数据(Marker、GeoJSON)直接用经纬度填就行。

四、UCS 与 WCS

CAD 里的 UCS(User Coordinate System)是用户自定义局部坐标;WCS(World Coordinate System)是图的全局坐标。

  • vjmap 获取的几何坐标都是 WCS。
  • map.hasUcs() 判断当前图是否存在 UCS 定义。
  • map.wcsToUcs(wcsPt) / map.ucsToWcs(ucsPt) 互转。

当需求是"图纸上标注的坐标"时(比如工程师手算的点号与坐标),通常要转 UCS 再显示。

五、墨卡托坐标

vjmap 内部用球面墨卡托投影(EPSG:3857,范围 ±20037508 米)绘制。⚠️ Map 上没有 toMercator/fromMercator——它们在 Projection 上,且输入是投影源空间坐标(CAD 底图 = CAD 坐标),不是经纬度:

const prj = map.getMapProjection();
prj.toMercator(cadPt);       // CAD -> 拉伸墨卡托米(线性拉伸到 ±20037508,非真实地理墨卡托)
prj.fromMercator(mktXY);     // 反向

// 真实 WGS84 <-> EPSG:3857 用静态方法(与地图投影无关):
vjmap.Projection.lngLat2Mercator([lng, lat]);
vjmap.Projection.mercator2LngLat([mx, my]);

mapext 里 CoordMapper.cadToMercator / mercatorToCad 走同一通路(委托 prj.toMercator/fromMercator)。用于需要做屏幕像素计算 / 单位米长度估算的场景。

长度换算见 projection-api 长度类 API 表——注意 prj.toMeter(1) 的"米"是渲染尺度不是真实地面米。

六、拿到一个坐标不知道它在哪个空间?(判断速查)

特征 可能是
|x|≤180 且 |y|≤85 经纬度(渲染或真实,看底图与上下文)
|x|、|y| 在 ±20037508 附近 Web 墨卡托米
X=6~8位、Y=7位的大数 CAD 投影坐标(EPSG 分带,见 cad-epsg)
其他大数 局部 CAD 坐标(无地理参考,需四参数)

七、四参数(平面相似变换)

无标准坐标系的 CAD 图靠四参数 dx, dy, scale, rotate(rotate 是弧度):

x' = dx + scale·cos(r)·x − scale·sin(r)·y
y' = dy + scale·sin(r)·x + scale·cos(r)·y
  • 解算:vjmap.coordTransfromGetFourParamter(srcPts, destPts, isSetRotateZero, isConsiderPointOrder?)——第 3 参必填(true=只解平移+缩放不旋转);至少 2 对公共点、建议 4~10 对分布图四角。返回值 {dx,dy,scale,rotate},ByFourParamter/ByInvFourParamter 均返回 GeoPoint(用 .x/.y 取值)。
  • 正算 coordTransfromByFourParamter(pt, param);反算 coordTransfromByInvFourParamter。
  • 服务端接口里 fourParameter(wmsTileUrl)与 fourParameterBefore/After(webMapUrl)都是 "dx,dy,scale,rotate" 字符串。

八、四条关键总则(高度概括)

  1. 渲染用经纬度:addSource / Marker / Popup / Symbol / 一切 GeoJSON 图层吃渲染经纬度。例外:CircleFill/CircleEdge/Ellipse*/MarkerCluster/DivOverlay/SvgOverlay 内部帮你 toLngLat,要直接传 CAD 坐标——详见 overlay-coords。
  2. 几何用 CAD:几何计算(相交、插值、偏移、旋转)在 CAD 坐标做。
  3. 保存至后台用 CAD:下次加载 map.toLngLat 再画。
  4. CAD 底图时渲染经纬度没有地理含义:千万不要把它传给 GCJ02/百度 API。

九、代码对照

CAD 底图

const prj = new vjmap.GeoProjection(res.bounds);
const map = new vjmap.Map({ center: prj.toLngLat(prj.getMapExtent().center()), ... });
map.attach(svc, prj);

// 保存到后台:
const cadJson = map.fromLngLat(draw.getAll());
await fetch("/api/save", { body: JSON.stringify(cadJson) });

// 加载:
const lngLatJson = map.toLngLat(cadJson);
draw.set(lngLatJson);

互联网底图

const prj = new vjmap.LnglatProjection();
const map = new vjmap.Map({ center: prj.toLngLat([116.391, 39.907]), ... });
new vjmap.Marker().setLngLat([116.391, 39.907]).addTo(map); // 直接写真实经纬度