C++程序  |  1081行  |  16.73 KB

/*****************************************************************************/
// Copyright 2006-2008 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_matrix.cpp#1 $ */ 
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */

/*****************************************************************************/

#include "dng_matrix.h"

#include "dng_exceptions.h"
#include "dng_utils.h"

/*****************************************************************************/
				
dng_matrix::dng_matrix ()
						
	:	fRows (0)
	,	fCols (0)
	
	{
	
	}
					
/*****************************************************************************/
				
dng_matrix::dng_matrix (uint32 rows,
						uint32 cols)
						
	:	fRows (0)
	,	fCols (0)
	
	{
	
	if (rows < 1 || rows > kMaxColorPlanes ||
		cols < 1 || cols > kMaxColorPlanes)
		{
		
		ThrowProgramError ();
		
		}
	
	fRows = rows;
	fCols = cols;
	
	for (uint32 row = 0; row < fRows; row++)
		for (uint32 col = 0; col < fCols; col++)
			{
			
			fData [row] [col] = 0.0;
			
			}
	
	}
					
/*****************************************************************************/
				
dng_matrix::dng_matrix (const dng_matrix &m)

	:	fRows (m.fRows)
	,	fCols (m.fCols)
	
	{
	
	for (uint32 row = 0; row < fRows; row++)
		for (uint32 col = 0; col < fCols; col++)
			{
			
			fData [row] [col] = m.fData [row] [col];
			
			}
	
	}
					
/*****************************************************************************/
				
void dng_matrix::Clear ()	
	{
	
	fRows = 0;
	fCols = 0;
	
	}
				
/*****************************************************************************/
				
void dng_matrix::SetIdentity (uint32 count)	
	{
	
	*this = dng_matrix (count, count);
	
	for (uint32 j = 0; j < count; j++)
		{
		
		fData [j] [j] = 1.0;
		
		}
	
	}
				
/******************************************************************************/

bool dng_matrix::operator== (const dng_matrix &m) const
	{
	
	if (Rows () != m.Rows () ||
	    Cols () != m.Cols ())
		{
		
		return false;
		
		}
	
	for (uint32 j = 0; j < Rows (); j++)	
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			if (fData [j] [k] != m.fData [j] [k])
				{
				
				return false;
				
				}
			
			}
			
	return true;
	
	}

/******************************************************************************/

bool dng_matrix::IsDiagonal () const
	{
	
	if (IsEmpty ())
		{
		return false;
		}
	
	if (Rows () != Cols ())
		{
		return false;
		}
	
	for (uint32 j = 0; j < Rows (); j++)
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			if (j != k)
				{
				
				if (fData [j] [k] != 0.0)
					{
					return false;
					}
				
				}
			
			}
			
	return true;
	
	}

/******************************************************************************/

real64 dng_matrix::MaxEntry () const
	{
	
	if (IsEmpty ())
		{
		
		return 0.0;
		
		}
	
	real64 m = fData [0] [0];
	
	for (uint32 j = 0; j < Rows (); j++)
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			m = Max_real64 (m, fData [j] [k]);
			
			}
			
	return m;
	
	}
		
/******************************************************************************/

real64 dng_matrix::MinEntry () const
	{
	
	if (IsEmpty ())
		{
		
		return 0.0;
		
		}
	
	real64 m = fData [0] [0];
	
	for (uint32 j = 0; j < Rows (); j++)
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			m = Min_real64 (m, fData [j] [k]);
			
			}
			
	return m;
	
	}
		
/*****************************************************************************/

void dng_matrix::Scale (real64 factor)
	{
	
	for (uint32 j = 0; j < Rows (); j++)	
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			fData [j] [k] *= factor;
			
			}
			
	}
			
/*****************************************************************************/

void dng_matrix::Round (real64 factor)
	{
	
	real64 invFactor = 1.0 / factor;
	
	for (uint32 j = 0; j < Rows (); j++)	
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			fData [j] [k] = Round_int32 (fData [j] [k] * factor) * invFactor;
			
			}
			
	}
	
/*****************************************************************************/

void dng_matrix::SafeRound (real64 factor)
	{
	
	real64 invFactor = 1.0 / factor;
	
	for (uint32 j = 0; j < Rows (); j++)
		{
		
		// Round each row to the specified accuracy, but make sure the
		// a rounding does not affect the total of the elements in a row
		// more than necessary.
		
		real64 error = 0.0;
		
		for (uint32 k = 0; k < Cols (); k++)
			{
			
			fData [j] [k] += error;
			
			real64 rounded = Round_int32 (fData [j] [k] * factor) * invFactor;
			
			error = fData [j] [k] - rounded;
			
			fData [j] [k] = rounded;
			
			}
		
		}
		
	}

/*****************************************************************************/

