如何绘制线性曲线

来源:互联网 发布:centos nginx yum 安装 编辑:程序博客网 时间:2024/04/28 12:03

绘制curveTO单曲线很简单 但是复杂的线性弯曲曲线该如何绘制,如果硬连的话,中间的过渡很不协调弯弯曲曲的和 线性 似乎不是很对应......
连接平滑曲线通常是两个方法:两个curveTo拼在一起,或者使用lineTo。前者的效率比较好,效果也好,但是我不是很理解计算方法。后者的话:
有一个公式可以算是cubicBerzier曲线的定义,如下:^是乘方
P(u)=A0+(3u^2-2u^3)(A1-A0)+(u-2u^2+u^3)T0+(u^3-u^2)T1

则根据这个定义可以写出下面的代码:
function cubicCurve(lstX:int,lstY:int,
                              ctrlX1:int,ctrlY1:int,
                              ctrlX2:int,ctrlY2:int,
                              x:int,y:int,
                              u:Number):Point{
        var a0:Point = new Point(lstX,lstY);
        var t0:Point = new Point(ctrlX1,ctrlY1);
        var t1:Point = new Point(ctrlX2,ctrlY2);
        var a1:Point = new Point(x,y);    
        var m2:Number = (3-2*u)*u*u;
        var m3:Number = 3*u*(1-u)*(1-u);
        var m4:Number = 3*u*u*(u-1);
        var c:Point = a1.subtract(a0);
        var d:Point = t0.subtract(a0);
        var e:Point = a1.subtract(t1);
        var f:Point
        c.x *= m2;
        c.y *= m2;
        c = c.add(a0);
        d.x *= m3;
        d.y *= m3;
        e.x *= m4;
        e.y *= m4;
        return c.add(e).add(d);    
    }

这样就得到了一个 u 对应的点。用合适的步长在(0,1)取得不同的 u 就得到了点的集合,用lineTo连接到一起即可。

drawCubicCurve(ax1,ay1,cx1,cy1,cx2,cy2,ax2,ay2){
     moveTo(ax1,ay1);
     for(var i =0;i<1;i+=0.05){
         var p = cubicCurve(ax1,ay1,cx1,cy1,cx2,cy2,ax2,ay2,i); 
         lineTo(p.x,p.y)
     }
}

没有测试

=======================================================================

参考:
一下参考来自http://math.ntnu.edu.tw/~cyc/  國立台灣師範大學數學系  陳創義

利用Bezier曲線及F曲線畫平滑曲線
國立台灣師範大學數學系  陳創義
E-mail:cyc@math.ntnu.edu.tw
網頁:http://math.ntnu.edu.tw/~cyc/

Bezier曲線及F曲線是畫平滑曲線常用到的曲線,例如:小畫家及word等裡頭的繪圖工具,畫平滑曲線是採用Bezier曲線,我們只要點出起點及終點,然到點出一、兩個控制彎曲程度的控制點後,一條平滑曲線就完成。Bezier曲線就是控制起點、終點及中間彎曲部分的幾個控制點來繪出平滑曲線。至於F曲線是利用三次曲線,控制起點、終點及它們的切向量,來繪出平滑曲線,它的好處是一段一段的F曲線連接起來在連接處可以較平滑,有些繪圖軟體也使用此種曲線。事實上,Bezier曲線也可以做到連接處能夠平滑的過渡到另一段曲線。我們將把這兩種曲線利用GSP軟體做成巨集,使用起來比在小畫家或word方便很多,而且可隨時調整,甚至可做成動態效果。在GSP裡你可以作更多的控制點以控制更多的彎曲。
Bezier曲線的作法如下(我們以5個控制點為例):
1.        給5個點A0,A1,A2,A3,A4,並畫線段A0A1,然後在線段A0A1上取一動點B;
2.        依序選取點A0,A1,B,在Transform功能表內,標定比值A0B/A0A1;
3.        依序以點A1,A2,A3為伸縮中心,A0B/A0A1為比值,分別將點A2,A3,A4作伸縮變換,產生點B1,B2,B3;
4.        再依序以點B,B1,B2為伸縮中心,A0B/A0A1為比值,分別將點B1,B2,B3作伸縮變換,產生點C0,C1,C2;
5.        再依序以點C0,C1為伸縮中心,A0B/A0A1為比值,分別將點C1,C2作伸縮變換,產生點D0,D1;
6.        再依序以點D0為伸縮中心,A0B/A0A1為比值,將點D1作伸縮變換,產生點E0;
7.        選取點E0及點B作軌跡,產生當B在線段A0A1上變動時點E0的軌跡【就是五個控制點的Bezier曲線】;
8.        只留下控制點A0,A1,A2,A3,A4及軌跡,其餘都隱藏,然後選取這五個控制點及軌跡作巨集(5bezier.gss)。

