import MutableMatrix33 from './MutableMatrix33' ; import MutableVector3 from './MutableVector3' ; import { Count , Size } from '../../types/CommonTypes' ; function radianToDegree ( rad ) { return ( rad * 180 ) / Math . PI ; } function degreeToRadian ( deg ) { return ( deg * Math . PI ) / 180 ; } const toHalfFloat = ( ) => { return function toHalf ( val ) { const floatView = new Float32Array ( 1 ) ; const int32View = new Int32Array ( floatView . buffer ) ; floatView [ 0 ] = val ; const x = int32View [ 0 ] ; let bits = ( x >> 16 ) & 0x8000 ; let m = ( x >> 12 ) & 0x07ff ; const e = ( x >> 23 ) & 0xff ; if ( e < 103 ) { return bits ; } if ( e > 142 ) { bits |= 0x7c00 ; bits |= ( e == 255 ? 0 : 1 ) && x & 0x007fffff ; return bits ; } if ( e < 113 ) { m |= 0x0800 ; bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 ) ; return bits ; } bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 ) ; bits += m & 1 ; return bits ; } ; } ; param x returns function isPowerOfTwo ( x ) { return ( x & ( x - 1 ) ) == 0 ; } function isPowerOfTwoTexture ( width , height ) { return isPowerOfTwo ( width ) && isPowerOfTwo ( height ) ; } function packNormalizedVec4ToVec2 ( x , y , z , w , criteria ) { x = ( x + 1 ) / 2.0 ; y = ( y + 1 ) / 2.0 ; z = ( z + 1 ) / 2.0 ; w = ( w + 1 ) / 2.0 ; const ir = Math . floor ( x * ( criteria - 1.0 ) ) ; const ig = Math . floor ( y * ( criteria - 1.0 ) ) ; const irg = ir * criteria + ig ; const v0 = irg / criteria ; const ib = Math . floor ( z * ( criteria - 1.0 ) ) ; const ia = Math . floor ( w * ( criteria - 1.0 ) ) ; const iba = ib * criteria + ia ; const v1 = iba / criteria ; return [ v0 , v1 ] ; } function erf ( x ) { let sign = 1 ; if ( x < 0 ) sign = - 1 ; x = Math . abs ( x ) ; const t = 1 / ( 1 + 0.3275911 * x ) ; const y = 1 - ( ( ( ( 1.061405429 * t + - 1.453152027 ) * t + 1.421413741 ) * t + - 0.284496736 ) * t + 0.254829592 ) * t * Math . exp ( - x * x ) ; return sign * y ; } function invErf ( x ) { let w , p = 0 ; w = - Math . log ( ( 1.0 - x ) * ( 1.0 + x ) ) ; if ( w < 5.0 ) { w = w - 2.5 ; p = 2.81022636e-8 ; p = 3.43273939e-7 + p * w ; p = - 3.5233877e-6 + p * w ; p = - 4.39150654e-6 + p * w ; p = 0.00021858087 + p * w ; p = - 0.00125372503 + p * w ; p = - 0.00417768164 + p * w ; p = 0.246640727 + p * w ; p = 1.50140941 + p * w ; } else { w = Math . sqrt ( w ) - 3 ; p = - 0.000200214257 ; p = 0.000100950558 + p * w ; p = 0.00134934322 + p * w ; p = - 0.00367342844 + p * w ; p = 0.00573950773 + p * w ; p = - 0.0076224613 + p * w ; p = 0.00943887047 + p * w ; p = 1.00167406 + p * w ; p = 2.83297682 + p * w ; } return p * x ; } function gaussianCdf ( x , mu , sigma ) { const U = 0.5 * ( 1 + erf ( ( x - mu ) / ( sigma * Math . sqrt ( 2.0 ) ) ) ) ; return U ; } function invGaussianCdf ( U , mu , sigma ) { const x = sigma * Math . sqrt ( 2.0 ) * invErf ( 2.0 * U - 1 ) + mu ; return x ; } function computeEigenValuesAndVectors ( A , Q , w ) { const n = 3 ; let sd = 0 ; let so = 0 ; let s = 0 ; let c = 0 ; let t = 0 ; let g = 0 ; let h = 0 ; let z = 0 ; let theta = 0 ; let thresh = 0 ; for ( let i = 0 ; i < n ; i ++ ) { Q . setAt ( i , i , 1.0 ) ; for ( let j = 0 ; j < i ; j ++ ) { Q . setAt ( i , j , 0.0 ) ; Q . setAt ( j , i , 0.0 ) ; } } for ( let i = 0 ; i < n ; i ++ ) w . setAt ( i , A . at ( i , i ) ) ; sd = 0.0 ; for ( let i = 0 ; i < n ; i ++ ) sd += Math . abs ( w . at ( i ) ) ; sd = sd * sd ; for ( let nIter = 0 ; nIter < 50 ; nIter ++ ) { so = 0.0 ; for ( let p = 0 ; p < n ; p ++ ) { for ( let q = p + 1 ; q < n ; q ++ ) so += Math . abs ( A . at ( p , q ) ) ; } if ( so == 0.0 ) return 0 ; if ( nIter < 4 ) thresh = ( 0.2 * so ) / ( n * n ) ; else thresh = 0.0 ; for ( let p = 0 ; p < n ; p ++ ) { for ( let q = p + 1 ; q < n ; q ++ ) { g = 100.0 * Math . abs ( A . at ( p , q ) ) ; if ( nIter > 4 && Math . abs ( w . at ( p ) ) + g == Math . abs ( w . at ( p ) ) && Math . abs ( w . at ( q ) ) + g == Math . abs ( w . at ( q ) ) ) { A . setAt ( p , q , 0.0 ) ; } else if ( Math . abs ( A . at ( p , q ) ) > thresh ) { h = w . at ( q ) - w . at ( p ) ; if ( Math . abs ( h ) + g == Math . abs ( h ) ) { t = A . at ( p , q ) / h ; } else { theta = ( 0.5 * h ) / A . at ( p , q ) ; if ( theta < 0.0 ) t = - 1.0 / ( Math . sqrt ( 1.0 + theta * theta ) - theta ) ; else t = 1.0 / ( Math . sqrt ( 1.0 + theta * theta ) + theta ) ; } c = 1.0 / Math . sqrt ( 1.0 + t * t ) ; s = t * c ; z = t * A . at ( p , q ) ; A . setAt ( p , q , 0.0 ) ; w . setAt ( p , w . at ( p ) - z ) ; w . setAt ( q , w . at ( q ) + z ) ; for ( let r = 0 ; r < p ; r ++ ) { t = A . at ( r , p ) ; A . setAt ( r , p , c * t - s * A . at ( r , q ) ) ; A . setAt ( r , q , s * t + c * A . at ( r , q ) ) ; } for ( let r = p + 1 ; r < q ; r ++ ) { t = A . at ( p , r ) ; A . setAt ( p , r , c * t - s * A . at ( r , q ) ) ; A . setAt ( r , q , s * t + c * A . at ( r , q ) ) ; } for ( let r = q + 1 ; r < n ; r ++ ) { t = A . at ( p , r ) ; A . setAt ( p , r , c * t - s * A . at ( q , r ) ) ; A . setAt ( q , r , s * t + c * A . at ( q , r ) ) ; } for ( let r = 0 ; r < n ; r ++ ) { t = Q . at ( r , p ) ; Q . setAt ( r , p , c * t - s * Q . at ( r , q ) ) ; Q . setAt ( r , q , s * t + c * Q . at ( r , q ) ) ; } } } } } return - 1 ; } function convertToStringAsGLSLFloat ( value ) { if ( Number . isInteger ( value ) ) { return `${ value }.0` ; } else { return '' + value ; } } function nearZeroToZero ( value ) { if ( Math . abs ( value ) < 0.00001 ) { value = 0 ; } else if ( 0.99999 < value && value < 1.00001 ) { value = 1 ; } else if ( - 1.00001 < value && value < - 0.99999 ) { value = - 1 ; } return value ; } function financial ( val ) { const fixedStr = Number . parseFloat ( val as string ) . toFixed ( 7 ) ; if ( val >= 0 ) { return ' ' + fixedStr ; } return fixedStr ; } function roundAsFloat ( value ) { return Math . round ( value * 10000000 ) / 10000000 ; } kernelSize variance mean effectiveDigit returns function computeGaussianDistributionRatioWhoseSumIsOne ( { kernelSize , variance , mean = 0 , effectiveDigit = 4 , } ) { const ceiledHalfKernelSize = Math . ceil ( kernelSize / 2.0 ) ; const gaussianDistributionRatio = new Array ( ceiledHalfKernelSize ) ; let totalSize = 0 ; for ( let i = 0 ; i < ceiledHalfKernelSize ; i ++ ) { gaussianDistributionRatio [ i ] = Math . exp ( - ( ( i - mean ) ** 2 ) / ( 2.0 * variance ) ) ; totalSize += gaussianDistributionRatio [ i ] ; } totalSize *= 2 ; if ( ( kernelSize / 2.0 ) % 2 !== 0.0 ) { totalSize -= gaussianDistributionRatio [ 0 ] ; } const gaussianDistributionRatioWhoseSumIsOne = new Array ( kernelSize ) ; let totalRatio = 0 ; const changeDigitParam = Math . pow ( 10 , effectiveDigit ) ; for ( let i = 0 ; i < ceiledHalfKernelSize - 1 ; i ++ ) { let ratio = gaussianDistributionRatio [ ceiledHalfKernelSize - 1 - i ] / totalSize ; ratio *= changeDigitParam ; ratio = Math . round ( ratio ) ; ratio /= changeDigitParam ; gaussianDistributionRatioWhoseSumIsOne [ i ] = ratio ; gaussianDistributionRatioWhoseSumIsOne [ kernelSize - 1 - i ] = ratio ; totalRatio += 2 * ratio ; } if ( kernelSize % 2 === 0 ) { const value = ( 1 - totalRatio ) / 2.0 ; gaussianDistributionRatioWhoseSumIsOne [ ceiledHalfKernelSize - 1 ] = value ; gaussianDistributionRatioWhoseSumIsOne [ ceiledHalfKernelSize ] = value ; } else { const value = 1 - totalRatio ; gaussianDistributionRatioWhoseSumIsOne [ ceiledHalfKernelSize - 1 ] = value ; } return gaussianDistributionRatioWhoseSumIsOne ; } export const MathUtil = Object . freeze ( { radianToDegree , degreeToRadian , toHalfFloat , isPowerOfTwo , isPowerOfTwoTexture , packNormalizedVec4ToVec2 , convertToStringAsGLSLFloat , nearZeroToZero , gaussianCdf , invGaussianCdf , computeEigenValuesAndVectors , computeGaussianDistributionRatioWhoseSumIsOne , roundAsFloat , financial } ) ;