唯杰地图 logo唯杰地图
VJMAP
EN

反应器系统

vjcad/references/quickref/reactor.md 6.6 KB253 行
原文

反应器用于实时响应实体变化并自动执行操作。

概念

反应器是一种事件驱动的机制,可以:

  • 监听实体的添加、修改、删除
  • 自动响应变化并执行关联操作
  • 实现实体间的依赖关系(如关联标注)

自定义反应器

通过事件监听实现自定义反应逻辑。

const { CadEventManager, CadEvents, Engine, CircleEnt, PolylineEnt } = vjcad;

class CircleBoundingBoxReactor {
    constructor() {
        this.enabled = true;
        this.boundingLines = new Map();  // 存储关联数据
    }
    
    install() {
        // 监听实体添加
        Engine.eventManager.on(CadEvents.EntityAdded, (args) => {
            if (this.enabled && args.entity.type === 'CIRCLE') {
                this.createBoundingBox(args.entity);
            }
        });
        
        // 监听实体修改
        Engine.eventManager.on(CadEvents.EntityModified, (args) => {
            if (this.enabled && args.entity.type === 'CIRCLE') {
                this.updateBoundingBox(args.entity);
            }
        });
        
        // 监听实体删除
        Engine.eventManager.on(CadEvents.EntitiesErased, (args) => {
            args.entities.forEach(entity => {
                if (entity.type === 'CIRCLE') {
                    this.removeBoundingBox(entity);
                }
            });
        });
    }
    
    createBoundingBox(circle) {
        const r = circle.radius;
        const cx = circle.center.x;
        const cy = circle.center.y;
        
        const rect = new PolylineEnt();
        rect.setPoints([
            [cx - r, cy - r],
            [cx + r, cy - r],
            [cx + r, cy + r],
            [cx - r, cy + r]
        ]);
        rect.isClosed = true;
        rect.setDefaults();
        rect.color = 3;
        
        Engine.addEntities(rect);
        this.boundingLines.set(circle.id, rect);
        Engine.regen();
    }
    
    updateBoundingBox(circle) {
        const rect = this.boundingLines.get(circle.id);
        if (!rect) return;
        
        const r = circle.radius;
        const cx = circle.center.x;
        const cy = circle.center.y;
        
        rect.setPoints([
            [cx - r, cy - r],
            [cx + r, cy - r],
            [cx + r, cy + r],
            [cx - r, cy + r]
        ]);
        Engine.regen();
    }
    
    removeBoundingBox(circle) {
        const rect = this.boundingLines.get(circle.id);
        if (rect) {
            Engine.eraseEntities(rect);
            this.boundingLines.delete(circle.id);
            Engine.regen();
        }
    }
    
    toggle() {
        this.enabled = !this.enabled;
        message.info(`反应器已${this.enabled ? '启用' : '禁用'}`);
    }
}

// 安装反应器
const reactor = new CircleBoundingBoxReactor();
reactor.install();

关键事件

事件 说明
CadEvents.EntityAdded 实体添加后触发
CadEvents.EntityModified 实体修改后触发
CadEvents.EntitiesErased 实体删除后触发(批量)

关联标注反应器

标注实体内置反应器机制,通过 setSourceEntities() 建立关联,源实体移动时标注自动更新。

const { LinearDimensionEnt, LineEnt, Point2D, Engine } = vjcad;

// 创建直线
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();
Engine.addEntities(line);

// 创建标注
const dim = new LinearDimensionEnt(
    new Point2D(0, 0),
    new Point2D(100, 0),
    new Point2D(50, 20),
    0
);
dim.setDefaults();
Engine.addEntities(dim);

// 建立关联(必须在 addEntities 之后)
dim.setSourceEntities(
    line.id, -1,    // 起点关联实体 + 段索引:LINE 忽略段索引(填 -1 即可);PLINE 须填 ≥0 的直线段索引(-1/弧段取不到点,标注不跟随)
    line.id, -1,    // 终点关联实体
    'start',        // 起点端点类型
    'end'           // 终点端点类型
);

// 检查关联状态
console.log("isAssociative:", dim.isAssociative);

// 移动直线时,标注会自动更新
line.move([0, 0], [50, 0]);
Engine.regen();

端点类型

类型 说明
'start' 起点
'end' 终点
'center' ⚠️ 类型里有但未实现(Linear/Aligned 关联回退为起点)
'midpoint' 中点

精确定位

使用 parameterT 指定在线段上的比例位置(0~1):

dim.setSourceEntities(
    line.id, -1,
    line.id, -1,
    undefined,       // 不使用 pointType
    undefined,
    0.25,            // startParameterT: 1/4 处
    0.75             // endParameterT: 3/4 处
);

支持的标注类型

上面的 setSourceEntities(...) 签名用于:

  • LinearDimensionEnt - 线性标注
  • AlignedDimensionEnt - 对齐标注

其他可关联的实体(参数各不相同,见 types.d.ts):

  • AngleDimensionEnt / TwoLineAngularDimensionEnt - setSourceEntities(line1Id, line1SegIdx, line2Id, line2SegIdx)
  • ThreePointAngularDimensionEnt - setSourceEntities(entity1Id, seg1, point1Type, entity2Id, seg2, point2Type, centerEntityId?, ...)
  • RadialDimensionEnt / DiametricDimensionEnt - setSourceEntity(entityId, pointAngle?)
  • ArcDimensionEnt - setSourceEntity(entityId)
  • OrdinateDimensionEnt - setSourceEntity(entityId, pointType?)
  • MLeaderEnt - setArrowSourceEntity(leaderLineIndex, entityId, segmentIndex?, pointType?, ...)(箭头跟随实体)

反应器生命周期管理

启用/禁用控制

class MyReactor {
    constructor() {
        this.enabled = true;
    }
    
    toggle() {
        this.enabled = !this.enabled;
    }
}

数据管理

使用 Map 存储关联数据:

class MyReactor {
    constructor() {
        this.relations = new Map();  // entityId -> relatedEntity
    }
    
    // 创建关联
    onCreate(entity) {
        const related = this.createRelated(entity);
        this.relations.set(entity.id, related);
    }
    
    // 更新关联
    onModify(entity) {
        const related = this.relations.get(entity.id);
        if (related) {
            this.updateRelated(entity, related);
        }
    }
    
    // 删除关联
    onDelete(entity) {
        const related = this.relations.get(entity.id);
        if (related) {
            Engine.eraseEntities(related);
            this.relations.delete(entity.id);
        }
    }
}

注意事项

  1. 关联标注必须在 addEntities 之后设置
  2. 线段索引 -1 表示整条线
  3. 使用 parameterT 时,pointType 应设为 undefined
  4. 关联后源实体变化时标注自动更新,无需手动调用