如何在前端通過JavaScript創建修改CAD圖形

背景

在之前的博文CAD圖DWG解析WebGIS可視化技術分析總結CAD_DWG圖Web可視化一站式解決方案-唯傑地圖-vjmap中講解了如何把CAD的DWG格式的圖紙Web可視化的方案,那在Web前端能不能通過JavaScript創建或基於現在的CAD圖形進行修改呢?

現狀

創建修改CAD圖形,一般是基於AutoCAD進行二次開發,ObjectARX是AutoDesk公司針對AutoCAD平台上的二次開發而推出的一個開發軟件包,它提供了以C++為基礎的面向對象開發環境應用程序接口,能真正快速的訪問AutoCAD圖形數據庫。 與以往的 AutoCAD 二次開發工具 AutoLISP 和ADS不同,ObjectARX應用程序是一個DLL(動態鏈接庫),共享AutoCAD的地址空間,對AutoCAD進行直接函數調用。所以,使用ARX編程的函數的執行速度得以大大提高。ARX 類庫採用了標準的C++類庫的封裝形式,這也大大提高了程序員編程的可靠度和效率。

運用ObjectARX進行二次開發,必須首先設置好ObjectARX的開發環境。常用的開發環境是Microsoft Visual C++ 6.0 、Microsoft visual studio 2005、Microsoft visual studio 2008、Microsoft visual studio 2010。同時,還需要安裝ObjectARX SDK。

Visual C++、ObjectARX等開發語言和環境肯定嚇跑了不少開發者。那對於一些簡單的場景,如只要根據數據自動成圖或者在現在的圖形上做一些很簡單的修改,有沒有一個簡單的辦法或語言和開發環境?

JS新建修改CAD圖形

唯傑地圖在前端實現了常用的AutoCAD實體封裝,能通過JavaScript腳本創建新的CAD圖形。

支持的CAD實體類型

類名稱 說明
DbLine 直線
DbCurve 曲線
Db2dPolyline 二維折線
Db3dPolyline 三維多段線
DbPolyline 多段線
BlockReference 塊參照
DbArc 圓弧
DbCircle
DbEllipse 橢圓
DbHatch 填充
Text 單行文本
DbMText 多行文本
RasterImage 柵格圖片
DbShape 型實體
Spline 樣條曲線
Wipeout 遮罩實體
Dimension 標註
Db2LineAngularDimension 角度標註[兩條線]
Db3PointAngularDimension 角度標註[三點]
DbAlignedDimension 對齊標註
DbArcDimension 圓弧標註
DbDiametricDimension 直徑標註
DbOrdinateDimension 坐標標註
DbRadialDimension 半徑標註
DbRadialDimensionLarge 半徑折線標註
DbRotatedDimension 轉角標註
DbLayer 圖層
DbTextStyle 文字樣式
DbDimStyle 標註樣式
DbLinetypeStyle 線型樣式
DbBlock 塊定義
DbDocument 數據庫文檔

下面以新建一個籃球場示意圖以例,相關代碼如下:

