唯杰地图 logo唯杰地图
VJMAP
EN

进阶实体

vjcad/references/quickref/entities-advanced.md 14.0 KB528 行
原文

标注、填充、块插入等高级实体类型。

HatchEnt - 填充

const { HatchEnt, PolylineEnt, Edge, Edges, EdgeType, Engine } = vjcad;

// 1. 创建边界(闭合多段线)
const boundary = new PolylineEnt();
boundary.setPoints([
    [0, 0],
    [100, 0],
    [100, 60],
    [0, 60]
]);
boundary.isClosed = true;
boundary.setDefaults();

// 2. 创建填充
const hatch = new HatchEnt();
hatch.patternName = "ANSI31";  // 图案名称
hatch.patternScale = 1.0;      // 图案比例
hatch.patternAngle = 0;        // 图案角度

// 3. 设置边界
const edge = new Edge();
edge.edgeType = EdgeType.Polyline;
edge.bulgePoints = boundary.bulgePoints.clone();

const edges = new Edges();
edges.add(edge);
hatch.setLoops(edges);

hatch.setDefaults();
hatch.color = 4;
Engine.addEntities([boundary, hatch]);

常用填充图案:

图案名 说明
SOLID 实心填充
ANSI31 45° 单斜线(铁/砖石)
ANSI32 45° 双线组(钢)
ANSI33 45° 实线+虚线交替(青铜/黄铜)
ANSI34 45° 四线组(塑料/橡胶)
ANSI37 45°/135° 交叉斜线

属性:

  • patternName - 图案名称
  • patternScale - 图案比例
  • patternAngle - 图案角度
  • color - 填充颜色

标注实体

LinearDimensionEnt - 线性标注

const { LinearDimensionEnt, Point2D, Engine } = vjcad;

const dim = new LinearDimensionEnt(
    new Point2D(0, 0),     // startPoint: 标注起点
    new Point2D(100, 0),   // endPoint: 标注终点
    new Point2D(50, 20),   // thirdPoint: 标注线位置
    0                      // dimAngle: 0=水平, PI/2=垂直
);
dim.setDefaults();
dim.textHeight = 5;
dim.arrowSize = 3;
dim.textOverride = "L=<>";  // <> 会被替换为测量值
dim.color = 3;
Engine.addEntities(dim);

AlignedDimensionEnt - 对齐标注

const { AlignedDimensionEnt, Point2D, Engine } = vjcad;

const dim = new AlignedDimensionEnt(
    new Point2D(0, 0),     // startPoint
    new Point2D(100, 50),  // endPoint
    new Point2D(50, 40)    // thirdPoint
);
dim.setDefaults();
Engine.addEntities(dim);

RadialDimensionEnt - 半径标注

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

// 先创建圆
const circle = new CircleEnt([50, 50], 30);
circle.setDefaults();
Engine.addEntities(circle);

// 创建半径标注
const dim = new RadialDimensionEnt(
    new Point2D(50, 50),   // center: 圆心
    new Point2D(80, 50),   // chordPoint: 圆周点
    10                     // leaderLength: 引线延伸长度
);
dim.setDefaults();
Engine.addEntities(dim);

DiametricDimensionEnt - 直径标注

const { DiametricDimensionEnt, Point2D, Engine } = vjcad;

const dim = new DiametricDimensionEnt(
    new Point2D(20, 50),   // chordPoint1: 直径端点1
    new Point2D(80, 50),   // chordPoint2: 直径端点2
    10                     // leaderLength
);
dim.setDefaults();
Engine.addEntities(dim);

AngleDimensionEnt - 角度标注

const { AngleDimensionEnt, Point2D, Engine } = vjcad;

const dim = new AngleDimensionEnt(
    new Point2D(0, 0),     // center: 角度顶点
    new Point2D(100, 0),   // xLine1Point: 第一条边上的点
    new Point2D(50, 80),   // xLine2Point: 第二条边上的点
    new Point2D(60, 40)    // arcPoint: 标注弧位置
);
dim.setDefaults();
Engine.addEntities(dim);

ArcDimensionEnt - 弧长标注

const { ArcDimensionEnt, Point2D, Engine } = vjcad;

const dim = new ArcDimensionEnt(
    new Point2D(50, 50),   // center
    new Point2D(80, 50),   // xLine1Point: 圆弧起点
    new Point2D(50, 80),   // xLine2Point: 圆弧终点
    new Point2D(70, 70)    // arcPoint: 标注位置
);
dim.setDefaults();
Engine.addEntities(dim);

OrdinateDimensionEnt - 坐标标注

const { OrdinateDimensionEnt, Point2D, Engine } = vjcad;

const dim = new OrdinateDimensionEnt(
    new Point2D(0, 0),     // origin: 坐标原点(首参,不能省)
    new Point2D(100, 50),  // definingPoint: 被标注点
    new Point2D(120, 70),  // leaderEndPoint: 引线终点
    true                   // displayModeOrUseXAxis: true=X坐标, false=Y坐标
);
dim.setDefaults();
Engine.addEntities(dim);

标注通用属性:

属性 说明
textHeight 文字高度
arrowSize 箭头大小
textOverride 文字覆盖(<> 被替换为测量值)
scaleFactor 缩放因子
decimalPlaces 小数位数

标注方法:

  • getMeasurement() - 获取测量值
  • getFormattedMeasurement() - 获取格式化后的文本

关联标注

标注可以关联到源实体,源实体移动时标注自动更新。

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);

端点类型:

  • '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 处
);

InsertEnt - 块插入

创建块定义

const { LineEnt, CircleEnt, Engine } = vjcad;

const doc = Engine.currentDoc;
const blockName = "MySymbol";

// 检查是否已存在
let blockDef = doc.blocks.itemByName(blockName);
if (!blockDef) {
    // 创建块定义
    blockDef = doc.blocks.add(blockName);
    blockDef.basePoint = [0, 0];  // 基点
    
    // 添加块内实体
    const line1 = new LineEnt([-10, 0], [10, 0]);
    const line2 = new LineEnt([0, -10], [0, 10]);
    const circle = new CircleEnt([0, 0], 5);
    
    line1.setDefaults();
    line2.setDefaults();
    circle.setDefaults();
    
    blockDef.addEntity(line1);
    blockDef.addEntity(line2);
    blockDef.addEntity(circle);
}

插入块引用

const { InsertEnt, Engine } = vjcad;

const insert = new InsertEnt();
insert.blockId = blockDef.blockId;     // 块ID(必须)
insert.insertionPoint = [50, 50];      // 插入点
insert.scaleFactor = 1.5;              // 缩放因子
insert.rotation = Math.PI / 4;         // 旋转角度(弧度)
insert.setDefaults();
insert.color = 5;
Engine.addEntities(insert);

炸开块

// getNestEnts(forceUpdate) 的参数是"强制重算缓存",不是"炸开";返回的是 insert 内部缓存数组
// (已按插入点/比例/旋转变换到世界坐标)——加入图纸前先 clone,别把缓存对象本身加进去
const explodedEnts = insert.getNestEnts(true).map(ent => ent.clone());
Engine.addEntities(explodedEnts);
Engine.eraseEntities(insert);
// 与 EXPLODE 命令的差别:命令还会把 0 图层 / ByBlock(color 0) 的子实体解析为继承插入块的图层/颜色,手写时需自行处理

属性:

  • blockId - 块ID(必须,从 blockDef.blockId 获取)
  • insertionPoint - 插入点
  • scaleFactor - 缩放因子
  • rotation - 旋转角度(弧度)

方法:

  • getNestEnts(forceUpdate = false) - 获取(变换到世界坐标的)嵌套实体缓存;true 强制重算,返回内部数组,炸开时需 clone

符号管理

从本地存储加载符号

const { 
    getLocalStorageService, 
    parseSymbolVcadData, 
    mergeSymbolToDocument,
    Point2D, Engine 
} = vjcad;

const localService = getLocalStorageService();

// 获取分类和符号列表
const categories = await localService.getLocalSymbolCategories();
const symbols = await localService.getLocalSymbolList(categories[0].id);
const symbol = await localService.getLocalSymbol(symbols[0].id);

// 解析符号数据
const symbolDoc = await parseSymbolVcadData(symbol.vcadData);

// 合并到文档(getLocalSymbol 返回 {record, vcadData},basePoint 在 record 上)
const addedEntities = mergeSymbolToDocument(
    symbolDoc,
    new Point2D(100, 100),   // insertPoint
    symbol.record.basePoint,  // basePoint: [x, y]
    1.5,                      // scale
    45,                       // rotation (度)
    false                     // clearSourceInfo
);

Engine.zoomExtents();

交互式插入符号

const { insertSymbolInteractive } = vjcad;

const entities = await insertSymbolInteractive(
    symbolData,
    basePoint,
    {
        allowScale: true,      // 允许指定缩放
        allowRotation: true,   // 允许指定旋转
        clearSourceInfo: false
    }
);

