
前言在 Web CAD 的开发领域图纸的展示、视图的平移与缩放这些功能构建了 CAD 系统的“只读”基础。然而 CAD 的“设计”与“修改”需要掌握图形的选择机制、几何变换原理以及夹点交互技术。基于 MxCAD 强大的底层 API我们将深入探讨如何通过代码精准控制图形实体实现从简单的移动、旋转到复杂的批量筛选与变换。这不仅是功能的堆砌更是对 CAD 图形数据底层逻辑的深度理解。一、 精准定位构建图形选择在进行任何编辑操作之前我们必须先确定“操作谁”。MxCAD 提供了极其灵活的MxCADSelectionSet选择集机制配合MxCADUtilityClass绘图工具类能够实现从简单的点选到复杂的属性过滤。1. 开启交互的大门环境配置在开始编码之前我们需要在项目初始化阶段“唤醒” CAD 的交互能力。这一步至关重要它决定了用户能否通过鼠标与图形进行交互。通过MxFun.setIniset配置我们主要开启三个核心开关EnableGripEdit开启夹点编辑系统变量。这是 CAD 特有的交互方式开启后选中的图形会显示蓝色的小方块夹点用户可以直接拖拽修改。multipleSelect启动多选功能。允许用户通过框选或累加选择来操作多个实体。IntelliSelectType智能选择类型。设置为 2 表示支持连续多选极大地提升了批量操作的效率。import { MxFun } from mxdraw; // 开启夹点编辑系统变量 MxFun.setIniset({ /** *启动夹点编辑 *true,1表示启用0,fase表示禁用2表示只显示夹点但不响应夹点编辑. */ EnableGripEdit: true, /** 启动多选,框选功能,默认值是false */ multipleSelect: true, /** * 开启多选 * 选择方式控制 1:多选暂不支持连续多选2:多选并支持连续多选,默认值为1 */ IntelliSelectType: 2 });此外mxcad对象中也设置了相关的选择属性配置项目用户也可以直接在mxcad对象中开启选择设置import { createMxCad } from mxcad; createMxCad({ //... enableIntelliSelect:true,// 是否启用选择功能默认是使用 multipleSelect: true, // 开启多选 //... })2. 选择的艺术从交互到过滤在实际开发中构建选择集通常有两种截然不同的路径交互式选择这是最直观的方式。根据用户的需求我们可以引导用户进行“点选”精准打击、“框选”区域覆盖、“累加选择”按住 Shift 逐个添加或“全选”。这种方式依赖于用户的鼠标操作MxCAD 内部已经封装了完善的逻辑开发者只需调用相应的命令接口即可。选择方式的实现详情请参考mxcad开发文档中的 选择图形 。构建过滤器高级应用当业务逻辑需要自动筛选特定对象时例如自动选中图纸中所有的圆交互式选择就显得力不从心了。此时我们需要祭出MxCADResbuf。通过构建过滤器我们可以根据实体的类型如McDbText、McDbMText、图层、颜色或扩展数据进行精确筛选。这就像在数据库中执行 SQL 查询一样让代码自动帮你找到目标是实现自动化批量处理的基石。import { MxCADResbuf, MxCpp, MxCADSelectionSet } from mxcad; const mxcad MxCpp.getCurrentMxCAD(); // 创建过滤器 const filter new MxCADResbuf(); filter.AddMcDbEntityTypes(TEXT,MTEXT); // 设置选择集筛选文本对象 let ss new MxCADSelectionSet(); ss.allSelect(filter); ss.forEach((id) { mxcad.addCurrentSelect(id) }); mxcad.updateDisplay();二、 几何变换从直观操作到数学本质一旦目标实体被锁定我们便进入了编辑的核心环节——几何变换。在 CAD 的底层世界里所有的移动、旋转和缩放本质上都是对实体顶点坐标进行的数学运算。1. 核心引擎变换矩阵在 MxCAD 的底层逻辑中一切皆矩阵。所有的复杂变换在数学上都统一为矩阵乘法。通过构建一个McGeMatrix3d变换矩阵我们可以描述任意的空间变换。这种设计的精妙之处在于效率。你可以将多次变换例如先旋转 45 度再移动 100 单位最后缩小一半合并为一个单一的矩阵。通过entity.transformBy(matrix)接口一次性应用实体的坐标将瞬间完成所有计算避免了多次循环计算顶点的性能损耗。2. 常见操作的两种境界虽然底层是矩阵但为了开发的便捷性MxCAD 为开发者提供了“快捷方法”和“矩阵变换”两种实现层级。移动直观上我们定义一个位移向量将实体所有点的坐标加上这个向量。快捷方式是move(basePoint, toPoint)直接定义起点和终点底层则是通过McGeMatrix3d.setToTranslation(vector)生成平移矩阵。import { McDbCircle, McGeVector3d, MxCpp, McGePoint3d, McGeMatrix3d } from mxcad; const mxcad MxCpp.getCurrentMxCAD(); const center new McGePoint3d(0,0,0) const circle new McDbCircle(center.x,center.y,center.z,10); // 移动前 mxcad.drawEntity(circle); // 方式一快捷调用平移函数move const movePt new McGeVector3d(50,50,0); circle.move(center,movePt); // 方式二调用平移矩阵 const matrix new McGeMatrix3d(); const vec new McGeVector3d(50,50,0) matrix.setToTranslation(vec); circle.transformBy(matrix); // 移动后 mxcad.drawEntity(circle); mxcad.updateDisplay();旋转旋转需要三个关键要素旋转基点、旋转轴和旋转角度。实体上的点将绕着指定轴旋转指定的弧度。快捷方式rotate(basePoint, dRotationAngle)让你无需关心复杂的三角函数计算而矩阵方式McGeMatrix3d.setToRotation(angle, axis, center)则赋予了你对空间旋转的绝对控制权。import { McDb, McGeVector3d, MxCpp, McGePoint3d, McGeMatrix3d } from mxcad; const mxcad MxCpp.getCurrentMxCAD(); const basePt new McGePoint3d(0,0,0) // 旋转前 const id mxcad.drawText(0,0,test,10,0, McDb.TextHorzMode.kTextLeft, McDb.TextVertMode.kTextBottom); const text id.getMcDbEntity(); const angle Math.PI/4; // 方式一快捷调用旋转函数rotate text.rotate(basePt,angle); // 方式二调用旋转矩阵 const matrix new McGeMatrix3d(); matrix.setToRotation(angle,McGeVector3d.kZAxis,basePt); text.transformBy(matrix); mxcad.updateDisplay();缩放缩放是相对于基点进行的。新坐标 基点 (旧坐标 - 基点) × 比例因子。无论是使用scaleEntity(basePoint, dScaleFactor)的便捷接口还是通过矩阵McGeMatrix3d.setToScaling(scaleAll, center)核心都在于基点的选择——它决定了图形是“原地缩小”还是“飞出屏幕”。import { McDb, McCmColor, MxCpp, McGePoint3d, McGeMatrix3d } from mxcad; const mxcad MxCpp.getCurrentMxCAD(); const basePt new McGePoint3d(0,0,0) // 旋转前 const id mxcad.drawText(0,0,test,10,0, McDb.TextHorzMode.kTextLeft, McDb.TextVertMode.kTextBottom); const text id.getMcDbEntity(); // 方式一快捷调用缩放函数scaleEntity text.scaleEntity(basePt,0.5); // 方式二调用缩放矩阵 const matrix new McGeMatrix3d(); matrix.setToScaling(0.5,basePt); text.transformBy(matrix); text.trueColor new McCmColor(255,0,0) mxcad.updateDisplay();三、综合实战带动态预览的批量文本移动为了串联选择、过滤、变换及交互体验我们实现一个核心场景批量移动全图文字并支持拖拽预览。本案例引入MxCADUiPrPoint的setUserDraw回调实现“所见即所得”的交互效果。核心逻辑流程精准筛选利用MxCADResbuf构建针对TEXT和MTEXT的过滤器通过MxCADSelectionSet获取全图目标实体。基点锁定使用MxCADUiPrPoint获取用户指定的移动基点。动态预览在鼠标移动过程中通过setUserDraw实时克隆并绘制文字的“幻影”提供视觉反馈。执行变换用户确认目标点后对原始实体应用真实的move变换并刷新视图。代码实现import { MxCADSelectionSet, MxCADResbuf, MxCADUiPrPoint, McDbEntity, MxCpp, McDbLine } from mxcad import { MxFun } from mxdraw; async function Mx_moveAllText() { const mxcad MxCpp.getCurrentMxCAD(); // 1. 构建过滤器仅筛选 TEXT 和 MTEXT const filter new MxCADResbuf(); filter.AddMcDbEntityTypes(TEXT,MTEXT); // 2. 获取选择集并缓存实体 const ss new MxCADSelectionSet(); ss.allSelect(filter); const entities: McDbEntity[] []; ss.forEach(id { mxcad.addCurrentSelect(id); // 高亮显示 const text id.getMcDbEntity(); if (text) entities.push(text); }) // 3. 交互获取基点 const getPoint new MxCADUiPrPoint(); getPoint.setMessage(请选择移动基点); const basePt await getPoint.go(); if (!basePt) return; // 4. 核心动态预览 (UserDraw) getPoint.setMessage(请选择移动终点); getPoint.setUserDraw((pt, pw) { // 绘制辅助线 pw.drawMcDbEntity(new McDbLine(basePt, pt)); // 克隆实体并绘制“幻影” entities.forEach(text { const _text text.clone() as McDbEntity; _text.move(basePt, pt); // 仅移动克隆体 pw.drawMcDbEntity(_text); }) }); // 5. 确认目标点并执行真实变换 const movePt await getPoint.go(); if (!movePt) return; entities.forEach(text { text.move(basePt, movePt); }); mxcad.clearMxCurrentSelect(); mxcad.updateDisplay(); } MxFun.addCommand(Mx_moveAllText, Mx_moveAllText);四、 总结与进阶思考通过本文的深度解析我们不仅掌握了 MxCAD 图形编辑的具体技法更理解了其背后的数学原理。选择机制是入口。利用MxCADSelectionSet和过滤器我们实现了从“人找图”到“代码找图”的跨越特别是构建过滤器的能力是实现自动化脚本的关键。变换原理是核心。深入理解基于矩阵的几何变换让我们明白快捷方法背后的逻辑。虽然快捷方法如move、rotate在日常开发中足够使用但在处理复杂的复合变换时直接操作矩阵才是效率的最高境界。夹点交互是用户体验的灵魂。解析 CAD 特有的夹点编辑流程即“获取-拖拽-更新”的闭环能让我们的应用拥有原生 CAD 般流畅的交互体验。