ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FreeCAD教程(二)

FreeCAD教程(二) 第2章 几何表示法总览本章摘要本章系统讲解 CAD 几何表示的三大类方法——隐式/参数/显式三种数学表示、CSG 构造实体几何、B-Rep 边界表示与空间分解法体素/八叉树/BSP/SDF并剖析 FreeCAD 如何以 B-Rep 为中心、通过文档 DAG 让多种表示在同一文档内共存互通。核心要点CSG 靠正则化保证结果永远是合法实体B-Rep 的关键设计是拓扑与几何分离SDF 的布尔运算是简单的 min/max 且圆角免费FreeCAD 的布尔运算是CSG 组织 B-Rep 求值的混合模式。 学习目标写出隐式、参数、显式三种数学表示的一般形式并说出各自擅长的判断/生成任务。理解 CSG 的三要素体素、正则布尔、构造树说清正则化为什么不可省略。理解 B-Rep 的核心思想用边界定义内部以及拓扑与几何分离。认识空间分解法体素/八叉树/BSP/SDF及其在切片、仿真、隐式建模中的复兴。说明 FreeCAD 如何让 B-Rep、网格、CSG、有限元网格四种表示在同一文档内共存。2.1 三种基本数学表示概念讲解任何一个曲面或曲线数学上都有三种写法它们各有擅长① 隐式表示 f(x, y, z) 0半径 R 的球面写作 x² y² z² − R² 0。-强项内外判断point membership classification极快。把点代入f 0 在内、f 0 在面上、f 0 在外。一次减法一次比较就完成这正是布尔运算和碰撞检测最需要的。② 参数表示 S(u, v) (x(u,v), y(u,v), z(u,v))球面写作 x R·cos(u)·cos(v)y R·cos(u)·sin(v)z R·sin(u)其中 u ∈ [−π/2, π/2]v ∈ [0, 2π]。。-强项生成点极快。给定 (u, v) 直接算出坐标天然适合镶嵌、渲染、生成刀路、算法线、算切向。而且有天然的参数域概念方便做局部裁剪。弱项内外判断难。给一个空间点要反求 (u, v) 需要迭代求解昂贵且可能不收敛。③ 显式表示 z f(x, y)是参数表示的退化特例令 ux, vy。强项最简单存储小。致命弱项无法表达多值面。球面上同一个 (x,y) 对应上下两个 z显式写不出来。所以显式只能用于地形、高度场不能用于通用 CAD。FreeCAD/OCCT 的选择B-Rep 的几何层几乎全部使用参数表示。你在 Python 里对一个面调用face.Surface得到的就是参数曲面对象调用face.ParameterRange得到 (uMin, uMax, vMin, vMax)。而在布尔运算内部OCCT 会对平面、球、柱这类解析曲面临时启用隐式判断来加速。两种表示各取所长这是现代内核的常态。操作步骤在 FreeCAD 里看见参数表示Part → 基本体 → 球体Radius10其余默认。打开视图 → 面板 → Python 控制台。输入s App.ActiveDocument.Sphere.Shape.Faces[0]回车。输入s.Surface回车 —— 输出类似Sphere (Position : (0,0,0), Radius : 10)这就是解析曲面对象。输入s.ParameterRange回车 —— 输出四个数即 u、v 的取值区间。输入s.valueAt(0, 0)回车 —— 用参数直接算出面上一点的坐标。输入s.normalAt(0, 0)回车 —— 得到该点的法向量。第 6、7 步就是参数表示生成点快的直接体现。配图说明功能示意图三栏对比图。左栏画一个球并写出x²y²z²−R²0配一个点和代入判断内/外的图示中栏画同一个球画出 u、v 参数网格线覆盖球面标注给 (u,v) 直接得点右栏画一片地形高度场并写zf(x,y)旁边画一个球被打上红叉注明多值面无法表达。2.2 CSG 构造实体几何概念讲解CSGConstructive Solid Geometry构造实体几何的思想极其简洁复杂形状 简单形状经过布尔运算组合。它有三个要素① 体素primitives一组预定义的基本实体——长方体、圆柱、圆锥、球、圆环、楔形、半空间。每个体素都用隐式不等式定义了一个内部区域。② 正则布尔运算regularized Boolean并∪*、交∩*、差−*。注意那个星号它代表正则化。③ 构造树CSG tree一棵二叉树叶子是体素内部节点是布尔运算符和变换矩阵。形状本身不被显式存储只存储配方。为什么必须正则化这是 CSG 理论中最重要、也最常被跳过的一点。考虑两个正方体恰好面对面接触不重叠只共享一个面。做普通集合交集结果是什么是那个二维的面——一个没有体积的薄片。再考虑一个正方体和另一个正方体相交后可能留下孤立的点、悬挂的边、零厚度的面。这些叫悬挂结构dangling structures它们在数学上是合法的点集但在物理上不是实体——你无法制造一个零厚度的面。正则化运算定义为对普通布尔结果先取内部interior再取闭包closure。A ∪* B closure( interior( A ∪ B ) )这一步的作用就是把所有低维的悬挂结构擦掉只保留有实体体积的部分再把边界补回来。这保证了CSG 运算的结果永远是一个合法实体——这个性质叫闭合性closure property是 CSG 最大的理论优势。CSG 的优缺点优点表示紧凑一棵树几十字节就能描述复杂形状天生有效永远不会产生病态实体内外判断快沿树递归即可编辑历史天然保留改叶子参数重算整棵树缺点无法表达自由曲面体素库是有限的难以做圆角、倒角、拔模这些不是布尔能表达的表示不唯一同一形状可以有无数棵不同的树不直接存储边界渲染和加工前必须现场计算边界“边界求值 boundary evaluation”慢配图说明功能示意图绘制一棵 CSG 构造树。根节点为差集 −*“左子树为并集 ∪*”其两个叶子分别是立方体 40×40×20和圆柱 R20 H20右子树是叶子圆柱 R8 H50。每个节点旁边画出该节点对应的三维小图最终根节点旁画出成品——一个带圆头的板上钻了通孔。另在图侧单独画一个小插图演示正则化两个立方体面接触 → 普通交集得到红色薄片 → 正则交集得到空集。操作步骤在 FreeCAD 中体验 CSGFreeCAD 的Part 工作台布尔运算本质就是 CSG 建树只不过它同时把边界算了出来B-Rep 结果。真正的纯 CSG 在OpenSCAD 工作台。Part → 基本体 → 立方体Length40、Width40、Height20。Part → 基本体 → 圆柱体Radius20、Height20Placement Position 设为 (20, 20, 0)。同时选中两者 →Part → 布尔运算 → 并集Union。模型树中出现Fusion展开它两个原始体素仍然作为子节点存在——这就是构造树。Part → 基本体 → 圆柱体Radius8、Height50Position 设为 (20, 20, −15)上下都穿出规避共面。选中Fusion和新圆柱 →Part → 布尔运算 → 切割Cut。展开模型树你会看到一棵完整的树Cut → [Fusion → [Box, Cylinder], Cylinder001]。现在双击最底层的Box把 Length 改成 60回车。整棵树自动重算——这就是 CSG 的参数化威力。参数说明参数位置默认值说明Refine布尔结果对象的属性面板false可在首选项改为默认 true是否自动清除布尔产生的多余共面边。建议开启首选项 → Part 设计 → 布尔运算后自动精炼首选项关闭打开后所有布尔结果自动 Refine布尔运算引擎首选项 → Part 设计 → 常规OCC 默认BOPOCCT 的通用布尔算法2.3 B-Rep 边界表示概念讲解B-RepBoundary Representation边界表示** 的核心思想是用物体的边界皮来定义物体本身瓤。一个封闭的、定向的曲面把三维空间分成内和外两部分。只要这层皮是封闭的、法向一致朝外的那么皮所包围的空间就是这个实体。所以 B-Rep 只需要存储边界不需要存储内部。内部。B-Rep 最关键的设计是拓扑与几何分离*-拓扑Topology回答谁连着谁。这个面由哪几条边围成这条边的两个端点是哪两个顶点这条边被哪两个面共享拓扑只关心连接关系**不关心形状。几何Geometry回答具体在哪、什么形状。这个面是半径 20 的圆柱面还是平面这条边是直线还是圆弧这个顶点的坐标是多少多少为什么要分离三个原因拓扑不变、几何可变把一个立方体的边倒圆角拓扑结构6 面 12 边 8 点 → 变成 26 面变了但如果只是把 Length 从 10 改成 20拓扑完全不变只有几何数据在变。参数化建模的重算过程就靠这个拓扑结构复用只重算几何。同一几何可被多个拓扑引用两个相邻的面共享一条边这条边的曲线几何只存一份两个面各自引用它。省内存也保证了共享边一定严格一致。算法解耦遍历模型结构比如找出所有平面只需要走拓扑求交则只需要几何。B-Rep 的优缺点优点能精确表达任意复杂形状包括 NURBS 自由曲面边界已经算好渲染/加工/测量直接可用支持圆角、抽壳、拔模这类局部操作。缺点数据结构复杂、易出错——正因为边界是显式存的就可能存错面之间有缝、法向反了、边比容差还短。这些病态是 CSG 天生没有的CSG 保证有效性也正是第 3 章的主题。FreeCAD 里的体现Part和PartDesign产出的所有对象都是 B-RepOCCT 的TopoDS_Shape。你在 Python 控制台里访问obj.Shape.Faces得到的就是拓扑面列表而face.Surface才是它挂载的几何曲面。这个两层结构第 3 章会详细拆开。2.4 空间分解法概念讲解第三大类表示法不描述边界也不用布而是把空间切成一堆小块标记每块是“实”还是“空”。**。① 体素Voxel把空间划成规则的三维网格相当于三维像素。每个体素存一个占据标志或密度值。优点结构极简布尔运算就是逐体素的与/或/非永远不会失败天然支持 CT/MRI 这类扫描数据。缺点内存随分辨率的三次方增长。1000³ 的网格就是十亿个体素。边界呈阶梯状。② 八叉树Octree体素的自适应压缩版。从一个大立方体开始如果它完全在内或完全在外就停止细分如果跨边界就切成 8 个子立方体递归。优点只在边界附近细分内存从 O(n³) 降到接近 O(n²)。用途碰撞检测加速、层次包围盒、稀疏体素渲染。③ BSP 树Binary Space Partitioning用任意方向的平面而不是轴对齐的格子递归二分空间。每个内部节点是一个分割平面叶子标记实/空。优点能精确表达多面体不产生阶梯且天然给出前后排序。用途早期游戏引擎渲染排序、凸分解、多面体布尔。**④ SDFSigned Distance Field符号距离场在每个采样点存“到最近表面的有符号距离”内为负外为正。为正。这是隐式表示的离散化版本。优点极其突出布尔运算是简单的 min/max并min交max差max(a,−b)永不失败圆角是免费的把 min 换成“平滑 min”就自动得到倒圆到倒圆偏移/加厚只需给距离值加一个常数天然适合光线步进ray marching渲染。缺点精度受采样分辨率限制转回精确 B-Rep 依然困为什么说它们在“复活”曾经空间分解被认为是“精度不够的玩具”但近年在四个方向强势回归势回归3D 打印切片切片器本质就是把模型按层做平面求交很多现代切片器内部用体素/SDF 处理修复破损模型和生成支撑。CAE 有限元/有限体积仿真必须把连续体离散成单元。FreeCAD 的FEM工作台用 Gmsh/Netgen 把 B-Rep 划分成四面体/六面体网格——这就是一种空间分解。拓扑优化 / 生成式设计优化算法在体素密度场上迭代SIMP 方法输出是密度分布。隐式建模新一代 CADnTopology 等软件用 SDF 做晶格结构、变密度点阵这类形状 B-Rep 根本存不下几百万个小杆件。配图说明功能示意图2×2左上“体素”一个球被规则立方格子填充边界呈阶梯状右上“八叉树”同一个球只有靠近表面的格子被细分成小格内部是大格左下“BSP”一个多边形被若干斜向直线递归分割画出对应的二叉树右下“SDF”一个球的剖面用颜色渐变表示到表面的距离内部蓝→负值表面白→0外部红→正值并在旁边写出union min(a,b)、smooth union → 自动圆角。动圆角。2.5 混合表示与 FreeCAD 的取舍概念讲解现实中没有一种表示能包打天下所有成熟 CAD 都是混合表示hybrid representation。FreeCAD 的选择非常清晰FreeCAD 模块内部表示数据类型典型对象Part/PartDesign/Sketcher/Surface/BIMB-Rep精确Part::TopoShape封装 OCCTTopoDS_ShapeBox、Pad、Pocket、墙体Mesh三角网格离散Mesh::MeshObject导入的 STLPoints点云Points::PointKernel扫描点云OpenSCADCSG 树解析.scad后转成 Part 对象导入的 OpenSCAD 脚本FEM有限元网格Fem::FemMesh四面体网格、结果场它们怎么在同一个文档里共存关键在 FreeCAD 的文档对象模型DAG架构.FCStd文档是一个有向无环图每个节点是一个App::DocumentObject它有若干属性Property。几何数据只是其中一个属性——Part::Feature有Shape属性B-RepMesh::Feature有Mesh属性网格Fem::FemMeshObject有FemMesh属性。文档本身不关心属性里装的是什么表示它只负责记录对象之间的依赖关系谁引用谁在参数变化时按拓扑序触发重算recompute持久化到 zip 包里B-Rep 存成.brp文件网格存成二进制块参数存成 XML。跨表示的桥梁命令这些是转换器节点转换命令位置说明B-Rep → 网格Mesh 工作台 → 网格 → 从形状创建网格有损可设精度网格 → B-RepPart 工作台 → Part → 从网格创建形状得到平面片拼成的伪实体B-Rep → 有限元网格FEM 工作台 → 网格 → Gmsh / Netgen用于分析CSG → B-RepOpenSCAD 工作台 → 导入 .scad自动求值边界点云 → 曲面ReverseEngineering 工作台拟合需人工判FreeCAD 的取舍逻辑以B-Rep 为中心其他表示都是“外围”通过显式的转换节点接入。节点接入。这与 Blender以网格为中心、OpenSCAD以 CSG 为中心形成鲜明对比。这个选择的代价是继承了 B-Rep 的所有病态问题收益是能出图、能加工、能标 配图说明步骤流程图中央画一个大方框标“FreeCAD 文档DAG”内部并排四个不同颜色的对象节点——“Part::FeatureB-Rep”“Mesh::Feature三角网格”“Points点云”“Fem::FemMesh有限元网格”。四者之间用带命令名的箭头连接“从形状创建网格”“从网格创建形状”“Gmsh 网格划分”“曲面拟合”。方框下方画一条时间轴表示 recompute 顺序注明“参数改变 → 按依赖拓扑序自动重算”。自动重算。实际案例一个文档四种表示新建文档。切到Part工作台Part → 基本体 → 圆柱体Radius10、Height30。切到Mesh工作台选中圆柱网格 → 从形状创建网格算法选标准Standard表面偏差填0.10。文档中出现第二个对象 Cylinder (Mesh3. 切到FEM工作台选中原始圆柱 →分析容器→ 在分析下网格 → 由形状生成 FEM 网格Gmsh最大单元尺寸填3.0 mm点“应用”。点应用。文档中出现第三种表示。现在模型树里同时存在B-Rep 圆柱、三角网格、有限元四面体网格——同一个几何三种表示。双击原始圆柱把 Radius 改成15回车然后按刷新RefreshCtrlR。B-Rep 立即更新网格对象因为依赖它也会重算FEM 网格需要手动重新生成FEM 网格通常不自动重算以免大模型卡死。这个案例把 2.5 节讲的共存 依赖 重算全部串了起来。❓ 常见问题解答Q1既然 CSG 永远不会失败为什么 FreeCAD 不干脆全用 CSGA因为 CSG 表达不了自由曲面、也做不了圆角和拔模。手机外壳、汽车覆盖件、人体工学手柄用体素布尔根CSG 的“永不失败”是用“表达能力受限”换来的。限换来的。FreeCAD 的做法是布尔运算的组织方式借鉴 CSG保留构造树但结果用 B-Rep 存储这样既有参数化又有表达力。Q2Part 工作台的布尔运算到底是 CSG 还是 B-RepA两者都是。模型树里保留的父子结构是CSG 构造树可以回溯修改叶子参数但每次布尔运算都会立即调用 OCCT 计算出**精确的 B-Rep 边界*所以它是“CSG 组织 B-Rep 求值”的混合模式业界主流做法。界主流做法。Q3为什么我做完布尔以后一个原本平整的面上多了一条边A这是布尔运算的正常副产品——两个共面区域被合并时OCCT 保留了原来的分界线。用Part → 精炼形状Refine shape可以清除也可以在编辑 → 首选项 → Part 设计里开启“布尔运算后自动精炼”一劳永逸。一劳永逸。但注意Refine 会改变面和边的编号可能触发拓扑命名问题第 3.6 节。Q4SDF 听起来这么好FreeCAD 支持吗AFreeCAD 1.1 主线不支持 SDF 建模。如果你需要做点阵、晶格、变密度结构可以考虑外部工具或通过 Python 生成网格再导入。FEM 的拓扑优化插件在某种意义上是体素密度法的应用。Q5隐式、参数、显式三种表示我平时建模时需要意识到吗A日常点鼠标不需要但两个场合需要① 写 Python 脚本操作几何时valueAt(u,v)、ParameterRange这些都是参数② 理解“为什么曲面上取点容易、判断点在不在实体内难”时这套理论能给你直觉。能给你直觉。 本章小结三种数学表示隐式擅长内外判断、参数擅长生成点、显式最简单但无法表达多值面。OCCT 以参数表示为主布尔时局部借用隐式加速。CSG 体素 正则布尔 构造树。正则化 closure(interior(·))作用是擦掉零厚度面、悬挂边这类非实体产物从而保证结果永远是合法实体闭合性。B-Rep 用边界定义实体核心设计是拓扑与几何分离——拓扑管连接关系几何管形状与位置。它表达力最强但也最容易产生病态数据。空间分解法体素/八叉树/BSP/SDF曾被认为精度不足如今在切片、有限元、拓扑优化、隐式建模四个方向强势回归。SDF 的布尔是 min/max圆角免费。FreeCAD 是以 B-Rep 为中心的混合系统Part/PartDesign/Sketcher/Surface/BIM 用 B-RepMesh 用三角网格Points 用点云FEM 用有限元网格OpenSCAD 工作台承载 CSG。它们通过文档 DAG 共存通过显式转换命令互通。✏️ 练习题用 Part 工作搭出一个“带四个安装孔的 L 形支架” 底板 80 × 60 × 8立板 80 × 8 × 50四个 φ6 通孔。 φ6 通孔。要求所有孔的圆柱都上下穿出至少 5 mm。完成后展开模型树手绘出它的 CSG 构造树。在 Pytho对一个 Radius 25 的球面执行5 的球面执行f.Surface、f.ParameterRange、f.valueAt(0.5, 1.0)、f.normalAt(0.5, 1.0)然后解释为什么用valueAt取点很快而“判断点 (10, 10, 10) 是否在球内”需要用shape.isInside() 这样的另一套方法的另一套举出两个“用 SDF/体素比用 B-Rep 更合适”的实际设计场景并说明理由。景并说明理由✅ 参考答案第 1 题L 形支架的 CSG 构造树用文字描述树形层次如下根节点为差集左子树为并集右子树为四个通孔圆柱Cut差集 −* ├── Fusion并集 ∪* │ ├── Box底板 80×60×8 │ └── Box001立板 80×8×50 └── 四个 φ6 通孔圆柱Cylinder001 ~ Cylinder004 ├── Cylinder001φ6上下穿出 ≥5 mm ├── Cylinder002φ6上下穿出 ≥5 mm ├── Cylinder003φ6上下穿出 ≥5 mm └── Cylinder004φ6上下穿出 ≥5 mm要点先对底板与立板做并集得到 L 形主体再对主体与四个通孔圆柱做差集。四个孔圆柱必须上下穿出至少 5 mm是为了避免与主体共面——否则普通布尔可能留下零厚度悬挂面需要正则化才能得到合法实体。第 2 题valueAt 与 isInside -valueAt(u, v)走的是参数求值**给定参数域坐标 (u,v)直接代入参数方程S(u,v)算出面上点的坐标。这是“生成点”路径一次代入即得结果所以极快。果所以极快。shape.isInside(point)走的是隐式判断给定一个空间点需要判断它相对实体边界的内外关系。对参数曲面而言这通常要反求参数、做迭代求解或沿边界做包含性测试昂贵且可一句话总结valueAt是“由参数到点”的正向生成isInside是“由点到实体”的反向判断——前者是参数表示的强项后者是隐式表示的强项二者互补。项二者互补。第 3 题SDF/体素优于 B-Rep 的两个场景3D 打印切片修复切片器常遇到破损或非流形的 STL 模型体素/SDF 能先把模型离散成体素场、自动修复缝隙和悬挂结构再逐层求交生成支撑。理由体素布尔是逐格子的与/或/非永不失败天然容错而 B-Rep 对破损边界会直接报错。拓扑优化 / 生成式设计优化算法在体素密度场上迭代SIMP 方法输出本身就是密度分布。理由优化过程天然工作在离散密度场上体素表示与算法数据结构一致无需像 B-Rep 那样反复。。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进