唯杰地图 logo唯杰地图
VJMAP
EN

编辑、选择与撤销

vjcad/references/quickref/edit-selection.md 10.7 KB483 行
原文

实体编辑、选择集操作、撤销系统。

实体变换

移动

const { LineEnt, Point2D, Engine } = vjcad;

const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();
Engine.addEntities(line);

// 移动实体:从 from 点移动到 to 点
line.move([0, 0], [50, 30]);  // 支持 [x, y] 数组形式

// 必须重绘才能看到变化
Engine.regen();

复制

// 使用 clone() 创建独立副本
const original = new LineEnt([0, 0], [100, 0]);
original.setDefaults();
Engine.addEntities(original);

const copy = original.clone();
copy.move([0, 0], [0, 50]);  // 移动副本
copy.color = 2;               // 修改副本属性
Engine.addEntities(copy);     // 添加副本

Engine.regen();

旋转

const { Point2D, Engine } = vjcad;

// rotate(basePoint, angle) - 绕基点旋转(角度为弧度)
const basePoint = new Point2D(50, 50);  // PointInput:Point2D 或 [x,y] 数组均可
entity.rotate(basePoint, Math.PI / 4);  // 旋转 45°

Engine.regen();

缩放

const { Point2D, Engine } = vjcad;

// scale(basePoint, scaleFactor) - 以基点为中心缩放
const basePoint = new Point2D(0, 0);
entity.scale(basePoint, 0.5);  // 缩小到 0.5 倍
entity.scale(basePoint, 2.0);  // 放大到 2 倍

Engine.regen();

镜像

const { Point2D, Engine } = vjcad;

// mirror(p1, p2) - 沿 p1-p2 定义的直线镜像
const p1 = new Point2D(100, 0);
const p2 = new Point2D(100, 100);
entity.mirror(p1, p2);  // 沿 x=100 垂直线镜像

Engine.regen();

注意:

  • move()/rotate()/scale()/mirror() 的点参数均为 PointInput——Point2D 对象或 [x, y] 数组均可
  • 变换后必须调用 Engine.regen() 才能看到变化

删除实体

const { Engine } = vjcad;

// 删除单个实体
Engine.eraseEntities(entity);

// 删除多个实体
Engine.eraseEntities([entity1, entity2, entity3]);

// 删除后 entity.isAlive 变为 false
console.log(entity.isAlive);  // false

绘图顺序

const { Engine } = vjcad;

// 方式1:使用命令
await Engine.editor.executerWithOp('ENTDRAWFRONT');  // 选中图形置于最前
await Engine.editor.executerWithOp('ENTDRAWBACK');   // 选中图形置于最后
await Engine.editor.executerWithOp('LAYDRAWFRONT');  // 选中图形的图层置于最前
await Engine.editor.executerWithOp('LAYDRAWBACK');   // 选中图形的图层置于最后

// 方式2:直接操作 items 数组
const items = Engine.currentSpace.items;
const idx = items.indexOf(entity);
if (idx > -1) {
    items.splice(idx, 1);  // 移除
    items.push(entity);    // 添加到末尾(最前面)
    Engine.pcanvas.regen(true);
}

分组

const { GroupEnt, LineEnt, CircleEnt, Engine } = vjcad;

// 创建实体
const line = new LineEnt([0, 0], [100, 0]);
const circle = new CircleEnt([50, 50], 20);
line.setDefaults();
circle.setDefaults();

// 创建组
const group = new GroupEnt("MyGroup", [line, circle]);
group.setDefaults();
Engine.addEntities(group);

// 访问组内实体(items 是数组属性,另有 count 属性可取数量)
group.items.forEach((item, index) => {
    console.log(`${index}: ${item.type}, 颜色: ${item.color}`);
});

// 炸开组
const explodedEntities = group.explode();
explodedEntities.forEach(ent => {
    Engine.addEntities(ent);
});
Engine.eraseEntities(group);
Engine.regen(true);

// 使用命令
await Engine.editor.executerWithOp('GROUP');    // 创建组
await Engine.editor.executerWithOp('UNGROUP');  // 取消组

