Skip to content
On this page

标高标注

下面我们将介绍如何利用 mxcad 插件实现在CAD图纸中标高标注的功能,该功能中用户可设置高度标注的初始比对位置,可根据标注需求设置标高方向、文字对齐方式、标注方式等。

功能实现

  1. 枚举设置选项
ts
// 文字对齐方式
enum textPos {
    // 文字齐始端
    start,
    // 文字齐线端
    end
}
// 标注方式
enum markPos {
    // 自由标注
    freeLabeling,
    // 对齐标注
    alignmentMark
}
  1. 实现自定义标高标注类

为了方便后期管理与修改标高标注设置,我们可以通过继承 McDbCustomEntity 自定义实体类来扩展实现自定义标高标注类。

ts
// 标高标注类
class McDbTestElevationMark extends McDbCustomEntity {
    // 定义McDbTestElevationMark内部的点对象 
    // 标注点
    private markPoint: McGePoint3d = new McGePoint3d();
    // 标注方向点
    private directPt: McGePoint3d = new McGePoint3d();
    // 标注结束点
    private endPt: McGePoint3d = new McGePoint3d();
    // 字高
    private height: number = 0;
    // 精度值
    private _precisionVal: number = 3;
    // 初始高度
    private _initialHeight: number = 0;
    // 标注高度
    private markHeight: string = "0";
    // 象限
    private _quadrant: number = 0;
    // 文字对齐方式
    private _textPos: number = textPos.end;