dng_matrix_3by3::dng_matrix_3by3 ()

	:	dng_matrix (3, 3)
	
	{
	}
		
/*****************************************************************************/

dng_matrix_3by3::dng_matrix_3by3 (const dng_matrix &m)

	:	dng_matrix (m)
	
	{
	
	if (Rows () != 3 ||
		Cols () != 3)
		{
		
		ThrowMatrixMath ();
		
		}
	
	}
		
/*****************************************************************************/

dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a01, real64 a02,
				        		  real64 a10, real64 a11, real64 a12,
				        		  real64 a20, real64 a21, real64 a22)
				        	   

	:	dng_matrix (3, 3)
	
	{
	
	fData [0] [0] = a00;
	fData [0] [1] = a01;
	fData [0] [2] = a02;
	
	fData [1] [0] = a10;
	fData [1] [1] = a11;
	fData [1] [2] = a12;
	
	fData [2] [0] = a20;
	fData [2] [1] = a21;
	fData [2] [2] = a22;
	
	}

/*****************************************************************************/

dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a11, real64 a22)

	:	dng_matrix (3, 3)
	
	{
	
	fData [0] [0] = a00;
	fData [1] [1] = a11;
	fData [2] [2] = a22;
	
	}

/*****************************************************************************/

dng_matrix_4by3::dng_matrix_4by3 ()

	:	dng_matrix (4, 3)
	
	{
	}
		
/*****************************************************************************/

dng_matrix_4by3::dng_matrix_4by3 (const dng_matrix &m)

	:	dng_matrix (m)
	
	{
	
	if (Rows () != 4 ||
		Cols () != 3)
		{
		
		ThrowMatrixMath ();
		
		}
	
	}
		
/*****************************************************************************/

dng_matrix_4by3::dng_matrix_4by3 (real64 a00, real64 a01, real64 a02,
				       			  real64 a10, real64 a11, real64 a12,
				        		  real64 a20, real64 a21, real64 a22,
				        		  real64 a30, real64 a31, real64 a32)
				        	   

	:	dng_matrix (4, 3)
	
	{
	
	fData [0] [0] = a00;
	fData [0] [1] = a01;
	fData [0] [2] = a02;
	
	fData [1] [0] = a10;
	fData [1] [1] = a11;
	fData [1] [2] = a12;
	
	fData [2] [0] = a20;
	fData [2] [1] = a21;
	fData [2] [2] = a22;
	
	fData [3] [0] = a30;
	fData [3] [1] = a31;
	fData [3] [2] = a32;
	
	}

/*****************************************************************************/
				
dng_vector::dng_vector ()

	:	fCount (0)
	
	{
	
	}
					
/*****************************************************************************/
				
dng_vector::dng_vector (uint32 count)

	:	fCount (0)
	
	{
	
	if (count < 1 || count > kMaxColorPlanes)
		{
		
		ThrowProgramError ();
		
		}
	
	fCount = count;
	
	for (uint32 index = 0; index < fCount; index++)
		{
		
		fData [index] = 0.0;
		
		}
	
	}
					
/*****************************************************************************/
				
dng_vector::dng_vector (const dng_vector &v)

	:	fCount (v.fCount)
	
	{
	
	for (uint32 index = 0; index < fCount; index++)
		{
		
		fData [index] = v.fData [index];
		
		}
	
	}
					
/*****************************************************************************/
				
void dng_vector::Clear ()	
	{
	
	fCount = 0;
	
	}
				
/*****************************************************************************/
				
void dng_vector::SetIdentity (uint32 count)	
	{
	
	*this = dng_vector (count);
	
	for (uint32 j = 0; j < count; j++)
		{
		
		fData [j] = 1.0;
		
		}
	
	}
				
/******************************************************************************/

bool dng_vector::operator== (const dng_vector &v) const
	{
	
	if (Count () != v.Count ())
		{
		
		return false;
		
		}
	
	for (uint32 j = 0; j < Count (); j++)	
		{
		
		if (fData [j] != v.fData [j])
			{
			
			return false;
			
			}
		
		}
			
	return true;
	
	}

/******************************************************************************/

real64 dng_vector::MaxEntry () const
	{
	
	if (IsEmpty ())
		{
		
		return 0.0;
		
		}
	
	real64 m = fData [0];
	
	for (uint32 j = 0; j < Count (); j++)
		{
		
		m = Max_real64 (m, fData [j]);
		
		}
			
	return m;
	
	}
		
/******************************************************************************/

real64 dng_vector::MinEntry () const
	{
	
	if (IsEmpty ())
		{
		
		return 0.0;
		
		}
	
	real64 m = fData [0];
	
	for (uint32 j = 0; j < Count (); j++)
		{
		
		m = Min_real64 (m, fData [j]);
		
		}
			
	return m;
	
	}
		
/*****************************************************************************/