(async () => {
	// --新建地圖--在後台新建CAD圖,然後在前端打開
	// js代碼
	let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
	let doc = new vjmap.DbDocument();
	let entitys = [];
	let line1 = new vjmap.DbLine();
	line1.start = [0, 0]
	line1.end = [0, 15]
	entitys.push(line1)

	let line2 = new vjmap.DbLine();
	line2.start = [0, 14.1]
	line2.end = [2.99, 14.1]
	entitys.push(line2)

	let line3 = new vjmap.DbLine();
	line3.start = [0, 0.9]
	line3.end = [2.99, 0.9]
	entitys.push(line3)

	let line4 = new vjmap.DbLine();
	line4.start = [0, 9.95]
	line4.end = [5.8, 9.95]
	entitys.push(line4)

	let line5 = new vjmap.DbLine();
	line5.start = [0, 5.05]
	line5.end = [5.8, 5.05]

	let hatch = new vjmap.DbHatch();
	hatch.pattern = "SOLID";
	hatch.color = 0xB43F32;
	hatch.points = [line4.start, line4.end, line5.end, line5.start];
	entitys.push(hatch);
	entitys.push(line4)
	entitys.push(line5)

	let line6 = new vjmap.DbLine();
	line6.start = [5.8, 5.05]
	line6.end = [5.8, 9.95]
	entitys.push(line6)

	let arc1 = new vjmap.DbArc();
	arc1.center = [5.7963, 7.504];
	arc1.radius = 1.8014;
	arc1.startAngle = 270 * Math.PI / 180.0;
	arc1.endAngle = 90 * Math.PI / 180.0;
	entitys.push(arc1)

	let arc2 = new vjmap.DbArc();
	arc2.center = [5.7963, 7.504];
	arc2.radius = 1.8014;
	arc2.startAngle = 90 * Math.PI / 180.0;
	arc2.endAngle = 270 * Math.PI / 180.0;
	//arc2.linetype = "DASHED"
	entitys.push(arc2)

	let arc3 = new vjmap.DbArc();
	arc3.center = [1.575, 7.5];
	arc3.radius = 6.75;
	arc3.startAngle = 282 * Math.PI / 180.0;
	arc3.endAngle = 78 * Math.PI / 180.0;
	entitys.push(arc3)

	let block = new vjmap.DbBlock();
	block.name = "ball";
	block.origin = [0, 0]
	block.entitys = entitys;
	doc.appendBlock(block);

	let blockRef1 = new vjmap.DbBlockReference();
	blockRef1.blockname = "ball";
	blockRef1.position = [0, 0];
	doc.appendEntity(blockRef1);

	let blockRef2 = new vjmap.DbBlockReference();
	blockRef2.blockname = "ball";
	blockRef2.position = [28, 15];
	blockRef2.rotation = Math.PI;
	doc.appendEntity(blockRef2);

	let otherEnts = [
		new vjmap.DbLine({
			start: [0, 15],
			end: [28, 15]
		}),
		new vjmap.DbLine({
			start: [0, 0],
			end: [28, 0]
		}),
		new vjmap.DbLine({
			start: [14, 0],
			end: [14, 15],
			colorIndex: 1
		}),
		new vjmap.DbCircle({
			center:[14, 7.5],
			radius: 1.83,
			color: 0xFF0000
		}),
		new vjmap.DbText({
			position: [14, 16],
			contents: "籃球場示意圖",
			colorIndex: 1,
			horizontalMode: 4,
			height: 1,
		})
	]

	doc.appendEntity(otherEnts);

	// js代碼
	let res = await svc.updateMap({
		mapid: "basketballCourt",
		filedoc: doc.toDoc(),
		mapopenway: vjmap.MapOpenWay.Memory,
		style: vjmap.openMapDarkStyle() // div為深色背景顏色時,這裡也傳深色背景樣式
	})
	if (res.error) {
		message.error(res.error)
	}
	let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
	let prj = new vjmap.GeoProjection(mapExtent);

	var map = new vjmap.Map({
		container: 'map', // container ID
		style: svc.rasterStyle(),
		center: prj.toLngLat(mapExtent.center()),
		zoom: 2,
		renderWorldCopies: false
	});
	map.attach(svc, prj);
	map.fitMapBounds();

	map.addControl(new vjmap.NavigationControl());
	map.addControl(new vjmap.MousePositionControl({showZoom: true}));

	map.enableLayerClickHighlight(svc, e => {
		e && message.info(`type: ${e.name}, objectid: ${e.objectid}, layer: ${e.layerindex}`);
	})
})();

創建完後,Web顯示如下:

image-20211018195709908

把創建的DWG圖形,在AutoCAD裏面可以打開此圖:

image-20211018200747551

修改或刪除

修改通過from屬性設置 來源於哪個圖,會在此圖的上面進行修改或新增刪除,格式如 形式為 mapid/version,如 exam/v1 .

刪除的話,指定圖中實體的objectID

示例代碼如下:

let doc = new vjmap.DbDocument();
/** 來源於哪個圖,會在此圖的上面進行修改或新增刪除,格式如 形式為 mapid/version,如 exam/v1 . */
doc.from = "basketballCourt/v1";

// 修改或刪除實體是通過傳遞 `objectid` 實體句柄,如果沒有 `objectid` 則表示新增
let modifyEnts = [
    /*修改*/
    new vjmap.DbCircle({
        objectid: "71",// 實體句柄,如傳了實體句柄,是表示修改或刪除此實體. 
        colorIndex: 2
    }),
    /*刪除*/
    new vjmap.DbText({
        objectid: "73",// 實體句柄,如傳了實體句柄,是表示修改或刪除此實體. 
        delete: true // 表示刪除
    }),
    /*新增(沒有傳 objectid )*/
    new vjmap.DbMText({
        position: [14, -2],
        contents: "我是多行文本",
        colorIndex: 3,
        attachment: 2,
        height: 1,
    })
]
doc.appendEntity(modifyEnts);

// js代碼
let res = await svc.updateMap({
    mapid: "newBasketballCourt",
    filedoc: doc.toDoc(),
    mapopenway: vjmap.MapOpenWay.Memory,
    style: vjmap.openMapDarkStyle() // div為深色背景顏色時,這裡也傳深色背景樣式
})

結果如下:

image-20211018201221961

可以訪問 demo地址 //vjmap.com/guide/newmap.html 去體驗下效果

應用場景

適用於在前端有數據,需要在線創建或基於現在CAD圖形進行修改或刪除;如可獲取全國的GeoJson數據創建一個CAD圖形;對於一些經常變化的數據如工程進度圖紙根據進度數據實時繪製生成DWG圖紙等場景;對於專業複雜的圖形繪製或編輯工作,建議使用ObjectARX對AutoCAD進行二次開發實現!