日期:2024年5月11日标签:Computer Graphics

CAD 几何建模中的导数与积分:从曲线长度到曲面面积与实体体积 #

1. 为什么几何建模需要导数和积分 #

在学习 CAD 几何算法时,经常会遇到:

  • 曲线长度;
  • 曲面面积;
  • Solid 体积;
  • 曲线切线;
  • 曲面法线;
  • 曲率;
  • 最近点;
  • 曲线/曲面求交;
  • 质量、重心、惯性矩;
  • Tessellation。

这些问题背后大量使用了微积分。

对于几何建模,可以先建立一个非常直观的认识:

导数负责描述一个几何对象在局部是怎样变化的;积分负责把无数个局部的小量累加成一个整体。

可以简单记成:

导数
↓
局部

积分
↓
整体

例如:

Curve
  ↓ 导数
局部切线、速度
  ↓ 积分
整条 Curve 的长度

曲面也是一样:

Surface
  ↓ 偏导数
局部切向量
  ↓
局部面积
  ↓ 积分
整个 Surface 面积

2. 什么是导数 #

假设有一个函数:

y=f(x)y=f(x)

导数:

f(x)f'(x)

可以理解成:

xx 发生一个非常小的变化时,yy 变化得有多快。

数学定义:

f(x)=limΔx0f(x+Δx)f(x)Δxf'(x) = \lim_{\Delta x\rightarrow0} \frac{f(x+\Delta x)-f(x)} {\Delta x}

其中:

f(x + Δx) - f(x)
-----------------
        Δx

表示:

y 的变化量 / x 的变化量。

Δx\Delta x 越来越小时,就得到这一点的瞬时变化率。

从几何上来说:

导数就是曲线在这一点的切线斜率。

3. CAD 中的参数曲线 #

CAD 中的 Curve 一般不是简单的:

y=f(x)y=f(x)

而通常使用参数曲线:

C(t)=(x(t),y(t),z(t))C(t) = (x(t),y(t),z(t))

例如:

t = 0.0 → P0
t = 0.1 → P1
t = 0.2 → P2
...

随着参数 tt 发生变化,一个点沿着 Curve 运动。

对参数曲线求导:

C(t)=(x(t),y(t),z(t))C'(t) = (x'(t),y'(t),z'(t))

得到的不再是一个数字,而是一个向量。

这个向量表示:

Curve 在参数 tt 处的瞬时运动方向以及运动速度。

因此:

C'(t)
↓
切向量

这就是 CAD Kernel 中常见的:

curve->D1(u, point, tangent);

这一类 API 背后的数学含义。

4. 一阶导数和二阶导数 #

参数曲线:

C(t)C(t)

一阶导数:

C(t)C'(t)

主要描述:

曲线往哪个方向走。

也就是切向量。

而二阶导数:

C(t)C''(t)

描述的是:

曲线的运动方向本身变化得有多快。

因此二阶导数与:

曲率
弯曲程度

密切相关。

可以粗略理解:

C(t)
↓
位置

C'(t)
↓
切线 / 速度

C''(t)
↓
切线变化 / 加速度 / 曲率

这也是为什么 B-Spline、Bezier 等几何 API 经常提供:

D0
D1
D2
D3

这样的求值接口。

5. 什么是积分 #

积分可以先理解成:

把无数个非常小的量加起来。

假设:

y=f(x)y=f(x)

希望计算从 aabb 的曲线下方面积。

把区间切成很多小段:

Δx\Delta x

每个小长方形面积约为:

f(xi)Δxf(x_i)\Delta x

所以:

Aif(xi)ΔxA \approx \sum_i f(x_i)\Delta x

如果让:

Δx0\Delta x\rightarrow0

这些长方形越来越窄、数量越来越多,就得到:

A=abf(x),dxA= \int_a^b f(x),dx

因此积分符号:

\int

可以先理解成:

不断累加。

6. dx、ds、dA、dV 是什么 #

积分公式里经常会看到:

dxdx

可以直观理解成:

x 方向上一个无限小的长度。

类似地:

ds → 一个无限小的曲线长度

