Skip to content
On this page

弧长

下面我们将介绍如何利用 mxcad 插件实现在CAD图纸中测量弧长的功能,该功能中用户点击目标圆弧对象将自动标记出这个圆弧的弧长,同时用户可以自定义选择标注文字的位置。测量弧长功能能够帮助用户快速掌握目标圆弧对象的数据信息,方便统计工程量。

功能实现

  1. 实现自定义弧长标注类

为了方便后期管理与修改标注,我们可以通过继承 McDbCustomEntity 自定义实体类来扩展实现弧长标注类。其中,在 mxcad 中圆弧对象对应的实体类为 McDbArc ,该类提供了获取或设置圆弧相关信息的属性或方法,我们可以根据我们的功能需求去选择调用。在测量弧长功能中,我们可以调用 McDbArc.getLength() 方法获取圆弧长度。

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

ts
// 自定义弧长标注类
class McDbTestArcComment extends McDbCustomEntity {
    /** 圆弧圆心 */
    private center: McGePoint3d = new McGePoint3d();
    /** 圆弧半径 */
    private radius: number;
    /** 圆弧开始角度 */
    private startAngle: number;
    /** 圆弧结束角度 */
    private endAngle: number;
    /** 弧线标注点 */
    private position: McGePoint3d = new McGePoint3d();
    /** 弧线标注文本高度 */
    private height: number = 50;
    constructor(imp?: any) {
        super(imp);
    }
    public create(imp: any) {
        return new McDbTestArcComment(imp)
    }
    /** 获取类名 */
    public getTypeName(): string {
        return "McDbTestArcComment";
    }
    //设置或获取标注圆弧圆心
    public set arcCenter(val: McGePoint3d) {
        this.center = val.clone();
    }
    public get arcCenter(): McGePoint3d {
        return this.center;
    }
    //设置或获取标注圆弧半径
    public set arcRadius(val: number) {
        this.radius = val;
    }
    public get arcRadius(): number {
        return this.radius;
    }
    //设置或获取标注文本高度
    public set textHeight(val: number) {
        this.height = val;
    }
    public get textHeight(): number {
        return this.height;
    }
    //设置或获取标注圆弧起始角度
    public set arcStartAngle(val: number) {
        this.startAngle = val;
    }
    public get arcStartAngle(): number {
        return this.startAngle;
    }
    public set arcEndAngle(val: number) {
        this.endAngle = val;
    }
    public get arcEndAngle(): number {
        return this.endAngle;
    }
    /** 读取数据 */
    public dwgInFields(filter: IMcDbDwgFiler): boolean {
        this.position = filter.readPoint('position').val;
        this.center = filter.readPoint('center').val;
        this.startAngle = filter.readDouble('startAngle').val;
        this.endAngle = filter.readDouble('endAngle').val;
        this.radius = filter.readDouble('radius').val;
        this.height = filter.readDouble('textHeight').val;
        return true;
    }
    /** 写入数据 */
    public dwgOutFields(filter: IMcDbDwgFiler): boolean {
        filter.writePoint("position", this.position);
        filter.writePoint("center", this.center);
        filter.writeDouble("startAngle", this.startAngle);
        filter.writeDouble("endAngle", this.endAngle);
        filter.writeDouble("radius", this.radius);
        filter.writeDouble("textHeight", this.height);
        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;
    };
    // 绘制标注样式线段
    private drawLine(pt1:McGePoint3d, pt2:McGePoint3d):any{
        const vec = pt2.sub(pt1).normalize().mult(MxFun.screenCoordLong2Doc(this.height*0.4));
        const _pt = pt2.clone().addvec(vec);
        const _ptClone = pt2.clone().subvec(vec);
        const line = new McDbLine(_pt, _ptClone)
        line.rotate(pt2,Math.PI/4);
        return {line, pt:_pt};
    }
    private pt1:McGePoint3d
    private pt2:McGePoint3d
    private dbulge:number
    /** 动态绘制 */
    public worldDraw(draw: MxCADWorldDraw): void {
        // 获取测量目标圆弧基础信息
        const arc = new McDbArc();
        arc.center  = this.center;
        arc.startAngle = this.startAngle;
        arc.endAngle = this.endAngle;
        arc.radius = this.radius;
        const length = arc.getLength().val;
        const startPt = arc.getPointAtDist(0).val;
        const endPt = arc.getPointAtDist(length).val;
        
        // 构造标注圆弧长度文本信息
        const lText = new McDbText();
        lText.textString = `${length.toFixed(2)}`;
        lText.height = MxFun.screenCoordLong2Doc(this.height);
        lText.horizontalMode = McDb.TextHorzMode.kTextCenter;
        lText.position = lText.alignmentPoint = this.position;
        // 弧线偏移
        const closePt = arc.getClosestPointTo(this.position, true).val;
        const dist = closePt.distanceTo(this.position);
        arc.offsetCurves(dist, this.position).forEach(obj => {
            const offsetEnt = obj.clone() as McDbArc;
            const length = offsetEnt.getLength().val;
            this.pt1 = offsetEnt.getPointAtDist(0).val;
            this.pt2 = offsetEnt.getPointAtDist(length).val;
            const midPt = offsetEnt.getPointAtDist(length / 2).val;
            this.dbulge = MxCADUtility.calcBulge(this.pt1, midPt, this.pt2).val;
        })
        // 绘制标注样式
        const pl = new McDbPolyline();
        pl.addVertexAt(this.pt1, this.dbulge);
        pl.addVertexAt(this.pt2);
        // 调整文本角度
        const angle = this.pt1.sub(this.pt2).angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
        lText.rotation = angle === Math.PI ? 0 : angle;

        const { line:line1, pt:_pt1 } = this.drawLine(startPt, this.pt1);
        const { line:line2, pt:_pt2 } = this.drawLine(endPt, this.pt2);
        pl.trueColor = lText.trueColor = line1.trueColor = line2.trueColor = this.trueColor;
        draw.drawEntity(pl);
        draw.drawEntity(lText);
        draw.drawEntity(line1);
        draw.drawEntity(line2);
        draw.drawEntity(new McDbLine(startPt, _pt1))
        draw.drawEntity(new McDbLine(endPt, _pt2))
    }
    /** 设置标注点 */
    public setPosition(pt: McGePoint3d) {
        this.assertWrite();
        this.position = pt.clone();
    }
    /** 获取标注点 */
    public getPoint() {
        return this.position;
    }

}
  1. 注册自定义类信息
