打断
下面我们将介绍如何利用 mxcad 插件实现在CAD图纸中的曲线打断功能。该功能中用户可以通过打断点将一条完整的曲线切割成两部分或多部分,这些切割出来的部分又将变成独立的曲线。其中,mxcad 中的曲线类实体包括:McDbPolyline 多段线、McDbArc 圆弧、McDbCircle 圆、McDbEllipse 椭圆/弧、McDbLine 直线。打断功能能够帮助用户对图纸中的目标曲线进行分段测量、删除、调整曲线长度等高效操作。
功能实现
- 选中目标曲线
我们可以通过 MxCADResbuf 设置过滤器,再调用 MxCADUiPrEntity 获取用户选择的实体,过滤器会使用户只能选择 McDbCurve 曲线类的实体方便我们后续的打断操作。为了方便我们更直观的观察到选中的实体是哪一个,我们可以将选中的实体通过 McDbCurve.highlight() 方法来设置为高亮显示。
ts
// 选中需要打断的曲线
const getCurve = new MxCADUiPrEntity();
getCurve.setMessage('请选择一条需要打断的曲线');
// 设置过滤器
const filter = new MxCADResbuf([DxfCode.kEntityType, "LWPOLYLINE,LINE,ARC,CIRCLE,ELLIPSE"]);
getCurve.setFilter(filter);
const curveId = await getCurve.go();
if(!curveId.id) return;
const curve = curveId.getMcDbEntity() as McDbCurve;
// 设置曲线高亮
curve.highlight(true);
- 设置打断点
我们可以通过 MxCADUiPrPoint 在上述步骤中选中的目标曲线上进行取点操作,这些被选中的点即作为目标曲线的断点。在绘制过程中,我们可以以断点为圆心动态绘制一个圆以此来方便我们观察断点的具体位置。
ts
// 选取曲线的打断点
const getBreakPoint = new MxCADUiPrPoint();
getBreakPoint.setMessage('请在曲线上选取打断点');
const pointsArr:McGePoint3d[] = [];
const radius = MxFun.screenCoordLong2Doc(5)
while(true){
// 动态绘制打断点
getBreakPoint.setUserDraw((pt,pw)=>{
if(pointsArr.length > 0){
pointsArr.forEach(pt=>{
const circle = new McDbCircle();
circle.center = pt;
circle.radius = radius;
pw.drawMcDbEntity(circle)
})
};
pw.drawCircle(new THREE.Vector3(pt.x,pt.y), radius)
})
const point = await getBreakPoint.go();
if(!point) break;
pointsArr.push(point);
}
- 打断曲线
完成上述步骤后,我们将目标曲线根据这些断点调用 McDbCurve.splitCurves() 方法进行曲线切割,然后我们就能够获取到打断后的曲线。
ts
// 打断曲线
const mxcad = MxCpp.getCurrentMxCAD();
if(pointsArr.length === 0) return;
curve.splitCurves(pointsArr).forEach(obj=>{
mxcad.drawEntity(obj as McDbCurve)
});
curve.highlight(false);
curveId.erase();
mxcad.updateDisplay();
功能扩展
- 实现交点打断功能
我们可以调用 McDbCurve.IntersectWith() 方法获取到曲线与曲线之间的交点,并以这些交点作为曲线的打断点,对曲线进行打断。在下面的示例中,我们将曲线间的交点作为断点去对曲线进行切割打断,并绘制出一定长度的断口来方便观察。用户可根据自己的实际需求做相应调整。
ts
// 交点打断
async function Mx_IntersectBreak() {
// 选择参考曲线
let eventObj = new MxCADUiPrEntity();
eventObj.setMessage("请选择参考曲线");
let eventObj_id = await eventObj.go();
let event = await eventObj_id.getMcDbEntity()//获取实例对象
if (event === null) return;
const mxcad = MxCpp.App.getCurrentMxCAD();
let curve = event.clone();
let filter = new MxCADResbuf();
filter.AddMcDbEntityTypes("CIRCLE,ARC,LINE,LWPOLYLINE,ELLIPSE");
let aryId = await MxCADUtility.userSelect("选择打断对象", filter);//选中对象的id
if (aryId.length == 0) return;
let dTol = mxcad.mxdraw.viewCoordLong2Cad(0.5);// 设置精度值
aryId.forEach(async (id) => {
if (id.id !== eventObj_id.id) {
let breakEvent: McDbCurve = (await id.getMcDbEntity()) as McDbCurve;
let breakArr = breakEvent.IntersectWith(curve as McDbEntity, McDb.Intersect.kOnBothOperands);//与实体相交的点集合
if (breakArr.length() != 0) {
//有交点的对象
let arr: McGePoint3d[] = [];//交点数组
breakArr.forEach((item: McGePoint3d) => {
arr.push(item)
})
let breakPoint: McGePoint3d[] = [];
arr.forEach(pt => {
let closePoint = breakEvent.getClosestPointTo(pt, false);//曲线上离鼠标位置最近的点
if (!closePoint.ret) return;
let vec = breakEvent.getFirstDeriv(closePoint.val);//断点所在位置的向量
if (!vec.ret) return;
vec.val.normalize().mult(MxFun.viewCoordLong2Cad(10));//断开的距离
let pt1 = closePoint.val.clone();
pt1.addvec(vec.val);
let pt2 = closePoint.val.clone();
pt2.subvec(vec.val);
// 如果是曲线端点相交,则需要特殊处理
const startPt = breakEvent.getPointAtDist(0).val;
const endPt = breakEvent.getPointAtDist(breakEvent.getLength().val).val;
if (startPt.distanceTo(closePoint.val) < dTol || endPt.distanceTo(closePoint.val) < dTol) {
const num = breakEvent.getDistAtPoint(pt1);
breakPoint.push(closePoint.val)
num.ret ? breakPoint.push(pt1) : breakPoint.push(pt2);
} else {
breakPoint.push(pt1);
breakPoint.push(pt2);
}
});
let breakcurve = breakEvent.splitCurves(breakPoint);
if (breakcurve.empty()) {
breakEvent.highlight(false);
return;
}
breakcurve.forEach((obj: McDbObject, index: number) => {
if (index % 2 == 0) mxcad.drawEntity(obj as McDbEntity);
});
breakEvent.erase()
}
}
})
}
功能实践
实践效果如下:
- 打断
- 点击打断按钮,执行打断方法
- 点击左键在图纸中选中目标曲线
- 再次点击左键在目标曲线中选中打断点(可循环取点),点击右键结束取点
- 成功打断目标曲线
- 在图纸中再次选中目标曲线,目标曲线已被打断为多条曲线
- 交点打断
- 点击交点打断按钮,执行交点打断方法
- 点击左键在图纸中选中参考曲线(即不会被打断的曲线)
- 选中参考曲线后,再次点击左键选取需要被打断的曲线(可连续选择多条曲线)
- 点击右键结束选择并根据曲线见的交点成功打断曲线