在学习 CAD 几何算法时,经常会遇到:
这些问题背后大量使用了微积分。
对于几何建模,可以先建立一个非常直观的认识:
导数负责描述一个几何对象在局部是怎样变化的;积分负责把无数个局部的小量累加成一个整体。
可以简单记成:
导数
↓
局部
积分
↓
整体
例如:
Curve
↓ 导数
局部切线、速度
↓ 积分
整条 Curve 的长度
曲面也是一样:
Surface
↓ 偏导数
局部切向量
↓
局部面积
↓ 积分
整个 Surface 面积
假设有一个函数:
导数:
可以理解成:
当 发生一个非常小的变化时, 变化得有多快。
数学定义:
其中:
f(x + Δx) - f(x)
-----------------
Δx
表示:
y 的变化量 / x 的变化量。
当 越来越小时,就得到这一点的瞬时变化率。
从几何上来说:
导数就是曲线在这一点的切线斜率。
CAD 中的 Curve 一般不是简单的:
而通常使用参数曲线:
例如:
t = 0.0 → P0
t = 0.1 → P1
t = 0.2 → P2
...
随着参数 发生变化,一个点沿着 Curve 运动。
对参数曲线求导:
得到的不再是一个数字,而是一个向量。
这个向量表示:
Curve 在参数 处的瞬时运动方向以及运动速度。
因此:
C'(t)
↓
切向量
这就是 CAD Kernel 中常见的:
curve->D1(u, point, tangent);
这一类 API 背后的数学含义。
参数曲线:
一阶导数:
主要描述:
曲线往哪个方向走。
也就是切向量。
而二阶导数:
描述的是:
曲线的运动方向本身变化得有多快。
因此二阶导数与:
曲率
弯曲程度
密切相关。
可以粗略理解:
C(t)
↓
位置
C'(t)
↓
切线 / 速度
C''(t)
↓
切线变化 / 加速度 / 曲率
这也是为什么 B-Spline、Bezier 等几何 API 经常提供:
D0
D1
D2
D3
这样的求值接口。
积分可以先理解成:
把无数个非常小的量加起来。
假设:
希望计算从 到 的曲线下方面积。
把区间切成很多小段:
每个小长方形面积约为:
所以:
如果让:
这些长方形越来越窄、数量越来越多,就得到:
因此积分符号:
可以先理解成:
不断累加。
积分公式里经常会看到:
可以直观理解成:
x 方向上一个无限小的长度。
类似地:
ds → 一个无限小的曲线长度
dA → 一个无限小的面积
dV → 一个无限小的体积
于是:
表示:
把所有小长度累加起来。
而:
表示:
把所有小面积累加起来。
所以:
长度 = 小长度的累加
面积 = 小面积的累加
体积 = 小体积的累加
这是理解几何积分最重要的直觉。
例如:
这里表示:
t 从 0 到 1
整个过程中值始终为 5
积分就是一个矩形的面积:
高度 = 5
宽度 = 1 - 0 = 1
所以:
一般来说:
例如:
如果把 5 理解成速度,那么就是:
速度 = 5
时间 = 3
路程 = 5 × 3 = 15
这与我们后面计算曲线长度的思想完全一致。
假设参数曲线:
参数范围:
希望计算真实曲线长度。
不能简单计算:
因为这只是两个端点之间的直线距离。
例如:
********
*** ***
A * * B
真实长度:
沿着 ****
端点距离:
A ---------------- B
所以必须计算曲线本身的长度。
假设参数变化了一个很小的:
那么:
这一小段 Curve 已经非常接近直线。
根据三维勾股定理:
代入:
而:
所以:
最终得到:
它其实就是:
速度 × 一个非常小的时间 = 一个非常小的路程。
现在已经知道一个小曲线段:
那么把整条 Curve 上所有小长度累加:
于是:
这就是参数曲线的长度公式。
这里导数和积分分别承担:
C'(t)
↓
计算某一点附近的局部长度变化
积分
↓
把所有局部长度累加起来
假设:
参数:
求导:
因此:
整个过程中速度始终为 5。
所以:
得到:
实际上 Curve:
t = 0 → (0,0)
t = 1 → (3,4)
它是一条直线,所以:
两种计算结果一致。
对于 Line:
可以直接得到解析结果。
对于圆弧:
也有解析公式。
但是对于复杂 B-Spline:
虽然仍然满足:
但这个积分通常很难得到简单的解析表达式。
于是 CAD Kernel 通常会采用:
Numerical Integration,数值积分。
数值积分的思想仍然是:
采样,然后逼近积分结果。
例如:
把参数区间切成:
0 0.1 0.2 0.3 ... 1
│ │ │ │ │
↓ ↓ ↓ ↓ ↓
计算 ||C'(t)||
然后近似累加:
理论上采样越密,通常结果越精确。
实际 Geometry Kernel 往往会采用:
其中 CAD 几何算法中比较常见的是高斯积分以及自适应积分。
假设 Curve 某个区域变化非常平缓:
────────────────────
这里没有必要大量计算。
但某个区域变化非常快:
__
_/ \_
____/ \____
这里需要更多采样。
所以自适应积分可以:
计算当前区间
↓
估算误差
↓
误差满足要求?
/ \
YES NO
↓ ↓
接受结果 把区间细分
↓
再计算
这和 CAD Tessellation 的:
误差过大
↓
增加细分
思想非常接近。
最简单的面积问题:
在:
之间的面积:
因为每一小块面积:
于是:
仍然是:
局部小面积
+
局部小面积
+
局部小面积
+
...
=
总面积
CAD 中的 Surface 通常表示为:
例如:
Plane
Cylinder
Sphere
Bezier Surface
B-Spline Surface
NURBS Surface
曲面有两个参数方向:
u
v
因此需要分别求导:
以及:
这里叫做:
偏导数。
可以理解成:
Su
↓
保持 v 不变,只改变 u 时,Surface 往哪个方向走
Sv
↓
保持 u 不变,只改变 v 时,Surface 往哪个方向走
所以:
和:
都是 Surface 上的切向量。
在 Surface 上:
Sv
↑
│
●──────→ Su
和 都位于曲面的切平面上。
两个向量叉积:
得到一个同时垂直于它们的向量:
N
↑
│
●────→ Su
/
Sv
因此曲面法线:
这就是 CAD Kernel 中计算 Surface Normal 的数学基础之一。
因此:
导数不仅用于长度,也直接参与曲面法线计算。
考虑 Surface 参数空间中一个非常小的区域:
在真实三维曲面上,它近似形成一个小平行四边形。
两个边分别近似:
以及:
平行四边形面积等于两个向量叉积的长度:
所以整个曲面面积:
其中 是 Face 在 UV 参数空间中的有效区域。
可以理解成:
Surface
↓
切成无数非常小的曲面片
dA1
dA2
dA3
...
↓ 全部累加
Surface Area
BRep 中:
Face 不等于完整 Surface。
例如一个 Plane 是无限大的,但 Face 可能只有:
┌──────────────────┐
│ │
│ Face │
│ │
└──────────────────┘
甚至有 Hole:
┌──────────────────┐
│ │
│ ┌────┐ │
│ │Hole│ │
│ └────┘ │
│ │
└──────────────────┘
所以真正计算 BRep Face 面积时:
中的 必须由:
Outer Wire
Inner Wire
P-Curve
共同限定。
也就是说:
Topology 决定积分区域,Geometry 决定区域上每一点的真实几何面积。
这也是 Geometry 与 Topology 分离以后非常典型的配合。
如果 Surface 已经 Tessellation 成:
Triangle 1
Triangle 2
Triangle 3
...
那么也可以计算:
Triangle 面积可以通过:
计算。
Triangle 越密:
Mesh Area
通常越接近真实 Surface Area。
但它仍然只是:
离散 Mesh 的近似结果。
而直接对精确 Surface 进行积分,则是在精确几何模型上计算。
实体体积也使用完全相同的思想。
把 Solid 想象成由无数非常小的体积:
组成:
┌──────────────────┐
│[][][][][][][][][][]│
│[][][][][][][][][][]│
│[][][][][][][][][][]│
│[][][][][][][][][][]│
└──────────────────┘
每一个小块:
把所有小体积累加:
这就是三重积分。
因此:
长度
L = ∫ ds
面积
A = ∬ dA
体积
V = ∭ dV
本质都是:
把无限多个局部小量累加起来。
对于 BRep Solid:
Solid
└── Shell
└── Faces
Kernel 已经拥有完整闭合边界。
数学上可以利用:
Divergence Theorem,散度定理
把三维体积积分:
转换成封闭 Surface 上的积分:
这样就可以:
Solid Volume
↓
转换成
Face Surface Integrals
↓
遍历所有 Face
↓
累加
所以像 OCCT 中的 Volume Properties 并不意味着一定把 Solid 内部真的切成无数小立方体。
数学定理允许 Kernel:
根据实体的边界曲面计算内部体积。
假设一个物体密度均匀。
重心可以直观理解成:
所有小体积的位置进行加权平均。
例如 x 坐标:
同理:
所以:
每个小体积
↓
位置 × 体积
↓
全部累加
↓
除以总体积
↓
Center of Mass
因此 CAD Kernel 中的:
Length Properties
Surface Properties
Volume Properties
Center Of Mass
背后其实都与积分密切相关。
机械 CAD 中还经常需要:
Moment of Inertia
例如某个质量单元距离旋转轴越远,它对惯性的贡献越大。
因此形式类似:
这里:
r
↓
小质量到旋转轴的距离
dm
↓
一个非常小的质量
将所有局部贡献累加,就得到整个实体的惯性矩。
所以 CAD Kernel 的 Mass Properties 通常不仅能计算:
长度
面积
体积
还可能计算:
Center of Mass
Moment of Inertia
Principal Axes
这些都离不开积分。
对于曲线:
一阶导数:
表示切向量。
二阶导数:
描述切向量变化。
因此曲率和:
C'
C''
密切相关。
对于三维参数曲线,曲率可以表示为:
不要求在面试时背这个公式。
只需要知道:
一阶导数描述曲线方向,二阶导数描述方向的变化,因此可以进一步得到曲率。
这对于:
都非常重要。
CAD 中经常看到:
C0
C1
C2
以及:
G0
G1
G2
其中和导数密切相关。
例如两个 Curve 拼接:
只要求:
位置相同
不仅位置相同,还要求一阶导数一致:
切向量相同
进一步要求二阶导数一致:
曲率变化更加平滑
因此导数也是判断:
曲线和曲面之间平滑程度
的重要工具。
这也是 Fillet、Sweep、Surface Modeling 中经常讨论连续性的原因。
几何 Kernel 中大量问题最终会转化成:
求一个方程的根。
例如:
Curve / Curve Intersection
Curve / Surface Intersection
Surface / Surface Intersection
Closest Point
Projection
很多情况下会使用:
Newton-Raphson Iteration,牛顿迭代。
一维情况下:
Newton 方法:
其中:
就是导数。
导数告诉算法:
当前函数往哪个方向变化、变化有多快。
从而决定下一步应该往哪里迭代。
因此:
导数不仅描述几何,还直接参与几何求解算法。
例如:
找空间点 到 Curve 的最近点。
可以定义距离平方:
最近距离意味着:
达到最小值。
极值点通常满足:
因此:
Closest Point
↓
构造距离函数
↓
求导
↓
求 F'(t)=0
↓
得到候选参数
这就是导数在 Projection、Snap、Closest Point 等 CAD 功能中的应用之一。
Tessellation 也经常需要导数信息。
例如曲面:
通过:
和:
可以计算 Surface Normal。
再比较不同采样位置的 Normal:
N1
N2
如果:
过大:
Angular Deviation 超出要求
↓
进一步 Tessellation
因此:
Surface Derivative
↓
Normal
↓
Angular Deviation
↓
决定 Tessellation 密度
这就是导数与网格离散化之间的联系。
积分和 Tessellation 都有一种:
把连续对象拆成很多局部部分。
的思想,但目的不同。
主要目的是:
精确 Surface
↓
Triangle Mesh
↓
GPU Rendering
得到离散几何表示。
主要目的是:
连续函数
↓
有限采样
↓
逼近积分
↓
得到长度 / 面积 / 体积等数值
两者都可能采用:
误差控制
自适应细分
所以算法思想有很多相似之处。
可以把常见用途总结为:
导数:
Tangent
Curvature
Continuity
Closest Point
Intersection
积分:
Curve Length
Center of Gravity of Wire
Moment
偏导数:
Tangent Direction
Normal
Curvature
Surface Continuity
Projection
Intersection
Tessellation
积分:
Surface Area
Surface Center of Mass
Surface Moments
积分:
Volume
Center of Mass
Moment of Inertia
Mass Properties
如果面试官问:
一个 BRep Edge 对应 B-Spline Curve,怎么计算它的长度?
可以回答:
Edge 会关联底层参数曲线以及它实际使用的参数区间 。对于参数曲线 ,一阶导数 表示曲线相对于参数的局部速度,因此微小弧长为:
整个 Edge 的长度就是:
Line、Circle 等简单解析曲线可以直接使用解析公式,而 B-Spline 等复杂曲线一般通过高斯积分、自适应数值积分等方法计算。
这已经是比较完整的几何算法回答。
可以回答:
对参数曲面 ,分别计算两个参数方向的一阶偏导 和 。两者构成曲面的局部切向量,其叉积的模表示参数空间一个微小区域映射到三维后的面积缩放,因此:
再对 Face 对应的有效 UV 区域进行二重积分:
对于 BRep Face,积分区域 还需要考虑 Outer Wire 和 Inner Wire 对应的边界。
这个回答已经体现了:
Geometry
+
Topology
+
Calculus
三者之间的关系。
可以回答:
从数学定义上,实体体积可以看成对内部所有微小体积 做三重积分:
但对于 BRep Solid,因为已经拥有闭合边界,几何 Kernel 可以利用散度定理把体积积分转换为对边界 Face 的曲面积分,再累加所有 Face 的贡献。因此不需要真正把 Solid 内部离散成大量体素。
这种回答比简单说:
调
VolumeProperties()。
更能体现对底层几何算法的理解。
以后遇到几何公式,可以先问两个问题。
例如:
Curve
→ ds
Surface
→ dA
Solid
→ dV
或者:
Curve
→ C'(t)
Surface
→ Su、Sv
这些通常通过导数得到。
把所有局部量:
ds
dA
dV
通过积分累加。
于是:
几何对象
│
▼
导数
│
描述局部变化规律
│
┌─────────┼─────────┐
▼ ▼ ▼
Tangent Normal Curvature
│
▼
微小几何量
ds / dA / dV
│
▼
积分
│
把局部贡献累加
│
┌─────────┼─────────┐
▼ ▼ ▼
Length Area Volume
对于 CAD 几何建模,导数和积分不应该只理解成数学公式。
最重要的是理解它们解决的问题。
描述几何对象局部是如何变化的。
典型应用:
曲线切线
曲面切向量
曲面法线
曲率
连续性
最近点
投影
几何求交
Newton 迭代
Tessellation
把无数个局部的小量累加成一个整体。
最重要的三个公式可以理解为:
表示小长度累加成曲线长度。
表示小面积累加成曲面面积。
表示小体积累加成实体体积。
而对于参数几何:
以及:
则把导数与积分真正联系起来。
可以最终浓缩成一句话:
导数负责研究几何的“局部”,积分负责把局部累加成“整体”。
这也是为什么从 Curve、Surface 到 BRep Solid,导数和积分会不断出现在 CAD 几何 Kernel 的长度、面积、体积、曲率、质量属性、求交、投影以及网格离散化算法中。