In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

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

forked from: forked from: スパスパサボ○ン

/**
 * Copyright ultranoir ( http://wonderfl.net/user/ultranoir )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/wQIS
 */

// forked from Nyarineko's forked from: スパスパサボ○ン
// forked from a24's スパスパサボ○ン
// 
// twitter mogera さんの発言より
// 
// ふろはいってる間想像してたのが、中央にとんがたたずんでいる。
// ドラッグしてスパンと切ると切り口からちいさいとんがわらわらでてくる。
// そのとんがだんだん大きくなって、こちら側にきてるように見える。
// またそのトンを切ることもできる。
//

package  
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Matrix;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	import flash.geom.Point;
	import flash.geom.ColorTransform;
	import flash.filters.BlurFilter;
	import flash.utils.setTimeout;
	import net.hires.debug.Stats;
	
	[SWF(backgroundColor="#ffffff", frameRate=60)]
	
	public class Main extends Sprite
	{
		static public var _particleArray:Array = new Array();
		static public var _hitArea:Shape = new Shape();
		static private var _objCount:TextField;
		static private var _pCount:TextField;
		static private var _count:int = 0;
		private var _point:Point;
		private var _sliceObj:LineSliceObject;
		private var _objContainer:Sprite = new Sprite();
		private var _gravity:Number = 1;
		private var _canvas:BitmapData = new BitmapData(465, 465, false, 0xffffff);
		private var _colorTr:ColorTransform = new ColorTransform(0.94, 0.94, 0.94, 0.94);
		private var _objCreateCont:int = 0;
		private var _icons:Array = new Array();
		private var _timer:Timer;
		private const _iconsData:Array = ["R0lGODlhUAA/AMQfAM+rbnRKLvb085NrRrOhl4pgN6WPg7KLV1MmDevJhdrRzGQ2G5J1ZHtUO8KyqUsjDFssEp2BcqJ6Sufh3ms/I87Cu14xF8OeZV9ALoJgTT0cCuXDgEQfC9y6eVkpDv///yH5BAEAAB8ALAAAAABQAD8AAAX/4CeOZClMSuUQjlNNQinP9CicSg7Hdd8LipUhwmBEIoQKz8cUAVWEKEuxbPomjiGRMch4vxlDxUoTVAjHYrH7jTiq5BE2zfU2GoG7/s4Yxz8CWXRsDRmFX4UEcFYVdHYBFJGSFAGVdwERi2UVQ2uPlaCWlxl+VoFphpAUCxYWEBCtCwuRkJYKTAJoRI+Rsqy+tKAUBqZodZCsrxAezB7KFrKTFA49E51dyK3K27DQkwsMmiS5u3jJy83pzK+xvhbUMwqoDauu6OrN7L6sDD4O5ate4RvorBsrV6XkbMmATCBBdey0eSBGQ0ERQxRcPXwYcdmCCeO2mNO4Ed+zZQgS/9owwAAjyZIDtzFrwCPXsWQwCTpEEGBRhZYMF9zLadIhBAIifrYMgJNoTGYIECANia2p06ceLPQUsAvSy6sDo2KooqALva8eCgDYcGEAhasQFgSI0vLsULD4oj6AJ8KAF6Z3AyTocGDwAmcDYL6adYieULwlETzIYKNuxrsDEkjw4JZZgQs5YVGqVO8uZHWSIYD8oOBvRnwUOiQAIOHwAgAJCiiG5Q7tadSSlQRK9RhfgwOyO7w9AIDoSYe/Ceo1AMOvXXUUDrBdICHBAQ/Mo4sPK5nUBAZ4LqsbsAFAAK3ewTdvVnz8ab1zLY7Exz3BALUbBOCBBB00sAwFG2xm3/99kmGQBEOAEVQAcxJYwAx3umUlwVsLQqYXBmKkV18zkXiQzAANDDRLh2lxSNSHBjhAj3rqBIAcABAUlkCK6QSwQYYbCQhBAS4SBMB3Tkn2AIgVOOabBxQkANoBF/injgW5lbQAaBZ0kNhGB/D44gMcgKhAA7I86cEFGxwmWAADHHCAbhb86IGNG1rQQJwFbGknkRA0MOGXg1LCjARHormRZGUqwkAramamm5xrEpYABRD8eNsAF1zQ3QUAdGDBBcoVkEAApgJQ5QJqFdCBgqYOAECfDzHKASkfECCTimw1cMEyrhaW2I/dSeBpAwkswN6AHZi4Y5SVJBvqAAUyE0D/B55aWCuZGijCWk6FdUAnW9RuRmyCfZrK2QbMOgvJpYJRAABtit4pJ7ZAAveABhys9oGYD5m6wVt1XmDqBVgOIBiVYSa7rAQBRknkqchS0B2ViUGArbIbIJkXt5SN4EBUGxlrsGdHSjCnpwMeqeysiFYCAIptfTaArAVYQCE6xiK6YVjcapCQAA2QzKJ9FBApHaMahEyCAlEZ3SEFA0ggIIt6caABBJoYEDUCHSLa6XYLZq2B0DUw8MADUkcXAG0AUMKWfUpq3e0PGawdtXhJd9DBMt3Z2Olm2S1A5WGRkWk3RT+orTfY0Wn8N2f+9XxqZrJaWSvT/E7VhAEcrM02/+SQSQ54bmoJuyYAhn+ZV91nW6ASEw5AEPropMPlNyW7d9xAgnf6d0CRzWRtdwb+xjFBBhzc3jZRCCYgfZZ+awfampq9rvjZD3j+xwgEWHD76FfteXNnUEpQQAMqFyCrtlDBfjby389wXvOiP/8bBRcc8HPxa2ve2TDAl/rFowH4w93R4rc9DSDAAOIwIAkcgIEE6i86egkaBxiQPAn+gAAIGN8F8WK8szXgFh5UHvOclzsPBfBsR0mhAZtkwRa+iHMa4KAMPRg+FoJFfhiY3Q6/d7/HJamB4RjiEB0gPvJFhnPdU6IUJ9CA/C2KcxhAoRSVyBUfau94EdwiD/PXQlGzaSACYkxjUiCgt3SY0Xtq3KICLODEN8bxjgpYAO44V8A7pnGObHuhBvroxzRWQH5wLKQaCRA0xinSjxGY3yMfKQAMcG2Sj4wCJh85gQ7eMQQAOw=="];
		
		public function Main() 
		{
			Wonderfl.capture_delay(4);
			
			addChild(new Bitmap(_canvas));
			addChild(new Stats());
			addChild(_objContainer);
			addChild(new MouseGrowEffect(stage));
			
			// text
			_objCount = createTextField(48, true);
            _objCount.x = 450;
            _objCount.y = 370;
			_objCount.text = "0";
            addChild(_objCount);
			
			_pCount = createTextField(12);
            _pCount.x = 445;
            _pCount.y = 430;
			_pCount.text = "0";
            addChild(_pCount);
			
			// timer
			_timer = new Timer(200, 0);
			_timer.addEventListener(TimerEvent.TIMER, TiemrHandler);
			
			// icon
			var len:int = _iconsData.length;
			for (var i:int = 0; i < len; i ++) 
				_icons.push(new Base64ImageLoader(_iconsData[i]));
			
			setTimeout(function():void
			{
				addEventListener(Event.ENTER_FRAME, drawParticles);
				
				var lobj:LineSliceObject = createObject(true);
				lobj.scaleX = lobj.scaleY = 0.5;
				lobj.x -= lobj.width / 2;
				lobj.y -= lobj.height / 2;
				lobj.addEventListener("sliced", timerStart);
				_objContainer.addChild(lobj);
			}, 500);
			
		}
		
		private function timerStart(e:Event):void
		{
			_timer.start();
		}
		
		private function createTextField(size:Number, bold:Boolean = false):TextField
		{
            var _format:TextFormat = new TextFormat();
            _format.align = "right";
            _format.bold = bold;
            _format.font = "Verdana";
            _format.color = 0xFFFFFF;
            _format.letterSpacing = 2;
            _format.size = size;
			
			var _tf:TextField = new TextField();
            _tf.defaultTextFormat = _format;
            _tf.autoSize = "right";
            _tf.mouseEnabled = false;
			
			return _tf;
		}
		
		private function TiemrHandler(e:TimerEvent):void 
		{
			//if (_timer.delay > 200) _timer.delay -= 50;
			
			if (_objContainer.numChildren > 30) return;
			_objContainer.addChild(createObject())
		}
		
		private function createObject(tween:Boolean = false):LineSliceObject
		{
			var img:Base64ImageLoader = _icons[0];
			var bmpData:BitmapData = new BitmapData(img.width, img.height, false ,0xffffff);
			bmpData.draw(img, null, null, null, null, true);
			var _pointArray:Array = [new Point(0, 0), new Point(img.width, 0), new Point(img.width, img.height), new Point(0, img.height)];
			
			var _obj:LineSliceObject = new LineSliceObject(stage, _pointArray, bmpData, tween);
			_obj.x = 230;
			_obj.y = 230;
			
			_objCreateCont ++;
			
			return _obj;
		}
		
		/*
		 * ------------------------------------------------------------
		 * パーティクルを描画
		 * ------------------------------------------------------------
		*/
		private function drawParticles(e:Event):void 
		{
			_canvas.colorTransform(_canvas.rect, _colorTr);
			_canvas.lock();
			_canvas.applyFilter(_canvas, _canvas.rect, new Point(0, 0), new BlurFilter(8, 8));
			
			var _length:int = _particleArray.length;
			var _nP:int = 0;
			
			for (var i:int = 0; i < _length; i ++)
			{
				if (_particleArray[i])
				{
					var p:Particle = _particleArray[i];
					var min:Number = 500;
					
					while ((p = p.next) != null)
					{
						_canvas.setPixel32(p.x, p.y, addColor(_canvas.getPixel(p.x, p.y), p.color));
						p.x += p.vx;
						p.y += p.vy;
						p.vy += _gravity;
						min = Math.min(min, p.y);
						_nP ++;
						
						// 画面外にでたら消す
						while (p.next != null && ((p.next.y > 465 && p.next.vy > 0) || (p.next.x < 0 || p.next.x > 465)))
						{
							p.next = p.next.next;
						}
					}
					
					// 一塊画面外にでたら配列から消す
					if (min > 465)
					{
						_particleArray.splice(i, 1)
						i --;
					}
				}
			}
			_pCount.text = _nP.toString();
			_canvas.unlock();
		}
		
		public static function countUp():void
		{
			_count ++;
			_objCount.text = _count.toString();
		}
		
		public function addColor(_col1:uint, _col2:uint):uint
		{
			var r1:uint = _col1 >> 16 & 0xFF;
			var g1:uint = _col1 >> 8 & 0xFF;
			var b1:uint = _col1 & 0xFF;
			
			var r2:uint = _col2 >> 16 & 0xFF;
			var g2:uint = _col2 >> 8 & 0xFF;
			var b2:uint = _col2 & 0xFF;
			
			var r3:uint = (r1 + r2 < 255) ? r1 + r2 : 255;
			var g3:uint = (g1 + g2 < 255) ? g1 + g2 : 255;
			var b3:uint = (b1 + b2 < 255) ? b1 + b2 : 255;
			
			return ((r3 & 0xFF) << 16) | ((g3 & 0xFF) << 8) | (b3 & 0xFF);
		}
	}
}


