用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);
}
}
}
}
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。