唯杰地图 logo唯杰地图
VJMAP
EN

pline-timing

vjcad/references/event/pline-timing.md 5.3 KB140 行
原文

本文回答(重要陷阱):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