Cardinal樣條曲線的Javascript實現(代碼篇)


由上一篇文章得到了Cardinal曲線的矩陣表達式,下面就這個矩陣表達式就可以來對曲線進行插值了。

這里選用了JS來實現,完全是因為之前交作業的時候還不知道怎么在Xcode里建完整的C++OpenGL的項目,所以就用js在瀏覽器這個最大的跨平台UI上寫。。

先看之前得到的Cardinal插值的樣條曲線的矩陣,對每一段曲線PkPk+1來說,都可以通過擬合一個被參數化為P(u)函數(0<= u <=1)的圖形的形式:

,其中

同樣,M*P得到的是系數矩陣[a b c d]的轉置,s是引入的表示每個連接點處曲線尖銳程度的變量-張量

所以我們現在的期望是

輸入:n個控制點的xy軸坐標數組x[],y[],張量tension,每兩個控制點之間插入的密度grain

輸出:插值好的樣條曲線上控制點的一個數組

1.構造函數 function CSpline(x, y, grain, tension, n)

擁有的成員變量和成員函數:

function CSpline(x, y, grain, tension, n) {   
    var jd = new Array(100);  //用戶輸入的控制點位置數組,臨時變量存儲
    this.n0=n;   //控制點個數
    this.m = new Array(16);  //Mc矩陣
    this.Spline = new Array(1024);  //插值好的控制點數組
    CSpline.prototype.GetCardinalMatrix = function(a1) {}    //通過給定的tension值生成Mc矩陣
    CSpline.prototype.Matrix = function(a, b, c, d, u){}   //計算P(u)的值,xy分量均相同
    CSpline.prototype.CubicSpline = function(np, knots, grain, tension) {}   //插值函數

    //臨時函數,建立曲線控制點數組jd,並調用CubicSpline函數計算插值曲線
    function CSpline(x, y, grain, tension, n)      
    { 
        for(var i=1; i<=np; i++){
          jd[i] = new CPT(x[i-1],y[i-1]);   //內部點
        }
        jd[0] = new CPT(x[0],y[0]);  //補上隱含的整條曲線起始點
        jd[np+1] = new CPT(x[np-1],y[np-1]);    //補上隱含的整條曲線終止點
        np=np+2;   
        this.CubicSpline(np, jd, grain, tension);
    }
}      

這里成員變量通過構造函數分別在實例中存儲,而成員函數則在對應的原型函數中存儲。

2.計算Mc矩陣函數GetCardinalMatrix = function(a1)

根據輸入的平滑度 tension 值計算Mc矩陣

CSpline.prototype.GetCardinalMatrix = function(a1) {
    this.m[0]=-a1; this.m[1]=2.0-a1; this.m[2]=a1-2.; this.m[3]=a1;                 
    this.m[4]=2.*a1; this.m[5]=a1-3.; this.m[8]=-a1; this.m[9]=0.;
    this.m[12]=0.; this.m[13]=1.; this.m[6]=3.-2*a1; this.m[7]=-a1;
    this.m[10]=a1; this.m[11]=0.; this.m[14]=0.; this.m[15]=0.;
} 

這里m是一個4*4的矩陣,a1表示tension值

3.計算P(u)的值

輸入4個點Pk-1,Pk,Pk+1,Pk+2的值(x分量或者y分量,以及參數化好的u值),返回計算得到的P(u)的值

CSpline.prototype.Matrix = function(p0, p1, p2, p3, u){ 
    //求解系數
    var a, b, c, d;
    a=this.m[0]*p0+this.m[1]*p1+this.m[2]*p2+this.m[3]*p3;    
    b=this.m[4]*p0+this.m[5]*p1+this.m[6]*p2+this.m[7]*p3; 
    c=this.m[8]*p0+this.m[9]*p1+this.m[10]*p2+this.m[11]*p3; 
    d=this.m[12]*p0+this.m[13]*p1+this.m[14]*p2+this.m[15]*p3; 
    return(d+u*(c+u*(b+u*a))); //au^3+bu^2+cu+d
}

4.主要繪制函數CSpline.prototype.CubicSpline = function(np, knots, grain, tension)  

CSpline.prototype.CubicSpline = function(np, knots, grain, tension) {
    alpha = new Array(50);
    var k0, kml, k1, k2;
        //獲取Mc矩陣
        this.GetCardinalMatrix(tension);
        //對每兩個關鍵點之間的插值點進行參數化到0~1之間
    for(var i=0; i<grain; i++){
        alpha[i]=i*1.0/grain;
    }
        //從最開始的四個點開始,給第一段曲線插值
    kml = 0;
    k0 = 1;
    k1 = 2;
    k2 = 3;
    this.s = 0; //紀錄總共插值后的點數
        //兩次循環第一次對輸入的控制點遍歷,第二次對每兩個控制點之間插值,分別計算xy分量上得出的插值后的函數值,k值分別+1
    for(var i =1; i<this.n0; i++){
        for(var j=0; j<grain; j++){
            cpx = this.Matrix(knots[kml].x, knots[k0].x, knots[k1].x, knots[k2].x, alpha[j]);
            cpy = this.Matrix(knots[kml].y, knots[k0].y, knots[k1].y, knots[k2].y, alpha[j]);
            this.Spline[this.s] = new CPT(cpx, cpy);
            this.s++;
        }
        kml++; k0++; k1++; k2++;
    }
}

最后的結果截圖如下:

完整的代碼正在上傳github。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM