网易首页 > 网易号 > 正文 申请入驻

在线CAD二次开发实现圆孔标记功能

0
分享至

一、概述

圆孔标记是一种常用的工程图纸标注方式,用于标识圆形孔的位置和特征。本文档将详细介绍如何通过自定义实体(`McDbTestRoundHoleMark`)来实现圆孔标记功能。具体功能源码可下载MxDraw云图开发包后查看。

二、自定义实体类定义

2.1 类结构

export class McDbTestRoundHoleMark extends McDbCustomEntity {
// 圆孔圆心
private center: McGePoint3d;
// 圆孔半径
private radius: number;
// 标记圆上的点集合
private circlePoints: McGePoint3d[];
// 标记中心点集合
private midPoints: McGePoint3d[];
// 标记圆弧中心点
private circleMidPts: McGePoint3d[];
// 标记基点
private originPt: McGePoint3d;
// 包围盒点
private minPt: McGePoint3d;
private maxPt: McGePoint3d;
}

2.2 核心属性说明

- `center`: 圆孔的圆心坐标

- `radius`: 圆孔的半径

- `circlePoints`: 标记圆弧的端点集合

- `midPoints`: 标记射线上的中点集合

- `circleMidPts`: 标记圆弧的中心点集合

- `originPt`: 标记的基准点

- `minPt`/`maxPt`: 包围盒的最小/最大点

三、核心功能实现

3.1 数据序列化

将上述定义的圆孔标记内的属性通过dwgInFields、dwgOutFields两方法分别设置,使得在圆孔标记自定义实体内部能够写入或读取相关的实体数据。

// 读取自定义实体数据
public dwgInFields(filter: IMcDbDwgFiler): boolean {
this.center = filter.readPoint("center").val;
this.originPt = filter.readPoint("originPt").val;
this.circlePoints = filter.readPoints("circlePoints").val;
this.circleMidPts = filter.readPoints("circleMidPts").val;
this.midPoints = filter.readPoints("midPoints").val;
this.radius = filter.readDouble("radius").val;
this.minPt = filter.readPoint("minPt").val;
this.maxPt = filter.readPoint("maxPt").val;
return true;
}
// 写入自定义实体数据
public dwgOutFields(filter: IMcDbDwgFiler): boolean {
filter.writePoint("center", this.center);
filter.writePoint("originPt", this.originPt);
filter.writePoints("circlePoints", this.circlePoints);
filter.writePoints("circleMidPts", this.circleMidPts);
filter.writePoints("midPoints", this.midPoints);
filter.writeDouble("radius", this.radius);
filter.writePoint("minPt", this.minPt);
filter.writePoint("maxPt", this.maxPt);
return true;
}

3.2 标记数据设置

根据标记在不同象限下的向量方向记录标记内部具体的圆弧曲线首尾两点以及圆弧中点,为后续动态绘制标记实体提供点位。

public setRoundData(center: McGePoint3d, radius: number, quadrant: number = 1, count: number = 1, angle: number = Math.PI / 2) {
this.center = this.originPt = center.clone();
this.radius = radius;
// 根据象限确定向量方向
let vec: McGeVector3d;
switch (quadrant) {
case 1: vec = McGeVector3d.kXAxis.clone(); break;
case 2: vec = McGeVector3d.kYAxis.clone(); break;
case 3: vec = McGeVector3d.kXAxis.clone().negate(); break;
case 4: vec = McGeVector3d.kYAxis.clone().negate(); break;
default: vec = McGeVector3d.kXAxis.clone(); break;
}
// 计算标记点位
const arcPt1 = this.center.clone().addvec(vec.clone().mult(this.radius));
const arcPt2 = this.center.clone().addvec(vec.clone().rotateBy(angle / 2).mult(this.radius));
const arcPt3 = this.center.clone().addvec(vec.clone().rotateBy(angle).mult(this.radius));
// 设置标记点集合
this.circlePoints = [arcPt1, arcPt3];
this.circleMidPts = [arcPt2];
// 计算射线中点
const lMidPt = this.center.clone().addvec(arcPt1.sub(this.center).mult(0.5));
const rMidPt = this.center.clone().addvec(arcPt3.sub(this.center).mult(0.5));
this.midPoints = [lMidPt, rMidPt];
}

3.3 标记夹点设置

