Ukázka a vlastnosti
Pro křivku definovanou čtyřmi body ve 2D, dostaneme P_x(t)=w_0(t)P_{0,x}+w_1(t)P_{1,x}+w_2(t)P_{2,x}+w_3(t)P_{3,x} P_y(t)=w_0(t)P_{0,y}+w_1(t)P_{1,y}+w_2(t)P_{2,y}+w_3(t)P_{3,y} Křivka definovaná čtyřmi body se nazývá křivka třetího stupně. Připomeňme, že parametr t nabývá hodnot <0;1>. Bézierova křivka třetího stupně může vypadat třeba takto
![]() |
![]() |
![]() |
![]() |
Vstupní čtyři body zadává uživatel a jejich změnou je schopen docílit změny výsledné křivky. Při editaci je třeba mít na paměti tři základní vlastnosti
- křivka nikdy neopustí konvexní obal definovaný vstupními body
- křivka bude vždy procházet prvním a posledním bodem
- směr křivky v koncových bodech je určen sousedními body
Váhové funkce
Ze vzorců výše vyplývá, že krom zadaných vstupních bodů budeme potřebovat ještě funkce w_i. Tyto funkce jsou generovány z Bernsteinových polynomů, které jsou definovány jako w_k(t)=\binom{n}{k}(1-t)^{n-k}(t)^k kde n je počet stupňů výsledné křivky. Počet stupňů se pak rovná počtu řídících bodů mínus jedna. Vypočítejme tedy funkce w_i pro křivku třetího stupně (čtyři řídící body) \begin{array}{lcl} w_0(t)&=&\binom{3}{0}(1-t)^{3-0}(t)^0= \\ &=&1(1-t)^3\cdot1= \\ &=&(1-t)^3 \\ \end{array} \begin{array}{lcl} w_1(t)&=&\binom{3}{1}(1-t)^{3-1}(t)^1= \\ &=&3(1-t)^2t^1= \\ &=&3(1-t)^2t \\ \end{array} \begin{array}{lcl} w_2(t)&=&\binom{3}{2}(1-t)^{3-2}(t)^2= \\ &=&3(1-t)^1t^2= \\ &=&3(1-t)t^2 \\ \end{array} \begin{array}{lcl} w_3(t)&=&\binom{3}{3}(1-t)^{3-3}(t)^3= \\ &=&1(1-t)^0t^3= \\ &=&1t^3= \\ &=&t^3 \\ \end{array} a vynesme je pro názornost do grafu
Příklad
Zkusme dle obecného vztahu výše, postupně vypočítat Bézierovu křivku pro následující čtyři bodyP | x | y |
0 | 0 | 0 |
1 | 30 | 50 |
2 | 60 | 50 |
3 | 90 | 0 |
Dosadíme pro x P_x(t)=(1-t)^3\cdot0+3(1-t)t^2\cdot30+3(1-t)^2t\cdot60+t^3\cdot90 a pro y P_y(t)=(1-t)^3\cdot0+3(1-t)t^2\cdot50+3(1-t)^2t\cdot50+t^3\cdot0 Po úpravách pak dostáváme \begin{align*} P_x(t)&=30\cdot3(1-t)t^2+60\cdot3(1-t)^2t+90t^3 \\ P_y(t)&=50\cdot3(1-t)t^2+50\cdot3(1-t)^2t \end{align*} Zkusme vypočítat hodnoty x a y pro bod v čase t=0 \begin{array}{lcl} P_x(0)&=&30\cdot3(1-0)0^2+60\cdot3(1-0)^2\cdot0+90\cdot0^3= \\ &=&30\cdot3\cdot1\cdot0+60\cdot3\cdot1\cdot0+90\cdot0= \\ &=&0+0+0= \\ &=&0 \\ P_y(0)&=&50 \cdot 3(1-0)0^2+50\cdot3(1-0)^20= \\ &=&50\cdot3\cdot1 \cdot 0+50\cdot3\cdot1\cdot0= \\ &=&0+0= \\ &=&0 \\ \end{array} a přidejme také výpočet pro čas t=1 \begin{array}{lcl} P_x(1)&=&30 \cdot 3(1-1)1^2+60 \cdot 3(1-1)^2 \cdot 1+90 \cdot 1^3= \\ &=&30 \cdot 3\cdot0 \cdot 1+60 \cdot 3\cdot0+90\cdot1= \\ &=&0+0+90= \\ &=&90 \\ P_y(1)&=&50\cdot3(1-1)1^2+50 \cdot 3(1-1)^2 \cdot 1= \\ &=&50\cdot3 \cdot 0 \cdot 1+50\cdot3\cdot0\cdot1= \\ &=&0+0= \\ &=&0 \\ \end{array} Jak vidíme, dostali jsme první bod výsledné křivky [0,0] a poslední [90,0]. Toto koresponduje s 2. vlastností Bézierových křivek, tedy že první bod musí odpovídat bodu P_0 a poslední bodu P_{n-1}. Stejným způsobem vypočítáme hodnoty pro x a y na celém intervalu t.

