Polynomial Library in OpenCascade

eryar@163.com

摘要Abstract:分析幂基曲线即多项式曲线在OpenCascade中的计算方法,以及利用OpenSceneGraph来显示OpenCascade的计算结果,加深对多项式曲线的理解。

关键字Key Words:OpenCascade、PLib、OpenSceneGraph、Polynomial Library

一、 概述 Overview

CAGD(Computer Aided Geometry Design)中,基表示的参数矢函数形式已经成为形状数学描述的标准形式。人们首先注意到在各类函数中,多项式函数(Polynomial Function)能较好地满足要求。它表示形式简单,又无穷次可微,且容易计算函数值及各阶导数值。采用多项式函数作为基函数即多项式基,相应可以得到参数多项式曲线曲面。

人们很早就注意到这样一个问题:设f(x)∈C[a,b],对于任意给的ε>0,是否存在这样的多项式p(x),使得

对一切a≤x≤b一致成立?

1885年,Weierstrass证明了p(x)的存在性;

1912年,Bernstein将满足条件的多项式构造出来。

Weierstrass定理:设f(x)∈C[a,b],那么对于任意给的ε>0,都存在这样的多项式p(x),使得

Weierstrass定理说明,[a,b]上的任何连续函数都可以用多项式来一致逼近。该定理实际上正好解决了利用多项式组成的函数来表示连续函数的问题。

幂(又称单项式monomial)基uj(j=0,1,,,n)是最简单的多项式基。相应多项式的全体构成n次多项式空间。n次多项式空间中任一组n+1个线性无关的多项式都可以作为一组基,因此就有无穷多组基。不同组基之间仅仅相差一个线性变换。

如果允许坐标函数x(u),y(u),z(u)是任意的,则可以得到范围很广的曲线。但是在实际开发一个几何造型系统时,我们需要一些折中,理想的情况是将坐标函数限制在满足下述条件的一类函数中:

l 能够精确地表示用户需要的所有曲线;

l 在计算机中能够被方便、高效、精确地处理,特别是可以高效地计算曲线上的点及各阶导矢;函数的数值计算对浮点数舍入误差不敏感;函数所需要的存储量较小;

l 比较简单,在数学上易于理解。

一类被广泛使用的函数就是多项式。尽管它们满足上标准中的后两项,但有很多类型的重要曲线(及曲面)不能用多项式精确表示,在系统中,这些曲线只能用多项式逼近。同一参数多项式曲线可以采用不同的基表示,如幂基表示和Bezier表示,由些决定了它们具有不同的性质,因而就有不同的优点。

二、 幂基曲线的计算 Calculate Polynomial Function

一条n次曲线的幂基表示形式是:

,其中是矢量。

给定u0,计算幂基曲线上的点C(u0)的最有效算法是英国数学家W.G.Horner提出的Horner方法。Horner算法是递归概念的一个典型实例,它采用最少的乘法来进行多项式求值,使计算由X^n问题转化为O(n)的问题。

l 当次数=1时:

l 当次数=2时:

l ……

l 当次数=n时:

用数组来直接计算:

  1. void Horner1(a, n, u0, C)
  2. {
  3. C = a[n];
  4. for (int i = n-; i >= ; i--)
  5. {
  6. C = C * u0 + a[i];
  7. }
  8. }

在OpenSceneGraph中来计算:

  1. void Horner(osg::Vec3Array* a, double u, osg::Vec3& p)
  2. {
  3. int n = a->size() - ;
  4. p = a->at(n);
  5.  
  6. for (int i = n-; i >= ; i--)
  7. {
  8. p = p * u + a->at(i);
  9. }
  10. }

三、 幂基曲线的显示 Render Power Basis Curve

利用Horner方法可以计算[0,1]区间上相应曲线上的点,将这些点连成线就构成了幂基曲线的近似表示。在OpenSceneGraph中显示幂基曲线程序如下所示:

  1. #include <osg/Vec3>
  2. #include <osg/Array>
  3. #include <osg/Geode>
  4. #include <osg/Group>
  5. #include <osgGA/StateSetManipulator>
  6. #include <osgViewer/Viewer>
  7. #include <osgViewer/ViewerEventHandlers>
  8.  
  9. #pragma comment(lib, "osgd.lib")
  10. #pragma comment(lib, "osgGAd.lib")
  11. #pragma comment(lib, "osgViewerd.lib")
  12.  
  13. /*
  14. * @breif Compute point on power basis curve.
  15. * @param [in] a:
  16. * @param [in] x:
  17. * @return: Point on power basis curve.
  18. */
  19. void Horner(osg::Vec3Array* a, double u, osg::Vec3& p)
  20. {
  21. int n = a->size() - ;
  22.  
  23. if (- == n)
  24. {
  25. return ;
  26. }
  27.  
  28. p = a->at(n);
  29.  
  30. for (int i = n-; i >= ; i--)
  31. {
  32. p = p * u + a->at(i);
  33. }
  34. }
  35.  
  36. osg::Node* RenderPowerBasisCurve()
  37. {
  38. const int nStep = ;
  39. osg::Geode* curveNode = new osg::Geode();
  40. osg::ref_ptr<osg::Geometry> curveGeom = new osg::Geometry();
  41. osg::ref_ptr<osg::Vec3Array> curvePnts = new osg::Vec3Array();
  42.  
  43. // Test to compuate point on power basis curve.
  44. osg::ref_ptr<osg::Vec3Array> ctrlPnts = new osg::Vec3Array;
  45. ctrlPnts->push_back(osg::Vec3(, , ));
  46. ctrlPnts->push_back(osg::Vec3(, , ));
  47. ctrlPnts->push_back(osg::Vec3(, , ));
  48. ctrlPnts->push_back(osg::Vec3(, , ));
  49.  
  50. for (int i = ; i < nStep; i++)
  51. {
  52. osg::Vec3 pnt;
  53. Horner(ctrlPnts, i * 1.0 / nStep, pnt);
  54.  
  55. curvePnts->push_back(pnt);
  56. }
  57.  
  58. curveGeom->setVertexArray(curvePnts);
  59. curveGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, , curvePnts->size()));
  60.  
  61. curveNode->addDrawable(curveGeom);
  62.  
  63. return curveNode;
  64. }
  65.  
  66. int main(int argc, char* argv[])
  67. {
  68. osgViewer::Viewer myViewer;
  69. osg::ref_ptr<osg::Group> root = new osg::Group();
  70.  
  71. root->addChild(RenderPowerBasisCurve());
  72.  
  73. myViewer.setSceneData(root);
  74.  
  75. myViewer.addEventHandler(new osgGA::StateSetManipulator(myViewer.getCamera()->getOrCreateStateSet()));
  76. myViewer.addEventHandler(new osgViewer::StatsHandler);
  77. myViewer.addEventHandler(new osgViewer::WindowSizeHandler);
  78.  
  79. return myViewer.run();
  80. }

设置不同的控制点ctrlPnts,就得到不同的曲线。

当n=1时,有两个控制点a0, a1,表示由a0到a0+a1的直线段,如图3.1所示:

Figure 3.1 连接两点(0,0,6)到(3,0,6)的直线

当n=2时,曲线是一段由a0到a0+a1+a2的抛物线弧,如图3.2所示:

Figure 3.2 抛物线弧(0,0,6)(3,0,6)(6,0,3)

四、 occ中的多项式计算库The PLib in OCC

在OpenCascade中的基础模块(FoundationClasses)的数学计算工具箱(TKMath Toolkit)中有个PLib包,用以对多项式进行基本的计算。PLib库中的函数都是静态函数,所以都是类函数,可以用类名加函数名直接调用。

PLib可对多项式进行如下计算:

l 计算多项式的值:EvalPolynomial;

l 计算Lagrange插值:EvalLagrange;

l 计算Hermite插值:EvalCubicHermite;

其中计算多项式值的方法也是用的Horner方法。

包PLib中提供了计算几何的数学基础中多项式插值中大部分插值计算。结合书籍《计算几何教程》科学出版社中第一章的理论内容及OpenCascade的源程序,可以方便计算几何的数学基础知识的学习。

五、 使用PLib Apply PLib Class

因为包PLib中的类PLib都是静态函数,所以函数传入的参数比较多,若要使用这些计算函数,需要对其函数参数进行了解。为了对不同维数多项式进行计算,类PLib中把空间点转换成了实数数组,并提供了相互转换的函数。以计算多项式值为例,来说明使用PLib的方法。程序代码如下所示:

  1. osg::Node* TestPLib(void)
  2. {
  3. const int nStep = ;
  4. osg::Geode* curveNode = new osg::Geode();
  5. osg::ref_ptr<osg::Geometry> curveGeom = new osg::Geometry();
  6. osg::ref_ptr<osg::Vec3Array> curvePnts = new osg::Vec3Array();
  7.  
  8. TColgp_Array1OfPnt poles(, );
  9. TColStd_Array1OfReal fp(, poles.Length() * );
  10. TColStd_Array1OfReal points(, , );
  11.  
  12. Standard_Real* polynomialCoeff = (Standard_Real*) &(fp(fp.Lower()));
  13. Standard_Real* result = (Standard_Real*)&(points(points.Lower()));
  14.  
  15. poles.SetValue(, gp_Pnt(, , ));
  16. poles.SetValue(, gp_Pnt(, , ));
  17. poles.SetValue(, gp_Pnt(, , ));
  18.  
  19. // Change poles to flat array.
  20. PLib::SetPoles(poles, fp);
  21.  
  22. // Three control point, so degree is 3-1=2.
  23. Standard_Integer nDegree = - ;
  24.  
  25. // Because point are 3 Dimension.
  26. Standard_Integer nDimension = ;
  27.  
  28. for (int i = ; i < nStep; i++)
  29. {
  30. PLib::NoDerivativeEvalPolynomial(
  31. i * 1.0 / nStep,
  32. nDegree,
  33. nDimension,
  34. nDegree * nDimension,
  35. polynomialCoeff[],
  36. result[]);
  37.  
  38. //
  39. curvePnts->push_back(osg::Vec3(result[], result[], result[]));
  40. }
  41.  
  42. curveGeom->setVertexArray(curvePnts);
  43. curveGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, , curvePnts->size()));
  44.  
  45. curveNode->addDrawable(curveGeom);
  46.  
  47. return curveNode;
  48. }

函数PLib::SetPoles可以将空间坐标点转换为实数数组。在调用无微分计算多项式的函数时,将坐标点的实数数组的首地址作为参数之一传入。

为了与前面的Horner方法计算多项式的结果进行对比,将OpenCascade对相同点计算的结果也显示出来。如下图5.1所示:

Figure 5.1 PLib compute result VS. Previous Horner method

