You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
6.1 KiB
332 lines
6.1 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef NMATRIX_H |
|
#define NMATRIX_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
|
|
#include <assert.h> |
|
#include "nvector.h" |
|
|
|
|
|
#define NMatrixMN NMatrix<M,N> |
|
|
|
|
|
template<int M, int N> |
|
class NMatrix |
|
{ |
|
public: |
|
|
|
NMatrixMN() {} |
|
|
|
static NMatrixMN SetupNMatrixNull(); // Return a matrix of all zeros. |
|
static NMatrixMN SetupNMatrixIdentity(); // Return an identity matrix. |
|
|
|
NMatrixMN const& operator=( NMatrixMN const &other ); |
|
|
|
NMatrixMN operator+( NMatrixMN const &v ) const; |
|
NMatrixMN const& operator+=( NMatrixMN const &v ); |
|
|
|
NMatrixMN operator-() const; |
|
NMatrixMN operator-( NMatrixMN const &v ) const; |
|
|
|
// Multiplies the column vector on the right-hand side. |
|
NVector<M> operator*( NVector<N> const &v ) const; |
|
|
|
// Can't get the compiler to work with a real MxN * NxR matrix multiply... |
|
NMatrix<M,M> operator*( NMatrix<N,M> const &b ) const; |
|
|
|
NMatrixMN operator*( float val ) const; |
|
|
|
bool InverseGeneral( NMatrixMN &mInverse ) const; |
|
NMatrix<N,M> Transpose() const; |
|
|
|
|
|
public: |
|
|
|
float m[M][N]; |
|
}; |
|
|
|
|
|
|
|
// Return the matrix generated by multiplying a column vector 'a' by row vector 'b'. |
|
template<int N> |
|
inline NMatrix<N,N> OuterProduct( NVectorN const &a, NVectorN const &b ) |
|
{ |
|
NMatrix<N,N> ret; |
|
|
|
for( int i=0; i < N; i++ ) |
|
for( int j=0; j < N; j++ ) |
|
ret.m[i][j] = a.v[i] * b.v[j]; |
|
|
|
return ret; |
|
} |
|
|
|
|
|
// -------------------------------------------------------------------------------- // |
|
// NMatrix inlines. |
|
// -------------------------------------------------------------------------------- // |
|
|
|
template<int M, int N> |
|
inline NMatrixMN NMatrixMN::SetupNMatrixNull() |
|
{ |
|
NMatrix ret; |
|
memset( ret.m, 0, sizeof(float)*M*N ); |
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN NMatrixMN::SetupNMatrixIdentity() |
|
{ |
|
assert( M == N ); // Identity matrices must be square. |
|
|
|
NMatrix ret; |
|
memset( ret.m, 0, sizeof(float)*M*N ); |
|
for( int i=0; i < N; i++ ) |
|
ret.m[i][i] = 1; |
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN const &NMatrixMN::operator=( NMatrixMN const &v ) |
|
{ |
|
memcpy( m, v.m, sizeof(float)*M*N ); |
|
return *this; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN NMatrixMN::operator+( NMatrixMN const &v ) const |
|
{ |
|
NMatrixMN ret; |
|
for( int i=0; i < M; i++ ) |
|
for( int j=0; j < N; j++ ) |
|
ret.m[i][j] = m[i][j] + v.m[i][j]; |
|
|
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN const &NMatrixMN::operator+=( NMatrixMN const &v ) |
|
{ |
|
for( int i=0; i < M; i++ ) |
|
for( int j=0; j < N; j++ ) |
|
m[i][j] += v.m[i][j]; |
|
|
|
return *this; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN NMatrixMN::operator-() const |
|
{ |
|
NMatrixMN ret; |
|
|
|
for( int i=0; i < M*N; i++ ) |
|
((float*)ret.m)[i] = -((float*)m)[i]; |
|
|
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN NMatrixMN::operator-( NMatrixMN const &v ) const |
|
{ |
|
NMatrixMN ret; |
|
for( int i=0; i < M; i++ ) |
|
for( int j=0; j < N; j++ ) |
|
ret.m[i][j] = m[i][j] - v.m[i][j]; |
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NVector<M> NMatrixMN::operator*( NVectorN const &v ) const |
|
{ |
|
NVectorN ret; |
|
|
|
for( int i=0; i < M; i++ ) |
|
{ |
|
ret.v[i] = 0; |
|
|
|
for( int j=0; j < N; j++ ) |
|
ret.v[i] += m[i][j] * v.v[j]; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrix<M,M> NMatrixMN::operator*( NMatrix<N,M> const &b ) const |
|
{ |
|
NMatrix<M,M> ret; |
|
|
|
for( int myRow=0; myRow < M; myRow++ ) |
|
{ |
|
for( int otherCol=0; otherCol < M; otherCol++ ) |
|
{ |
|
ret[myRow][otherCol] = 0; |
|
for( int i=0; i < N; i++ ) |
|
ret[myRow][otherCol] += a.m[myRow][i] * b.m[i][otherCol]; |
|
} |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrixMN NMatrixMN::operator*( float val ) const |
|
{ |
|
NMatrixMN ret; |
|
|
|
for( int i=0; i < N*M; i++ ) |
|
((float*)ret.m)[i] = ((float*)m)[i] * val; |
|
|
|
return ret; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
bool NMatrixMN::InverseGeneral( NMatrixMN &mInverse ) const |
|
{ |
|
int iRow, i, j, iTemp, iTest; |
|
float mul, fTest, fLargest; |
|
float mat[N][2*N]; |
|
int rowMap[N], iLargest; |
|
float *pOut, *pRow, *pScaleRow; |
|
|
|
|
|
// Can only invert square matrices. |
|
if( M != N ) |
|
{ |
|
assert( !"Tried to invert a non-square matrix" ); |
|
return false; |
|
} |
|
|
|
|
|
// How it's done. |
|
// AX = I |
|
// A = this |
|
// X = the matrix we're looking for |
|
// I = identity |
|
|
|
// Setup AI |
|
for(i=0; i < N; i++) |
|
{ |
|
const float *pIn = m[i]; |
|
pOut = mat[i]; |
|
|
|
for(j=0; j < N; j++) |
|
{ |
|
pOut[j] = pIn[j]; |
|
} |
|
|
|
for(j=N; j < 2*N; j++) |
|
pOut[j] = 0; |
|
|
|
pOut[i+N] = 1.0f; |
|
|
|
rowMap[i] = i; |
|
} |
|
|
|
// Use row operations to get to reduced row-echelon form using these rules: |
|
// 1. Multiply or divide a row by a nonzero number. |
|
// 2. Add a multiple of one row to another. |
|
// 3. Interchange two rows. |
|
|
|
for(iRow=0; iRow < N; iRow++) |
|
{ |
|
// Find the row with the largest element in this column. |
|
fLargest = 0.001f; |
|
iLargest = -1; |
|
for(iTest=iRow; iTest < N; iTest++) |
|
{ |
|
fTest = (float)fabs(mat[rowMap[iTest]][iRow]); |
|
if(fTest > fLargest) |
|
{ |
|
iLargest = iTest; |
|
fLargest = fTest; |
|
} |
|
} |
|
|
|
// They're all too small.. sorry. |
|
if(iLargest == -1) |
|
{ |
|
return false; |
|
} |
|
|
|
// Swap the rows. |
|
iTemp = rowMap[iLargest]; |
|
rowMap[iLargest] = rowMap[iRow]; |
|
rowMap[iRow] = iTemp; |
|
|
|
pRow = mat[rowMap[iRow]]; |
|
|
|
// Divide this row by the element. |
|
mul = 1.0f / pRow[iRow]; |
|
for(j=0; j < 2*N; j++) |
|
pRow[j] *= mul; |
|
|
|
pRow[iRow] = 1.0f; // Preserve accuracy... |
|
|
|
// Eliminate this element from the other rows using operation 2. |
|
for(i=0; i < N; i++) |
|
{ |
|
if(i == iRow) |
|
continue; |
|
|
|
pScaleRow = mat[rowMap[i]]; |
|
|
|
// Multiply this row by -(iRow*the element). |
|
mul = -pScaleRow[iRow]; |
|
for(j=0; j < 2*N; j++) |
|
{ |
|
pScaleRow[j] += pRow[j] * mul; |
|
} |
|
|
|
pScaleRow[iRow] = 0.0f; // Preserve accuracy... |
|
} |
|
} |
|
|
|
// The inverse is on the right side of AX now (the identity is on the left). |
|
for(i=0; i < N; i++) |
|
{ |
|
const float *pIn = mat[rowMap[i]] + N; |
|
pOut = mInverse.m[i]; |
|
|
|
for(j=0; j < N; j++) |
|
{ |
|
pOut[j] = pIn[j]; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
template<int M, int N> |
|
inline NMatrix<N,M> NMatrixMN::Transpose() const |
|
{ |
|
NMatrix<N,M> ret; |
|
|
|
for( int i=0; i < M; i++ ) |
|
for( int j=0; j < N; j++ ) |
|
ret.m[j][i] = m[i][j]; |
|
|
|
return ret; |
|
} |
|
|
|
#endif // NMATRIX_H |
|
|
|
|