曲線補間
/**
* Copyright umhr ( http://wonderfl.net/user/umhr )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/tfuX
*/
package
{
import com.bit101.components.CheckBox;
import com.bit101.components.Label;
import com.bit101.components.Slider;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
/**
* ...
* @author umhr
*/
public class WonderflMain3 extends Sprite
{
[SWF(width = 465, height = 465, backgroundColor = 0xFFFFFF, frameRate = 30)]
private var _pointList:Array/*Point*/ = [];
private var _checkBoxList:Array/*CheckBox*/ = [];
private var _circumscribedCurve:CircumscribedCurve;
private var _inscribedCurve:InscribedCurve;
private var _cubicCurve:CubicBezierCurve;
private var _line:Line;
private var _segmentLabel:Label;
private var _randomLabel:Label;
private var _tangentialLineLabel:Label;
private var _segment:int = 5;
private var _random:Number = 200;
private var _tangentialLineRetio:Number = 0.33;
public function WonderflMain3()
{
init();
}
private function init():void
{
_circumscribedCurve = new CircumscribedCurve(graphics);
_inscribedCurve = new InscribedCurve(graphics);
_cubicCurve = new CubicBezierCurve(graphics);
_line = new Line(graphics);
var segmentSlider:Slider = new Slider("horizontal", this, 230, 20, slider_change);
segmentSlider.width = 220;
segmentSlider.setSliderParams(4, 30, _segment);
var randomSlider:Slider = new Slider("horizontal", this, 230, 55, randomSlider_change);
randomSlider.width = 220;
randomSlider.setSliderParams(0, 400, _random);
var tangentialSlider:Slider = new Slider("horizontal", this, 230, 90, tangentialSlider_change);
tangentialSlider.width = 220;
tangentialSlider.setSliderParams(0, 2, _tangentialLineRetio);
_segmentLabel = new Label(this, 230, 30, "Segments : " + _segment);
_randomLabel = new Label(this, 230, 65, "Random : " + _random);
_tangentialLineLabel = new Label(this, 230, 100, "TangentialLineRetio(for CubicBezierCurve) : " + _tangentialLineRetio);
_checkBoxList[0] = new CheckBox(this, 25, 355, "Line", checkBox_click);
_checkBoxList[0].selected = true;
(_checkBoxList[0].getChildAt(2) as Label).textField.textColor = 0x888888;
_checkBoxList[1] = new CheckBox(this, 25, 380, "QuadraticBezierCurve(Circumscribed)", checkBox_click);
_checkBoxList[1].selected = true;
(_checkBoxList[1].getChildAt(2) as Label).textField.textColor = 0xFF0000;
_checkBoxList[2] = new CheckBox(this, 25, 405, "QuadraticBezierCurve(Inscribed)", checkBox_click);
_checkBoxList[2].selected = true;
(_checkBoxList[2].getChildAt(2) as Label).textField.textColor = 0x0000FF;
_checkBoxList[3] = new CheckBox(this, 25, 430, "CubicBezierCurve", checkBox_click);
_checkBoxList[3].selected = true;
(_checkBoxList[3].getChildAt(2) as Label).textField.textColor = 0x00FF00;
click(null);
stage.addEventListener(MouseEvent.CLICK, click);
//addEventListener(Event.ENTER_FRAME, enterFrame);
}
private function checkBox_click(e:Event):void
{
var check:CheckBox = e.target as CheckBox;
}
private function tangentialSlider_change(e:Event):void
{
_tangentialLineRetio = Number(e.target.value);
_tangentialLineLabel.text = "TangentialLineRetio(for CubicBezierCurve) : " + _tangentialLineRetio;
click(null);
}
private function randomSlider_change(e:Event):void
{
_random = int(e.target.value);
_randomLabel.text = "Random : " + _random;
click(null);
}
private function slider_change(e:Event):void
{
_segment = int(e.target.value);
_segmentLabel.text = "Segments : " + _segment;
click(null);
}
private function enterFrame(e:Event):void
{
_pointList.length = Math.min(_pointList.length, 50);
graphics.clear();
_pointList.unshift(new Point(mouseX, mouseY));
draw();
}
private function click(e:MouseEvent):void
{
_pointList.length = 0;
graphics.clear();
var n:int = _segment;
for (var i:int = 0; i < n; i++)
{
var pt:Point = new Point();
pt.x = (i / (n - 1)) * (449 - _random) + _random * Math.random() + 16 * 0.5;
pt.y = (i / (n - 1)) * (449 - _random) + _random * Math.random() + 16 * 0.5;
_pointList.unshift(pt);
}
draw();
}
private function draw():void {
if(_checkBoxList[0].selected){
_line.draw(_pointList);
}
if(_checkBoxList[1].selected){
_circumscribedCurve.draw(_pointList);
}
if(_checkBoxList[2].selected){
_inscribedCurve.draw(_pointList);
}
if(_checkBoxList[3].selected){
_cubicCurve.draw(_pointList, _tangentialLineRetio);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
class Line {
private var _graphics:Graphics;
public function Line(graphics:Graphics) {
_graphics = graphics;
}
public function draw(pointList:Array/*Point*/):void
{
var i:int;
var n:int = pointList.length;
if (n > 1) {
var m:int = n;
_graphics.lineStyle(0, 0x888888, 0.3);
_graphics.moveTo(pointList[0].x, pointList[0].y);
for (i = 0; i < m; i++)
{
_graphics.lineTo(pointList[i].x, pointList[i].y);
}
}
_graphics.lineStyle(0, 0x000000, 0.5);
for (i = 0; i < n; i++)
{
_graphics.drawCircle(pointList[i].x, pointList[i].y, 2);
}
}
}
// 2次ベジェ曲線(内接)
class InscribedCurve {
private var _graphics:Graphics;
public function InscribedCurve(graphics:Graphics) {
_graphics = graphics;
}
public function draw(pointList:Array/*Point*/):void
{
var n:int = pointList.length;
if (n > 2) {
var m:int = n - 2;
for (var i:int = 0; i < m; i++)
{
drawCurve(pointList[i], pointList[i + 1], pointList[i + 2], i == 0, i == (m - 1));
}
}
}
private function drawCurve(pt0:Point, pt1:Point, pt2:Point, isIn:Boolean, isOut:Boolean):void
{
var p0:Point = new Point((pt1.x + pt0.x) * 0.5, (pt1.y + pt0.y) * 0.5);
var p1:Point = new Point((pt1.x + pt2.x) * 0.5, (pt1.y + pt2.y) * 0.5);
_graphics.lineStyle(0, 0x0000FF, 0.5);
if (isIn) {
_graphics.moveTo(pt0.x, pt0.y);
_graphics.lineTo(p0.x, p0.y);
}
_graphics.moveTo(p0.x, p0.y);
_graphics.curveTo(pt1.x, pt1.y, p1.x, p1.y);
if (isOut) {
_graphics.lineTo(pt2.x, pt2.y);
}
}
}
// 3次ベジェ曲線
class CubicBezierCurve {
private var _graphics:Graphics;
private var _tangentialLineLength:Number;
public function CubicBezierCurve(graphics:Graphics) {
_graphics = graphics;
}
public function draw(pointList:Array/*Point*/, tangentialLineLength:Number):void
{
_tangentialLineLength = tangentialLineLength;
var n:int = pointList.length;
if (n > 3) {
var m:int = n - 3;
for (var i:int = 0; i < m; i++)
{
drawLine(pointList[i], pointList[i + 1], pointList[i + 2], pointList[i + 3], i == 0, i == (m - 1));
}
}
}
private function drawLine(pt0:Point, pt1:Point, pt2:Point, pt3:Point, isIn:Boolean, isOut:Boolean):void
{
var p1:Point = Calc.tangentialLine(pt0, pt1, pt2);
var p2:Point = Calc.tangentialLine(pt3, pt2, pt1);
var clossPoint:Point = Calc.getClossPoint(pt1, pt2, pt1.add(p1), pt2.add(p2));
var cpt1:Point = clossPoint.subtract(pt1);
var cpt2:Point = clossPoint.subtract(pt2);
// 接線
var length:Number = pt1.subtract(pt2).length * _tangentialLineLength;
p1.normalize(length);
p2.normalize(length);
_graphics.lineStyle(0, 0x66FF66, 0.3);
_graphics.moveTo(pt1.x, pt1.y);
_graphics.lineTo(pt1.x + p1.x, pt1.y + p1.y);
_graphics.lineStyle(0, 0x66FF66, 0.3);
_graphics.moveTo(pt2.x, pt2.y);
_graphics.lineTo(pt2.x + p2.x, pt2.y + p2.y);
_graphics.lineStyle(0, 0x00FF00, 0.6);
_graphics.moveTo(pt1.x, pt1.y);
_graphics.cubicCurveTo(pt1.x + p1.x, pt1.y + p1.y, pt2.x + p2.x, pt2.y + p2.y, pt2.x, pt2.y);
if(isIn){
length = pt0.subtract(pt1).length * _tangentialLineLength;
p1.normalize(length);
_graphics.lineStyle(0, 0x00FF00, 0.6);
_graphics.moveTo(pt0.x, pt0.y);
_graphics.cubicCurveTo(pt0.x + (pt1.x - pt0.x) * _tangentialLineLength, pt0.y + (pt1.y - pt0.y) * _tangentialLineLength, pt1.x - p1.x, pt1.y - p1.y, pt1.x, pt1.y);
_graphics.lineStyle(0, 0x66FF66, 0.3);
_graphics.lineTo(pt1.x - p1.x, pt1.y - p1.y);
_graphics.moveTo(pt0.x, pt0.y);
_graphics.lineTo(pt0.x + (pt1.x - pt0.x) * _tangentialLineLength, pt0.y + (pt1.y - pt0.y) * _tangentialLineLength);
}
if (isOut) {
length = pt2.subtract(pt3).length * _tangentialLineLength;
p2.normalize(length);
_graphics.lineStyle(0, 0x00FF00, 0.6);
_graphics.moveTo(pt2.x, pt2.y);
_graphics.cubicCurveTo(pt2.x - p2.x, pt2.y - p2.y, pt3.x + (pt2.x - pt3.x) * _tangentialLineLength, pt3.y + (pt2.y - pt3.y) * _tangentialLineLength, pt3.x, pt3.y);
_graphics.lineStyle(0, 0x66FF66, 0.3);
_graphics.lineTo(pt3.x + (pt2.x - pt3.x) * _tangentialLineLength, pt3.y + (pt2.y - pt3.y) * _tangentialLineLength);
_graphics.moveTo(pt2.x, pt2.y);
_graphics.lineTo(pt2.x - p2.x, pt2.y - p2.y);
}
}
private function drawCurve(pt0:Point, clossPoint:Point, pt1:Point):void
{
_graphics.moveTo(pt0.x, pt0.y);
_graphics.curveTo(clossPoint.x, clossPoint.y, pt1.x, pt1.y);
}
}
// 2次ベジェ曲線(外接)
class CircumscribedCurve {
private var _graphics:Graphics;
public function CircumscribedCurve(graphics:Graphics) {
_graphics = graphics;
}
public function draw(pointList:Array/*Point*/):void
{
var n:int = pointList.length;
if (n > 3) {
var m:int = n - 3;
for (var i:int = 0; i < m; i++)
{
drawLine(pointList[i], pointList[i + 1], pointList[i + 2], pointList[i + 3], i == 0, i == (m - 1));
}
}
}
private function drawLine(pt0:Point, pt1:Point, pt2:Point, pt3:Point, isIn:Boolean, isOut:Boolean):void
{
var p1:Point = Calc.tangentialLine(pt0, pt1, pt2);
var p2:Point = Calc.tangentialLine(pt3, pt2, pt1);
var clossPoint:Point = Calc.getClossPoint(pt1, pt2, pt1.add(p1), pt2.add(p2));
var cpt1:Point = clossPoint.subtract(pt1);
var cpt2:Point = clossPoint.subtract(pt2);
if (p1.add(cpt1).length > p1.subtract(cpt1).length && p2.add(cpt2).length > p2.subtract(cpt2).length) {
_graphics.lineStyle(0, 0xFF0000, 0.5);
drawCurve(pt1, clossPoint, pt2);
_graphics.lineStyle(0, 0xFF6666, 0.2);
_graphics.moveTo(pt1.x, pt1.y);
_graphics.lineTo(clossPoint.x, clossPoint.y);
_graphics.lineTo(pt2.x, pt2.y);
}else {
var p1Radian:Number = Calc.angleBetween(p1, pt2.subtract(pt1));
var p2Radian:Number = Calc.angleBetween(p2, pt1.subtract(pt2));
var ratio:Number = p2Radian / (p1Radian + p2Radian);
var radian:Number = (Math.atan2(p1.y, p1.x) + Math.atan2(p2.y, p2.x)) * 0.5;
var apt:Point = new Point(pt1.x, pt1.y);
var bpt:Point = new Point(pt1.x + p1.x * 30, pt1.y + p1.y * 30);
var cpt:Point = new Point((pt1.x * ratio + pt2.x * (1 - ratio)), (pt1.y * ratio + pt2.y * (1 - ratio)));
var dpt:Point = new Point((pt1.x * ratio + pt2.x * (1 - ratio)) + Math.cos(radian) * 20, (pt1.y * ratio + pt2.y * (1 - ratio)) + Math.sin(radian) * 20);
var ept:Point = new Point(pt2.x, pt2.y);
var fpt:Point = new Point(pt2.x + p2.x * 30, pt2.y + p2.y * 30);
var c1Point:Point = Calc.getClossPoint(apt, cpt, bpt, dpt);
var c2Point:Point = Calc.getClossPoint(ept, cpt, fpt, dpt);
_graphics.lineStyle(0, 0xFF0000, 0.5);
drawCurve(apt, c1Point, cpt);
drawCurve(cpt, c2Point, ept);
_graphics.lineStyle(0, 0xFF6666, 0.2);
_graphics.moveTo(apt.x, apt.y);
_graphics.lineTo(c1Point.x, c1Point.y);
_graphics.lineTo(c2Point.x, c2Point.y);
_graphics.lineTo(ept.x, ept.y);
}
var length:Number;
var corner:Point;
if (isIn) {
length = pt0.subtract(pt1).length * 0.25;
_graphics.lineStyle(0, 0xFF0000, 0.5);
corner = new Point(pt1.x - p1.x * length, pt1.y - p1.y * length);
drawCurve(pt0, corner, pt1);
_graphics.lineStyle(0, 0xFF6666, 0.2);
_graphics.moveTo(pt0.x, pt0.y);
_graphics.lineTo(corner.x, corner.y);
_graphics.lineTo(pt1.x, pt1.y);
}
if (isOut) {
length = pt2.subtract(pt3).length * 0.25;
_graphics.lineStyle(0, 0xFF0000, 0.5);
corner = new Point(pt2.x - p2.x * length, pt2.y - p2.y * length)
drawCurve(pt2, corner, pt3);
_graphics.lineStyle(0, 0xFF6666, 0.2);
_graphics.moveTo(pt2.x, pt2.y);
_graphics.lineTo(corner.x, corner.y);
_graphics.lineTo(pt3.x, pt3.y);
}
}
private function drawCurve(pt0:Point, clossPoint:Point, pt1:Point):void
{
_graphics.moveTo(pt0.x, pt0.y);
_graphics.curveTo(clossPoint.x, clossPoint.y, pt1.x, pt1.y);
}
}
class Calc {
public function Calc() {
}
static public function angleBetween(a:Point,b:Point):Number {
return Math.acos((a.x * b.x + a.y * b.y) / (Math.sqrt(a.x * a.x + a.y * a.y) * Math.sqrt(b.x * b.x + b.y * b.y)));
}
// 折れた直線の接線のベクトルを求める
static public function tangentialLine(point0:Point, point1:Point, point2:Point):Point
{
var pt0:Point = point1.subtract(point0);
var pt1:Point = point1.subtract(point2);
pt0.normalize(1);
pt1.normalize(1);
return pt0.subtract(pt1);
}
// 4点からなる交点
static public function getClossPoint(pa0:Point, pa1:Point, pb0:Point, pb1:Point):Point {
var result:Point = new Point();
var s0:Number = ((pb1.x - pa1.x) * (pa0.y - pa1.y) - (pb1.y - pa1.y) * (pa0.x - pa1.x)) * 0.5;
var s1:Number = ((pb1.x - pa1.x) * (pa1.y - pb0.y) - (pb1.y - pa1.y) * (pa1.x - pb0.x)) * 0.5;
result.x = pa0.x + (pb0.x - pa0.x) * (s0 / (s0 + s1));
result.y = pa0.y + (pb0.y - pa0.y) * (s0 / (s0 + s1));
return result;
}
}