Geometrie/Algoritmus de Casteljau

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.

Vyjádření

editovat

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.

Výpočet bodu na Bézierově křivce

editovat

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ů

Rozdělení Bézierovy křivky

editovat

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:

 

 

Skládání Bézierových křivek

editovat

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   u ∈ <0,1> řídícím polygonem   (i=0,..,n) a Bézierovu křivku   v ∈ <0,1> řídícím polygonem  . Předpokládejme, že platí:

  - počáteční bod křivky   je koncovým bodem křivky  .

Pro tečné vektory  platí:

   


Pokud chceme pro Bézierovy křivky ve společném bodě zajistit C1 spojitost (totožné tečné vektory), musí platit:

 

Pro   dostaneme z této rovnice vztah pro výpočet bodu  :

 

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: Δ   : Δ  . 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.

Zvýšení stupně Bézierovy křivky

editovat

Č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

 

Při bližším pohledu na uvedený postup zjistíme, že neděláme nic jiného, než že původní parametr   jakoby „rozsekáme“ na   částí, kdy původní body jsou umístěny vždy v násobcích   a nové body umístíme do násobků  . Graficky vzato, každou úsečku původního řídícího polygonu rozdělíme na   stejných částí a pak po každých   dílcích umístíme bod nový.

Algoritmizace

editovat

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));
}

Autoři

editovat

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.