Skip to content
On this page

测量面积(多边形、矩形)

下面我们将介绍如何利用 mxcad 插件实现在CAD图纸中测量面积(多边形、矩形)的功能,该功能中通过用户点击目标多边形的每一个顶点来确定多边形的形状和位置,通过用户点击矩形的量角点来确定矩形的大小和位置,同时用户可以自定义选择标注文字的位置。测量面积(多边形、矩形)功能能够帮助用户快速掌握目标对象的数据信息,方便统计工程量。

功能实现

  1. 实现自定义面积标注类

为了方便后期管理与修改标注,我们可以通过继承 McDbCustomEntity 自定义实体类来扩展实现面积标注类。其中,在 mxcad 中多边形与矩形都是通过多段线绘制出来的,多段线对象对应的实体类为 McDbPolyline,该类提供了获取或设置图形对象相关信息的属性或方法,我们可以根据我们的功能需求去选择调用。在测量面积(多边形、矩形)功能中,我们可以调用 McDbPolyline.getLength() 方法获取多段线对象的长度、以及在多段线闭合的情况下调用 McDbPolyline.getArea() 方法获取面积。

然后,我们可以利用 McDbMText 构造测量信息多文本对象,将对象的标注信息绘制在页面中。

ts
// 自定义面积标注类
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;
    }

}
  1. 注册自定义类信息
ts
new McDbTestAreaComment().rxInit();
  1. 编写方法,调用 McDbTestAreaComment 自定义面积标注类实现测量面积(多边形、矩形)功能
  • 测量多边形面积

测量多边形面积需要连续取点,且取点不少于3个。我们可以利用 MxCADUiPrPoint 取点对象在图纸中循环取点来确定需要测量多边形的位置与大小,并通过 MxCADUiPrPoint.setKeyWords() 为其设置关键字列表,使用户能够实现自主撤销操作或提前结束操作,方便交互。

ts
// 测量多边形面积
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);
}
  • 测量矩形面积

测量矩形面积只需要选取矩形的两个角点就可以确定矩形的大小与位置。

ts
// 矩形面积
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);
}

功能实践

实践效果如下:

  • 点击测量按钮,执行测量方法
  • 鼠标左键点击画布取点
  • 命令行输入关键字执行相应指令
  • 点击鼠标右键结束取点
  • 调整鼠标位置,点击左键设置标注点位置
  • 成功绘制测量标注内容