在 getGripPoints() 方法内放入作为实体夹点的点位,在moveGripPointsAt()方法内设置每个夹点被移动编辑后需要执行的操作,如移动标注基点后,标注实体内部的所有夹点都跟着移动;移动标注实体圆弧中心点后重新计算新点位下圆弧的大小;移动标记实体半径上的点后会修改标注基点和相关联圆弧的大小等。

// 移动自定义对象的夹点
public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
this.assertWrite();
// 移动所有点
const moveAllPoints = () => {
// 基点移动,所有点都跟着移动
this.originPt.x += dXOffset;
this.originPt.y += dYOffset;
this.originPt.z += dZOffset;
this.center.x += dXOffset;
this.center.y += dYOffset;
this.center.z += dZOffset;
const pointArr = [...this.circleMidPts, ...this.circlePoints, ...this.midPoints]
pointArr.forEach(pt => {
pt.x += dXOffset;
pt.y += dYOffset;
pt.z += dZOffset;
});
}
// 重新计算所有半径上的中点
const resetRMidPts = () => {
this.circlePoints.forEach((pt, i) => {
const rMidPt = this.center.clone().addvec(pt.sub(this.center).mult(0.5));
this.midPoints[i] = rMidPt
})
}
// 重新计算圆弧上的中心点
const resetArcMidPts = () => {
let num = 0;
for (let i = 0; i < this.circlePoints.length; i += 2) {
const arc = new McDbArc();
arc.computeArc(this.circlePoints[i].x, this.circlePoints[i].y, this.circleMidPts[num].x, this.circleMidPts[num].y, this.circlePoints[i + 1].x, this.circlePoints[i + 1].y);
const midPt = arc.getPointAtDist(arc.getLength().val / 2).val;
this.circleMidPts[num] = midPt.clone();
num += 1;
}
}
if (iIndex === 0) {
moveAllPoints()
} else if (iIndex === 1) {
const pt = this.center.clone();
if (pt.distanceTo(this.originPt) < 0.0001) {
moveAllPoints()
} else {
this.center.x += dXOffset;
this.center.y += dYOffset;
this.center.z += dZOffset;
resetRMidPts();
}
} else if (iIndex < this.circlePoints.length + 2) {
// 圆弧两端点移动=》半径中点+圆弧中点跟着移动
const i = iIndex - 2;
const pt = this.circlePoints[i].clone();
pt.x += dXOffset;
pt.y += dYOffset;
pt.z += dZOffset;
this.circlePoints[i] = pt;
// 重新计算圆弧中心点
resetArcMidPts();
// 计算半径上的中心点
const rMidPt = this.center.clone().addvec(pt.sub(this.center).mult(0.5));
this.midPoints[i] = rMidPt
} else if (iIndex < this.circlePoints.length + 2 + this.circleMidPts.length) {
// 圆弧中心点移动=>重新计算圆弧中心点
const i = iIndex - 2 - this.circlePoints.length;
const pt = this.circleMidPts[i].clone();
pt.x += dXOffset;
pt.y += dYOffset;
pt.z += dZOffset;
this.circleMidPts[i] = pt;
// 重新计算圆弧中心点
resetArcMidPts();
} else {
const i = iIndex - 2 - this.circlePoints.length - this.circleMidPts.length;
this.center.x += dXOffset;
this.center.y += dYOffset;
this.center.z += dZOffset;
this.midPoints[i].x += dXOffset;
this.midPoints[i].y += dYOffset;
this.midPoints[i].z += dZOffset;
this.circlePoints[i].x += dXOffset;
this.circlePoints[i].y += dYOffset;
this.circlePoints[i].z += dZOffset;
// 重新计算圆弧中心点
resetArcMidPts();
// 计算半径上的中心点
resetRMidPts()
}
};
// 获取自定义对象的夹点
public getGripPoints(): McGePoint3dArray {
let ret = new McGePoint3dArray();
ret.append(this.originPt);
ret.append(this.center);
this.circlePoints.forEach(pt => {
ret.append(pt);
})
this.circleMidPts.forEach(pt => {
ret.append(pt);
})
this.midPoints.forEach(pt => {
ret.append(pt);
})
return ret;
};

3.4 实体绘制

通过上述步骤中的操作我们可以得到标注内部的圆弧点位,根据这些点位我们就能够计算出圆弧所在的位置并通过创建 McDbHatch 填充类来绘制最终的标注实体。