    // 构造函数
    constructor(imp?: any) {
        super(imp);
    }
    // 创建函数height
    public create(imp: any) {
        return new McDbTestElevationMark(imp)
    }
    // 获取类名
    public getTypeName(): string {
        return "McDbTestElevationMark";
    }
    //设置或获取精度值
    public set precisionVal(val: number) {
        this._precisionVal = val;
    }
    public get precisionVal(): number {
        return this._precisionVal;
    }
    //设置或获取初始高度
    public set initialHeight(val: number) {
        this._initialHeight = val;
    }
    public get initialHeight(): number {
        return this._initialHeight;
    }
    //设置或获取文字对齐方式
    public set textPos(val: number) {
        this._textPos = val;
    }
    public get textPos(): number {
        return this._textPos;
    }
    //设置或获取象限
    public set quadrant(val: number) {
        this._quadrant = val;
    }
    public get quadrant(): number {
        return this._quadrant;
    }
    // 写入自定义实体数据
    public dwgOutFields(filter: IMcDbDwgFiler): boolean {
        filter.writePoint("markPoint", this.markPoint);
        filter.writePoint("directPt", this.directPt);
        filter.writePoint("endPt", this.endPt);
        filter.writeDouble("height", this.height);
        filter.writeDouble("height", this.height);
        filter.writeDouble("initialHeight", this._initialHeight);
        filter.writeLong("precisionVal", this._precisionVal);
        filter.writeLong("quadrant", this._quadrant);
        filter.writeLong("textPos", this._textPos);
        filter.writeString("markHeight", this.markHeight);
        return true;
    }
    // 读取自定义实体数据
    public dwgInFields(filter: IMcDbDwgFiler): boolean {
        this.markPoint = filter.readPoint("markPoint").val;
        this.directPt = filter.readPoint("directPt").val;
        this.endPt = filter.readPoint("endPt").val;
        this.height = filter.readDouble("height").val;
        this._initialHeight = filter.readDouble("initialHeight").val;
        this.markHeight = filter.readString("markHeight").val;
        this._precisionVal = filter.readLong("precisionVal").val;
        this._textPos = filter.readLong("textPos").val;
        this._quadrant = filter.readLong("quadrant").val;
        return true;
    }
    // 移动自定义对象的夹点
    public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
        this.assertWrite();
        if (iIndex === 0) {
            this.markPoint.x += dXOffset;
            this.markPoint.y += dYOffset;
            this.markPoint.z += dZOffset;
            this.directPt.x += dXOffset;
            this.directPt.y += dYOffset;
            this.directPt.z += dZOffset;
            this.endPt.x += dXOffset;
            this.endPt.y += dYOffset;
            this.endPt.z += dZOffset;
        } else if (iIndex === 1) {
            const pt = this.directPt.clone();
            pt.x += dXOffset;
            pt.y += dYOffset;
            pt.z += dZOffset;
            this.countQuadrant(pt);
        } else if (iIndex === 2) {
            const point = this.endPt.clone();
            const v = this.endPt.sub(this.directPt).normalize().mult(2*this.height);
            const pt = this.directPt.clone().addvec(v);
            const x = point.x + dXOffset;
            if(this._quadrant === 1 || this._quadrant === 4){
                x > pt.x ? this.endPt.x += dXOffset:this.endPt.x = pt.x
            }else if(this._quadrant === 2 || this._quadrant === 3){
                x < pt.x ? this.endPt.x += dXOffset:this.endPt.x = pt.x
            }
        }
    };
    // 获取自定义对象的夹点
    public getGripPoints(): McGePoint3dArray {
        let ret = new McGePoint3dArray()
        ret.append(this.markPoint);
        ret.append(this.directPt);
        ret.append(this.endPt);
        return ret;
    };

    // 绘制实体 
    public worldDraw(draw: MxCADWorldDraw): void {
        // 绘制文本
        const text = new McDbText();
        text.height = this.height;
        text.textString = this.markHeight;
        if (this._textPos === textPos.start) {
            text.position = text.alignmentPoint =
                (this._quadrant === 3 || this._quadrant === 4) ?
                    this.endPt.clone().subvec(McGeVector3d.kYAxis.clone().mult(this.height * (5 / 4))) :
                    this.endPt.clone().addvec(McGeVector3d.kYAxis.clone().mult((1 / 4) * this.height));
        } else {
            text.position = text.alignmentPoint =
                (this._quadrant === 3 || this._quadrant === 4) ?
                    this.directPt.clone().subvec(McGeVector3d.kYAxis.clone().mult(this.height * (5 / 4))) :
                    this.directPt.clone().addvec(McGeVector3d.kYAxis.clone().mult((1 / 4) * this.height));
        }

        // 绘制标高线
        const v = McGeVector3d.kXAxis.clone().mult(this.height * 2);
        let pt;
        if (this._quadrant === 1 || this._quadrant === 4) {
            pt = this.directPt.clone().addvec(v);
            if (this._textPos === textPos.start) {
                text.horizontalMode = McDb.TextHorzMode.kTextRight;
            } else if (this._textPos === textPos.end) {
                text.horizontalMode = McDb.TextHorzMode.kTextLeft;
            }

        } else {
            pt = this.directPt.clone().subvec(v);
            if (this._textPos === textPos.start) {
                text.horizontalMode = McDb.TextHorzMode.kTextLeft;
            } else if (this._textPos === textPos.end) {
                text.horizontalMode = McDb.TextHorzMode.kTextRight;
            }
        }
        const pl = new McDbPolyline();
        pl.addVertexAt(pt);
        pl.addVertexAt(this.markPoint);
        pl.addVertexAt(this.directPt);
        pl.addVertexAt(this.endPt);
        draw.drawEntity(pl);
        draw.drawEntity(text);
    }
    // 计算象限,终点
    private countQuadrant(pt?: McGePoint3d) {
        const vec = McGeVector3d.kYAxis.clone().mult(this.height);
        const v = McGeVector3d.kXAxis.clone().mult(this.height)
        if (pt) {
            if (pt.y > this.markPoint.y) {
                if (pt.x > this.markPoint.x) {
                    this._quadrant = 1;
                } else {
                    this._quadrant = 2;
                }
            } else {
                if (pt.x > this.markPoint.x) {
                    this._quadrant = 4;
                } else {
                    this._quadrant = 3;
                }
            };
        }
        if (this._quadrant === 1 || this._quadrant === 2) {
            const midPt = this.markPoint.clone().addvec(vec);
            if (this._quadrant === 1) {
                this.directPt = midPt.clone().subvec(v);
            } else {
                this.directPt = midPt.clone().addvec(v);
            }
        }
        if (this._quadrant === 3 || this._quadrant === 4) {
            const midPt = this.markPoint.clone().subvec(vec);
            if (this._quadrant === 4) {
                this.directPt = midPt.clone().subvec(v);
            } else {
                this.directPt = midPt.clone().addvec(v);
            }
        }
        const text = new McDbText();
        text.height = this.height;
        text.textString = this.markHeight;
        const id = MxCpp.getCurrentMxCAD().drawEntity(text);
        const { minPt, maxPt } = id.getMcDbEntity().getBoundingBox();
        id.erase();
        const length = maxPt.x - minPt.x + this.height * (7 / 2);
        const _v = McGeVector3d.kXAxis.clone().mult(length);
        if (this._quadrant === 1 || this._quadrant === 4) {
            this.endPt = this.directPt.clone().addvec(_v);
        } else {
            this.endPt = this.directPt.clone().subvec(_v);
        }
    }
    // 设置标注点位置
    public setMarkPoint(pt: McGePoint3d) {
        this.markPoint = pt.clone();
        if (!this.height) this.height = MxFun.screenCoordLong2Doc(15);
        this.markHeight = (this.markPoint.y - this._initialHeight).toFixed(this._precisionVal);
        !this._quadrant ? this.countQuadrant(this.markPoint) : this.countQuadrant();
    }
    // 获取标注点位置
    public getMarkPoint() {
        return this.markPoint;
    }
    // 设置指向
    public setDirectPt(pt: McGePoint3d) {
        this.countQuadrant(pt);
    }
    // 获取指向
    public getDirectPt() {
        return this.directPt;
    }
};
  1. 注册自定义类信息
