sogotobj 发表于 2013-1-26 14:06:15

[转载] Hermite 与 Bezier 曲线的绘制

发信人:william@cis_nctu(何陋居主),信区:programming
标    题:[转载]Hermite与Bezier曲线的绘制
发信站:交大资科_BBS(May2500:32:411995)
转信站:cis_nctu


      From:Chi'uI-Nan                                          *Area:90C语言
   To:All                           Date:03May95   22:37:26
      Subj:Hermite与Bezier曲线的绘制

**********************************************************************
*Hermite与Bezier曲线绘制方法研究                                    *
*作者:邱奕南(Chi'uI-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

可得:

          ┌0001┐┌Ax┐    ┌x1    ┐
          │1111││Bx│=│x2    │
          │0010││Cx│    │xr1│
          └3210┘└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曲线的绘制程式:


#defineIterative    24                              /*曲线仿真的线数(必须小于32)*/
#defineIterative2(Iterative*Iterative)
#defineIterative3(Iterative2*Iterative)

voidDrawHermiteCurve(intx1,inty1,intx2,inty2,intxr1,intyr1,
      intxr2,intyr2)
      {
      /*------------------------------------------------------------
            作用:画出Hermite曲线
            输入:x1,y1,x2,y2=曲线端点
                        xr1,yr1,xr2,yr2=曲线两参考向量
            作者:邱奕南Chi'uI-Nan
            ------------------------------------------------------------*/
      inti,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;
            }
      }

voidDrawBezierCurve(intx1,inty1,intx2,inty2,intxr1,intyr1,
      intxr2,intyr2)
      {
      /*------------------------------------------------------------
            作用:画出Bezier曲线
            输入:x1,y1,x2,y2=曲线端点
                        xr1,yr1,xr2,yr2=曲线两参考点
            作者:邱奕南Chi'uI-Nan
            ------------------------------------------------------------*/
      DrawHermiteCurve(x1,y1,x2,y2,3*(xr1-x1),3*(yr1-y1),3*(x2-xr2),3*(y2-yr2));
      }

                                  *青衫诗客--小邱*

--Via中文银版快信V2.28C
    !Origin:档案货柜,欢迎您来挖宝,28800BPS,04-230-2080;(90:2010/622)
________________________________________
---------------------------- ------------------------
≡何陋居≡中学生以伏案读书为主,大学生则应起而高瞻远瞩。    Whitehead.
---------------------------- ------------------------
页: [1]
查看完整版本: [转载] Hermite 与 Bezier 曲线的绘制