文档
精确的 B-rep 内核
精确边界表示:解析和 NURBS 几何、布尔、圆角、孔识别、质量属性、验证、曲面细分和 STEP。
从英文自动翻译。 查看英文原文
B-rep 内核是什么
确切的内核在 packages/core/src/cad/brep (24 个源文件,大约 8 660 行,加上测试)通过精确边界表示实体:解析曲面和 NURBS 曲面,通过精确边缘的循环进行修剪。一切都是纯数据和纯函数,因此 B-rep 序列化为 JSON,跨越工作人员边界,并且项目历史记录中的差异保持不变。布尔运算、圆角和倒角、孔识别、质量属性、验证、无懈可击的曲面细分和 STEP 交换都适用于这一结构。
拓扑表
A Brep 是一组索引表。实体通过索引相互引用,而不是通过对象引用。
| 实体 | 持有 | 步骤对应 |
|---|---|---|
| 顶点 | 点、公差 | VERTEX_POINT |
| 边缘 | exact curve, [t0, t1] with t0 < t1, v0 = C(t0), v1 = C(t1), tolerance | EDGE_CURVE |
| 科埃奇 | 循环使用边缘的一种方式:边缘索引、反向、面中的可选 p 曲线 (u, v) | ORIENTED_EDGE + PCURVE |
| 环形 | 共边闭循环;从外部看到的左侧材料(外部逆时针,孔顺时针) | EDGE_LOOP |
| 脸 | 一个表面的区域;反转表示向外法线为 −(S_u × S_v) | ADVANCED_FACE |
| 壳 | 连接的面集;封闭的壳限制了体积 | CLOSED_SHELL |
Seams (an edge used twice by the same face, such as the generator line of a full cylinder) and poles (a loop through a degenerate point, such as a cone apex) need no special entities. That is why the exact sphere has 2 vertices, 1 edge and 1 face, and the torus 1 vertex, 2 edges and 1 face.
makeBox(60, 40, 15) {"V":8,"E":12,"F":6,"S":1,"surfaces":["plane"]}
makeSphere(10) {"V":2,"E":1,"F":1,"S":1,"surfaces":["sphere"]}
makeTorus(20, 5) {"V":1,"E":2,"F":1,"S":1,"surfaces":["torus"]}
makeCone(10, 4, 20) {"V":2,"E":3,"F":3,"S":1,"surfaces":["cone","plane"]} 曲线和曲面
分析类型使用 STEP (ISO 10303-42) 参数化,因此从 STEP 读取和写入的面会保留其参数。
| 类型 | 参数化 |
|---|---|
| 线 | C(t) = O + t·d,d单位,t弧长 |
| 圆圈 | C(t) = O + r(cos t·x + sin t·y) |
| 椭圆 | C(t) = O + a cos t·x + b sin t·y |
| 飞机 | S(u,v) = O + u·x + v·y |
| 圆柱 | S(u,v) = O + r(cos u·x + sin u·y) + v·z |
| 锥体 | S(u,v) = O + (R + v tan α)(cos u·x + sin u·y) + v·z |
| 领域 | S(u,v) = O + r cos v(cos u·x + sin u·y) + r sin v·z |
| 环面 | S(u,v) = O + (R + r cos v)(cos u·x + sin u·y) + r sin v·z |
| 革命 | S(u,v) = rotate(C(v), axis, u) |
| 挤压 | S(u,v) = C(u) + v·d |
| 努布斯 | 有理 B 样条曲线或曲面(nurbs.ts 中的 Piegl & Tiller 算法) |
精确布尔值
- 相交。 每个实体相对于另一个实体面的边(牛顿精确点)、位于另一个实体表面上的边以及每对不重合面的相交曲线,在两个表面上进行细化并识别为直线和圆,否则在拟合公差内拟合为三次 B 样条曲线。
- 印记。 每个交点都成为两个实体的一个注册表中的顶点,边在此处分割,并且每个面通过其 (u, v) 域中的平面排列被其上的曲线切割。
- 分类。 每个片段内的一个点相对于另一个实体定位:以相同或相反的方向向内、向外或向上。
- 缝。 片段按照操作规则保留,重合的片段成为一条边,共面的邻居合并,并且结果得到验证。不是封闭流形固体的结果抛出
BooleanError;它永远不会被返回。
export const booleanBrep: (A: Brep, B: Brep, op: BooleanOp, options?: BooleanOptions) => BooleanResult
export interface BooleanOptions {
tol?: number // coincidence, default 1e-8 × model size, at least 1e-7 mm
fitTol?: number // fitted intersection curves, default 1e-6 × size, at least 1e-6 mm
seedAngleDeg?: number // normal turn per seed-mesh triangle, default 10
debug?: (stage: string, data: unknown) => void
}
export interface BooleanResult {
brep: Brep; warnings: string[]
stats: { intersectionCurves: number; splitPoints: number; fragments: number; keptFaces: number }
} import { brep } from "@cadcamfun/core"
const { makeBox, makeCylinder, frame, booleanBrep, validateBrep, massProperties } = brep
const box = makeBox(60, 40, 15)
const hole = makeCylinder(6, 25, frame({ x: 30, y: 20, z: -5 }))
const r = booleanBrep(box, hole, "subtract") // 141 ms
r.stats // {"intersectionCurves":2,"splitPoints":12,"fragments":13,"keptFaces":7}
r.warnings // []
validateBrep(r.brep)
// {"valid":true,"manifoldSolid":true,"genus":1,"volume":34303.53996706151,"issues":[]}
massProperties(r.brep).volume // 34303.53996706151 = 60·40·15 − π·6²·15 exactly 质量特性
体积、面积、质心和惯性张量(单位密度,关于质心,行长)来自边界面上的散度定理。平面通过格林定理沿着精确的边缘曲线精确积分;曲面被集成在精确表面的参数步细分上。
| 身体 | massProperties | 封闭式 |
|---|---|---|
| 盒子 - Ø12 孔,体积 | 34303.53996706151 | 34303.539967061515 |
| 相同,面积 | 8139.292006587684 | 8139.292006587698 |
| 相同,质心 | (30.000, 20.000, 7.500) | (30, 20, 7.5) |
| 球体 r10,体积 | 4188.790204786379 | 4188.790204786391 |
| 环面 20/5,体积 | 9869.60440109475 | 9869.604401089358 |
| 圆角板,体积 | 34097.52220392302 | 34097.522203923065 |
The filleted-plate closed form is the subtracted plate minus four corner slivers of (r² − πr²/4)·h = (16 − 4π)·15 each.
圆角、倒角和孔识别
export const blendCandidates: (b: Brep, minAngleDegrees?: number /* 0.5 */) => BlendCandidate[]
export const selectBlendEdges: (edges: ReadonlyArray<BlendCandidate>, s?: BlendSelector) => BlendCandidate[]
// BlendSelector: parallel?: "x"|"y"|"z", within?: box, kind?: "convex"|"concave"|"both" (default convex), minLength?, curved?
export const blendBrep: (b: Brep, edges: ReadonlyArray<BlendCandidate>, size: number,
style?: "fillet" | "chamfer", options?: BlendOptions) => BlendResult
// BlendResult: brep, blended, vertices (rolling-ball corners), rejected (edge ids), ...
export const recognizeHoles: (b: Brep, options?: HoleRecognitionOptions) => ReadonlyArray<RecognizedHole> 在盒子 - 圆柱体上有 14 个混合候选者; selectBlendEdges(c, { parallel: "z" }) 选取 4 垂直外边缘,并且 blendBrep(b, sel, 4) 已对所有 4 进行圆角处理,且在 94 毫秒内没有拒绝任何内容。这个洞只从面孔上读回:
[{"entry":{"x":30,"y":20,"z":15},"direction":{"x":0,"y":0,"z":-1},"depth":15,"diameter":12,
"form":"simple","bottom":"through",
"segments":[{"kind":"cylinder","start":0,"end":15,"diameterStart":12,"diameterEnd":12,"faces":[6]}]}] 表格有 simple, counterbore 和 countersink;底部是 through, flat 和 drill-point。识别读取的是面孔,而不是历史记录,因此 STEP 导入、布尔结果和参数部分的识别方式是相似的。
防水镶嵌
每条边都在其精确曲线上采样一次,并且使用它的每个面共享这些样本,因此焊接网格没有裂纹。面由约束 Delaunay 在其 (u, v) 域中进行三角剖分。
| 选项 | 默认 | 意义 |
|---|---|---|
| chordTol | 模型对角线的 1/2000,夹紧到 [0.001, 0.05] mm | 网格与精确表面之间的最大距离 |
| angleTolDeg | 15 | 穿过三角形的最大正常转弯(0 禁用) |
| maxEdge | 0(无) | 边长目标 |
| maxPointsPerFace | 200 000 | 安全帽 |
| paramStep | — | massProperties 使用的集成模式 |
对于圆角板 defaultChordTol 返回 0.0368 毫米并且 tessellateBrep 生成了 652 个三角形以及每个面的网格、边缘折线和警告。
步骤交换
writeStepBreps 以毫米和弧度写入 AP214 (AUTOMOTIVE_DESIGN) 文件,每个零件一个 ADVANCED_BREP_SHAPE_REPRESENTATION。 readStepBreps 读取 AP203、AP214 和 AP242 几何形状和拓扑,包括组件及其转换和产品名称。未知实体报告于 warnings 他们的脸都跳了起来;没有什么是猜测的。
ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('CADCAMFUN exact B-rep'),'2;1');
FILE_NAME('plate','2026-10-15T04:49:21',(''),(''),'CADCAMFUN B-rep kernel','CADCAMFUN','');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
ENDSEC;
DATA;
#1=APPLICATION_CONTEXT('core data for automotive mechanical design processes');
#2=APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#1);
#3=PRODUCT_CONTEXT('',#1,'mechanical');
#4=PRODUCT_DEFINITION_CONTEXT('part definition',#1,'design');
#5=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.)); 读回该文件,得到一个体积为 34097.52220392303 mm3 的零件,等于写入的正文,精确到 11 有效数字。
时间预算
内核是同步的并且在调用者的线程上运行。 withBudget(ms, f) 设定最后期限;长循环(布尔值的面对、面分割、表面相交、曲面细分)调用 checkBudget,这会抛出 BudgetExceeded。嵌套预算保留较早的截止日期;没有预算,一张支票就需要一次比较。
withBudget(1, () => booleanBrep(makeSphere(10), makeBox(10, 10, 10), "union"))
// BudgetExceeded: the exact model exceeded its time budget of 1 ms 故障排除
| 症状 | 原因 | 使固定 |
|---|---|---|
BooleanError | 缝合结果不是闭合流形实体(相切或接近重合的面) | 将操作数稍微偏离相切;首先使用 validateBrep 检查两者 |
BudgetExceeded | 行动花费的时间超过了预算 | 简化,或给呼叫者更大的预算 |
| 来自原语的 RangeError | 非正大小,或小圆环 ≥ 大圆环 | 例如“圆环小半径必须小于大半径” |
混合边缘 rejected | 面对于半径、刀刃或倾斜的壁来说太窄 | 较小的半径,或倒角 |
| STEP 部分缺失面 | 文件中不支持的实体 | 读 warnings 来自 readStepBreps |
| validateBrep 报告问题 | 构建体中的索引、方向或表面边缘误差 | 该问题命名了该实体;没有任何内容会自动修复 |