class Particle
{
	public var x:Number;
	public var y:Number;
	public var vx:Number;
	public var vy:Number;
	public var next:Particle;
	public var color:uint;
	
	public function Particle(){ }
}


import flash.display.DisplayObject;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.events.TweenEvent;
import org.libspark.betweenas3.tweens.ITween;

class LineSliceObject extends Sprite
{
	private var _stage:Stage;
	private var _pointArray:Array;
	private var _bmpData:BitmapData;
	private var _point1:Point;
	private var _point2:Point;
	private var _tempPoint:Point;
	private var _nAngle:int;
	private var _isOver:Boolean;
	
	private var _centroid:Point;
	private var particles:Particle;
	
	private var _gravity:Number = 1;
	private var _vx:Number = 0;
	private var _vy:Number = 0;
	private var _rotation:Number = 0;
	private var _tween:ITween;
	
	public function LineSliceObject(stage:Stage, pointArray:Array, bmpData:BitmapData, isSliced:Boolean = false ) 
	{
		_stage = stage;
		_pointArray = pointArray;
		_bmpData = bmpData;
		blendMode = "add";
		drawRectFromPoint(this, _pointArray, _bmpData);
		_centroid = getCentroid(_pointArray);
		
		_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		
		if (!isSliced) addEventListener(Event.ADDED_TO_STAGE, addedHandler);
	}
	
	private function addedHandler(e:Event):void 
	{
		removeEventListener(Event.ADDED_TO_STAGE, addedHandler);
		
		var me:Sprite = this;
		var tx:Number = -100 + Math.random() * 565 >> 0;
		var ty:Number = -100 + Math.random() * 565 >> 0;
		scaleX = scaleY = 0;
		_tween = BetweenAS3.tween(this, { x:-_bmpData.width / 2 + tx, y:-_bmpData.height / 2 + ty, scaleX:1, scaleY:1 }, null, 3.0);
		_tween.addEventListener(TweenEvent.COMPLETE, function():void {
			me.visible = false;
			_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		});
		_tween.play();
	}
	
	private function mouseMoveHandler(e:MouseEvent):void 
	{
		if (hitTestPoint(_stage.mouseX, _stage.mouseY, true) && !_isOver)
		{
			_point1 = _tempPoint;
			_isOver = true;
		}
		
		_tempPoint = new Point(_stage.mouseX, _stage.mouseY);
		
		if (!hitTestPoint(_stage.mouseX, _stage.mouseY, true) && _isOver)
		{
			_isOver = false;
			
			if (!_point1) return;
			
			_point2 = _tempPoint;
			slice(_point1, _point2);
		}
	}
	
	private function drawRectFromPoint(_target:Sprite, _pointArray:Array, _bmpData:BitmapData):void
	{
		var hx:int = - _bmpData.width / 2;
		var hy:int = - _bmpData.height / 2;
		
		_target.graphics.beginBitmapFill(_bmpData);
		
		_target.graphics.moveTo(_pointArray[0].x, _pointArray[0].y);
		_nAngle = _pointArray.length;
		for (var i:int = 1; i < _nAngle; i ++)
		{
			var _point:Point = _pointArray[i];
			_target.graphics.lineTo(_point.x, _point.y);
		}
		_target.graphics.endFill();
	}
	
