Geometrie/Algoritmus de Casteljau
Z Wikiknih
Obsah |
[editovat] Popis
Pro řadu algoritmů s Bézierovou křivkou (výpočet bodu na křivce, zvýšení stupně Bézierovy křivky, rozdělení Bézierovy křivky atd.) bude základem algoritmus de Casteljau. Ukážeme si základní principy tohoto algoritmu.
[editovat] Vyjádření
Výchozím algoritmem je rekurentní výpočet Bernsteinových polynomů.

Vlastní algoritmus de Casteljau vypadá takto:
kde k = 1,...,n; i = 0,...,n-k.
[editovat] Výpočet bodu na Bézierově křivce
Pro výpočet bodu na Bézierově křivce můžeme použít algoritmus de Casteljau.
Když si výpočet graficky znázorníme, zjistíme, že se ve skutečnosti nejedná o nic jiného, než o postupné dělení úseček řídícího polygonu v zadaném poměru. Počet nově vzniklých bodů se v každém kroku zmenšuje o 1 a ve chvíli, kdy zůstane bod jediný, dostaneme hledaný bod křivky. Bod na Bézierově křivce můžeme rovněž vypočítat přímo pomocí vektorové rovnice Bézierovy křivky, kdy použijeme algoritmus pro výpočet Bernsteinových polynomů
[editovat] Rozdělení Bézierovy křivky
Pro rozdělení Bézierovy křivky v daném bodě na dvě křivky použijeme modifikovaného algoritmu de Casteljau. Pokud chceme rozdělit Bézierovu kubiku, bude dělícím bodem bod
a nově vytvořené kubiky budou určeny řídícími polygony:


[editovat] Skládání Bézierových křivek
Podmínkou hladkého spojení Bézierových křivek je zajištění požadované spojitosti (parametrické nebo geometrické) ve společném bodě těchto křivek. Mějme dánu Bézierovu křivku P = P(u), u ∈ <0,1> řídícím polygonem Pi (i=0,..,n) a Bézierovu křivku Q = Q(v), v ∈ <0,1> řídícím polygonem Qj(j = 0,...,n). Předpokládejme, že platí:
P(1) = Q(0) - počáteční bod křivky Q(v) je koncovým bodem křivky P(u).
Pro tečné vektory P'(1),Q'(0)platí:
P'(1) = m(Pm - Pm - 1) Q'(1) = n(Q1 - Q0)
Pokud chceme pro Bézierovy křivky ve společném bodě zajistit C1 spojitost (totožné tečné vektory), musí platit:
n(Q1 - Q0) = m(Pm - Pm - 1)
Pro Pm = Q0 dostaneme z této rovnice vztah pro výpočet bodu Q1:
Q1 = m / n(Pm - Pm - 1) + Pm
Pokud nemají obě křivky stejnou parametrizaci, je výpočet vrcholů navazujícího polygonu (který má být C1 nebo C2 spojitý) závislý na poměru parametrizace: Δ u0 : Δ u1. Stupeň spojitosti určuje počet definovaných vrcholů nově vytvořeného řídícího polygonu. Pro skládání křivek můžeme rovněž použít upraveného algoritmu de Casteljau.
[editovat] Zvýšení stupně Bézierovy křivky
Častým technickým požadavkem při modelování křivek bývá přidání dalšího bodu do řídícího polygonu tak, aby se výsledný tvar křivky nezměnil (hovoříme o zvýšení stupně aproximační křivky). Pro vyřešení tohoto problému můžeme použít modifikovaný algoritmus de Casteljau.
Pokud si vrcholy původního řídícího polygonu označíme jako
, pak pro vrcholy nového řídícího polygonu platí:

kde
ui = i / (n + 1),i = 0,...,n + 1
Při bližším pohledu na uvedený postup zjistíme, že neděláme nic jiného, než že původní parametr u jakoby „rozsekáme“ na n.(n + 1) částí, kdy původní body jsou umístěny vždy v násobcích (n + 1) a nové body umístíme do násobků n. Graficky vzato, každou úsečku původního řídícího polygonu rozdělíme na (n + 1) stejných částí a pak po každých n dílcích umístíme bod nový.
[editovat] Algoritmizace
Vrací bod na Bézierově křivce v obecném parametru s
public override Vector GetPoint(double s)
{
int n = ControlPoly.Count;
double t = (s - StartParam)/(EndParam-StartParam);
Vector[] points = new Vector[n];
for (int i=0;i<n;i++)
{
points[i] = ((RichPoint)(ctrlPoly[i])).Locate;
}
for (int j=0;j<n-1;j++)
for (int i=0;i<n-1;i++)
points[i]=points[i].lerp(t,points[i+1]);
return points[0];
}
Rozdělí Bézierovu křivku na dvě v bodě určeném prametrem s
s - parametr, ve kterém se má bod rozdělit
c1 - první nová křivka
c2 - druhá nová křivka
public override void Split(double s, out Curve c1, out Curve c2)
{
int n = ControlPoly.Count;
if (n>=2)
{
double t = (s- StartParam)/(EndParam-StartParam);
Vector[] pointsc1 = new Vector[n];
Vector[] pointsc2 = new Vector[n];
Vector[] points= new Vector[n];
for (int i=0;i<n;i++)
{
points[i] = ((RichPoint)(ctrlPoly[i])).Locate;
}
for (int j=0;j<n-1;j++)
{
pointsc1[j]= points[0];
pointsc2[n-1-j]= points[n-1-j];
for (int i=0;i<n-1;i++)
{
points[i]=points[i].lerp(t,points[i+1]);
}
}
pointsc1[n-1]= points[0];
pointsc2[0]= (Vector)points[0].Clone();
c1 = new BezierSynteticly(pointsc1);
c2 = new BezierSynteticly(pointsc2);
}
else
if (n==1)
{
c1 = new BezierSynteticly(ctrlPoly);
Vector v = (Vector)((RichPoint)ControlPoly[0]).Locate.Clone();
c2 = new BezierSynteticly(new Vector[]{v});
}
else
{
c1= new BezierSynteticly(new Vector[]{});
c2= new BezierSynteticly(new Vector[]{});
}
}
Vrátí Bezierovu křivku o stupeň vyšší
public void IncreaseDegreeByOne()
{
double ti=0;
int n = ControlPoly.Count;
Vector[] points= new Vector[n];
for (int i=0;i<n;i++)
{
points[i] = ((RichPoint)(ctrlPoly[i])).Locate;
}
for (int i=1;i<n;i++)
{
ti = ((double)i)/n;
RichPoint rp = (RichPoint)this.ControlPoly[i];
rp.Locate = points[i].lerp(ti,points[i-1]);
}
this.ControlPoly.Add(new RichPoint(points[n-1]));
}
public override RichPoint CreateRichPoint()
{
return new RichPoint(new Vector(0,0));
}
[editovat] Autoři
Tento text vypracovali studenti Univerzity Palackého v Olomouci katedry Matematické informatiky jako zápočtový úkol do předmětu Počítačová geometrie.