一、前言
本章將介紹如何利用mxcad插件實現在CAD圖紙中測量圓和測量面積的功能,用户點擊目標圓對象將自動標記出這個圓的半徑、面積值和周長值,同時可以自定義選擇標註文字的位置,測量圓功能能夠快速掌握目標圓對象的數據信息,方便統計工程量。
測量面積功能(多邊形、矩形)以多邊形的每一個頂點來確定多邊形的形狀和位置,通過點擊矩形的量角點來確定矩形的大小和位置,也可以自定義標註文字的位置。
二、測量圓的功能實現
2.1.實現自定義圓標註類
為了方便後期管理與修改標註,可以通過繼承McDbCustomEntity自定義實體類來擴展實現圓標註類。其中在 mxcad 中圓對象對應的實體類為McDbCircle,該類提供了獲取或設置圓相關信息的屬性或方法,我們可以根據功能需求去選擇調用。
在測量圓功能中需要獲取圓對象的半徑、面積與周長,因此可以調用McDbCircle.radius屬性獲取圓半徑,McDbCircle.getArea()方法或直接計算來獲取圓面積,以及McDbCircle.getLength()方法獲取圓周長。然後利用McDbMText構造測量信息多文本對象,將圓的標註信息繪製在頁面中,參考代碼如下:
// 自定義圓標註類
class McDbTestMeasuringCircle extends McDbCustomEntity {
// 定義McDbTestMeasuringCircle內部的點對象
// 圓心
private center: McGePoint3d = new McGePoint3d();
// 標註點
private position: McGePoint3d = new McGePoint3d();
// 圓半徑
private radius: number;
// 構造函數
constructor(imp?: any) {
super(imp);
}
// 創建函數
public create(imp: any) {
return new McDbTestMeasuringCircle(imp)
}
// 獲取類名
public getTypeName(): string {
return "McDbTestMeasuringCircle";
}
//設置或獲取圓半徑
public set circleRadius(val: number) {
this.radius = val;
}
public get circleRadius(): number {
return this.radius;
}
// 讀取自定義實體數據center、position、radius
public dwgInFields(filter: IMcDbDwgFiler): boolean {
this.center = filter.readPoint("center").val;
this.position = filter.readPoint("position").val;
this.radius = filter.readDouble("radius").val;
return true;
}
// 寫入自定義實體數據center、position、radius
public dwgOutFields(filter: IMcDbDwgFiler): boolean {
filter.writePoint("center", this.center);
filter.writePoint("position", this.position);
filter.writeDouble("radius", this.radius);
return true;
}
// 移動自定義對象的夾點
public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
this.assertWrite();
this.position.x += dXOffset;
this.position.y += dYOffset;
this.position.z += dZOffset;
};
// 獲取自定義對象的夾點
public getGripPoints(): McGePoint3dArray {
let ret = new McGePoint3dArray()
ret.append(this.position);
return ret;
};
// 繪製實體
public worldDraw(draw: MxCADWorldDraw): void {
// 繪製標註圓與標註信息
const circle = new McDbCircle();
circle.center = this.center;
circle.radius = this.radius;
const length = circle.getLength().val;
const radius = circle.radius;
const area = Math.PI * radius * radius;
const mText = new McDbMText();
mText.contents = `半徑:${radius.toFixed(2)} \\P 周長:${length.toFixed(2)} \\P 面積:${area.toFixed(2)}`
mText.textHeight = radius / 6;
mText.attachment = McDb.AttachmentPoint.kMiddleCenter;
mText.location = this.position;
mText.trueColor = circle.trueColor = this.trueColor;
draw.drawEntity(mText);
draw.drawEntity(circle);
}
// 設置pt1
public setCenter(pt: McGePoint3d) {
this.assertWrite();
this.center = pt.clone();
}
// 獲取pt1
public getCenter() {
return this.center;
}
// 獲取position
public setPosition(pt: McGePoint3d) {
this.assertWrite();
this.position = pt.clone();
}
// 獲取position
public getPosition() {
return this.position;
}
}
2.2 註冊自定義類信息
運行代碼:
new McDbTestMeasuringCircle().rxInit();
2.3 編寫方法調用McDbTestMeasuringCircle自定義圓標註類實現測量圓功能
2.3.1 獲取目標圓對象,得到相關數據信息
利用選擇實體對象MxCADUiPrEntity()根據用户鼠標點擊的座標得到對應的實體,其中需要只選擇圓對象,因此,我們再調用MxCADResbuf()為選擇實體對象設置過濾器來過濾出目標實體,參考代碼如下:
// 選擇實體對象
const getEnt = new MxCADUiPrEntity();
// 設置提示信息
getEnt.setMessage("請選擇一個圓對象");
// 設置過濾器
const filter = new MxCADResbuf([DxfCode.kEntityType, "CIRCLE"]);
getEnt.setFilter(filter);
// entId過濾選擇後的圓實體對象ID
const entId = await getEnt.go();
if (!entId.id) return;
// 獲取圓相關信息
const circle = entId.getMcDbEntity() as McDbCircle;
const mCircle = new McDbTestMeasuringCircle();
mCircle.setCenter(circle.center);
mCircle.circleRadius = circle.radius;
2.3.2 指定標註點並繪製圓標註對象
利用MxCADUiPrPoint取點對象在頁面中交互取點。在取點過程中通過MxCADUiPrPoint.setUserDraw()方法動態繪製標註對象,使用户更加直觀的觀察到標註對象的位置變化,參考代碼如下:
// 設置取點對象
const getPt = new MxCADUiPrPoint();
// 設置提示信息
getPt.setMessage('請指定文字位置');
// 動態繪製
getPt.setUserDraw((pt, pw) => {
pw.setColor(0xFF0000);
mCircle.setPosition(pt);
pw.drawMcDbEntity(mCircle);
});
const point = await getPt.go();
if (!point) return;
// 設置標註文本位置
mCircle.setPosition(point);
// 設置圓標註對象顏色
mCircle.trueColor = new McCmColor(255, 0, 0)
const mxcad = MxCpp.getCurrentMxCAD();
// 繪製圓標註對象
mxcad.drawEntity(mCircle);
效果如下圖:
三、測量面積的功能實現
3.1 實現自定義面積標註類
為了方便後期管理與修改標註,可以通過繼承McDbCustomEntity自定義實體類來擴展實現面積標註類。其中在mxcad中多邊形與矩形都是通過多段線繪製出來的,多段線對象對應的實體類為McDbPolyline,該類提供了獲取或設置圖形對象相關信息的屬性或方法,根據功能需求去選擇調用。
在測量面積(多邊形、矩形)功能中,調用McDbPolyline.getLength()方法獲取多段線對象的長度、以及在多段線閉合的情況下調用McDbPolyline.getArea()方法獲取面積。然後利用McDbMText構造測量信息多文本對象,將對象的標註信息繪製在頁面中,參考代碼如下:
// 自定義面積標註類
class McDbTestAreaComment extends McDbCustomEntity {
/** 點數組 */
private ptArr: McGePoint3d[] = [];
/** 標註點 */
private pt: McGePoint3d;
/** 字高 */
private height: number = 50;
/** 凸度數組 */
private dbulges: number[] = [];
/** 測量對象是否為矩形 */
private isReactFlag: boolean = false;
constructor(imp?: any) {
super(imp);
}
public create(imp: any) {
return new McDbTestAreaComment(imp)
}
/** 獲取類名 */
public getTypeName(): string {
return "McDbTestAreaComment";
}
//設置或獲取文本字高
public set textHeight(val: number) {
this.height = val;
}
public get textHeight(): number {
return this.height;
}
//設置或獲取測量對象是否為矩形
public set isReact(val: boolean) {
this.isReactFlag = val;
}
public get isReact(): boolean {
return this.isReactFlag;
}
/** 讀取數據 */
public dwgInFields(filter: IMcDbDwgFiler): boolean {
this.ptArr = filter.readPoints('ptArr').val;
this.pt = filter.readPoint('pt').val;
const _dbulges = filter.readString("dbulges").val;
this.dbulges = _dbulges.split(',').map(Number);
this.isReactFlag = filter.readLong("isReactFlag").val ? true : false;
return true;
}
/** 寫入數據 */
public dwgOutFields(filter: IMcDbDwgFiler): boolean {
filter.writePoints("ptArr", this.ptArr);
filter.writePoint("pt", this.pt);
const _dbulges = this.dbulges.toString();
filter.writeString("dbulges", _dbulges);
filter.writeLong("isReactFlag", this.isReactFlag ? 1 : 0);
return true;
}
/** 移動夾點 */
public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
this.assertWrite();
this.ptArr.forEach((point, index) => {
if (index === iIndex) {
point.x += dXOffset;
point.y += dYOffset;
point.z += dZOffset;
}
});
if (iIndex === this.ptArr.length) {
this.pt.x += dXOffset;
this.pt.y += dYOffset;
this.pt.z += dZOffset;
}
};
/** 獲取夾點 */
public getGripPoints(): McGePoint3dArray {
let ret = new McGePoint3dArray();
this.ptArr.forEach(point => {
ret.append(point);
})
ret.append(this.pt);
return ret;
};
/** 動態繪製 */
public worldDraw(draw: MxCADWorldDraw): void {
const pl = new McDbPolyline();
pl.isClosed = true;
if (this.isReactFlag) {
// 測量的是矩形,得到的就是矩形的兩個角點
pl.addVertexAt(this.ptArr[0], 0, 0.1, 0.1);
pl.addVertexAt(new McGePoint3d(this.ptArr[1].x, this.ptArr[0].y), 0, 0.1, 0.1);
pl.addVertexAt(this.ptArr[1], 0, 0.1, 0.1);
pl.addVertexAt(new McGePoint3d(this.ptArr[0].x, this.ptArr[1].y), 0, 0.1, 0.1);
} else {
// 測量的是多邊形
this.ptArr.forEach((pt, index) => {
pl.addVertexAt(pt, this.dbulges[index], 0.1, 0.1);
});
}
// 獲取對象數據信息
const area = pl.getArea().val;
const length = pl.getLength().val;
// 構造對文本對象
const text = new McDbMText();
text.contents = `面積:${area.toFixed(2)}\\P周長:${length.toFixed(2)} `;
text.attachment = McDb.AttachmentPoint.kMiddleCenter;
text.location = this.pt;
text.textHeight = MxFun.screenCoordLong2Doc(this.height);
// 設置標註顏色
text.trueColor = this.trueColor;
draw.trueColor = this.trueColor;
// 繪製標註對象
draw.drawEntity(text);
draw.drawEntity(pl);
}
/** 設置標註點 */
public setPoint(pt: McGePoint3d) {
this.assertWrite();
this.pt = pt.clone();
}
/** 增加頂點 */
public addVertex(pt: McGePoint3d, dbulge?: number) {
this.assertWrite();
this.ptArr.push(pt.clone());
this.dbulges.push(dbulge ? dbulge : 0);
}
/** 獲取標註點 */
public getPoint() {
return this.pt;
}
}
3.2 註冊自定義類信息
運行代碼如下:
new McDbTestAreaComment().rxInit();
3.3 編寫方法,調用McDbTestAreaComment自定義面積標註類實現測量面積(多邊形、矩形)功能
3.3.1 測量多邊形面積
測量多邊形面積需要連續取點,且取點不少於3個。利用MxCADUiPrPoint取點對象在圖紙中循環取點來確定需要測量多邊形的位置與大小,並通過MxCADUiPrPoint.setKeyWords()為其設置關鍵字列表,使用户能夠實現自主撤銷操作或提前結束操作,方便交互,參考代碼如下:
// 測量多邊形面積
async function Mx_Area() {
// 多邊形頂點數值
const ptArr: McGePoint3d[] = [];
// 獲取多邊形第一個頂點
const getPt1 = new MxCADUiPrPoint();
getPt1.setMessage('請選擇面積的第一個點');
const pt1 = await getPt1.go();
if (!pt1) return;
ptArr.push(pt1);
// 循環取點
while (true) {
const getPt = new MxCADUiPrPoint();
getPt.setMessage('請選擇下一個點');
getPt.setKeyWords("[回退(B)/結束(O)]");
getPt.setUserDraw((pt, pw) => {
const draw_pl = new McDbPolyline();
ptArr.forEach(point => {
draw_pl.addVertexAt(point, 0, 0.1, 0.1);
});
draw_pl.addVertexAt(pt);
pw.drawMcDbEntity(draw_pl);
});
const pt = await getPt.go();
const key = getPt.keyWordPicked();
if (key === 'B') {
// 回退到上一個取點對象
if (ptArr.length > 1) {
ptArr.pop();
}
} else if (key === 'O') {
// 結束取點
break;
} else {
if (!pt) break;
ptArr.push(pt);
}
};
// 測量多邊形至少取3個點
if(ptArr.length < 2) return;
// 構造面積標註對象並設置標註位置
const mxcad = MxCpp.getCurrentMxCAD();
const area = new McDbTestAreaComment();
ptArr.forEach((point) => {
area.addVertex(point, 0);
});
const position = new MxCADUiPrPoint();
position.setMessage('請選擇面積標註的位置');
position.setUserDraw((pt, pw) => {
pw.setColor(0xFF0000)
area.setPoint(pt);
pw.drawMcDbEntity(area);
})
const positionPt = await position.go();
if (!positionPt) return;
area.setPoint(positionPt);
area.trueColor = new McCmColor(255,0,0)
mxcad.drawEntity(area);
}
3.3.2 測量矩形面積
測量矩形面積只需要選取矩形的兩個角點就可以確定矩形的大小與位置,參考代碼如下:
// 矩形面積
async function Mx_ReactArea() {
// 設置測量矩形的兩個角點
const getPt1 = new MxCADUiPrPoint();
getPt1.setMessage('請選擇矩形的角點1');
const pt1 = await getPt1.go();
if (!pt1) return;
const getPt2 = new MxCADUiPrPoint();
getPt2.setMessage('請選擇矩形的角點2');
// 動態繪製矩形
getPt2.setUserDraw((pt, pw) => {
const pl = new McDbPolyline();
pl.isClosed = true;
pl.addVertexAt(pt1);
pl.addVertexAt(new McGePoint3d(pt.x, pt1.y));
pl.addVertexAt(pt);
pl.addVertexAt(new McGePoint3d(pt1.x, pt.y));
pw.drawMcDbEntity(pl);
})
const pt2 = await getPt2.go();
if (!pt2) return;
// 構造面積標註
const reactArea = new McDbTestAreaComment();
reactArea.isReact = true;
reactArea.addVertex(pt1);
reactArea.addVertex(pt2);
// 設置標註位置
const getPos = new MxCADUiPrPoint();
getPos.setMessage('請設置面積標註的位置');
getPos.setUserDraw((pt, pw) => {
pw.setColor(0xFF0000)
reactArea.setPoint(pt);
pw.drawMcDbEntity(reactArea);
});
const position = await getPos.go();
if (!position) return;
reactArea.setPoint(position);
// 設置標註顏色
reactArea.trueColor = new McCmColor(255, 0, 0)
MxCpp.getCurrentMxCAD().drawEntity(reactArea);
}
效果如下圖: