第2章 B-Rep边界表示法 — 习题与答案

基础、进阶、挑战、思考四级别习题,全部附带详细解析


摘要: 本文围绕 B-Rep 边界表示法整理了 20 道习题与详细解析,按基础、进阶、挑战、思考四个难度递进。内容覆盖 B-Rep 的几何与拓扑分离、6 层拓扑元素、欧拉公式与欧拉-庞加莱公式验证、半边结构与 OCCT 享元模式、面环方向、自由边检测、带孔方块构建、拉伸与旋转的本质区别、法线变换公式、扫掠建模挑战、B-Rep 验证与修复,以及混合架构、非流形拓扑、数据交换、辐射边结构和布尔运算鲁棒性等进阶话题,适合用于巩固概念与备考复习。

习题目录


基础练习 {#basic}

这些习题直接应用 B-Rep 基本概念,适合巩固基础知识。

习题 2.1 B-Rep核心概念

B-Rep 将实体分为哪两个部分?分别举例说明。

显示答案

答案:

B-Rep 将实体分为**几何(Geometry)拓扑(Topology)**两部分:

几何: 描述形状的位置和形状信息。
例如:点的坐标 (1,2,3)、圆的方程 (x-2)²+(y-3)²=25、平面的法向量 (0,0,1)。

拓扑: 描述几何元素之间的连接关系。
例如:面 A 由边 1、2、3、4 围成,边 1 由顶点 V1 和 V2 界定,面 A 和面 B 共享边 1。

几何与拓扑的分离是 B-Rep 设计的核心原则,使得相同的拓扑结构可以承载不同的几何信息。

习题 2.2 拓扑元素层级

列出 B-Rep 的 6 层拓扑元素,从大到小排列,并说明每层的 OCCT 类名。

显示答案

答案:

1. 体(Solid) - TopoDS_Solid - 由壳围成的封闭三维区域
2. 壳(Shell) - TopoDS_Shell - 由一组面组成的封闭或不封闭曲面
3. 面(Face) - TopoDS_Face - 曲面上由环界定的有限区域
4. 环(Wire) - TopoDS_Wire - 由首尾相连的边组成的封闭或不封闭序列
5. 边(Edge) - TopoDS_Edge - 曲线上由两个顶点界定的有界线段
6. 顶点(Vertex) - TopoDS_Vertex - 三维空间中的点

维度依次为:3D、2D、2D、1D、1D、0D。

习题 2.3 欧拉公式验证

一个五棱柱有多少个顶点、边和面?验证欧拉公式 V-E+F=2。

显示答案

答案:

五棱柱:底面五边形 + 顶面五边形 + 5个侧面四边形

V = 10(5个底顶点 + 5个顶顶点)
E = 15(5条底边 + 5条顶边 + 5条侧棱)
F = 7(2个五边形底面 + 5个四边形侧面)

验证:V - E + F = 10 - 15 + 7 = 2

习题 2.4 六棱锥欧拉公式

一个六棱锥(底面为六边形,顶点汇聚于一点)的顶点数、边数和面数各是多少?验证欧拉公式。

显示答案

答案:

六棱锥:底面六边形 + 1个顶点(锥顶)+ 6个三角形侧面

V = 7(6个底顶点 + 1个锥顶)
E = 12(6条底边 + 6条侧棱)
F = 7(1个六边形底面 + 6个三角形侧面)

验证:V - E + F = 7 - 12 + 7 = 2

习题 2.5 半边结构基本概念

在半边数据结构中,半边的 “twin” 指针指向什么?如果没有 twin 指针,哪些操作会变得困难?

显示答案

答案:

twin 指针指向方向相反的半边(即相邻面的同一条几何边所对应的另一条半边)。

如果没有 twin 指针,以下操作会变得困难或低效:
(1) 无法从面 A 的边快速找到相邻面 B
(2) 无法从一条边快速获取两个端点
(3) 无法从顶点快速遍历其邻接面
(4) 布尔运算中无法高效地查找相邻信息
(5) 无法高效遍历顶点的1-邻域(所有邻接边和面)

twin 指针是半边结构实现 O(1) 邻接查询的关键。


进阶练习 {#intermediate}

这些习题需要多步推导,组合多个 B-Rep 概念。

习题 2.6 带孔立方体欧拉公式

一个带有一个通孔的立方体(即手柄数为 1),V=16, E=32, F=16,问是否满足欧拉-庞加莱公式?

显示答案

答案:

欧拉-庞加莱公式:V - E + F - S = 2 - 2G

V=16, E=32, F=16, S=1(一个壳),G=1(一个通孔 = 一个手柄)
V - E + F - S = 16 - 32 + 16 - 1 = -1
2 - 2G = 2 - 2 = 0
-1 ≠ 0,不满足欧拉-庞加莱公式!

实际上,题目中给出的参数有问题。对于带盲孔的立方体,正确的参数应为 V=16, E=24, F=10,此时 V - E + F = 2,满足欧拉公式。
而对于真正的通孔(G=1),需要更多元素来形成手柄结构,参数会有所不同。

习题 2.7 面环方向

在 B-Rep 中,一个面的外环和内环的方向应该是什么?为什么?

显示答案

答案:

外环(Outer Wire): 逆时针方向(从曲面外侧看)
内环(Inner Wire): 顺时针方向(从曲面外侧看)

原因: 根据右手定则,逆时针方向的外环使得面的法线指向外侧(向外)。内环采用相反方向,表示“去除”的区域。在布尔运算中,方向一致性是正确计算结果的前提。

如果方向错误,可能导致:布尔运算结果不正确、面的内外判定出错、渲染出现“破面”。

习题 2.8 半边结构面遍历

在半边数据结构中,给定一个面,描述如何遍历构成该面的所有边(时间复杂度是多少?)。

显示答案

答案:

算法:

  1. 从面存储的半边引用(起始半边)开始
  2. 沿当前半边的next指针移动到下一条半边
  3. 每次访问的半边包含了对应边的引用
  4. 重复步骤2-3,直到回到起始半边

伪代码:

he = face.halfEdge
do {
  edge = he.edge  // 访问该边
  he = he.next    // 下一条半边
} while (he != face.halfEdge)

时间复杂度: O(k),其中k是构成面的边数。每个面被访问一次,每条边(的半边)被访问一次。

习题 2.9 OCCT 享元模式

在 OCCT 中,TopoDS_Shape、TopoDS_TShape 和 Location 之间是什么关系?

显示答案

答案:

TopoDS_Shape 是外观类(Facade),用户通过它操作形状。它内部包含三个部分:

(1) TopoDS_TShape 指针: 指向实际拓扑数据的智能指针。TShape 存储了拓扑元素的不可变信息(如面的曲面、边的曲线、顶点的点)。多个 TopoDS_Shape 可以共享同一个 TShape。
(2) Location: 一个 gp_Trsf 变换矩阵,定义了形状的位置。两个相同的形状可以共享同一个 TShape 但有不同的 Location。
(3) Orientation: 朝向(FORWARD/REVERSED/INTERNAL/EXTERNAL),表示该形状的使用方向。

这种设计实现了享元模式:TShape 是不变且共享的,Location 和 Orientation 是可变且可定制的,大幅节省了内存。

习题 2.10 自由边问题

如果一个模型中存在“自由边”(即只被一个面使用的边),这意味着什么?BRepCheck_Analyzer 会报告什么?

显示答案

答案:

自由边的含义: 自由边意味着模型在边界处“开口”,不是水密实体。在 B-Rep 中,每条边应该被恰好两个面共享(对于封闭实体),自由边意味着面的边界没有闭合。

可能的后果:
(1) 模型不是封闭的实体,而是开放的壳
(2) 布尔运算可能失败
(3) 无法确定点在模型内部还是外部
(4) 渲染时可能出现“破面”

BRepCheck_Analyzer 的响应:
BRepCheck_Analyzer 会检查每条边是否被恰好两个面共享。如果发现自由边,会报告对应的检查失败。在 OCCT 中,BRepCheck_Edge 会返回 BRepCheck_Invalid 或类似的错误状态,具体取决于自由边的类型和上下文。


挑战题 {#advanced}

这些习题需要深入理解 B-Rep 概念,综合应用多个知识点。

习题 2.11 B-Rep构建带孔方块

描述用 B-Rep 构建一个带孔方块(一个方块中间有一个圆柱形通孔)的步骤。

显示答案

答案:

步骤:

方法一:布尔差运算
(1) 用 BRepPrimAPI_MakeBox 创建方块。
(2) 用 BRepPrimAPI_MakeCylinder 创建圆柱(半径等于孔半径,高度大于方块高度,确保完全穿透)。
(3) 将圆柱移动到方块中心:使用 gp_Trsf.SetTranslation() 移动圆柱位置。
(4) 用 BRepAlgoAPI_Cut 做布尔差运算,从方块中减去圆柱。
(5) 使用 BRepCheck_Analyzer 验证结果有效性。

方法二:扫掠+差运算
(1) 在方块的一个面上画圆轮廓。
(2) 拉伸圆轮廓形成贯穿方块的圆柱体。
(3) 用布尔差运算从方块中减去圆柱体。

注意: 圆柱的高度应大于方块的高度,以确保完全穿透而不是产生“盲孔”。

习题 2.12 拉伸 vs 旋转本质区别

拉伸和旋转建模的本质区别是什么?

显示答案

答案:

本质区别:

拉伸(Extrude/Prism): 是平移变换——轮廓沿直线路径移动,结果是“棱柱”形状。拉伸生成的曲面是直纹面(Ruled Surface),即由直线段沿曲线扫掠形成的曲面。

旋转(Revolve): 是旋转变换——轮廓绕轴旋转,结果是"轴对称"形状。旋转生成的曲面是旋转面(Surface of Revolution),即由曲线绕轴旋转形成的曲面。

比较:

  • 拉伸产生的形状在任何横截面上都是相同的轮廓
  • 旋转产生的形状在任何通过轴线的截面上都是相同的轮廓
  • 拉伸适合棱柱、管道等
  • 旋转适合瓶罐、轴类等轴对称零件

习题 2.13 法线变换公式

在 B-Rep 中,为什么法线的变换不能用变换矩阵 M 直接进行,而需要使用 M⁻ᵀ(逆的转置)?

显示答案

答案:

原因: 法线必须始终垂直于切平面。如果使用 M 直接变换法线,在非均匀缩放的情况下,法线会失去垂直性。

数学推导:
设切向量 t 满足 t · n = 0(垂直条件)。
变换后,切向量变为 t’ = Mt
我们需要找到变换后的法线 n’,使得 t’ · n’ = 0。
t’ · n’ = (Mt)ᵀn’ = tᵀMᵀn’
要使上式等于0,需要 Mᵀn’ = n(即 n’ = (Mᵀ)⁻¹n = M⁻ᵀn)。

如果 M 是正交矩阵(如旋转矩阵),M⁻ᵀ = M,所以法线变换矩阵等于变换矩阵本身。但对于非均匀缩放,M⁻ᵀ ≠ M,必须使用 M⁻ᵀ。

习题 2.14 扫掠建模挑战

在 CAD 中,扫掠建模(Sweep)比简单的拉伸/旋转更灵活,但也更复杂。扫掠建模的主要挑战是什么?

显示答案

答案:

扫掠建模的主要挑战包括:

(1) 自相交问题: 当导轨曲率过大时,扫掠轮廓可能自相交,产生非法几何体。例如,沿一个急转弯的导轨扫掠一个大的矩形轮廓时,轮廓的不同部分可能在转弯处相互穿透。

(2) 扭曲控制: 轮廓沿导轨的旋转需要精确控制。如果轮廓在导轨上旋转不当,会产生扭曲的几何体。最小扭转法则(Minimum Twist)是常用的控制策略。

(3) 可变截面: 截面轮廓沿导轨变化时,插值方法的选择会影响结果质量。线性插值可能产生不光滑的过渡,需要使用样条插值。

(4) 导轨不光滑: C1 不连续的导轨会导致扫掠结果出现尖角或裂缝。需要保证导轨至少具有 C1 连续性。

在 OCCT 中,BRepOffsetAPI_MakePipeShell 提供了对这些问题的处理机制。

习题 2.15 B-Rep验证与修复

B-Rep 有效性验证和 ShapeFix 修复工具之间的关系是什么?为什么先验证后修复是一个好习惯?

显示答案

答案:

关系:

BRepCheck_Analyzer 只检测问题但不修复。它检查 B-Rep 形状的每个元素(面、边、顶点),报告哪些元素存在问题以及问题的类型。

ShapeFix_* 系列工具(如 ShapeFix_Face、ShapeFix_Wire、ShapeFix_Edge、ShapeFix_Solid)负责修复检测到的问题。每个工具对应特定的修复任务。

为什么先验证后修复:
(1) 精确定位: 验证可以精确定位问题类型和位置,指导修复策略的选择。
(2) 性能优化: 如果验证通过,可以跳过修复步骤,节省计算资源。
(3) 避免引入新问题: 盲目修复可能引入新的问题。先验证确保我们知道真正需要修复的是什么。
(4) 修复验证闭环: 修复后再次验证,确认问题已解决。

典型流程:
导入模型 → BRepCheck 检查 → 根据错误类型使用对应的 ShapeFix 工具 → 再次验证 → 确认修复成功。


思考题 {#thinking}

这些是开放性问题,需要深入分析和论证。

习题 2.16 混合架构必要性

为什么现代 CAD 系统不单独使用 CSG 或 B-Rep,而是采用混合架构?

显示答案

参考答案:

单独使用 CSG 的问题:
(1) 显示和交互慢——每次需要重新求值,不能直接渲染边界
(2) 不能直接操作边界(如倒角、圆角等局部操作)
(3) 数据交换困难——CSG不是标准交换格式

单独使用 B-Rep 的问题:
(1) 编辑困难——修改后需要重新构建拓扑
(2) 设计历史丢失——无法回溯到之前的版本
(3) 参数化能力弱——修改尺寸需要复杂的操作

混合架构的优势: CSG 树记录设计历史和参数(用户看到的“特征树”),B-Rep 提供快速显示和精确几何操作。当用户修改特征时,系统从 CSG 树重新求值生成新的 B-Rep。两者互补,各取所长。

习题 2.17 非流形拓扑

什么是非流形拓扑?在什么情况下会出现非流形 B-Rep?

显示答案

参考答案:

非流形拓扑: 在流形拓扑中,每个点的邻域都同胚于一个圆盘(2D)或球体(3D)。在非流形拓扑中,存在某些点的邻域不同胚于圆盘或球体。具体来说:

非流形边界条件:
(1) 一条边被3个或更多面共享(非流形边)
(2) 一个顶点周围的面的排列不构成一个圆盘(非流形顶点)
(3) 两个体通过一个点或一条边连接(而不是通过面)

出现非流形的情况:
(1) 布尔运算中的退化情况(如两个面正好相切)
(2) T 形连接(三个面共享一条边)
(3) 薄片厚度为零的模型
(4) 有限元分析中的一些特殊网格

OCCT 的辐射边结构支持非流形拓扑,但大多数 CAD 应用推荐使用流形拓扑。

习题 2.18 数据交换中的 B-Rep 问题

在 CAD 数据交换(如 STEP/IGES 格式)中,B-Rep 模型经常出现“烂面”问题。这是什么原因造成的?如何解决?

显示答案

参考答案:

原因:
(1) 精度差异: 不同 CAD 系统的内部精度不同,导致边界不一致。
(2) 容差不同: 各系统使用的容差机制不同,导致微小的几何差异。
(3) 表示方法差异: 不同系统对 NURBS 曲面的表示存在差异,导致曲面边界不一致。
(4) 曲线曲面逼近: 数据交换时,曲线曲面可能被重新参数化或逼近,引入误差。

解决方案:
(1) 使用 ShapeFix 工具集进行自动修复:ShapeFix_Face 修复面,ShapeFix_Wire 修复环,ShapeFix_Edge 修复边。
(2) 调整容差:适当增大OCCT的容差以适应数据交换的精度损失。
(3) 使用"缝合"(Sewing)操作:BRepBuilderAPI_Sewing 将多个面缝合为封闭实体。
(4) 在导出时设置高精度,尽量减小数据交换中的精度损失。

习题 2.19 半边结构 vs 辐射边结构

半边数据结构与 OCCT 的辐射边结构(Radial Edge Structure)有什么异同?

显示答案

参考答案:

相同点:
(1) 都使用半边(或类似的定向边)概念来表示边的方向
(2) 都支持 O(1) 的邻接关系查询
(3) 都使用 next/prev 指针来遍历面边界

不同点:
(1) 辐射边结构支持非流形拓扑(一条边可以被多个面共享),而半边结构只支持流形拓扑
(2) 辐射边结构在边周围维护了一个“辐射”的面环(radial cycle),每个邻接面都有一条对应的半边
(3) 辐射边结构在边的数据结构中维护了一个环状的“辐射边”链表,连接该边的所有邻接面
(4) 辐射边结构更适合 CAD 中的复杂布尔运算,因为布尔运算经常产生非流形中间结果

OCCT 内部使用辐射边结构的变体,但对外暴露的 TopoDS API 隐藏了这些细节。

习题 2.20 B-Rep布尔运算鲁棒性

在 B-Rep 布尔运算中,数值误差可能导致哪些问题?如何提高布尔运算的鲁棒性?

显示答案

参考答案:

数值误差可能导致的问题:
(1) 面-面相交失败: 两个面应该相交但因数值误差被视为不相交。
(2) 边分类错误: 边在面内的测试结果错误(点在面内 vs. 点在面外)。
(3) 拓扑冲突: 相交结果产生非法的拓扑结构。
(4) 微小特征丢失: 尺寸小于容差的特征被错误地合并或忽略。
(5) 裂纹/间隙: 布尔运算后的面之间存在微小间隙

提高鲁棒性的方法:
(1) 使用模糊容差(SetFuzzyValue)处理微小间隙
(2) 使用精确的几何谓词(如Shewchuk的精确算术)
(3) 适当调整容差,根据模型尺寸选择合适的容差级别
(4) 使用ShapeFix工具修复布尔运算后的结果
(5) 在每次操作前后进行BRepCheck验证
(6) 避免退化情况(如共面、相切)——在操作前检查并处理
(7) 使用"底切"(Under-cut)策略:将圆柱体稍微加长以确保完全穿透


Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