SplineCurve2
参考書籍
C言語によるアルゴリズム事典
/**
* Copyright okoi ( http://wonderfl.net/user/okoi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/itsS
*/
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.display.Graphics;
[SWF(width = "465", height = "465", frameRate="60")]
/**
* ...
* @author okoi
*/
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() - 0.5, Math.random() - 0.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:/*Point*/Array = new Array();
for ( i = 0; i < pnum; i++ ) array.push( ctrlp[i].pos );
// ソート
var sort:int = 0;
for ( var a:int = 0; a < pnum - 1; a++ )
{
sort = 1;
for ( var b:int = pnum-1; b > a; b-- )
{
var pA:Point = array[b - 1];
var pB:Point = array[b];
if( pA.x > pB.x )
{
var tmp:* = array[b];
array[b] = array[b - 1];
array[b - 1] = tmp;
sort = 0;
}
}
if ( sort != 0 ) break;
}
spline.Make( array );
var t:Number
for ( t = array[0].x; t <= array[pnum-1].x; t+=0.1 )
{
var y:Number = spline.GetSplineValue( t );
if ( t == array[0].x ) g.moveTo( t, y );
else g.lineTo( t, y );
}
/*
for ( t = 0; t <= WIDTH; t+=0.1 )
{
var y:Number = spline.GetSplineValue( t );
if ( t == 0 ) g.moveTo( t, y );
else g.lineTo( t, y );
}
*/
}
}
}
import flash.geom.Point;
class ControlPoint {
public var pos:Point;
public var vec:Point;
}
/**
* x[0..N] y[0..N] に与えたN+1個の点(xi,yi), x0 < x1 < ... < xN, y0 < y1 < ... < yN を
* 周期 xN - x0 の周期関数で補間する
* Makeで求める z:Array は各点での2次導関数の1/6にあたる
* x = t での補間値は GetSplineValue で求める
* @author okoi
*/
class Spline
{
private var N:int;
private var z:Array;
private var x:Array;
private var y:Array;
public function Make( points:/*Point*/Array ) : void
{
var i:int;
var t:Number;
N = points.length - 1;
z = new Array(N + 1);
var h:Array = new Array(N + 1);
var d:Array = new Array(N + 1);
var w:Array = new Array(N + 1);
x = new Array(N + 1);
y = new Array(N + 1);
for ( i = 0; i < points.length; i++ )
{
x[i] = points[i].x;
y[i] = points[i].y;
}
for ( i = 0; i < N; i++ )
{
h[i] = x[i + 1] - x[i];
w[i] = (y[i + 1] - y[i]) / h[i];
}
w[N] = w[0];
for ( i = 1; i < N; i++ )
{
d[i] = 2 * (x[i + 1] - x[i - 1]);
}
d[N] = 2 * (h[N - 1] + h[0]);
for ( i = 1; i <= N; i++ )
{
z[i] = w[i] - w[i - 1];
}
w[1] = h[0];
w[N - 1] = h[N - 1];
w[N] = d[N];
for ( i = 2; i < N - 1; i++ ) w[i] = 0;
for ( i = 1; i < N; i++ )
{
t = h[i] / d[i];
z[i + 1] = z[i + 1] - z[i] * t;
d[i + 1] = d[i + 1] - h[i] * t;
w[i + 1] = w[i + 1] - w[i] * t;
}
w[0] = w[N];
z[0] = z[N];
for ( i = N - 2; i >= 0; i-- )
{
t = h[i] / d[i + 1];
z[i] = z[i] - z[i + 1] * t;
w[i] = w[i] - w[i + 1] * t;
}
t = z[0] / w[0];
z[0] = t;
z[N] = t;
for ( i = 1; i < N; i++ )
{
z[i] = (z[i] - w[i] * t) / d[i];
}
}
public function GetSplineValue( t:Number ) : Number
{
var i:int, j:int, k:int;
var d:Number, h:Number, period:Number;
period = x[N] - x[0];
while ( t > x[N] ) t -= period;
while ( t < x[0] ) t += period;
i = 0; j = N;
while ( i < j ) {
k = (i + j) / 2;
if ( x[k] < t ) i = k + 1;
else j = k;
}
if ( i > 0 ) i--;
h = x[i + 1] - x[i];
d = t - x[i];
return (((z[i + 1] - z[i]) * d / h + z[i] * 3) * d
+ ((y[i + 1] - y[i]) / h
- (z[i] * 2 + z[i + 1]) * h)) * d + y[i];
}
}