ベジェ曲線のアルゴリズム理解
ベジェ曲線ってどういうふうに計算しているんだろう?
というのを確認したときに、絵で見てみたくなって作ったFlash。
文章はこっち:
http://blog.livedoor.jp/takaaki_bb/archives/51352885.html
/**
* Copyright takaaki024 ( http://wonderfl.net/user/takaaki024 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wk6o
*/
package {
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
/*
* ベジェ曲線ってどういうふうに計算しているんだろう?
* というのを確認したときに、絵で見てみたくなって作ったFlash。
*
* 文章はこっち:
* http://blog.livedoor.jp/takaaki_bb/archives/51352885.html
*/
[SWF(width="480", height="360", backgroundColor="#ffffff", frameRate=24)]
public class TestBezier2 extends Sprite
{
private var pA:Point; // 始点のコントロールポイント
private var pB:Point; // 始点のコントロールポイント
private var pC:Point; // 終点のアンカーポイント
private var pD:Point; // 終点のコントロールポイント
private var pE:Point; // AB を t : 1 - t に内分する点
private var pF:Point; // BC を t : 1 - t に内分する点
private var pG:Point; // CD を t : 1 - t に内分する点
private var pH:Point; // EF を t : 1 - t に内分する点
private var pI:Point; // FG を t : 1 - t に内分する点
private var pJ:Point; // HI を t : 1 - t に内分する点
private var t:Number;
private var curve:Array; // <Point>
public function TestBezier2() {
pA = new Point( 30, 240);
pB = new Point(150, 80);
pC = new Point(270, 50);
pD = new Point(370, 200);
curve = new Array();
t = 0;
// いきなり再生されるのもあれなので、クリックされたら動かすようにした
var tf:TextField = new TextField();
tf.text = "\n クリックして開始(ベジェ曲線を描きます)"; // ・・・
tf.width = 400;
tf.height = 300;
tf.selectable = false;
addChild(tf);
tf.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
removeChild(tf);
addEventListener(Event.ENTER_FRAME, calcBezier);
removeEventListener(MouseEvent.CLICK, arguments.callee);
});
}
/*
* ベジェ曲線の計算をする(現時点の t での座標を求める)
*/
private function calcBezier(e:Event):void {
pE = getDividingPoint(pA, pB, t);
pF = getDividingPoint(pB, pC, t);
pG = getDividingPoint(pC, pD, t);
pH = getDividingPoint(pE, pF, t);
pI = getDividingPoint(pF, pG, t);
pJ = getDividingPoint(pH, pI, t);
curve.push(pJ);
// いったん絵を消す
graphics.clear();
// 線を引く
graphics.lineStyle(1, 0xCCCCFF);
graphics.moveTo(pA.x, pA.y);
graphics.lineTo(pB.x, pB.y);
graphics.lineTo(pC.x, pC.y);
graphics.lineTo(pD.x, pD.y);
graphics.lineStyle(1, 0xCCFFCC);
graphics.moveTo(pE.x, pE.y);
graphics.lineTo(pF.x, pF.y);
graphics.lineTo(pG.x, pG.y);
graphics.lineStyle(1, 0xFFCCCC);
graphics.moveTo(pH.x, pH.y);
graphics.lineTo(pI.x, pI.y);
// 点を打つ
graphics.lineStyle(0, 0, 0);
graphics.beginFill(0x000000);
graphics.drawCircle(pA.x, pA.y, 2);
graphics.drawCircle(pB.x, pB.y, 2);
graphics.drawCircle(pC.x, pC.y, 2);
graphics.drawCircle(pD.x, pD.y, 2);
graphics.endFill();
graphics.beginFill(0x0000FF);
graphics.drawCircle(pE.x, pE.y, 2);
graphics.drawCircle(pF.x, pF.y, 2);
graphics.drawCircle(pG.x, pG.y, 2);
graphics.endFill();
graphics.beginFill(0x00FF00);
graphics.drawCircle(pH.x, pH.y, 2);
graphics.drawCircle(pI.x, pI.y, 2);
graphics.endFill();
graphics.beginFill(0xFF0000);
graphics.drawCircle(pJ.x, pJ.y, 2);
graphics.endFill();
// ratio 1.0 までいったら終わり
if (t > 1.0) {
e.target.removeEventListener(Event.ENTER_FRAME, arguments.callee);
e.target.graphics.clear();
graphics.beginFill(0x000000);
graphics.drawCircle(pA.x, pA.y, 1);
graphics.drawCircle(pB.x, pB.y, 1);
graphics.drawCircle(pC.x, pC.y, 1);
graphics.drawCircle(pD.x, pD.y, 1);
graphics.endFill();
}
t += 0.005;
// 出来た線を引く
graphics.lineStyle(1, 0xFF0000, 1);
graphics.moveTo(curve[0].x, curve[0].y);
for (var i:int = 1; i < curve.length; i++) {
graphics.lineTo(curve[i].x, curve[i].y);
}
}
/*
* p1 と p2 を t : 1 - t に内分する点を求める
*/
private function getDividingPoint(p1:Point, p2:Point, t:Number):Point {
return new Point(p1.x + (p2.x - p1.x) * t, p1.y + (p2.y - p1.y) * t);
}
}
}