跳到内容
CADCAMFUN
文档

文档

Mesh 和 CSG 内核

来自参数化实体的闭合三角形网格、具有凸快速路径的 BSP 布尔、清理和拓扑检查。

从英文自动翻译。 查看英文原文

什么是网格内核

网格内核适用于闭合三角形网格:它从参数基元构建它们(meshOf),测量它们(meshVolume, meshBounds, meshTopology),并将它们与布尔值 (booleanMesh, booleanAll)。它是视口显示的内容、CAM 生成器加工的内容以及 STL 导出写入的内容。

它不是精确的边界表示。被切割的圆柱体仍然是多面圆柱体,并且没有可供圆角或测量的面拓扑。对于精确的面、圆角、质量属性和 STEP, B-代表内核 是一段单独的代码。

文件线路角色
cad/solid.ts659实体模式(长方体、圆柱体、球体、圆锥体、环面、拉伸、旋转)、meshOf、meshVolume、meshBounds
cad/csg.ts459BSP 布尔值、凸分类器、平移/旋转/合并
cad/mesh-clean.ts626焊接、T 形接头修复、共面合并、重新三角测量
cad/mesh-topology.ts110流形、壳、属、体积、面积
cad/triangulate.ts383带孔多边形三角剖分
带钻孔凸台的钻孔板 拖动进行轨道旋转·滚动进行缩放·右键拖动进行平移
真实的 booleanMesh 输出:一个 60 × 40 × 10 盒子减去四个 Ø6 孔(booleanAll 减去),与 Ø20 × 8 凸台结合,然后钻孔 Ø10。 640 三角形; meshTopology 报告封闭固体,1 壳,属 5,V 23981.4 mm3。

网格类型和基元

solid.ts
export interface Mesh {
  readonly positions: Float32Array   // x, y, z per vertex
  readonly indices: Uint32Array      // three per triangle, counter-clockwise seen from outside
}
export const meshOf: (solid: Solid, tolerance?: number /* 0.1 mm */) => Mesh
export const meshVolume: (mesh: Mesh) => number     // signed; positive when outward-facing
export const meshBounds: (mesh: Mesh) => SolidBounds
坚硬的领域限制
盒子原点,尺寸 {x, y, z}尺寸 > 0
圆柱原点、半径、高度、线段、轴?段 3–512; z 轴 | x| y
领域中心、半径、环铃声 2–256
锥体原点、baseRadius、topRadius、高度、线段、轴?顶部半径≥0;段 3–512
环面中心、majorRadius、minorRadius、旋转?、majorSegments、minorSegments、轴?3–512 和 3–256
拉伸轮廓(≥ 3 点,不闭合),高度,原点?xY 轮廓
围绕轮廓(≥ XZ 中的 2 点)、角度、线段?关于Z;段 3–512,默认 16
segments 和 rings 是最小值: meshOf 提高它们直到和弦误差在范围内 tolerance, using step = 4·asin(√(min(1, tol/r)/2)). Two budgets stop runaway tolerances.
警卫价值错误信息
公差必须是正的且有限的—网格公差必须为正且有限
每条曲线的线段65 536网格公差超出细分预算
网格行×列(球体、环面、旋转)1 000 000网格容差超出顶点预算

Ø6 圆柱体 segments: 24 在公差 0 处。05 得到 96 个三角形(24 条边,两个 24 边形帽); a Ø20 具有 128,因为较大的半径需要 32 段才能保持在 0.05 毫米内。

通过二进制空间划分进行布尔运算

每个操作数成为一个分类器。通用网格得到一棵BSP树;凸网格(封闭的、连通的、每条边都是凸的)只是其不同的面平面,因此一个盒子有六个平面,一万个三角形的球体可以在不构建凸实体 BSP 退化为的二次链的情况下进行分类。多边形被分类为列表,并且保留或删除没有其他操作数边界框的多边形,而不走任何东西。

  1. If either mesh is empty, or the bounding boxes do not meet (within tolerance), answer directly: union = merge, subtract = a, intersect = empty.
  2. 构建 A 和 B 的分类器(凸平面或 BSP)。
  3. 并集:将 A 保留在 B 之外,将 B 保留在 A 之外,并将 B 的面与 A 的指向相同的方向重合,因此保留一次共享面。
  4. Subtract and intersect follow the classic a.clipTo(b), b.clipTo(a), b.invert() sequence on polygon lists, without copying trees.
  5. 清理多边形汤:焊接 max(10·eps, 1e-9·size) 内的点,关闭 T 形接头,关闭条子之间最多 1e-4·size 的间隙,合并共面片段并重新三角化。
csg.ts
export type BooleanOp = "union" | "subtract" | "intersect"
export interface CsgOptions {
  /** Distance below which a point counts as on a plane, mm. Default 1e-7 × the larger extent. */
  readonly tolerance?: number
  /** Merge coplanar fragments and re-triangulate (default true). */
  readonly mergeCoplanar?: boolean
}
export const booleanMesh: (a: Mesh, b: Mesh, op: BooleanOp, options?: CsgOptions) => Mesh
/** Union reduced as a balanced tree; subtract and intersect fold left to right. */
export const booleanAll: (meshes: ReadonlyArray<Mesh>, op: BooleanOp, options?: CsgOptions) => Mesh
export const translateMesh: (mesh: Mesh, dx: number, dy: number, dz: number) => Mesh
export const rotateMesh: (mesh: Mesh, axis: V3, radians: number, origin?: V3) => Mesh
export const mergeMeshes: (meshes: ReadonlyArray<Mesh>) => Mesh

三角形数量随着特征而增长,而不是随着布尔值的数量而增长:合并步骤将共面的条带回整个面。在上面的板中,盒子有 12 个三角形,在四个孔之后 412,在凸台之后 540,在孔之后 640;整个链在 96 毫秒内运行。

对曲线输入进行并集、相减、相交

A 20 mm cube at the origin against a sphere of radius 12 centred on its far corner (20, 20, 20), meshed at tolerance 0.2 (624 triangles). Real volumes:

结果体积,立方毫米三角形
单独的球体7 063.84(确切地说是 7 238.23)624
立方体∩球体882.98112
立方体∪球体14 180.86—
立方体-球体7 117.02—

检查:8 000 + 7 063.84 − 882.98 = 14 180.86 和 8 000 − 882.98 = 7 117.02,因此三个结果彼此一致第一百。球体网格本身是精确球体下的 2.4 %,这是粗略公差的分面,而不是布尔误差。

立方体-球体 拖动进行轨道旋转·滚动进行缩放·右键拖动进行平移
减法结果:角上挖出第八个球体的立方体。
立方体∩球体 拖动进行轨道旋转·滚动进行缩放·右键拖动进行平移
相交结果:位于立方体内部的球体的第八个。

拓扑检查

meshTopology 计算顶点、边和三角形的数量,查找边界、非流形和错误定向的边、退化三角形和壳,并导出欧拉特征和亏格。 describeTopology 打印助手和视口使用的一行摘要。
meshTopology(bored) — 实际输出
{"vertices":312,"triangles":640,"edges":960,"boundaryEdges":0,"nonManifoldEdges":0,
 "misorientedEdges":0,"degenerateTriangles":0,"shells":1,"eulerCharacteristic":-8,"genus":5,
 "closed":true,"solid":true,"volume":23981.43509870267,"area":8238.640705862534}
// describeTopology → "closed solid, 1 shell, genus 5, 640 triangles, V 23981.4 mm³, A 8238.6 mm²"

V − E + F = 312 − 960 + 640 = −8 = 2 − 2g, so g = 5: the four drilled holes plus the bore, which runs through the boss and the plate.

多边形三角剖分

triangulatePolygon(outer, holes) 将索引三元组返回到外环和孔的串联中。带有 4 × 4 孔的 2 × 2 正方形可得出八个三角形:
实际输出
triangulatePolygon(
  [{x:0,y:0},{x:4,y:0},{x:4,y:4},{x:0,y:4}],
  [[{x:1,y:1},{x:1,y:3},{x:3,y:3},{x:3,y:1}]])
// [[0,4,5],[7,4,0],[3,0,5],[7,0,1],[2,3,5],[6,7,1],[2,5,6],[6,1,2]]
triangulatePolygonChecked 回报 undefined 当输入无法进行三角测量时(自相交环、外环外侧的孔),而不是部分结果。

故障排除

症状原因使固定
布尔结果有洞或翻转面输入开路或顺时针缠绕使用 meshTopology 检查两个输入:boundaryEdges 和 MisorientedEdges 必须为 0
两个操作数共享的面丢失或重复面几乎但不完全重合(距离超出公差)将操作数对齐到同一平面,或提高 CsgOptions.tolerance
RangeError:网格容差超出细分预算对于半径来说公差太细使用公差预设(0.1 至 0.0005 毫米)
体积与公式不同粗公差刻面网格更细,或使用 B-rep 内核获得精确的质量属性
许多工具上的布尔运算速度很慢首先构建的工具联盟逐一减去工具(booleanAll 执行此操作):每个凸工具都是几个平面