免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

穿過已知點(diǎn)畫平滑曲線(3次貝塞爾曲線)

 mediatv 2022-02-24

原文地址:http://www./research/ 
bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION

Interpolation with Bezier Curves  貝塞爾插值

 

A very simple method of smoothing polygons 一種非常簡單的多邊形平滑方法

 

翻譯:唐風(fēng)

之前 comp.graphic.algorithms 上有一個(gè)討論,是關(guān)于怎么樣使用曲線對多邊形進(jìn)行插值處理,使得最終產(chǎn)生的曲線是光滑的而且能通過所有的頂點(diǎn)。Gernot Hoffmann 建議說使用著名的 B-Spline 來進(jìn)行插值。這里有他當(dāng)時(shí)的文章。B-Spline 在這里效果很好,它看起來就像是一個(gè)固定在多邊形頂點(diǎn)上的橡皮尺(elastic ruler)。

 

spline_polygon1    spline_polygon2

 


 

bezier_interpolation但我有個(gè)大膽的推測,我覺得肯定還存在更簡單的方法。比如,使用三次貝塞曲線(cubic Bezier)進(jìn)行近似。貝塞爾曲線有兩個(gè)固定點(diǎn)(起點(diǎn)和終點(diǎn)),另加兩個(gè)決定曲線形狀的控制點(diǎn)(CP)。關(guān)于貝塞爾曲線的更多知識(shí)可以在搜索引擎中找到,比如,你可以參考 Paul Bourke 的站點(diǎn) 。 現(xiàn)在給貝塞爾曲線的錨點(diǎn)(固定點(diǎn)),也就是多邊形的某一對頂點(diǎn),那么問題是,我們怎么計(jì)算控制點(diǎn)的位置?我運(yùn)行 Xara X 然后畫出了右邊這個(gè)圖形,這很簡單,所以我決定嘗試下計(jì)算出它們的坐標(biāo)。很顯然,多邊形兩條相鄰邊的兩個(gè)控制點(diǎn)與這兩個(gè)控制點(diǎn)之間的頂點(diǎn)應(yīng)該在一條直線 上,只有這樣,兩條相鄰的插值曲線才能平滑地連接在一起。所以,這兩個(gè)控制點(diǎn)應(yīng)該是相對于頂點(diǎn)是對稱的,不過,也不全是……,因?yàn)檎嬲膶ΨQ就要求它們與 中心點(diǎn)的距離應(yīng)該是相等的,但對于我們的情況中并不完全是這樣的。一開始,我試著先算出多邊形兩條邊的角平分線,然后把控制點(diǎn)放在這條角平分線的垂直線 上。但從圖上可以看到,控制點(diǎn)的連線并不會(huì)總是垂直于角平分線的。

 


 

 

最終,我找到一個(gè)非常簡單的辦法,不需要任何復(fù)雜的數(shù)學(xué)計(jì)算。首先,我們計(jì)算出多邊形所有邊線的中點(diǎn),Ai。

 

bezier_interpolation_s1

 


 

然后連接起相鄰邊中點(diǎn),得到很多線段,記為 Ci 。并用圖記的方法計(jì)算出 Bi 點(diǎn)。

bezier_interpolation_s2

 


 

最后一步,只需要簡單地將 Ci 進(jìn)行平移,平移的路徑就是每條線段上 Bi 到對應(yīng)頂點(diǎn)的路徑。就這樣,我們計(jì)算出了貝塞爾曲線的控制點(diǎn),平滑的結(jié)果看起來也很棒。

bezier_interpolation_s3

 


 

這里還可以做一點(diǎn)小小的改進(jìn),因?yàn)槲覀円呀?jīng)得到了一條決定控制點(diǎn)的直線,所以,我們可以根據(jù)需要,使控制點(diǎn)在這條直線上移動(dòng),這樣可以改變插值曲線 的狀態(tài)。我使用了一個(gè)與控制點(diǎn)和頂點(diǎn)初始距離相關(guān)的系數(shù) K ,用來沿直線移動(dòng)控制點(diǎn)??刂泣c(diǎn)離頂點(diǎn)越遠(yuǎn),圖形看起來就越銳利。

bezier_interpolation_s4

 


 

下面是用原始形狀和系統(tǒng)K=1.0的貝塞爾插值兩種方法來描畫的 SVG 的獅子。

bezier_lion1   bezier_lion2

 


 

下面是放大圖

bezier_lion3   bezier_lion4

 


 

這個(gè)方法對于自相關(guān)的多邊形也適用,下面的例子可以看到,結(jié)果非常有意思:

 

bezier_self_intersecting1

 

 


 

bezier_self_intersecting2

 


 

bezier_self_intersecting3

 


 

 

這個(gè)方法只是探索和經(jīng)驗(yàn)式的,如果從嚴(yán)格的數(shù)學(xué)模型的角度看它可能是錯(cuò)誤的。但在實(shí)際使用中的效果已經(jīng)足夠好了,而 且這個(gè)方法只需要最小的計(jì)算量。下面的代碼就是用來畫出上面獅子圖像的。這些代碼并沒有進(jìn)行優(yōu)化,只是用來演示的。里面有些變量計(jì)算了兩次,在實(shí)際程序 中,如果連續(xù)的步驟中都用到同一個(gè)變量值,我們可以先緩存變量值進(jìn)行復(fù)用(以避免重復(fù)的計(jì)算)。

