27
2016
04

自然边界三次样条插值

用as3实现3次样条曲线插值。

参考:三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)

demo如下(可以用鼠标拖动小圆点):

获得 Adobe Flash Player

代码如下:

HInterpolation.as

package
{
	
	public class HInterpolation
	{
		public function HInterpolation()
		{
			throw(new Error("静态类,不可以实例化,请直接使用类中的静态函数。"));
		}
		/**
		 * 自然边界的三次样条曲线。
		 * 参考:http://www.cnblogs.com/xpvincent/archive/2013/01/26/2878092.html
		 * 
		 * 输入数组为采样点,数组中的每一项都必须要有(x、y)属性;
		 * 三次样条曲线,每个区间(相邻两个点组成一个区间)的多项式方程为:yi=ai+bi(x-xi)+ci*(x-xi)^2+di*(x-xi)^3;
		 * 输出数组为:[ai,bi,ci,di],其中ai,bi,ci,di分别为多项式方程的参数数组。
		 * 
		 * 
		 * @param	map		源数据数组,数组中的每一项必须有(x、y)属性(比如,Point)。
		 * @return	Array	每个区间的参数数组
		 */
		public static function splineCubicNatural(map:Array):Array
		{
			var i:int, j:int, n:int = map.length;
			var A:Array = [];
			var B:Array = [];
			var C:Array = [];
			var D:Array = [];
			var E:Array = [];
			var M:Array = [];
			
			var h:Array = [];
			var ai:Array = [];
			var bi:Array = [];
			var ci:Array = [];
			var di:Array = [];
			for (i = 0; i < n - 1; i++)
			{
				h[i] = map[i + 1].x - map[i].x;
			}
			for (i = 0; i < n - 2; i++)
			{
				A[i] = h[i];
				B[i] = 2 * (h[i] + h[i + 1]);
				C[i] = h[i + 1];
				
				D[i] = 6 * ((map[i + 2].y - map[i + 1].y) / h[i + 1] - (map[i + 1].y - map[i].y) / h[i]);
			}
			//--TDMA--
			var tmp:Number;
			var X:Array = [];
			TDMA(n - 2);
			function TDMA(n:int)
			{
				//上三角矩阵
				C[0] = C[0] / B[0];
				D[0] = D[0] / B[0];
				for (i = 1; i < n; i++)
				{
					tmp = (B[i] - A[i] * C[i - 1]);
					C[i] = C[i] / tmp;
					D[i] = (D[i] - A[i] * D[i - 1]) / tmp;
				}
				//直接求出X的最后一个值
				X[n - 1] = D[n - 1];
				//逆向迭代, 求出X
				for (i = n - 2; i >= 0; i--)
				{
					X[i] = D[i] - C[i] * X[i + 1];
				}
			}
			//M
			M[0] = 0;
			M[n - 1] = 0;
			for (i = 1; i < n - 1; i++)
			{
				M[i] = X[i - 1];
			}
			//计算系数
			for (i = 0; i < n - 1; i++)
			{
				ai[i] = map[i].y;
				bi[i] = (map[i + 1].y - map[i].y) / h[i] - (2 * h[i] * M[i] + h[i] * M[i + 1]) / 6;
				ci[i] = M[i] / 2;
				di[i] = (M[i + 1] - M[i]) / (6 * h[i]);
			}
			return [ai, bi, ci, di];
		}
	}
}

Main.as

package
{
	
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class Main extends MovieClip
	{
		
		private var map:Array;
		private var i:int, j:int, n:int;
		private var shape1:Shape = new Shape();
		private var shape2:Shape = new Shape();
		public function Main()
		{
			// constructor code
			
			map = [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9];
			n = map.length;
			for (i = 0; i < n; i++ ) {
				map[i].buttonMode = true;
				drag(map[i]);
			}
			
			addChild(shape1);
			addChild(shape2);
			drawLine1();
			drawLine2();
		}
		/**
		 * 拖动小圆点
		 * @param	sp
		 */
		private function drag(sp:Sprite):void {
			sp.addEventListener(MouseEvent.MOUSE_DOWN, dragMouseHandler);
			
		}
		private var curSp:Sprite;
		private function dragMouseHandler(e:Event):void 
		{
			switch(e.type) {
				case MouseEvent.MOUSE_DOWN:
					stage.addEventListener(MouseEvent.MOUSE_UP, dragMouseHandler);
					stage.addEventListener(Event.MOUSE_LEAVE, dragMouseHandler);
					stage.addEventListener(MouseEvent.MOUSE_MOVE, dragMouseHandler);
					curSp = e.currentTarget as Sprite;
					curSp.startDrag(false);
					break;
				case MouseEvent.MOUSE_MOVE:
					drawLine1();
					drawLine2();
					break;
				default:
					curSp.stopDrag();
					curSp = null;
					stage.removeEventListener(MouseEvent.MOUSE_UP, dragMouseHandler);
					stage.removeEventListener(Event.MOUSE_LEAVE, dragMouseHandler);
					stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragMouseHandler);
					break;
			}
		}
		
		/**
		 * 画线1,直接用直线连接相邻的两个点
		 */
		private function drawLine1():void
		{
			var g:Graphics = shape1.graphics;
			g.clear();
			g.lineStyle(1, 0x00ff00);
			for (i = 0; i < map.length; i++)
			{
				var p0:Object = map[i];
				if (i == 0)
				{
					g.moveTo(p0.x, p0.y);
				}
				else
				{
					g.lineTo(p0.x, p0.y);
				}
			}
		}
		/**
		 * 画线2,三次样条插值
		 */
		private function drawLine2():void
		{
			var g:Graphics = shape2.graphics;
			var arr:Array = HInterpolation.splineCubicNatural(map);//调用插值函数,得到参数数组
			var ai:Array = arr[0];
			var bi:Array = arr[1];
			var ci:Array = arr[2];
			var di:Array = arr[3];
			g.clear();
			g.lineStyle(1, 0xff0000);
			for (i = 0; i < map.length - 1; i++)
			{
				var p0:Object = map[i];
				var p1:Object = map[i + 1];
				if (i == 0)
				{
					g.moveTo(p0.x, p0.y);
				}
				
				for (j = p0.x; j < p1.x; j++)
				{
					var pow:Number = (j - p0.x) * (j - p0.x);
					g.lineTo(j, ai[i] + bi[i] * (j - p0.x) + ci[i] * pow + di[i] * pow * (j - p0.x));
				}
				g.lineTo(p1.x, p1.y);
			}
		}
		
	}

}

源码打包下载

« 上一篇下一篇 »

相关文章:

闪电效果  (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)

发表评论:

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