本帖最后由 MxDraw 于 2025-8-15 10:04 编辑
一、项目概述MxCAD 与Mapbox 结合项目是一个创新性的解决方案,在线CAD编辑功能与地图服务无缝集成。该项目通过自定义的 Mapbox 版本支持中国国家大地坐标系(CGCS2000),并结合MxCAD 强大的在线CAD编辑能力,实现了在地图上直接加载、编辑和管理CAD图纸的功能。
核心技术栈包括: - 修改版 Mapbox GL JS(支持 CGCS2000) - MxCAD 在线 CAD 编辑引擎 - WebAssembly 技术 - TypeScript/JavaScript
二、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 坐标系的支持。在代码中的引用方式: - <font size="3">import {
- type AnyLayer,
- Map as _Map,
- type AnySourceData,
- LngLat,
- Point,
- } from "@cgcs2000/mapbox-gl";
- import mapboxgl from "@cgcs2000/mapbox-gl";</font>
复制代码我们对修改后的 js 进行了处理,使其支持 CGCS2000 坐标系和 mxcad 的交互。
2.3、坐标转换与投影实现在使用时我们依然要扩展了 Map 类,扩展的方法都是必须的,用于配合 mxcad 实现坐标的转换和交互: - <font size="3">// 扩展重写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);
- }
- }</font>
复制代码
三、MxCAD 与 Mapbox 的结合实践
3.1、MxCAD在线CAD编辑引擎与Mapbox集成MxCAD是一个功能强大的在线CAD 编辑引擎,通过WebAssembly 技术实现了高性能的CAD 渲染和编辑功能。在项目中,我们将 MxCAD 与 Mapbox 无缝集成,实现了在地图上直接操作 CAD 图纸的能力,关键集成代码: - <font size="3">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 },
- });
- });</font>
复制代码
3.2、坐标系统对齐实现坐标系统对齐是 MxCAD 与 Mapbox 结合的核心。我们通过`setCoordinatePointAlignment`方法将 CAD 坐标系与地图坐标系进行对齐: - <font size="3">// 图纸中的中心在地址上的位置,单位经纬度
- let mapOrigin = [116.42787, 39.93232];
- // CAD图纸中的中心中,CAD图纸单位
- let cadOrigin = [506411.1543, 307348.2786];
- // CAD单位与米的比例
- let meterInCADUnits = 1;
- // 设置坐标点对齐
- mx_map.setCoordinatePointAlignment(mapOrigin, cadOrigin, meterInCADUnits);</font>
复制代码这样设置后,当用户在地图上点击时,可以获取对应的 CAD 坐标: - <font size="3">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));
- });</font>
复制代码
四、天地图 CGCS2000 加载实现
4.1 天地图服务介绍天地图是中国国家测绘地理信息局主办的国家地理信息公共服务平台,提供了基于 CGCS2000 坐标系的地图服务。在本项目中,我们集成了天地图作为底图服务。
4.2 天地图key 申请流程2. 注册并登录开发者账号 3. 选择地图API 4. 申请key 5. 在"控制台"页面选择"创建应用" 6. 填写应用名称、应用类型等信息 7. 提交后获取应用 key 8. 使用获取的 key 替换代码中的 tk 参数
4.3 天地图 CGCS2000 图层配置在项目中,我们通过以下方式配置天地图图层: - <font size="3">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;</font>
复制代码注意:在实际使用时,需要将上述代码中的`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 编辑系统。
扩展插件开发 通过开发一个简单的插件,我们可以快速集成MxCAD与Mapbox。以下是一个基本的插件代码示例: - <font size="3">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))
- });
- });</font>
复制代码
插件部署与配置 1. 插件文件结构 将上述JavaScript代码保存为一个index.js文件,放置在`dist/plugins/mapPlugin/`目录下(目录名可自定义)。
2. 配置config.json 在`dist/plugins/config.json`文件中添加插件配置: - <font size="3"> {
- "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"}
- ]
- }</font>
复制代码 注意: - 插件名称应与目录名一致 - `isAfterLoad`表示是否在主应用加载完成后再加载插件 - `dir`设置为true表示插件在独立目录中
启动地图模式 访问应用时,在URL后添加`?map=true`参数即可启动地图模式,例如: http://your-domain.com/mxcad/?map=true
集成到现有项目 您可以通过以下方式将MxCAD地图模式集成到现有项目中: 1. 使用iframe嵌入 - <font size="3"> <iframe src="http://your-domain.com/mxcad/?map=true" width="100%" height="600px"></iframe>
- </font>
复制代码
2. 页面通信 通过postMessage实现父页面与iframe中的MxCAD应用通信: - <font size="3"> // 父页面发送消息
- 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
- });
- }
- }</font>
复制代码通过这种方式,您可以在自己的项目中轻松集成MxCAD与Mapbox结合的在线地图CAD编辑系统,同时保留对地图和CAD操作的完全控制能力,同时集成了mxcad在线CAD项目的各种功能。
4.5坐标系统选择注意事项在集成MxCAD与Mapbox时,坐标系统的选择非常重要: 1. CGCS2000与WGS84的区别 - 本项目中采用的是CGCS2000坐标系 - 默认的Mapbox使用的是WGS84坐标系 - 两种坐标系在中国区域的偏差约为几米到几十米不等
2. 坐标系选择建议 - 如果您的项目需要精确对应中国国内地理位置,建议使用修改版的Mapbox CGCS2000 - 使用CGCS2000时,所有经纬度输入和输出都是CGCS2000坐标系下的值 - 如果对精度要求不高或主要用于国际项目,可以使用默认的Mapbox(WGS84)+ 补丁方式 - 使用默认WGS84时,无需替换为修改版的Mapbox库
3. 坐标转换 如果需要在两种坐标系统之间进行转换,可以使用相关转换工具或库,例如proj4js: - <font size="3">// 使用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);</font>
复制代码选择合适的坐标系对于项目的精确定位至关重要,特别是在涉及到工程测量、规划设计等高精度应用场景中。
|