This method is pure heuristic and empiric. It probably gives 
a wrong result from the point of view of strict mathematical
modeling. But in practice the result is good enough and it
requires absolute minimum of calculations. Below is the source code
that has been used to generate the lions shown above. It's
not optimal and just an illustration. It calculates some variables
twice, while in real programs we can store and reuse them in the
  1. // Assume we need to calculate the control  
  2.    // points between (x1,y1) and (x2,y2).  
  3.    // Then x0,y0 - the previous vertex,  
  4.    //      x3,y3 - the next one.  
  5.   
  6.    double xc1 = (x0 + x1) / 2.0;  
  7.    double yc1 = (y0 + y1) / 2.0;  
  8.    double xc2 = (x1 + x2) / 2.0;  
  9.    double yc2 = (y1 + y2) / 2.0;  
  10.    double xc3 = (x2 + x3) / 2.0;  
  11.    double yc3 = (y2 + y3) / 2.0;  
  12.   
  13.    double len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));  
  14.    double len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));  
  15.    double len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));  
  16.   
  17.    double k1 = len1 / (len1 + len2);  
  18.    double k2 = len2 / (len2 + len3);  
  19.   
  20.    double xm1 = xc1 + (xc2 - xc1) * k1;  
  21.    double ym1 = yc1 + (yc2 - yc1) * k1;  
  22.   
  23.    double xm2 = xc2 + (xc3 - xc2) * k2;  
  24.    double ym2 = yc2 + (yc3 - yc2) * k2;  
  25.   
  26.    // Resulting control points. Here smooth_value is mentioned  
  27.    // above coefficient K whose value should be in range [0...1].  
  28.    ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;  
  29.    ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;  
  30.   
  31.    ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;  
  32.    ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;  
 

consecutive steps.

使用三次貝塞爾近似的代碼:

  1. // Number of intermediate points between two source ones,  
  2. // Actually, this value should be calculated in some way,  
  3. // Obviously, depending on the real length of the curve.  
  4. // But I don't know any elegant and fast solution for this  
  5. // problem.  
  6. #define NUM_STEPS 20  
  7.   
  8. void curve4(Polygon* p,  
  9.             double x1, double y1,   //Anchor1  
  10.             double x2, double y2,   //Control1  
  11.             double x3, double y3,   //Control2  
  12.             double x4, double y4)   //Anchor2  
  13. {  
  14.     double dx1 = x2 - x1;  
  15.     double dy1 = y2 - y1;  
  16.     double dx2 = x3 - x2;  
  17.     double dy2 = y3 - y2;  
  18.     double dx3 = x4 - x3;  
  19.     double dy3 = y4 - y3;  
  20.   
  21.     double subdiv_step  = 1.0 / (NUM_STEPS + 1);  
  22.     double subdiv_step2 = subdiv_step*subdiv_step;  
  23.     double subdiv_step3 = subdiv_step*subdiv_step*subdiv_step;  
  24.   
  25.     double pre1 = 3.0 * subdiv_step;  
  26.     double pre2 = 3.0 * subdiv_step2;  
  27.     double pre4 = 6.0 * subdiv_step2;  
  28.     double pre5 = 6.0 * subdiv_step3;  
  29.   
  30.     double tmp1x = x1 - x2 * 2.0 + x3;  
  31.     double tmp1y = y1 - y2 * 2.0 + y3;  
  32.   
  33.     double tmp2x = (x2 - x3)*3.0 - x1 + x4;  
  34.     double tmp2y = (y2 - y3)*3.0 - y1 + y4;  
  35.   
  36.     double fx = x1;  
  37.     double fy = y1;  
  38.   
  39.     double dfx = (x2 - x1)*pre1 + tmp1x*pre2 + tmp2x*subdiv_step3;  
  40.     double dfy = (y2 - y1)*pre1 + tmp1y*pre2 + tmp2y*subdiv_step3;  
  41.   
  42.     double ddfx = tmp1x*pre4 + tmp2x*pre5;  
  43.     double ddfy = tmp1y*pre4 + tmp2y*pre5;  
  44.   
  45.     double dddfx = tmp2x*pre5;  
  46.     double dddfy = tmp2y*pre5;  
  47.   
  48.     int step = NUM_STEPS;  
  49.   
  50.     // Suppose, we have some abstract object Polygon which  
  51.     // has method AddVertex(x, y), similar to LineTo in  
  52.     // many graphical APIs.  
  53.     // Note, that the loop has only operation add!  
  54.     while(step--)  
  55.     {  
  56.         fx   += dfx;  
  57.         fy   += dfy;  
  58.         dfx  += ddfx;  
  59.         dfy  += ddfy;  
  60.         ddfx += dddfx;  
  61.         ddfy += dddfy;  
  62.         p->AddVertex(fx, fy);  
  63.     }  
  64.     p->AddVertex(x4, y4); // Last step must go exactly to x4, y4  
  65. }  

你可以下載一個(gè)能運(yùn)行的畫獅子的例子,對它進(jìn)行旋轉(zhuǎn)和縮放,也可以生成一些隨機(jī)的多邊形。點(diǎn)左鍵并拖動(dòng)它可以圍繞中 心點(diǎn)旋轉(zhuǎn)和縮放圖像。點(diǎn)右鍵并從左向右拖動(dòng),可以改變系統(tǒng)數(shù)K。 K=1時(shí)大約是距窗口左邊100像素處。每次雙擊會(huì)產(chǎn)生一個(gè)隨機(jī)的多邊形,對于這些多邊形,也可以進(jìn)行旋轉(zhuǎn)、縮放以及改變K值的操作。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多