在 Web CAD 的开发领域,图纸的展示、视图的平移与缩放,这些功能构建了 CAD 系统的“只读”基础。然而 CAD 的“设计”与“修改”需要掌握图形的选择机制、几何变换原理以及夹点交互技术。
基于 MxCAD 强大的底层 API,我们将深入探讨如何通过代码精准控制图形实体,实现从简单的移动、旋转到复杂的批量筛选与变换。这不仅是功能的堆砌,更是对 CAD 图形数据底层逻辑的深度理解。
在进行任何编辑操作之前,我们必须先确定“操作谁”。MxCAD 提供了极其灵活的
MxCADSelectionSet
(选择集)机制,配合
MxCADUtilityClass
绘图工具类,能够实现从简单的点选到复杂的属性过滤。
在开始编码之前,我们需要在项目初始化阶段“唤醒” 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, // 开启多选
//...
})
在实际开发中,构建选择集通常有两种截然不同的路径:
交互式选择 :这是最直观的方式。根据用户的需求,我们可以引导用户进行“点选”(精准打击)、“框选”(区域覆盖)、“累加选择”(按住 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 的底层世界里,所有的移动、旋转和缩放,本质上都是对实体顶点坐标进行的数学运算。
在 MxCAD 的底层逻辑中,一切皆矩阵。所有的复杂变换在数学上都统一为
矩阵乘法
。通过构建一个
McGeMatrix3d
变换矩阵,我们可以描述任意的空间变换。
这种设计的精妙之处在于
效率
。你可以将多次变换(例如先旋转 45 度,再移动 100 单位,最后缩小一半)合并为一个单一的矩阵。通过
entity.transformBy(matrix)
接口一次性应用,实体的坐标将瞬间完成所有计算,避免了多次循环计算顶点的性能损耗。
虽然底层是矩阵,但为了开发的便捷性,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
)在日常开发中足够使用,但在处理复杂的复合变换时,直接操作矩阵才是效率的最高境界。
夹点交互
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70041755/viewspace-3180137/ ,如需转载,请注明出处,否则将追究法律责任。