久しぶりのエントリーです。仕事が忙しくなると物欲がたくましくなる今日この頃です。年末はゲームもプラモもいろいろ発売でゆるゆるです。バーチャとシュトルヒが欲しい…。で、懲りずにベジェです。3次ベジェの切り分けです。
上の図は、3次ベジェを調べたことのある方なら見慣れた図かと思います。図のtpの座標をスクリプトで書くと、
/**
* Bezier Function
* @param t
* @return Point
*/
/*
_point0:Point 始点
_point1:Point 終点
_control0:Point 制御点
_control1:Point 制御点
*/
function f(t:Number):Point
{
var tp:Number = 1.0 - t;
return new Point( _point0.x*tp*tp*tp + 3*_control0.x*t*tp*tp + 3*_control1.x*t*t*tp + _point1.x*t*t*t,
_point0.y*tp*tp*tp + 3*_control0.y*t*tp*tp + 3*_control1.y*t*t*tp + _point1.y*t*t*t );
}
な感じのtに関する関数になります。
で、任意のt値、例えばポイントtpで3次ベジェを2つに分けようというものです。
2つに分けるには、2つの3次ベジェの新しい制御点を求めることになりますが、図を眺めているとすでに見えているのですね。2分割した後の曲線は、以下の図のようになります。勢いでやってみると、案外すんなりいくものです。
図でいうところの、■□、△▲が新しい制御点になります。
ベタにスクリプトで書くと、
/**
* Split Bezier at t.
* @param t( 0 to 1 )
*/
function split(t:Number):Array
{
var tp:Point = f(t); //上に書いた関数
var m:Point = Point.interpolate( _control1, _control0, t);
//制御点■□
var ac0:Point = Point.interpolate( _control0, _point0, t);
var ac1:Point = Point.interpolate( m, ac0, t);
//制御点△▲
var bc1:Point = Point.interpolate( _point1, _control1, t);
var bc0:Point = Point.interpolate( bc1, m, t);
return [ {p0:_point0.clone(),p1:tp,cp0:ac0,cp1:ac1},
{p0:tp.clone(),p1:_point1.clone(),cp0:bc0,cp1:bc1}];
}
のような感じです。
青、オレンジの曲線が切り取った線で、中の黒い線がもともとの曲線です。
SVGの読み込みをしようと思って、その過程で3次ベジェを2次ベジェに変換したくて、その前処理に使ったりしてます。