	private function getCentroid(_pointArray:Array):Point
	{
		var X:Number = 0;
		var Y:Number = 0;
		for each(var point:Point in _pointArray)
		{
			X += point.x;
			Y += point.y;
		}
		return new Point((X / _pointArray.length), (Y / _pointArray.length));
	}
	
	private function convertToPointFromCentroid(_pointArray:Array):Array
	{
		var cp:Point = getCentroid(_pointArray);
		var len:int = _pointArray.length;
		
		for (var i:int = 0; i < len; i ++) 
		{
			var pt:Point = _pointArray[i];
			_pointArray[i] = new Point(pt.x - cp.x, pt.y - cp.y);
		}
		return _pointArray;
	}
	
	public function slice(_point1:Point, _point2:Point):void
	{
		var _pt1:Point = globalToLocal(_point1);
		var _pt2:Point = globalToLocal(_point2);
		var _newPointArray:Array = [new Array(), new Array()];
		var _numCloss:int = 0;
		
		for (var i:int = 0; i < _nAngle ; i ++) 
		{
			var _pt3:Point = _pointArray[i];
			var _pt4:Point = (_pointArray[i + 1]) ? _pointArray[i + 1] : _pointArray[0];
			var _clossPt:Point = crossPoint(_pt1, _pt2, _pt3, _pt4);
			
			_newPointArray[0].push(_pt3);
			if (_clossPt)
			{
				_newPointArray[0].push(_clossPt);
				_newPointArray[1].push(_clossPt);
				_newPointArray.reverse();
				_numCloss ++;
			}
		}
		if (_numCloss == 2)
		{
			var _newObj1:LineSliceObject = new LineSliceObject(_stage, _newPointArray[0], _bmpData, true);
			var _newObj2:LineSliceObject = new LineSliceObject(_stage, _newPointArray[1], _bmpData, true);
			_newObj1.x = _newObj2.x = this.x;
			_newObj1.y = _newObj2.y = this.y;
			_newObj1.scaleX = _newObj1.scaleY = _newObj2.scaleX = _newObj2.scaleY = scaleX;
			parent.addChild(_newObj1);
			parent.addChild(_newObj2);
			parent.removeChild(this);
			removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			dispatchEvent(new Event("sliced"));
			
			var _vector:Point = _pt2.subtract(_pt1);
			var _angle:Number = Math.atan2(_vector.y, _vector.x);
			var _force:int = 4;
			var _fx:Number = Math.abs(Math.sin(_angle));
			var _fy:Number = Math.abs(Math.cos(_angle));
			var _fx1:Number = (_newPointArray[0][0].x <  _newPointArray[1][0].x) ? -_fx : _fx;
			var _fx2:Number = (_newPointArray[1][0].x <= _newPointArray[0][0].x) ? -_fx : _fx;
			var _fy1:Number = (_newPointArray[0][0].y <   _newPointArray[1][0].y) ? -_fy : _fy;
			var _fy2:Number = (_newPointArray[1][0].y <= _newPointArray[0][0].y) ? -_fy : _fy;
			
			_newObj1._vx = _fx1 * _force;
			_newObj2._vx = _fx2 * _force;
			_newObj1._vy = _fy1 * _force - 10;
			_newObj2._vy = _fy2 * _force - 10;
			_newObj1.sliced();
			_newObj2.sliced();
			Main.countUp();
		}
	}
	
