填充实体(HatchEnt)的完整使用指南,包含内置图案、自定义图案、边界创建。
概览
WebCAD 内置 80+ 种填充图案,涵盖 ANSI、ISO、JIS 标准以及各种材质图案。
基本用法
创建填充
const { HatchEnt, PolylineEnt, Engine, Edge, Edges, EdgeType } = vjcad;
// 1. 创建闭合边界
const boundary = new PolylineEnt();
boundary.addVertex([0, 0]);
boundary.addVertex([100, 0]);
boundary.addVertex([100, 60]);
boundary.addVertex([0, 60]);
boundary.isClosed = true;
boundary.setDefaults();
// 2. 创建填充实体
const hatch = new HatchEnt();
hatch.patternName = "SOLID"; // 图案名称
hatch.patternScale = 1; // 图案比例
// 3. 从多段线创建边界
const edge = new Edge();
edge.edgeType = EdgeType.Polyline;
edge.bulgePoints = boundary.bulgePoints.clone();
const edges = new Edges();
edges.add(edge);
// 4. 设置边界
hatch.setLoops(edges);
hatch.setDefaults();
hatch.color = 3; // 绿色
// 5. 添加到画布
Engine.addEntities([boundary, hatch]);
Engine.zoomExtents();
填充属性
| 属性 |
说明 |
patternName |
图案名称(如 "SOLID", "ANSI31") |
patternScale |
图案比例(默认 1) |
patternAngle |
图案角度(弧度,与其他实体 rotate 一致;Math.PI/4 = 45°) |
color |
填充颜色 |
内置图案
获取所有图案名称
const patternManager = Engine.patternManager;
const allPatternNames = patternManager.getAllPatternNames();
console.log(`共有 ${allPatternNames.length} 个填充图案`);
实心填充
ANSI 图案(美国标准)
| 图案名 |
说明 |
ANSI31 |
铁、砖和石 (45° 斜线) |
ANSI32 |
钢 |
ANSI33 |
青铜、黄铜和紫铜 |
ANSI34 |
塑料和橡胶 |
ANSI35 |
耐火砖和耐火材质 |
ANSI36 |
大理石、板岩和玻璃 |
ANSI37 |
铅、锌、镁和绝缘体 (交叉斜线) |
ANSI38 |
铝 |
AR 图案(建筑)
| 图案名 |
说明 |
AR-B816 |
8x16 块砖顺砌 |
AR-B816C |
8x16 块砖顺砌(带灰泥接缝) |
AR-B88 |
8x8 块砖顺砌 |
AR-BRELM |
标准砖块英式堆砌 |
AR-BRSTD |
标准砖块顺砌 |
AR-CONC |
随机点和石头图案(混凝土) |
AR-HBONE |
人字形图案 |
AR-PARQ1 |
镶木地板图案 |
AR-RROOF |
屋顶木瓦图案 |
AR-RSHKE |
屋顶实木瓦图案 |
AR-SAND |
随机点图案(沙地) |
ISO 图案(国际标准)
| 图案名 |
说明 |
ACAD_ISO02W100 |
划线 |
ACAD_ISO03W100 |
划、空格线 |
ACAD_ISO04W100 |
长划、点线 |
ACAD_ISO05W100 |
长划、双点线 |
ACAD_ISO06W100 |
长划、三点线 |
ACAD_ISO07W100 |
点线 |
ACAD_ISO08W100 |
长划、短划线 |
ACAD_ISO09W100 |
长划、双短划线 |
ACAD_ISO10W100 |
划、点线 |
ACAD_ISO11W100 |
双划、点线 |
ACAD_ISO12W100 |
划、双点线 |
ACAD_ISO13W100 |
双划、双点线 |
ACAD_ISO14W100 |
划、三点线 |
ACAD_ISO15W100 |
双划、三点线 |
JIS 图案
| 图案名 |
说明 |
JIS_LC_8 |
LC 图案 (@8) |
JIS_LC_8A |
LC 图案 (@8 变体) |
JIS_LC_20 |
LC 图案 (@20) |
JIS_LC_20A |
LC 图案 (@20 变体) |
JIS_RC_10 |
RC 图案 (@10) |
JIS_RC_15 |
RC 图案 (@15) |
JIS_RC_18 |
RC 图案 (@18) |
JIS_RC_30 |
RC 图案 (@30) |
JIS_STN_1E |
石材图案 (@1) |
JIS_STN_2.5 |
石材图案 (@2.5) |
JIS_WOOD |
木材图案 |
材质图案
| 图案名 |
说明 |
ANGLE |
角钢 |
BOX |
方钢 |
BRASS |
黄铜 |
BRICK |
砖 |
BRSTONE |
砖和石 |
CLAY |
粘土 |
CORK |
软木 |
CROSS |
十字形 |
DASH |
划线 |
DOLMIT |
地壳岩层 |
DOTS |
点 |
EARTH |
地面 |
ESCHER |
Escher 图案 |
FLEX |
软性材质 |
GRASS |
草地 |
GRATE |
格栅 |
GRAVEL |
沙砾 |
HEX |
六边形 |
HONEY |
蜂巢 |
HOUND |
犬牙交错 |
INSUL |
绝缘材质 |
LINE |
平行水平线 |
MUDST |
泥沙 |
NET |
水平/垂直栅格 |
NET3 |
网状 0-60-120 |
PLAST |
塑料 |
PLASTI |
塑料(变体) |
SACNCR |
混凝土 |
SQUARE |
小方块 |
STARS |
六芒星 |
STEEL |
钢 |
SWAMP |
沼泽 |
TRANS |
热传递材质 |
TRIANG |
等边三角形 |
ZIGZAG |
锯齿 |
GOST_GLASS |
玻璃 (GOST) |
GOST_WOOD |
木材 (GOST) |
GOST_GROUND |
地面 (GOST) |
边界类型
多段线边界
const boundary = new PolylineEnt();
boundary.setPoints([[0, 0], [60, 0], [60, 50], [30, 70], [0, 50]]);
boundary.isClosed = true;
boundary.setDefaults();
const edges = new Edges();
const edge = new Edge();
edge.edgeType = EdgeType.Polyline;
edge.bulgePoints = boundary.bulgePoints.clone();
edges.add(edge);
hatch.setLoops(edges);
圆形边界
const { CircleEnt } = vjcad;
const circle = new CircleEnt([100, 50], 30);
circle.setDefaults();
const edges = new Edges();
const edge = new Edge();
edge.edgeType = EdgeType.Circle;
edge.center = circle.center.clone();
edge.radius = circle.radius;
edges.add(edge);
hatch.setLoops(edges);
带孔填充(外边界 + 内边界)
// 外边界(矩形)
const outerRect = new PolylineEnt();
outerRect.setPoints([[0, 0], [100, 0], [100, 80], [0, 80]]);
outerRect.isClosed = true;
outerRect.setDefaults();
// 内边界(圆形孔)
const innerCircle = new CircleEnt([50, 40], 20);
innerCircle.setDefaults();
// 创建 Edges(外边界 + 内边界)
const allEdges = new Edges();
// 外边界
const outerEdge = new Edge();
outerEdge.edgeType = EdgeType.Polyline;
outerEdge.bulgePoints = outerRect.bulgePoints.clone();
allEdges.add(outerEdge);
// 内边界(孔)
const innerEdge = new Edge();
innerEdge.edgeType = EdgeType.Circle;
innerEdge.center = innerCircle.center.clone();
innerEdge.radius = innerCircle.radius;
allEdges.add(innerEdge);
// 设置边界
hatch.setLoops(allEdges);
图案比例
自动计算比例
const { calculateHatchPatternScale } = vjcad;
// 计算边界大小
const bbox = boundary.boundingBox();
const boundsSize = Math.max(bbox.maxX - bbox.minX, bbox.maxY - bbox.minY);
// 获取图案定义
const patternDef = Engine.patternManager.getPattern(patternName);
// 自动计算合适的比例
const autoScale = calculateHatchPatternScale(boundsSize, patternName, patternDef);
hatch.patternScale = autoScale;
手动设置比例
hatch.patternScale = 2; // 放大 2 倍
hatch.patternScale = 0.5; // 缩小一半
自定义图案
PAT 格式说明
*图案名称,图案描述
角度,X原点,Y原点,deltaX,deltaY[,线型定义...]
- 角度: 线条绘制方向(度),0=水平向右,90=垂直向上
- X原点/Y原点: 第一条线的起点坐标
- deltaX: 沿线条方向的偏移量
- deltaY: 垂直于线条方向的偏移量(行间距)
- 线型定义: 可选的虚线模式(正数=实线,负数=空隙,0=点)
注册自定义图案
最简单:直接把 PAT 文本交给内置解析器(可含多个 *图案,返回成功加载的数量):
const count = Engine.patternManager.loadFromPATDefinitions(`*MY_PATTERN,我的自定义图案
45,0,0,0,5
135,0,0,0,5`, "custom");
也可以自己解析后 registerPattern:
// PAT 格式字符串
const patString = `*MY_PATTERN,我的自定义图案
45,0,0,0,5
135,0,0,0,5`;
// 解析 PAT 格式
function parsePatternString(patString) {
const lines = patString.trim().split('\n');
const headerMatch = lines[0].match(/^\*([^,]+),(.*)$/);
const name = headerMatch[1].trim();
const description = headerMatch[2].trim();
const patternLines = [];
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
if (!line || line.startsWith(';')) continue;
const parts = line.split(',').map(p => parseFloat(p.trim()));
patternLines.push({
angle: parts[0],
xOrigin: parts[1],
yOrigin: parts[2],
deltaX: parts[3],
deltaY: parts[4],
dashes: parts.slice(5)
});
}
return { name, description, lines: patternLines };
}
// 注册图案
const patternDef = parsePatternString(patString);
Engine.patternManager.registerPattern(patternDef, "custom");
PatternManager API
获取管理器
const patternManager = Engine.patternManager;
常用方法
// 获取所有图案名称
const allNames = patternManager.getAllPatternNames();
const categoryNames = patternManager.getAllPatternNames("builtin");
// 获取图案定义
const patternDef = patternManager.getPattern("ANSI31");
console.log(patternDef.name);
console.log(patternDef.description);
console.log(patternDef.lines); // 线定义数组
// 检查图案是否存在
const exists = patternManager.hasPattern("MY_PATTERN");
// 注册自定义图案
patternManager.registerPattern(definition, "custom");
// 获取分类
const categories = patternManager.getCategories();
// 获取统计信息
const stats = patternManager.getStatistics();
完整示例:图案表
const {
HatchEnt, PolylineEnt, TextEnt,
Engine, Edge, Edges, EdgeType
} = vjcad;
const patternManager = Engine.patternManager;
const allPatternNames = patternManager.getAllPatternNames();
const COLS = 6;
const CELL_WIDTH = 80;
const CELL_HEIGHT = 60;
const PADDING = 10;
function createEdgesFromPolyline(polyline) {
const edges = new Edges();
const edge = new Edge();
edge.edgeType = EdgeType.Polyline;
edge.bulgePoints = polyline.bulgePoints.clone();
edges.add(edge);
return edges;
}
const allEntities = [];
allPatternNames.forEach((patternName, i) => {
const col = i % COLS;
const row = Math.floor(i / COLS);
const x = col * (CELL_WIDTH + PADDING);
const y = -row * (CELL_HEIGHT + PADDING + 20);
// 边界
const boundary = new PolylineEnt();
boundary.addVertex([x, y]);
boundary.addVertex([x + CELL_WIDTH, y]);
boundary.addVertex([x + CELL_WIDTH, y + CELL_HEIGHT]);
boundary.addVertex([x, y + CELL_HEIGHT]);
boundary.isClosed = true;
boundary.setDefaults();
allEntities.push(boundary);
// 填充
const hatch = new HatchEnt();
hatch.patternName = patternName;
hatch.patternScale = patternName === "SOLID" ? 1 : 5;
hatch.setLoops(createEdgesFromPolyline(boundary));
hatch.setDefaults();
hatch.color = patternName === "SOLID" ? 3 : 2;
allEntities.push(hatch);
// 标签
const label = new TextEnt();
label.insertionPoint = [x, y - 8];
label.text = patternName;
label.height = 5;
label.setDefaults();
allEntities.push(label);
});
Engine.addEntities(allEntities);
Engine.zoomExtents();
命令方式
// HATCH 命令:选择边界并填充
await Engine.editor.executerWithOp('HATCH');
// EHATCH 命令:编辑现有填充(注册名是 EHATCH,不是 HATCHEDIT)
await Engine.editor.executerWithOp('EHATCH');