SplineCurve
参考書籍
C言語によるアルゴリズム事典
/**
* Copyright okoi ( http://wonderfl.net/user/okoi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/eGnp
*/
package {
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.Event;
import flash.geom.Point;
[SWF(width = "465", height = "465", frameRate="60")]
/**
* ...
* @author
*/
public class Main extends Sprite
{
public static const WIDTH:int = 465;
public static const HEIGHT:int = 465;
private var ctrlp:/*ControlPoint*/Array;
private var spline:Spline;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
ctrlp = new Array();
for ( var i:int = 0; i < 5; i++ )
{
var p:ControlPoint = new ControlPoint();
p.pos = new Point( Math.random() * WIDTH, Math.random() * HEIGHT );
p.vec = new Point( Math.random() * 5 - 2.5, Math.random() * 5 - 2.5 );
ctrlp.push( p );
}
spline = new Spline();
addEventListener( Event.ENTER_FRAME, EnterFrameHandler );
}
private function EnterFrameHandler( e:Event ) : void
{
var pnum:int = ctrlp.length;
var i:int;
for ( i = 0; i < pnum; i++ )
{
ctrlp[i].pos.x += ctrlp[i].vec.x;
ctrlp[i].pos.y += ctrlp[i].vec.y;
if ( ctrlp[i].pos.x < 0 ) ctrlp[i].pos.x = WIDTH + ctrlp[i].pos.x;
else if ( ctrlp[i].pos.x > WIDTH ) ctrlp[i].pos.x = (ctrlp[i].pos.x % WIDTH);
if ( ctrlp[i].pos.y < 0 ) ctrlp[i].pos.y = HEIGHT + ctrlp[i].pos.y;
else if ( ctrlp[i].pos.y > HEIGHT ) ctrlp[i].pos.y = (ctrlp[i].pos.y % HEIGHT);
}
var g:Graphics = this.graphics;
g.clear();
g.lineStyle(1, 0);
for ( i = 0; i < pnum; i++ )
{
g.drawCircle( ctrlp[i].pos.x, ctrlp[i].pos.y, 3 );
}
var array:Array = new Array();
for ( i = 0; i < pnum; i++ ) array.push( ctrlp[i].pos );
array = spline.Make( array );
for ( i = 0; i < WIDTH; i++ )
{
var y:Number = spline.GetSplineValue( i, array );
if ( i == 0 ) g.moveTo( i, y );
else g.lineTo( i, y );
}
}
}
}
import flash.geom.Point;
class ControlPoint {
public var pos:Point;
public var vec:Point;
}
/**
* スプライン曲線を作成するクラス
* @author
*/
class Spline
{
private var _z:Array;
public function Spline()
{
}
/**
* スプライン曲線を作成する
* @param p Point型の制御点の位置を入れてある配列 (未ソートでOK)
*/
public function Make( p:/*Point*/Array ) : Array
{
if ( !CheckControlPointType( p ) ) return p;
var i:int;
// 制御点をソートしる
var len:int = p.length;
var sort:int = 0;
for ( var a:int = 0; a < len - 1; a++ )
{
sort = 1;
for ( var b:int = len-1; b > a; b-- )
{
var pA:Point = p[b - 1];
var pB:Point = p[b];
if( pA.x > pB.x )
{
var tmp:* = p[b];
p[b] = p[b - 1];
p[b - 1] = tmp;
sort = 0;
}
}
if ( sort != 0 ) break;
}
// テーブルを作成する
var N:int = p.length;
var h:Array = new Array(N);
var d:Array = new Array(N);
_z = new Array(N);
_z[0] = 0; _z[N - 1] = 0;
for ( i = 0; i < N - 1; i++ )
{
h[i] = p[i + 1].x - p[i].x;
d[i + 1] = (p[i + 1].y - p[i].y) / h[i];
}
_z[1] = d[2] - d[1] - h[0] * _z[0];
d[1] = 2 * (p[2].x - p[0].x);
var t:Number;
for ( i = 1; i < N - 2; i++ )
{
t = h[i] / d[i];
_z[i + 1] = d[i + 2] - d[i + 1] - _z[i] * t;
d[i + 1] = 2 * (p[i + 2].x - p[i].x) - h[i] * t;
}
_z[N - 2] -= h[N - 2] * _z[N - 1];
for ( i = N - 2; i > 0; i-- )
{
_z[i] = (_z[i] - h[i] * _z[i + 1]) / d[i];
}
return p;
}
/**
* 補間値を取得する
* @param t
* @param p
* @return
*/
public function GetSplineValue( t:Number, p:/*Point*/Array ) : Number
{
var i:int, j:int, k:int;
var N:int = p.length;
var h:Number, d:Number;
i = 0; j = N - 1;
while ( i < j ) {
k = (i + j) / 2;
if ( p[k].x < t ) i = k + 1;
else j = k;
}
if ( i > 0 ) i--;
h = p[i + 1].x - p[i].x;
d = t - p[i].x;
return (((_z[i + 1] - _z[i]) * d / h + _z[i] * 3) * d
+ ((p[i + 1].y - p[i].y) / h
- (_z[i] * 2 + _z[i + 1]) * h)) * d + p[i].y;
}
/**
* 制御点のエラーチェック
* @param p
* @return
*/
private function CheckControlPointType( p:Array ) : Boolean
{
try {
if( p == null ) throw new Error("*** Error Spline.as CheckControlPointType ***");
var len:int = p.length;
for ( var i:int = 0; i < len; i++ )
{
if ( !(p[i] is Point) ) throw new Error("*** Error Spline.as CheckControlPointType ***");
}
}catch (e:Error)
{
trace(e.message);
return false;
}
return true;
}
}