ts
new McDbTestElevationMark().rxInit();
  1. 编写方法,调用 McDbTestElevationMark 自定义标高标注类实现标高标注功能
  • 构建初始 McDbTestElevationMark 对象

标高标注中的高度精度值设置需设置为正整数,即该数代表标高数值精确到小数点后几位;文字对齐方式则需设置为上述步骤中枚举的 textPos 类中的值;标注对齐方式则需设置为上述步骤中枚举的 markPos 类中的值。下述示例为直接设置标高标注的初始值。

ts
let basePt: McGePoint3d = new McGePoint3d();
const eMark = new McDbTestElevationMark();
// 标高数值精确到小树后3位
eMark.precisionVal = 3;
// 文字标注方式设置为文字齐始端
eMark.textPos = textPos.start;
  • 设置标高点及标高方向

调用 MxCADUiPrPoint 取点对象设置标高标注的标高点及标高方向。

ts
// 获取标高点
const getPos = new MxCADUiPrPoint();
getPos.setMessage('请点取标高点:');
getPos.setUserDraw((pt, pw) => {
    const _eMark = eMark.clone() as McDbTestElevationMark;
    _eMark.initialHeight = pt.y;
    _eMark.setMarkPoint(pt);
    pw.drawMcDbEntity(_eMark);
});
const position = await getPos.go();
if (!position) return;
basePt = position.clone();
// 设置初始比对高度
eMark.initialHeight = position.y;
eMark.setMarkPoint(position);

// 设置标高方向
const getDirectPt = new MxCADUiPrPoint();
getDirectPt.setMessage('点取标高方向:');
getDirectPt.setUserDraw((pt, pw) => {
    const _eMark = eMark.clone() as McDbTestElevationMark;
    _eMark.setDirectPt(pt);
    pw.drawMcDbEntity(_eMark);
});
const directPt = await getDirectPt.go();
if (!directPt) return;
eMark.setDirectPt(directPt);
const mxcad = MxCpp.getCurrentMxCAD();
mxcad.drawEntity(eMark);
  • 连续绘制标注

以绘制的第一个标注点为相对高度起始点,连续绘制后续标高标注。在绘制过程中,可根据上述步骤中设置的标注对齐方式来确定后续标注点位置。若标注方式为对齐标注,则后续标高点应与初始标高点位置对齐;若为自由标注,则可任意设置标高点位置。

ts
// 标高对齐线
const line_y = new McDbLine(position.x, 0, 0, position.x, position.y, position.z);
// 标注对齐方式设置为自由标注
let _markPos = markPos.freeLabeling;
// 循环标注
while (true) {
    // 连续取点
    const getPoint = new MxCADUiPrPoint();
    getPoint.setMessage('请点取下一点:');
    let point:McGePoint3d = new McGePoint3d();
    // 动态绘制标高标注
    getPoint.setUserDraw((pt, pw) => {
        const _eMark = eMark.clone() as McDbTestElevationMark;
        if (_markPos === markPos.alignmentMark) {
            point = line_y.getClosestPointTo(pt, true).val
        } else {
            point = pt.clone()
        }
        _eMark.setMarkPoint(point);
        pw.drawMcDbEntity(_eMark);
        // 动态绘制辅助线
        const line = new McDbLine(basePt.x, basePt.y, basePt.z, point.x, point.y, point.z);
        pw.drawMcDbEntity(line);
    });
    const nextPt = await getPoint.go();
    if (!nextPt) return;
    basePt = nextPt.clone();
    const _eMark = eMark.clone() as McDbTestElevationMark;
    _eMark.setMarkPoint(point);
    mxcad.drawEntity(_eMark);
}

功能实践

实践效果如下:

  • 点击标高标注按钮,执行标高标注方法
  • 点击鼠标左键设置标高点起始位置
  • 移动鼠标确定标高方向,点击左键确定
  • 继续移动鼠标可连续点击左键进行标注
  • 点击右键可退出循环结束取点
  • 成功绘制标高标注