• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            eryar

            PipeCAD - Plant Piping Design Software.
            RvmTranslator - Translate AVEVA RVM to OBJ, glTF, etc.
            posts - 603, comments - 590, trackbacks - 0, articles - 0

            OpenCascade B-Spline Basis Function

            Posted on 2014-07-21 19:18 eryar 閱讀(3488) 評論(0)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE

            OpenCascade B-Spline Basis Function

            eryar@163.com

            Abstract. B-splines are quite a bit more flexible than Bezier curves. This flexibility comes from the fact that you have much more control over the basis functions. For Bezier curves that each control point had an effect on each point on the curve; likewise the number of control points affected the degree of the curve. For the sake of flexiblity, you would like to be able to arbitrarily set the degree of the curve and to also determine the range of the affect each control point has. B-splines allow this level of control, the secret is its basis function. This paper focus on the B-splines basis function and some important properties of B-spline basis function, such as local support property, the multiplicity of the knot vector .etc.

            Key words. B-spline Basis Function, OpenCascade B-spline, Multiplicity, 

            1. Introduction

            在當前的CAD/CAM系統中,B樣條曲線曲面已經成為幾何造型系統的核心部分。B樣條曲線曲面造型方法的理論基礎就是B樣條。Bezier曲線是以Bernstein基函數為基礎的,雖然它有許多優點,但也有一些不足之處:

            v 當給定了Bezier曲線的控制點后,也就確定了曲線的次數。當次數過高時,會給Bezier曲線的計算帶來不便。如果采用分段三次Bezier曲線且要保持曲線間的連續性還必須有附加條件;

            v Bezier曲線是整體定義的,改變任意一個控制點,將對整條曲線都有影響。因此Bezier不具有局部修改性。

            1964年由Schoenberg提出了B樣條理論,1972年de Boor與Cox分別獨立給出了關于B樣條的標準算法。Gordon和Riesenfeld又把B樣條理論應用于形狀描述,最終提出了B樣條方法。用B樣條代替Bernstein基,構造出B樣條曲線,這種方法繼承了Bezier方法的一切優點,克服了Bezier方法的缺點,較成功地解決了局部控制問題,又輕而易舉地在參數連續性基礎上解決了連接問題,從而使自由曲線曲面形狀的描述問題得到較好解決。

            B樣條方法具有表示與設計自由曲線曲面的強大功能,它不僅是最廣為流行的形狀數學描述的主流方法之一,而且已成為關于工業產品幾何定義國際標準的有理B樣條方法的基礎。從B樣條理論的發展歷程可以看出,理論與實踐的相互作用。正是由于實際的需要,才提出解決問題的新方法。

            本文給出B樣條的遞推定義并使用OpenCascade的B樣條庫在OpenSceneGraph中繪制出B樣條基函數的曲線,在此基礎上來理解B樣條基函數的局部支撐性、節點向量的重復度等概念。

            2. Definition of B-spline Basis Functions

            有很多方法可以用來定義B樣條基函數以及證明它的一些重要性質。例如可以采用截尾冪函數的差商定義,開花定義及由de Boor和Cox等人提出的遞推公式等來定義。我們這里采用的是遞推定義方法,因為這種方法在計算機實現中是最有效的。

            令U={u0,u1,…,um}是一個單調不減的實數序列,即ui<=ui+1,i=0,1,…,m-1。其中,ui稱為節點,U稱為節點矢量,用Ni,p(u)表示第i個p次B樣條基函數,其定義為:

            wps_clip_image-22901

            遞推公式的幾何意義可以歸結為:移位、升階和線性組合。由上述公式可知:

            1) 當p>0時,Ni,p(u)是兩個p-1次基函數的線性組合;

            2) 計算一組基函數時需要事先指定節點矢量U和次數p;

            3) 計算p次基函數的過程生成一個如下形式的三角陣列:

            wps_clip_image-2251

            B樣條基有如下性質:

            a) 遞推性;

            b) 局部支承性;

            c) 規范性;

            d) 可微性;

            關于B樣條基函數更多的定義方式,可以參考《計算幾何教程》、《自由曲線曲面造型技術》等。

            3. Use OpenCascade B-spline Library

            在OpenCascade中,B樣條的計算庫位于基礎模塊(FoundationClasses Module)的TKMath,有分別對曲線和曲面的底層計算類BSplCLib和BSplSLib。關于B樣條曲線計算庫中對B樣條基函數計算的實現方法見:B-Spline Curve Library in Open Cascade

            http://www.shnenglu.com/eryar/archive/2013/03/12/198367.html
            本文主要介紹將B樣條基函數的計算結果在OpenSceneGraph中顯示出來,以便于直觀的理解B樣條基的相關性質。程序代碼如下所示:

             

            /*
            *    Copyright (c) 2014 eryar All Rights Reserved.
            *
            *        File    : Main.cpp
            *        Author  : eryar@163.com
            *        Date    : 2014-07-20 20:46
            *        Version : 1.0v
            *
            *    Description : Show OpenCascade B-Spline Basis evaluate 
            *                  result in OpenSceneGraph.
            *
            *      Key words : OpenCascade, OpenSceneGraph, 
            *                  B-Spline Basis Function
            */

            // OpenSceneGraph library.
            #include <osg/MatrixTransform>

            #include 
            <osgDB/ReadFile>
            #include 
            <osgViewer/Viewer>
            #include 
            <osgGA/StateSetManipulator>
            #include 
            <osgViewer/ViewerEventHandlers>

            #pragma comment(lib, 
            "osgd.lib")
            #pragma comment(lib, 
            "osgDBd.lib")
            #pragma comment(lib, 
            "osgGAd.lib")
            #pragma comment(lib, 
            "osgViewerd.lib")

            // OpenCASCADE library.
            #define WNT

            #include 
            <TColStd_Array1OfReal.hxx>
            #include 
            <math_Matrix.hxx>
            #include 
            <BSplCLib.hxx>

            #pragma comment(lib, 
            "TKernel.lib")
            #pragma comment(lib, 
            "TKMath.lib")

            osg::Node
            * BuildAxes(Standard_Real x, Standard_Real y)
            {
                osg::ref_ptr
            <osg::Geode> aGeode = new osg::Geode();
                osg::ref_ptr
            <osg::Geometry> aLineGeom = new osg::Geometry();
                osg::ref_ptr
            <osg::Vec3Array> aVertices = new osg::Vec3Array();

                
            // x axis
                aVertices->push_back(osg::Vec3(0.00.00.0));
                aVertices
            ->push_back(osg::Vec3(x + 0.50.00.0));

                
            // arrow for x axis
                aVertices->push_back(osg::Vec3(x + 0.50.00.0));
                aVertices
            ->push_back(osg::Vec3(x + 0.30.00.05));

                aVertices
            ->push_back(osg::Vec3(x + 0.50.00.0));
                aVertices
            ->push_back(osg::Vec3(x + 0.30.0-0.05));

                
            // x ruler
                for (Standard_Integer i = 1; i <= x; ++i)
                {
                    aVertices
            ->push_back(osg::Vec3(i, 0.00.05));
                    aVertices
            ->push_back(osg::Vec3(i, 0.0-0.05));
                }

                
            // y axis
                aVertices->push_back(osg::Vec3(0.00.00.0));
                aVertices
            ->push_back(osg::Vec3(0.00.0, y + 0.5));

                
            // arrow for y axis
                aVertices->push_back(osg::Vec3(0.00.0, y + 0.5));
                aVertices
            ->push_back(osg::Vec3(0.050.0, y + 0.3));

                aVertices
            ->push_back(osg::Vec3(0.00.0, y + 0.5));
                aVertices
            ->push_back(osg::Vec3(-0.050.0, y + 0.3));

                
            // y ruler
                for (Standard_Integer j = 1; j <= y; ++j)
                {
                    aVertices
            ->push_back(osg::Vec3(0.050.0, j));
                    aVertices
            ->push_back(osg::Vec3(-0.050.0, j));
                }

                aLineGeom
            ->setVertexArray(aVertices);
                aLineGeom
            ->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, aVertices->size()));

                aGeode
            ->addDrawable(aLineGeom);
                
            return aGeode.release();
            }

            osg::Node
            * BuildBSplineBasis(const TColStd_Array1OfReal &theKnots, int theDegree)
            {
                osg::ref_ptr
            <osg::Group> aGroup = new osg::Group();
                osg::ref_ptr
            <osg::Geode> aGeode = new osg::Geode();
                osg::ref_ptr
            <osg::Geometry> aPointGeom = new osg::Geometry();
                osg::ref_ptr
            <osg::Vec3Array> aVertices = new osg::Vec3Array();

                Standard_Integer aIndex 
            = 0;
                Standard_Integer aOrder 
            = theDegree + 1;
                math_Matrix m(
            111, aOrder);

                
            for (Standard_Real u = theKnots.Value(theKnots.Lower()); u <= theKnots.Value(theKnots.Upper()); u += 0.001)
                {
                    BSplCLib::EvalBsplineBasis(
            00, aOrder, theKnots, u, aIndex, m);

                    
            for (Standard_Integer i = 1; i <= aOrder; ++i)
                    {
                        aVertices
            ->push_back(osg::Vec3(u, 0.0, m(1, i)));
                    }
                }

                aPointGeom
            ->setVertexArray(aVertices);
                aPointGeom
            ->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, aVertices->size()));

                
            // set the color for the points.
                osg::ref_ptr<osg::Vec4Array> aColor = new osg::Vec4Array();
                aColor
            ->push_back(osg::Vec4(aOrder % 1, aOrder % 2, aOrder % 31.0));

                aPointGeom
            ->setColorArray(aColor);
                aPointGeom
            ->setColorBinding(osg::Geometry::BIND_OVERALL);

                aGeode
            ->addDrawable(aPointGeom);

                aGroup
            ->addChild(aGeode);
                aGroup
            ->addChild(BuildAxes(theKnots.Value(theKnots.Upper()), 1.0));

                
            return aGroup.release();
            }

            osg::Node
            * BuildBSplineBasis(void)
            {
                osg::ref_ptr
            <osg::Group> aGroupNode = new osg::Group();
                TColStd_Array1OfReal aKnots1(
            18);

                aKnots1(
            1= 0.0;
                aKnots1(
            2= 0.0;
                aKnots1(
            3= 0.0;
                aKnots1(
            4= 0.0;
                aKnots1(
            5= 1.0;
                aKnots1(
            6= 1.0;
                aKnots1(
            7= 1.0;
                aKnots1(
            8= 1.0;

                osg::ref_ptr
            <osg::MatrixTransform> aUniformBasis = new osg::MatrixTransform();
                aUniformBasis
            ->setMatrix(osg::Matrix::translate(0.00.00.0));
                aUniformBasis
            ->addChild(BuildBSplineBasis(aKnots1, 4));

                aGroupNode
            ->addChild(aUniformBasis);
                
            return aGroupNode.release();
            }

            int main(int argc, char* argv[])
            {
                osgViewer::Viewer aViewer;

                aViewer.setSceneData(BuildBSplineBasis());

                aViewer.addEventHandler(
            new osgGA::StateSetManipulator(aViewer.getCamera()->getOrCreateStateSet()));
                aViewer.addEventHandler(
            new osgViewer::StatsHandler);
                aViewer.addEventHandler(
            new osgViewer::WindowSizeHandler);

                
            return aViewer.run();
            }

            B樣條基函數計算使用了函數BSplCLib::EvalBsplineBasis(),通過這個函數不僅可以計算基函數,還可以計算B樣條基函數的導數。計算結果輸出到一個矩陣之中。根據定義可知要計算B樣條基函數,需要指定節點矢量和次數,所以函數BuildBSplineBasis()就根據這兩個參數生成B樣條基函數的圖形進行顯示。上述代碼生成的一個B樣條基函數結果如下圖所示:

            wps_clip_image-4426

            Figure 3.1 U=[0,0,0,0,1,1,1,1], p=4的B樣條基函數

            改變次數,生成p=3時的基函數如下圖所示:

            wps_clip_image-28149

            Figure 3.2 U=[0,0,0,0,1,1,1,1], p=3的B樣條基函數

            4. Local Support Property

            B樣條的局部支承性(Local Support Property)是B樣條最重要的性質之一,也是B樣條方法與Bezier方法的主要差別所在。由于局部支承性質,使B樣條曲線具有良好的局部性,從而為曲線、曲面設計奠定了良好的基礎。

            wps_clip_image-2157

            Figure 4.1 Local Support Property of B-spline Basis Function

            從上圖可以看出,N1,3是N1,0,N2,0,N3,0,N4,0的線性組合,所以N1,3的非零區域只在u∈[u1, u5],即:

            wps_clip_image-11981

            上式表明,第i條k次B樣條僅在節點ti到ti+k+1的k+1個區間內不為0,其他區間均為0.這個性質稱為局部支承性。

            k次B樣條僅在k+1個區間內非0。換言之,每段k次B樣條曲線只涉及k+1個基函數,并由k+1個頂點所定義。B樣條的局部支承性對曲線、曲面設計有兩方面的影響:

            v 第i段k次B樣條曲線僅由Pi, Pi+1, ..., Pi+k共k+1個頂點所控制,而與其他頂點無關。為此,為修改一段曲線,僅需修改有關的k+1個頂點即可;

            v 反之,修改一個頂點,對B樣條曲線的影響也是局部的,對于均勻的k次B樣條曲線調整一個頂點的位置僅影響與該頂點有關的k+1段曲線。

            局部支承性是B樣條方法最引人的特點之一。

            5. Multiplicity of the Knot Vector

            重節點連續階性質:在每一個節點區間(ui, ui+1)內部,Ni,p(u)為多項式,因此有導數存在。在一個節點ui處,Ni,p(u)是一個p-mi次連續可微的,此處mi是該節點的重數(Multiplicity)。所以增加次數,則增加連續性,而增加節點的重數,則降低連續性。

            節點矢量U={0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5}上的2次B樣條基函數如下圖所示:

            wps_clip_image-1220

            Figure 5.1 U={0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 5} p = 2 B-spline Basis Function

            程序代碼如下所示:

             

            TColStd_Array1OfReal aKnots2(111);

            aKnots2(
            1= 0.0;
            aKnots2(
            2= 0.0;
            aKnots2(
            3= 0.0;
            aKnots2(
            4= 1.0;
            aKnots2(
            5= 2.0;
            aKnots2(
            6= 3.0;
            aKnots2(
            7= 4.0;
            aKnots2(
            8= 4.0;
            aKnots2(
            9= 5.0;
            aKnots2(
            10= 5.0;
            aKnots2(
            11= 5.0;

            osg::ref_ptr
            <osg::MatrixTransform> aNonUniformBasis2 = new osg::MatrixTransform();
            aNonUniformBasis2
            ->addChild(BuildBSplineBasis(aKnots2, 2));
            aGroupNode
            ->addChild(aNonUniformBasis2);

            從上圖可知,在節點u=4的位置,B樣條基函數的曲線已經失去了連續性。再舉一個例子,節點矢量U={0,0,0,0,1,2,3,4,4,4,5,5,5,5},p=3的B樣條基函數如下圖所示:

            wps_clip_image-26696

            Figure 5.2 U={0, 0, 0, 0,1, 2, 3, 4, 4,4, 5, 5, 5,5} p = 3 B-spline Basis Function

            當節點矢量兩端的重復度如下所示時,則B樣條基函數退化為Bernstein基函數:

            wps_clip_image-2936

            因此,Bezier可以看作是B樣條表達式的一種特例。在OpenCascade的B樣條計算類中有一個函數可以根據次數p來生成Bezier的節點矢量:

             

            //=====================================================================
            // function: FlatBezierKnots
            // purpose :
            //=====================================================================
            // array of flat knots for bezier curve of maximum 25 degree
            static const Standard_Real knots[52= { 00000000000000000000000000
                                                     
            11111111111111111111111111 };
            const Standard_Real& BSplCLib::FlatBezierKnots (const Standard_Integer Degree)
            {
              Standard_OutOfRange_Raise_if (Degree 
            < 1 || Degree > MaxDegree() || MaxDegree() != 25,
                
            "Bezier curve degree greater than maximal supported");

              
            return knots[25-Degree];
            }

             

            由上述代碼可知,函數FlatBezierKnots()直接返回了靜態數組變量knots中的部分值,且Bezier的次數最高不能超過25次。

            6. Conclusion

            B樣條基函數是NURBS理論的基礎,本文結合OpenCascade中的B樣條計算庫,將其計算結果在OpenSceneGraph中顯示出來,以便直觀的理解B樣條的有關性質,如局部支承性、節點重復度等概念。

            讀者可以結合上述代碼,嘗試給出不同的節點矢量及次數,來觀察B樣條基函數的結果,直觀的理解B樣條的性質,進而結合源程序來理解B樣條基函數的具體實現。

            7. References

            1. 趙罡,穆國旺,王拉柱譯Les Piegl,Wayne Tiller The NURBS Book(Second Edition) 2010 清華大學出版社

            2. 莫容,常智勇 計算機輔助幾何造型技術 2009 科學出版社

            3. 朱心雄等,自由曲線曲面造型技術,2000,科學出版社

            4. Kelly Dempski, Focus on Curves and Surface, 2003, Premier Press

            5. 王仁宏,李崇君,朱春鋼 計算幾何教程 2008 科學出版社

            久久久噜噜噜久久中文字幕色伊伊 | 国产亚洲美女精品久久久| 亚洲人成网亚洲欧洲无码久久| 蜜臀久久99精品久久久久久| 久久激情亚洲精品无码?V| 久久国产精品视频| 精品久久久久久无码国产| 久久精品国产亚洲7777| 国产—久久香蕉国产线看观看| 国产AV影片久久久久久| 久久亚洲2019中文字幕| 亚洲伊人久久成综合人影院| 精产国品久久一二三产区区别| 中文字幕久久久久人妻| 久久91精品久久91综合| 国产A级毛片久久久精品毛片| 久久天天躁狠狠躁夜夜av浪潮| 99久久免费国产精品特黄| 久久国产欧美日韩精品| 国产精品99久久久久久人| 成人精品一区二区久久| 欧美色综合久久久久久| 久久天天躁狠狠躁夜夜avapp| 99久久精品日本一区二区免费| 国产福利电影一区二区三区久久久久成人精品综合 | 久久水蜜桃亚洲av无码精品麻豆| 91精品国产高清91久久久久久| 国产成人AV综合久久| 一本色道久久综合狠狠躁篇| 久久精品国产亚洲av麻豆小说| 国产激情久久久久影院老熟女免费 | 国产精品对白刺激久久久| 国产999精品久久久久久| 浪潮AV色综合久久天堂| 国产精品成人无码久久久久久| 国产aⅴ激情无码久久| 国产精品亚洲美女久久久| 亚洲精品乱码久久久久久蜜桃图片 | 一本色道久久综合狠狠躁篇| 久久精品国产精品国产精品污| 国产精品一区二区久久精品涩爱|