ラグランジュ補間法
式は
http://www.sist.ac.jp/~suganuma/kougi/other_lecture/SE/num/num.htm#7.1
のJava版を移植させていただきました。
あとは扱いやすいようにクラス化した感じです。
点が多いと酷いことになるので注意。
赤い玉はドラッグできます。
/**
* Copyright Hiiragi ( http://wonderfl.net/user/Hiiragi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/cTzd
*/
package
{
import flash.display.Sprite;
import flash.display.Graphics;
import flash.geom.Point;
import flash.events.Event;
/**
* ラグランジュ補間法
* @author Hiiragi
*
* 式は
* http://www.sist.ac.jp/~suganuma/kougi/other_lecture/SE/num/num.htm#7.1
* のJava版を移植させていただきました。
*
* あとは扱いやすいようにクラス化した感じです。
* 点が多いと酷いことになるので注意。
*
* 赤い玉はドラッグできます。
*/
[SWF(width="465", height="465", frameRate="30", backgroundColor="0xFFFFFF")]
public class Main extends Sprite
{
private var _dragPoints:Vector.<DragPoint>;
public function Main()
{
_dragPoints = new Vector.<DragPoint>();
_dragPoints.push(this.addChild(new DragPoint(50, 200)) as DragPoint);
_dragPoints.push(this.addChild(new DragPoint(100, 100)) as DragPoint);
_dragPoints.push(this.addChild(new DragPoint(200, 300)) as DragPoint);
_dragPoints.push(this.addChild(new DragPoint(400, 50)) as DragPoint);
_dragPoints.push(this.addChild(new DragPoint(440, 200)) as DragPoint);
this.addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
}
private function onEnterFrameHandler(e:Event):void
{
var points:Vector.<Point> = new Vector.<Point>();
var i:int;
var len:int = _dragPoints.length;
for (i = 0; i < len; i++)
{
points.push(_dragPoints[i].getPoint());
}
var vec:Vector.<Point> = MathEx.lagrangePolynomial(points, 30);
len = vec.length;
var g:Graphics = this.graphics;
g.clear();
g.lineStyle(1);
g.moveTo(vec[0].x, vec[0].y);
for (i = 1; i < len; i++)
{
g.lineTo(vec[i].x, vec[i].y);
}
}
}
}
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.MouseEvent;
class DragPoint extends Sprite
{
public function DragPoint(positionX:Number = 0, positionY:Number = 0):void
{
this.x = positionX;
this.y = positionY;
var g:Graphics = this.graphics;
g.beginFill(0xFF0000, 0.5);
g.drawCircle(0, 0, 8);
g.endFill();
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
this.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
}
private function onMouseDownHandler(e:MouseEvent):void
{
this.startDrag();
}
private function onMouseUpHandler(e:MouseEvent):void
{
this.stopDrag();
}
public function getPoint():Point
{
return new Point(this.x, this.y);
}
}
import flash.geom.Point;
class MathEx extends Object
{
public static function lagrangePolynomial(points:Vector.<Point>, splitCount:uint):Vector.<Point>
{
points.sort(xNumericAscending);
var len:int = points.length - 1;
var len2:int;
var currentX:Number = points[0].x;
var diffX:Number;
var returnVec:Vector.<Point> = new Vector.<Point>();
for (var i:int = 0; i < len; i++)
{
diffX = (points[i + 1].x - points[i].x) / splitCount;
for (var j:int = 0; j < splitCount; j++)
{
var point:Point = new Point(currentX, lagrangePolynomialBase(points, currentX));
returnVec.push(point);
currentX += diffX;
}
}
returnVec.push(points[points.length - 1]);
return returnVec;
}
private static function lagrangePolynomialBase(points:Vector.<Point>, currentX:Number):Number
{
var s1:Number;
var s2:Number;
var y1:Number = 0.0;
var i1:int;
var i2:int;
var n:int = points.length - 1;
for (i1 = 0; i1 <= n; i1++)
{
s1 = 1.0;
s2 = 1.0;
for (i2 = 0; i2 <= n; i2++)
{
if (i2 != i1)
{
s1 *= (currentX - points[i2].x);
s2 *= (points[i1].x - points[i2].x);
}
}
y1 += points[i1].y * s1 / s2;
}
return y1;
}
public static function xNumericAscending(a1:Point, a2:Point):Number
{
if (a1.x > a2.x)
{
return 1;
}
else if (a1.x < a2.x)
{
return -1;
}
return 0;
}
}