public worldDraw(draw: MxCADWorldDraw): void {
const allEntityArr: McDbEntity[] = [];
// 绘制标记圆弧和射线
for (let i = 0; i < this.circlePoints.length; i += 2) {
const num = (i + 2) / 2;
const bulges = MxCADUtility.calcBulge(
this.circlePoints[i],
this.circleMidPts[num - 1],
this.circlePoints[i + 1]
).val;
// 创建填充实体
const hatch = new McDbHatch();
hatch.appendLoop(
new McGePoint3dArray([this.center, this.circlePoints[i], this.circlePoints[i + 1]]),
[0, bulges, 0]
);
draw.drawEntity(hatch);
allEntityArr.push(hatch);
}
// 计算包围盒
this.getBox(allEntityArr);
}
// 计算标注实体包围盒大小
private getBox(entityArr: McDbEntity[]) {
const mxcad = MxCpp.getCurrentMxCAD();
let _minPt, _maxPt = null;
entityArr.forEach(entity => {
const { minPt, maxPt, ret } = entity.getBoundingBox();
if (!_minPt) _minPt = minPt.clone();
if (!_maxPt) _maxPt = maxPt.clone();
if (minPt.x < _minPt.x) _minPt.x = minPt.x;
if (minPt.y < _minPt.y) _minPt.y = minPt.y;
if (maxPt.x > _maxPt.x) _maxPt.x = maxPt.x;
if (maxPt.y > _maxPt.y) _maxPt.y = maxPt.y;
});
if (_minPt && _maxPt) {
this.maxPt = _maxPt;
this.minPt = _minPt
}
}
四、使用方法

4.1 初始化注册

// 在插件初始化时注册自定义实体
new McDbTestRoundHoleMark().rxInit();
MxFun.addCommand("Mx_RoundHoleMark", Mx_RoundHoleMark);

4.2 创建圆孔标记

