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

PrspctvPrjctn

PerspectiveProjectionと
同じ計算をするクラスを作るとしたら
こんなかんじかな。

値がぴったり一致しないのは、
ビルトインクラス側では三角関数をMathではなく、
別なものから求めているからなんじゃないかな、、、。
/**
 * Copyright umhr ( http://wonderfl.net/user/umhr )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/iPa6
 */

/*
PerspectiveProjectionと
同じ計算をするクラスを作るとしたら
こんなかんじかな。

値がぴったり一致しないのは、
ビルトインクラス側では三角関数をMathではなく、
別なものから求めているからなんじゃないかな、、、。

*/

package
{
	import flash.display.Sprite;
	import flash.geom.PerspectiveProjection;
	import flash.geom.Point;
	import flash.text.TextField;
	
	public class Main extends Sprite
	{
		public function Main()
		{
			var pp1:PerspectiveProjection = new PerspectiveProjection();
			var pp2:PrspctvPrjctn = new PrspctvPrjctn();
			
			var pp1txt:String = "ビルトインクラスの\nPerspectiveProjection\n\nデフォルト値\n";
			var pp2txt:String = "カスタムクラスの\nPrspctvPrjctn\n\nデフォルト値\n";
			pp1txt += "fieldOfView : "+pp1.fieldOfView+"\n";
			pp1txt += "focalLength : "+pp1.focalLength+"\n";
			pp1txt += "projectionCenter : "+pp1.projectionCenter+"\n";
			pp2txt += "fieldOfView : "+pp2.fieldOfView+"\n";
			pp2txt += "focalLength : "+pp2.focalLength+"\n";
			pp2txt += "projectionCenter : "+pp2.projectionCenter+"\n";
			
			var random:Number = Math.random();
			pp1.fieldOfView = pp2.fieldOfView = 180*random;
			
			pp1txt += "\nfieldOfViewに値を入れてみる\n";
			pp1txt += "fieldOfView = "+180*random+"\n";
			pp2txt += "\nfieldOfViewに値を入れてみる\n";
			pp2txt += "fieldOfView = "+180*random+"\n";
			pp1txt += "focalLength : "+pp1.focalLength+"\n";
			pp1txt += "projectionCenter : "+pp1.projectionCenter+"\n";
			pp2txt += "focalLength : "+pp2.focalLength+"\n";
			pp2txt += "projectionCenter : "+pp2.projectionCenter+"\n";
			
			random = Math.random();
			pp1.focalLength = pp2.focalLength = 2000*random;
			
			pp1txt += "\nfocalLengthに値を入れてみる\n";
			pp1txt += "focalLength = "+2000*random+"\n";
			pp2txt += "\nfocalLengthに値を入れてみる\n";
			pp2txt += "focalLength = "+2000*random+"\n";
			pp1txt += "fieldOfView : "+pp1.fieldOfView+"\n";
			pp1txt += "projectionCenter : "+pp1.projectionCenter+"\n";
			pp2txt += "fieldOfView : "+pp2.fieldOfView+"\n";
			pp2txt += "projectionCenter : "+pp2.projectionCenter+"\n";
			
			random = Math.random();
			var randomy:Number = Math.random();
			pp1.projectionCenter = pp2.projectionCenter = new Point(random*1000,randomy*1000);
			
			pp1txt += "\nprojectionCenterに値を入れてみる\n";
			pp1txt += "projectionCenter = new Point("+random*1000+","+randomy*1000+")\n";
			pp2txt += "\nprojectionCenterに値を入れてみる\n";
			pp2txt += "projectionCenter = new Point("+random*1000+","+randomy*1000+")\n";
			pp1txt += "fieldOfView : "+pp1.fieldOfView+"\n";
			pp1txt += "focalLength : "+pp1.focalLength+"\n";
			pp2txt += "fieldOfView : "+pp2.fieldOfView+"\n";
			pp2txt += "focalLength : "+pp2.focalLength+"\n";
			
			pp1txt += "toMatrix3D().rawData : "+pp1.toMatrix3D().rawData+"\n";
			pp2txt += "toMatrix3D().rawData : "+pp2.toMatrix3D().rawData+"\n";
			
			var tf1:TextField = new TextField();
			tf1.width = 465/2;
			tf1.height = 465;
			tf1.text = pp1txt;
			tf1.wordWrap = true;
			this.addChild(tf1);
			
			var tf2:TextField = new TextField();
			tf2.width = 232;
			tf2.height = 465;
			tf2.text = pp2txt;
			tf2.wordWrap = true;
			tf2.x =233;
			this.addChild(tf2);
		}
	}
}