高亮

const { Engine } = vjcad;

// 高亮指定实体
Engine.highLightEntities([entity1, entity2]);

// 清除高亮
Engine.clearHighLight();

// 高亮是临时视觉效果,不影响实体属性

选择集操作

设置选择集

const { Engine } = vjcad;

// 选择单个实体
Engine.ssSetFirst([entity]);

// 选择多个实体
Engine.ssSetFirst([entity1, entity2, entity3]);

// 清空选择集
Engine.ssSetFirst([]);

// 选择所有实体(getEntities 含已删除实体,须过滤 isAlive)
const allEntities = Engine.getEntities(ent => ent.isAlive);
Engine.ssSetFirst(allEntities);

获取选择集

const { Engine } = vjcad;

// 获取当前选择集
const selected = Engine.ssGetFirst();

console.log(`选中 ${selected.length} 个实体`);

// 遍历选择集
selected.forEach((entity, index) => {
    console.log(`${index + 1}. 类型: ${entity.type}, 颜色: ${entity.color}`);
});

// 对选择集进行操作
selected.forEach(entity => {
    entity.color = 1;
});
Engine.regen();

获取实体

获取所有实体

const { Engine } = vjcad;

// getEntities() 返回 currentSpace.items 原样——含已删除实体(isAlive=false)
const allEntities = Engine.getEntities(ent => ent.isAlive);   // 或 Engine.currentSpace.aliveItems

注意:下面的 getEntitiesByType / 条件过滤同样含已删除实体,实际使用时条件里带上 ent.isAlive(或对结果 .filter(e => e.isAlive))。

按类型获取

const { Engine } = vjcad;

const lines = Engine.getEntitiesByType('LINE');
const circles = Engine.getEntitiesByType('CIRCLE');
const arcs = Engine.getEntitiesByType('ARC');
const plines = Engine.getEntitiesByType('PLINE');
const texts = Engine.getEntitiesByType('TEXT');
const mtexts = Engine.getEntitiesByType('MTEXT');
const inserts = Engine.getEntitiesByType('INSERT');
const hatches = Engine.getEntitiesByType('HATCH');

按条件过滤

const { Engine } = vjcad;

// 按颜色过滤
const redEntities = Engine.getEntities(ent => ent.color === 1);

// 按图层过滤
const layerAEntities = Engine.getEntities(ent => ent.layer === "图层A");

// 组合条件
const redLines = Engine.getEntities(ent => 
    ent.type === "LINE" && ent.color === 1
);

// 自定义复杂条件
const largeCircles = Engine.getEntities(ent => 
    ent.type === "CIRCLE" && ent.radius > 50
);

// 排除某些实体
const notHidden = Engine.getEntities(ent => 
    ent.layer !== "隐藏图层"
);

撤销系统

基本撤销/重做

const { Engine } = vjcad;

const undoMgr = Engine.undoManager;

// 检查是否可撤销/重做
if (undoMgr.canUndo()) {
    undoMgr.undo();
}

if (undoMgr.canRedo()) {
    undoMgr.redo();
}

撤销标记

const { Engine, Point2D } = vjcad;

const undoMgr = Engine.undoManager;

// 添加/删除实体的撤销标记——仅在用底层 Engine.pcanvas.addEntity / currentSpace.erase 时手动补;
// Engine.addEntities / eraseEntities 已自动记录;重复 added_undoMark 会在撤销时多删一个无关实体
undoMgr.added_undoMark([entity1, entity2]);
undoMgr.erased_undoMark([entity1, entity2]);

// 移动操作的撤销标记
const fromPt = new Point2D(0, 0);
const toPt = new Point2D(40, 0);
entity.move(fromPt, toPt);
undoMgr.moved_undoMark([entity], fromPt, toPt);

// 旋转操作的撤销标记
undoMgr.rotate_undoMark(entities, basePoint, angle);

// 缩放操作的撤销标记
undoMgr.scaled_undoMark(entities, basePoint, scale);