async function Mx_RoundHoleMark() {
// 选择圆形实体
const filter = new MxCADResbuf([DxfCode.kEntityType, "CIRCLE"]);
const ss = new MxCADSelectionSet();
if (!await ss.userSelect(t("请选择需要标记的圆:"), filter)) return;
if (ss.count() == 0) return;
// 为每个选中的圆创建标记
ss.forEach(entityId => {
const circle = entityId.getMcDbEntity() as McDbCircle;
const roundHoleMark = new McDbTestRoundHoleMark();
// 设置标记数据
roundHoleMark.setRoundData(circle.center, circle.radius, [1, 1, Math.PI / 2]);
roundHoleMark.trueColor = new McCmColor(0, 255, 0);
// 绘制标记
mxcad.drawEntity(roundHoleMark);
}
五、最佳实践

圆孔标注实体具有以下特性:

1. 支持多象限标记:可在四个象限中选择标记方向

2. 可调节标记角度:通过angle参数控制标记的张开角度

3. 支持多重标记:可同时创建多个对称的标记

4. 动态编辑:支持通过夹点编辑修改标记形状和位置

5. 自动计算包围盒:用于空间定位和选择操作

根据 McDbTestRoundHoleMark 圆孔标注自定实体,我们可以结合MxCAD项目实现一个完整的圆孔标注功能,效果如下:

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
一个都没跑出来!NBA选秀,中国篮球全军覆没,我们到底输在哪

一个都没跑出来!NBA选秀,中国篮球全军覆没,我们到底输在哪

涵有话说
2026-06-28 10:36:38
“她就是个累赘”,怀胎十月约见网友,用力过猛临盆扼杀新生女儿

“她就是个累赘”,怀胎十月约见网友,用力过猛临盆扼杀新生女儿

易玄
2026-06-26 11:13:44
吃完嫩的吃老的,山西儿媳出轨公公10年,亲自给丈夫生下一个妹妹

吃完嫩的吃老的,山西儿媳出轨公公10年,亲自给丈夫生下一个妹妹

莫地方
2026-06-02 00:10:26
曾讽中国仅马宁去世界杯!韩媒崩溃:韩国出局在中国登上热搜第一

曾讽中国仅马宁去世界杯!韩媒崩溃:韩国出局在中国登上热搜第一

风过乡
2026-06-28 10:50:13
9亿执行令才过4年,董卿打出一张“好牌”,原来密春雷还有退路

9亿执行令才过4年,董卿打出一张“好牌”,原来密春雷还有退路

冰语历史
2026-06-27 23:20:06
特朗普突然翻脸,中东开打了,巴铁接到电话,中方援助将送抵伊朗

特朗普突然翻脸,中东开打了,巴铁接到电话,中方援助将送抵伊朗

影孖看世界
2026-06-27 23:18:14
忙完主持疯狂合影!张凌赫晒出白玉兰九宫格第一张就勾起无数回忆

忙完主持疯狂合影!张凌赫晒出白玉兰九宫格第一张就勾起无数回忆

TVB的四小花
2026-06-27 15:14:42
“85花”大洗牌:2人出局,杨幂跌出前三,赵丽颖换桌,榜首易主

“85花”大洗牌:2人出局,杨幂跌出前三,赵丽颖换桌,榜首易主

冰语历史
2026-06-28 11:50:19
给所有老年人一个忠告:永远不要在熟人面前和老年群里说这两句话

给所有老年人一个忠告:永远不要在熟人面前和老年群里说这两句话

心理观察局
2026-06-04 07:19:04
2名日本人偷运稀土被抓,中方打出第二枪,彻底堵死日本全部后路

2名日本人偷运稀土被抓,中方打出第二枪,彻底堵死日本全部后路

孟彦说
2026-06-28 13:07:05
娃半夜把金锁嚼碎吞了,妈妈崩溃送医,医生:不用治,回家等吧!

娃半夜把金锁嚼碎吞了,妈妈崩溃送医,医生:不用治,回家等吧!

菁妈育儿
2026-06-25 17:49:57
北大数学天才柳智宇,放弃麻省奖学金当和尚,还俗后与女修者结婚

北大数学天才柳智宇,放弃麻省奖学金当和尚,还俗后与女修者结婚

从零到一研究所
2026-06-26 16:48:03
特朗普爆料,有一个强国可能想出兵帮伊朗,战斗力不在以色列之下

特朗普爆料,有一个强国可能想出兵帮伊朗,战斗力不在以色列之下

国际阿尝
2026-06-28 11:18:00
163的王祖蓝和175的老婆换裤子穿,一个成人行拖把,一个成7分裤

163的王祖蓝和175的老婆换裤子穿,一个成人行拖把,一个成7分裤

木子爱娱乐大号
2026-06-22 10:21:23
中国制裁不是闹着玩的!特奥多罗全家被拉黑,菲律宾政客看傻了!

中国制裁不是闹着玩的!特奥多罗全家被拉黑,菲律宾政客看傻了!

照亮你的前行之路
2026-06-28 04:39:05
日媒:都认为中国发展新能源是因为没有发动机技术,大错特错

日媒:都认为中国发展新能源是因为没有发动机技术,大错特错

逍遥漠
2026-06-26 15:06:43
不可思议5-0使韩国世界杯上上签成致命亡命符

不可思议5-0使韩国世界杯上上签成致命亡命符

自己撑起一片天
2026-06-27 19:47:47
英格兰克罗地亚,贝林厄姆莫德里奇:救世主!

英格兰克罗地亚,贝林厄姆莫德里奇:救世主!

张佳玮写字的地方
2026-06-28 07:33:20
李小孩的“玻璃鸡蛋”最薄处仅0.1毫米,在隋朝做什么用?

李小孩的“玻璃鸡蛋”最薄处仅0.1毫米,在隋朝做什么用?

收藏大视界
2026-06-27 17:16:50
学费最贵的十所大学来了!最高约100万,你会报考吗?

学费最贵的十所大学来了!最高约100万,你会报考吗?

史海流年号
2026-06-22 17:11:29
2026-06-28 13:43:00
CAD梦想画图
CAD梦想画图
是一款极速轻量级的CAD软件
610文章数 123关注度
往期回顾 全部

头条要闻

三队出线世界杯32强席位正式落定 伊朗在最后一刻出局

头条要闻

三队出线世界杯32强席位正式落定 伊朗在最后一刻出局

体育要闻

世界杯最火门将,站到了阿根廷和梅西面前

娱乐要闻

白玉兰奖落幕,唯她被骂惨

财经要闻

两只股票撑起的韩国股市,半年熔断 33 次

科技要闻

DeepSeek最新论文:如何让大模型跑得更快

汽车要闻

蔚来ES大五座体验 全场景行李舱让你带着生活出发

态度原创

亲子
数码
健康
本地
公开课

亲子要闻

小卡蜜拉偷走了小格力乔的睡觉时间

数码要闻

从RGB-Mini LED到全球首发RGBX!海信引领下一代显示全新色彩赛道

“无糖汤圆”是否隐藏着健康陷阱?

本地新闻

世界杯球迷节:比球赛更好玩的派对

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版