Bootstrap

CAD程序性能优化之数学的应用

       CAD是一门利用计算机技术和图形设备辅助工程师设计的技术,它融合了数学、物理等多学科知识。而数学又是基础中的基础,从简单的点线面,到复杂的微分几何,数学的身影无处不在,特别是像几何内核、数值仿真这种基础计算程序。个人认为,数学可以通过以下两种方式来提升计算效率:

  • 提出新的计算方式,简化计算步骤,提升计算效率。经典的例子是对数的发明,相当于延长了科学家的生命。
  • 将问题归纳和抽象为数学概念,集中研究解决方法。经典的例子是线性代数,发展了各种各样的快速求解方程组的方法。

       无疑,学好数学对编写高性能的CAD程序非常有好处。下面以几个例子说明这一点。

1. 计算几何:凸包算法

       凸包在CAD建模中有重要应用,比如碰撞检测。如图1所示,给定平面上点集 S = { P i ∣ i = 1 , . . , n } S=\{P_i|i=1,..,n\} S={Pii=1,..,n} ,其凸包 Φ ( S ) \Phi(S) Φ(S) 是:顶点取自于 S S S ,且包含 S S S 中所有点的凸多边形。有一个更加形象的理解是,将点想象成钉在桌子上钉子,将一个橡皮筋撑大,使其包围所有的钉子,松开手后,橡皮筋的形状就是这些点的凸包。

图1. 计算凸包的一般算法
 

       假设 Φ \Phi Φ 是顺时针的,则需要找到所有这样的点对 ( P i , P j ) (P_i,P_j) (Pi,Pj) ,使得所有其它点都在边 P i P j P_iP_j PiPj 的右侧。不难看出,可能的边有 n ( n − 1 ) n(n-1) n(n1)条,每条边都要进行 n − 2 n-2 n2 次左右侧判断,因此,一般凸包算法的计算复杂度为 O ( n 3 ) O(n^3) O(n3) 。在实际应用中,这样一个需要运行三次方时间的凸包算法,除非是处理小规模的输入集,否则都会由于太慢而毫无用处。

       接下来介绍一种计算凸包的递增式算法。如图2所示,首先,对所有点按照X坐标进行排序,这一处理的复杂度为 O ( n l o g n ) O(nlogn) O(nlogn) 。然后,借助于第一个点 P 1 P_1 P1 和最后一个点 P 16 P_{16} P16 ,将凸包一分为二,分为上凸包和下凸包,分别查找。最后,将2个凸包合并即完成任务。

图2. 计算凸包的递增式算法
 

       递增式算法的基本思路是:在已有凸包列表的基础上,取其最后2个点,寻找“右拐点”,比如 P 7 P_7 P7 P 1 P 3 P_1P_3 P1P3的右侧,即为右拐点。对于上凸包,首先将 P 1 P_1 P1 P 2 P_2 P2 加入上凸包列表 Φ u p p e r \Phi_{upper} Φupper 中,满足列表中至少有2个点。然后,遍历到 P 3 P_3 P3,相对于 P 1 P_1 P1 P 2 P_2 P2 P 3 P_3 P3 是左拐点,需要从列表中删除 P 2 P_2 P2,并将 P 3 P_3 P3 放入 Φ u p p e r \Phi_{upper} Φupper 。相对于 P 1 P_1 P1 P 3 P_3 P3 P 4 P_4 P4 是右拐点,将其放入 Φ u p p e r \Phi_{upper} Φupper ,同样地,相对 Φ u p p e r \Phi_{upper} Φupper 中的最后2个点, P 5 P_5 P5 P 6 P_6 P6 也是右拐点,也会被放入 Φ u p p e r \Phi_{upper} Φupper。但是, P 7 P_7 P7 的引入又会将 P 6 P_6 P6 P 5 P_5 P5 P 4 P_4 P4 依次从 Φ u p p e r \Phi_{upper} Φupper 中删除,因为 P 7 P_7 P7 相对这些点都是左拐点,直到 Φ u p p e r \Phi_{upper} Φupper 仅剩下 P 1 P_1 P1 P 3 P_3 P3 ,才将 P 7 P_7 P7 加入列表。接下来的过程与前面相似,不做赘述。

       寻找上凸包的算法复杂度是 O ( n ) O(n) O(n),因为每个点至多被删除1次。同样地,下凸包也可以用类似方法在 O ( n ) O(n) O(n) 时间内找到。综合排序的复杂度,递增式算法的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

       正如文献[1]中所言,面对几何算法问题,需要具备两方面的要素:(1) 对该问题的几何特性的深刻理解;(2) 算法和数据结构的合理应用。个人认为,“右拐点的抽象”和“渐增式寻找”分别是上面2个要素的体现。

2. 线性代数:通过点插值Nurbs曲线

       给定一系列点,计算一条Nurbs曲线,使其通过这些点,是CAD建模中的基础问题。首先大概了解一下Nurbs插值的一般步骤(如图3):(1) 确定这些点在曲线上的参数 u i u_i ui;(2) 确定曲线的次数和节点向量;(3) 对于 u i u_i ui,计算基函数取值 a i j ( j = 1 , 2 , . . . , n ) a_{ij}(j=1,2,...,n) aij(j=1,2,...,n) (后面简称为基值);(4) 组装基值矩阵 A A A,求解方程组 A X = B AX=B AX=B。这是一个 n ∗ n n*n nn的线性方程组,当 B B B V i V_i Vi x x x坐标组成的向量,求解得到 X X X,就是曲线的极点 P i P_i Pi x x x坐标。同理,可以计算出极点 P i P_i Pi y y y坐标和 z z z坐标。当通过点达到一定数目时,第4步的计算会占用绝大多数时间。

