Dead Code Preservation :: Archived AS3 works from wonderfl.net

シェイプトゥイーンの実験

作りかけのライブラリでパスのモーフィングが実装できたので、実験的に上げてみました。
まだちょっと重いですね。。。
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;
        }
    }
}