年末気分で、事務所でビール飲んでしまいました。不良社員です。うまいです。全体ベジェばっかりですが、今回は2次ベジェ曲線でgetRectです。素直にやれば、ShapeやらのDisplayObjectに描画してgetRect()すればRectangleを得れるのですが、2次ベジェの各点(始点・終点・制御点)から計算してみます。
最初に、2次ベジェ曲線の関数を書いておきます。
/** * Quadratic Bezier Function * @param t( 0~1.0 ) * @return 座標 */ /* _point0:Point 始点 _point1:Point 終点 _control:Point 制御点 */ function f(t:Number):Point{ var tp:Number = 1.0 - t; return new Point( _point0.x*tp*tp + 2*_control.x*t*tp + _point1.x*t*t, _point0.y*tp*tp + 2*_control.y*t*tp + _point1.y*t*t ); }
Rectangleを得るのは、x、yそれぞれの最小値、最大値を求めればよいわけですが、曲線の場合、評価対象になるのは始点、終点、及び曲線の極値になります。極値というのは、曲線の一番盛り上がってるところですね。山か谷です。
で、始点、終点、極値の3点を相互に評価して最大値と最小値を導きます。
極値は、先ほどのベジェ関数のx座標、y座標それぞれで微分した結果から求めます。微分は値の増減を現しますから、増減の切り変わるポイント、つまり微分値が0になるところが極値になります。
x座標、y座標はぞれぞれtに関しての2次関数になりますから、微分すると1次関数です。
//x座標の微分 var diff_x:Number = 2*( t*( _point0.x + _point1.x - 2*_control.x ) - _point0.x + _control.x ); //y座標の微分 var diff_y:Number = 2*( t*( _point0.y + _point1.y - 2*_control.y ) - _point0.y + _control.y );
でもって、diff_x、diff_yがそれぞれ0になればいいので、極値をとるt値の値は、
//x極値 var xt:Number = (_point0.x - _control.x)/( _point0.x + _point1.x - 2*_control.x ); //y極値 var yt:Number = (_point0.y - _control.y)/( _point0.y + _point1.y - 2*_control.y );
あとは、それぞれの値の大小を比べてみます。
/** * Rectangle of Q Bezier. */ /* _point0:Point 始点 _point1:Point 終点 _control:Point 制御点 */ function getRect():Rectangle { //極値がInfinity,NaNの場合の為に初期値をいれてみる var xlim:Number = _point0.x; var ylim:Number = _point0.y; //極値のt var xt:Number = (_point0.x - _control.x)/( _point0.x + _point1.x - 2*_control.x ); var yt:Number = (_point0.y - _control.y)/( _point0.y + _point1.y - 2*_control.y ); //xt,ytの範囲を0~1に制限 if( xt>0 && xt<1 ){ xlim = _point0.x*(1-xt)*(1-xt) + 2*_control.x*xt*(1-xt) + _point1.x*xt*xt; } if( yt>0 && yt<1 ){ ylim = _point0.y*(1-yt)*(1-yt) + 2*_control.y*yt*(1-yt) + _point1.y*yt*yt; } //始点・終点・極値を比べる var x0:Number = Math.min( _point0.x, Math.min( _point1.x, xlim ) ); var y0:Number = Math.min( _point0.y, Math.min( _point1.y, ylim ) ); var x1:Number = Math.max( _point0.x, Math.max( _point1.x, xlim ) ); var y1:Number = Math.max( _point0.y, Math.max( _point1.y, ylim ) ); return new Rectangle( x0, y0, x1-x0, y1-y0 ); }
こんな感じになります。