| INDEX |

年末気分で、事務所でビール飲んでしまいました。不良社員です。うまいです。全体ベジェばっかりですが、今回は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 );
}

こんな感じになります。

| INDEX |