import Utils from '../Utils' ; import Vertice from './Vertice' ; import Vector from './Vector' ; export default class Matrix { private elements : Float64Array ; constructor ( m11 = 1 , m12 = 0 , m13 = 0 , m14 = 0 , m21 = 0 , m22 = 1 , m23 = 0 , m24 = 0 , m31 = 0 , m32 = 0 , m33 = 1 , m34 = 0 , m41 = 0 , m42 = 0 , m43 = 0 , m44 = 1 ) { this . elements = new Float64Array ( 16 ) ; this . setElements ( m11 , m12 , m13 , m14 , m21 , m22 , m23 , m24 , m31 , m32 , m33 , m34 , m41 , m42 , m43 , m44 ) ; } getFloat32Array ( ) { return new Float32Array ( this . elements ) ; } equals ( matrix ) { if ( this === matrix ) { return true ; } return Utils . every ( this . elements , ( ele , index ) => { return ele === matrix . elements [ index ] ; } ) ; } toJson ( ) { var elements = [ ] ; Utils . forEach ( this . elements , function ( ele ) { elements . push ( ele ) ; } ) ; return { elements : elements } ; } fromJson ( json ) { json . elements . forEach ( ( ele , i ) => { this . elements [ i ] = ele ; } ) ; } static fromJson ( json ) { if ( ! json ) { return null ; } var mat = new Matrix ( ) ; mat . fromJson ( json ) ; return mat ; } setElements ( m11 , m12 , m13 , m14 , m21 , m22 , m23 , m24 , m31 , m32 , m33 , m34 , m41 , m42 , m43 , m44 ) { var count = arguments . length ; if ( count < 16 ) { throw "invalid arguments:arguments length error" ; } var values = this . elements ; values [ 0 ] = m11 ; values [ 4 ] = m12 ; values [ 8 ] = m13 ; values [ 12 ] = m14 ; values [ 1 ] = m21 ; values [ 5 ] = m22 ; values [ 9 ] = m23 ; values [ 13 ] = m24 ; values [ 2 ] = m31 ; values [ 6 ] = m32 ; values [ 10 ] = m33 ; values [ 14 ] = m34 ; values [ 3 ] = m41 ; values [ 7 ] = m42 ; values [ 11 ] = m43 ; values [ 15 ] = m44 ; return this ; } setVectorX ( vector ) { this . elements [ 0 ] = vector . x ; this . elements [ 1 ] = vector . y ; this . elements [ 2 ] = vector . z ; } getVectorX ( ) { return new Vector ( this . elements [ 0 ] , this . elements [ 1 ] , this . elements [ 2 ] ) ; } setVectorY ( vector ) { this . elements [ 4 ] = vector . x ; this . elements [ 5 ] = vector . y ; this . elements [ 6 ] = vector . z ; } getVectorY ( ) { return new Vector ( this . elements [ 4 ] , this . elements [ 5 ] , this . elements [ 6 ] ) ; } setVectorZ ( vector ) { this . elements [ 8 ] = vector . x ; this . elements [ 9 ] = vector . y ; this . elements [ 10 ] = vector . z ; } getVectorZ ( ) { return new Vector ( this . elements [ 8 ] , this . elements [ 9 ] , this . elements [ 10 ] ) ; } setPosition ( vertice ) { this . elements [ 12 ] = vertice . x ; this . elements [ 13 ] = vertice . y ; this . elements [ 14 ] = vertice . z ; } getPosition ( ) { return new Vertice ( this . elements [ 12 ] , this . elements [ 13 ] , this . elements [ 14 ] ) ; } setLastRowDefault ( ) { this . elements [ 3 ] = 0 ; this . elements [ 7 ] = 0 ; this . elements [ 11 ] = 0 ; this . elements [ 15 ] = 1 ; } transpose ( ) { var result = this . getTransposeMatrix ( ) ; this . setMatrixByOther ( result ) ; } getTransposeMatrix ( ) { var result = new Matrix ( ) ; result . elements [ 0 ] = this . elements [ 0 ] ; result . elements [ 4 ] = this . elements [ 1 ] ; result . elements [ 8 ] = this . elements [ 2 ] ; result . elements [ 12 ] = this . elements [ 3 ] ; result . elements [ 1 ] = this . elements [ 4 ] ; result . elements [ 5 ] = this . elements [ 5 ] ; result . elements [ 9 ] = this . elements [ 6 ] ; result . elements [ 13 ] = this . elements [ 7 ] ; result . elements [ 2 ] = this . elements [ 8 ] ; result . elements [ 6 ] = this . elements [ 9 ] ; result . elements [ 10 ] = this . elements [ 10 ] ; result . elements [ 14 ] = this . elements [ 11 ] ; result . elements [ 3 ] = this . elements [ 12 ] ; result . elements [ 7 ] = this . elements [ 13 ] ; result . elements [ 11 ] = this . elements [ 14 ] ; result . elements [ 15 ] = this . elements [ 15 ] ; return result ; } inverse ( ) { var result = this . getInverseMatrix ( ) ; this . setMatrixByOther ( result ) ; } getInverseMatrix ( ) { var a = this . elements ; var result = new Matrix ( ) ; var b = result . elements ; var c = a [ 0 ] , d = a [ 1 ] , e = a [ 2 ] , g = a [ 3 ] , f = a [ 4 ] , h = a [ 5 ] , i = a [ 6 ] , j = a [ 7 ] , k = a [ 8 ] , l = a [ 9 ] , n = a [ 10 ] , o = a [ 11 ] , m = a [ 12 ] , p = a [ 13 ] , r = a [ 14 ] , s = a [ 15 ] ; var A = c * h - d * f ; var B = c * i - e * f ; var t = c * j - g * f ; var u = d * i - e * h ; var v = d * j - g * h ; var w = e * j - g * i ; var x = k * p - l * m ; var y = k * r - n * m ; var z = k * s - o * m ; var C = l * r - n * p ; var D = l * s - o * p ; var E = n * s - o * r ; var q = A * E - B * D + t * C + u * z - v * y + w * x ; if ( ! q ) { console . log ( "can't get inverse matrix" ) ; return null ; } q = 1 / q ; b [ 0 ] = ( h * E - i * D + j * C ) * q ; b [ 1 ] = ( - d * E + e * D - g * C ) * q ; b [ 2 ] = ( p * w - r * v + s * u ) * q ; b [ 3 ] = ( - l * w + n * v - o * u ) * q ; b [ 4 ] = ( - f * E + i * z - j * y ) * q ; b [ 5 ] = ( c * E - e * z + g * y ) * q ; b [ 6 ] = ( - m * w + r * t - s * B ) * q ; b [ 7 ] = ( k * w - n * t + o * B ) * q ; b [ 8 ] = ( f * D - h * z + j * x ) * q ; b [ 9 ] = ( - c * D + d * z - g * x ) * q ; b [ 10 ] = ( m * v - p * t + s * A ) * q ; b [ 11 ] = ( - k * v + l * t - o * A ) * q ; b [ 12 ] = ( - f * C + h * y - i * x ) * q ; b [ 13 ] = ( c * C - d * y + e * x ) * q ; b [ 14 ] = ( - m * u + p * B - r * A ) * q ; b [ 15 ] = ( k * u - l * B + n * A ) * q ; return result ; } setMatrixByOther ( otherMatrix ) { for ( var i = 0 ; i < otherMatrix . elements . length ; i ++ ) { this . elements [ i ] = otherMatrix . elements [ i ] ; } } /**
     * 将矩阵设置为单位阵
     */ setUnitMatrix ( ) { this . setElements ( 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ) ; } setUniqueValue ( value ) { var length = this . elements . length ; for ( var i = 0 ; i < length ; i ++ ) { this . elements [ i ] = value ; } } returns { boolean } isUnitMatrix ( ) { var values = this . elements ; for ( var i = 0 ; i < values . length ; i ++ ) { if ( i % 4 === 0 ) { if ( values [ i ] != 1 ) { return false ; } } else { if ( values [ i ] !== 0 ) { return false ; } } } return true ; } clone ( ) { return new Matrix ( this . elements [ 0 ] , this . elements [ 4 ] , this . elements [ 8 ] , this . elements [ 12 ] , this . elements [ 1 ] , this . elements [ 5 ] , this . elements [ 9 ] , this . elements [ 13 ] , this . elements [ 2 ] , this . elements [ 6 ] , this . elements [ 10 ] , this . elements [ 14 ] , this . elements [ 3 ] , this . elements [ 7 ] , this . elements [ 11 ] , this . elements [ 15 ] ) ; } multiplyMatrix ( otherMatrix ) { var values1 = this . elements ; var values2 = otherMatrix . elements ; var m11 = values1 [ 0 ] * values2 [ 0 ] + values1 [ 4 ] * values2 [ 1 ] + values1 [ 8 ] * values2 [ 2 ] + values1 [ 12 ] * values2 [ 3 ] ; var m12 = values1 [ 0 ] * values2 [ 4 ] + values1 [ 4 ] * values2 [ 5 ] + values1 [ 8 ] * values2 [ 6 ] + values1 [ 12 ] * values2 [ 7 ] ; var m13 = values1 [ 0 ] * values2 [ 8 ] + values1 [ 4 ] * values2 [ 9 ] + values1 [ 8 ] * values2 [ 10 ] + values1 [ 12 ] * values2 [ 11 ] ; var m14 = values1 [ 0 ] * values2 [ 12 ] + values1 [ 4 ] * values2 [ 13 ] + values1 [ 8 ] * values2 [ 14 ] + values1 [ 12 ] * values2 [ 15 ] ; var m21 = values1 [ 1 ] * values2 [ 0 ] + values1 [ 5 ] * values2 [ 1 ] + values1 [ 9 ] * values2 [ 2 ] + values1 [ 13 ] * values2 [ 3 ] ; var m22 = values1 [ 1 ] * values2 [ 4 ] + values1 [ 5 ] * values2 [ 5 ] + values1 [ 9 ] * values2 [ 6 ] + values1 [ 13 ] * values2 [ 7 ] ; var m23 = values1 [ 1 ] * values2 [ 8 ] + values1 [ 5 ] * values2 [ 9 ] + values1 [ 9 ] * values2 [ 10 ] + values1 [ 13 ] * values2 [ 11 ] ; var m24 = values1 [ 1 ] * values2 [ 12 ] + values1 [ 5 ] * values2 [ 13 ] + values1 [ 9 ] * values2 [ 14 ] + values1 [ 13 ] * values2 [ 15 ] ; var m31 = values1 [ 2 ] * values2 [ 0 ] + values1 [ 6 ] * values2 [ 1 ] + values1 [ 10 ] * values2 [ 2 ] + values1 [ 14 ] * values2 [ 3 ] ; var m32 = values1 [ 2 ] * values2 [ 4 ] + values1 [ 6 ] * values2 [ 5 ] + values1 [ 10 ] * values2 [ 6 ] + values1 [ 14 ] * values2 [ 7 ] ; var m33 = values1 [ 2 ] * values2 [ 8 ] + values1 [ 6 ] * values2 [ 9 ] + values1 [ 10 ] * values2 [ 10 ] + values1 [ 14 ] * values2 [ 11 ] ; var m34 = values1 [ 2 ] * values2 [ 12 ] + values1 [ 6 ] * values2 [ 13 ] + values1 [ 10 ] * values2 [ 14 ] + values1 [ 14 ] * values2 [ 15 ] ; var m41 = values1 [ 3 ] * values2 [ 0 ] + values1 [ 7 ] * values2 [ 1 ] + values1 [ 11 ] * values2 [ 2 ] + values1 [ 15 ] * values2 [ 3 ] ; var m42 = values1 [ 3 ] * values2 [ 4 ] + values1 [ 7 ] * values2 [ 5 ] + values1 [ 11 ] * values2 [ 6 ] + values1 [ 15 ] * values2 [ 7 ] ; var m43 = values1 [ 3 ] * values2 [ 8 ] + values1 [ 7 ] * values2 [ 9 ] + values1 [ 11 ] * values2 [ 10 ] + values1 [ 15 ] * values2 [ 11 ] ; var m44 = values1 [ 3 ] * values2 [ 12 ] + values1 [ 7 ] * values2 [ 13 ] + values1 [ 11 ] * values2 [ 14 ] + values1 [ 15 ] * values2 [ 15 ] ; return new Matrix ( m11 , m12 , m13 , m14 , m21 , m22 , m23 , m24 , m31 , m32 , m33 , m34 , m41 , m42 , m43 , m44 ) ; } param c return { Matrix } multiplyColumn ( c ) { var valid = c . length == 4 ; if ( ! valid ) { throw "invalid c" ; } var values1 = this . elements ; var values2 = c ; var m11 = values1 [ 0 ] * values2 [ 0 ] + values1 [ 4 ] * values2 [ 1 ] + values1 [ 8 ] * values2 [ 2 ] + values1 [ 12 ] * values2 [ 3 ] ; var m21 = values1 [ 1 ] * values2 [ 0 ] + values1 [ 5 ] * values2 [ 1 ] + values1 [ 9 ] * values2 [ 2 ] + values1 [ 13 ] * values2 [ 3 ] ; var m31 = values1 [ 2 ] * values2 [ 0 ] + values1 [ 6 ] * values2 [ 1 ] + values1 [ 10 ] * values2 [ 2 ] + values1 [ 14 ] * values2 [ 3 ] ; var m41 = values1 [ 3 ] * values2 [ 0 ] + values1 [ 7 ] * values2 [ 1 ] + values1 [ 11 ] * values2 [ 2 ] + values1 [ 15 ] * values2 [ 3 ] ; return [ m11 , m21 , m31 , m41 ] ; } hasNaN ( ) { return Utils . some ( this . elements , function ( v ) { return isNaN ( v ) ; } ) ; } divide ( a ) { if ( a === 0 ) { throw "invalid a:a is 0" ; } if ( a !== 0 ) { for ( var i = 0 , length = this . elements . length ; i < length ; i ++ ) { this . elements [ i ] /= a ; } } } worldTranslate ( x , y , z ) { this . elements [ 12 ] += x ; this . elements [ 13 ] += y ; this . elements [ 14 ] += z ; } localTranslate ( x , y , z ) { var localColumn = [ x , y , z , 1 ] ; var worldColumn = this . multiplyColumn ( localColumn ) ; var origin = this . getPosition ( ) ; this . worldTranslate ( worldColumn [ 0 ] - origin . x , worldColumn [ 1 ] - origin . y , worldColumn [ 2 ] - origin . z ) ; } worldScale ( scaleX , scaleY , scaleZ ) { scaleX = ( scaleX !== undefined ) ? scaleX : 1 ; scaleY = ( scaleY !== undefined ) ? scaleY : 1 ; scaleZ = ( scaleZ !== undefined ) ? scaleZ : 1 ; var m = new Matrix ( scaleX , 0 , 0 , 0 , 0 , scaleY , 0 , 0 , 0 , 0 , scaleZ , 0 , 0 , 0 , 0 , 1 ) ; var result = m . multiplyMatrix ( this ) ; this . setMatrixByOther ( result ) ; } localScale ( scaleX , scaleY , scaleZ ) { var transVertice = this . getPosition ( ) ; this . setPosition ( new Vertice ( 0 , 0 , 0 ) ) ; this . worldScale ( scaleX , scaleY , scaleZ ) ; this . setPosition ( transVertice ) ; } worldRotateX ( radian ) { var c = Math . cos ( radian ) ; var s = Math . sin ( radian ) ; var m = new Matrix ( 1 , 0 , 0 , 0 , 0 , c , - s , 0 , 0 , s , c , 0 , 0 , 0 , 0 , 1 ) ; var result = m . multiplyMatrix ( this ) ; this . setMatrixByOther ( result ) ; } worldRotateY ( radian ) { var c = Math . cos ( radian ) ; var s = Math . sin ( radian ) ; var m = new Matrix ( c , 0 , s , 0 , 0 , 1 , 0 , 0 , - s , 0 , c , 0 , 0 , 0 , 0 , 1 ) ; var result = m . multiplyMatrix ( this ) ; this . setMatrixByOther ( result ) ; } worldRotateZ ( radian ) { var c = Math . cos ( radian ) ; var s = Math . sin ( radian ) ; var m = new Matrix ( c , - s , 0 , 0 , s , c , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 ) ; var result = m . multiplyMatrix ( this ) ; this . setMatrixByOther ( result ) ; } worldRotateByVector ( radian , vector ) { var x = vector . x ; var y = vector . y ; var z = vector . z ; var length , s , c ; var xx , yy , zz , xy , yz , zx , xs , ys , zs , one_c ; s = Math . sin ( radian ) ; c = Math . cos ( radian ) ; length = Math . sqrt ( x * x + y * y + z * z ) ; x /= length ; y /= length ; z /= length ; xx = x * x ; yy = y * y ; zz = z * z ; xy = x * y ; yz = y * z ; zx = z * x ; xs = x * s ; ys = y * s ; zs = z * s ; one_c = 1.0 - c ; var m11 = ( one_c * xx ) + c ; var m12 = ( one_c * xy ) - zs ; var m13 = ( one_c * zx ) + ys ; var m14 = 0.0 ; var m21 = ( one_c * xy ) + zs ; var m22 = ( one_c * yy ) + c ; var m23 = ( one_c * yz ) - xs ; var m24 = 0.0 ; var m31 = ( one_c * zx ) - ys ; var m32 = ( one_c * yz ) + xs ; var m33 = ( one_c * zz ) + c ; var m34 = 0.0 ; var m41 = 0.0 ; var m42 = 0.0 ; var m43 = 0.0 ; var m44 = 1.0 ; var mat = new Matrix ( m11 , m12 , m13 , m14 , m21 , m22 , m23 , m24 , m31 , m32 , m33 , m34 , m41 , m42 , m43 , m44 ) ; var result = mat . multiplyMatrix ( this ) ; this . setMatrixByOther ( result ) ; } localRotateX ( radian ) { var transVertice = this . getPosition ( ) ; this . setPosition ( new Vertice ( 0 , 0 , 0 ) ) ; var columnX = this . getVectorX ( ) ; this . worldRotateByVector ( radian , columnX ) ; this . setPosition ( transVertice ) ; } localRotateY ( radian ) { var transVertice = this . getPosition ( ) ; this . setPosition ( new Vertice ( 0 , 0 , 0 ) ) ; var columnY = this . getVectorY ( ) ; this . worldRotateByVector ( radian , columnY ) ; this . setPosition ( transVertice ) ; } localRotateZ ( radian ) { var transVertice = this . getPosition ( ) ; this . setPosition ( new Vertice ( 0 , 0 , 0 ) ) ; var columnZ = this . getVectorZ ( ) ; this . worldRotateByVector ( radian , columnZ ) ; this . setPosition ( transVertice ) ; } localRotateByVector ( radian , localVector ) { var localColumn = localVector . getArray ( ) ; localColumn . push ( 1 ) ; var worldColumn = this . multiplyColumn ( localColumn ) ; var worldVector = new Vector ( worldColumn [ 0 ] , worldColumn [ 1 ] , worldColumn [ 2 ] ) ; var transVertice = this . getPosition ( ) ; this . setPosition ( new Vertice ( 0 , 0 , 0 ) ) ; this . worldRotateByVector ( radian , worldVector ) ; this . setPosition ( transVertice ) ; } } ;