	private function crossPoint(_pt1:Point, _pt2:Point, _pt3:Point, _pt4:Point):Point
	{	
		var _vector1:Point = _pt2.subtract(_pt1);
		var _vector2:Point = _pt4.subtract(_pt3);
		
		if (cross(_vector1, _vector2) == 0.0) return null;
		
		var _s:Number = cross(_vector2, _pt3.subtract(_pt1)) / cross(_vector2, _vector1);
		var _t:Number = cross(_vector1, _pt1.subtract(_pt3)) / cross(_vector1, _vector2);
		
		if (isCross(_s) && isCross(_t))
		{
			_vector1.x *= _s;
			_vector1.y *= _s;
			return _pt1.add(_vector1);
		}
		else return null;
	}
		
	private function cross(_vector1:Point, _vector2:Point):Number
	{
		return (_vector1.x * _vector2.y - _vector1.y * _vector2.x);
	}
	
	private function isCross(_n:Number):Boolean
	{
		return ((0 <= _n) && (_n <= 1));
	}
	
	private function sliced():void
	{
		addEventListener(Event.ENTER_FRAME, enterFrameHandler);
	}
	
	private function enterFrameHandler(e:Event):void 
	{
		var _matrix:Matrix = transform.matrix;
		MatrixTransformer.rotateAroundInternalPoint(_matrix, _centroid.x, _centroid.y, 20);
		transform.matrix = _matrix;
		
		x += _vx;
		y += _vy;
		_vy += _gravity;
		
		if (y > 460)
		{
			removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			createParticle();
		}
	}
	
	private function createParticle():void 
	{
		y = 400;
		_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		
		if (width < 1 || height < 1) {
			parent.removeChild(this);
			return;
		}
		
		var n:int = width * height;
		var prev:Particle = particles = new Particle();
		var p:Particle;
		var i:int = -1;
		var _bmpData:BitmapData = new BitmapData(width, height, false, 0x000000);
		_bmpData.draw(this);
		
		while (i <= n)
		{
			var X:int = i % width;
			var Y:int = int(i / width);
			var col:uint = _bmpData.getPixel(X, Y);
			
			if (col)
			{
				p = new Particle();
				p.color = col;
				p.x = this.x + X;
				p.y = this.y + Y + 20;
				p.vx = -10 + Math.random() * 20;
				p.vy = -10 -Math.random() * Math.random() * 18;
				prev.next = p;
				prev = p;
			}
			i += 2;
		}
		parent.removeChild(this);
		Main._particleArray.push(particles);
	}
	
	private function pointRotation(_target:DisplayObject, _point:Point, _degree:Number):void
	{
		var _matrix:Matrix = _target.transform.matrix;
		MatrixTransformer.rotateAroundInternalPoint(_matrix, _point.x, _point.y, _degree);
		_target.transform.matrix = _matrix;
	}
}


import flash.display.Loader;
import flash.utils.ByteArray;
import mx.utils.Base64Decoder;