import flash.geom.Point;
class PrspctvPrjctn{
	private var _fieldOfView:Number = 55;
	private var _focalLength:Number = 250/Math.tan(_fieldOfView*0.008726646259971648);
	private var _projectionCenter:Point = new Point(250,250);
	public function PrspctvPrjctn(){
	}
	public function get fieldOfView():Number{return _fieldOfView};
	public function set fieldOfView(value:Number):void{
		if(value<0 || 180<value){
			return;
		}
		_fieldOfView = value;
		_focalLength = 250/Math.tan(value*0.008726646259971648);
		//0.008726646259971648 = Math.PI/360
	}
	public function get focalLength():Number{return _focalLength};
	public function set focalLength(value:Number):void{
		if(value<0){
			return;
		}
		_focalLength = value;
		_fieldOfView = Math.atan2(250,value)*114.59155902616465;
		//114.59155902616465 = 360/Math.PI
	}
	public function get projectionCenter():Point{return _projectionCenter};
	public function set projectionCenter(value:Point):void{
		_projectionCenter = value.clone();
	}
	public function toMatrix3D():Mtrx3D{
		return new Mtrx3D([_focalLength,0,0,0,0,_focalLength,0,0,0,0,1,1,0,0,0,0]);
	}
}

//Matrix3D的なもの
class Mtrx3D {
	private var _rawData:Array = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
	
	//コンストラクタ
	public function Mtrx3D(v:Array = null) {
		if (v) {
			_rawData = v.concat();
		}
	}
	
	//プロパティ
	public function get determinant():Number{
		//余因子(cofactor)を作る
		var d:Number = _rawData[0]*sarrus([_rawData[5],_rawData[9],_rawData[13],_rawData[6],_rawData[10],_rawData[14],_rawData[7],_rawData[11],_rawData[15]]);
		//dはdeterminantから
		d -= _rawData[1]*sarrus([_rawData[4],_rawData[8],_rawData[12],_rawData[6],_rawData[10],_rawData[14],_rawData[7],_rawData[11],_rawData[15]]);
		d += _rawData[2]*sarrus([_rawData[4],_rawData[8],_rawData[12],_rawData[5],_rawData[9],_rawData[13],_rawData[7],_rawData[11],_rawData[15]]);
		d -= _rawData[3]*sarrus([_rawData[4],_rawData[8],_rawData[12],_rawData[5],_rawData[9],_rawData[13],_rawData[6],_rawData[10],_rawData[14]]);
		d -= ((_rawData[4]-_rawData[8])*_rawData[1]+(_rawData[9]-_rawData[5])*_rawData[0])*_rawData[11]*_rawData[14];
		return -d;
		function sarrus(c:Array):Number{
			//cはcofactorから
			//サルス(Sarrus)の公式(関-サルスの公式)
			return c[0]*c[4]*c[8]+c[3]*c[7]*c[2]+c[6]*c[1]*c[5]
				-c[6]*c[4]*c[2]-c[3]*c[1]*c[8]-c[0]*c[7]*c[5];
		}
	}
	public function get position():Vctr3D{
		return new Vctr3D(_rawData[12],_rawData[13],_rawData[14]);
	}
	public function set position(v:Vctr3D):void{
		_rawData[12] = v.x;
		_rawData[13] = v.y;
		_rawData[14] = v.z;
	}
	public function get rawData():Array { return _rawData };
	public function set rawData(value:Array):void {
		_rawData = value.concat();
	}
	
	
	//メソッド
	public function append(lhs:Mtrx3D):void {
		_rawData = matrix44Calculat(_rawData,lhs.rawData);
	}
	public function appendRotation(degrees:Number,axis:Vctr3D,pivotPoint:Vctr3D=null):void {
		if(!pivotPoint){
			pivotPoint = new Vctr3D(0, 0, 0);
		}
		var tempAxis:Vctr3D = axis.clone();
		
		//AXIS_ANGLE to QUATERNION
		var degreesPIper360:Number = degrees / 360 * Math.PI;
		var w:Number = Math.cos(degreesPIper360);
		var x:Number = Math.sin(degreesPIper360) * tempAxis.x;
		var y:Number = Math.sin(degreesPIper360) * tempAxis.y;
		var z:Number = Math.sin(degreesPIper360) * tempAxis.z;
		
		//rawData from QUATERNION
		var p:Array = rawDataFromQuaternion(x, y, z, w);
		
		//Matrix * entity
		_rawData = matrix44Calculat(_rawData, p);
		appendTranslation(pivotPoint.x,pivotPoint.y,pivotPoint.z);
		
	}
	public function appendScale(xScale:Number,yScale:Number,zScale:Number):void {
		_rawData[0]*=xScale;
		_rawData[1]*=yScale;
		_rawData[2]*=zScale;
		_rawData[4]*=xScale;
		_rawData[5]*=yScale;
		_rawData[6]*=zScale;
		_rawData[8]*=xScale;
		_rawData[9]*=yScale;
		_rawData[10]*=zScale;
		_rawData[12]*=xScale;
		_rawData[13]*=yScale;
		_rawData[14]*=zScale;
	}
	public function appendTranslation(x:Number, y:Number, z:Number):void{
		_rawData[12] += x;
		_rawData[13] += y;
		_rawData[14] += z;
	}
	
