25
2016
05

Catmull–Rom spline(一种过控制点的插值方法)

贝塞尔曲线不过控制点,Catmull–Rom插值治国控制点,在某些场合希望曲线穿过所有控制点的话可以使用catmull-rom spline。catmull-rom spline需要4个点,具体原理可以参考维基百科

demo:

获得 Adobe Flash Player

按照定义,t应该从t1到t2,也就是说只画出中间两个控制点之间的曲线。如果我们把t0到t3之间的曲线都画出来,会是什么样子呢?

demo如下;

获得 Adobe Flash Player

我发现catmull-rom spline并不能像贝塞尔曲线那样迭代,最后求c的公式和前面两个不一样。如果我们把c=(t2-t)/(t2-t1)*b1+(t-t1)/(t2-t1)*b2改为c=(t3-t)/(t3-t0)*b1+(t-t0)/(t3-t0)*b2会是什么样呢?

demo如下:

获得 Adobe Flash Player

居然4个点都过了。

不知道如果像贝塞尔曲线那样改为任意阶会怎么样。

代码如下:

package  {
	
	import fl.controls.NumericStepper;
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	import flash.geom.Point;
	
	
	public class Main extends MovieClip {
		
		public var numSteper:NumericStepper;
		public var p0:MovieClip;
		public var p1:MovieClip;
		public var p2:MovieClip;
		public var p3:MovieClip;
		private var alp:Number = 0.5;
		private var fun:Function;
		public function Main() {
			// constructor code
			
			stage?initStage(null):addEventListener(Event.ADDED_TO_STAGE, initStage);
		}
		
		private function initStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, initStage);
			drag(p0);
			drag(p1);
			drag(p2);
			drag(p3);
			fun = CatmullRomSpline;
			var funType:* = root.loaderInfo.parameters["fun"];
			switch(String(funType)) {
				case "1":
					fun = CatmullRomSpline_2;
					break;
				case "2":
					fun = CatmullRomSpline_3;
					break;
				default:
					fun = CatmullRomSpline;
					break;
			}
			if (ExternalInterface.available) {
				ExternalInterface.call("console.log","funType:"+funType);
			}
			numSteper.addEventListener(Event.CHANGE, onChanged);
			updateLine();
		}
		private var curSp:Sprite;
		private function drag(sp:Sprite):void {
			sp.addEventListener(MouseEvent.MOUSE_DOWN, dragHandler);
		}
		
		private function dragHandler(e:Event):void 
		{
			switch(e.type) {
				case MouseEvent.MOUSE_DOWN:
					curSp = e.currentTarget as Sprite;
					curSp.startDrag();
					stage.addEventListener(MouseEvent.MOUSE_UP, dragHandler);
					stage.addEventListener(Event.MOUSE_LEAVE, dragHandler);
					stage.addEventListener(MouseEvent.MOUSE_MOVE, dragHandler);
					break;
				case MouseEvent.MOUSE_MOVE:
					updateLine();
					break;
				default:
					curSp.stopDrag();
					curSp = null;
					stage.removeEventListener(MouseEvent.MOUSE_UP, dragHandler);
					stage.removeEventListener(Event.MOUSE_LEAVE, dragHandler);
					stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragHandler);
					break;
			}
		}
		private function onChanged(e:Event):void 
		{
			alp = numSteper.value;
			updateLine();
		}
		private function updateLine():void {
			var arr:Array = fun(p0, p1, p2, p3, alp, 100);
			var g:Graphics = graphics;
			g.clear();
			g.lineStyle(1, 0xff0000, 1.0);
			var len:int = arr.length;
			for (var i:int = 0; i <len;i++ ) {
				var p:Object = arr[i];
				if (i==0) {
					g.moveTo(p.x, p.y);
				}
				else {
					g.lineTo(p.x, p.y);
				}
			}
		}
		/**
		 * CatmullRomSpline
		 * @param	p0
		 * @param	p1
		 * @param	p2
		 * @param	p3
		 * @param	alp
		 * @param	nPoints
		 * @return
		 */
		private function CatmullRomSpline(p0:Object,p1:Object,p2:Object,p3:Object,alp:Number=0.5,nPoints:int=100):Array {
			var t0:Number = 0;
			var t1:Number = Math.pow((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y), alp) + t0;
			var t2:Number = Math.pow((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y), alp) + t1;
			var t3:Number = Math.pow((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y), alp) + t2;
			var arr:Array = [];
			var step:Number = (t2 - t1) / (nPoints - 1);
			var a1:Point = new Point();
			var a2:Point = new Point();
			var a3:Point = new Point();
			var b1:Point = new Point();
			var b2:Point = new Point();
			var c:Point;
			for (var t:Number = t1; t < t2;t+=step ) {
				a1.x = (t1 - t) / (t1 - t0) * p0.x + (t - t0) / (t1 - t0) * p1.x;
				a1.y = (t1 - t) / (t1 - t0) * p0.y + (t - t0) / (t1 - t0) * p1.y;
				a2.x = (t2 - t) / (t2 - t1) * p1.x + (t - t1) / (t2 - t1) * p2.x;
				a2.y = (t2 - t) / (t2 - t1) * p1.y + (t - t1) / (t2 - t1) * p2.y;
				a3.x = (t3 - t) / (t3 - t2) * p2.x + (t - t2) / (t3 - t2) * p3.x;
				a3.y = (t3 - t) / (t3 - t2) * p2.y + (t - t2) / (t3 - t2) * p3.y;
				b1.x = (t2 - t) / (t2 - t0) * a1.x + (t - t0) / (t2 - t0) * a2.x;
				b1.y = (t2 - t) / (t2 - t0) * a1.y + (t - t0) / (t2 - t0) * a2.y;
				b2.x = (t3 - t) / (t3 - t1) * a2.x + (t - t1) / (t3 - t1) * a3.x;
				b2.y = (t3 - t) / (t3 - t1) * a2.y + (t - t1) / (t3 - t1) * a3.y;
				c = new Point();
				c.x = (t2 - t) / (t2 - t1) * b1.x + (t - t1) / (t2 - t1) * b2.x;
				c.y = (t2 - t) / (t2 - t1) * b1.y + (t - t1) / (t2 - t1) * b2.y;
				arr.push(c);
			}
			return arr;
		}
		/**
		 * 让t从t0到t3.
		 * @param	p0
		 * @param	p1
		 * @param	p2
		 * @param	p3
		 * @param	alp
		 * @param	nPoints
		 * @return
		 */
		private function CatmullRomSpline_2(p0:Object,p1:Object,p2:Object,p3:Object,alp:Number=0.5,nPoints:int=100):Array {
			var t0:Number = 0;
			var t1:Number = Math.pow((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y), alp) + t0;
			var t2:Number = Math.pow((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y), alp) + t1;
			var t3:Number = Math.pow((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y), alp) + t2;
			var arr:Array = [];
			var step:Number = (t3 - t0) / (nPoints - 1);
			var a1:Point = new Point();
			var a2:Point = new Point();
			var a3:Point = new Point();
			var b1:Point = new Point();
			var b2:Point = new Point();
			var c:Point;
			for (var t:Number = t0; t < t3;t+=step ) {
				a1.x = (t1 - t) / (t1 - t0) * p0.x + (t - t0) / (t1 - t0) * p1.x;
				a1.y = (t1 - t) / (t1 - t0) * p0.y + (t - t0) / (t1 - t0) * p1.y;
				a2.x = (t2 - t) / (t2 - t1) * p1.x + (t - t1) / (t2 - t1) * p2.x;
				a2.y = (t2 - t) / (t2 - t1) * p1.y + (t - t1) / (t2 - t1) * p2.y;
				a3.x = (t3 - t) / (t3 - t2) * p2.x + (t - t2) / (t3 - t2) * p3.x;
				a3.y = (t3 - t) / (t3 - t2) * p2.y + (t - t2) / (t3 - t2) * p3.y;
				b1.x = (t2 - t) / (t2 - t0) * a1.x + (t - t0) / (t2 - t0) * a2.x;
				b1.y = (t2 - t) / (t2 - t0) * a1.y + (t - t0) / (t2 - t0) * a2.y;
				b2.x = (t3 - t) / (t3 - t1) * a2.x + (t - t1) / (t3 - t1) * a3.x;
				b2.y = (t3 - t) / (t3 - t1) * a2.y + (t - t1) / (t3 - t1) * a3.y;
				c = new Point();
				c.x = (t2 - t) / (t2 - t1) * b1.x + (t - t1) / (t2 - t1) * b2.x;
				c.y = (t2 - t) / (t2 - t1) * b1.y + (t - t1) / (t2 - t1) * b2.y;
				arr.push(c);
			}
			return arr;
		}
		/**
		 * c=(t2-t)/(t2-t1)*b1+(t-t1)/(t2-t1)*b2
		 * 改为:
		 * c=(t3-t)/(t3-t0)*b1+(t-t0)/(t3-t0)*b2
		 * @param	p0
		 * @param	p1
		 * @param	p2
		 * @param	p3
		 * @param	alp
		 * @param	nPoints
		 * @return
		 */
		private function CatmullRomSpline_3(p0:Object,p1:Object,p2:Object,p3:Object,alp:Number=0.5,nPoints:int=100):Array {
			var t0:Number = 0;
			var t1:Number = Math.pow((p1.x - p0.x) * (p1.x - p0.x) + (p1.y - p0.y) * (p1.y - p0.y), alp) + t0;
			var t2:Number = Math.pow((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y), alp) + t1;
			var t3:Number = Math.pow((p3.x - p2.x) * (p3.x - p2.x) + (p3.y - p2.y) * (p3.y - p2.y), alp) + t2;
			var arr:Array = [];
			var step:Number = (t3 - t0) / (nPoints - 1);
			var a1:Point = new Point();
			var a2:Point = new Point();
			var a3:Point = new Point();
			var b1:Point = new Point();
			var b2:Point = new Point();
			var c:Point;
			for (var t:Number = t0; t < t3;t+=step ) {
				a1.x = (t1 - t) / (t1 - t0) * p0.x + (t - t0) / (t1 - t0) * p1.x;
				a1.y = (t1 - t) / (t1 - t0) * p0.y + (t - t0) / (t1 - t0) * p1.y;
				a2.x = (t2 - t) / (t2 - t1) * p1.x + (t - t1) / (t2 - t1) * p2.x;
				a2.y = (t2 - t) / (t2 - t1) * p1.y + (t - t1) / (t2 - t1) * p2.y;
				a3.x = (t3 - t) / (t3 - t2) * p2.x + (t - t2) / (t3 - t2) * p3.x;
				a3.y = (t3 - t) / (t3 - t2) * p2.y + (t - t2) / (t3 - t2) * p3.y;
				b1.x = (t2 - t) / (t2 - t0) * a1.x + (t - t0) / (t2 - t0) * a2.x;
				b1.y = (t2 - t) / (t2 - t0) * a1.y + (t - t0) / (t2 - t0) * a2.y;
				b2.x = (t3 - t) / (t3 - t1) * a2.x + (t - t1) / (t3 - t1) * a3.x;
				b2.y = (t3 - t) / (t3 - t1) * a2.y + (t - t1) / (t3 - t1) * a3.y;
				c = new Point();
				c.x = (t3 - t) / (t3 - t0) * b1.x + (t - t0) / (t3 - t0) * b2.x;
				c.y = (t3 - t) / (t3 - t0) * b1.y + (t - t0) / (t3 - t0) * b2.y;
				arr.push(c);
			}
			return arr;
		}
	}
	
}



源码打包下载

« 上一篇下一篇 »

相关文章:

闪电效果  (2017-11-28 15:4:19)

线段与椭圆的交点  (2017-1-6 14:43:41)

as3录制swf并保存flv视频  (2016-12-28 8:43:41)

解九连环  (2016-12-1 20:58:11)

as3实现setTimeout和trace  (2016-11-10 16:47:37)

registerCursor注册系统光标  (2016-9-14 9:49:40)

鼠标光标管理  (2016-9-13 17:44:3)

变形框(transform)实现  (2016-9-13 16:56:6)

flash文本消除锯齿不显示  (2016-8-25 11:43:31)

greenSock的easing曲线  (2016-8-24 18:30:11)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。