void dng_vector::Scale (real64 factor)
	{
	
	for (uint32 j = 0; j < Count (); j++)	
		{
		
		fData [j] *= factor;
		
		}
		
	}
			
/*****************************************************************************/

void dng_vector::Round (real64 factor)
	{
	
	real64 invFactor = 1.0 / factor;
	
	for (uint32 j = 0; j < Count (); j++)	
		{
		
		fData [j] = Round_int32 (fData [j] * factor) * invFactor;
		
		}
			
	}
	
/*****************************************************************************/
				
dng_matrix dng_vector::AsDiagonal () const
	{
	
	dng_matrix M (Count (), Count ());
	
	for (uint32 j = 0; j < Count (); j++)
		{
		
		M [j] [j] = fData [j];
		
		}
		
	return M;
	
	}

/*****************************************************************************/
				
dng_matrix dng_vector::AsColumn () const
	{
	
	dng_matrix M (Count (), 1);
	
	for (uint32 j = 0; j < Count (); j++)
		{
		
		M [j] [0] = fData [j];
		
		}
		
	return M;
	
	}

/******************************************************************************/

dng_vector_3::dng_vector_3 ()

	:	dng_vector (3)
	
	{
	}
		
/******************************************************************************/

dng_vector_3::dng_vector_3 (const dng_vector &v)

	:	dng_vector (v)
	
	{
	
	if (Count () != 3)
		{
		
		ThrowMatrixMath ();
					 
		}
	
	}
		
/******************************************************************************/

dng_vector_3::dng_vector_3 (real64 a0,
							real64 a1,
						    real64 a2)

	:	dng_vector (3)
	
	{
	
	fData [0] = a0;
	fData [1] = a1;
	fData [2] = a2;
	
	}
		
/******************************************************************************/

dng_vector_4::dng_vector_4 ()

	:	dng_vector (4)
	
	{
	}
		
/******************************************************************************/

dng_vector_4::dng_vector_4 (const dng_vector &v)

	:	dng_vector (v)
	
	{
	
	if (Count () != 4)
		{
		
		ThrowMatrixMath ();
					 
		}
	
	}
		
/******************************************************************************/

dng_vector_4::dng_vector_4 (real64 a0,
							real64 a1,
						    real64 a2,
						    real64 a3)

	:	dng_vector (4)
	
	{
	
	fData [0] = a0;
	fData [1] = a1;
	fData [2] = a2;
	fData [3] = a3;
	
	}
		
/******************************************************************************/

dng_matrix operator* (const dng_matrix &A,
					  const dng_matrix &B)
	{
	
	if (A.Cols () != B.Rows ())
		{
		
		ThrowMatrixMath ();
					 
		}
	
	dng_matrix C (A.Rows (), B.Cols ());
	
	for (uint32 j = 0; j < C.Rows (); j++)
		for (uint32 k = 0; k < C.Cols (); k++)
			{
			
			C [j] [k] = 0.0;
			
			for (uint32 m = 0; m < A.Cols (); m++)
				{
				
				real64 aa = A [j] [m];
				
				real64 bb = B [m] [k];
				
				C [j] [k] += aa * bb;
				
				}
			
			}
			
	return C;

	}

/******************************************************************************/

dng_vector operator* (const dng_matrix &A,
					  const dng_vector &B)
	{
	
	if (A.Cols () != B.Count ())
		{
		
		ThrowMatrixMath ();
					 
		}
	
	dng_vector C (A.Rows ());
	
	for (uint32 j = 0; j < C.Count (); j++)
		{
		
		C [j] = 0.0;
		
		for (uint32 m = 0; m < A.Cols (); m++)
			{
			
			real64 aa = A [j] [m];
			
			real64 bb = B [m];
			
			C [j] += aa * bb;
			
			}
		
		}
			
	return C;

	}

/******************************************************************************/

dng_matrix operator* (real64 scale,
					  const dng_matrix &A)
	{
	
	dng_matrix B (A);
	
	B.Scale (scale);
	
	return B;
		
	}

/******************************************************************************/

dng_vector operator* (real64 scale,
					  const dng_vector &A)
	{
	
	dng_vector B (A);
	
	B.Scale (scale);
	
	return B;
		
	}

/******************************************************************************/

dng_matrix operator+ (const dng_matrix &A,
					  const dng_matrix &B)
	{
	
	if (A.Cols () != B.Cols () ||
		A.Rows () != B.Rows ())
		{
		
		ThrowMatrixMath ();
					 
		}
	
	dng_matrix C (A);
	
	for (uint32 j = 0; j < C.Rows (); j++)
		for (uint32 k = 0; k < C.Cols (); k++)
			{
			
			C [j] [k] += B [j] [k];
						
			}
			
	return C;

	}

/******************************************************************************/

const real64 kNearZero = 1.0E-10; 