	public function clone():Mtrx3D {
		return new Mtrx3D(_rawData);
	}
	
	public function decompose(orientationStyle:String = "eulerAngles"):Array{
		var e:Array = _rawData.concat();
		
		//prependScale的処理
		var vec:Array = matrix3dToEulerAnglePrepend(e);
		
		if(orientationStyle != "eulerAngles"){
			vec = matrix3dToQuaternion(e,vec[2],orientationStyle);
		}
		return vec;
	}
	
	private function matrix3dToQuaternion(e:Array,scale:Vctr3D,orientationStyle:String):Array{
		if(scale.x > 0){
			e[0]/=scale.x;
			e[4]/=scale.x;
			e[8]/=scale.x;
		}
		if(scale.y > 0){
			e[1]/=scale.y;
			e[5]/=scale.y;
			e[9]/=scale.y;
		}
		if(scale.z > 0){
			e[2]/=scale.z;
			e[6]/=scale.z;
			e[10]/=scale.z;
		}
		var w:Number;
		var x:Number;
		var y:Number;
		var z:Number;
		var _ar:Array = new Array(e[0]+e[5]+e[10],e[0]-e[5]-e[10],e[5]-e[0]-e[10],e[10]-e[0]-e[5]);
		var biggestIndex:int = _ar.sort(Array.NUMERIC|Array.RETURNINDEXEDARRAY|Array.DESCENDING)[0];
		var biggestVal:Number = Math.sqrt(_ar[biggestIndex]+1)*0.5;
		var mult:Number = 0.25/biggestVal;
		switch (biggestIndex) {
			case 0:
				w = biggestVal;
				x = (e[6]-e[9])*mult;
				y = (e[8]-e[2])*mult;
				z = (e[1]-e[4])*mult;
				break;
			case 1:
				x = biggestVal;
				w = (e[6]-e[9])*mult;
				y = (e[4]+e[1])*mult;
				z = (e[2]+e[8])*mult;
				break;
			case 2:
				y = biggestVal;
				w = (e[8]-e[2])*mult;
				x = (e[4]+e[1])*mult;
				z = (e[9]+e[6])*mult;
				break;
			case 3:
				z = biggestVal;
				w = (e[1]-e[4])*mult;
				x = (e[2]+e[8])*mult;
				y = (e[9]+e[6])*mult;
				break;
		}
		
		if(orientationStyle == "axisAngle"){
			if(Math.sin(Math.acos(w)) != 0){
				x = x/Math.sin(Math.acos(w));
				y = y/Math.sin(Math.acos(w));
				z = z/Math.sin(Math.acos(w));
				w = 2*Math.acos(w);
			}else{
				x = y = z= w = 0;
			}
		}
		return [new Vctr3D(e[12],e[13],e[14]),new Vctr3D(x,y,z,w),scale];
	}
	
	private function matrix3dToEulerAnglePrepend(e:Array):Array{
		var _z:Number = Math.atan2(e[1],e[0]);
		var sz:Number = Math.sin(_z);
		var cz:Number = Math.cos(_z);
		
		var _y:Number;
		if(Math.abs(cz) > 0.7){
			_y = Math.atan2(-e[2],e[0]/cz);
		}else{
			_y = Math.atan2(-e[2],e[1]/sz);
		}
		var sy:Number = Math.sin(_y);
		var cy:Number = Math.cos(_y);
		
		var _x:Number;
		if(Math.abs(cz) > 0.7){
			_x = Math.atan2((sy*sz-e[9]*cy/e[10]),cz);
		}else{
			_x = Math.atan2((e[8]*cy/e[10]-sy*cz)/sz,1);
		}
		
		//_x = Math.atan2((sy*sz-e[9]*cy/e[10])/cz,1);
		//_x = Math.atan2((e[8]*cy/e[10]-sy*cz)/sz,1);
		
		var sx:Number = Math.sin(_x);
		var cx:Number = Math.cos(_x);
		
		var scale_x:Number = -e[2]/sy;
		var scale_y:Number = e[6]/(sx*cy);
		var scale_z:Number = e[10]/(cx*cy);
		return [new Vctr3D(e[12], e[13], e[14]), new Vctr3D(_x, _y, _z), new Vctr3D(scale_x, scale_y, scale_z)];
		
	}
	
	
	
