シェイプトゥイーンの実験
作りかけのライブラリでパスのモーフィングが実装できたので、実験的に上げてみました。
まだちょっと重いですね。。。
package
{
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=60)]
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 path5:CompoundPath = new CompoundPath();
SVGPathParser.draw(path5, "M16.154,5.135c-0.504,0-1,0.031-1.488,0.089l-0.036-0.18c-0.021-0.104-0.06-0.198-0.112-0.283c0.381-0.308,0.625-0.778,0.625-1.306c0-0.927-0.751-1.678-1.678-1.678s-1.678,0.751-1.678,1.678c0,0.745,0.485,1.376,1.157,1.595c-0.021,0.105-0.021,0.216,0,0.328l0.033,0.167C7.645,6.95,3.712,11.804,3.712,17.578c0,6.871,5.571,12.441,12.442,12.441c6.871,0,12.441-5.57,12.441-12.441C28.596,10.706,23.025,5.135,16.154,5.135zM16.369,8.1c4.455,0,8.183,3.116,9.123,7.287l-0.576,0.234c-0.148-0.681-0.755-1.191-1.48-1.191c-0.837,0-1.516,0.679-1.516,1.516c0,0.075,0.008,0.148,0.018,0.221l-2.771-0.028c-0.054-0.115-0.114-0.226-0.182-0.333l3.399-5.11l0.055-0.083l-4.766,4.059c-0.352-0.157-0.74-0.248-1.148-0.256l0.086-0.018l-1.177-2.585c0.64-0.177,1.111-0.763,1.111-1.459c0-0.837-0.678-1.515-1.516-1.515c-0.075,0-0.147,0.007-0.219,0.018l0.058-0.634C15.357,8.141,15.858,8.1,16.369,8.1zM12.146,3.455c0-0.727,0.591-1.318,1.318-1.318c0.727,0,1.318,0.591,1.318,1.318c0,0.425-0.203,0.802-0.516,1.043c-0.183-0.123-0.413-0.176-0.647-0.13c-0.226,0.045-0.413,0.174-0.535,0.349C12.542,4.553,12.146,4.049,12.146,3.455zM7.017,17.452c0-4.443,3.098-8.163,7.252-9.116l0.297,0.573c-0.61,0.196-1.051,0.768-1.051,1.442c0,0.837,0.678,1.516,1.515,1.516c0.068,0,0.135-0.006,0.2-0.015l-0.058,2.845l0.052-0.011c-0.442,0.204-0.824,0.513-1.116,0.895l0.093-0.147l-1.574-0.603l1.172,1.239l0.026-0.042c-0.19,0.371-0.306,0.788-0.324,1.229l-0.003-0.016l-2.623,1.209c-0.199-0.604-0.767-1.041-1.438-1.041c-0.837,0-1.516,0.678-1.516,1.516c0,0.064,0.005,0.128,0.013,0.191l-0.783-0.076C7.063,18.524,7.017,17.994,7.017,17.452zM16.369,26.805c-4.429,0-8.138-3.078-9.106-7.211l0.691-0.353c0.146,0.686,0.753,1.2,1.482,1.2c0.837,0,1.515-0.679,1.515-1.516c0-0.105-0.011-0.207-0.031-0.307l2.858,0.03c0.045,0.095,0.096,0.187,0.15,0.276l-3.45,5.277l0.227-0.195l4.529-3.92c0.336,0.153,0.705,0.248,1.094,0.266l-0.019,0.004l1.226,2.627c-0.655,0.166-1.142,0.76-1.142,1.468c0,0.837,0.678,1.515,1.516,1.515c0.076,0,0.151-0.007,0.225-0.018l0.004,0.688C17.566,26.746,16.975,26.805,16.369,26.805zM18.662,26.521l-0.389-0.6c0.661-0.164,1.152-0.759,1.152-1.47c0-0.837-0.68-1.516-1.516-1.516c-0.066,0-0.13,0.005-0.193,0.014v-2.86l-0.025,0.004c0.409-0.185,0.77-0.459,1.055-0.798l1.516,0.659l-1.104-1.304c0.158-0.335,0.256-0.704,0.278-1.095l2.552-1.164c0.19,0.618,0.766,1.068,1.447,1.068c0.838,0,1.516-0.679,1.516-1.516c0-0.069-0.006-0.137-0.016-0.204l0.65,0.12c0.089,0.517,0.136,1.049,0.136,1.591C25.722,21.826,22.719,25.499,18.662,26.521z");
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, path5));
morphs.push(CompoundPath.createMorphingPath(path5, path1));
var shape:Shape = new Shape();
shape.scaleX = 10;
shape.scaleY = 10;
shape.x = 50;
shape.y = 50;
addChild(shape);
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 >= 500)
{
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();
t += 2;
});
}
}
}
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
{
var dataIndex:uint = startData.length;
count = startPath.coordsList.length;
startData[dataIndex] = startPath.x;
endData[dataIndex++] = endPath.x;
startData[dataIndex] = startPath.y;
endData[dataIndex++] = 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[dataIndex] = startCoords.cx;
endData[dataIndex++] = endCoords.cx;
startData[dataIndex] = startCoords.cy;
endData[dataIndex++] = endCoords.cy;
startData[dataIndex] = startCoords.ax;
endData[dataIndex++] = endCoords.ax;
startData[dataIndex] = startCoords.ay;
endData[dataIndex++] = 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;
}
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, index:uint = selfData.length;
selfData[index++] = x;
selfData[index++] = y;
for each (var coords:Coords in coordsList)
{
selfData[index++] = coords.cx;
selfData[index++] = coords.cy;
selfData[index++] = coords.ax;
selfData[index++] = coords.ay;
getBounds1(coords.sy, coords.sx, coords.cx, coords.cy, coords.ax, coords.ay, pointsX, pointsY);
len += 4;
}
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;
index -= len + 2;
len /= 2;
centerData[index++] = x;
centerData[index++] = y;
for (var i:uint = 0; i < len; i++)
{
centerData[index++] = x;
centerData[index++] = y;
}
return len / 2;
}
public function writeCoordInterpolate(compare:Path, data:Vector.<Number>):uint
{
var self:Path = clone(), coords:Coords;
for each (coords in compare.coordsList)
{
self.split(coords.pos);
}
var dataIndex:uint = data.length;
data[dataIndex++] = x;
data[dataIndex++] = y;
for each (coords in self.coordsList)
{
data[dataIndex++] = coords.cx;
data[dataIndex++] = coords.cy;
data[dataIndex++] = coords.ax;
data[dataIndex++] = 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):void
{
if (pos === 0)
{
return;
}
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;
}
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);
}
}
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;
}
}
}