您的位置:首页 > 其它

Hermite与Bezier曲线绘制方法研究

2013-08-15 00:57 671 查看
发信人:   william@cis_nctu   (何陋居主),   信区:   programming   
  标     题:   [转载]   Hermite   与   Bezier   曲线的绘制   
  发信站:   交大资科_BBS   (May   25   00:32:41   1995)   
  转信站:   cis_nctu   
    
    
      From:   Chi'u   I-Nan                                           *   Area:   90   C   语言   
          To:   All                                                           Date:   03   May   95     22:37:26   
      Subj:   Hermite   与   Bezier   曲线的绘制   
    
  **********************************************************************   
  *   Hermite与Bezier曲线绘制方法研究                                                                         *   
  *   作者:邱奕南   (Chi'u   I-Nan)                                                                                   *   
  *   版权声明:以下文章内容本人仅同意供BBS   站上流传学习,但必须完整流传   *   
  *                       (含版权声明及程序),其余权利一概保留。任何未经本人同意   *   
  *                       ,将本文贩卖、刊登、节录、或其它一切侵害本人著作权之行为   *   
  *                       者,皆需负担刑事责任及民事赔偿责任。                                           *   
  **********************************************************************   
    
            Hermite及Bezier曲线为三度空间曲线的常用表示法,以下我们先说明一   
  下这两个曲线的定义:   
    
  1.Hermite曲线   
    
            Hermite曲线为给定两端点及两端点向量所得的三次曲线。令三次曲线:   
    
                                      3                   2   
            x(t)   =   Ax   *   t     +   Bx   *   t     +   Cx   *   t   +   d   
    
                                      3                   2   
            y(t)   =   Ay   *   t     +   By   *   t     +   Cy   *   t   +   d   
    
  且令给定的两端点为(x1,y1)、(x2,y2),以及两端点向量(xr1,yr1)、(xr2,yr2),   
  则:   
    
            x(0)     =   x1,       y(0)     =   y1   
            x(1)     =   x2,       y(1)     =   y2   
            x'(0)   =   xr1,     y'(0)   =   yr1   
            x'(1)   =   xr2,     y'(1)   =   yr2   
    
  绘出(x(t),y(t)),0<=t<=1,即为Hermite曲线。   
    
  2.Bezier曲线   
    
          Bezier曲线为给定两端点及另两参考点所得的三次曲线,它可说是Hermite   
  曲线的另一种表示方式。假设两端点为P1、P2,以及两参考点Pr1、Pr2,则   
  Bezier曲线换算成Hermite曲线的方式为:   
    
          R1   =   3*(Pr1-P1)   
          R2   =   3*(P2-Pr2)   
    
  R1、R2即为Hermite曲线的两端点向量。   
    
          由于Bezier曲线和Hermite曲线可以说是相同的,因此以下之说明我们便以   
  Hermite曲线为主。由Hermite曲线的定义,首先我们必须求出Ax,Bx...等值。   
  由定义中的条件:   
    
          x(0)     =   x1,     x(1)     =   x2,     x'(0)   =   xr1,     x'(1)   =   xr2   
    
  以及   
    
                                              2   
          x'(t)   =   3   *   Ax   *   t     +   2   *   Bx   *   t   +   Cx   
    
  可得:   
    
          ┌   0   0   0   1   ┐┌   Ax   ┐     ┌   x1     ┐   
          │   1   1   1   1   ││   Bx   │=│   x2     │   
          │   0   0   1   0   ││   Cx   │     │   xr1   │   
          └   3   2   1   0   ┘└   Dx   ┘     └   xr2   ┘   
    
  解之得:   
    
          ┌   Ax   ┐     ┌     2   -2     1     1   ┐┌   x1     ┐   
          │   Bx   │=│   -3     3   -2     1   ││   x2     │   
          │   Cx   │     │     0     0     1     0   ││   xr1   │   
          └   Dx   ┘     └     1     0     0     0   ┘└   xr2   ┘   
    
  因此   
    
          x(t)   =   (2*t^3   -   3*t^2   +   1)   *   x1   +   (-2*t^3   +   3*t^2)   *   x2   +   
                        (t^3   -   2*t^2   +   t)   *   xr1   +   (t^3   -   t^2)   *   xr2   
    
  同理   
    
          y(t)   =   (2*t^3   -   3*t^2   +   1)   *   y1   +   (-2*t^3   +   3*t^2)   *   y2   +   
                        (t^3   -   2*t^2   +   t)   *   yr1   +   (t^3   -   t^2)   *   yr2   
    
          上述的公式中,由于t的值是介于0与1之间,这对于我们在实际绘图上较不   
  方便,而且运算速度也比较慢。因此假设我们以n条直线来仿真Hermite曲线,   
  则我们必须将t值化成整数,使它成为0<=t<=n(注意n条连续直线需有n+1个点)。   
  令i=n*t代入上述公式,化简后可得:   
    
          x(i)   =   (m1*x1   +   m2*x2   +   m3*xr1   +   m4*xr2)   /   n^3   
          y(i)   =   (m1*y1   +   m2*y2   +   m3*yr1   +   m4*yr2)   /   n^3   
    
  其中   
    
          m1   =   2*i^3   -   3*n*i^2   +   n^3                 ,   0   <=   i   <=   n   
          m2   =   -2*i^3   +   3*n*i^2   
          m3   =   i^3   -   2*n*i^2   +   n^2*i   
          m4   =   i^3   -   n*i^2   
    
  如此我们便能很方便地求出仿真直线的各端点。然而上述公式中的乘法仍相当   
  多,对于m1~m4的计算上至少需5次乘法、2次移位乘法和6次加法(或4次乘法、   
  3次移位乘法和7次加法),在计算上仍然会浪费相当多时间(PC上的乘法约为   
  加法的近20倍,移位乘法则和加法相当),因此有必要再予以化简。如何简化   
  呢?由上述公式可发现,主要的乘法来自于i^3的计算,因此欲将之简化的最简   
  单的方式便是由前一个m1~m4值来求得后一个m1~m4值,藉此消减掉这个三次   
  方值的运算:   
    
          m1(i+1)   =   m1(i)   +   6*i^2   +   6*i   +   2   -   3*n*(2*i+1)   
          m2(i+1)   =   m2(i)   -   6*i^2   -   6*i   -   2   +   3*n*(2*i+1)   
          m3(i+1)   =   m3(i)   +   3*i^2   +   3*i   +   1   -   2*n*(2i+1)   +   n^2   
          m4(i+1)   =   m4(i)   +   3*i^2   +   3*i   +   1   -   n*(2*i+1)   
    
  现在便是要化简各式中后面的计算项次。由于这些项次有相当多的重复,故可   
  将之写成:   
    
          m1(i+1)   =   m1(i)   +   a   
          m2(i+1)   =   m2(i)   -   a   
          m3(i+1)   =   m3(i)   +   d   -   c   +   n^2   
          m4(i+1)   =   m4(i)   +   d   
          a   =   2*b   -   3*c   
          b   =   3*i^2   +   3*i   +   1   
          c   =   n*(2*i+1)   
          d   =   b-c   
    
  再进一步简化为:   
    
          e   =   2*i   +   1   
          c   =   n*e   
          b   =   3*i^2   +   3*i   +   1   
              =   (3*i+1)*i   +   (2*i+1)   
              =   (e+i)*i   +   e   
    
  整理一下成为(依计算顺序):   
    
          e     =   2*i   +   1   
          b     =   (e+i)*i   +   e   
          c     =   n*e   
          d     =   b-c   
          m4   =   m4   +   d   
          f     =   d-c   
          m3   =   m3   +   f   +   n^2   
          a     =   d   +   f   
          m2   =   m2   -   a   
          m1   =   m1   +   a   
    
  共计2次乘法、1次移位乘法和11次加法,等于是以两次加法代替了两次乘法,   
  其速度必然较快。记得m1~m4的初值为:   
    
          m1(0)   =   n^3   
          m2(0)   =   m3(0)   =   m4(0)   =   0   
    
          接下来我们要探讨一下模拟线数n的问题。倒底取多少模拟线数较为恰当?   
  采用的仿真线数太少,曲线将不够平滑,但若模拟线数太多,曲线绘制速度又   
  会太慢。据作者实际的测试,一般取n=20以上曲线便已相当平滑,但对于弯度   
  太大的曲线,其转折处仍约略可见,不过并不严重。由于在绘制曲线时,大都   
  以整数来运算(为求速度),因此仿真线数最好不要超出32,以避免运算结果   
  超出整数运算的值域。以下便是Hermite曲线和Bezier曲线的绘制程式:   
    
    
  #define   Iterative     24                               /*   曲线仿真的线数(必须小于32)   */   
  #define   Iterative2   (Iterative*Iterative)   
  #define   Iterative3   (Iterative2*Iterative)   
    
  void   DrawHermiteCurve(int   x1,int   y1,int   x2,int   y2,int   xr1,int   yr1,   
        int   xr2,int   yr2)   
      {   
        /*   ------------------------------------------------------------   
              作用:画出Hermite曲线   
              输入:x1,y1,x2,y2   =   曲线端点   
                          xr1,yr1,xr2,yr2   =   曲线两参考向量   
              作者:邱奕南   Chi'u   I-Nan   
              ------------------------------------------------------------   */   
        int   i,   oldx,   oldy,   m1,   m2,   m3,   m4,   x,   y,   k1,   k2;   
    
        oldx   =   x1;   
        oldy   =   y1;   
        m1   =   Iterative3;   
        m2   =   m3   =   m4   =   0;   
        for   (i=0;   i<Iterative;   i++)     /*   用Iterative条直线仿真   */   
            {   
              k1   =   (i   <<   1)   +   1;   
              k2   =   (k1+i)*i   +   k1;   
              m4   +=   (k2   -=   (k1   *=   Iterative));   
              m3   +=   (k1   =   k2   -   k1)   +   Iterative2;   
              m2   -=   (k2   +=   k1);   
              m1   +=   k2;   
              x   =   (int)   (((long)   x1*m1   +   (long)   x2*m2   +   (long)   xr1*m3   +   
                                      (long)   xr2*m4)   /   Iterative3);   
              y   =   (int)   (((long)   y1*m1   +   (long)   y2*m2   +   (long)   yr1*m3   +   
                                      (long)   yr2*m4)   /   Iterative3);   
              DrawLine(oldx,oldy,x,y);   
              oldx   =   x;   
              oldy   =   y;   
            }   
      }   
    
  void   DrawBezierCurve(int   x1,int   y1,int   x2,int   y2,int   xr1,int   yr1,   
        int   xr2,int   yr2)   
      {   
        /*   ------------------------------------------------------------   
              作用:画出Bezier曲线   
              输入:x1,y1,x2,y2   =   曲线端点   
                          xr1,yr1,xr2,yr2   =   曲线两参考点   
              作者:邱奕南   Chi'u   I-Nan   
              ------------------------------------------------------------   */   
        DrawHermiteCurve(x1,y1,x2,y2,3*(xr1-x1),3*(yr1-y1),3*(x2-xr2),3*(y2-yr2));   
      }   
    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息