Nov 04

Postanowiłem napisać co nieco na temat krzywych Béziera – temat wg mnie ciekawy, choć na pierwszy rzut oka wydający się niełatwym. Przedstawię także przykładową implementację w Action Script 3.0 programu rysującego takie krzywe.

bezierCurveSample

Przykładowa krzywa trzeciego stopnia o czterech punktach kontrolnych P1=(50,300) , P2=(100,100) , P3=(300,50) , P4=(350,250), nakreślona we Flash’u.

1. Wstęp

Krzywe Béziera, to parametryczne krzywe opracowane niezależnie przez Pierre’a Béziera oraz Paula de Casteljau. Pierwszy z nich rozpowszechnił je poprzez swoje publikacje we Francji w latach 60. i wykorzystywanie ich przy projektowaniu karoserii samochodowych. Drugi natomiast stworzył algorytm rekurencyjny pozwalający obliczać wartości wielomianów Bernsteina, co jest równoważne obliczaniu punktów krzywej Béziera.

Flash, Illustrator, Photoshop, programy graficzne 3D czy CAD posiadają gotowe narzędzia, które pozwalają tworzyć krzywe B. w sposób o wiele bardziej wydajny niż przedstawiony przeze mnie, jednak myślę, że używanie gotowego narzędzia nie jest tak ciekawe jak napisanie go własnoręcznie.

2. Matematyczne podstawy

Dowolna krzywa Béziera n-tego stopnia wyrażona jest wzorem (w1)

, w którym składowa

nazywana wielomianami bazowymi Bernsteina ma postać (w2)

, natomiast

jest i-tym punktem kontrolnym krzywej.

Po podstawieniu wyrażenia (w2) do (w1) otrzymujemy wzór ogólny (w3)


3. Wyprowadzenie wzoru na krzywe Béziera stopnia trzeciego (n = 3)

Po podstawieniu pod wzór (w3) n=3 i rozwinięciu wyrażenia pod znakiem sigma, otrzymujemy

Biorąc pod uwagę fakt, że

oraz

otrzymujemy ostateczny wzór na krzywą Béziera stopnia trzeciego (w4)

Aby wyznaczyć współrzędne punktów tej krzywej, wzór (w4) rozbijamy na części, pozwalające obliczyć poszczególne składowe ( x oraz y ).

Kolejne punkty wyliczamy zmieniając wartość parametru t w zakresie <0 , 1>.

Przykładowo, chcąc obliczyć składowe punktów leżących na krzywej opisanej wzorem (w4), przedział <0,1> dzielę na n równych części, otrzymując n+1 wartości parametru t.

Wartości te tworzą zbiór T = { 0/n , 1/n , 2/n, 3/n, … , n/n }. Dla każdego elementu tego zbioru wyliczam wartość wyrażenia B(t), otrzymując w efekcie zbiór n+1 punktów krzywej P = { B(0/n) , B(1/n) , B(2/n) , … , B(n/n) }.

4. Implementacja funkcji do wyliczania współrzędnych punktów krzywych Béziera stopnia trzeciego na płaszczyźnie

Aby wyliczyć poszczególne współrzędne punktów leżących na krzywej potrzebuję funkcji, która w zależności od parametru t oraz punktów kontrolnych zwróci współrzędne punktu krzywej.

package
{
    import flash.geom.Point;
   
    public class Bezier
    {
       
        /**
        Funkcja zwraca wspolrzedne punktu krzywej Beziera
        trzeciego stopnia, w zaleznosci od paramteru t oraz
        czterech punktow kontrolnych p0,p1,p2,p3.
        */

       
        public static function bezierCurvePoint (
       
                                                    t  : Number,
                                                    p0 : Point,
                                                    p1 : Point,
                                                    p2 : Point,
                                                    p3 : Point
                                                   
                                                ) : Point
        {
            /**
            Implementacja wzoru (w4)
            */

            const a : Number = 1 * (1-t) * (1-t) * (1-t);
            const b : Number = 3 * t * (1-t) * (1-t);
            const c : Number = 3 * t * t * (1-t);
            const d : Number = 1 * t * t * t;
           
            var px : Number = a * p0.x + b * p1.x + c * p2.x + d * p3.x;
            var py : Number = a * p0.y + b * p1.y + c * p2.y + d * p3.y;
           
            return new Point(px , py);
        }
    }
}

Bezier.as

Aby sprawdzić działanie funkcji bezierCurvePoint tworzę Document Class BezierTestDC.

package
{
    import flash.geom.Point;
    import flash.display.Sprite;

    /**
    Testowy Document Class wyswietlajacy  krzywa Beziera.
    */

   
    public class BezierTestDC extends Sprite
    {
        public function BezierTestDC()
        {
            graphics.clear();
            graphics.lineStyle (1,0x000000,1);
           
            const p0:Point  = new Point(0,0);
            const p1:Point  = new Point(100,50);
            const p2:Point  = new Point(200,-50);
            const p3:Point  = new Point(350,350);
           
            const N : int   = 50;
           
            for (var i : int = 0; i&lt;=N; i++)
            {
                var p : Point = Bezier.bezierCurvePoint(i/N,p0,p1,p2,p3);
               
                if(i == 0)
                {
                    graphics.moveTo (p.x,p.y);
                }
               
                graphics.lineTo (p.x , p.y);
            }
        }
    }
}

BezierTestDC.as

Okno działającego programu. Krzywa narysowana została poprzez połączenie odcinkami 51 punktów wyznaczonych funkcją Bezier.bezierCurvePoint().BezierTest.swfOkno, w którym widać krzywą, narysowaną poprzez połączenie kolejnych punktów wyznaczonych dla t = { 0.00 , 0.02 , 0.04 , … , 1.00 }.

Kody źródłowe oraz pliki fla i swf do pobrania stąd.

Krzywe Béziera – część druga

Leave a Reply

You must be logged in to post a comment.