pline-timing
本文回答(重要陷阱):PLINE / SPLINE 这类交互式命令"边输入边构建",事件触发时机分阶段:用户点第 2 个点 → 触发
EntityAdded(只 2 个点);后续点 3, 4, 5… → 触发EntityModified;按回车结束 → 触发CommandEnded(完整点数)。在EntityAdded里读bulgePoints.items拿不到全部数据。
一、事件时序图
用户输入 触发的事件
──────────────────────────────────────────────
点击第 1 个点 (无事件,只在内存)
点击第 2 个点 EntityAdded(实体 ID 诞生,bulgePoints = 2 个点)
点击第 3 个点 EntityModified(bulgePoints = 3 个点)
点击第 4 个点 EntityModified(bulgePoints = 4 个点)
...
回车结束 CommandEnded(最终状态)
ESC 取消 CommandEnded(同样只发 Ended;CommandCancelled 不派发)
(已过第 2 点则保留已绘制部分,否则完全无实体)
MCP 参考:vjcad/example/event/06plinepoints.js、vjcad/doc/event/event-usage.md。
二、错与对
// 错:在 EntityAdded 拿不到全部点
Engine.eventManager.on(CadEvents.EntityAdded, (args) => {
if (args.entity.type === 'PLINE') {
console.log(args.entity.bulgePoints.items.length); // 输出: 2(不完整)
}
});
// 对(方案 A):在 CommandEnded 拿全部
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
if (args.commandName === 'PLINE') {
const plines = Engine.getEntities(e => e.type === 'PLINE');
const last = plines[plines.length - 1];
console.log(last.bulgePoints.items.length); // 输出: 完整点数
}
});
// 对(方案 B):实时跟踪
Engine.eventManager.on(CadEvents.EntityModified, (args) => {
if (args.entity.type === 'PLINE') {
console.log('当前点数:', args.entity.bulgePoints.items.length);
}
});
MCP 参考:vjcad/doc/event/event-usage.md、vjcad/example/event/06plinepoints.js。
三、读点位的两种数据形态对照
| 属性 | 实体对象 | toDb() 输出 |
|---|---|---|
| 点位集合 | entity.bulgePoints.items |
dbPline.dbBulgePoints.pts |
| 单个点坐标 | bp.point2d.x / .y |
pts[i][0] / pts[i][1] |
| 凸度 | bp.bulge |
bulges?[i](全 0 时省略) |
// 实体对象
const pl = Engine.getEntities(e => e.type === 'PLINE').slice(-1)[0];
pl.bulgePoints.items.forEach((bp, i) => {
console.log(`P${i}:`, bp.point2d.x, bp.point2d.y, 'bulge=', bp.bulge);
});
// toDb 输出
const dbDoc = Engine.currentDoc.toDb();
// dbBlocks.items 是数组(DbBlock[]),按 name 找模型空间块
const model = dbDoc.dbBlocks.items.find(b => b.name === '*Model');
const dbPl = model.items.find(it => it.type === 'PLINE');
const pts = dbPl.dbBulgePoints.pts; // [[x,y], ...]
const bulges = dbPl.dbBulgePoints.bulges; // [b1, b2, ...] | undefined
pts.forEach((pt, i) => {
const b = bulges ? bulges[i] : 0;
console.log(`pt${i}: [${pt[0]}, ${pt[1]}] bulge=${b}`);
});
// 从 DB 数据还原
const np = new PolylineEnt(new BulgePoints());
np.fromDb(dbPl);
MCP 参考:vjcad/doc/event/event-usage.md、vjcad/example/event/06plinepoints.js。
四、追踪当前 active 实体
let activePline = null;
Engine.eventManager.on(CadEvents.CommandStarted, (args) => {
if (args.commandName === 'PLINE') activePline = null;
});
Engine.eventManager.on(CadEvents.EntityAdded, (args) => {
if (args.entity.type === 'PLINE') activePline = args.entity;
});
Engine.eventManager.on(CadEvents.EntityModified, (args) => {
if (args.entity === activePline) {
console.log('当前点数:', activePline.bulgePoints.items.length);
}
});
// 回车完成与 ESC 取消都只触发 CommandEnded(CommandCancelled 不派发),在这里统一分支
Engine.eventManager.on(CadEvents.CommandEnded, (args) => {
if (args.commandName === 'PLINE') {
if (activePline) {
console.log('结束,保留实体点数:', activePline.bulgePoints.items.length);
} else {
console.log('结束,未创建实体(第 2 点前就退出)');
}
}
activePline = null;
});
MCP 参考:vjcad/example/event/06plinepoints.js。
五、其他可能受同种时序影响的命令
PLINE 这种"边交互边构建实体"的命令同类型有:
SPLINE(样条曲线)MTEXT(多行文字)- 部分
DIMENSION*标注命令 - 自定义命令中通过
getPoint(callback)实时预览的实体
凡是这类命令,都按 CommandEnded 兜底比较可靠。
反例
- 在
EntityAdded弹 toast "已添加 PLINE,点数 N":永远显示 2。 EntityModified没过滤 active 实体,把页面上所有 PLINE 的修改都误认为是"当前命令的"。- 用
entity.id做去重关键:可以,但EntityAdded时拿到的id与CommandEnded时是同一个 id,请确保不要在EntityAdded里做"我的版本号 = 0"这样的状态依赖。
参考(官方文档 MCP)
- 文档:
vjcad/doc/event/event-usage.md - 示例:
vjcad/example/event/06plinepoints.js