In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

ベジェ曲線のアルゴリズム理解

ベジェ曲線ってどういうふうに計算しているんだろう?
というのを確認したときに、絵で見てみたくなって作ったFlash。

文章はこっち:
http://blog.livedoor.jp/takaaki_bb/archives/51352885.html
Get Adobe Flash player
by takaaki024 04 Jan 2010
/**
 * 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);
		}
		
	}
}