用as3实现3次样条曲线插值。
参考:三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)
demo如下(可以用鼠标拖动小圆点):
代码如下:
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); } } } }
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。