	public function deltaTransformVector(v:Vctr3D):Vctr3D {
		var e:Array = _rawData;
		return new Vctr3D((e[0]*v.x+e[4]*v.y+e[8]*v.z),(e[1]*v.x+e[5]*v.y+e[9]*v.z),(e[2]*v.x+e[6]*v.y+e[10]*v.z),(e[3]*v.x+e[7]*v.y+e[11]*v.z));
	}
	public function identity():void {
		_rawData=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];
	}
	public function interpolate(thisMat:Mtrx3D,toMat:Mtrx3D,percent:Number):Mtrx3D{
		var v0:Vctr3D = thisMat.decompose("quaternion")[1];
		var v1:Vctr3D = toMat.decompose("quaternion")[1];
		var cosOmega:Number = v0.w*v1.w + v0.x*v1.x + v0.y*v1.y + v0.z*v1.z;
		if(cosOmega < 0){
			v1.x = -v1.x;
			v1.y = -v1.y;
			v1.z = -v1.z;
			v1.w = -v1.w;
			cosOmega = -cosOmega;
		}
		var k0:Number;
		var k1:Number;
		if(cosOmega > 0.9999){
			k0 = 1 - percent;
			k1 = percent;
		}else{
			var sinOmega:Number = Math.sqrt(1 - cosOmega*cosOmega);
			var omega:Number = Math.atan2(sinOmega,cosOmega);
			var oneOverSinOmega:Number = 1/sinOmega;
			k0 = Math.sin((1-percent)*omega)*oneOverSinOmega;
			k1 = Math.sin(percent*omega)*oneOverSinOmega;
		}
		var scale_x:Number = thisMat.decompose("quaternion")[2].x*(1-percent) + toMat.decompose("quaternion")[2].x*percent;
		var scale_y:Number = thisMat.decompose("quaternion")[2].y*(1-percent) + toMat.decompose("quaternion")[2].y*percent;
		var scale_z:Number = thisMat.decompose("quaternion")[2].z*(1-percent) + toMat.decompose("quaternion")[2].z*percent;
		
		var tx:Number = thisMat.decompose("quaternion")[0].x*(1-percent) + toMat.decompose("quaternion")[0].x*percent;
		var ty:Number = thisMat.decompose("quaternion")[0].y*(1-percent) + toMat.decompose("quaternion")[0].y*percent;
		var tz:Number = thisMat.decompose("quaternion")[0].z*(1-percent) + toMat.decompose("quaternion")[0].z*percent;
		
		var x:Number = v0.x*k0+v1.x*k1;
		var y:Number = v0.y*k0+v1.y*k1;
		var z:Number = v0.z*k0+v1.z*k1;
		var w:Number = v0.w * k0 + v1.w * k1;
		var _q:Array = rawDataFromQuaternion(x, y, z, w);
		_q[12] = tx;
		_q[13] = ty;
		_q[14] = tz;
		
		//var v:Vctr3D = new Vctr3D(v0.x*k0+v1.x*k1,v0.y*k0+v1.y*k1,v0.z*k0+v1.z*k1,v0.w*k0+v1.w*k1);
		
		//var txyz:Vector3D = new Vector3D(tx,ty,tz);
		//var m:Matrix3D=new Matrix3D();
		//m.recompose(Vector.<Vector3D>([txyz,v,new Vector3D(scale_x,scale_y,scale_z)]),"quaternion");
		//trace(m.rawData);
		return new Mtrx3D(_q);
	}
	public function interpolateTo():* {
		//未実装
	}	
	
	public function invert():Boolean {
		var e:Array = _rawData;
		var a:Array=new Array(16);
		//aはadjugateから
		a[0]=sarrus([e[5],e[9],e[13],e[6],e[10],e[14],e[7],e[11],e[15]]);
		a[1]=- sarrus([e[4],e[8],e[12],e[6],e[10],e[14],e[7],e[11],e[15]]);
		a[2]=sarrus([e[4],e[8],e[12],e[5],e[9],e[13],e[7],e[11],e[15]]);
		a[3]=- sarrus([e[4],e[8],e[12],e[5],e[9],e[13],e[6],e[10],e[14]]);
		
		a[4]=- sarrus([e[1],e[9],e[13],e[2],e[10],e[14],e[3],e[11],e[15]]);
		a[5]=sarrus([e[0],e[8],e[12],e[2],e[10],e[14],e[3],e[11],e[15]]);
		a[6]=- sarrus([e[0],e[8],e[12],e[1],e[9],e[13],e[3],e[11],e[15]]);
		a[7]=sarrus([e[0],e[8],e[12],e[1],e[9],e[13],e[2],e[10],e[14]]);
		
		a[8]=sarrus([e[1],e[5],e[13],e[2],e[6],e[14],e[3],e[7],e[15]]);
		a[9]=- sarrus([e[0],e[4],e[12],e[2],e[6],e[14],e[3],e[7],e[15]]);
		a[10]=sarrus([e[0],e[4],e[12],e[1],e[5],e[13],e[3],e[7],e[15]]);
		a[11]=- sarrus([e[0],e[4],e[12],e[1],e[5],e[13],e[2],e[6],e[14]]);
		
		a[12]=- sarrus([e[1],e[5],e[9],e[2],e[6],e[10],e[3],e[7],e[11]]);
		a[13]=sarrus([e[0],e[4],e[8],e[2],e[6],e[10],e[3],e[7],e[11]]);
		a[14]=- sarrus([e[0],e[4],e[8],e[1],e[5],e[9],e[3],e[7],e[11]]);
		a[15]=sarrus([e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]]);
		
		var d:Number=e[0]*a[0]+e[1]*a[1]+e[2]*a[2]+e[3]*a[3];
		//dはdeterminantから
		if (d!=0) {
			_rawData = [
				a[0]/d,a[4]/d,a[8]/d,a[12]/d,
				a[1]/d,a[5]/d,a[9]/d,a[13]/d,
				a[2]/d,a[6]/d,a[10]/d,a[14]/d,
				a[3]/d,a[7]/d,a[11]/d,a[15]/d];
		}
		return d != 0;
		function sarrus(c:Array):Number {
			//cはcofactorから
			return c[0]*(c[4]*c[8]-c[5]*c[7])+
				c[1]*(c[5]*c[6]-c[3]*c[8])+
				c[2]*(c[3]*c[7]-c[4]*c[6]);
		}
	}
	public function pointAt():* {
		//未実装
	}	
	public function prepend(rhs:Mtrx3D):void {
		_rawData = matrix44Calculat(rhs.rawData,_rawData);
	}
	public function prependRotation(degrees:Number,axis:Vctr3D,pivotPoint:Vctr3D=null):void {
		if(!pivotPoint){
			pivotPoint = new Vctr3D(0, 0, 0);
		}
		var tempAxis:Vctr3D = axis.clone();
		tempAxis.normalize();
		//AXIS_ANGLE to QUATERNION
		var degreesPIper360:Number = degrees / 360 * Math.PI;
		var w:Number = Math.cos(degreesPIper360);
		var x:Number = Math.sin(degreesPIper360) * tempAxis.x;
		var y:Number = Math.sin(degreesPIper360) * tempAxis.y;
		var z:Number = Math.sin(degreesPIper360) * tempAxis.z;
		
		//rawData from QUATERNION
		var p:Array = rawDataFromQuaternion(x, y, z, w);
		
		//Matrix * entity
		_rawData = matrix44Calculat(p, _rawData);
		appendTranslation(pivotPoint.x,pivotPoint.y,pivotPoint.z);
	}
	public function prependScale(xScale:Number,yScale:Number,zScale:Number):void {
		_rawData[0]*=xScale;
		_rawData[1]*=xScale;
		_rawData[2]*=xScale;
		_rawData[3]*=xScale;
		_rawData[4]*=yScale;
		_rawData[5]*=yScale;
		_rawData[6]*=yScale;
		_rawData[7]*=yScale;
		_rawData[8]*=zScale;
		_rawData[9]*=zScale;
		_rawData[10]*=zScale;
		_rawData[11]*=zScale;
	}
	
	public function prependTranslation(x:Number, y:Number, z:Number):void{
		_rawData[12] += _rawData[0]*x+_rawData[4]*y+_rawData[8]*z;
		_rawData[13] += _rawData[1]*x+_rawData[5]*y+_rawData[9]*z;
		_rawData[14] += _rawData[2]*x+_rawData[6]*y+_rawData[10]*z;
		_rawData[15] += _rawData[3]*x+_rawData[7]*y+_rawData[11]*z;
	}
	public function recompose(components:Array, orientationStyle:String = "eulerAngles"):Boolean {
		var scale:Array=new Array(16);
		//prependScale的な乗算
		scale[0] = scale[1] = scale[2] = components[2].x;
		scale[4] = scale[5] = scale[6] = components[2].y;
		scale[8] = scale[9] = scale[10] = components[2].z;
		
		var v:Array=new Array(16);
		if (orientationStyle=="eulerAngles") {
			//eulerAngles to Matrix3D
			var cx:Number=Math.cos(components[1].x);
			var cy:Number=Math.cos(components[1].y);
			var cz:Number=Math.cos(components[1].z);
			var sx:Number=Math.sin(components[1].x);
			var sy:Number=Math.sin(components[1].y);
			var sz:Number=Math.sin(components[1].z);
			v[0]=cy*cz*scale[0];
			v[1]=cy*sz*scale[1];
			v[2]=- sy*scale[2];
			v[3]=0;
			v[4] = (sx*sy*cz-cx*sz)*scale[4];
			v[5] = (sx*sy*sz+cx*cz)*scale[5];
			v[6]=sx*cy*scale[6];
			v[7]=0;
			v[8] = (cx*sy*cz+sx*sz)*scale[8];
			v[9] = (cx*sy*sz-sx*cz)*scale[9];
			v[10]=cx*cy*scale[10];
			v[11]=0;
			v[12]=components[0].x;
			v[13]=components[0].y;
			v[14]=components[0].z;
			v[15]=1;
		} else {
			//"quaternion" to Matrix3D
			var x:Number=components[1].x;
			var y:Number=components[1].y;
			var z:Number=components[1].z;
			var w:Number=components[1].w;
			if (orientationStyle=="axisAngle") {
				//"axisAngle" to Matrix3D
				x*=Math.sin(w/2);
				y*=Math.sin(w/2);
				z*=Math.sin(w/2);
				w=Math.cos(w/2);
			}
			v[0] = (1-2*y*y-2*z*z)*scale[0];
			v[1] = (2*x*y+2*w*z)*scale[1];
			v[2] = (2*x*z-2*w*y)*scale[2];
			v[3]=0;
			v[4] = (2*x*y-2*w*z)*scale[4];
			v[5] = (1-2*x*x-2*z*z)*scale[5];
			v[6] = (2*y*z+2*w*x)*scale[6];
			v[7]=0;
			v[8] = (2*x*z+2*w*y)*scale[8];
			v[9] = (2*y*z-2*w*x)*scale[9];
			v[10] = (1-2*x*x-2*y*y)*scale[10];
			v[11]=0;
			v[12]=components[0].x;
			v[13]=components[0].y;
			v[14]=components[0].z;
			v[15]=1;
		}
		//v[0],v[4],v[8]が三つとも0だと
		//ArgumentError: Error #2188: 行マトリックスが無効です。マトリックスは反転可能である必要があります。
		//というエラーでMatrix3Dを作れないので、設定可能な最小値を入れている。
		//0.000000000000000000000000000000000000000000001;
		//これは1e-45と書ける。
		//ただしx,y,z三つとも1e-45には設定できないので、1e-15にしてる。
		if(components[2].x == 0){v[0] = 1e-15};
		if(components[2].y == 0){v[5] = 1e-15};
		if(components[2].z == 0){v[10] = 1e-15};
		_rawData = v;
		//helpには拡大 / 縮小エレメントのいずれかが 0 の場合は、false を返します。
		//とあるがtrueしか返さないっぽい、、
		return !(components[2].x == 0 || components[2].y == 0 || components[2].y == 0)
	}
	public function transformVector(v:Vctr3D):Vctr3D{
		var tempV:Vctr3D = new Vctr3D();
		tempV.x = _rawData[0]*v.x+_rawData[4]*v.y+_rawData[8]*v.z+_rawData[12];
		tempV.y = _rawData[1]*v.x+_rawData[5]*v.y+_rawData[9]*v.z+_rawData[13];
		tempV.z = _rawData[2]*v.x+_rawData[6]*v.y+_rawData[10]*v.z+_rawData[14];
		tempV.w = _rawData[3]*v.x+_rawData[7]*v.y+_rawData[11]*v.z+_rawData[15];
		return tempV;
	}
	
	public function transformVectors(vin:Array, vout:Array):void {
		var e:Array = _rawData;
		var n:int=vin.length;
		var temp:Array = new Array(n);
		for (var i:int=0; i<n; i+=3) {
			temp[i] = e[0]*vin[i]+e[4]*vin[i+1]+e[8]*vin[i+2]+e[12];
			temp[i+1] = e[1]*vin[i]+e[5]*vin[i+1]+e[9]*vin[i+2]+e[13];
			temp[i+2] = e[2]*vin[i]+e[6]*vin[i+1]+e[10]*vin[i+2]+e[14];
		}
		for (var j:int=0; j<n; j++) {
			vout[j] = temp[j];
		}
	}
	public function transpose():void {
		_rawData = [
			_rawData[0],_rawData[4],_rawData[8],_rawData[12],
			_rawData[1],_rawData[5],_rawData[9],_rawData[13],
			_rawData[2],_rawData[6],_rawData[10],_rawData[14],
			_rawData[3],_rawData[7],_rawData[11],_rawData[15]
		]
	}
	
	
	
	//private function
	private function matrix44Calculat(e:Array,p:Array):Array {
		var pe:Array = new Array();
		
		pe[0] = p[0]*e[0]+p[4]*e[1]+p[8]*e[2]+p[12]*e[3];
		pe[1] = p[1]*e[0]+p[5]*e[1]+p[9]*e[2]+p[13]*e[3];
		pe[2] = p[2]*e[0]+p[6]*e[1]+p[10]*e[2]+p[14]*e[3];
		pe[3] = p[3]*e[0]+p[7]*e[1]+p[11]*e[2]+p[15]*e[3];
		
		pe[4] = p[0]*e[4]+p[4]*e[5]+p[8]*e[6]+p[12]*e[7];
		pe[5] = p[1]*e[4]+p[5]*e[5]+p[9]*e[6]+p[13]*e[7];
		pe[6] = p[2]*e[4]+p[6]*e[5]+p[10]*e[6]+p[14]*e[7];
		pe[7] = p[3]*e[4]+p[7]*e[5]+p[11]*e[6]+p[15]*e[7];
		
		pe[8] = p[0]*e[8]+p[4]*e[9]+p[8]*e[10]+p[12]*e[11];
		pe[9] = p[1]*e[8]+p[5]*e[9]+p[9]*e[10]+p[13]*e[11];
		pe[10] = p[2]*e[8]+p[6]*e[9]+p[10]*e[10]+p[14]*e[11];
		pe[11] = p[3]*e[8]+p[7]*e[9]+p[11]*e[10]+p[15]*e[11];
		
		pe[12] = p[0]*e[12]+p[4]*e[13]+p[8]*e[14]+p[12]*e[15];
		pe[13] = p[1]*e[12]+p[5]*e[13]+p[9]*e[14]+p[13]*e[15];
		pe[14] = p[2]*e[12]+p[6]*e[13]+p[10]*e[14]+p[14]*e[15];
		pe[15] = p[3]*e[12]+p[7]*e[13]+p[11]*e[14]+p[15]*e[15];
		
		return pe;
	}
	private function rawDataFromQuaternion(x:Number,y:Number,z:Number,w:Number):Array {
		var p:Array = new Array(16);
		p[0] = (w*w+x*x-y*y-z*z);
		p[1] = 2*(y*x+w*z);
		p[2] = 2*(z*x-w*y);
		p[3] = 0;
		p[4] = 2*(y*x-w*z);
		p[5] = (w*w-x*x+y*y-z*z);
		p[6] = 2*(w*x+z*y);
		p[7] = 0;
		p[8] = 2*(z*x+w*y);
		p[9] = 2*(z*y-w*x);
		p[10] = (w*w-x*x-y*y+z*z);
		p[11] = 0;
		p[12] = 0;
		p[13] = 0;
		p[14] = 0;
		p[15] = 1;
		return p;
	}
	
}