由上图可知,PLib的计算结果与前面的Horner方法计算结果相同。查看OpenCascade的源程序,得其多项式计算方法也是采用的Horner方法。

  1. void PLib::NoDerivativeEvalPolynomial(const Standard_Real Par,
  2. const Standard_Integer Degree,
  3. const Standard_Integer Dimension,
  4. const Standard_Integer DegreeDimension,
  5. Standard_Real& PolynomialCoeff,
  6. Standard_Real& Results)
  7. {
  8. Standard_Integer jj;
  9. Standard_Real *RA = &Results ;
  10. Standard_Real *PA = &PolynomialCoeff ;
  11. Standard_Real *tmpRA = RA;
  12. Standard_Real *tmpPA = PA + DegreeDimension;
  13.  
  14. switch (Dimension) {
  15.  
  16. case : {
  17. *tmpRA = *tmpPA;
  18.  
  19. for (jj = Degree ; jj > ; jj--) {
  20. tmpPA--;
  21.  
  22. *tmpRA = Par * (*tmpRA) + (*tmpPA);
  23. }
  24. break;
  25. }
  26. }

从上述计算一维多项式的代码可以看出,计算方法与前面的Horner方法相同。

六、 结论 

学习使用Horner方法来计算多项式的值,并将计算结果在OpenSceneGraph中显示。通过使用OpenCascade的多项式库PLib来计算多项式的值,并结合其源程序来理解如何使用库PLib。库PLib为了统一多项式的计算,将空间点都转换成数组后再进行计算,在这其中大量使用了指针,代码可读性也不是很好,需要仔细、耐心。

七、 参考资料 

1. 王仁宏、李崇君、朱春钢 计算几何教程 科学出版社 2008.6

2. 赵罡、穆国旺、王拉柱 非均匀有理B样条《The NURBS Book》 清华大学出版社 2010.12

3.  OpenCascade source code

PDF Version and Source Code: Polynomial Library in OpenCascade

Polynomial Library in OpenCascade的更多相关文章

  1. OpenCASCADE Interpolation - Lagrange

    OpenCASCADE Interpolation - Lagrange eryar@163.com Abstract. Power basis polynomial is the most simp ...

  2. OpenCascade B-Spline Basis Function

    OpenCascade B-Spline Basis Function eryar@163.com Abstract. B-splines are quite a bit more flexible ...

  3. Overview of OpenCascade Library

    Overview of OpenCascade Library eryar@163.com 摘要Abstract:对OpenCascade库的功能及其实现做简要介绍. 关键字Key Words:Ope ...

  4. Create views of OpenCASCADE objects in the Debugger

    Create views of OpenCASCADE objects in the Debugger eryar@163.com Abstract. The Visual Studio Natvis ...

  5. OpenCASCADE JT Assistant

    OpenCASCADE JT Assistant eryar@163.com Abstract. Siemens’ JT data format accepted as the world’s fir ...

  6. OpenNURBS to OpenCASCADE

    OpenNURBS to OpenCASCADE eryar@163.com Abstract. The OpenNURBS initiative provides CAD/CAM/CAE and c ...

  7. OpenCASCADE DataExchange DWG

    OpenCASCADE DataExchange DWG eryar@163.com Abstract. DWG is a file format created in the 70’s for th ...

  8. OpenCASCADE Conic to BSpline Curves-Parabola

    OpenCASCADE Conic to BSpline Curves-Parabola eryar@163.com Abstract. Rational Bezier Curve can repre ...

  9. OpenCascade Chinese Text Rendering

    OpenCascade Chinese Text Rendering eryar@163.com Abstract. OpenCascade uses advanced text rendering ...

随机推荐

  1. C++常用特性原理解析

    在我的早期印象中,C++这门语言是软件工程发展过程中,出于对面向对象语言级支持不可或缺的情况下,一群曾经信誓旦旦想要用C统治宇宙的极客们妥协出来的一个高性能怪咖. 它驳杂万分,但引人入胜,出于多(mi ...

  2. clientX .offsetX .screenX x 的区别

    clientX 设置或获取鼠标指针位置相对于当前窗口的 x 坐标,其中客户区域不包括窗口自身的控件和滚动条. clientY 设置或获取鼠标指针位置相对于当前窗口的 y 坐标,其中客户区域不包括窗口自 ...

  3. bzoj3680模拟退火

    看题意就是一道数学物理题,带权费马点   --这怎么是数学了,这也是物理的 所以要用物理方法,比如FFF 国际著名oi选手miaom曾说 模拟退火初温可以低,但是最好烧个几千次 国际著名物理课代表+1 ...

  4. PHP注册与登录【2】用户注册

    注册页面 reg.html 负责收集用户填写的注册信息.教程里只列出关键的代码片段,完整的代码附在本节最后. 注册表单 <fieldset> <legend>用户注册</ ...

  5. Spring MVC篇一、搭建Spring MVC框架

    本项目旨在搭建一个简单的Spring MVC框架,了解Spring MVC的基础配置等内容. 一.项目结构 本项目使用idea intellij创建,配合maven管理.整体的目录结构如图: 其中ja ...

  6. Linux 系统查看物理内存使用率的命令脚本,以百分比形式输出。

    想监视系统内存?好像是没法直接得到现成的百分比的,自己取值计算一下吧 totalmem=`free -m | grep 'Mem' | awk '{print $3}'` usedmem=`free ...

  7. ZK 使用jfreeChart

    前台: <?page title="Grid使用" contentType="text/html;charset=UTF-8"?> <zk x ...

  8. Struts 2的OGNL的根对象

    Struts2中的OGNL表达式语言是对Xwork的OGNL的封装.我们要理解一下几点: 1. Struts2中将ActionContext作为OGNL的上下文环境(ActionContext内部含有 ...

  9. android中webview调用拨号盘

    wv.setWebViewClient(new WebViewClient(){              public boolean shouldOverrideUrlLoading(WebVie ...

  10. DOMO1

    以下是Demo首页的预览图 demo下载:http://www.eoeandroid.com/forum.php?mod=attachment&aid=NjE0Njh8ZTIyZDA2M2N8 ...