Představme konkrétní parametrickou křivku, která vychází z předpisu
\[
P(t)=w_0(t)P_0+w_1(t)P_1+w_2(t)P_2+...+w_n(t)P_n
\]
kde $w$ jsou váhové funkce a $P$ vstupní body.
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 článku se budu odkazovat na konkrétní vlastnost použitím jejího pořadí v seznamu výše.
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 body
P |
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 takto
d = 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