class Base64ImageLoader extends Loader
{
	public function Base64ImageLoader( data:String ) 
	{
		var byteArray:ByteArray;
		var base64Decoder:Base64Decoder;
		
		base64Decoder = new Base64Decoder();
		base64Decoder.decode( data );
		
		byteArray = base64Decoder.toByteArray();
		byteArray.position = 0;
		
		loadBytes( byteArray );
	}
}


import flash.display.Stage;
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.Event;
import flash.filters.GlowFilter;
import flash.geom.Point;

class MouseGrowEffect extends Sprite
{
	private var _stage:Stage;
	private var dep:Number = 0;
	private var linearr:Array = new Array();
	private var dotarr:Array = new Array();
	private var draw_mc:Sprite = new Sprite();
	
	public function MouseGrowEffect( _stage:Stage )
	{
		this._stage = _stage;
		this.addEventListener( Event.ADDED_TO_STAGE, onAdd2Stage );
	}
	
	private function onAdd2Stage( e:Event ):void
	{
		this.addChild( draw_mc );
		var glow:GlowFilter = new GlowFilter( 0x33FF33, 1, 16, 16, 2, 3, false, false );
		draw_mc.filters = [ glow ];            
		this.addEventListener( Event.ENTER_FRAME, onEventEnterFrame );
		
	}
	private function onEventEnterFrame( e:Event ):void
	{
		var _obj:Object = new Object();
		
		if ( _stage.mouseX != 0 && _stage.mouseX != 0 )
		{
			_obj.x = _stage.mouseX;
			_obj.y = _stage.mouseY;
			dotarr.push( _obj );
		}
		if ( dotarr.length > 10 )
		{
			dotarr.splice( 0,1 );
		}
		
		var _g:Graphics = draw_mc.graphics;
		_g.clear();
		_g.lineStyle( 0, 0xff0000, 100, true, "none", "round", "round", 1 );                
		var _prevPoint:Point = null;
		var _dotLength:int = dotarr.length;     
		
		if ( _dotLength <= 0 ) return;
		
		for ( var i:int = 1; i < _dotLength; ++i )
		{        
			var _prevObj:Object = dotarr[i - 1];                                    
			var _currentObj:Object = dotarr[i];
			_g.lineStyle( i / 1.2  , 0xffffff, 1, true, "none", "round", "round", 1 );                
			var _point:Point = new Point( _prevObj.x + ( _currentObj.x - _prevObj.x ) / 2, _prevObj.y + ( _currentObj.y - _prevObj.y ) / 2 );                
			
			if ( _prevPoint )
			{
				_g.moveTo( _prevPoint.x,_prevPoint.y );
				_g.curveTo( _prevObj.x,_prevObj.y,_point.x,_point.y );
			} else {
				_g.moveTo( _prevObj.x,_prevObj.y );
				_g.lineTo( _point.x,_point.y );
			}
			_prevPoint = _point;
		}
		if ( _currentObj )
		{
			_g.lineTo( _currentObj.x, _currentObj.y );
		}
	}
}

// Copyright © 2007. Adobe Systems Incorporated. All Rights Reserved.
import flash.geom.*;

/**
 * The MatrixTransformer class contains methods for modifying individual properties of a transformation matrix:
 * horizontal and vertical scale, horizontal and vertical skew, and rotation.
 * This class also has methods for rotating around a given transformation point rather than the typical (0, 0) point.
 * @playerversion Flash 9.0.28.0
 * @langversion 3.0
 * @keyword MatrixTransformer, Copy Motion as ActionScript    
 * @see ../../motionXSD.html Motion XML Elements   
 * @see flash.geom
 */
class MatrixTransformer
{	
    /**
     * Calculates the horizontal scale present in a matrix.
     *
     * @param m A Matrix instance.
     *
     * @return The horizontal scale.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix
     */
	public static function getScaleX(m:Matrix):Number
	{
		return Math.sqrt(m.a*m.a + m.b*m.b);
	}



