flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aha...@apache.org
Subject [30/51] [abbrv] git commit: [flex-asjs] [refs/heads/mavenfolders] - new folders for Graphics
Date Wed, 03 Feb 2016 17:41:33 GMT
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/46eaea76/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/CompoundTransform.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/CompoundTransform.as b/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/CompoundTransform.as
new file mode 100644
index 0000000..7b1916b
--- /dev/null
+++ b/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/CompoundTransform.as
@@ -0,0 +1,777 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flex.core.graphics.utils
+{
+	import flash.geom.Matrix;
+	import flash.geom.Matrix3D;
+	import flash.geom.Vector3D;
+	
+	import __AS3__.vec.Vector;
+	
+	/**
+	 *  A CompoundTransform represents a 2D or 3D matrix transform.  A compound transform represents a matrix that can be queried or set either as a 2D matrix,
+	 *  a 3D matrix, or as individual convenience transform properties such as x, y, scaleX, rotationZ, etc. 
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 9
+	 *  @playerversion AIR 1.1
+	 *  @productversion Flex 3
+	 */
+	public class CompoundTransform
+	{
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function CompoundTransform()
+		{
+		}
+		
+		
+		
+		/**
+		 * @private
+		 * storage for transform properties. These values are concatenated together with the layout properties to
+		 * form the actual computed matrix used to render the object.
+		 */
+		private var _rotationX:Number = 0;
+		private var _rotationY:Number = 0;
+		private var _rotationZ:Number = 0;
+		private var _scaleX:Number = 1;
+		private var _scaleY:Number = 1;
+		private var _scaleZ:Number = 1;     
+		private var _x:Number = 0;
+		private var _y:Number = 0;
+		private var _z:Number = 0;
+		
+		private var _transformX:Number = 0;
+		private var _transformY:Number = 0;
+		private var _transformZ:Number = 0;
+		
+		
+		/**
+		 * @private
+		 * slots for the 2D and 3D matrix transforms.  Note that 
+		 * these are only allocated and computed on demand -- many component instances will never use a 3D
+		 * matrix, for example. 
+		 */
+		private var _matrix:Matrix;
+		private var _matrix3D:Matrix3D;
+		
+		
+		/**
+		 * @private
+		 * bit field flags for indicating which transforms are valid -- the layout properties, the matrices,
+		 * and the 3D matrices.  Since developers can set any of the three programmatically, the last one set
+		 * will always be valid, and the others will be invalid until validated on demand.
+		 */
+		private static const MATRIX_VALID:uint      = 0x20;
+		private static const MATRIX3D_VALID:uint        = 0x40;
+		private static const PROPERTIES_VALID:uint  = 0x80;
+		
+		
+		/**
+		 * @private
+		 * flags for tracking whether the  transform is 3D. A transform is 3D if any of the 3D properties -- rotationX/Y, scaleZ, or z -- are set.
+		 */
+		private static const IS_3D:uint                 = 0x200;
+		private static const M3D_FLAGS_VALID:uint           = 0x400;
+		
+		/**
+		 * @private
+		 * constants to indicate which form of a transform -- the properties, matrix, or matrix3D -- is
+		 *  'the source of truth.'   
+		 */
+		public static const SOURCE_PROPERTIES:uint          = 1;
+		/**
+		 * @private
+		 * constants to indicate which form of a transform -- the properties, matrix, or matrix3D -- is
+		 *  'the source of truth.'   
+		 */
+		public static const SOURCE_MATRIX:uint          = 2;
+		/**
+		 * @private
+		 * constants to indicate which form of a transform -- the properties, matrix, or matrix3D -- is
+		 *  'the source of truth.'   
+		 */
+		public static const SOURCE_MATRIX3D:uint            = 3;
+		
+		/**
+		 * @private
+		 * indicates the 'source of truth' for the transform.  
+		 */
+		public var sourceOfTruth:uint = SOURCE_PROPERTIES;
+		
+		/**
+		 * @private
+		 * general storage for all of ur flags.  
+		 */
+		private var _flags:uint =  PROPERTIES_VALID;
+		
+		/**
+		 * @private
+		 * flags that get passed to the invalidate method indicating why the invalidation is happening.
+		 */
+		private static const INVALIDATE_FROM_NONE:uint =            0;                      
+		private static const INVALIDATE_FROM_PROPERTY:uint =        4;                      
+		private static const INVALIDATE_FROM_MATRIX:uint =          5;                      
+		private static const INVALIDATE_FROM_MATRIX3D:uint =        6;                      
+		
+		/**
+		 * @private
+		 * static data used by utility methods below
+		 */
+		private static var decomposition:Vector.<Number> = new Vector.<Number>();
+		decomposition.push(0);
+		decomposition.push(0);
+		decomposition.push(0);
+		decomposition.push(0);
+		decomposition.push(0);
+		
+		private static const RADIANS_PER_DEGREES:Number = Math.PI / 180;
+		
+		//----------------------------------------------------------------------------
+		
+		/**
+		 *  The x value of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set x(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _x)
+				return;
+			translateBy(value-_x,0,0);
+			invalidate(INVALIDATE_FROM_PROPERTY, false /*affects3D*/);
+		}
+		/**
+		 * @private
+		 */
+		public function get x():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _x;
+		}
+		
+		/**
+		 *  The y value of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set y(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _y)
+				return;
+			translateBy(0,value-_y,0);
+			invalidate(INVALIDATE_FROM_PROPERTY, false /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get y():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _y;
+		}
+		
+		/**
+		 *  The z value of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set z(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _z)
+				return;
+			translateBy(0,0,value-_z);
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get z():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _z;
+		}
+		
+		//------------------------------------------------------------------------------
+		
+		
+		/**
+		 *  The rotationX, in degrees, of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set rotationX(value:Number):void
+		{
+			// clamp the rotation value between -180 and 180.  This is what 
+			// the Flash player does, so let's mimic it here too.
+			value = MatrixUtil.clampRotation(value);
+			
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _rotationX)
+				return;
+			_rotationX = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get rotationX():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _rotationX;
+		}
+		
+		/**
+		 *  The rotationY, in degrees, of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set rotationY(value:Number):void
+		{
+			// clamp the rotation value between -180 and 180.  This is what 
+			// the Flash player does, so let's mimic it here too.
+			value = MatrixUtil.clampRotation(value);
+			
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _rotationY)
+				return;
+			_rotationY = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get rotationY():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _rotationY;
+		}
+		
+		/**
+		 *  The rotationZ, in degrees, of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set rotationZ(value:Number):void
+		{
+			// clamp the rotation value between -180 and 180.  This is what 
+			// the Flash player does, so let's mimic it here too.
+			value = MatrixUtil.clampRotation(value);
+			
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _rotationZ)
+				return;
+			_rotationZ = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, false /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get rotationZ():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _rotationZ;
+		}
+		
+		//------------------------------------------------------------------------------
+		
+		
+		/**
+		 *  The scaleX of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set scaleX(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _scaleX)
+				return;
+			_scaleX = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, false /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get scaleX():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _scaleX;
+		}
+		
+		/**
+		 *  The scaleY of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set scaleY(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _scaleY)
+				return;
+			_scaleY = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, false /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get scaleY():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _scaleY;
+		}
+		
+		
+		/**
+		 *  The scaleZ of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set scaleZ(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _scaleZ)
+				return;
+			_scaleZ = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get scaleZ():Number
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			return _scaleZ;
+		}
+		
+		
+		/**
+		 * @private
+		 * returns true if the transform has 3D values.
+		 */
+		public function get is3D():Boolean
+		{
+			if ((_flags & M3D_FLAGS_VALID) == 0)
+				update3DFlags();
+			return ((_flags & IS_3D) != 0);
+		}
+		
+		//------------------------------------------------------------------------------
+		/**
+		 *  The x value of the transform center. The transform center is kept fixed as rotation and scale are applied. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set transformX(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _transformX)
+				return;
+			_transformX = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get transformX():Number
+		{
+			return _transformX;
+		}
+		
+		//------------------------------------------------------------------------------
+		/**
+		 *  The y value of the tansform center. The transform center is kept fixed as rotation and scale are applied. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set transformY(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _transformY)
+				return;
+			_transformY = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get transformY():Number
+		{
+			return _transformY;
+		}
+		//------------------------------------------------------------------------------
+		/**
+		 *  The z value of the tansform center. The transform center is kept fixed as rotation and scale are applied. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function set transformZ(value:Number):void
+		{
+			if ((_flags & PROPERTIES_VALID) == false) validatePropertiesFromMatrix();
+			if (value == _transformZ)
+				return;
+			_transformZ = value;
+			invalidate(INVALIDATE_FROM_PROPERTY, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 */
+		public function get transformZ():Number
+		{
+			return _transformZ;
+		}
+		
+		//------------------------------------------------------------------------------
+		
+		/**
+		 * @private
+		 * invalidates our various cached values.  Any change to the CompoundTransform object that affects
+		 * the various transforms should call this function. 
+		 * @param reason - the code indicating what changes to cause the invalidation.
+		 * @param affects3D - a flag indicating whether the change affects the 2D/3D nature of the various transforms.
+		 * @param dispatchChangeEvent - if true, the CompoundTransform will dispatch a change indicating that its underlying transforms
+		 * have been modified. 
+		 */
+		private function invalidate(reason:uint, affects3D:Boolean):void
+		{
+			//race("invalidating: " + reason);
+			switch(reason)
+			{
+				case INVALIDATE_FROM_PROPERTY:
+					sourceOfTruth = SOURCE_PROPERTIES;
+					_flags |= PROPERTIES_VALID;
+					_flags &= ~MATRIX_VALID;
+					_flags &= ~MATRIX3D_VALID;
+					break;
+				case INVALIDATE_FROM_MATRIX:
+					sourceOfTruth = SOURCE_MATRIX;
+					_flags |= MATRIX_VALID;
+					_flags &= ~PROPERTIES_VALID;
+					_flags &= ~MATRIX3D_VALID;
+					break;
+				case INVALIDATE_FROM_MATRIX3D:
+					sourceOfTruth = SOURCE_MATRIX3D;
+					_flags |= MATRIX3D_VALID;
+					_flags &= ~PROPERTIES_VALID;
+					_flags &= ~MATRIX_VALID;
+					break;
+			}                       
+			if (affects3D)
+				_flags &= ~M3D_FLAGS_VALID;
+			
+		}
+		
+		private static const EPSILON:Number = .001;
+		/**
+		 * @private
+		 * updates the flags that indicate whether the layout, offset, and/or computed transforms are 3D in nature.  
+		 * Since the user can set either the individual transform properties or the matrices directly, we compute these 
+		 * flags based on what the current 'source of truth' is for each of these values.
+		 */
+		private function update3DFlags():void
+		{           
+			if ((_flags & M3D_FLAGS_VALID) == 0)
+			{
+				var matrixIs3D:Boolean = false;
+				
+				switch(sourceOfTruth)
+				{
+					case SOURCE_PROPERTIES:
+						matrixIs3D = ( // note that rotationZ is the same as rotation, and not a 3D affecting                           
+							(Math.abs(_scaleZ-1) > EPSILON) ||  // property.
+							((Math.abs(_rotationX)+EPSILON)%360) > 2*EPSILON ||
+							((Math.abs(_rotationY)+EPSILON)%360) > 2*EPSILON ||
+							Math.abs(_z) > EPSILON
+						);
+						break;
+					case SOURCE_MATRIX:
+						matrixIs3D = false;
+						break;
+					case SOURCE_MATRIX3D:
+						var rawData:Vector.<Number> = _matrix3D.rawData;                    
+						matrixIs3D = (rawData[2] != 0 ||        // rotation y 
+							rawData[6] != 0 ||      // rotation x
+							rawData[8] !=0 ||       // rotation y
+							rawData[10] != 1 ||     // scalez / rotation x / rotation y
+							rawData[14] != 0);      // translation z
+						break;                              
+				}
+				
+				if (matrixIs3D)
+					_flags |= IS_3D;
+				else
+					_flags &= ~IS_3D;
+				
+				_flags |= M3D_FLAGS_VALID;
+			}
+		}
+		
+		
+		/** 
+		 *  Applies the delta to the transform's translation component. Unlike setting the x, y, or z properties directly,
+		 *  this method can be safely called without changing the transform's concept of 'the source of truth'.
+		 * 
+		 *  @param x The x value of the transform.
+		 *  
+		 *  @param y The y value of the transform.
+		 *  
+		 *  @param z The z value of the transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function translateBy(x:Number,y:Number,z:Number = 0):void
+		{
+			if (_flags & MATRIX_VALID)
+			{
+				_matrix.tx += x;
+				_matrix.ty += y;
+			}
+			if (_flags & PROPERTIES_VALID)
+			{
+				_x += x;
+				_y += y;
+				_z += z;
+			}
+			if (_flags & MATRIX3D_VALID)
+			{
+				var data:Vector.<Number> = _matrix3D.rawData;
+				data[12] += x;
+				data[13] += y;
+				data[14] += z;
+				_matrix3D.rawData = data;           
+			}   
+			invalidate(INVALIDATE_FROM_NONE, z != 0 /*affects3D*/);
+		}
+		
+		
+		/**
+		 *  The 2D matrix either set directly by the user, or composed by combining the transform center, scale, rotation
+		 *  and translation, in that order.  
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function get matrix():Matrix
+		{
+			
+			if (_flags & MATRIX_VALID)
+				return _matrix;
+			
+			if ((_flags & PROPERTIES_VALID) == false)
+				validatePropertiesFromMatrix();
+			
+			var m:Matrix = _matrix;
+			if (m == null)
+				m = _matrix = new Matrix();
+			else
+				m.identity();
+			
+			AdvancedLayoutFeatures.build2DMatrix(m,_transformX,_transformY,
+				_scaleX,_scaleY,
+				_rotationZ,
+				_x,_y);   
+			_flags |= MATRIX_VALID;
+			return m;       
+		}
+		
+		/**
+		 * @private
+		 */ 
+		public function set matrix(v:Matrix):void
+		{
+			if (_matrix== null)
+			{
+				_matrix = v.clone();
+			}
+			else
+			{
+				_matrix.identity(); 
+				_matrix.concat(v);          
+			}
+			
+			// affects3D is true since setting matrix changes the transform to 2D
+			invalidate(INVALIDATE_FROM_MATRIX, true /*affects3D*/);
+		}
+		
+		/**
+		 * @private
+		 * decomposes the offset transform matrices down into the convenience offset properties. Note that this is not
+		 * a bi-directional transformation -- it is possible to create a matrix that can't be fully represented in the
+		 * convenience properties. This function will pull from the matrix or matrix3D values, depending on which was most
+		 * recently set
+		 */
+		private function validatePropertiesFromMatrix():void
+		{       
+			if (sourceOfTruth == SOURCE_MATRIX3D)
+			{
+				var result:Vector.<Vector3D> = _matrix3D.decompose();
+				_rotationX = result[1].x / RADIANS_PER_DEGREES;
+				_rotationY = result[1].y / RADIANS_PER_DEGREES;
+				_rotationZ = result[1].z / RADIANS_PER_DEGREES;
+				_scaleX = result[2].x;
+				_scaleY = result[2].y;
+				_scaleZ = result[2].z;
+				
+				if (_transformX != 0 || _transformY != 0 || _transformZ != 0)
+				{
+					var postTransformTCenter:Vector3D = _matrix3D.transformVector(new Vector3D(_transformX,_transformY,_transformZ));
+					_x = postTransformTCenter.x - _transformX;
+					_y = postTransformTCenter.y - _transformY;
+					_z = postTransformTCenter.z - _transformZ;
+				}
+				else
+				{
+					_x = result[0].x;
+					_y = result[0].y;
+					_z = result[0].z;
+				}
+			}                        
+			else if (sourceOfTruth == SOURCE_MATRIX)
+			{
+				MatrixUtil.decomposeMatrix(decomposition,_matrix,_transformX,_transformY);
+				_x = decomposition[0];
+				_y = decomposition[1];
+				_z = 0;
+				_rotationX = 0;
+				_rotationY = 0;
+				_rotationZ = decomposition[2];
+				_scaleX = decomposition[3];
+				_scaleY = decomposition[4];
+				_scaleZ = 1;
+			}
+			_flags |= PROPERTIES_VALID;
+			
+		}
+		
+		
+		
+		/**
+		 *  The 3D matrix either set directly by the user, or composed by combining the transform center, scale, rotation
+		 *  and translation, in that order. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public function get matrix3D():Matrix3D
+		{
+			if (_flags & MATRIX3D_VALID)
+				return _matrix3D;
+			
+			if ((_flags & PROPERTIES_VALID) == false)
+				validatePropertiesFromMatrix();
+			
+			var m:Matrix3D = _matrix3D;
+			if (m == null)
+				m =  _matrix3D = new Matrix3D();
+			else
+				m.identity();
+			
+			AdvancedLayoutFeatures.build3DMatrix(m,transformX,transformY,transformZ,
+				_scaleX,_scaleY,_scaleZ,
+				_rotationX,_rotationY,_rotationZ,                       
+				_x,_y,_z);
+			_flags |= MATRIX3D_VALID;
+			return m;
+			
+		}
+		
+		/**
+		 * @private
+		 */
+		public function set matrix3D(v:Matrix3D):void
+		{
+			if (_matrix3D == null)
+			{
+				_matrix3D = v.clone();
+			}
+			else
+			{
+				_matrix3D.identity();
+				if (v)
+					_matrix3D.append(v);            
+			}
+			invalidate(INVALIDATE_FROM_MATRIX3D, true /*affects3D*/);
+		}
+		
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/46eaea76/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/IAssetLayoutFeatures.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/IAssetLayoutFeatures.as b/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/IAssetLayoutFeatures.as
new file mode 100644
index 0000000..1e36b60
--- /dev/null
+++ b/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/IAssetLayoutFeatures.as
@@ -0,0 +1,371 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flex.core.graphics.utils
+{
+	import flash.geom.Matrix;
+	import flash.geom.Matrix3D;
+	
+	
+	/**
+	 *  The IAssetLayoutFeatures interface defines the minimum properties and methods 
+	 *  required for an Object to support advanced transforms in embedded assets.
+	 *  
+	 *  @see mx.core.AdvancedLayoutFeatures
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4.1
+	 */
+	public interface IAssetLayoutFeatures
+	{
+		
+		/**
+		 *  Layout transform convenience property.  Represents the x value of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutX(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutX():Number;
+		
+		/**
+		 *  Layout transform convenience property.  Represents the y value of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutY(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutY():Number;
+		
+		/**
+		 *  Layout transform convenience property.  Represents the z value of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutZ(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutZ():Number;
+		
+		/**
+		 *  Used by the mirroring transform. See the mirror property.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get layoutWidth():Number;
+		
+		/**
+		 *  @private
+		 */
+		function set layoutWidth(value:Number):void;
+		
+		//------------------------------------------------------------------------------
+		
+		/**
+		 *  The x value of the point around which any rotation and scale is performed in both the layout and computed matrix.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set transformX(value:Number):void;
+		/**
+		 * @private
+		 */
+		function get transformX():Number;
+		
+		/**
+		 *  The y value of the point around which any rotation and scale is performed in both the layout and computed matrix.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set transformY(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get transformY():Number;
+		
+		/**
+		 *  The z value of the point around which any rotation and scale is performed in both the layout and computed matrix.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set transformZ(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get transformZ():Number;
+		
+		//------------------------------------------------------------------------------
+		
+		/**
+		 *  Layout transform convenience property.  Represents the rotation around the X axis of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutRotationX(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutRotationX():Number;
+		
+		/**
+		 *  Layout transform convenience property.  Represents the rotation around the Y axis of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutRotationY(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutRotationY():Number;
+		
+		/**
+		 *  Layout transform convenience property.  Represents the rotation around the Z axis of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutRotationZ(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutRotationZ():Number;
+		
+		//------------------------------------------------------------------------------
+		
+		/**
+		 *  Layout transform convenience property.  Represents the scale along the X axis of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutScaleX(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutScaleX():Number;
+		
+		/**
+		 *  Layout transform convenience property.  Represents the scale along the Y axis of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutScaleY(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutScaleY():Number;
+		
+		/**
+		 *  Layout transform convenience property.  Represents the scale along the Z axis of the layout matrix used in layout and in 
+		 *  the computed transform.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutScaleZ(value:Number):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutScaleZ():Number;
+		
+		/**
+		 *  The 2D matrix used during layout calculations to determine the layout and size of the component and its parent and siblings.
+		 *  
+		 *   @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutMatrix(value:Matrix):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutMatrix():Matrix;
+		
+		/**
+		 *  The 3D matrix used during layout calculations to determine the layout and size of the component and its parent and siblings.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function set layoutMatrix3D(value:Matrix3D):void;
+		
+		/**
+		 * @private
+		 */
+		function get layoutMatrix3D():Matrix3D;
+		
+		/**
+		 *  True if the computed transform has 3D values.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get is3D():Boolean;
+		
+		/**
+		 *  True if the layout transform has 3D values.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get layoutIs3D():Boolean;
+		
+		/**
+		 *  If true the X axis is scaled by -1 and the x coordinate of the origin
+		 *  is translated by the component's width.  
+		 * 
+		 *  The net effect of this "mirror" transform is to flip the direction 
+		 *  that the X axis increases in without changing the layout element's 
+		 *  location relative to the parent's origin.
+		 * 
+		 *  @default false
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get mirror():Boolean;
+		
+		/**
+		 *  @private
+		 */
+		function set mirror(value:Boolean):void;
+		
+		
+		/**
+		 *  The stretchY is the horizontal component of the stretch scale factor which
+		 *  is applied before any other transformation property.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get stretchX():Number;
+		
+		/**
+		 *  @private
+		 */
+		function set stretchX(value:Number):void;
+		
+		/**
+		 *  The stretchY is the vertical component of the stretch scale factor which
+		 *  is applied before any other transformation property.
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get stretchY():Number;
+		
+		/**
+		 *  @private
+		 */
+		function set stretchY(value:Number):void;
+		
+		//------------------------------------------------------------------------------
+		
+		/**
+		 *  The computed matrix, calculated by combining the layout matrix and any offsets provided.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get computedMatrix():Matrix;
+		
+		/**
+		 *  The computed 3D matrix, calculated by combining the 3D layout matrix and any offsets provided.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4.1
+		 */
+		function get computedMatrix3D():Matrix3D;
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/46eaea76/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/MatrixUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/MatrixUtil.as b/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/MatrixUtil.as
new file mode 100644
index 0000000..04c2c13
--- /dev/null
+++ b/frameworks/projects/Graphics/src/main/flex/org/apache/flex/core/graphics/utils/MatrixUtil.as
@@ -0,0 +1,1605 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package org.apache.flex.core.graphics.utils
+{
+	
+	import flash.display.DisplayObject;
+	import flash.geom.Matrix;
+	import flash.geom.Matrix3D;
+	import flash.geom.PerspectiveProjection;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	import flash.geom.Utils3D;
+	import flash.geom.Vector3D;
+	import flash.system.ApplicationDomain;
+	
+	/**
+	 *  @private
+	 *  The MatrixUtil class is for internal use only.
+	 *  Class for matrix and geometric related math routines.
+	 */
+	public final class MatrixUtil
+	{
+		
+		private static const RADIANS_PER_DEGREES:Number = Math.PI / 180;
+		private static var SOLUTION_TOLERANCE:Number = 0.1;
+		private static var MIN_MAX_TOLERANCE:Number = 0.1;
+		
+		private static var staticPoint:Point = new Point();
+		
+		// For use in getConcatenatedMatrix function
+		private static var fakeDollarParent:QName;
+		private static var uiComponentClass:Class;
+		private static var uiMovieClipClass:Class;
+		private static var usesMarshalling:Object;
+		private static var lastModuleFactory:Object;
+		private static var computedMatrixProperty:QName;
+		private static var $transformProperty:QName;
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Class methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Returns rotation value clamped between -180 and 180 degreeds.
+		 *  This mimicks the Flash player behavior. 
+		 */
+		public static function clampRotation(value:Number):Number
+		{
+			// Flash player doesn't handle values larger than 2^15 - 1 (FP-749).
+			if (value > 180 || value < -180)
+			{
+				value = value % 360;
+				
+				if (value > 180)
+					value = value - 360;
+				else if (value < -180)
+					value = value + 360;
+			}
+			return value;
+		}
+		
+		/**
+		 *  Returns a static Point object with the result.
+		 *  If matrix is null, point is untransformed. 
+		 */
+		public static function transformPoint(x:Number, y:Number, m:Matrix):Point
+		{
+			if (!m)
+			{
+				staticPoint.x = x;
+				staticPoint.y = y;
+				return staticPoint;
+			}
+			
+			staticPoint.x = m.a * x + m.c * y + m.tx;
+			staticPoint.y = m.b * x + m.d * y + m.ty;
+			return staticPoint;
+		}
+		
+		public static function composeMatrix(x:Number = 0,
+											 y:Number = 0,
+											 scaleX:Number = 1,
+											 scaleY:Number = 1,
+											 rotation:Number = 0,
+											 transformX:Number = 0,
+											 transformY:Number = 0):Matrix
+		{
+			var m:Matrix = new Matrix();
+			m.translate(-transformX, -transformY);
+			m.scale(scaleX, scaleY);
+			if (rotation != 0) 
+				m.rotate(rotation / 180 * Math.PI);
+			m.translate(transformX + x, transformY + y);
+			return m;
+		}
+		
+		/**
+		 *  Decompose a matrix into its component scale, rotation, and translation parts.
+		 *  The Vector of Numbers passed in the components parameter will be 
+		 *  populated by this function with the component parts. 
+		 * 
+		 *  @param components Vector which holds the component scale, rotation 
+		 *  and translation values.
+		 *  x = components[0]
+		 *  y = components[1]
+		 *  rotation = components[2]
+		 *  scaleX = components[3]
+		 *  scaleY = components[4]
+		 * 
+		 *  @param matrix The matrix to decompose
+		 *  @param transformX The x value of the transform center
+		 *  @param transformY The y value of the transform center
+		 */	
+		public static function decomposeMatrix(components:Vector.<Number>,
+											   matrix:Matrix,
+											   transformX:Number = 0,
+											   transformY:Number = 0):void
+		{
+			// else decompose matrix.  Don't use MatrixDecompose(), it can return erronous values
+			//   when negative scales (and therefore skews) are in use.
+			var Ux:Number;
+			var Uy:Number;
+			var Vx:Number;
+			var Vy:Number;
+			
+			Ux = matrix.a;
+			Uy = matrix.b;
+			components[3] = Math.sqrt(Ux*Ux + Uy*Uy);
+			
+			Vx = matrix.c;
+			Vy = matrix.d;
+			components[4] = Math.sqrt(Vx*Vx + Vy*Vy );
+			
+			// sign of the matrix determinant will tell us if the space is inverted by a 180 degree skew or not.
+			var determinant:Number = Ux*Vy - Uy*Vx;
+			if (determinant < 0) // if so, choose y-axis scale as the skewed one.  Unfortunately, its impossible to tell if it originally was the y or x axis that had the negative scale/skew.
+			{
+				components[4] = -(components[4]);
+				Vx = -Vx;
+				Vy = -Vy;
+			}
+			
+			components[2] = Math.atan2( Uy, Ux ) / RADIANS_PER_DEGREES;
+			
+			if (transformX != 0 || transformY != 0)     
+			{
+				var postTransformCenter:Point = matrix.transformPoint(new Point(transformX,transformY));
+				components[0] = postTransformCenter.x - transformX;
+				components[1] = postTransformCenter.y - transformY;
+			}
+			else
+			{
+				components[0] = matrix.tx;
+				components[1] = matrix.ty;
+			}
+		}
+		
+		/**
+		 *  @return Returns the union of <code>rect</code> and
+		 *  <code>Rectangle(left, top, right - left, bottom - top)</code>.
+		 *  Note that if rect is non-null, it will be updated to reflect the return value.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function rectUnion(left:Number, top:Number, right:Number, bottom:Number,
+										 rect:Rectangle):Rectangle
+		{
+			if (!rect)
+				return new Rectangle(left, top, right - left, bottom - top);
+			
+			var minX:Number = Math.min(rect.left,   left);
+			var minY:Number = Math.min(rect.top,    top);
+			var maxX:Number = Math.max(rect.right,  right);
+			var maxY:Number = Math.max(rect.bottom, bottom);
+			
+			rect.x      = minX;
+			rect.y      = minY;
+			rect.width  = maxX - minX;
+			rect.height = maxY - minY;
+			return rect;
+		}
+		
+		/**
+		 *  Calculates the bounding box of a post-transformed ellipse.
+		 *   
+		 *  @param cx The x coordinate of the ellipse's center
+		 *  @param cy The y coordinate of the ellipse's center
+		 *  @param rx The horizontal radius of the ellipse
+		 *  @param ry The vertical radius of the ellipse
+		 *  @param matrix The transformation matrix.
+		 *  @param rect If non-null, rect will be updated to the union of rect and
+		 *  the segment bounding box.
+		 *  @return Returns the union of the passed in rect with the
+		 *  bounding box of the the post-transformed ellipse.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */ 
+		public static function getEllipseBoundingBox(cx:Number, cy:Number,
+													 rx:Number, ry:Number,
+													 matrix:Matrix,
+													 rect:Rectangle = null):Rectangle
+		{
+			var a:Number = matrix.a;
+			var b:Number = matrix.b;
+			var c:Number = matrix.c;
+			var d:Number = matrix.d;
+			
+			// Ellipse can be represented by the following parametric equations:         
+			//
+			// (1) x = cx + rx * cos(t)
+			// (2) y = cy + ry * sin(t)
+			//
+			// After applying transformation with matrix m(a, c, b, d) we get:
+			//
+			// (3) x = a * cx + a * cos(t) * rx + c * cy + c * sin(t) * ry + m.tx
+			// (4) y = b * cx + b * cos(t) * rx + d * cy + d * sin(t) * ry + m.ty
+			//
+			// In (3) and (4) x and y are functions of a parameter t. To find the extremums we need
+			// to find where dx/dt and dy/dt reach zero:
+			//
+			// (5) dx/dt = - a * sin(t) * rx + c * cos(t) * ry
+			// (6) dy/dt = - b * sin(t) * rx + d * cos(t) * ry
+			// (7) dx/dt = 0 <=> sin(t) / cos(t) = (c * ry) / (a * rx);   
+			// (8) dy/dt = 0 <=> sin(t) / cos(t) = (d * ry) / (b * rx);
+			
+			if (rx == 0 && ry == 0)
+			{
+				var pt:Point = new Point(cx, cy);
+				pt = matrix.transformPoint(pt);
+				return rectUnion(pt.x, pt.y, pt.x, pt.y, rect);
+			}
+			
+			var t:Number;
+			var t1:Number;
+			
+			if (a * rx == 0)
+				t = Math.PI / 2;
+			else
+				t = Math.atan((c * ry) / (a * rx));
+			
+			if (b * rx == 0)
+				t1 = Math.PI / 2;
+			else
+				t1 = Math.atan((d * ry) / (b * rx));            
+			
+			var x1:Number = a * Math.cos(t) * rx + c * Math.sin(t) * ry;             
+			var x2:Number = -x1;
+			x1 += a * cx + c * cy + matrix.tx;
+			x2 += a * cx + c * cy + matrix.tx;
+			
+			var y1:Number = b * Math.cos(t1) * rx + d * Math.sin(t1) * ry;             
+			var y2:Number = -y1;
+			y1 += b * cx + d * cy + matrix.ty;
+			y2 += b * cx + d * cy + matrix.ty;
+			
+			return rectUnion(Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2), rect); 
+		}
+		
+		/**
+		 *  @param x0 x coordinate of the first control point
+		 *  @param y0 y coordinate of the first control point
+		 *  @param x1 x coordinate of the second control point
+		 *  @param y1 y coordinate of the second control point
+		 *  @param x2 x coordinate of the third control point
+		 *  @param y2 y coordinate of the third control point
+		 *  @param sx The pre-transform scale factor for x coordinates.
+		 *  @param sy The pre-transform scale factor for y coordinates.
+		 *  @param matrix The transformation matrix. Can be null for identity transformation.
+		 *  @param rect If non-null, rect will be updated to the union of rect and
+		 *  the segment bounding box.
+		 *  @return Returns the union of the post-transformed quadratic
+		 *  bezier segment's axis aligned bounding box and the passed in rect.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */	
+		static public function getQBezierSegmentBBox(x0:Number, y0:Number,
+													 x1:Number, y1:Number,
+													 x2:Number, y2:Number,
+													 sx:Number, sy:Number,
+													 matrix:Matrix,
+													 rect:Rectangle):Rectangle
+		{
+			var pt:Point;
+			pt = MatrixUtil.transformPoint(x0 * sx, y0 * sy, matrix);
+			x0 = pt.x;
+			y0 = pt.y;
+			
+			pt = MatrixUtil.transformPoint(x1 * sx, y1 * sy, matrix);
+			x1 = pt.x;
+			y1 = pt.y;
+			
+			pt = MatrixUtil.transformPoint(x2 * sx, y2 * sy, matrix);
+			x2 = pt.x;
+			y2 = pt.y;
+			
+			var minX:Number = Math.min(x0, x2);
+			var maxX:Number = Math.max(x0, x2);
+			
+			var minY:Number = Math.min(y0, y2);
+			var maxY:Number = Math.max(y0, y2);
+			
+			var txDiv:Number = x0 - 2 * x1 + x2;
+			if (txDiv != 0)
+			{
+				var tx:Number = (x0 - x1) / txDiv;
+				if (0 <= tx && tx <= 1)
+				{
+					var x:Number = (1 - tx) * (1 - tx) * x0 + 2 * tx * (1 - tx) * x1 + tx * tx * x2;
+					minX = Math.min(x, minX);
+					maxX = Math.max(x, maxX);
+				}  
+			}
+			
+			var tyDiv:Number = y0 - 2 * y1 + y2;
+			if (tyDiv != 0)
+			{
+				var ty:Number = (y0 - y1) / tyDiv;
+				if (0 <= ty && ty <= 1)
+				{
+					var y:Number = (1 - ty) * (1 - ty) * y0 + 2 * ty * (1 - ty) * y1 + ty * ty * y2;
+					minY = Math.min(y, minY);
+					maxY = Math.max(y, maxY);
+				}  
+			}
+			
+			return rectUnion(minX, minY, maxX, maxY, rect);
+		}
+		
+		/**
+		 *  @param width The width of the bounds to be transformed.
+		 *  @param height The height of the bounds to be transformed.
+		 *  @param matrix The transfomration matrix. 
+		 *  
+		 *  @param vec If vec is non-null it will be set to the vector from the
+		 *  transformed bounds top left to the untransformed bounds top left
+		 *  in the coordinate space defined by <code>matrix</code>.
+		 *  This is useful if you want to align the transformed bounds to x,y
+		 *  by modifying the object's position. Moving the object by
+		 *  <code>x + vec.x</code> and <code>y + vec.y</code> respectively
+		 *  will offset the transformed bounds top left corner by x,y.
+		 *
+		 *  @return Returns the transformed bounds. Note that the Point object returned will be reused
+		 *  by other MatrixUtil methods.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function transformSize(width:Number, height:Number, matrix:Matrix):Point
+		{
+			const a:Number = matrix.a;
+			const b:Number = matrix.b;
+			const c:Number = matrix.c;
+			const d:Number = matrix.d;
+			
+			// transform point (0,0)
+			var x1:Number = 0;
+			var y1:Number = 0;
+			
+			// transform point (width, 0)
+			var x2:Number = width * a;
+			var y2:Number = width * b;
+			
+			// transform point (0, height)
+			var x3:Number = height * c;
+			var y3:Number = height * d;
+			
+			// transform point (width, height)
+			var x4:Number = x2 + x3;
+			var y4:Number = y2 + y3;
+			
+			var minX:Number = Math.min(Math.min(x1, x2), Math.min(x3, x4));
+			var maxX:Number = Math.max(Math.max(x1, x2), Math.max(x3, x4));
+			var minY:Number = Math.min(Math.min(y1, y2), Math.min(y3, y4));
+			var maxY:Number = Math.max(Math.max(y1, y2), Math.max(y3, y4));
+			
+			staticPoint.x = maxX - minX;
+			staticPoint.y = maxY - minY;
+			return staticPoint;
+		}
+		
+		/**
+		 *  @param width The width of the bounds to be transformed.
+		 *  @param height The height of the bounds to be transformed.
+		 *  @param matrix The transfomration matrix.
+		 *  
+		 *  @param topleft If topLeft is non-null it will be used as the origin of the bounds
+		 *  rectangle to be transformed.  On return, it will be set to the top left of the rectangle
+		 *  after transformation.
+		 *
+		 *  @return Returns the transformed width and height. Note that the Point object returned will be reused
+		 *  by other MatrixUtil methods.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function transformBounds(width:Number, height:Number, matrix:Matrix, topLeft:Point = null):Point
+		{
+			const a:Number = matrix.a;
+			const b:Number = matrix.b;
+			const c:Number = matrix.c;
+			const d:Number = matrix.d;
+			
+			// transform point (0,0)
+			var x1:Number = 0;
+			var y1:Number = 0;
+			
+			// transform point (width, 0)
+			var x2:Number = width * a;
+			var y2:Number = width * b;
+			
+			// transform point (0, height)
+			var x3:Number = height * c;
+			var y3:Number = height * d;
+			
+			// transform point (width, height)
+			var x4:Number = x2 + x3;
+			var y4:Number = y2 + y3;
+			
+			var minX:Number = Math.min(Math.min(x1, x2), Math.min(x3, x4));
+			var maxX:Number = Math.max(Math.max(x1, x2), Math.max(x3, x4));
+			var minY:Number = Math.min(Math.min(y1, y2), Math.min(y3, y4));
+			var maxY:Number = Math.max(Math.max(y1, y2), Math.max(y3, y4));
+			
+			staticPoint.x = maxX - minX;
+			staticPoint.y = maxY - minY;
+			
+			if (topLeft)
+			{
+				const tx:Number = matrix.tx;
+				const ty:Number = matrix.ty;
+				const x:Number = topLeft.x;
+				const y:Number = topLeft.y;
+				
+				topLeft.x = minX + a * x + b * y + tx;
+				topLeft.y = minY + c * x + d * y + ty;
+			}
+			return staticPoint;
+		}
+		
+		/**
+		 *  Returns the axis aligned bounding box <code>bounds</code> transformed
+		 *  with <code>matrix</code> and then projected with <code>projection</code>.
+		 * 
+		 *  @param bounds The bounds, in child coordinates, to be transformed and projected.
+		 *  @param matrix <p>The transformation matrix. Note that the method will clobber the
+		 *  original matrix values.</p>
+		 *  @param projection The projection.
+		 *  @return Returns the <code>bounds</code> parameter that has been updated with the
+		 *  transformed and projected bounds.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function projectBounds(bounds:Rectangle,
+											 matrix:Matrix3D, 
+											 projection:PerspectiveProjection):Rectangle
+		{
+			// Setup the matrix
+			var centerX:Number = projection.projectionCenter.x;
+			var centerY:Number = projection.projectionCenter.y;
+			matrix.appendTranslation(-centerX, -centerY, projection.focalLength);
+			matrix.append(projection.toMatrix3D());
+			
+			// Project the corner points
+			var pt1:Vector3D = new Vector3D(bounds.left, bounds.top, 0); 
+			var pt2:Vector3D = new Vector3D(bounds.right, bounds.top, 0) 
+			var pt3:Vector3D = new Vector3D(bounds.left, bounds.bottom, 0);
+			var pt4:Vector3D = new Vector3D(bounds.right, bounds.bottom, 0);
+			pt1 = Utils3D.projectVector(matrix, pt1);
+			pt2 = Utils3D.projectVector(matrix, pt2);
+			pt3 = Utils3D.projectVector(matrix, pt3);
+			pt4 = Utils3D.projectVector(matrix, pt4);
+			
+			// Find the bounding box in 2D
+			var maxX:Number = Math.max(Math.max(pt1.x, pt2.x), Math.max(pt3.x, pt4.x));
+			var minX:Number = Math.min(Math.min(pt1.x, pt2.x), Math.min(pt3.x, pt4.x));
+			var maxY:Number = Math.max(Math.max(pt1.y, pt2.y), Math.max(pt3.y, pt4.y));
+			var minY:Number = Math.min(Math.min(pt1.y, pt2.y), Math.min(pt3.y, pt4.y));
+			
+			// Add back the projection center
+			bounds.x = minX + centerX;
+			bounds.y = minY + centerY;
+			bounds.width = maxX - minX;
+			bounds.height = maxY - minY;
+			return bounds;
+		}
+		
+		/**
+		 *  @param matrix
+		 *  @return Returns true when <code>pt == matrix.DeltaTransformPoint(pt)</code>
+		 *  for any <code>pt:Point</code> (<code>matrix</code> is identity matrix,
+		 *  when disregarding the translation part).   
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function isDeltaIdentity(matrix:Matrix):Boolean
+		{
+			return (matrix.a == 1 && matrix.d == 1 &&
+				matrix.b == 0 && matrix.c == 0);
+		}
+		
+		/**
+		 *  <code>fitBounds</code> Calculates a size (x,y) for a bounding box (0,0,x,y)
+		 *  such that the bounding box transformed with <code>matrix</code> will fit
+		 *  into (0,0,width,height).
+		 *  
+		 *  @param width This is the width of the bounding box that calculated size
+		 *  needs to fit in.
+		 * 
+		 *  @param height This is the height of the bounding box that the calculated
+		 *  size needs to fit in.
+		 * 
+		 *  @param matrix This defines the transformations that the function will take
+		 *  into account when calculating the size. The bounding box (0,0,x,y) of the
+		 *  calculated size (x,y) transformed with <code>matrix</code> will fit in the
+		 *  specified <code>width</code> and <code>height</code>.
+		 * 
+		 *  @param explicitWidth Explicit width for the calculated size. The function
+		 *  will first try to find a solution using this width.
+		 * 
+		 *  @param explicitHeight Preferred height for the calculated size. The function
+		 *  will first try to find a solution using this height.
+		 * 
+		 *  @param preferredWidth Preferred width for the calculated size. If possible
+		 *  the function will set the calculated size width to this value.
+		 * 
+		 *  @param preferredHeight Preferred height for the calculated size. If possible
+		 *  the function will set the calculated size height to this value.
+		 * 
+		 *  @param minWidth The minimum allowed value for the calculated size width.
+		 * 
+		 *  @param minHeight The minimum allowed value for the calculated size height.
+		 * 
+		 *  @param maxWidth The maximum allowed value for the calculated size width.
+		 * 
+		 *  @param maxHeight The maximum allowed value for the calculated size height.
+		 * 
+		 *  @return Returns the size (x,y) such that the bounding box (0,0,x,y) will
+		 *  fit into (0,0,width,height) after transformation with <code>matrix</code>.
+		 *  Returns null if there is no possible solution.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */ 
+		public static function fitBounds(width:Number, height:Number, matrix:Matrix,
+										 explicitWidth:Number, explicitHeight:Number,
+										 preferredWidth:Number, preferredHeight:Number,
+										 minWidth:Number, minHeight:Number,
+										 maxWidth:Number, maxHeight:Number):Point
+		{
+			if (isNaN(width) && isNaN(height))
+				return new Point(preferredWidth, preferredHeight);
+			
+			// Allow for precision errors by including tolerance for certain values.
+			const newMinWidth:Number = (minWidth < MIN_MAX_TOLERANCE) ? 0 : minWidth - MIN_MAX_TOLERANCE;
+			const newMinHeight:Number = (minHeight < MIN_MAX_TOLERANCE) ? 0 : minHeight - MIN_MAX_TOLERANCE;
+			const newMaxWidth:Number = maxWidth + MIN_MAX_TOLERANCE;
+			const newMaxHeight:Number = maxHeight + MIN_MAX_TOLERANCE;
+			
+			var actualSize:Point;
+			
+			if (!isNaN(width) && !isNaN(height))
+			{
+				actualSize = calcUBoundsToFitTBounds(width, height, matrix,
+					newMinWidth, newMinHeight, 
+					newMaxWidth, newMaxHeight); 
+				
+				// If we couldn't fit in both dimensions, try to fit only one and
+				// don't stick out of the other
+				if (!actualSize)
+				{
+					var actualSize1:Point;
+					actualSize1 = fitTBoundsWidth(width, matrix,
+						explicitWidth, explicitHeight,
+						preferredWidth, preferredHeight,
+						newMinWidth, newMinHeight, 
+						newMaxWidth, newMaxHeight);
+					
+					// If we fit the width, but not the height.
+					if (actualSize1)
+					{
+						var fitHeight:Number = transformSize(actualSize1.x, actualSize1.y, matrix).y;
+						if (fitHeight - SOLUTION_TOLERANCE > height)
+							actualSize1 = null;
+					}
+					
+					var actualSize2:Point
+					actualSize2 = fitTBoundsHeight(height, matrix,
+						explicitWidth, explicitHeight,
+						preferredWidth, preferredHeight,
+						newMinWidth, newMinHeight, 
+						newMaxWidth, newMaxHeight); 
+					
+					// If we fit the height, but not the width
+					if (actualSize2)
+					{
+						var fitWidth:Number = transformSize(actualSize2.x, actualSize2.y, matrix).x;
+						if (fitWidth - SOLUTION_TOLERANCE > width)
+							actualSize2 = null;
+					}
+					
+					if (actualSize1 && actualSize2)
+					{
+						// Pick a solution
+						actualSize = ((actualSize1.x * actualSize1.y) > (actualSize2.x * actualSize2.y)) ? actualSize1 : actualSize2;
+					}
+					else if (actualSize1)
+					{
+						actualSize = actualSize1;
+					}
+					else
+					{
+						actualSize = actualSize2;
+					}
+				}
+				return actualSize;
+			}
+			else if (!isNaN(width))
+			{
+				return fitTBoundsWidth(width, matrix,
+					explicitWidth, explicitHeight,
+					preferredWidth, preferredHeight,
+					newMinWidth, newMinHeight, 
+					newMaxWidth, newMaxHeight); 
+			}
+			else
+			{
+				return fitTBoundsHeight(height, matrix,
+					explicitWidth, explicitHeight,
+					preferredWidth, preferredHeight,
+					newMinWidth, newMinHeight, 
+					newMaxWidth, newMaxHeight); 
+			}
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  <code>fitTBoundsWidth</code> Calculates a size (x,y) for a bounding box (0,0,x,y)
+		 *  such that the bounding box transformed with <code>matrix</code> will fit
+		 *  into the specified width.
+		 *  
+		 *  @param width This is the width of the bounding box that calculated size
+		 *  needs to fit in.
+		 * 
+		 *  @param matrix This defines the transformations that the function will take
+		 *  into account when calculating the size. The bounding box (0,0,x,y) of the
+		 *  calculated size (x,y) transformed with <code>matrix</code> will fit in the
+		 *  specified <code>width</code> and <code>height</code>.
+		 * 
+		 *  @param explicitWidth Explicit width for the calculated size. The function
+		 *  will first try to find a solution using this width.
+		 * 
+		 *  @param explicitHeight Preferred height for the calculated size. The function
+		 *  will first try to find a solution using this height.
+		 * 
+		 *  @param preferredWidth Preferred width for the calculated size. If possible
+		 *  the function will set the calculated size width to this value.
+		 * 
+		 *  @param preferredHeight Preferred height for the calculated size. If possible
+		 *  the function will set the calculated size height to this value.
+		 * 
+		 *  @param minWidth The minimum allowed value for the calculated size width.
+		 * 
+		 *  @param minHeight The minimum allowed value for the calculated size height.
+		 * 
+		 *  @param maxWidth The maximum allowed value for the calculated size width.
+		 * 
+		 *  @param maxHeight The maximum allowed value for the calculated size height.
+		 * 
+		 *  @return Returns the size (x,y) such that the bounding box (0,0,x,y) will
+		 *  fit into (0,0,width,height) after transformation with <code>matrix</code>.
+		 *  Returns null if there is no possible solution.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */    
+		private static function fitTBoundsWidth(width:Number, matrix:Matrix,
+												explicitWidth:Number, explicitHeight:Number,
+												preferredWidth:Number, preferredHeight:Number,
+												minWidth:Number, minHeight:Number,
+												maxWidth:Number, maxHeight:Number):Point
+		{
+			var actualSize:Point;
+			
+			// cases 1 and 2: only explicit width or explicit height is specified,
+			// so we try to find a solution with that hard constraint.
+			if (!isNaN(explicitWidth) && isNaN(explicitHeight))
+			{
+				actualSize = calcUBoundsToFitTBoundsWidth(width, matrix,
+					explicitWidth, preferredHeight, 
+					explicitWidth, minHeight, 
+					explicitWidth, maxHeight);
+				
+				if (actualSize)
+					return actualSize;
+			}
+			else if (isNaN(explicitWidth) && !isNaN(explicitHeight))
+			{
+				actualSize = calcUBoundsToFitTBoundsWidth(width, matrix,
+					preferredWidth, explicitHeight, 
+					minWidth, explicitHeight, 
+					maxWidth, explicitHeight);
+				if (actualSize)
+					return actualSize;
+			}
+			
+			// case 3: default case. When explicitWidth, explicitHeight are both set
+			// or not set, we use the preferred size since calcUBoundsToFitTBoundsWidth
+			// will just pick one.
+			actualSize = calcUBoundsToFitTBoundsWidth(width, matrix,
+				preferredWidth, preferredHeight, 
+				minWidth, minHeight, 
+				maxWidth, maxHeight);
+			
+			return actualSize;
+		}
+		
+		/**
+		 *  @private
+		 * 
+		 *  <code>fitTBoundsWidth</code> Calculates a size (x,y) for a bounding box (0,0,x,y)
+		 *  such that the bounding box transformed with <code>matrix</code> will fit
+		 *  into the specified height.
+		 *  
+		 *  @param height This is the height of the bounding box that the calculated
+		 *  size needs to fit in.
+		 * 
+		 *  @param matrix This defines the transformations that the function will take
+		 *  into account when calculating the size. The bounding box (0,0,x,y) of the
+		 *  calculated size (x,y) transformed with <code>matrix</code> will fit in the
+		 *  specified <code>width</code> and <code>height</code>.
+		 * 
+		 *  @param explicitWidth Explicit width for the calculated size. The function
+		 *  will first try to find a solution using this width.
+		 * 
+		 *  @param explicitHeight Preferred height for the calculated size. The function
+		 *  will first try to find a solution using this height.
+		 * 
+		 *  @param preferredWidth Preferred width for the calculated size. If possible
+		 *  the function will set the calculated size width to this value.
+		 * 
+		 *  @param preferredHeight Preferred height for the calculated size. If possible
+		 *  the function will set the calculated size height to this value.
+		 * 
+		 *  @param minWidth The minimum allowed value for the calculated size width.
+		 * 
+		 *  @param minHeight The minimum allowed value for the calculated size height.
+		 * 
+		 *  @param maxWidth The maximum allowed value for the calculated size width.
+		 * 
+		 *  @param maxHeight The maximum allowed value for the calculated size height.
+		 * 
+		 *  @return Returns the size (x,y) such that the bounding box (0,0,x,y) will
+		 *  fit into (0,0,width,height) after transformation with <code>matrix</code>.
+		 *  Returns null if there is no possible solution.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */    
+		private static function fitTBoundsHeight(height:Number, matrix:Matrix,
+												 explicitWidth:Number, explicitHeight:Number,
+												 preferredWidth:Number, preferredHeight:Number,
+												 minWidth:Number, minHeight:Number,
+												 maxWidth:Number, maxHeight:Number):Point
+		{
+			var actualSize:Point;
+			
+			// cases 1 and 2: only explicit width or explicit height is specified,
+			// so we try to find a solution with that hard constraint.
+			if (!isNaN(explicitWidth) && isNaN(explicitHeight))
+			{
+				actualSize = calcUBoundsToFitTBoundsHeight(height, matrix,
+					explicitWidth, preferredHeight, 
+					explicitWidth, minHeight, 
+					explicitWidth, maxHeight);
+				
+				if (actualSize)
+					return actualSize;
+			}
+			else if (isNaN(explicitWidth) && !isNaN(explicitHeight))
+			{
+				actualSize = calcUBoundsToFitTBoundsHeight(height, matrix,
+					preferredWidth, explicitHeight, 
+					minWidth, explicitHeight, 
+					maxWidth, explicitHeight);
+				if (actualSize)
+					return actualSize;
+			}
+			
+			// case 3: default case. When explicitWidth, explicitHeight are both set
+			// or not set, we use the preferred size since calcUBoundsToFitTBoundsWidth
+			// will just pick one.
+			actualSize = calcUBoundsToFitTBoundsHeight(height, matrix,
+				preferredWidth, preferredHeight, 
+				minWidth, minHeight, 
+				maxWidth, maxHeight);
+			
+			return actualSize;
+		}
+		
+		/**
+		 *  Calculates (x,y) such that the bounding box (0,0,x,y) transformed
+		 *  with <code>matrix</code> will have bounding box with
+		 *  height equal to <code>h</code>.
+		 *  x and y are restricted by <code>minX</code>, <code>maxX</code> and
+		 *  <code>minY</code>, <code>maxY</code>.
+		 *
+		 *  If possible x will be set to <code>preferredX</code> or
+		 *  y will be set to <code>preferredY</code>.
+		 *  
+		 *  When there are multiple solutions, the function picks the one that
+		 *  minimizes the bounding box area of transformed (0,0,x,y).
+		 * 
+		 *  The functon assumes <code>minX >= 0</code> and <code>minY >= 0</code>
+		 *  (solution components x and y are non-negative).
+		 *  
+		 *  @return Returns Point(x,y) or null if no solution exists. 
+		 * 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */        
+		static public function calcUBoundsToFitTBoundsHeight(h:Number,
+															 matrix:Matrix,
+															 preferredX:Number,
+															 preferredY:Number,
+															 minX:Number,
+															 minY:Number,
+															 maxX:Number, 
+															 maxY:Number):Point
+		{
+			// Untransformed bounds size is (x,y). The corners of the untransformed
+			// bounding box are p1(0,0) p2(x,0) p3(0,y) p4(x,y).
+			// Matrix is | a c tx |
+			//           | b d ty |
+			//
+			// After transfomation with the matrix those four points are:
+			// t1 = (0, 0)              = matrix.deltaTransformPoint(p1)
+			// t2 = (ax, bx)            = matrix.deltaTransformPoint(p2)
+			// t3 = (cy, dy)            = matrix.deltaTransformPoint(p3)
+			// t4 = (ax + cy, cx + dy)  = matrix.deltaTransformPoint(p4)
+			//
+			// The transformed bounds bounding box dimensions are (w,h):
+			// (1) w = max( t1.x, t2.x, t3.x, t4.x ) - min( t1.x, t2.x, t3.x, t4.x)
+			// (2) h = max( t1.y, t2.y, t3.y, t4.y ) - min( t1.y, t2.y, t3.y, t4.y)
+			//
+			// Looking at all the possible cases for min and max functions above,
+			// we can construct and solve simple linear systems for x and y.
+			// For example in the case of
+			// t1.x <= t2.x <= t3.x <= t4.x
+			// our first equation is
+			// (1) w = t4.x - t1.x <==> w = ax + cy
+			//
+			// To minimize the cases we're looking at we can take advantage of
+			// the limits we have: x >= 0, y >= 0;
+			// Taking into account these limits we deduce that:
+			// a*c >= 0  gives us (1) w = abs( t4.x - t1.x ) = abs( ax + cy )
+			// a*c <  0  gives us (1) w = abs( t2.x - t3.x ) = abs( ax - cy )
+			// b*d >= 0  gives us (2) h = abs( t4.y - t1.y ) = abs( bx + dy )
+			// b*d <  0  gives us (2) h = abs( t2.y - t3.y ) = abs( bx - dy )
+			//
+			// If we do a substitution such that
+			// c1 = a*c >= 0 ? c : -c
+			// d1 = b*d >= 0 ? d : -d
+			// we get the following linear system:
+			// (1) w = abs( ax + c1y )
+			// (2) h = abs( bx + d1y )
+			//
+			// Since we're matching height we only care about (2) 
+			
+			var b:Number = matrix.b;
+			var d:Number = matrix.d;
+			
+			// If components are very close to zero, zero them out to handle the special cases
+			if (-1.0e-9 < b && b < +1.0e-9)
+				b = 0;
+			if (-1.0e-9 < d && d < +1.0e-9)
+				d = 0;
+			
+			if (b == 0 && d == 0)
+				return null; // No solution
+			
+			// Handle special cases first
+			if (b == 0 && d == 0)
+				return null; // No solution
+			
+			if (b == 0)
+				return new Point( preferredX, h / Math.abs(d) );               
+			else if (d == 0)
+				return new Point( h / Math.abs(b), preferredY );    
+			
+			const d1:Number = (b*d >= 0) ? d : -d;
+			// Now we have the following linear sytesm:
+			// (1) x = preferredX or y = preferredY
+			// (2) h = abs( bx + d1y )
+			
+			var s:Point;
+			var x:Number;
+			var y:Number;
+			
+			if (d1 != 0 && preferredX > 0)
+			{
+				const invD1:Number = 1 / d1;
+				preferredX = Math.max(minX, Math.min(maxX, preferredX));
+				x = preferredX;
+				
+				// Case1:
+				// bx + d1y >= 0
+				// x = preferredX
+				y = (h - b * x) * invD1;
+				if (minY <= y && y <= maxY &&
+					b * x + d1 * y >= 0 ) // Satisfy Case1
+				{
+					s = new Point(x, y);
+				}
+				
+				// Case2:
+				// bx + d1y < 0
+				// x = preferredX
+				y = (-h - b * x) * invD1;
+				if (minY <= y && y <= maxY &&
+					b * x + d1 * y < 0 ) // Satisfy Case2
+				{
+					// If there is no solution, or the new solution yields smaller value, pick the new solution.
+					if (!s || transformSize(s.x, s.y, matrix).x > transformSize(x, y, matrix).x)
+						s = new Point(x, y);
+				}
+			}
+			
+			if (b != 0 && preferredY > 0)
+			{
+				const invB:Number = 1 / b;
+				preferredY = Math.max(minY, Math.min(maxY, preferredY));
+				y = preferredY;
+				
+				// Case3:
+				// bx + d1y >= 0
+				// y = preferredY
+				x = ( h - d1 * y ) * invB;
+				if (minX <= x && x <= maxX &&
+					b * x + d1 * y >= 0) // Satisfy Case3
+				{
+					// If there is no solution, or the new solution yields smaller value, pick the new solution.
+					if (!s || transformSize(s.x, s.y, matrix).x > transformSize(x, y, matrix).x)
+						s = new Point(x, y);
+				}
+				
+				// Case4:
+				// bx + d1y < 0
+				// y = preferredY
+				x = ( -h - d1 * y ) * invB;
+				if (minX <= x && x <= maxX &&
+					b * x + d1 * y < 0) // Satisfy Case4
+				{
+					// If there is no solution, or the new solution yields smaller value, pick the new solution.
+					if (!s || transformSize(s.x, s.y, matrix).x > transformSize(x, y, matrix).x)
+						s = new Point(x, y);
+				}
+			}
+			
+			// If there's already a solution that matches preferred dimention, return
+			if (s)
+				return s;
+			
+			// Find a solution that matches the width and minimizes the height: 
+			const a:Number = matrix.a;
+			const c:Number = matrix.c;
+			const c1:Number = ( a*c >= 0 ) ? c : -c;
+			return solveEquation(b, d1, h, minX, minY, maxX, maxY, a, c1);
+		}
+		
+		/**
+		 *  Calculates (x,y) such that the bounding box (0,0,x,y) transformed
+		 *  with <code>matrix</code> will have bounding box with
+		 *  width equal to <code>w</code>.
+		 *  x and y are restricted by <code>minX</code>, <code>maxX</code> and
+		 *  <code>minY</code>, <code>maxY</code>.
+		 *
+		 *  If possible x will be set to <code>preferredX</code> or
+		 *  y will be set to <code>preferredY</code>.
+		 *  
+		 *  When there are multiple solutions, the function picks the one that
+		 *  minimizes the bounding box area of transformed (0,0,x,y).
+		 * 
+		 *  The functon assumes <code>minX >= 0</code> and <code>minY >= 0</code>
+		 *  (solution components x and y are non-negative).
+		 *  
+		 *  @return Returns Point(x,y) or null if no solution exists. 
+		 * 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */        
+		static public function calcUBoundsToFitTBoundsWidth(w:Number,
+															matrix:Matrix,
+															preferredX:Number,
+															preferredY:Number,
+															minX:Number,
+															minY:Number,
+															maxX:Number,
+															maxY:Number):Point
+		{
+			// Untransformed bounds size is (x,y). The corners of the untransformed
+			// bounding box are p1(0,0) p2(x,0) p3(0,y) p4(x,y).
+			// Matrix is | a c tx |
+			//           | b d ty |
+			//
+			// After transfomation with the matrix those four points are:
+			// t1 = (0, 0)              = matrix.deltaTransformPoint(p1)
+			// t2 = (ax, bx)            = matrix.deltaTransformPoint(p2)
+			// t3 = (cy, dy)            = matrix.deltaTransformPoint(p3)
+			// t4 = (ax + cy, cx + dy)  = matrix.deltaTransformPoint(p4)
+			//
+			// The transformed bounds bounding box dimensions are (w,h):
+			// (1) w = max( t1.x, t2.x, t3.x, t4.x ) - min( t1.x, t2.x, t3.x, t4.x)
+			// (2) h = max( t1.y, t2.y, t3.y, t4.y ) - min( t1.y, t2.y, t3.y, t4.y)
+			//
+			// Looking at all the possible cases for min and max functions above,
+			// we can construct and solve simple linear systems for x and y.
+			// For example in the case of
+			// t1.x <= t2.x <= t3.x <= t4.x
+			// our first equation is
+			// (1) w = t4.x - t1.x <==> w = ax + cy
+			//
+			// To minimize the cases we're looking at we can take advantage of
+			// the limits we have: x >= 0, y >= 0;
+			// Taking into account these limits we deduce that:
+			// a*c >= 0  gives us (1) w = abs( t4.x - t1.x ) = abs( ax + cy )
+			// a*c <  0  gives us (1) w = abs( t2.x - t3.x ) = abs( ax - cy )
+			// b*d >= 0  gives us (2) h = abs( t4.y - t1.y ) = abs( bx + dy )
+			// b*d <  0  gives us (2) h = abs( t2.y - t3.y ) = abs( bx - dy )
+			//
+			// If we do a substitution such that
+			// c1 = a*c >= 0 ? c : -c
+			// d1 = b*d >= 0 ? d : -d
+			// we get the following linear system:
+			// (1) w = abs( ax + c1y )
+			// (2) h = abs( bx + d1y )
+			//
+			// Since we're matching width we only care about (1) 
+			
+			var a:Number = matrix.a;
+			var c:Number = matrix.c;
+			
+			// If components are very close to zero, zero them out to handle the special cases
+			if (-1.0e-9 < a && a < +1.0e-9)
+				a = 0;
+			if (-1.0e-9 < c && c < +1.0e-9)
+				c = 0;
+			
+			// Handle special cases first
+			if (a == 0 && c == 0)
+				return null; // No solution
+			
+			if (a == 0)
+				return new Point( preferredX, w / Math.abs(c) );               
+			else if (c == 0)
+				return new Point( w / Math.abs(a), preferredY );    
+			
+			const c1:Number = ( a*c >= 0 ) ? c : -c;
+			// Now we have the following linear sytesm:
+			// (1) w = abs( ax + c1y )
+			// (2) x = preferredX or y = preferredY
+			
+			var s:Point;
+			var x:Number;
+			var y:Number;
+			
+			if (c1 != 0 && preferredX > 0)
+			{
+				const invC1:Number = 1 / c1;
+				preferredX = Math.max(minX, Math.min(maxX, preferredX));
+				x = preferredX;
+				
+				// Case1:
+				// a * x + c1 * y >= 0
+				// x = preferredX
+				y = (w - a * x) * invC1;
+				if (minY <= y && y <= maxY &&
+					a * x + c1 * y >= 0 ) // Satisfy Case1
+				{
+					s = new Point(x, y);        
+				}
+				
+				// Case2:
+				// a * x + c1 * y < 0
+				// x = preferredX
+				y = (-w - a * x) * invC1;
+				if (minY <= y && y <= maxY &&
+					a * x + c1 * y < 0 ) // Satisfy Case2
+				{
+					// If there is no solution, or the new solution yields smaller value, pick the new solution.
+					if (!s || transformSize(s.x, s.y, matrix).y > transformSize(x, y, matrix).y)
+						s = new Point(x, y);
+				}
+			}
+			
+			if (a != 0 && preferredY > 0)
+			{
+				const invA:Number = 1 / a;
+				preferredY = Math.max(minY, Math.min(maxY, preferredY));
+				y = preferredY;
+				
+				// Case3:
+				// a * x + c1 * y >= 0
+				// y = preferredY
+				x = (w - c1 * y ) * invA;
+				if (minX <= x && x <= maxX &&
+					a * x + c1 * y >= 0) // Satisfy Case3
+				{
+					// If there is no solution, or the new solution yields smaller value, pick the new solution.
+					if (!s || transformSize(s.x, s.y, matrix).y > transformSize(x, y, matrix).y)
+						s = new Point(x, y);
+				}
+				
+				// Case4:
+				// a * x + c1 * y < 0
+				// y = preferredY
+				x = (-w - c1 * y ) * invA;
+				if (minX <= x && x <= maxX &&
+					a * x + c1 * y < 0) // Satisfy Case4
+				{
+					// If there is no solution, or the new solution yields smaller value, pick the new solution.
+					if (!s || transformSize(s.x, s.y, matrix).y > transformSize(x, y, matrix).y)
+						s = new Point(x, y);
+				}
+			}
+			
+			// If there's already a solution that matches preferred dimention, return
+			if (s)
+				return s;
+			
+			// Find a solution that matches the width and minimizes the height: 
+			const b:Number = matrix.b;
+			const d:Number = matrix.d;
+			const d1:Number = (b*d >= 0) ? d : -d;
+			return solveEquation(a, c1, w, minX, minY, maxX, maxY, b, d1);
+		}
+		
+		/**
+		 *  Finds a solution (x,y) for the equation abs(a*x + c*y) = w such that
+		 *  abs(b*x +d*y) is minimized.
+		 *  If there is infinite number of solutions, x and y are picked to be
+		 *  as close as possible.
+		 * 
+		 *  Doesn't handle cases where <code>a</code> or <code>c</code> are zero.
+		 * 
+		 *  @return Returns Point(x,y)
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */        
+		static private function solveEquation(a:Number,
+											  c:Number,
+											  w:Number,
+											  minX:Number,
+											  minY:Number, 
+											  maxX:Number, 
+											  maxY:Number, 
+											  b:Number, 
+											  d:Number):Point
+		{
+			if (a == 0 || c == 0)
+				return null; // x and y are not co-dependent
+			
+			// (1) w = abs( ax + cy )
+			// Find the range of solutsion for y and pick:
+			var x:Number;
+			var y:Number;
+			var s:Point;
+			
+			// Case1: ax + cy >= 0, from (1) above we get:
+			// (1) x = (w - cy) / a
+			//
+			// Lets find the possible range of values for y:
+			// We know that
+			// (3) minX <= x <= maxX
+			//
+			// Substitute x with (w - cy)/a in (3):
+			// (3) minX - w/a <= -cy/a <= maxX - w/a
+			// (3) min( A, B ) <= y <= max( A, B ), where
+			// A = (minX - w/a) * (-a/c)
+			// B = (maxX - w/a) * (-a/c)
+			
+			var A:Number = (w - minX * a) / c;              
+			var B:Number = (w - maxX * a) / c;              
+			var rangeMinY:Number = Math.max(minY, Math.min(A, B));
+			var rangeMaxY:Number = Math.min(maxY, Math.max(A, B));
+			const det:Number = (b * c - a * d);
+			
+			// We have a possible solution for Case1 if the range for y is valid
+			if (rangeMinY <= rangeMaxY)
+			{
+				// Now that we have a valid range for y, we need to pick a value within
+				// that range.
+				//
+				// We calculate the value based on a custom condition.
+				//
+				// The custom condition that we use could be anything that defines
+				// another equation for x and y. Some examples are:
+				// "make x and y as close as possible": y = w / ( a + c );  
+				// "minimize abs(bx + dy)": y = b * w / det    
+				// "preserve aspect ratio": y = w / ( a * preferredX / preferredY + c );
+				if (Math.abs(det) < 1.0e-9)
+				{
+					// There is infinite number of solutions, lets pick x == y
+					y = w / ( a + c );
+				}
+				else
+				{
+					// Minimize abs(bx + dy) - we need to solve:
+					// abs( b * ( w - c * y ) / a + d * y ) = 0
+					// which gives us:
+					y = b * w / det;
+				}
+				
+				// Now that we have the y value calculated from the custom condition,
+				// we clamp with the range. This gives us a solution with
+				// values as close as possible to satisfy our custom condition when
+				// the condition is a linear function of x and y (in our case it is).
+				y = Math.max(rangeMinY, Math.min(y, rangeMaxY));
+				
+				x = (w - c * y) / a;
+				return new Point(x, y);
+			}
+			
+			// Case2: ax + cy < 0, from (1) above we get:
+			// (1) x = (-w - cy) / a
+			//
+			// Lets find the possible range of values for y:
+			// We know that
+			// (3) minX <= x <= maxX
+			//
+			// Substitute x with (-w - cy)/a in (3):
+			// (3) minX + w/a <= -cy/a <= maxX + w/a
+			// (3) min( A, B ) <= y <= max( A, B ), where
+			// A = (minX + w/a) * (-a/c)
+			// B = (maxX + w/a) * (-a/c)
+			
+			A = -(minX * a + w) / c;
+			B = -(maxX * a + w) / c;
+			rangeMinY = Math.max(minY, Math.min(A, B));
+			rangeMaxY = Math.min(maxY, Math.max(A, B));
+			
+			// We have a possible solution for Case2 if the range for y is valid
+			if (rangeMinY <= rangeMaxY)
+			{
+				// Now that we have a valid range for y, we need to pick a value within
+				// that range.
+				//
+				// We calculate the value based on a custom condition.
+				//
+				// The custom condition that we use could be anything that defines
+				// another equation for x and y. Some examples are:
+				// "make x and y as close as possible": y = -w / ( a + c );  
+				// "minimize abs(bx + dy)": y = -b * w / det    
+				// "preserve aspect ratio": y = w / ( a * preferredX / preferredY + c );
+				if (Math.abs(det) < 1.0e-9)
+				{
+					// There is infinite number of solutions, lets pick x == y
+					y = -w / ( a + c );
+				}
+				else
+				{
+					// Minimize abs(bx + dy) - we need to solve:
+					// abs( b * ( -w - c * y ) / a + d * y ) = 0
+					// which gives us:
+					y = -b * w / det;
+				}
+				
+				// Now that we have the y value calculated from the custom condition,
+				// we clamp with the range. This gives us a solution with
+				// values as close as possible to satisfy our custom condition when
+				// the condition is a linear function of x and y (in our case it is).
+				y = Math.max(rangeMinY, Math.min(y, rangeMaxY));
+				x = (-w - c * y) / a;
+				return new Point(x, y);
+				
+			}
+			return null; // No solution
+		}
+		
+		/**
+		 *  Calculates (x,y) such that the bounding box (0,0,x,y) transformed
+		 *  with <code>matrix</code> will have bounding box (0,0,w,h).
+		 *  x and y are restricted by <code>minX</code>, <code>maxX</code> and
+		 *  <code>minY</code>, <code>maxY</code>.
+		 * 
+		 *  When there is infinite number of solutions, the function will
+		 *  calculate x and y to be as close as possible.
+		 * 
+		 *  The functon assumes <code>minX >= 0</code> and <code>minY >= 0</code>
+		 *  (solution components x and y are non-negative). 
+		 *  
+		 *  @return Point(x,y) or null if no solution exists.
+		 * 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		static public function calcUBoundsToFitTBounds(w:Number, 
+													   h:Number,
+													   matrix:Matrix,
+													   minX:Number,
+													   minY:Number, 
+													   maxX:Number, 
+													   maxY:Number):Point
+		{
+			// Untransformed bounds size is (x,y). The corners of the untransformed
+			// bounding box are p1(0,0) p2(x,0) p3(0,y) p4(x,y).
+			// Matrix is | a c tx |
+			//           | b d ty |
+			//
+			// After transfomation with the matrix those four points are:
+			// t1 = (0, 0)              = matrix.deltaTransformPoint(p1)
+			// t2 = (ax, bx)            = matrix.deltaTransformPoint(p2)
+			// t3 = (cy, dy)            = matrix.deltaTransformPoint(p3)
+			// t4 = (ax + cy, cx + dy)  = matrix.deltaTransformPoint(p4)
+			//
+			// The transformed bounds bounding box dimensions are (w,h):
+			// (1) w = max( t1.x, t2.x, t3.x, t4.x ) - min( t1.x, t2.x, t3.x, t4.x)
+			// (2) h = max( t1.y, t2.y, t3.y, t4.y ) - min( t1.y, t2.y, t3.y, t4.y)
+			//
+			// Looking at all the possible cases for min and max functions above,
+			// we can construct and solve simple linear systems for x and y.
+			// For example in the case of
+			// t1.x <= t2.x <= t3.x <= t4.x
+			// our first equation is
+			// (1) w = t4.x - t1.x <==> w = ax + cy
+			//
+			// To minimize the cases we're looking at we can take advantage of
+			// the limits we have: x >= 0, y >= 0;
+			// Taking into account these limits we deduce that:
+			// a*c >= 0  gives us (1) w = abs( t4.x - t1.x ) = abs( ax + cy )
+			// a*c <  0  gives us (1) w = abs( t2.x - t3.x ) = abs( ax - cy )
+			// b*d >= 0  gives us (2) h = abs( t4.y - t1.y ) = abs( bx + dy )
+			// b*d <  0  gives us (2) h = abs( t2.y - t3.y ) = abs( bx - dy )
+			//
+			// If we do a substitution such that
+			// c1 = a*c >= 0 ? c : -c
+			// d1 = b*d >= 0 ? d : -d
+			// we get the following linear system:
+			// (1) w = abs( ax + c1y )
+			// (2) h = abs( bx + d1y )
+			// 
+			
+			var a:Number = matrix.a;
+			var b:Number = matrix.b;
+			var c:Number = matrix.c;
+			var d:Number = matrix.d;
+			
+			// If components are very close to zero, zero them out to handle the special cases
+			if (-1.0e-9 < a && a < +1.0e-9)
+				a = 0;
+			if (-1.0e-9 < b && b < +1.0e-9)
+				b = 0;
+			if (-1.0e-9 < c && c < +1.0e-9)
+				c = 0;
+			if (-1.0e-9 < d && d < +1.0e-9)
+				d = 0;
+			
+			// Handle special cases.
+			if (b == 0 && c == 0)
+			{
+				// No solution in the following cases since the matrix collapses
+				// all points into a line.
+				if (a == 0 || d == 0)
+					return null;
+				
+				// (1) w = abs( ax + cy ) <=> w = abs( ax ) <=> w = abs(a)x
+				// (2) h = abs( bx + dy ) <=> h = abs( dy ) <=> h = abs(d)y
+				return new Point(w / Math.abs(a), h / Math.abs(d));
+			}
+			
+			if (a == 0 && d == 0)
+			{
+				// No solution in the following cases since the matrix collapses
+				// all points into a line.
+				if (b == 0 || c == 0)
+					return null;
+				
+				// (1) w = abs( ax + cy ) <=> w = abs( cy ) <=> w = abs(c)y
+				// (2) h = abs( bx + dy ) <=> h = abs( bx ) <=> h = abs(b)x
+				return new Point(h / Math.abs(b), w / Math.abs(c));
+			}
+			
+			// Handle general cases.
+			const c1:Number = ( a*c >= 0 ) ? c : -c;
+			const d1:Number = ( b*d >= 0 ) ? d : -d;
+			// we get the following linear system:
+			// (1) w = abs( ax + c1y )
+			// (2) h = abs( bx + d1y )
+			
+			// Calculate the determinant of the system
+			const det:Number = a * d1 - b * c1;
+			if (Math.abs(det) < 1.0e-9)
+			{
+				// No solution in these cases since the matrix
+				// collapses all points into a line.
+				if (c1 == 0 || a == 0 || a == -c1)
+					return null;
+				
+				if (Math.abs(a * h - b * w) > 1.0e-9)
+					return null; // No solution in this case
+				
+				// Determinant is zero, the equations (1) & (2) are equivalent and
+				// we have only one equation:
+				// (1) w = abs( ax + c1y )
+				//
+				// Solve it finding x and y as close as possible:
+				return solveEquation(a, c1, w, minX, minX, maxX, maxY, b, d1);
+			}
+			
+			// Pre-multiply w & h by the inverse dteterminant
+			const invDet:Number = 1 / det;
+			w *= invDet;
+			h *= invDet;
+			
+			// Case 1:
+			// a * x + c1 * y >= 0
+			// b * x + d1 * y >= 0
+			var s:Point;
+			s = solveSystem(a, c1, b, d1, w, h);
+			if (s &&
+				minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+				a * s.x + c1 * s.x >= 0 &&
+				b * s.x + d1 * s.y >= 0)
+				return s;
+			
+			// Case 2:
+			// a * x + c1 * y >= 0
+			// b * x + d1 * y < 0
+			s = solveSystem( a, c1, b, d1, w, -h);
+			if (s &&
+				minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+				a * s.x + c1 * s.x >= 0 &&
+				b * s.x + d1 * s.y < 0)
+				return s;
+			
+			// Case 3:
+			// a * x + c1 * y < 0
+			// b * x + d1 * y >= 0
+			s = solveSystem( a, c1, b, d1, -w, h);
+			if (s &&
+				minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+				a * s.x + c1 * s.x < 0 &&
+				b * s.x + d1 * s.y >= 0)
+				return s;
+			
+			// Case 4:
+			// a * x + c1 * y < 0
+			// b * x + d1 * y < 0
+			s = solveSystem( a, c1, b, d1, -w, -h);
+			if (s &&
+				minX <= s.x && s.x <= maxX && minY <= s.y && s.y <= maxY &&
+				a * s.x + c1 * s.x < 0 &&
+				b * s.x + d1 * s.y < 0)
+				return s;
+			
+			return null; // No solution.
+		}
+		
+		/**
+		 *  Determine if two Matrix instances are equal.
+		 *  
+		 *  @return true if the matrices are equal.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function isEqual(m1:Matrix, m2:Matrix):Boolean
+		{
+			return ((m1 && m2 && 
+				m1.a == m2.a &&
+				m1.b == m2.b &&
+				m1.c == m2.c &&
+				m1.d == m2.d &&
+				m1.tx == m2.tx &&
+				m1.ty == m2.ty) || 
+				(!m1 && !m2));
+		}
+		
+		/**
+		 *  Determine if two Matrix3D instances are equal.
+		 *  
+		 *  @return true if the matrices are equal.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		public static function isEqual3D(m1:Matrix3D, m2:Matrix3D):Boolean
+		{
+			if (m1 && m2 && m1.rawData.length == m2.rawData.length)
+			{
+				var r1:Vector.<Number> = m1.rawData;
+				var r2:Vector.<Number> = m2.rawData;
+				
+				return (r1[0] == r2[0] &&
+					r1[1] == r2[1] &&
+					r1[2] == r2[2] &&
+					r1[3] == r2[3] &&
+					r1[4] == r2[4] &&
+					r1[5] == r2[5] &&
+					r1[6] == r2[6] &&
+					r1[7] == r2[7] &&
+					r1[8] == r2[8] &&
+					r1[9] == r2[9] &&
+					r1[10] == r2[10] &&
+					r1[11] == r2[11] &&
+					r1[12] == r2[12] &&
+					r1[13] == r2[13] &&
+					r1[14] == r2[14] &&
+					r1[15] == r2[15]);
+			}
+			
+			return (!m1 && !m2);
+		}
+		
+		/**
+		 *  Calculates (x,y) such as to satisfy the linear system:
+		 *  | a * x + c * y = m
+		 *  | b * x + d * y = n
+		 * 
+		 *  @param mOverDet <code>mOverDet must be equal to m / (a*d - b*c)</code>
+		 *  @param nOverDet <code>mOverDet must be equal to n / (a*d - b*c)</code>
+		 *
+		 *  @return returns Point(x,y)
+		 *
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 9
+		 *  @playerversion AIR 1.1
+		 *  @productversion Flex 3
+		 */
+		static private function solveSystem(a:Number, 
+											c:Number, 
+											b:Number, 
+											d:Number, 
+											mOverDet:Number, 
+											nOverDet:Number):Point
+		{
+			return new Point(d * mOverDet - c * nOverDet,
+				a * nOverDet - b * mOverDet);
+		}
+		
+	}
+	
+}
+


Mime
View raw message