W części pierwszej pokazałem jak w prosty sposób można narysować krzywą Beziera stopnia trzeciego.
W tej części pokażę implementację funkcji, które pozwolą rysować krzywe wyższych stopni.
Wracam do wzoru (w1)
Widzę, że potrzebuję metody, która zwróci mi wartość wielomianu b.
Wielomian ten opisuje wzór (w2)
Aby wyznaczyć jego wartość w zależności od parametrów i , n , t potrzebuję jeszcze funkcji, która zwróci mi wartość dwumianu Newtona.
Intuicyjne implementacje tych funkcji zamieszczam poniżej
{
import flash.errors.IllegalOperationError;
public class MathUtils
{
/**
Funkcja zwraca wartosc n!
*/
public static function factor(n : int) : Number
{
if(n < 0 )
{
throw new IllegalOperationError
('Wartosc n musi byc dodatnia liczba calkowita!');
}
else
{
var result : Number = n;
if(n == 0 || n == 1)
{
result = 1;
}
else
{
for(var k : int = n-1 ; k > 0 ; k--) result *= k;
}
return result;
}
}
/**
Funkcja zwraca wartosc dwumianu Newtona 'n po k'
*/
public static function binomialCoefficient(n : int, k : int) : Number
{
if(n < 0 )
{
throw new IllegalOperationError
('Wartosc n musi byc nieujemna liczba calkowita ( n >= 0 )!');
}
else if(k < 0 )
{
throw new IllegalOperationError
('Wartosc k musi byc nieujemna liczba calkowita ( k >= 0 )!');
}
else if(k > n)
{
throw new IllegalOperationError
('Wartosc k nie moze byc wieksza od n ( k <= n )');
}
else
{
return factor(n) / ( factor(n - k) * factor(k) );
}
}
/**
Funkcja zwraca wartosc wielomianu Bernsteina B_i_n(t).
*/
public static function bernstainPolynomial(i : int, n : int, t : Number):Number
{
if(i > n || i < 0)
{
return 0;
}
else
{
return binomialCoefficient(n , i)
* Math.pow(t , i)
* Math.pow((1-t),n-i);
}
}
}
}
MathUtils.as
Stworzyłem także nowy Document Class, w którym krzywa jest rysowana przy zmianie położenia kursora myszki w czasie przeciągania dowolnego punktu kontrolnego.
{
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.text.TextField;
public class NBezierTestDC extends Sprite
{
const n : int = 8;
const deltaT : Number = 0.02;
private var _points : Array = new Array(n + 1);
public function NBezierTestDC()
{
trace(MathUtils.factor(21));
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);
for ( var t : Number = 0.0 ; t <= 1.0 ; t+= deltaT )
{
var curvePoint : Point = new Point();
for( var i : int = 0 ; i < (n + 1) ; i++ )
{
var P_i : Sprite = _points[i] as Sprite;
var B : Number = MathUtils.bernstainPolynomial(i , n , t);
curvePoint.x += B * P_i.x;
curvePoint.y += B * P_i.y;
}
graphics.lineTo(curvePoint.x , curvePoint.y);
}
}
}
}
NBezierTestDC.as
Efekt działania programu
NBezierTest.swf
Kody źródłowe oraz pliki fla i swf do pobrania stąd.
Leave a Reply
You must be logged in to post a comment.