forked from: シェイプトゥイーンの実験
変形前後のアンカーポイントの補間アルゴリズムを改善してみました。前バージョンよりも、10~20%程度アンカーポイントが減っています。あとエフェクトも足しました。
// forked from kacchan6's シェイプトゥイーンの実験
package
{
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.GlowFilter;
[SWF(width=465, height=465, backgroundColor=0x000000, frameRate=30)]
public class ShapeTween extends Sprite
{
public function ShapeTween()
{
//アイコンデータは以下から参照 http://raphaeljs.com/icons/
var path1:CompoundPath = new CompoundPath();
SVGPathParser.draw(path1, "M28.4,22.469c0.479-0.964,0.851-1.991,1.095-3.066c0.953-3.661,0.666-6.854,0.666-6.854l-0.327,2.104c0,0-0.469-3.896-1.044-5.353c-0.881-2.231-1.273-2.214-1.274-2.21c0.542,1.379,0.494,2.169,0.483,2.288c-0.01-0.016-0.019-0.032-0.027-0.047c-0.131-0.324-0.797-1.819-2.225-2.878c-2.502-2.481-5.943-4.014-9.745-4.015c-4.056,0-7.705,1.745-10.238,4.525C5.444,6.5,5.183,5.938,5.159,5.317c0,0-0.002,0.002-0.006,0.005c0-0.011-0.003-0.021-0.003-0.031c0,0-1.61,1.247-1.436,4.612c-0.299,0.574-0.56,1.172-0.777,1.791c-0.375,0.817-0.75,2.004-1.059,3.746c0,0,0.133-0.422,0.399-0.988c-0.064,0.482-0.103,0.971-0.116,1.467c-0.09,0.845-0.118,1.865-0.039,3.088c0,0,0.032-0.406,0.136-1.021c0.834,6.854,6.667,12.165,13.743,12.165l0,0c1.86,0,3.636-0.37,5.256-1.036C24.938,27.771,27.116,25.196,28.4,22.469zM16.002,3.356c2.446,0,4.73,0.68,6.68,1.86c-2.274-0.528-3.433-0.261-3.423-0.248c0.013,0.015,3.384,0.589,3.981,1.411c0,0-1.431,0-2.856,0.41c-0.065,0.019,5.242,0.663,6.327,5.966c0,0-0.582-1.213-1.301-1.42c0.473,1.439,0.351,4.17-0.1,5.528c-0.058,0.174-0.118-0.755-1.004-1.155c0.284,2.037-0.018,5.268-1.432,6.158c-0.109,0.07,0.887-3.189,0.201-1.93c-4.093,6.276-8.959,2.539-10.934,1.208c1.585,0.388,3.267,0.108,4.242-0.559c0.982-0.672,1.564-1.162,2.087-1.047c0.522,0.117,0.87-0.407,0.464-0.872c-0.405-0.466-1.392-1.105-2.725-0.757c-0.94,0.247-2.107,1.287-3.886,0.233c-1.518-0.899-1.507-1.63-1.507-2.095c0-0.366,0.257-0.88,0.734-1.028c0.58,0.062,1.044,0.214,1.537,0.466c0.005-0.135,0.006-0.315-0.001-0.519c0.039-0.077,0.015-0.311-0.047-0.596c-0.036-0.287-0.097-0.582-0.19-0.851c0.01-0.002,0.017-0.007,0.021-0.021c0.076-0.344,2.147-1.544,2.299-1.659c0.153-0.114,0.55-0.378,0.506-1.183c-0.015-0.265-0.058-0.294-2.232-0.286c-0.917,0.003-1.425-0.894-1.589-1.245c0.222-1.231,0.863-2.11,1.919-2.704c0.02-0.011,0.015-0.021-0.008-0.027c0.219-0.127-2.524-0.006-3.76,1.604C9.674,8.045,9.219,7.95,8.71,7.95c-0.638,0-1.139,0.07-1.603,0.187c-0.05,0.013-0.122,0.011-0.208-0.001C6.769,8.04,6.575,7.88,6.365,7.672c0.161-0.18,0.324-0.356,0.495-0.526C9.201,4.804,12.43,3.357,16.002,3.356z");
var path2:CompoundPath = new CompoundPath();
SVGPathParser.draw(path2, "M27.998,2.266c-2.12-1.91-6.925,0.382-9.575,1.93c-0.76-0.12-1.557-0.185-2.388-0.185c-3.349,0-6.052,0.985-8.106,2.843c-2.336,2.139-3.631,4.94-3.631,8.177c0,0.028,0.001,0.056,0.001,0.084c3.287-5.15,8.342-7.79,9.682-8.487c0.212-0.099,0.338,0.155,0.141,0.253c-0.015,0.042-0.015,0,0,0c-2.254,1.35-6.434,5.259-9.146,10.886l-0.003-0.007c-1.717,3.547-3.167,8.529-0.267,10.358c2.197,1.382,6.13-0.248,9.295-2.318c0.764,0.108,1.567,0.165,2.415,0.165c5.84,0,9.937-3.223,11.399-7.924l-8.022-0.014c-0.337,1.661-1.464,2.548-3.223,2.548c-2.21,0-3.729-1.211-3.828-4.012l15.228-0.014c0.028-0.578-0.042-0.985-0.042-1.436c0-5.251-3.143-9.355-8.255-10.663c2.081-1.294,5.974-3.209,7.848-1.681c1.407,1.14,0.633,3.533,0.295,4.518c-0.056,0.254,0.24,0.296,0.296,0.057C28.814,5.573,29.026,3.194,27.998,2.266zM13.272,25.676c-2.469,1.475-5.873,2.539-7.539,1.289c-1.243-0.935-0.696-3.468,0.398-5.938c0.664,0.992,1.495,1.886,2.473,2.63C9.926,24.651,11.479,25.324,13.272,25.676zM12.714,13.046c0.042-2.435,1.787-3.49,3.617-3.49c1.928,0,3.49,1.112,3.49,3.49H12.714z");
var path3:CompoundPath = new CompoundPath();
SVGPathParser.draw(path3, "M15.954,2.046c-7.489,0-12.872,5.432-12.872,13.581c0,7.25,5.234,13.835,12.873,13.835c7.712,0,12.974-6.583,12.974-13.835C28.929,7.413,23.375,2.046,15.954,2.046zM15.952,26.548L15.952,26.548c-2.289,0-3.49-1.611-4.121-3.796c-0.284-1.037-0.458-2.185-0.563-3.341c-0.114-1.374-0.129-2.773-0.129-4.028c0-0.993,0.018-1.979,0.074-2.926c0.124-1.728,0.386-3.431,0.89-4.833c0.694-1.718,1.871-2.822,3.849-2.822c2.5,0,3.763,1.782,4.385,4.322c0.429,1.894,0.56,4.124,0.56,6.274c0,2.299-0.103,5.153-0.763,7.442C19.473,24.979,18.242,26.548,15.952,26.548z");
var path4:CompoundPath = new CompoundPath();
SVGPathParser.draw(path4, "M15.318,7.677c0.071-0.029,0.148-0.046,0.229-0.046h11.949c-2.533-3.915-6.938-6.506-11.949-6.506c-5.017,0-9.428,2.598-11.959,6.522l4.291,7.431C8.018,11.041,11.274,7.796,15.318,7.677zM28.196,8.84h-8.579c2.165,1.357,3.605,3.763,3.605,6.506c0,1.321-0.334,2.564-0.921,3.649c-0.012,0.071-0.035,0.142-0.073,0.209l-5.973,10.347c7.526-0.368,13.514-6.587,13.514-14.205C29.77,13.002,29.201,10.791,28.196,8.84zM15.547,23.022c-2.761,0-5.181-1.458-6.533-3.646c-0.058-0.046-0.109-0.103-0.149-0.171L2.89,8.855c-1,1.946-1.565,4.153-1.565,6.492c0,7.624,5.999,13.846,13.534,14.205l4.287-7.425C18.073,22.698,16.848,23.022,15.547,23.022zM9.08,15.347c0,1.788,0.723,3.401,1.894,4.573c1.172,1.172,2.785,1.895,4.573,1.895c1.788,0,3.401-0.723,4.573-1.895s1.895-2.785,1.895-4.573c0-1.788-0.723-3.4-1.895-4.573c-1.172-1.171-2.785-1.894-4.573-1.894c-1.788,0-3.401,0.723-4.573,1.894C9.803,11.946,9.081,13.559,9.08,15.347z");
var morphs:Array = [];
morphs.push(CompoundPath.createMorphingPath(path1, path2));
morphs.push(CompoundPath.createMorphingPath(path2, path3));
morphs.push(CompoundPath.createMorphingPath(path3, path4));
morphs.push(CompoundPath.createMorphingPath(path4, path1));
var shape:Shape = new Shape();
var data:BitmapData = new BitmapData(465, 465, true, 0);
var bitmap:Bitmap = new Bitmap(data);
var m:Matrix = new Matrix();
m.scale(10, 10);
m.translate(50, 50);
addChild(bitmap);
var g:Graphics = graphics;
g.beginFill(0x000000);
g.drawRect(0, 0, 465, 465);
g.endFill();
var t:uint = 0;
addEventListener(Event.ENTER_FRAME, function(e:Event):void
{
if (t >= 400)
{
t = 0;
}
var index:int = int(t / 100);
var t0:Number = (t - index * 100) / 100;
t0 *= t0;
var morph:MorphingPath = morphs[index];
morph.interpolate(t0);
var g:Graphics = shape.graphics;
g.clear();
g.beginFill(0xffffff);
g.drawPath(morph.commands, morph.data);
g.endFill();
data.colorTransform(data.rect, new ColorTransform(0.5, 0.9, 0.7, 0.95));
data.draw(shape, m);
t += 4;
});
}
}
}
import flash.display.GraphicsPathCommand;
class SVGPathParser
{
private static var _svgPathCommands:Object = {a: 7, A: 7, q: 4, Q: 4,
t: 2, T: 2, s: 4, S: 4,
c: 6, C: 6, v: 1, V: 1,
h: 1, H: 1, l: 2, L: 2,
z: 0, Z: 0, m: 2, M: 2};
private static var _svgPathPattern:RegExp = /^\s*(([-+]?(([0-9]*\.?[0-9]+)|([0-9]+\.?[0-9]*)))|[aAqQtTsScCvVhHlLzZmM,])\s*/;
public static function draw(path:CompoundPath, pathString:String):void
{
if (pathString === null || pathString === "")
{
return;
}
var tokens:Array;
var lastCommand:String;
var moved:Boolean = false;
var args:Vector.<Number> = new Vector.<Number>();
var commaAccept:Boolean;
var commandAccept:Boolean;
var point:ControlPoint = new ControlPoint();
while (tokens = pathString.match(_svgPathPattern))
{
var token:String = tokens[1];
pathString = pathString.substring(tokens[0].length);
if (!moved && token !== "m" && token !== "M")
{
return;
}
else if (!moved)
{
moved = true;
lastCommand = token;
continue;
}
if (token in _svgPathCommands)
{
if (commandAccept)
{
return;
}
if (executeCommand(path, point, lastCommand, args))
{
lastCommand = token;
}
else
{
return;
}
lastCommand = token;
commaAccept = false;
commandAccept = false;
}
else
{
if (token !== ",")
{
commandAccept = false;
args.push(parseFloat(token));
}
else
{
commandAccept = true;
if (commaAccept)
{
continue;
}
else
{
return;
}
}
commaAccept = true;
}
}
if (lastCommand)
{
executeCommand(path, point, lastCommand, args)
}
}
private static function executeCommand(path:CompoundPath, point:ControlPoint, command:String, args:Vector.<Number>):Boolean
{
var argLength:uint = _svgPathCommands[command];
var command0:String = command.toLocaleLowerCase();
var relative:Number = command0 === command ? 1 : 0;
var x:Number, y:Number, x1:Number, y1:Number;
args.reverse();
while (true)
{
if (args.length < argLength)
{
return false;
}
switch (command0)
{
case "a":
//unsupported
break;
case "q":
point.qx = args.pop() + relative * path.x;
point.qy = args.pop() + relative * path.y;
//passthrough
case "t":
x = args.pop() + relative * path.x;
y = args.pop() + relative * path.y;
if (isNaN(point.qx))
{
point.qx = path.x;
}
if (isNaN(point.qy))
{
point.qy = path.y;
}
path.curveTo(point.qx, point.qy, x, y);
point.cx = point.cy = NaN;
point.qx = x * 2 - point.qx;
point.qy = y * 2 - point.qy;
break;
case "c":
point.cx = args.pop() + relative * path.x;
point.cy = args.pop() + relative * path.y;
//passthrough
case "s":
x = args.pop() + relative * path.x;
y = args.pop() + relative * path.y;
x1 = relative * path.x + args.pop();
y1 = relative * path.y + args.pop();
if (isNaN(point.cx))
{
point.cx = path.x;
}
if (isNaN(point.cy))
{
point.cy = path.y;
}
path.cubicCurveTo(point.cx, point.cy, x, y, x1, y1);
point.qx = point.qy = NaN;
point.cx = x1 * 2 - x;
point.cy = y1 * 2 - y;
break;
case "v":
path.lineTo(path.x, relative * path.y + args.pop());
point.cx = point.qx = point.cy = point.qy = NaN;
break;
case "h":
path.lineTo(relative * path.x + args.pop(), path.y);
point.cx = point.qx = point.cy = point.qy = NaN;
break;
case "l":
path.lineTo(relative * path.x + args.pop(), relative * path.y + args.pop());
point.cx = point.qx = point.cy = point.qy = NaN;
break;
case "z":
path.close();
point.cx = point.qx = point.cy = point.qy = NaN;
break;
case "m":
path.moveTo(relative * path.x + args.pop(), relative * path.y + args.pop());
point.cx = point.qx = point.cy = point.qy = NaN;
break;
default:
return false;
}
if (args.length === 0)
{
break;
}
}
return true;
}
private static function radiusToDegress(angle:Number):Number
{
return angle * (180 / Math.PI);
}
}
class CompoundPath
{
private static var _cbt:Vector.<Number> = Vector.<Number>([0, 0, 0, 1,
0.001953125, 0.041015625, 0.287109375, 0.669921875,
0.015625, 0.140625, 0.421875, 0.421875,
0.052734375, 0.263671875, 0.439453125, 0.244140625,
0.125, 0.375, 0.375, 0.125,
0.244140625, 0.439453125, 0.263671875, 0.052734375,
0.421875, 0.421875, 0.140625, 0.015625,
0.669921875, 0.287109375, 0.041015625, 0.001953125,
1, 0, 0, 0]);
public static function createMorphingPath(start:CompoundPath, end:CompoundPath):MorphingPath
{
start.close();
end.close();
var paths:uint = Math.max(start._paths.length, end._paths.length);
var startData:Vector.<Number> = new Vector.<Number>();
var endData:Vector.<Number> = new Vector.<Number>();
var commands:Vector.<int> = new Vector.<int>();
for (var i:uint = 0; i < paths; i++)
{
var startPath:Path = start._paths[i];
var endPath:Path = end._paths[i];
var count:uint;
if (startPath === null)
{
count = endPath.writeCoordCenter(endData, startData);
}
else if (endPath === null)
{
count = startPath.writeCoordCenter(startData, endData);
}
else if (startPath.coordsList.length !== endPath.coordsList.length)
{
count = startPath.writeCoordInterpolate(endPath, startData);
endPath.writeCoordInterpolate(startPath, endData);
}
else
{
count = startPath.coordsList.length;
startData.push(startPath.x, startPath.y);
endData.push(endPath.x, endPath.y);
for (var j:uint = 0, len:uint = startPath.coordsList.length; j < len; j++)
{
var startCoords:Coords = startPath.coordsList[j];
var endCoords:Coords = endPath.coordsList[j];
startData.push(startCoords.cx, startCoords.cy, startCoords.ax, startCoords.ay);
endData.push(endCoords.cx, endCoords.cy, endCoords.ax, endCoords.ay);
}
}
var commandIndex:uint = commands.length;
commands[commandIndex++] = GraphicsPathCommand.MOVE_TO;
for (var k:uint = 0; k < count; k++)
{
commands[commandIndex++] = GraphicsPathCommand.CURVE_TO;
}
}
return new MorphingPath(commands, startData, endData);
}
private var _coordsList:Array;
private var _lastMoveX:Number;
private var _lastMoveY:Number;
private var _paths:Array;
private var _x:Number;
private var _y:Number;
public function CompoundPath()
{
_paths = [];
_coordsList = [];
_x = 0;
_y = 0;
_lastMoveX = 0;
_lastMoveY = 0;
}
public function close():void
{
if (_coordsList.length > 0)
{
if (_x !== _lastMoveX || _y !== _lastMoveY)
{
lineTo(_lastMoveX, _lastMoveY);
_x = _lastMoveX;
_y = _lastMoveY;
}
_paths.push(new Path(_lastMoveX, _lastMoveY, _coordsList.splice(0)));
}
}
public function cubicCurveTo(cx1:Number, cy1:Number, cx2:Number, cy2:Number, ax:Number, ay:Number):void
{
var t:Vector.<Number> = _cbt, x0:Number, x1:Number, x2:Number, y0:Number, y1:Number, y2:Number, i:int;
for (i = 24; i >= 0; i -= 8)
{
x0 = t[i] * _x + t[i + 1] * cx1 + t[i + 2] * cx2 + t[i + 3] * ax;
y0 = t[i] * _y + t[i + 1] * cy1 + t[i + 2] * cy2 + t[i + 3] * ay;
x1 = t[i + 4] * _x + t[i + 5] * cx1 + t[i + 6] * cx2 + t[i + 7] * ax;
y1 = t[i + 4] * _y + t[i + 5] * cy1 + t[i + 6] * cy2 + t[i + 7] * ay;
x2 = t[i + 8] * _x + t[i + 9] * cx1 + t[i + 10] * cx2 + t[i + 11] * ax;
y2 = t[i + 8] * _y + t[i + 9] * cy1 + t[i + 10] * cy2 + t[i + 11] * ay;
var coords:Coords = new Coords(_x, _y, x1 * 2 - (x0 + x2) * 0.5, y1 * 2 - (y0 + y2) * 0.5, x0, y0);
if (coords.length > 0)
{
_coordsList.push(coords);
}
_x = x0;
_y = y0;
}
_x = ax;
_y = ay;
}
public function curveTo(cx:Number, cy:Number, ax:Number, ay:Number):void
{
var coords:Coords = new Coords(_x, _y, cx, cy, ax, ay);
if (coords.length > 0)
{
_coordsList.push(coords);
}
_x = ax;
_y = ay;
}
public function lineTo(x:Number, y:Number):void
{
var coords:Coords = new Coords(_x, _y, x + (_x - x) * 0.5, y + (_y - y) * 0.5, x, y);
if (coords.length > 0)
{
_coordsList.push(coords);
}
_x = x;
_y = y;
}
public function moveTo(x:Number, y:Number):void
{
if (_coordsList.length > 0)
{
_paths.push(new Path(_lastMoveX, _lastMoveY, _coordsList.splice(0)));
}
_x = x;
_y = y;
_lastMoveX = x;
_lastMoveY = y;
}
public function get x():Number
{
return _x;
}
public function get y():Number
{
return _y;
}
}
class ControlPoint
{
public var cx:Number;
public var cy:Number;
public var qx:Number;
public var qy:Number;
}
class Path
{
public var coordsList:Array;
public var x:Number;
public var y:Number;
public function Path(x:Number, y:Number, coordsList:Array):void
{
var total:Number = 0;
var coords:Coords;
var current:Number = 0;
for each (coords in coordsList)
{
total += coords.length;
}
for each (coords in coordsList)
{
coords.pos = current / total;
current += coords.length;
}
this.x = x;
this.y = y;
this.coordsList = coordsList;
}
private function getNumCoords(from:Number, to:Number):uint
{
var count:uint = 0;
for each (var coords:Coords in coordsList)
{
if (from <= coords.pos && coords.pos < to)
{
count++;
}
else if (to <= coords.pos)
{
break;
}
}
return count;
}
public function writeCoordCenter(selfData:Vector.<Number>, centerData:Vector.<Number>):uint
{
var pointsX:Array = [];
var pointsY:Array = [];
var x:Number = this.x, y:Number = this.y;
var len:uint = 0;
selfData.push(x, y);
for each (var coords:Coords in coordsList)
{
selfData.push(coords.cx, coords.cy, coords.ax, coords.ay);
getBounds1(coords.sx, coords.sy, coords.cx, coords.cy, coords.ax, coords.ay, pointsX, pointsY);
len++;
}
x = Math.min.apply(null, pointsX);
y = Math.min.apply(null, pointsY);
x += (Math.max.apply(null, pointsX) - x) / 2;
y += (Math.max.apply(null, pointsY) - y) / 2;
centerData.push(x, y);
for (var i:uint = 0; i < len; i++)
{
centerData.push(x, y, x, y);
}
return len;
}
public function writeCoordInterpolate(compare:Path, data:Vector.<Number>):uint
{
var self:Path = clone(), coords:Coords;
var segments:uint = 4, i:uint, diff:int;
var posFrom:Number, posTo:Number;
for (i = 0; i < segments; i++)
{
posFrom = i / segments;
posTo = (i + 1) / segments;
diff = compare.getNumCoords(posFrom, posTo) - self.getNumCoords(posFrom, posTo);
if (diff <= 0)
{
continue;
}
for each (coords in compare.coordsList)
{
if (posFrom <= coords.pos && coords.pos < posTo)
{
if (self.split(coords.pos))
{
diff--;
if (diff === 0)
{
break;
}
}
}
else if (posTo <= coords.pos)
{
break;
}
}
}
data.push(x, y);
for each (coords in self.coordsList)
{
data.push(coords.cx, coords.cy, coords.ax, coords.ay);
}
return self.coordsList.length;
}
private function clone():Path
{
var coordsList:Array = new Array(this.coordsList.length);
for (var i:uint = 0, len:uint = coordsList.length; i < len; i++)
{
coordsList[i] = this.coordsList[i].clone();
}
return new Path(x, y, coordsList);
}
private function getBounds1(x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number, pointsX:Array, pointsY:Array):void
{
var left:Number = Math.min(x1, x3);
var right:Number = Math.max(x1, x3);
var top:Number = Math.min(y1, y3);
var bottom:Number = Math.max(y1, y3);
var t:Number, tp:Number, p:Number;
t = (x1 - x2) / (x3 - 2 * x2 + x1);
if (0 <= t && t <= 1)
{
tp = 1 - t;
p = tp * tp * x1 + 2 * tp * t * x2 + t * t * x3;
if (p < left)
{
left = p;
}
else if (right < p)
{
right = p;
}
}
t = (y1 - y2) / (y3 - 2 * y2 + y1);
if (0 <= t && t <= 1)
{
tp = 1 - t;
p = tp * tp * y1 + 2 * tp * t * y2 + t * t * y3;
if (p < top)
{
top = p;
}
else if (bottom < p)
{
bottom = p;
}
}
pointsX.push(left, right);
pointsY.push(bottom, top);
}
private function split(pos:Number):Boolean
{
if (pos === 0)
{
return false;
}
var coords0:Coords;
var coords1:Coords;
var index:uint = 0;
var pos0:Number;
var pos1:Number;
for (var i:int = 0, len:uint = coordsList.length; i < len; i++)
{
coords0 = coordsList[i];
coords1 = coordsList[i + 1];
if (coords0.pos === pos)
{
return false;
}
pos0 = coords0.pos;
pos1 = coords1 === null ? 1 : coords1.pos;
if (pos0 < pos && pos < pos1)
{
index = i;
break;
}
}
var t:Number = 1 - (pos1 - pos) / (pos1 - pos0);
var tp:Number = 1 - t;
var dx:Number = tp * coords0.sx + t * coords0.cx;
var dy:Number = tp * coords0.sy + t * coords0.cy;
var ex:Number = tp * coords0.cx + t * coords0.ax;
var ey:Number = tp * coords0.cy + t * coords0.ay;
var fx:Number = tp * tp * coords0.sx + 2 * tp * t * coords0.cx + t * t * coords0.ax;
var fy:Number = tp * tp * coords0.sy + 2 * tp * t * coords0.cy + t * t * coords0.ay;
var coords2:Coords = new Coords(fx, fy, ex, ey, coords0.ax, coords0.ay);
coords2.pos = pos;
coords0.cx = dx;
coords0.cy = dy;
coords0.ax = fx;
coords0.ay = fy;
coordsList.splice(index + 1, 0, coords2);
return true;
}
}
class Coords
{
public var ax:Number;
public var ay:Number;
public var cx:Number;
public var cy:Number;
public var length:Number;
public var pos:Number;
public var sx:Number;
public var sy:Number;
public function Coords(sx:Number, sy:Number, cx:Number, cy:Number, ax:Number, ay:Number)
{
this.sx = sx;
this.sy = sy;
this.cx = cx;
this.cy = cy;
this.ax = ax;
this.ay = ay;
length = computeLength();
}
public function clone():Coords
{
var coords:Coords = new Coords(sx, sy, cx, cy, ax, ay);
coords.pos = pos;
coords.length = length;
return coords;
}
private function computeLength():Number
{
var xa:Number = 2 * (sx - 2 * cx + ax);
var xb:Number = -2 * sx + 2 * cx;
var ya:Number = 2 * (sy - 2 * cy + ay);
var yb:Number = -2 * sy + 2 * cy;
var a:Number = xa * xa + ya * ya;
var b:Number = 2 * (xa * xb + ya * yb);
var c:Number = xb * xb + yb * yb;
if (b * b !== 4 * a * c)
{
return (2 * ((2 * a + b) * Math.sqrt(a * (a + b + c)) - b * Math.sqrt(a * c)) + (b * b - 4 * a * c) * Math.log((2 * Math.sqrt(a * c) + b) / (2 * (Math.sqrt(a * (a + b + c)) + a) + b))) / (8 *
a * Math.sqrt(a));
}
else if (a !== 0)
{
if (1 !== -b / (2 * a))
{
return (2 * ((2 * a + b) * Math.sqrt(a * (a + b + c)) - b * Math.sqrt(a * c))) / (8 * a * Math.sqrt(a));
}
return -b * Math.sqrt(c) / (4 * a);
}
return Math.sqrt(c);
}
}
class MorphingPath
{
private var _commands:Vector.<int>;
private var _data:Vector.<Number>;
private var _endData:Vector.<Number>;
private var _startData:Vector.<Number>;
public function MorphingPath(commands:Vector.<int>, startData:Vector.<Number>, endData:Vector.<Number>)
{
_startData = startData;
_endData = endData;
_commands = commands;
_data = new Vector.<Number>(_startData.length, true);
interpolate(0);
}
public function get commands():Vector.<int>
{
return _commands;
}
public function get data():Vector.<Number>
{
return _data;
}
public function interpolate(t:Number):void
{
var i:int, len:uint, start:Number;
for (i = 0, len = _startData.length; i < len; i++)
{
start = _startData[i];
_data[i] = start + (_endData[i] - start) * t;
}
}
}