※        上述共作了9次伸縮變換,如果作n+1個點A0,A1,A2,...,An-1,An,共要作 次的伸縮變換。
※        作n+1個點A0,A1,A2,...,An-1,An的Bezier曲線的參數式α(t)為
            
因此,在t=0時的切向量α'(0)=n(A1-A0);在t=1時的切向量α'(1)=n(An-1-An)。
由這個訊息,我們可以作另一個巨集,把兩段Bezier曲線平滑的接在一起,也就是把前一段曲線的終點An作為後一段曲線的起點A0,將前一段的控制點An-1作對稱於An所產生的點作為後一段曲線的控制點A1。(例如:5_bezier.gss)

令P(u),0&pound;u&pound;1是一條起點在A0、終點在A1、在A0的切向量為T0、在A1的切向量為T1的三次參數曲線,也就是 且P(0)=A0,P'(0)=T0,P(1)=A1,P'(1)=T1,所以
       P(u)=A0+(3u2-2u3)(A1-A0)+(u-2u2+u3)T0+(u3-u2)T1, 0&pound;u&pound;1.
稱此曲線為F曲線。
F曲線巨集作法如下:
1.        給出四個點A0、T0、A1、T1,畫線段A0T0,並在線段A0T0上取一動點B;
【向量A0T0表切向量T0,向量A1T1表切向量T1】
2.        依序選取A0、T0、B,並測量其比值[m1]=A0B/A0T0;
【參數u=[m1]】
3.        計算[m2]=3u2-2u3,[m3]=u-2u2+u3,[m4]=u3-u2;
4.        以為A0伸縮中心,分別以比值[m2]、[m3],將點A1、點T0作伸縮變換,產生點C、點D,再以A1伸縮中心,比值[m4],將點T1作伸縮變換,產生點E;
5.        將點C以向量A0D作平移,產生點F,再將點F以向量A1E作平移,產生點G;
6.        作當點B在線段A0T0上移動時,點G的軌跡;
7.        留下點A0、點T0、點A1、點T1及軌跡,其餘全部隱藏,再取點A0、T0、A1、T1及軌跡作巨集。(f_curve.gss)

※        兩條F曲線相接連的地方只是到切向量相同,若要更平滑,可用5次的參數式,要求曲率中心相同。
※        上述的兩種曲線,都可以用在三維直角坐標檔案上。


練習:
1.        作其他數的Bezier曲線巨集。
2.        利用這些曲線來畫臉譜並加入動態。



出错是有可能的,我原来使用8.5写的。发上来时又改了改。整个代码是不方便发上来的,抱歉。

err,看出来为什么出错了,lineTo在as3中是graphics的方法。

两个curve的算法我不是很确定,大概是这个样子:

如果两个curveTo,他们在控制点连线的中间处连接,则是平滑的(2阶berzier曲线的对称性)
于是:

moveTo(a1.x,a1.y);
var c1:Point = new Point(controlX1,controlY1);
var c2:Point = new Point(controlX2,controlY2);
var m:Point = Point.interpolate(c1,c2,0.5);
curveTo(c1.x,c1.y,m.x,m.y);
curveTo(c2.x,c2.y,a2.x,a2.y);

经过一定研究.弄出来了封闭平滑过渡曲线1.GIF

原创粉丝点击