图3. 组装线性方程组
 

       不幸的是,一般的求解线性方程组的时间复杂度是 O ( n 3 ) O(n^3) O(n3),也就是说,通过点个数增加到原来的2倍,计算时长可能增加到原来的8倍,这是异常恐怖的(后面简称翻倍增长率)。因此,众多求解方程组的快速方法被研究出来,这里以经典的线性库Eigen为例,展示不同求解算法的效率差别,见表1。不难看出,不同求解方法的差异非常大。

表1. 不同算法求解方程组时间对比(单位:us)
 

       第一列直接使用稠密矩阵的QR分解(Dense QR),实际的翻倍增长率是略小于8倍,但当点数较多时,计算时长是无法接受的。根据Nurbs的局部支撑性,给定参数 u u u,只有degree+1个基值不是0,也就是说可以采用稀疏矩阵,来提高计算效率和减少内存占用。因此,第二列同样采用QR分解,但计算A是稀疏矩阵,可以看出,在点数目相同情况下,计算的时长被大大减少,并且翻倍增长率大概为4。第三列采用稀疏矩阵的LU分解,计算时长再次大幅减少,并且翻倍增长率小于2。第4列采用稀疏矩阵的Cholesky方法求解,是一种迭代求解方法,虽然计算时长更短,但在实际测试,生成的Nurbs容易出现异常波浪,预示着数值稳定性较差。

       限于篇幅,本文不打算分析这些方法的原理、特点,只是举例说明线性方程组在现代数值算法中的重要性和在CAD性能提升方面的应用。

3. 微积分:计算封闭曲线包围的面积

       如图4,给定一条简单的封闭曲线,如何计算其包围的面积是一个微积分在CAD建模领域的经典应用。假设这条曲线是由一系列点 V i ( i = 1 , 2... , n ) V_i (i=1,2...,n) Vi(i=1,2...,n)组成的多段线 L L L。一种可行的计算方法是将此区域划分为三角形,然后再求每个三角形的面积,所有三角形的面积之和就是包围的面积,但三角化的计算复杂度较高。

       本文采用格林公式来解决这个问题,时间复杂度为 O ( n ) O(n) O(n)。格林公式为:
∬ σ ∂ Q ∂ x − ∂ P ∂ y d σ = ∮ L + P d x + Q d y . \iint \limits_{\sigma}\frac{\partial Q}{\partial x}-\frac{\partial P}{\partial y}d\sigma = \oint\limits_{L^+}Pdx+Qdy. σxQyPdσ=L+Pdx+Qdy.
它描述了“平面上沿闭曲线 L L L 的曲线积分”与“曲线 L L L 所围成区域 σ \sigma σ 的面积积分”之间的关系,这是格林公式能解决此问题的基础。当 P = − y , Q = 0 P=-y,Q=0 P=yQ=0时,有:
∬ σ ∂ Q ∂ x − ∂ P ∂ y d σ = ∬ σ 1 d σ = ∮ L + − y d x . \iint \limits_{\sigma}\frac{\partial Q}{\partial x}-\frac{\partial P}{\partial y}d\sigma = \iint \limits_{\sigma}1d\sigma = \oint \limits_{L^+}{-y}dx. σxQyPdσ=σ1dσ=L+ydx.
中间项即代表 L L L包围的面积。

                                                                            图4. 封闭曲线 L L L包围的区域 σ \sigma σ
 

       在实际计算中,取 y = y i + y i + 1 2 y=\cfrac{y_i+y_{i+1}}{2} y=2yi+yi+1,以及 d x = x i + 1 − x i dx=x_{i+1}-x_{i} dx=xi+1xi,则包围面积可以表示为:
A = 1 2 ∑ i = 1 n − 1 ( y i + y i + 1 ) ( x i − x i + 1 ) . A=\frac{1}{2}\sum\limits_{i=1}^{n-1}(y_i+y_{i+1})(x_{i}-x_{i+1}). A=21i=1n1(yi+yi+1)(xixi+1).
如图4所示,上式中的第 i i i项的几何意义是第 i i i段线段与 X X X轴围成的矩形面积。由于只需要遍历每个线段,此算法的计算复杂度是 O ( n ) O(n) O(n)

       关于这个主题的拓展有两个:

  • 根据格林公式计算的面积是有向面积,当曲线逆时针时,面积为正(即图4所示),反之,面积为负。因此可以通过所求面积的正负判断曲线的旋向。
  • 2D封闭曲线所围成的面积可以通过格林公式快速计算,那么,3D封闭曲面所围成的体积怎样快速计算呢?答案是高斯公式。

       CAD技术从诞生到现在,不过60年,何以在工业界如此举足轻重?个人以为,CAD技术并没有太多的理论创新,而是顺应计算机发展的应用,是建立在数学、物理等基础学科的几百年积累之上的。数学工具是相当丰富的,是足够的,但同时也是难以快速掌握的,因此,这需要长时间的积累,切不可一蹴而就,而是要长期保持学习的状态。与诸君共勉!

参考文献

[1] 计算几何——算法与应用(第3版),Mark de Berg等,清华大学出版社。

[2] 数值分析(第2版),Timothy Sauer,机械工业出版社。

[3] 工科数学分析基础(第2版,下册),马知恩等,高等教育出版社。

 

文章首发于微信公众号:CAD智造干将,欢迎关注
 
请添加图片描述

;