标高标注
下面我们将介绍如何利用 mxcad 插件实现在CAD图纸中标高标注的功能,该功能中用户可设置高度标注的初始比对位置,可根据标注需求设置标高方向、文字对齐方式、标注方式等。
功能实现
- 枚举设置选项
ts
// 文字对齐方式
enum textPos {
// 文字齐始端
start,
// 文字齐线端
end
}
// 标注方式
enum markPos {
// 自由标注
freeLabeling,
// 对齐标注
alignmentMark
}
- 实现自定义标高标注类
为了方便后期管理与修改标高标注设置,我们可以通过继承 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;
}
};
- 注册自定义类信息
ts
new McDbTestElevationMark().rxInit();
- 编写方法,调用 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);
}
功能实践
实践效果如下:
- 点击标高标注按钮,执行标高标注方法
- 点击鼠标左键设置标高点起始位置
- 移动鼠标确定标高方向,点击左键确定
- 继续移动鼠标可连续点击左键进行标注
- 点击右键可退出循环结束取点
- 成功绘制标高标注