填充实体(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 | 图案角度(度) |
color | 填充颜色 |
const patternManager = Engine.patternManager;
const allPatternNames = patternManager.getAllPatternNames();
console.log(`共有 ${allPatternNames.length} 个填充图案`);
| 图案名 | 说明 |
|---|
ANSI31 | 铁、砖和石 (45° 斜线) |
ANSI32 | 钢 |
ANSI33 | 青铜、黄铜和紫铜 |
ANSI34 | 塑料和橡胶 |
ANSI35 | 耐火砖和耐火材质 |
ANSI36 | 大理石、板岩和玻璃 |
ANSI37 | 铅、锌、镁和绝缘体 (交叉斜线) |
ANSI38 | 铝 |
| 图案名 | 说明 |
|---|
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 | 随机点图案(沙地) |
| 图案名 | 说明 |
|---|
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_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; // 缩小一半
*图案名称,图案描述
角度,X原点,Y原点,deltaX,deltaY[,线型定义...]
- 角度: 线条绘制方向(度),0=水平向右,90=垂直向上
- X原点/Y原点: 第一条线的起点坐标
- deltaX: 沿线条方向的偏移量
- deltaY: 垂直于线条方向的偏移量(行间距)
- 线型定义: 可选的虚线模式(正数=实线,负数=空隙,0=点)
// 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");
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');
// HATCHEDIT 命令:编辑现有填充
await Engine.editor.executerWithOp('HATCHEDIT');