/******************************************************************************/

// Work around bug #1294195, which may be a hardware problem on a specific machine.
// This pragma turns on "improved" floating-point consistency.
#ifdef _MSC_VER
#pragma optimize ("p", on)
#endif

static dng_matrix Invert3by3 (const dng_matrix &A)
	{
	
	real64 a00 = A [0] [0];
	real64 a01 = A [0] [1];
	real64 a02 = A [0] [2];
	real64 a10 = A [1] [0];
	real64 a11 = A [1] [1];
	real64 a12 = A [1] [2];
	real64 a20 = A [2] [0];
	real64 a21 = A [2] [1];
	real64 a22 = A [2] [2];
	
	real64 temp [3] [3];

	temp [0] [0] = a11 * a22 - a21 * a12;
	temp [0] [1] = a21 * a02 - a01 * a22;
	temp [0] [2] = a01 * a12 - a11 * a02;
	temp [1] [0] = a20 * a12 - a10 * a22;
	temp [1] [1] = a00 * a22 - a20 * a02;
	temp [1] [2] = a10 * a02 - a00 * a12;
	temp [2] [0] = a10 * a21 - a20 * a11;
	temp [2] [1] = a20 * a01 - a00 * a21;
	temp [2] [2] = a00 * a11 - a10 * a01;

	real64 det = (a00 * temp [0] [0] +
				  a01 * temp [1] [0] +
				  a02 * temp [2] [0]);

	if (Abs_real64 (det) < kNearZero)
		{
		
		ThrowMatrixMath ();
					 
		}

	dng_matrix B (3, 3);
	
	for (uint32 j = 0; j < 3; j++)	
		for (uint32 k = 0; k < 3; k++)
			{
			
			B [j] [k] = temp [j] [k] / det;
			
			}
			
	return B;

	}
		
// Reset floating-point optimization. See comment above.
#ifdef _MSC_VER
#pragma optimize ("p", off)
#endif

/******************************************************************************/

static dng_matrix InvertNbyN (const dng_matrix &A)
	{
	
	uint32 i;
	uint32 j;
	uint32 k;
	
	uint32 n = A.Rows ();
	
	real64 temp [kMaxColorPlanes] [kMaxColorPlanes * 2];
	
	for (i = 0; i < n; i++)
		for (j = 0; j < n; j++)
			{
			
			temp [i] [j    ] = A [i] [j];
			
			temp [i] [j + n] = (i == j ? 1.0 : 0.0);
			
			}
			
	for (i = 0; i < n; i++)
		{
		
		real64 alpha = temp [i] [i];
		
		if (Abs_real64 (alpha) < kNearZero)
			{
			
			ThrowMatrixMath ();
						 
			}
			
		for (j = 0; j < n * 2; j++)
			{
			
			temp [i] [j] /= alpha;
			
			}
			
		for (k = 0; k < n; k++)
			{
			
			if (i != k)
				{
				
				real64 beta = temp [k] [i];
				
				for (j = 0; j < n * 2; j++)
					{
					
					temp [k] [j] -= beta * temp [i] [j];
					
					}
				
				}
			
			}
			
		}
		
	dng_matrix B (n, n);
	
	for (i = 0; i < n; i++)
		for (j = 0; j < n; j++)
			{
			
			B [i] [j] = temp [i] [j + n];
			
			}
			
	return B;

	}
		
/******************************************************************************/

dng_matrix Transpose (const dng_matrix &A)
	{
	
	dng_matrix B (A.Cols (), A.Rows ());
	
	for (uint32 j = 0; j < B.Rows (); j++)
		for (uint32 k = 0; k < B.Cols (); k++)
			{
			
			B [j] [k] = A [k] [j];
			
			}
			
	return B;	
	
	}

/******************************************************************************/

dng_matrix Invert (const dng_matrix &A)
	{
	
	if (A.Rows () < 2 || A.Cols () < 2)
		{
		
		ThrowMatrixMath ();
						 
		}
	
	if (A.Rows () == A.Cols ())
		{
		
		if (A.Rows () == 3)
			{
			
			return Invert3by3 (A);
			
			}
			
		return InvertNbyN (A);
		
		}
		
	else
		{
		
		// Compute the pseudo inverse.
	
		dng_matrix B = Transpose (A);
	
		return Invert (B * A) * B;
		
		}
		
	}
		
/******************************************************************************/

dng_matrix Invert (const dng_matrix &A,
				   const dng_matrix &hint)
	{
	
	if (A.Rows () == A   .Cols () ||
		A.Rows () != hint.Cols () ||
		A.Cols () != hint.Rows ())
		{
		
		return Invert (A);
		
		}
		
	else
		{
		
		// Use the specified hint matrix.
		
		return Invert (hint * A) * hint;
		
		}
	
	}
	
/*****************************************************************************/