|
|
/*******************************************************************************
* DXVector.h * *------------* * Description: * This is the header file for the matrix classes. * *******************************************************************************/ #ifndef __DXTPRIV_H_
#define __DXTPRIV_H_
#ifndef _INC_MATH
#include <math.h>
#endif
#ifndef _INC_CRTDBG
#include <crtdbg.h>
#endif
//=== Class, Enum, Struct and Union Declarations ===================
class CDXMatrix4x4F;
//=== Enumerated Set Definitions ===================================
//=== Function Type Definitions ====================================
float det4x4( CDXMatrix4x4F *pIn ); float det3x3( float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3 ); float det2x2( float a, float b, float c, float d );
/*** CDX2DXForm ************
* This class implements basic matrix operation based on the GDI XFORM * structure. */ //const DX2DXFORM g_DX2DXFORMIdentity = { 1., 0., 0., 1., 0., 0., DX2DXO_IDENTITY };
class CDX2DXForm : public DX2DXFORM { /*=== Methods =======*/ public: /*--- Constructors ---*/ CDX2DXForm() { SetIdentity(); } CDX2DXForm( const CDX2DXForm& Other ) { memcpy( this, &Other, sizeof(*this) ); } CDX2DXForm( const DX2DXFORM& Other ) { memcpy( this, &Other, sizeof(*this) ); }
/*--- methods ---*/ void DetermineOp( void ); void Set( const DX2DXFORM& Other ) { memcpy( this, &Other, sizeof(*this) ); DetermineOp(); } void ZeroMatrix( void ) { memset( this, 0, sizeof( *this ) ); } void SetIdentity( void ) { eM11 = 1.; eM12 = 0.; eM21 = 0.; eM22 = 1.; eDx = 0.; eDy = 0.; eOp = DX2DXO_IDENTITY; } BOOL IsIdentity() const { return eOp == DX2DXO_IDENTITY; } void Scale( float sx, float sy ); void Rotate( float Rotation ); void Translate( float dx, float dy ); BOOL Invert(); void TransformBounds( const DXBNDS& Bnds, DXBNDS& ResultBnds ) const; void TransformPoints( const DXFPOINT InPnts[], DXFPOINT OutPnts[], ULONG ulCount ) const; void GetMinMaxScales( float& MinScale, float& MaxScale );
/*--- operators ---*/ DXFPOINT operator*( const DXFPOINT& v ) const; CDX2DXForm operator*( const CDX2DXForm& Other ) const; };
//=== CDX2DXForm methods ==============================================================
inline void CDX2DXForm::DetermineOp( void ) { if( ( eM12 == 0. ) && ( eM21 == 0. ) ) { if( ( eM11 == 1. ) && ( eM22 == 1. ) ) { eOp = ( ( eDx == 0 ) && ( eDy == 0 ) )?(DX2DXO_IDENTITY):(DX2DXO_TRANSLATE); } else { eOp = ( ( eDx == 0 ) && ( eDy == 0 ) )?(DX2DXO_SCALE):(DX2DXO_SCALE_AND_TRANS); } } else { eOp = ( ( eDx == 0 ) && ( eDy == 0 ) )?(DX2DXO_GENERAL):(DX2DXO_GENERAL_AND_TRANS); } } /* CDX2DXForm::DetermineOp */
inline float DXSq( float f ) { return f * f; }
// This function computes the Min and Max scale that a matrix represents.
// In other words, what is the maximum/minimum length that a line of length 1
// could get stretched/shrunk to if the line was transformed by this matrix.
//
// The function uses eigenvalues; and returns two float numbers. Both are
// non-negative; and MaxScale >= MinScale.
//
inline void CDX2DXForm::GetMinMaxScales( float& MinScale, float& MaxScale ) { if( ( eM12 == 0. ) && ( eM21 == 0. ) ) { // Let MinScale = abs(eM11)
if (eM11 < 0) MinScale = -eM11; else MinScale = eM11;
// Let MaxScale = abs(eM22)
if (eM22 < 0) MaxScale = -eM22; else MaxScale = eM22;
// Swap Min/Max if necessary
if (MinScale > MaxScale) { float flTemp = MinScale; MinScale = MaxScale; MaxScale = flTemp; } } else { float t1 = DXSq(eM11) + DXSq(eM12) + DXSq(eM21) + DXSq(eM22); if( t1 == 0. ) { MinScale = MaxScale = 0; } else { float t2 = (float)sqrt( (DXSq(eM12 + eM21) + DXSq(eM11 - eM22)) * (DXSq(eM12 - eM21) + DXSq(eM11 + eM22)) );
// Due to floating point error; t1 may end up less than t2;
// but that would mean that the min scale was small (relative
// to max scale)
if (t1 <= t2) MinScale = 0; else MinScale = (float)sqrt( (t1 - t2) * .5f );
MaxScale = (float)sqrt( (t1 + t2) * .5f ); } } } /* CDX2DXForm::GetMinMaxScales */
inline void CDX2DXForm::Rotate( float Rotation ) { double Angle = Rotation * (3.1415926535/180.0); float CosZ = (float)cos( Angle ); float SinZ = (float)sin( Angle ); if (CosZ > 0.0F && CosZ < 0.0000005F) { CosZ = .0F; } if (SinZ > -0.0000005F && SinZ < .0F) { SinZ = .0F; }
float M11 = ( CosZ * eM11 ) + ( SinZ * eM21 ); float M21 = (-SinZ * eM11 ) + ( CosZ * eM21 ); float M12 = ( CosZ * eM12 ) + ( SinZ * eM22 ); float M22 = (-SinZ * eM12 ) + ( CosZ * eM22 ); eM11 = M11; eM21 = M21; eM12 = M12; eM22 = M22; DetermineOp(); } /* CDX2DXForm::Rotate */
inline void CDX2DXForm::Scale( float sx, float sy ) { eM11 *= sx; eM12 *= sx; eDx *= sx; eM21 *= sy; eM22 *= sy; eDy *= sy; DetermineOp(); } /* CDX2DXForm::Scale */
inline void CDX2DXForm::Translate( float dx, float dy ) { eDx += dx; eDy += dy; DetermineOp(); } /* CDX2DXForm::Translate */
inline void CDX2DXForm::TransformBounds( const DXBNDS& Bnds, DXBNDS& ResultBnds ) const { ResultBnds = Bnds; if( eOp != DX2DXO_IDENTITY ) { ResultBnds.u.D[DXB_X].Min = (long)(( eM11 * Bnds.u.D[DXB_X].Min ) + ( eM12 * Bnds.u.D[DXB_Y].Min ) + eDx); ResultBnds.u.D[DXB_X].Max = (long)(( eM11 * Bnds.u.D[DXB_X].Max ) + ( eM12 * Bnds.u.D[DXB_Y].Max ) + eDx); ResultBnds.u.D[DXB_Y].Min = (long)(( eM21 * Bnds.u.D[DXB_X].Min ) + ( eM22 * Bnds.u.D[DXB_Y].Min ) + eDy); ResultBnds.u.D[DXB_Y].Max = (long)(( eM21 * Bnds.u.D[DXB_X].Max ) + ( eM22 * Bnds.u.D[DXB_Y].Max ) + eDy); } } /* CDX2DXForm::TransformBounds */
inline void CDX2DXForm::TransformPoints( const DXFPOINT InPnts[], DXFPOINT OutPnts[], ULONG ulCount ) const { ULONG i; switch( eOp ) { case DX2DXO_IDENTITY: memcpy( OutPnts, InPnts, ulCount * sizeof( DXFPOINT ) ); break; case DX2DXO_TRANSLATE: for( i = 0; i < ulCount; ++i ) { OutPnts[i].x = InPnts[i].x + eDx; OutPnts[i].y = InPnts[i].y + eDy; } break; case DX2DXO_SCALE: for( i = 0; i < ulCount; ++i ) { OutPnts[i].x = InPnts[i].x * eM11; OutPnts[i].y = InPnts[i].y * eM22; } break; case DX2DXO_SCALE_AND_TRANS: for( i = 0; i < ulCount; ++i ) { OutPnts[i].x = (InPnts[i].x * eM11) + eDx; OutPnts[i].y = (InPnts[i].y * eM22) + eDy; } break; case DX2DXO_GENERAL: for( i = 0; i < ulCount; ++i ) { OutPnts[i].x = ( InPnts[i].x * eM11 ) + ( InPnts[i].y * eM12 ); OutPnts[i].y = ( InPnts[i].x * eM21 ) + ( InPnts[i].y * eM22 ); } break; case DX2DXO_GENERAL_AND_TRANS: for( i = 0; i < ulCount; ++i ) { OutPnts[i].x = ( InPnts[i].x * eM11 ) + ( InPnts[i].y * eM12 ) + eDx; OutPnts[i].y = ( InPnts[i].x * eM21 ) + ( InPnts[i].y * eM22 ) + eDy; } break; default: _ASSERT( 0 ); // invalid operation id
} } /* CDX2DXForm::TransformPoints */
inline DXFPOINT CDX2DXForm::operator*( const DXFPOINT& v ) const { DXFPOINT NewPnt; NewPnt.x = ( v.x * eM11 ) + ( v.y * eM12 ) + eDx; NewPnt.y = ( v.x * eM21 ) + ( v.y * eM22 ) + eDy; return NewPnt; } /* CDX2DXForm::operator* */
inline CDX2DXForm CDX2DXForm::operator*( const CDX2DXForm& Other ) const { DX2DXFORM x; x.eM11 = ( eM11 * Other.eM11 ) + ( eM12 * Other.eM21 ); x.eM12 = ( eM11 * Other.eM12 ) + ( eM12 * Other.eM22 ); x.eDx = ( eM11 * Other.eDx ) + ( eM12 * Other.eDy ) + eDx;
x.eM21 = ( eM21 * Other.eM11 ) + ( eM22 * Other.eM21 ); x.eM22 = ( eM21 * Other.eM12 ) + ( eM22 * Other.eM22 ); x.eDy = ( eM21 * Other.eDx ) + ( eM22 * Other.eDy ) + eDy; return x; } /* CDX2DXForm::operator*= */
inline BOOL CDX2DXForm::Invert() { switch( eOp ) { case DX2DXO_IDENTITY: break; case DX2DXO_TRANSLATE: eDx = -eDx; eDy = -eDy; break; case DX2DXO_SCALE:
if (eM11 == 0.0 || eM22 == 0.0) return false; eM11 = 1.0f / eM11; eM22 = 1.0f / eM22; break;
case DX2DXO_SCALE_AND_TRANS: { if (eM11 == 0.0f || eM22 == 0.0f) return false;
// Our old equation was F = aG + b
// The inverse is G = F/a - b/a where a is eM11 and b is eDx
float flOneOverA = 1.0f / eM11; eDx = -eDx * flOneOverA; eM11 = flOneOverA;
// Our old equation was F = aG + b
// The inverse is G = F/a - b/a where a is eM22 and b is eDy
flOneOverA = 1.0f / eM22; eDy = -eDy * flOneOverA; eM22 = flOneOverA; break; }
case DX2DXO_GENERAL: case DX2DXO_GENERAL_AND_TRANS: { // The inverse of A= |a b| is | d -c|*(1/Det) where Det is the determinant of A
// |c d| |-b a|
// Det(A) = ad - bc
// Compute determininant
float flDet = (eM11 * eM22 - eM12 * eM21); if (flDet == 0.0f) return FALSE;
float flCoef = 1.0f / flDet;
// Remember old value of eM11
float flM11Original = eM11;
eM11 = flCoef * eM22; eM12 = -flCoef * eM12; eM21 = -flCoef * eM21; eM22 = flCoef * flM11Original;
// If we have a translation; then we need to
// compute new values for that translation
if (eOp == DX2DXO_GENERAL_AND_TRANS) { // Remember original value of eDx
float eDxOriginal = eDx;
eDx = -eM11 * eDx - eM12 * eDy; eDy = -eM21 * eDxOriginal - eM22 * eDy; } } break;
default: _ASSERT( 0 ); // invalid operation id
}
// We don't need to call DetermineOp here
// because the op doesn't change when inverted
// i.e. a scale remains a scale, etc.
return true; } /* CDX2DXForm::Invert */
/*** CDXMatrix4x4F ************
* This class implements basic matrix operation based on a 4x4 array. */ //const float g_DXMat4X4Identity[4][4] =
//{
// { 1.0, 0. , 0. , 0. },
// { 0. , 1.0, 0. , 0. },
// { 0. , 0. , 1.0, 0. },
// { 0. , 0. , 0. , 1.0 }
//};
class CDXMatrix4x4F { public: /*=== Member Data ===*/ float m_Coeff[4][4];
/*=== Methods =======*/ public: /*--- Constructors ---*/ CDXMatrix4x4F() { SetIdentity(); } CDXMatrix4x4F( const CDXMatrix4x4F& Other ) { CopyMemory( (void *)&m_Coeff, (void *)&Other.m_Coeff, sizeof(m_Coeff) ); } CDXMatrix4x4F( DX2DXFORM& XForm );
/*--- operations ---*/ void ZeroMatrix( void ) { memset( m_Coeff, 0, sizeof( m_Coeff ) ); } void SetIdentity( void ) { memset( m_Coeff, 0, sizeof( m_Coeff ) ); m_Coeff[0][0] = m_Coeff[1][1] = m_Coeff[2][2] = m_Coeff[3][3] = 1.0; } void SetCoefficients( float Coeff[4][4] ) { memcpy( m_Coeff, Coeff, sizeof( m_Coeff )); } void GetCoefficients( float Coeff[4][4] ) { memcpy( Coeff, m_Coeff, sizeof( m_Coeff )); }
//BOOL IsIdentity();
void Scale( float sx, float sy, float sz ); void Rotate( float rx, float ry, float rz ); void Translate( float dx, float dy, float dz ); BOOL Invert(); BOOL GetInverse( CDXMatrix4x4F *pIn ); void Transpose(); void GetTranspose( CDXMatrix4x4F *pIn ); void GetAdjoint( CDXMatrix4x4F *pIn ); HRESULT InitFromSafeArray( SAFEARRAY *psa ); HRESULT GetSafeArray( SAFEARRAY **ppsa ) const; void TransformBounds( DXBNDS& Bnds, DXBNDS& ResultBnds );
/*--- operators ---*/ CDXDVec operator*( CDXDVec& v) const; CDXCVec operator*( CDXCVec& v) const; CDXMatrix4x4F operator*(CDXMatrix4x4F Matrix) const; void operator*=(CDXMatrix4x4F Matrix) const; void CDXMatrix4x4F::operator=(const CDXMatrix4x4F srcMatrix); void CDXMatrix4x4F::operator+=(const CDXMatrix4x4F otherMatrix); void CDXMatrix4x4F::operator-=(const CDXMatrix4x4F otherMatrix); BOOL CDXMatrix4x4F::operator==(const CDXMatrix4x4F otherMatrix) const; BOOL CDXMatrix4x4F::operator!=(const CDXMatrix4x4F otherMatrix) const; };
inline CDXMatrix4x4F::CDXMatrix4x4F( DX2DXFORM& XForm ) { SetIdentity(); m_Coeff[0][0] = XForm.eM11; m_Coeff[0][1] = XForm.eM12; m_Coeff[1][0] = XForm.eM21; m_Coeff[1][1] = XForm.eM22; m_Coeff[0][3] = XForm.eDx; m_Coeff[1][3] = XForm.eDy; }
// Additional Operations
inline void CDXMatrix4x4F::operator=(const CDXMatrix4x4F srcMatrix) { CopyMemory( (void *)m_Coeff, (const void *)srcMatrix.m_Coeff, sizeof(srcMatrix.m_Coeff) ); } /* CDXMatrix4x4F::operator= */
inline BOOL CDXMatrix4x4F::operator==(const CDXMatrix4x4F otherMatrix) const { return !memcmp( (void *)m_Coeff, (const void *)otherMatrix.m_Coeff, sizeof(otherMatrix.m_Coeff) ); } /* CDXMatrix4x4F::operator== */
inline BOOL CDXMatrix4x4F::operator!=(const CDXMatrix4x4F otherMatrix) const { return memcmp( (void *)m_Coeff, (const void *)otherMatrix.m_Coeff, sizeof(otherMatrix.m_Coeff) ); } /* CDXMatrix4x4F::operator!= */
inline void CDXMatrix4x4F::operator+=(const CDXMatrix4x4F otherMatrix) { for( int i = 0; i < 4; i++ ) for( int j = 0; j < 4; j++ ) m_Coeff[i][j] += otherMatrix.m_Coeff[i][j]; } /* CDXMatrix4x4F::operator+= */
inline void CDXMatrix4x4F::operator-=(const CDXMatrix4x4F otherMatrix) { for( int i = 0; i < 4; i++ ) for( int j = 0; j < 4; j++ ) m_Coeff[i][j] -= otherMatrix.m_Coeff[i][j]; } /* CDXMatrix4x4F::operator-= */
inline CDXDVec CDXMatrix4x4F::operator*(CDXDVec& v) const { CDXDVec t; float temp; temp = v[0]*m_Coeff[0][0]+v[1]*m_Coeff[1][0]+v[2]*m_Coeff[2][0]+v[3]*m_Coeff[3][0]; t[0] = (long)((temp < 0) ? temp -= .5 : temp += .5); temp = v[0]*m_Coeff[0][1]+v[1]*m_Coeff[1][1]+v[2]*m_Coeff[2][1]+v[3]*m_Coeff[3][1]; t[1] = (long)((temp < 0) ? temp -= .5 : temp += .5); temp = v[0]*m_Coeff[0][2]+v[1]*m_Coeff[1][2]+v[2]*m_Coeff[2][2]+v[3]*m_Coeff[3][2]; t[2] = (long)((temp < 0) ? temp -= .5 : temp += .5); temp = v[0]*m_Coeff[0][3]+v[1]*m_Coeff[1][3]+v[2]*m_Coeff[2][3]+v[3]*m_Coeff[3][3]; t[3] = (long)((temp < 0) ? temp -= .5 : temp += .5); return t; } /* CDXMatrix4x4F::operator*(DXDVEC) */
inline CDXCVec CDXMatrix4x4F::operator*(CDXCVec& v) const { CDXCVec t; t[0] = v[0]*m_Coeff[0][0]+v[1]*m_Coeff[1][0]+v[2]*m_Coeff[2][0]+v[3]*m_Coeff[3][0]; t[1] = v[0]*m_Coeff[0][1]+v[1]*m_Coeff[1][1]+v[2]*m_Coeff[2][1]+v[3]*m_Coeff[3][1]; t[2] = v[0]*m_Coeff[0][2]+v[1]*m_Coeff[1][2]+v[2]*m_Coeff[2][2]+v[3]*m_Coeff[3][2]; t[3] = v[0]*m_Coeff[0][3]+v[1]*m_Coeff[1][3]+v[2]*m_Coeff[2][3]+v[3]*m_Coeff[3][3]; return t; } /* CDXMatrix4x4F::operator*(DXCVEC) */
inline CDXMatrix4x4F CDXMatrix4x4F::operator*(CDXMatrix4x4F Mx) const { CDXMatrix4x4F t; int i, j;
for( i = 0; i < 4; i++ ) { for( j = 0; j < 4; j++ ) { t.m_Coeff[i][j] = m_Coeff[i][0] * Mx.m_Coeff[0][j] + m_Coeff[i][1] * Mx.m_Coeff[1][j] + m_Coeff[i][2] * Mx.m_Coeff[2][j] + m_Coeff[i][3] * Mx.m_Coeff[3][j]; } }
return t; } /* CDXMatrix4x4F::operator*(CDXMatrix4x4F) */ inline void CDXMatrix4x4F::operator*=(CDXMatrix4x4F Mx) const { CDXMatrix4x4F t; int i, j;
for( i = 0; i < 4; i++ ) { for( j = 0; j < 4; j++ ) { t.m_Coeff[i][j] = m_Coeff[i][0] * Mx.m_Coeff[0][j] + m_Coeff[i][1] * Mx.m_Coeff[1][j] + m_Coeff[i][2] * Mx.m_Coeff[2][j] + m_Coeff[i][3] * Mx.m_Coeff[3][j]; } }
CopyMemory( (void *)m_Coeff, (void *)t.m_Coeff, sizeof(m_Coeff) ); } /* CDXMatrix4x4F::operator*=(CDXMatrix4x4F) */
inline void CDXMatrix4x4F::Scale( float sx, float sy, float sz ) { if( sx != 1. ) { m_Coeff[0][0] *= sx; m_Coeff[0][1] *= sx; m_Coeff[0][2] *= sx; m_Coeff[0][3] *= sx; } if( sy != 1. ) { m_Coeff[1][0] *= sy; m_Coeff[1][1] *= sy; m_Coeff[1][2] *= sy; m_Coeff[1][3] *= sy; } if( sz != 1. ) { m_Coeff[2][0] *= sz; m_Coeff[2][1] *= sz; m_Coeff[2][2] *= sz; m_Coeff[2][3] *= sz; } } /* CDXMatrix4x4F::Scale */
inline void CDXMatrix4x4F::Translate( float dx, float dy, float dz ) { float a, b, c, d; a = b = c = d = 0; if( dx != 0. ) { a += m_Coeff[0][0]*dx; b += m_Coeff[0][1]*dx; c += m_Coeff[0][2]*dx; d += m_Coeff[0][3]*dx; } if( dy != 0. ) { a += m_Coeff[1][0]*dy; b += m_Coeff[1][1]*dy; c += m_Coeff[1][2]*dy; d += m_Coeff[1][3]*dy; } if( dz != 0. ) { a += m_Coeff[2][0]*dz; b += m_Coeff[2][1]*dz; c += m_Coeff[2][2]*dz; d += m_Coeff[2][3]*dz; } m_Coeff[3][0] += a; m_Coeff[3][1] += b; m_Coeff[3][2] += c; m_Coeff[3][3] += d; } /* CDXMatrix4x4F::Translate */
inline void CDXMatrix4x4F::Rotate( float rx, float ry, float rz ) { const float l_dfCte = (const float)(3.1415926535/180.0);
float lAngleY = 0.0; float lAngleX = 0.0; float lAngleZ = 0.0; float lCosX = 1.0; float lSinX = 0.0; float lCosY = 1.0; float lSinY = 0.0; float lCosZ = 1.0; float lSinZ = 0.0;
// calculate rotation angle sines and cosines
if( rx != 0 ) { lAngleX = rx * l_dfCte; lCosX = (float)cos(lAngleX); lSinX = (float)sin(lAngleX); if (lCosX > 0.0F && lCosX < 0.0000005F) { lCosX = .0F; } if (lSinX > -0.0000005F && lSinX < .0F) { lSinX = .0F; } } if( ry != 0 ) { lAngleY = ry * l_dfCte; lCosY = (float)cos(lAngleY); lSinY = (float)sin(lAngleY); if (lCosY > 0.0F && lCosY < 0.0000005F) { lCosY = .0F; } if (lSinY > -0.0000005F && lSinY < .0F) { lSinY = .0F; } } if( rz != 0 ) { lAngleZ = rz * l_dfCte; lCosZ = (float)cos(lAngleZ); lSinZ = (float)sin(lAngleZ); if (lCosZ > 0.0F && lCosZ < 0.0000005F) { lCosZ = .0F; } if (lSinZ > -0.0000005F && lSinZ < .0F) { lSinZ = .0F; } }
float u, v; int i;
//--- X Rotation
for( i = 0; i < 4; i++ ) { u = m_Coeff[1][i]; v = m_Coeff[2][i]; m_Coeff[1][i] = lCosX*u+lSinX*v; m_Coeff[2][i] = -lSinX*u+lCosX*v; }
//--- Y Rotation
for( i = 0; i < 4; i++ ) { u = m_Coeff[0][i]; v = m_Coeff[2][i]; m_Coeff[0][i] = lCosY*u-lSinY*v; m_Coeff[2][i] = lSinY*u+lCosY*v; }
//--- Z Rotation
for( i = 0; i < 4; i++ ) { u = m_Coeff[0][i]; v = m_Coeff[1][i]; m_Coeff[0][i] = lCosZ*u+lSinZ*v; m_Coeff[1][i] = -lSinZ*u+lCosZ*v; } }
/*
inline BOOL CDXMatrix4x4F::IsIdentity() { return !memcmp( m_Coeff, g_DXMat4X4Identity, sizeof(g_DXMat4X4Identity) ); } /* CDXMatrix4x4F::IsIdentity */
/*
Uses Gaussian elimination to invert the 4 x 4 non-linear matrix in t and return the result in Mx. The matrix t is destroyed in the process. */ inline BOOL CDXMatrix4x4F::Invert() { int i,j,k,Pivot; float PValue; CDXMatrix4x4F Mx; Mx.SetIdentity();
/* Find pivot element. Use partial pivoting by row */ for( i = 0;i < 4; i++ ) { Pivot = 0; for( j = 0; j < 4; j++ ) { if( fabs(m_Coeff[i][j]) > fabs(m_Coeff[i][Pivot]) ) Pivot = j; }
if( m_Coeff[i][Pivot] == 0.0 ) { ZeroMatrix(); /* Singular Matrix */ return FALSE; }
/* Normalize */ PValue = m_Coeff[i][Pivot]; for( j = 0; j < 4; j++ ) { m_Coeff[i][j] /= PValue; Mx.m_Coeff[i][j] /= PValue; }
/* Zeroing */ for( j = 0; j < 4; j++ ) { if( j != i ) { PValue = m_Coeff[j][Pivot]; for( k = 0; k < 4; k++ ) { m_Coeff[j][k] -= PValue*m_Coeff[i][k]; Mx.m_Coeff[j][k] -= PValue*Mx.m_Coeff[i][k]; } } } }
/* Reorder rows */ for( i = 0; i < 4; i++ ) { if( m_Coeff[i][i] != 1.0 ) { for( j = i + 1; j < 4; j++ ) if( m_Coeff[j][i] == 1.0 ) break; if( j >= 4 ) { ZeroMatrix(); return FALSE; }
//--- swap rows i and j of original
for( k = 0; k < 4; k++ ) { m_Coeff[i][k] += m_Coeff[j][k]; m_Coeff[j][k] = m_Coeff[i][k] - m_Coeff[j][k]; m_Coeff[i][k] -= m_Coeff[j][k]; } //--- swap rows i and j of result
for( k = 0; k < 4; k++ ) { Mx.m_Coeff[i][k] += Mx.m_Coeff[j][k]; Mx.m_Coeff[j][k] = Mx.m_Coeff[i][k] - Mx.m_Coeff[j][k]; Mx.m_Coeff[i][k] -= Mx.m_Coeff[j][k]; } } } *this = Mx; return TRUE; } /* CDXMatrix4x4F::Invert */
inline void CDXMatrix4x4F::Transpose() { float temp;
temp = m_Coeff[0][1]; m_Coeff[0][1] = m_Coeff[1][0]; m_Coeff[1][0] = temp;
temp = m_Coeff[0][2]; m_Coeff[0][2] = m_Coeff[2][0]; m_Coeff[2][0] = temp;
temp = m_Coeff[0][3]; m_Coeff[0][3] = m_Coeff[3][0]; m_Coeff[3][0] = temp;
temp = m_Coeff[1][2]; m_Coeff[1][2] = m_Coeff[2][1]; m_Coeff[2][1] = temp;
temp = m_Coeff[1][3]; m_Coeff[1][3] = m_Coeff[3][1]; m_Coeff[3][1] = temp;
temp = m_Coeff[2][3]; m_Coeff[2][3] = m_Coeff[3][2]; m_Coeff[3][2] = temp;
} /* CDXMatrix4x4F::Transpose */
inline void CDXMatrix4x4F::GetTranspose( CDXMatrix4x4F *m ) { float temp;
(*this) = *m;
temp = m_Coeff[0][1]; m_Coeff[0][1] = m_Coeff[1][0]; m_Coeff[1][0] = temp;
temp = m_Coeff[0][2]; m_Coeff[0][2] = m_Coeff[2][0]; m_Coeff[2][0] = temp;
temp = m_Coeff[0][3]; m_Coeff[0][3] = m_Coeff[3][0]; m_Coeff[3][0] = temp;
temp = m_Coeff[1][2]; m_Coeff[1][2] = m_Coeff[2][1]; m_Coeff[2][1] = temp;
temp = m_Coeff[1][3]; m_Coeff[1][3] = m_Coeff[3][1]; m_Coeff[3][1] = temp;
temp = m_Coeff[2][3]; m_Coeff[2][3] = m_Coeff[3][2]; m_Coeff[3][2] = temp;
} /* CDXMatrix4x4F::Transpose */
/*
Matrix Inversion by Richard Carling from "Graphics Gems", Academic Press, 1990 */
#define SMALL_NUMBER 1.e-8
/*
* inverse( original_matrix, inverse_matrix ) * * calculate the inverse of a 4x4 matrix * * -1 * A = ___1__ adjoint A * det A */
inline BOOL CDXMatrix4x4F::GetInverse( CDXMatrix4x4F *pIn ) { int i, j; float det;
/* calculate the adjoint matrix */
GetAdjoint( pIn );
/* calculate the 4x4 determinant
* if the determinant is zero, * then the inverse matrix is not unique. */
det = det4x4( pIn );
if( fabs( det ) < SMALL_NUMBER ) { // Non-singular matrix, no inverse!
return FALSE;; }
/* scale the adjoint matrix to get the inverse */
for( i = 0; i < 4; i++ ) for( j = 0; j < 4; j++ ) m_Coeff[i][j] = m_Coeff[i][j] / det;
return TRUE; }
/*
* adjoint( original_matrix, inverse_matrix ) * * calculate the adjoint of a 4x4 matrix * * Let a denote the minor determinant of matrix A obtained by * ij * * deleting the ith row and jth column from A. * * i+j * Let b = (-1) a * ij ji * * The matrix B = (b ) is the adjoint of A * ij */ inline void CDXMatrix4x4F::GetAdjoint( CDXMatrix4x4F *pIn ) { float a1, a2, a3, a4, b1, b2, b3, b4; float c1, c2, c3, c4, d1, d2, d3, d4;
/* assign to individual variable names to aid */ /* selecting correct values */
a1 = pIn->m_Coeff[0][0]; b1 = pIn->m_Coeff[0][1]; c1 = pIn->m_Coeff[0][2]; d1 = pIn->m_Coeff[0][3];
a2 = pIn->m_Coeff[1][0]; b2 = pIn->m_Coeff[1][1]; c2 = pIn->m_Coeff[1][2]; d2 = pIn->m_Coeff[1][3];
a3 = pIn->m_Coeff[2][0]; b3 = pIn->m_Coeff[2][1]; c3 = pIn->m_Coeff[2][2]; d3 = pIn->m_Coeff[2][3];
a4 = pIn->m_Coeff[3][0]; b4 = pIn->m_Coeff[3][1]; c4 = pIn->m_Coeff[3][2]; d4 = pIn->m_Coeff[3][3];
/* row column labeling reversed since we transpose rows & columns */
m_Coeff[0][0] = det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4); m_Coeff[1][0] = - det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4); m_Coeff[2][0] = det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4); m_Coeff[3][0] = - det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4); m_Coeff[0][1] = - det3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4); m_Coeff[1][1] = det3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4); m_Coeff[2][1] = - det3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4); m_Coeff[3][1] = det3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4); m_Coeff[0][2] = det3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4); m_Coeff[1][2] = - det3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4); m_Coeff[2][2] = det3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4); m_Coeff[3][2] = - det3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4); m_Coeff[0][3] = - det3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3); m_Coeff[1][3] = det3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3); m_Coeff[2][3] = - det3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3); m_Coeff[3][3] = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3); } /*
* float = det4x4( matrix ) * * calculate the determinant of a 4x4 matrix. */ inline float det4x4( CDXMatrix4x4F *pIn ) { float ans; float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
/* assign to individual variable names to aid selecting */ /* correct elements */
a1 = pIn->m_Coeff[0][0]; b1 = pIn->m_Coeff[0][1]; c1 = pIn->m_Coeff[0][2]; d1 = pIn->m_Coeff[0][3];
a2 = pIn->m_Coeff[1][0]; b2 = pIn->m_Coeff[1][1]; c2 = pIn->m_Coeff[1][2]; d2 = pIn->m_Coeff[1][3];
a3 = pIn->m_Coeff[2][0]; b3 = pIn->m_Coeff[2][1]; c3 = pIn->m_Coeff[2][2]; d3 = pIn->m_Coeff[2][3];
a4 = pIn->m_Coeff[3][0]; b4 = pIn->m_Coeff[3][1]; c4 = pIn->m_Coeff[3][2]; d4 = pIn->m_Coeff[3][3];
ans = a1 * det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4 ) - b1 * det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4 ) + c1 * det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4 ) - d1 * det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4 ); return ans; }
/*
* float = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 ) * * calculate the determinant of a 3x3 matrix * in the form * * | a1, b1, c1 | * | a2, b2, c2 | * | a3, b3, c3 | */
inline float det3x3( float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3 ) { float ans;
ans = a1 * det2x2( b2, b3, c2, c3 ) - b1 * det2x2( a2, a3, c2, c3 ) + c1 * det2x2( a2, a3, b2, b3 ); return ans; }
/*
* float = det2x2( float a, float b, float c, float d ) * * calculate the determinant of a 2x2 matrix. */ inline float det2x2( float a, float b, float c, float d ) { float ans = a * d - b * c; return ans; }
inline HRESULT CDXMatrix4x4F::InitFromSafeArray( SAFEARRAY * /*pSA*/ ) { HRESULT hr = S_OK; #if 0
long *pData;
if( !pSA || ( pSA->cDims != 1 ) || ( pSA->cbElements != sizeof(float) ) || ( pSA->rgsabound->lLbound != 1 ) || ( pSA->rgsabound->cElements != 8 ) ) { hr = E_INVALIDARG; } else { hr = SafeArrayAccessData(pSA, (void **)&pData);
if( SUCCEEDED( hr ) ) { for( int i = 0; i < 4; ++i ) { m_Bounds[i].Min = pData[i]; m_Bounds[i].Max = pData[i+4]; m_Bounds[i].SampleRate = SampleRate; }
hr = SafeArrayUnaccessData( pSA ); } } #endif
return hr; } /* CDXMatrix4x4F::InitFromSafeArray */
inline HRESULT CDXMatrix4x4F::GetSafeArray( SAFEARRAY ** /*ppSA*/ ) const { HRESULT hr = S_OK; #if 0
SAFEARRAY *pSA;
if( !ppSA ) { hr = E_POINTER; } else { SAFEARRAYBOUND rgsabound; rgsabound.lLbound = 1; rgsabound.cElements = 16;
if( !(pSA = SafeArrayCreate( VT_I4, 1, &rgsabound ) ) ) { hr = E_OUTOFMEMORY; } else { long *pData; hr = SafeArrayAccessData( pSA, (void **)&pData );
if( SUCCEEDED( hr ) ) { for( int i = 0; i < 4; ++i ) { pData[i] = m_Bounds[i].Min; pData[i+4] = m_Bounds[i].Max; }
hr = SafeArrayUnaccessData( pSA ); } }
if( SUCCEEDED( hr ) ) { *ppSA = pSA; } } #endif
return hr; } /* CDXMatrix4x4F::GetSafeArray */
inline void CDXMatrix4x4F::TransformBounds( DXBNDS& /*Bnds*/, DXBNDS& /*ResultBnds*/ ) {
} /* CDXMatrix4x4F::TransformBounds */
#endif // __DXTPRIV_H_
|