dA → 一个无限小的面积

dV → 一个无限小的体积

于是:

ds\int ds

表示:

把所有小长度累加起来。

而:

dA\int dA

表示:

把所有小面积累加起来。

所以:

长度 = 小长度的累加
面积 = 小面积的累加
体积 = 小体积的累加

这是理解几何积分最重要的直觉。

7. 最简单的积分:常数积分 #

例如:

L=015,dtL= \int_0^1 5,dt

这里表示:

t 从 0 到 1
整个过程中值始终为 5

积分就是一个矩形的面积:

高度 = 5
宽度 = 1 - 0 = 1

所以:

L=5×1=5L=5\times1=5

一般来说:

abc,dt=c(ba)\int_a^b c,dt = c(b-a)

例如:

035,dt=5(30)=15\int_0^3 5,dt = 5(3-0) = 15

如果把 5 理解成速度,那么就是:

速度 = 5
时间 = 3

路程 = 5 × 3 = 15

这与我们后面计算曲线长度的思想完全一致。

8. 为什么曲线长度需要导数和积分 #

假设参数曲线:

C(t)=(x(t),y(t),z(t))C(t) = (x(t),y(t),z(t))

参数范围:

t[t0,t1]t\in[t_0,t_1]

希望计算真实曲线长度。

不能简单计算:

Distance(C(t0),C(t1))Distance(C(t_0),C(t_1))

因为这只是两个端点之间的直线距离。

例如:

       ********
    ***        ***
 A *              * B

真实长度:
沿着 ****

端点距离:
A ---------------- B

所以必须计算曲线本身的长度。

9. 从一个非常小的曲线段开始 #

假设参数变化了一个很小的:

dtdt

那么:

dx=x(t)dtdx=x'(t)dt dy=y(t)dtdy=y'(t)dt dz=z(t)dtdz=z'(t)dt

这一小段 Curve 已经非常接近直线。

根据三维勾股定理:

ds=dx2+dy2+dz2ds = \sqrt{dx^2+dy^2+dz^2}

代入:

ds=x(t)2+y(t)2+z(t)2,dtds = \sqrt{ x'(t)^2+ y'(t)^2+ z'(t)^2 },dt

而:

C(t)=(x(t),y(t),z(t))C'(t) = (x'(t),y'(t),z'(t))

所以:

C(t)=x(t)2+y(t)2+z(t)2|C'(t)| = \sqrt{ x'(t)^2+ y'(t)^2+ z'(t)^2 }

最终得到:

ds=C(t)dt\boxed{ ds=|C'(t)|dt }

它其实就是:

速度 × 一个非常小的时间 = 一个非常小的路程。

10. 整条曲线长度 #

现在已经知道一个小曲线段:

dsds

那么把整条 Curve 上所有小长度累加:

L=dsL=\int ds

于是:

L=t0t1C(t)dt\boxed{ L= \int_{t_0}^{t_1} |C'(t)|dt }

这就是参数曲线的长度公式。

这里导数和积分分别承担:

C'(t)
↓
计算某一点附近的局部长度变化

积分
↓
把所有局部长度累加起来

11. 一个简单的曲线长度例子 #

假设:

C(t)=(3t,4t)C(t)=(3t,4t)

参数:

0t10\le t\le1

求导:

C(t)=(3,4)C'(t)=(3,4)

因此:

C(t)=32+42=5|C'(t)| = \sqrt{3^2+4^2} = 5

整个过程中速度始终为 5。

所以:

L=015dtL= \int_0^1 5dt

得到:

L=5L=5

实际上 Curve:

t = 0 → (0,0)

t = 1 → (3,4)

它是一条直线,所以:

L=32+42=5L=\sqrt{3^2+4^2}=5

两种计算结果一致。

12. B-Spline 曲线长度怎么计算 #

对于 Line:

L=Distance(P0,P1)L=Distance(P_0,P_1)

可以直接得到解析结果。

对于圆弧:

L=RθL=R\theta

也有解析公式。

但是对于复杂 B-Spline:

C(t)C(t)

虽然仍然满足:

L=t0t1C(t)dtL= \int_{t_0}^{t_1} |C'(t)|dt

但这个积分通常很难得到简单的解析表达式。

于是 CAD Kernel 通常会采用:

Numerical Integration,数值积分。

13. 什么是数值积分 #

数值积分的思想仍然是:

采样,然后逼近积分结果。

例如:

L=01C(t)dtL= \int_0^1|C'(t)|dt

把参数区间切成:

0   0.1   0.2   0.3   ...   1
│    │     │     │           │
↓    ↓     ↓     ↓           ↓
计算 ||C'(t)||

然后近似累加:

LiC(ti)ΔtL \approx \sum_i |C'(t_i)|\Delta t

理论上采样越密,通常结果越精确。

实际 Geometry Kernel 往往会采用:

  • 梯形积分;
  • Simpson 积分;
  • Gaussian Quadrature,高斯积分;
  • Adaptive Integration,自适应积分。

其中 CAD 几何算法中比较常见的是高斯积分以及自适应积分。

14. 自适应积分和自适应 Tessellation 很相似 #

假设 Curve 某个区域变化非常平缓:

────────────────────

这里没有必要大量计算。

但某个区域变化非常快:

        __
      _/  \_
 ____/      \____

这里需要更多采样。

所以自适应积分可以:

计算当前区间
    ↓
估算误差
    ↓
误差满足要求?
   /          \
 YES          NO
 ↓             ↓
接受结果      把区间细分
                  ↓
               再计算

这和 CAD Tessellation 的:

误差过大
↓
增加细分

思想非常接近。

15. 积分如何计算平面面积 #

最简单的面积问题:

y=f(x)y=f(x)

在:

[a,b][a,b]

之间的面积:

A=abf(x)dxA= \int_a^b f(x)dx

因为每一小块面积:

dA=f(x)dxdA=f(x)dx

于是:

A=dAA=\int dA

仍然是:

局部小面积
+
局部小面积
+
局部小面积
+
...
=
总面积

16. 参数曲面的导数 #

CAD 中的 Surface 通常表示为:

S(u,v)S(u,v)

例如:

Plane
Cylinder
Sphere
Bezier Surface
B-Spline Surface
NURBS Surface

曲面有两个参数方向:

u
v

因此需要分别求导:

Su=SuS_u = \frac{\partial S}{\partial u}

以及:

Sv=SvS_v = \frac{\partial S}{\partial v}

这里叫做:

偏导数。

可以理解成:

Su
↓
保持 v 不变,只改变 u 时,Surface 往哪个方向走

Sv
↓
保持 u 不变,只改变 v 时,Surface 往哪个方向走

所以:

SuS_u

和:

SvS_v

都是 Surface 上的切向量。

17. 曲面法线为什么是两个偏导数叉积 #

在 Surface 上:

             Sv
             ↑
             │
             ●──────→ Su

SuS_uSvS_v 都位于曲面的切平面上。

两个向量叉积:

Su×SvS_u\times S_v

得到一个同时垂直于它们的向量:

               N
               ↑
               │
               ●────→ Su
              /
            Sv

因此曲面法线:

N=Su×SvSu×Sv\boxed{ N= \frac{S_u\times S_v} {|S_u\times S_v|} }

这就是 CAD Kernel 中计算 Surface Normal 的数学基础之一。

因此:

导数不仅用于长度,也直接参与曲面法线计算。

18. 曲面面积为什么需要二重积分 #

考虑 Surface 参数空间中一个非常小的区域:

du×dvdu\times dv

在真实三维曲面上,它近似形成一个小平行四边形。

两个边分别近似:

SuduS_u du

以及:

SvdvS_v dv

平行四边形面积等于两个向量叉积的长度:

dA=Su×Sv,du,dvdA = |S_u\times S_v| ,du,dv

所以整个曲面面积:

A=DSu×Sv,du,dv\boxed{ A= \iint_D |S_u\times S_v| ,du,dv }

其中 DD 是 Face 在 UV 参数空间中的有效区域。

可以理解成:

Surface
↓
切成无数非常小的曲面片

dA1
dA2
dA3
...

↓ 全部累加

Surface Area

19. 为什么 BRep Face 面积不是简单对整个 Surface 积分 #

BRep 中:

Face 不等于完整 Surface。

例如一个 Plane 是无限大的,但 Face 可能只有:

┌──────────────────┐
│                  │
│      Face        │
│                  │
└──────────────────┘

甚至有 Hole:

┌──────────────────┐
│                  │
│      ┌────┐      │
│      │Hole│      │
│      └────┘      │
│                  │
└──────────────────┘

所以真正计算 BRep Face 面积时:

D\iint_D

中的 DD 必须由:

Outer Wire
Inner Wire
P-Curve

共同限定。

也就是说:

Topology 决定积分区域,Geometry 决定区域上每一点的真实几何面积。

这也是 Geometry 与 Topology 分离以后非常典型的配合。

20. Triangle Mesh 也能近似计算曲面面积 #

如果 Surface 已经 Tessellation 成:

Triangle 1
Triangle 2
Triangle 3
...

那么也可以计算:

Amesh=iAiA_{mesh} = \sum_i A_i

Triangle 面积可以通过:

Ai=12(P1P0)×(P2P0)A_i = \frac12 | (P_1-P_0)\times(P_2-P_0) |

计算。

Triangle 越密:

Mesh Area

通常越接近真实 Surface Area。

但它仍然只是:

离散 Mesh 的近似结果。

而直接对精确 Surface 进行积分,则是在精确几何模型上计算。

21. Solid 体积和积分 #

实体体积也使用完全相同的思想。

把 Solid 想象成由无数非常小的体积:

dVdV

组成:

┌──────────────────┐
│[][][][][][][][][][]│
│[][][][][][][][][][]│
│[][][][][][][][][][]│
│[][][][][][][][][][]│
└──────────────────┘

每一个小块:

dVdV

把所有小体积累加:

V=ΩdV\boxed{ V= \iiint_\Omega dV }

这就是三重积分。

因此:

长度
L = ∫ ds

面积
A = ∬ dA

体积
V = ∭ dV

本质都是:

把无限多个局部小量累加起来。

22. BRep Kernel 为什么可以通过边界计算体积 #

对于 BRep Solid:

Solid
└── Shell
    └── Faces

Kernel 已经拥有完整闭合边界。

数学上可以利用:

Divergence Theorem,散度定理

把三维体积积分:

Ω\iiint_\Omega

转换成封闭 Surface 上的积分:

Ω\iint_{\partial\Omega}

这样就可以:

Solid Volume
↓
转换成
Face Surface Integrals
↓
遍历所有 Face
↓
累加

所以像 OCCT 中的 Volume Properties 并不意味着一定把 Solid 内部真的切成无数小立方体。

数学定理允许 Kernel:

根据实体的边界曲面计算内部体积。

23. 重心也需要积分 #

假设一个物体密度均匀。

重心可以直观理解成:

所有小体积的位置进行加权平均。

例如 x 坐标:

xˉ=1VΩx,dV\bar x = \frac{1}{V} \iiint_\Omega x,dV

同理:

yˉ=1VΩy,dV\bar y = \frac{1}{V} \iiint_\Omega y,dV zˉ=1VΩz,dV\bar z = \frac{1}{V} \iiint_\Omega z,dV

所以:

每个小体积
↓
位置 × 体积
↓
全部累加
↓
除以总体积
↓
Center of Mass

因此 CAD Kernel 中的:

Length Properties
Surface Properties
Volume Properties
Center Of Mass

背后其实都与积分密切相关。

24. 惯性矩同样来自积分 #

机械 CAD 中还经常需要:

Moment of Inertia

例如某个质量单元距离旋转轴越远,它对惯性的贡献越大。

因此形式类似:

I=r2,dmI = \int r^2,dm

这里:

r
↓
小质量到旋转轴的距离

dm
↓
一个非常小的质量

将所有局部贡献累加,就得到整个实体的惯性矩。

所以 CAD Kernel 的 Mass Properties 通常不仅能计算:

长度
面积
体积

还可能计算:

Center of Mass
Moment of Inertia
Principal Axes

这些都离不开积分。

25. 导数在曲率计算中的作用 #

对于曲线:

C(t)C(t)

一阶导数:

C(t)C'(t)

表示切向量。

二阶导数:

C(t)C''(t)

描述切向量变化。

因此曲率和:

C'
C''

密切相关。

对于三维参数曲线,曲率可以表示为:

κ=C(t)×C(t)C(t)3\kappa = \frac{ |C'(t)\times C''(t)| }{ |C'(t)|^3 }

不要求在面试时背这个公式。

只需要知道:

一阶导数描述曲线方向,二阶导数描述方向的变化,因此可以进一步得到曲率。

这对于:

  • Fillet;
  • Sweep;
  • Offset;
  • 曲线公平性;
  • Tessellation;

都非常重要。

26. 导数和连续性 #

CAD 中经常看到:

C0
C1
C2

以及:

G0
G1
G2

其中和导数密切相关。

例如两个 Curve 拼接:

C0 连续 #

只要求:

位置相同

C1 连续 #

不仅位置相同,还要求一阶导数一致:

切向量相同

C2 连续 #

进一步要求二阶导数一致:

曲率变化更加平滑

因此导数也是判断:

曲线和曲面之间平滑程度

的重要工具。

这也是 Fillet、Sweep、Surface Modeling 中经常讨论连续性的原因。

27. 导数在 Newton 迭代中的作用 #

几何 Kernel 中大量问题最终会转化成:

求一个方程的根。

例如:

Curve / Curve Intersection
Curve / Surface Intersection
Surface / Surface Intersection
Closest Point
Projection

很多情况下会使用:

Newton-Raphson Iteration,牛顿迭代。

一维情况下:

f(x)=0f(x)=0

Newton 方法:

xn+1=xnf(xn)f(xn)x_{n+1} = x_n- \frac{f(x_n)} {f'(x_n)}

其中:

f(x)f'(x)

就是导数。

导数告诉算法:

当前函数往哪个方向变化、变化有多快。

从而决定下一步应该往哪里迭代。

因此:

导数不仅描述几何,还直接参与几何求解算法。

28. 最近点和投影也需要导数 #

例如:

找空间点 PP 到 Curve C(t)C(t) 的最近点。

可以定义距离平方:

F(t)=C(t)P2F(t) = |C(t)-P|^2

最近距离意味着:

F(t)F(t)

达到最小值。

极值点通常满足:

F(t)=0F'(t)=0

因此:

Closest Point
↓
构造距离函数
↓
求导
↓
求 F'(t)=0
↓
得到候选参数

这就是导数在 Projection、Snap、Closest Point 等 CAD 功能中的应用之一。

29. 导数和 Tessellation #

Tessellation 也经常需要导数信息。

例如曲面:

S(u,v)S(u,v)

通过:

SuS_u

和:

SvS_v

可以计算 Surface Normal。

再比较不同采样位置的 Normal:

N1
N2

如果:

angle(N1,N2)angle(N_1,N_2)

过大:

Angular Deviation 超出要求
↓
进一步 Tessellation

因此:

Surface Derivative
↓
Normal
↓
Angular Deviation
↓
决定 Tessellation 密度

这就是导数与网格离散化之间的联系。

30. 积分和 Tessellation 的区别 #

积分和 Tessellation 都有一种:

把连续对象拆成很多局部部分。

的思想,但目的不同。

Tessellation #

主要目的是:

精确 Surface
↓
Triangle Mesh
↓
GPU Rendering

得到离散几何表示。

Numerical Integration #

主要目的是:

连续函数
↓
有限采样
↓
逼近积分
↓
得到长度 / 面积 / 体积等数值

两者都可能采用:

误差控制
自适应细分

所以算法思想有很多相似之处。

31. 导数和积分在 CAD 中的典型应用 #

可以把常见用途总结为:

曲线相关 #

导数:

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

32. 面试中如何回答“怎么计算 Edge 长度” #

如果面试官问:

一个 BRep Edge 对应 B-Spline Curve,怎么计算它的长度?

可以回答:

Edge 会关联底层参数曲线以及它实际使用的参数区间 [u0,u1][u_0,u_1]。对于参数曲线 C(u)C(u),一阶导数 C(u)C'(u) 表示曲线相对于参数的局部速度,因此微小弧长为:

ds=C(u)duds=|C'(u)|du

整个 Edge 的长度就是:

L=u0u1C(u)duL= \int_{u_0}^{u_1} |C'(u)|du

Line、Circle 等简单解析曲线可以直接使用解析公式,而 B-Spline 等复杂曲线一般通过高斯积分、自适应数值积分等方法计算。

这已经是比较完整的几何算法回答。

33. 面试中如何回答“怎么计算 Surface 面积” #

可以回答:

对参数曲面 S(u,v)S(u,v),分别计算两个参数方向的一阶偏导 SuS_uSvS_v。两者构成曲面的局部切向量,其叉积的模表示参数空间一个微小区域映射到三维后的面积缩放,因此:

dA=Su×Svdu,dvdA= |S_u\times S_v|du,dv

再对 Face 对应的有效 UV 区域进行二重积分:

A=DSu×Svdu,dvA= \iint_D |S_u\times S_v|du,dv

对于 BRep Face,积分区域 DD 还需要考虑 Outer Wire 和 Inner Wire 对应的边界。

这个回答已经体现了:

Geometry
+
Topology
+
Calculus

三者之间的关系。

34. 面试中如何回答“怎么计算 Solid 体积” #

可以回答:

从数学定义上,实体体积可以看成对内部所有微小体积 dVdV 做三重积分:

V=ΩdVV=\iiint_\Omega dV

但对于 BRep Solid,因为已经拥有闭合边界,几何 Kernel 可以利用散度定理把体积积分转换为对边界 Face 的曲面积分,再累加所有 Face 的贡献。因此不需要真正把 Solid 内部离散成大量体素。

这种回答比简单说:

VolumeProperties()

更能体现对底层几何算法的理解。

35. 一个统一的理解框架 #

以后遇到几何公式,可以先问两个问题。

第一:局部量是什么? #

例如:

Curve
→ ds

Surface
→ dA

Solid
→ dV

或者:

Curve
→ C'(t)

Surface
→ Su、Sv

这些通常通过导数得到。

第二:怎么得到整体? #

把所有局部量:

ds
dA
dV

通过积分累加。

于是:

                几何对象
                    │
                    ▼
                  导数
                    │
           描述局部变化规律
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
        Tangent   Normal    Curvature
          │
          ▼
       微小几何量
      ds / dA / dV
          │
          ▼
                积分
                  │
          把局部贡献累加
                  │
        ┌─────────┼─────────┐
        ▼         ▼         ▼
      Length     Area      Volume

36. 总结 #

对于 CAD 几何建模,导数和积分不应该只理解成数学公式。

最重要的是理解它们解决的问题。

导数 #

描述几何对象局部是如何变化的。

典型应用:

曲线切线
曲面切向量
曲面法线
曲率
连续性
最近点
投影
几何求交
Newton 迭代
Tessellation

积分 #

把无数个局部的小量累加成一个整体。

最重要的三个公式可以理解为:

L=ds\boxed{ L=\int ds }

表示小长度累加成曲线长度。

A=dA\boxed{ A=\iint dA }

表示小面积累加成曲面面积。

V=dV\boxed{ V=\iiint dV }

表示小体积累加成实体体积。

而对于参数几何:

L=C(t)dt\boxed{ L= \int |C'(t)|dt }

以及:

A=Su×Svdu,dv\boxed{ A= \iint |S_u\times S_v| du,dv }

则把导数与积分真正联系起来。

可以最终浓缩成一句话:

导数负责研究几何的“局部”,积分负责把局部累加成“整体”。

这也是为什么从 Curve、Surface 到 BRep Solid,导数和积分会不断出现在 CAD 几何 Kernel 的长度、面积、体积、曲率、质量属性、求交、投影以及网格离散化算法中。

目录