ts
new McDbTestArcComment().rxInit();
  1. 编写方法,调用 McDbTestArcComment 自定义弧长标注类实现测量弧长功能
  • 获取目标圆弧对象,得到相关数据信息

我们可以利用选择实体对象 MxCADUiPrEntity() 根据用户鼠标点击的坐标得到对应的实体,其中我们需要只选择圆弧对象,因此,我们再调用 MxCADResbuf() 为选择实体对象设置过滤器来过滤出目标实体。

ts
// 选择实体对象
const getEnt = new MxCADUiPrEntity();
// 设置提示信息
getEnt.setMessage('请选择一条弧线');
// 设置过滤器
const filter = new MxCADResbuf([DxfCode.kEntityType, "ARC"]);
getEnt.setFilter(filter);
// entId过滤选择后的圆实体对象ID
const entId = await getEnt.go();
if (!entId.id) return;
// 获取圆弧相关信息
const arc = entId.getMcDbEntity() as McDbArc;
const mArc = new McDbTestArcComment();
mArc.arcCenter = arc.center;
mArc.arcStartAngle = arc.startAngle;
mArc.arcEndAngle = arc.endAngle;
mArc.arcRadius = arc.radius;
  • 指定标注点并绘制弧长标注对象

我们可以利用 MxCADUiPrPoint 取点对象在页面中交互取点。在取点过程中,我们可以通过 MxCADUiPrPoint.setUserDraw() 方法动态绘制标注对象,使用户更加直观的观察到标注对象的位置变化。

ts
// 设置取点对象
const getPos = new MxCADUiPrPoint();
// 设置提示信息
getPos.setMessage("请指定尺寸线位置");
// 动态绘制
getPos.setUserDraw((pt, pw) => {
    pw.setColor(0xFF0000);
    mArc.setPosition(pt);
    pw.drawMcDbEntity(mArc)
});
const position = await getPos.go();
if (!position) return;
// 设置标注文本位置
mArc.setPosition(position);
// 设置弧长标注对象颜色
mArc.trueColor = new McCmColor(0xFF000000);
// 绘制弧长圆标注对象
const mxcad = MxCpp.getCurrentMxCAD();
mxcad.drawEntity(mArc);

功能实践

实践效果如下:

  • 点击弧长按钮,执行测量弧长方法
  • 选中目标圆弧对象
  • 设置标注点位置
  • 成功绘制测量标注内容