    /**
     * Changes the horizontal scale in a matrix.
     *
     * @param m A Matrix instance to be modified.
     *
     * @param scaleX The new horizontal scale.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix   
     */
	public static function setScaleX(m:Matrix, scaleX:Number):void
	{
		var oldValue:Number = getScaleX(m);
		// avoid division by zero 
		if (oldValue)
		{
			var ratio:Number = scaleX / oldValue;
			m.a *= ratio;
			m.b *= ratio;
		}
		else
		{
			var skewYRad:Number = getSkewYRadians(m);
			m.a = Math.cos(skewYRad) * scaleX;
			m.b = Math.sin(skewYRad) * scaleX;
		}
	}



    /**
     * Calculates the vertical scale present in a matrix.
     *
     * @param m A Matrix instance.
     *
     * @return The vertical scale.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix        
     */
   	public static function getScaleY(m:Matrix):Number
	{
		return Math.sqrt(m.c*m.c + m.d*m.d);
	}



    /**
     * Changes the vertical scale in a matrix.
     *
     * @param m A Matrix instance to be modified.
     *
     * @param scaleY The new vertical scale.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix       
     */
	public static function setScaleY(m:Matrix, scaleY:Number):void
	{
		var oldValue:Number = getScaleY(m);
		// avoid division by zero 
		if (oldValue)
		{
			var ratio:Number = scaleY / oldValue;
			m.c *= ratio;
			m.d *= ratio;
		}
		else
		{
			var skewXRad:Number = getSkewXRadians(m);
			m.c = -Math.sin(skewXRad) * scaleY;
			m.d =  Math.cos(skewXRad) * scaleY;
		}
	}



    /**
     * Calculates the angle of horizontal skew present in a matrix, in radians.
     *
     * @param m A Matrix instance.
     *
     * @return The angle of horizontal skew, in radians.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix       
     */
	public static function getSkewXRadians(m:Matrix):Number
	{
		return Math.atan2(-m.c, m.d);
	}



    /**
     * Changes the horizontal skew in a matrix.
     *
     * @param m A Matrix instance to be modified.
     *
     * @param skewX The new horizontal skew, in radians.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix       
     */
	public static function setSkewXRadians(m:Matrix, skewX:Number):void
	{
		var scaleY:Number = getScaleY(m);
		m.c = -scaleY * Math.sin(skewX);
		m.d =  scaleY * Math.cos(skewX);
	}



    /**
     * Calculates the angle of vertical skew present in a matrix, in radians.
     *
     * @param m A Matrix instance.
     *
     * @return The angle of vertical skew, in radians.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix       
     */
	public static function getSkewYRadians(m:Matrix):Number
	{
		return Math.atan2(m.b, m.a);
	} 


    /**
     * Changes the vertical skew in a matrix.
     *
     * @param m A Matrix instance to be modified.
     *
     * @param skewY The new vertical skew, in radians.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
	public static function setSkewYRadians(m:Matrix, skewY:Number):void
	{
		var scaleX:Number = getScaleX(m);
		m.a = scaleX * Math.cos(skewY);
		m.b = scaleX * Math.sin(skewY);
	}



    /**
     * Calculates the angle of horizontal skew present in a matrix, in degrees.
     *
     * @param m A Matrix instance.
     *
     * @return The angle of horizontal skew, in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
	public static function getSkewX(m:Matrix):Number
	{
		return Math.atan2(-m.c, m.d) * (180/Math.PI);
	}



    /**
     * Changes the horizontal skew in a matrix.
     *
     * @param m A Matrix instance to be modified.
     *
     * @param skewX The new horizontal skew, in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
   	public static function setSkewX(m:Matrix, skewX:Number):void
	{
		setSkewXRadians(m, skewX*(Math.PI/180));
	}



    /**
     * Calculates the angle of vertical skew present in a matrix, in degrees.
     *
     * @param m A Matrix instance.
     *
     * @return The angle of vertical skew, in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
	public static function getSkewY(m:Matrix):Number
	{
		return Math.atan2(m.b, m.a) * (180/Math.PI);
	}



    /**
     * Changes the vertical skew in a matrix.
     *
     * @param m A Matrix instance to be modified.
     *
     * @param skewX The new vertical skew, in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
	public static function setSkewY(m:Matrix, skewY:Number):void
	{
		setSkewYRadians(m, skewY*(Math.PI/180));
	}	



    /**
     * Calculates the angle of rotation present in a matrix, in radians.
     * If the horizontal and vertical skews are not equal, 
     * the vertical skew value is used.
     *
     * @param m A Matrix instance.
     *
     * @return The angle of rotation, in radians.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
   	public static function getRotationRadians(m:Matrix):Number
	{
		return getSkewYRadians(m);
	}


    /**
     * Changes the angle of rotation in a matrix.
     * If the horizontal and vertical skews are not equal,
     * the vertical skew is set to the rotation value
     * and the horizontal skew is increased by the difference between the 
     * old rotation and the new rotation.
     * This matches the rotation behavior in Flash Player.
     *
     * @param m A Matrix instance.
     *
     * @param rotation The angle of rotation, in radians.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix           
     */
	public static function setRotationRadians(m:Matrix, rotation:Number):void
	{
		var oldRotation:Number = getRotationRadians(m);
		var oldSkewX:Number = getSkewXRadians(m);
		setSkewXRadians(m, oldSkewX + rotation-oldRotation);
		setSkewYRadians(m, rotation);		
	}



