#NEWLINE# def decompose_matrix( matrix ) : #NEWLINE# #INDENT# 'Return sequence of transformations from transformation matrix.\n\n    matrix : array_like\n        Non-degenerative homogeneous transformation matrix\n\n    Return tuple of:\n        scale : vector of 3 scaling factors\n        shear : list of shear factors for x-y, x-z, y-z axes\n        angles : list of Euler angles about static x, y, z axes\n        translate : translation vector along x, y, z axes\n        perspective : perspective partition of matrix\n\n    Raise ValueError if matrix is of wrong type or degenerative.\n\n    >>> T0 = translation_matrix((1, 2, 3))\n    >>> scale, shear, angles, trans, persp = decompose_matrix(T0)\n    >>> T1 = translation_matrix(trans)\n    >>> numpy.allclose(T0, T1)\n    True\n    >>> S = scale_matrix(0.123)\n    >>> scale, shear, angles, trans, persp = decompose_matrix(S)\n    >>> scale[0]\n    0.123\n    >>> R0 = euler_matrix(1, 2, 3)\n    >>> scale, shear, angles, trans, persp = decompose_matrix(R0)\n    >>> R1 = euler_matrix(*angles)\n    >>> numpy.allclose(R0, R1)\n    True\n\n    ' #NEWLINE# M = numpy . array ( matrix , dtype = numpy . float64 , copy = True ) . T #NEWLINE# if ( abs ( M [ ( 3 , 3 ) ] ) < _EPS ) : #NEWLINE# #INDENT# raise ValueError ( 'M[3, 3] is zero' ) #NEWLINE# #UNINDENT# M /= M [ ( 3 , 3 ) ] #NEWLINE# P = M . copy ( ) #NEWLINE# P [ : , 3 ] = ( 0 , 0 , 0 , 1 ) #NEWLINE# if ( not numpy . linalg . det ( P ) ) : #NEWLINE# #INDENT# raise ValueError ( 'Matrix is singular' ) #NEWLINE# #UNINDENT# scale = numpy . zeros ( ( 3 , ) , dtype = numpy . float64 ) #NEWLINE# shear = [ 0 , 0 , 0 ] #NEWLINE# angles = [ 0 , 0 , 0 ] #NEWLINE# if any ( ( abs ( M [ : 3 , 3 ] ) > _EPS ) ) : #NEWLINE# #INDENT# perspective = numpy . dot ( M [ : , 3 ] , numpy . linalg . inv ( P . T ) ) #NEWLINE# M [ : , 3 ] = ( 0 , 0 , 0 , 1 ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# perspective = numpy . array ( ( 0 , 0 , 0 , 1 ) , dtype = numpy . float64 ) #NEWLINE# #UNINDENT# translate = M [ 3 , : 3 ] . copy ( ) #NEWLINE# M [ 3 , : 3 ] = 0 #NEWLINE# row = M [ : 3 , : 3 ] . copy ( ) #NEWLINE# scale [ 0 ] = vector_norm ( P [ 0 ] ) #NEWLINE# row [ 0 ] /= scale [ 0 ] #NEWLINE# shear [ 0 ] = numpy . dot ( row [ 0 ] , row [ 1 ] ) #NEWLINE# row [ 1 ] -= ( row [ 0 ] * shear [ 0 ] ) #NEWLINE# scale [ 1 ] = vector_norm ( row [ 1 ] ) #NEWLINE# row [ 1 ] /= scale [ 1 ] #NEWLINE# shear [ 0 ] /= scale [ 1 ] #NEWLINE# shear [ 1 ] = numpy . dot ( row [ 0 ] , row [ 2 ] ) #NEWLINE# row [ 2 ] -= ( row [ 0 ] * shear [ 1 ] ) #NEWLINE# shear [ 2 ] = numpy . dot ( row [ 1 ] , row [ 2 ] ) #NEWLINE# row [ 2 ] -= ( row [ 1 ] * shear [ 2 ] ) #NEWLINE# scale [ 2 ] = vector_norm ( row [ 2 ] ) #NEWLINE# row [ 2 ] /= scale [ 2 ] #NEWLINE# shear [ 1 : ] /= scale [ 2 ] #NEWLINE# if ( numpy . dot ( row [ 0 ] , numpy . cross ( row [ 1 ] , row [ 2 ] ) ) < 0 ) : #NEWLINE# #INDENT# scale *= ( - 1 ) #NEWLINE# row *= ( - 1 ) #NEWLINE# #UNINDENT# angles [ 1 ] = math . asin ( ( - row [ ( 0 , 2 ) ] ) ) #NEWLINE# if math . cos ( angles [ 1 ] ) : #NEWLINE# #INDENT# angles [ 0 ] = math . atan2 ( row [ ( 1 , 2 ) ] , row [ ( 2 , 2 ) ] ) #NEWLINE# angles [ 2 ] = math . atan2 ( row [ ( 0 , 1 ) ] , row [ ( 0 , 0 ) ] ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# angles [ 0 ] = math . atan2 ( ( - row [ ( 2 , 1 ) ] ) , row [ ( 1 , 1 ) ] ) #NEWLINE# angles [ 2 ] = 0.0 #NEWLINE# #UNINDENT# return ( scale , shear , angles , translate , perspective )