class Vctr3D{
	public var w:Number;
	public var x:Number;
	public var y:Number;
	public var z:Number;
	public static const X_AXIS:Vctr3D=new Vctr3D(1,0,0);
	public static const Y_AXIS:Vctr3D=new Vctr3D(0,1,0);
	public static const Z_AXIS:Vctr3D=new Vctr3D(0,0,1);
	function Vctr3D(x:Number=0.,y:Number=0.,z:Number=0.,w:Number=0.) {
		this.w=w;
		this.x=x;
		this.y=y;
		this.z=z;
	}
	public function get length():Number {
		return Math.sqrt(x*x+y*y+z*z);
	}
	public function get lengthSquared():Number {
		return x*x+y*y+z*z;
	}
	public function add(a:Vctr3D):Vctr3D {
		return new Vctr3D(a.x+x,a.y+y,a.z+z);
	}
	public static function angleBetween(a:Vctr3D,b:Vctr3D):Number {
		return Math.acos(a.x*b.x+a.y*b.y+a.z*b.z/Math.sqrt(a.x*a.x+a.y*a.y+a.z*a.z)*Math.sqrt(b.x*b.x+b.y*b.y+b.z*b.z));
	}
	public function clone():Vctr3D {
		return new Vctr3D(x,y,z,w);
	}
	public function crossProduct(a:Vctr3D):Vctr3D {
		return new Vctr3D(y*a.z-z*a.y,z*a.x-x*a.z,x*a.y-y*a.x,1);
	}
	public function decrementBy(a:Vctr3D):void {
		x-=a.x;
		y-=a.y;
		z-=a.z;
	}
	public static function distance(pt1:Vctr3D,pt2:Vctr3D):Number {
		return Math.sqrt(pt1.x-pt2.x*pt1.x-pt2.x+pt1.y-pt2.y*pt1.y-pt2.y+pt1.z-pt2.z*pt1.z-pt2.z);
	}
	public function dotProduct(a:Vctr3D):Number {
		return x*a.x+y*a.y+z*a.z;
	}
	public function equals(toCompare:Vctr3D,allFour:Boolean=false):Boolean {
		return x==toCompare.x&&y==toCompare.y&&z==toCompare.z&&! allFour||w==toCompare.w;
	}
	public function incrementBy(a:Vctr3D):void {
		x+=a.x;
		y+=a.y;
		z+=a.z;
	}
	public function nearEquals(toCompare:Vctr3D,tolerance:Number,allFour:Boolean=false):Boolean {
		return Math.abs(x-toCompare.x)<tolerance&&Math.abs(y-toCompare.y)<tolerance&&Math.abs(z-toCompare.z)<tolerance&&! allFour||Math.abs(w-toCompare.w)<tolerance;
	}
	public function negate():void {
		x=- x;
		y=- y;
		z=- z;
	}
	public function normalize():Number {
		var _len:Number=Math.sqrt(x*x+y*y+z*z);
		x/=_len;
		y/=_len;
		z/=_len;
		return _len;
	}
	public function project():void {
		x/=w;
		y/=w;
		z/=w;
	}
	public function scaleBy(s:Number):void {
		x*=s;
		y*=s;
		z*=s;
	}
	public function subtract(a:Vctr3D):Vctr3D {
		return new Vctr3D(x-a.x,y-a.y,z-a.z);
	}
	public function toString():String {
		return "Vctr3D("+x+", "+y+", "+z+")";
	}
	// おまけ
	public function isHiddenCrossProduct(a:Vctr3D):Boolean {
		return x*a.y-y*a.x>0;
	}
}