    /**
     * Calculates the angle of rotation present in a matrix, in degrees.
     * If the horizontal and vertical skews are not equal, 
     * the vertical skew value is used.
     * This matches the rotation behavior in Flash Player.
     *
     * @param m A Matrix instance.
     *
     * @return The angle of rotation, in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix         
     */
	public static function getRotation(m:Matrix):Number
	{
		return getRotationRadians(m)*(180/Math.PI);
	}



    /**
     * Changes the angle of rotation in a matrix.
     * If the horizontal and vertical skews are not equal,
     * the vertical skew is set to the rotation value
     * and the horizontal skew is increased by the difference between the 
     * old rotation and the new rotation.
     * This matches the rotation behavior in Flash Player.
     *
     * @param m A Matrix instance.
     *
     * @param rotation The angle of rotation, in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix         
     */
	public static function setRotation(m:Matrix, rotation:Number):void
	{
		setRotationRadians(m, rotation*(Math.PI/180));
	}



    /**
     * Rotates a matrix about a point defined inside the matrix's transformation space.
     * This can be used to rotate a movie clip around a transformation point inside itself. 
     *
     * @param m A Matrix instance.
     *
     * @param x The x coordinate of the point.
     *
     * @param y The y coordinate of the point.
     *
     * @param angleDegrees The angle of rotation in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix         
     */
	public static function rotateAroundInternalPoint(m:Matrix, x:Number, y:Number, angleDegrees:Number):void
	{
		var point:Point = new Point(x, y);
		point = m.transformPoint(point);
		m.tx -= point.x;
		m.ty -= point.y;
		m.rotate(angleDegrees*(Math.PI/180));
		m.tx += point.x;
		m.ty += point.y;
	}



    /**
     * Rotates a matrix about a point defined outside the matrix's transformation space.
     * This can be used to rotate a movie clip around a transformation point in its parent. 
     *
     * @param m A Matrix instance.
     *
     * @param x The x coordinate of the point.
     *
     * @param y The y coordinate of the point.
     *
     * @param angleDegrees The angle of rotation in degrees.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix       
     */
	public static function rotateAroundExternalPoint(m:Matrix, x:Number, y:Number, angleDegrees:Number):void
	{
		m.tx -= x;
		m.ty -= y;
		m.rotate(angleDegrees*(Math.PI/180));
		m.tx += x;
		m.ty += y;
	}


    /**
     * Moves a matrix as necessary to align an internal point with an external point.
     * This can be used to match a point in a transformed movie clip with one in its parent.
     *
     * @param m A Matrix instance.
     *
     * @param internalPoint A Point instance defining a position within the matrix's transformation space.
     *
     * @param externalPoint A Point instance defining a reference position outside the matrix's transformation space.
     * @playerversion Flash 9.0.28.0
     * @langversion 3.0
     * @keyword Matrix, Copy Motion as ActionScript    
     * @see flash.geom.Matrix       
     */	
    public static function matchInternalPointWithExternal(m:Matrix, internalPoint:Point, externalPoint:Point):void
	{
		var internalPointTransformed:Point = m.transformPoint(internalPoint);
		var dx:Number = externalPoint.x - internalPointTransformed.x;
		var dy:Number = externalPoint.y - internalPointTransformed.y;	
		m.tx += dx;
		m.ty += dy;
	}
}