创建本地符号

const { 
    getLocalStorageService,
    buildSymbolVcadData,
    generateThumbnailFromEntities
} = vjcad;

const localService = getLocalStorageService();

// 创建分类
const category = await localService.createLocalSymbolCategory("我的符号");

// 创建符号内容
const entities = [line1, circle1];

// 生成符号数据
const vcadData = await buildSymbolVcadData(entities, false);
const thumbnail = await generateThumbnailFromEntities(entities, 128, 128);

// 保存符号
const symbol = await localService.saveLocalSymbol({
    categoryId: category.id,
    name: "十字符号",
    basePoint: [0, 0],
    thumbnail: thumbnail,
    vcadData: vcadData
});

SplineEnt 进阶 - 拟合点与参数化

拟合点 vs 控制点

const { SplineEnt, Engine } = vjcad;

const points = [[0, 0], [50, 80], [100, 20], [150, 90], [200, 40]];

// 拟合点:曲线精确经过每个点
const fit = new SplineEnt();
fit.setFitPoints(points);
fit.setDefaults();
fit.color = 1;

// 控制点:点"拉动"曲线但不经过
const ctrl = new SplineEnt();
ctrl.setControlPoints(points);
ctrl.setDefaults();
ctrl.color = 3;

Engine.addEntities([fit, ctrl]);  // 第二参是 options 不是第二个实体,必须传数组

参数化方式

方式 说明 适用场景
'chord' 弦长参数化(默认) 通用场景
'sqrtChord' 弦长平方根(向心) 急转弯、密集点
'uniform' 均匀参数化 等距分布点
// 向心参数化
spline.setFitPoints(points, { parameterization: 'sqrtChord' });

端点切线控制

spline.setFitPoints(points, {
    startTangent: [1, 0],   // 起点水平向右
    endTangent: [0, 1]      // 终点竖直向上
});

不指定切线时使用自然端条件(端点二阶导数为零)。

拟合点 API 速查

方法 说明
setFitPoints(pts, opts?) 设置拟合点,自动计算控制点和节点向量
addFitPoint(pt, opts?) 追加一个拟合点并重新计算 ⚠️ 内部是"读当前 fitPoints→push→setFitPoints",而 setFitPoints 的插值求解器在拟合点 <4 个时静默 return——从空样条逐点 addFitPoint 永远不积累(每次求解失败、读回仍为空)。要逐点加需先 setFitPoints/addFitPoints 铺够 ≥4 个点
addFitPoints(pts, opts?) 批量追加拟合点(一次给 ≥4 个即可通过求解器)
getFitPoint(i) 获取第 i 个拟合点 [x, y]
getFitPoints() 获取所有拟合点 [x, y][]

控制点 API 速查

方法 说明
setControlPoints(pts) 设置控制点,支持 [x,y] 或 [[x,y], weight]
addControlPoint(pt, w?) 追加一个控制点(链式调用)
addControlPoints(pts) 批量追加控制点
getControlPoint(i) 获取第 i 个控制点 [x, y]
getControlPoints() 获取所有控制点 [x, y][]
getControlPointsWithWeight() 获取含权重的控制点

底层插值算法

const { fitPointsToControlPoints } = vjcad;

const result = fitPointsToControlPoints(
    [[0,0], [50,100], [100,50], [150,100], [200,0]],
    { parameterization: 'chord' }
);
// result.controlPoints — 计算出的控制点
// result.knots — 对应的节点向量

MLeaderEnt - 多重引线

const { MLeaderEnt, Point2D, Engine } = vjcad;

const mleader = new MLeaderEnt();
mleader.setDefaults();
mleader.textContent = "标注内容";  // 注意是 textContent 不是 text
// 文字位置用 textPosition 设置(默认 (0,0)),且要在 addLeaderLine 之前设——基线朝向据此计算
mleader.textPosition = new Point2D(100, 50);
mleader.textHeight = 5;
mleader.arrowSize = 3;
// 引线顶点用 addLeaderLine + addLastVertex 构建(无 leaderPoints 数组属性)
const lineIdx = mleader.addLeaderLine(new Point2D(0, 0)); // 箭头位置
mleader.addLastVertex(lineIdx, new Point2D(50, 50));      // 中间拐点(addLastVertex 只加顶点,不决定文字位置)
Engine.addEntities(mleader);

GroupEnt - 组

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 是数组属性)
group.items.forEach((item, index) => {
    console.log(`${index}: ${item.type}`);
});

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