注意:Engine.addEntities() 和 Engine.eraseEntities() 会自动记录撤销。

撤销分组

将多个操作合并为一次撤销。

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

const undoMgr = Engine.undoManager;

// 开始撤销组
undoMgr.start_undoMark();

try {
    // 执行多个操作
    const line = new LineEnt([0, 0], [100, 0]);
    line.setDefaults();
    Engine.addEntities(line);
    
    const circle = new CircleEnt([50, 50], 30);
    circle.setDefaults();
    Engine.addEntities(circle);
    
    // 移动操作
    line.move([0, 0], [50, 0]);
    undoMgr.moved_undoMark([line], new Point2D(0, 0), new Point2D(50, 0));
    
} finally {
    // 结束撤销组(必须确保调用)
    undoMgr.end_undoMark();
}

// 撤销时会一次性撤销整个组内的所有操作

视图操作

缩放

const { Engine } = vjcad;

// 缩放到全图
Engine.zoomExtents();

// 缩放到指定实体
Engine.zoomToEntities([entity1, entity2]);

// 带边距的缩放
Engine.zoomToEntities(entities, {
    padding: { top: 50, bottom: 50, left: 50, right: 50 }
});

刷新显示

const { Engine } = vjcad;

// render() - 最底层渲染,只执行 GPU 绘制
Engine.render();

// redraw() - 更新视图变换后渲染
Engine.redraw();

// regen() - 局部更新,只重绘已修改的实体(快)
Engine.regen();

// regen(true) - 完全重绘所有图形(慢)
Engine.regen(true);

预览

const { Engine } = vjcad;

// 绘制预览实体
Engine.drawPreviewEntity(entity);
Engine.drawPreviewEntities([entity1, entity2]);

// 清除预览
Engine.clearPreview();

设置视图中心

const { Engine, Point2D } = vjcad;

// 设置视图中心点
Engine.setCenter(new Point2D(100, 100));

// 带边距的设置
Engine.setCenter(new Point2D(100, 100), true, {
    top: 50, bottom: 50, left: 50, right: 50
});

背景色

const { Engine } = vjcad;

// 设置背景灰度值 0-255:0 与 255 是特例,其余值为 rgb(v,v,v)
Engine.setBgc(0);     // 默认深色背景 #212830(不是纯黑)
Engine.setBgc(33);    // rgb(33,33,33) 深灰(不是默认深色背景)
Engine.setBgc(1);     // 近似纯黑 rgb(1,1,1)
Engine.setBgc(255);   // 纯白 #FFFFFF

Engine.redraw();

主题

const { Engine } = vjcad;

// 切换主题(THEME_MODE 的 setter 已自动调用 setBgc(0/255),无需再手动 setBgc;
// 若再 setBgc(33) 反而会把默认深色背景 #212830 覆盖成灰色)
Engine.THEME_MODE = 0;   // 深色主题
Engine.redraw();

Engine.THEME_MODE = 1;   // 浅色主题
Engine.redraw();

// 检查当前主题
const isDark = Engine.isDarkTheme();

屏幕范围

const { Engine } = vjcad;

// 获取屏幕边界(世界坐标系)
const bounds = Engine.getScreenBoundsWcs();
// 返回: BoundingBox 类实例——{ pt1, pt2, minX, minY, maxX, maxY, width, height, center, ... }

// 获取屏幕内的实体
const screenEntities = Engine.getScreenEntities();
const expandedEntities = Engine.getScreenEntities(1.5);  // 扩展 1.5 倍范围

缩放因子

const { Engine } = vjcad;

// 获取当前缩放比例
const zoom = Engine.currentSpace.zoom;

// 设置滚轮缩放因子(百分比,默认 75):每格滚轮 zoom 除/乘以 ZOOMFACTOR/100
// 值越小每格缩放越大(越快);100 = 滚轮不缩放;ZOOMFACTOR 命令只接受 ≥60
Engine.ZOOMFACTOR = 60;   // 缩放更快(每格约 1.67 倍)
Engine.ZOOMFACTOR = 90;   // 缩放更慢(每格约 1.11 倍)