一、项目概述
MxCAD 与 Mapbox 结合项目是一个创新性的解决方案,旨在将在线 CAD 编辑功能与地图服务无缝集成。该项目通过自定义的 Mapbox 版本支持中国国家大地坐标系(CGCS2000),并结合 MxCAD 强大的在线 CAD 编辑能力,实现了在地图上直接加载、编辑和管理 CAD 图纸的功能。
核心技术栈包括:
二、Mapbox 修改版支持 CGCS2000 坐标系
2.1、CGCS2000 坐标系介绍
CGCS2000(China Geodetic Coordinate System 2000)是中国国家大地坐标系,是中国测绘基准的重要组成部分,用于替代原有的北京 54 坐标系和西安 80 坐标系。在国内 GIS 应用中,支持 CGCS2000 是必不可少的功能。
2.2、基于 @cgcs2000/mapbox-gl 的坐标系扩展
项目使用了自定义的@cgcs2000/mapbox-gl
包,这是对标准 Mapbox GL JS 的扩展,主要增加了对 CGCS2000 坐标系的支持。在代码中的引用方式:
import {
type AnyLayer,
Map as _Map,
type AnySourceData,
LngLat,
Point,
} from "@cgcs2000/mapbox-gl";
import mapboxgl from "@cgcs2000/mapbox-gl";
复制代码
我们对修改后的 js 进行了处理,使其支持 CGCS2000 坐标系和 mxcad 的交互。
2.3、坐标转换与投影实现
在使用时我们依然要扩展了 Map 类,扩展的方法都是必须的,用于配合 mxcad 实现坐标的转换和交互:
// 扩展重写Map类
export class Map extends _Map {
public dom_mousePos(event: any) {
return this.dom_mousePos_imp(this.getCanvasContainer(), event);
}
public lnglat_to_mercator(lng: any, lat: any): any {
let pt = mapboxgl.MercatorCoordinate.fromLngLat([lng, lat], 0);
return pt;
}
public mercator_to_lnglat(x: number, y: number, z: number): any {
let mecatorcoord = new mapboxgl.MercatorCoordinate(x, y, z);
return mecatorcoord.toLngLat();
}
public mercatorCoordinate_from_LngLat(
lngLat: number[],
modelAltitude: number
): any {
return mapboxgl.MercatorCoordinate.fromLngLat(lngLat as any, modelAltitude);
}
protected getScaledPoint(
el: HTMLElement,
rect: ClientRect,
e: MouseEvent | WheelEvent | Touch
) {
const scaling =
el.offsetWidth === rect.width ? 1 : el.offsetWidth / rect.width;
return new Point(
(e.clientX - rect.left) * scaling,
(e.clientY - rect.top) * scaling
);
}
protected dom_mousePos_imp(el: HTMLElement, e: MouseEvent | WheelEvent) {
const rect = el.getBoundingClientRect();
return this.getScaledPoint(el, rect, e);
}
}
复制代码
三、MxCAD 与 Mapbox 的结合实践
3.1、MxCAD 在线 CAD 编辑引擎与 Mapbox 集成
MxCAD 是一个功能强大的在线 CAD 编辑引擎,通过 WebAssembly 技术实现了高性能的 CAD 渲染和编辑功能。在项目中,我们将 MxCAD 与 Mapbox 无缝集成,实现了在地图上直接操作 CAD 图纸的能力,关键集成代码:
import { MxMap } from "mxcad";
let mx_map = new MxMap();
// 设置坐标点对齐,将CAD坐标系与地图坐标系对齐
// 图纸中的中心在地址上的位置,单位经纬度
let mapOrigin = [116.42787, 39.93232];
// 小=右,大=下
// CAD图纸中的中心中,CAD图纸单位
let cadOrigin = [506411.1543, 307348.2786];
// 1 CAD单位与米的比例 这里 1 cad单位是1m
let meterInCADUnits = 1;
mx_map.setCoordinatePointAlignment(mapOrigin, cadOrigin, meterInCADUnits);
const style = {
version: 8,
sources: {
tianditu: {
type: "raster",
tiles: [
"http://t0.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=天地图的密钥",
],
tileSize: 256,
maxzoom: 18,
},
},
layers: [
{
id: "tianditu-layer",
type: "raster",
source: "tianditu",
minzoom: 0,
maxzoom: 18,
}
],
};
let map = new Map({
// Mapbox GL JS 进行地图渲染的 HTML 元素,或该元素的字符串 id 。该指定元素不能有子元素。
container: "map",
// crs: 'EGSP:4490',
// 地图最小缩放级别(0-24)。
minZoom: 0,
// 地图最大缩放级别(0-24)。
maxZoom: 24,
// 地图初始化时的地理中心点
center: mapOrigin,
// 地图初始化时的层级
zoom: 16,
// 地图的 Mapbox 配置样式
style: style,
});
// 你需要打开的图纸
let cadFile = new URL("../../public/demo/line3.dwg.mxweb", import.meta.url).href;
// 在地图加载完成后初始化MxCAD
map.on("style.load", async function () {
// 设置canvas ID
map.getCanvas().id = "myCanvas";
// 创建MxCAD实例
mx_map.create(map, {
locateFile: (fileName: string) => {
return new URL(
`../../node_modules/mxcad/dist/wasm/${mode}/${fileName}`,
import.meta.url
).href;
},
fileUrl: cadFile,
middlePan: true,
viewBackgroundColor: load_local_title
? { red: 0, green: 0, blue: 0 }
: { red: 255, green: 255, blue: 255 },
});
});
复制代码
3.2、坐标系统对齐实现
坐标系统对齐是 MxCAD 与 Mapbox 结合的核心。我们通过setCoordinatePointAlignment
方法将 CAD 坐标系与地图坐标系进行对齐:
// 图纸中的中心在地址上的位置,单位经纬度
let mapOrigin = [116.42787, 39.93232];
// CAD图纸中的中心中,CAD图纸单位
let cadOrigin = [506411.1543, 307348.2786];
// CAD单位与米的比例
let meterInCADUnits = 1;
// 设置坐标点对齐
mx_map.setCoordinatePointAlignment(mapOrigin, cadOrigin, meterInCADUnits);
复制代码
这样设置后,当用户在地图上点击时,可以获取对应的 CAD 坐标:
map.on("click", async function (e) {
let { lng, lat } = e.lngLat;
// 获取墨卡托坐标
let pt = mapboxgl.MercatorCoordinate.fromLngLat([lng, lat], 0);
// 转换为CAD坐标
let ptCAD = mx_map.mercatorCoord2CAD(pt.x, pt.y);
console.log("CAD坐标:", JSON.stringify(ptCAD));
});
复制代码
四、天地图 CGCS2000 加载实现
4.1、天地图服务介绍
天地图是中国国家测绘地理信息局主办的国家地理信息公共服务平台,提供了基于 CGCS2000 坐标系的地图服务。在本项目中,我们集成了天地图作为底图服务。
4.2、天地图 key 申请流程
访问天地图开发者平台:http://lbs.tianditu.gov.cn/
注册并登录开发者账号
选择地图 API
申请 key
在"控制台"页面选择"创建应用"
填写应用名称、应用类型等信息
提交后获取应用 key
使用获取的 key 替换代码中的 tk 参数
4.3、天地图 CGCS2000 图层配置
在项目中,我们通过以下方式配置天地图图层:
const style = {
version: 8,
sources: {
tianditu: {
type: "raster",
tiles: [
"http://t0.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=",
],
tileSize: 256,
maxzoom: 18,
},
},
layers: [
{
id: "tianditu-layer",
type: "raster",
source: "tianditu",
minzoom: 0,
maxzoom: 18,
}
]
} as mapboxgl.Style;
复制代码
注意:在实际使用时,需要将上述代码中的tk=
后面添加您申请的天地图 key。
天地图提供了多种图层类型,常用的包括:
img_c
: 影像底图
vec_c
: 矢量底图
cva_c
: 矢量注记
cia_c
: 影像注记
可以根据需求选择不同的图层类型。
MxCAD 与 Mapbox 的结合为 CAD 图纸的在线编辑与地理位置关联提供了强大的解决方案,通过支持 CGCS2000 坐标系和集成天地图服务,该项目特别适合中国国内的 GIS 应用开发。项目的核心功能包括坐标系转换、CAD 图纸在地图上的精确定位与编辑、图层管理等,为城市规划、管网管理、不动产管理等领域提供了有力的技术支持。
4.4、集成 mxcad 在线 CAD 项目地图模式
刚刚我们介绍了从 0 到 1 的 MxCAD 与 Mapbox 结合实现,但是所有 CAD 的功能都要从头开发, 所以我们提供了在线 CAD 项目集成方案, 同时可以启动地图模式, 简单开发一个扩展插件轻松集成 MxCAD 与 Mapbox 结合实现在线地图 CAD 编辑系统。开发前我们一定要下载MxDraw云图开发包然后解压可以看到一个 exe 程序点击运行点击“打开 MxCAD 代码开发目录” 就可以看到 dist 目录了,查看详情。
扩展插件开发
通过开发一个简单的插件,我们可以快速集成 MxCAD 与 Mapbox。以下是一个基本的插件代码示例:
import { MxCADPluginBase, MxCADUI, MxMap } from "mxcad";
import { MxFun } from "mxdraw";
import * as mapboxgl from "mapbox-gl";
import { Map } from "mapbox-gl";
class MxCADPlugin extends MxCADPluginBase {
constructor() {
super()
this.map_default_data = {
/** 地图与CAD图纸的对齐位置 */
mapOrigin: [116.42787, 39.93232],
/** CAD图纸与地图的对齐点 */
cadOrigin: [506411.1543, 307348.2786],
meterInCADUnits: 1,
/** mapbox地图token */
mapbox_accessToken: '',
/** 需要打开的cad图纸 */
openFile: new URL("../demo/line3.dwg.mxweb", import.meta.url).href,
/** 栅格瓦片图层列表 */
rasterTileLayerList: []
}
}
}
let mxcadui;
// cad应用加载开始
MxFun.on("mxcadApplicationStart", (mxcaduiimp) => {
mxcadui = mxcaduiimp;
mxcadui.init(new MxCADPlugin());
});
let mx_map;
let map;
// 初始化gis
MxFun.on("mxcadApplicationInitMap", () => {
mx_map = mxcadui.mxmap;
map = mx_map.getMapbox()
map.getCanvas().id = "mxcad"
// 可以在这里设置地图样式
// map.setStyle({
// version: 8,
// sources: {
// tianditu: {
// type: 'raster',
// tiles: [
// 'http://t0.tianditu.gov.cn/img_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=c&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=密钥'
// ],
// tileSize: 256,
// maxzoom: 18
// }
// },
// layers: [
// {
// id: 'tianditu-layer',
// type: 'raster',
// source: 'tianditu',
// minzoom: 0,
// maxzoom: 18
// }
// ]
// })
map.on("click", async function (e) {
let { lng, lat } = e.lngLat;
let pt = mapboxgl.MercatorCoordinate.fromLngLat(
[lng, lat],
0
);
console.log("经纬度坐标:", JSON.stringify([lng, lat]));
let ptCAD = mx_map.mercatorCoord2CAD(pt.x, pt.y);
console.log("CAD坐标:", JSON.stringify(ptCAD))
});
});
复制代码
插件部署与配置
插件文件结构 将上述 JavaScript 代码保存为一个 index.js 文件,放置在dist/plugins/mapPlugin/
目录下(目录名可自定义)。
配置 config.json 在dist/plugins/config.json
文件中添加插件配置:
{
"plugins": \[
"loginPlugin",
{"name": "pluginCodeEdit", "isAfterLoad": true, "dir": true, "version": "1.0.0"},
{"name": "pluginIdentifyPattern", "isAfterLoad": true, "dir": true, "version": "1.0.0"},
{"name": "pluginBaseTemplate", "isAfterLoad": false, "dir": true, "version": "1.0.0"},
{"name": "mapPlugin", "isAfterLoad": false, "dir": true, "version": "1.0.0"}
]
}
复制代码
注意: 插件名称应与目录名一致 - isAfterLoad
表示是否在主应用加载完成后再加载插件 - dir
设置为 true 表示插件在独立目录中
启动地图模式访问应用时,在 URL 后添加?map=true
参数即可启动地图模式,例如:
http://your-domain.com/mxcad/?map=true
复制代码
集成到现有项目
您可以通过以下方式将 MxCAD 地图模式集成到现有项目中:
使用 iframe 嵌入
<iframe src="http://your-domain.com/mxcad/?map=true" width="100%" height="600px"></iframe>
复制代码
页面通信
通过 postMessage 实现父页面与 iframe 中的 MxCAD 应用通信:
// 父页面发送消息
const mxcadFrame = document.getElementById('mxcad-frame');
mxcadFrame.contentWindow\.postMessage({
type: 'COMMAND',
command: 'ZOOM\_TO',
data: { center: \[116.42787, 39.93232], zoom: 16 }
}, '\*');
// 在MxCAD插件中接收消息
window\.addEventListener('message', (event) => {
if (event.data.type === 'COMMAND') {
// 处理来自父页面的命令
handleCommand(event.data);
}
});
function handleCommand(data) {
if (data.command === 'ZOOM\_TO' && map) {
map.flyTo({
center: data.data.center,
zoom: data.data.zoom,
essential: true
});
}
}
复制代码
通过这种方式,您可以在自己的项目中轻松集成 MxCAD 与 Mapbox 结合的在线地图 CAD 编辑系统,同时保留对地图和 CAD 操作的完全控制能力,同时集成了 mxcad 在线 CAD 项目的各种功能。
4.5 坐标系统选择注意事项
在集成 MxCAD 与 Mapbox 时,坐标系统的选择非常重要:
CGCS2000 与 WGS84 的区别
- 本项目中采用的是 CGCS2000 坐标系
- 默认的 Mapbox 使用的是 WGS84 坐标系
- 两种坐标系在中国区域的偏差约为几米到几十米不等
2.坐标系选择建议
- 如果您的项目需要精确对应中国国内地理位置,建议使用修改版的 Mapbox CGCS2000
- 使用 CGCS2000 时,所有经纬度输入和输出都是 CGCS2000 坐标系下的值
- 如果对精度要求不高或主要用于国际项目,可以使用默认的 Mapbox(WGS84)+ 补丁方式
- 使用默认 WGS84 时,无需替换为修改版的 Mapbox 库
坐标转换
如果需要在两种坐标系统之间进行转换,可以使用相关转换工具或库,例如 proj4js:
// 使用proj4js进行坐标转换示例
import proj4 from 'proj4';
// 定义坐标系
proj4.defs('EPSG:4326', '+proj=longlat +datum=WGS84 +no\_defs'); // WGS84
proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no\_defs'); // CGCS2000
// WGS84转CGCS2000
const wgs84Point = \[116.3912, 39.9073]; // 北京某点WGS84坐标
const cgcs2000Point = proj4('EPSG:4326', 'EPSG:4490', wgs84Point);
console.log('CGCS2000坐标:', cgcs2000Point);
复制代码
选择合适的坐标系对于项目的精确定位至关重要,特别是在涉及到工程测量、规划设计等高精度应用场景中。
评论