Implementace
Algoritmus má pár zvláštností, které můžou být v rozporu s naší individuální představou. Pseudokód pro výpočet křivky třetího stupně může vypadat taktod = 0.01; for(t = 0, t <= 1; t = t + d) { w0 = (1-t)*(1-t)*(1-t) w1 = 3*(1-t)*(1-t)*t w2 = 3*(1-t)*t*t w3 = t*t*t; x = w0*P0x + w1*P1x + w2*P2x + w3*P3x; y = w0*P0y + w1*P1y + w2*P2y + w3*P3y; putPixel(x, y); }Narážíme na problém - nejsme schopni spočítat všechny hodnoty na intervalu od 0 do 1! Pracujeme v diskrétním prostoru, což pro nás znamená použití určitého kroku. Vypočítáme tedy množinu bodů s krokem definovaným v proměnné d a ty vykreslíme na obrazovku. Nedostaneme krásnou křivku jako na obrázcích výše, ale více či méně separovaných bodů. Nabízí se řešení nastavit d dostatečně malé. Tento způsob nebude uspokojivě fungovat z několika důvodů. Pokud bude d příliš malé, budeme počítat hodnoty pro menší velikost, než je šířka pixelu na obrazovce. Pokud bude příliš velké, budou nám vznikat díry. Například pro d=0.2 dostaneme hodnoty pro pouhých šest bodů {0, 0.2, 0.4, 0.6, 0.8, 1}. Jako optimální řešení volíme spojení dvou bezprostředně za sebou následujících bodů úsečkou.
d = 0.01; predchozi_x = x0; predchozi_y = y0; for(t = 0, t <= 1; t = t + d) { w0 = (1-t)*(1-t)*(1-t) w1 = 3*(1-t)*(1-t)*t w2 = 3*(1-t)*t*t w3 = t*t*t; x = w0*P0x + w1*P1x + w2*P2x + w3*P3x; y = w0*P0y + w1*P1y + w2*P2y + w3*P3y; line(predchozi_x, predchozi_y, x, y); predchozi_x = x; predchozi_y = y; }Při zvolení vhodného d si tuto aproximaci můžeme dovolit, protože i oblouček můžeme diskrétně chápat jako spojení více krátkých úseček.
Literatura a odkazy
KOLCUN, A. Základy počítačovej grafiky. Učební texty, Ostrava 2006.ŽÁRA, J.; SOCHOR, J.; BENEŠ, B.; FELKEL, P. Moderní počítačová grafika. Computerpress, Brno 2004.
http://lubovo.misto.cz/_MAIL_/curves/ - pěkné zpracování tématiky v češtině, včetně appletů
http://herakles.zcu.cz/education/zpg/cviceni.php?no=11 - materiály ze Zápodočeské Univerzity v Plzni, také interaktivní
http://processingjs.nihongoresources.com/bezierinfo/ - spousta dalších informací a detailů (anglicky)
http://en.wikipedia.org/wiki/B%C3%A9zier_curve
Žádné komentáře:
Okomentovat