To już ostatnia część mojej wypowiedzi na temat krzywych Béziera. Pokażę sposób wyliczania położenia punktów na krzywych za pomocą algorytmu de Casteljau i jego implementację w AS 3.0.
Przyjmijmy, że naszą krzywą określa n+1 punktów P0, P1, P2 … Pn. Każdy z odcinków |P0P1| , |P1P2| , … , |Pn-1Pn| dzielimy w stosunku t : (1-t), otrzymując n punktów A0, A1, A2, … , An-1. Po raz kolejny odcinki |A0A1| , |A1A2| , … , |An-2An-1| dzielimy w stosunku t : (1-t), wyznaczając n – 1 punktów B0, B1, B2, … , Bn-2. Operację powtarzamy do momentu, w którym ilość wygenerowanych punktów jest równa 1. W ten sposób otrzymujemy punkt krzywej dla parametru t.
Jeśli wykonamy tę operację dla wszystkich t z przedziału <1 , 0> wyznaczymy wszystkie punkty krzywej Béziera.
Działanie algorytmu, który wyznacza punkt dla t = 0.5 krzywej określonej punktami P0, P1, P2, P3, P4 ilustruje rysunek

Implementacja funkcji, które wyznaczają punkty krzywej Béziera
{
public class DeCasteljauBezier
{
import flash.geom.Point;
/**
Funkcja zwraca wspolrzedne punktu X,
ktory dzieli odcinek |p0p1| tak, ze |p0X|/|Xp1| = t.
*/
public static function calculatePoint (
p0 : Point,
p1 : Point ,
t : Number
) : Point
{
return new Point(p0.x + (p1.x-p0.x) * t , p0.y + (p1.y - p0.y) * t);
}
/**
Funkcja zwraca wspolrzedne punktu krzywej Beziera dla parametru t.
*/
public static function deCasteljauAlgorithm (
points : Array,
t : Number
) : Point
{
if(points.length == 1) return points[0];
else
{
var outputPoints : Array = new Array(points.length - 1);
for( var i : int = 0 ; i < outputPoints.length ; i++)
{
outputPoints[i] = calculatePoint(points[i] , points[i+1] , t);
}
return deCasteljauAlgorithm(outputPoints , t);
}
}
/**
Funkcja wylicza tablice punktow krzywej Beziera
o punktach kontrolnych controlPoints z dokladnoscia do parametru deltaT.
*/
public static function calculateCurvePoints (
controlPoints : Array ,
deltaT : Number = 0.05
) : Array
{
var outputPoints : Array = new Array();
for ( var t : Number = 0.00 ; t <= 1.00 ; t += deltaT )
{
outputPoints.push(deCasteljauAlgorithm(controlPoints , t));
}
return outputPoints;
}
}
}
DeCasteljauBezier.as
oraz Document Class, który jest zmodyfikowaną wersją DC z części drugiej mojego artykułu na temat krzywych Béziera.
{
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.text.TextField;
public class DeCasteljauTestDC extends Sprite
{
const n : int = 8;
const deltaT : Number = 0.02;
private var _points : Array = new Array(n + 1);
public function DeCasteljauTestDC()
{
for( var j : int = 0 ; j < (n + 1) ; j++ )
{
var point : Sprite = new Sprite();
point.graphics.beginFill(0xad1f47 , 1);
point.graphics.drawCircle(0,0,3);
point.graphics.endFill();
point.addEventListener (
MouseEvent.MOUSE_DOWN,
mouseDownEventHandler
);
point.addEventListener (
MouseEvent.MOUSE_UP,
mouseUpEventHandler
);
point.mouseChildren = false;
point.buttonMode = true;
var tf : TextField = new TextField();
tf.autoSize = 'left';
tf.selectable = false;
tf.textColor = 0xad1f47;
tf.text = 'P_'+ j;
point.addChild(tf);
point.x = Math.random() * 400;
point.y = Math.random() * 400;
_points[j] = addChild(point);
}
}
/**
Events handlers
*/
private function mouseDownEventHandler(event : MouseEvent) : void
{
(event.target as Sprite).addEventListener (
MouseEvent.MOUSE_MOVE,
mouseMoveEventHandler
);
(event.target as Sprite).startDrag(false);
}
private function mouseUpEventHandler(event : MouseEvent) : void
{
(event.target as Sprite).stopDrag();
}
private function mouseMoveEventHandler(event : MouseEvent) : void
{
/**
Funkcja przy kazdej zmianie pozycji dowolnego z punktow kontrolnych,
czysci okno i rysuje nowa krzywa.
*/
graphics.clear();
graphics.lineStyle(1,0x999999 , 1);
graphics.moveTo(_points[0].x,_points[0].y);
var controlPoints : Array = new Array();
for( var j : int = 0 ; j < _points.length; j++ )
{
controlPoints.push(new Point( _points[j].x , _points[j].y ));
}
var points : Array =
DeCasteljauBezier.calculateCurvePoints(controlPoints,0.01);
for (var i : int = 0; i < points.length; i++)
{
graphics.lineTo (points[i].x,points[i].y);
}
}
}
}
DeCasteljauTestDC.as
Nie zamieszczam obrazka okna, wyświetlającego krzywą, ponieważ wygląda ono identycznie jak w części drugiej – zmienił się tylko sposób implementacji metody rysującej.
Kody źródłowe oraz pliki fla i swf do pobrania stąd.


