📄 mgceigen.cpp
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement. The various license agreements may be found at
// the Magic Software web site. This file is subject to the license
//
// FREE SOURCE CODE
// http://www.magic-software.com/License/free.pdf
#include "MgcEigen.h"
#include "MgcRTLib.h"
//---------------------------------------------------------------------------
MgcEigen::MgcEigen (int iSize)
{
assert( iSize >= 2 );
m_iSize = iSize;
m_aafMat = new MgcReal*[m_iSize];
for (int i = 0; i < m_iSize; i++)
m_aafMat[i] = new MgcReal[m_iSize];
m_afDiag = new MgcReal[m_iSize];
m_afSubd = new MgcReal[m_iSize];
}
//---------------------------------------------------------------------------
MgcEigen::~MgcEigen ()
{
delete[] m_afSubd;
delete[] m_afDiag;
for (int i = 0; i < m_iSize; i++)
delete[] m_aafMat[i];
delete[] m_aafMat;
}
//---------------------------------------------------------------------------
void MgcEigen::Tridiagonal2 (MgcReal** m_aafMat, MgcReal* m_afDiag,
MgcReal* m_afSubd)
{
// matrix is already tridiagonal
m_afDiag[0] = m_aafMat[0][0];
m_afDiag[1] = m_aafMat[1][1];
m_afSubd[0] = m_aafMat[0][1];
m_afSubd[1] = 0.0;
m_aafMat[0][0] = 1.0;
m_aafMat[0][1] = 0.0;
m_aafMat[1][0] = 0.0;
m_aafMat[1][1] = 1.0;
}
//---------------------------------------------------------------------------
void MgcEigen::Tridiagonal3 (MgcReal** m_aafMat, MgcReal* m_afDiag,
MgcReal* m_afSubd)
{
MgcReal fM00 = m_aafMat[0][0];
MgcReal fM01 = m_aafMat[0][1];
MgcReal fM02 = m_aafMat[0][2];
MgcReal fM11 = m_aafMat[1][1];
MgcReal fM12 = m_aafMat[1][2];
MgcReal fM22 = m_aafMat[2][2];
m_afDiag[0] = fM00;
m_afSubd[2] = 0.0;
if ( fM02 != 0.0 )
{
MgcReal fLength = MgcMath::Sqrt(fM01*fM01+fM02*fM02);
MgcReal fInvLength = 1.0/fLength;
fM01 *= fInvLength;
fM02 *= fInvLength;
MgcReal fQ = 2.0*fM01*fM12+fM02*(fM22-fM11);
m_afDiag[1] = fM11+fM02*fQ;
m_afDiag[2] = fM22-fM02*fQ;
m_afSubd[0] = fLength;
m_afSubd[1] = fM12-fM01*fQ;
m_aafMat[0][0] = 1.0; m_aafMat[0][1] = 0.0; m_aafMat[0][2] = 0.0;
m_aafMat[1][0] = 0.0; m_aafMat[1][1] = fM01; m_aafMat[1][2] = fM02;
m_aafMat[2][0] = 0.0; m_aafMat[2][1] = fM02; m_aafMat[2][2] = -fM01;
}
else
{
m_afDiag[1] = fM11;
m_afDiag[2] = fM22;
m_afSubd[0] = fM01;
m_afSubd[1] = fM12;
m_aafMat[0][0] = 1.0; m_aafMat[0][1] = 0.0; m_aafMat[0][2] = 0.0;
m_aafMat[1][0] = 0.0; m_aafMat[1][1] = 1.0; m_aafMat[1][2] = 0.0;
m_aafMat[2][0] = 0.0; m_aafMat[2][1] = 0.0; m_aafMat[2][2] = 1.0;
}
}
//---------------------------------------------------------------------------
void MgcEigen::Tridiagonal4 (MgcReal** m_aafMat, MgcReal* m_afDiag,
MgcReal* m_afSubd)
{
// save matrix M
MgcReal fM00 = m_aafMat[0][0];
MgcReal fM01 = m_aafMat[0][1];
MgcReal fM02 = m_aafMat[0][2];
MgcReal fM03 = m_aafMat[0][3];
MgcReal fM11 = m_aafMat[1][1];
MgcReal fM12 = m_aafMat[1][2];
MgcReal fM13 = m_aafMat[1][3];
MgcReal fM22 = m_aafMat[2][2];
MgcReal fM23 = m_aafMat[2][3];
MgcReal fM33 = m_aafMat[3][3];
m_afDiag[0] = fM00;
m_afSubd[3] = 0.0;
m_aafMat[0][0] = 1.0;
m_aafMat[0][1] = 0.0;
m_aafMat[0][2] = 0.0;
m_aafMat[0][3] = 0.0;
m_aafMat[1][0] = 0.0;
m_aafMat[2][0] = 0.0;
m_aafMat[3][0] = 0.0;
float fLength, fInvLength;
if ( fM02 != 0.0 || fM03 != 0.0 )
{
MgcReal fQ11, fQ12, fQ13;
MgcReal fQ21, fQ22, fQ23;
MgcReal fQ31, fQ32, fQ33;
// build column Q1
fLength = MgcMath::Sqrt(fM01*fM01+fM02*fM02+fM03*fM03);
fInvLength = 1.0/fLength;
fQ11 = fM01*fInvLength;
fQ21 = fM02*fInvLength;
fQ31 = fM03*fInvLength;
m_afSubd[0] = fLength;
// compute S*Q1
MgcReal fV0 = fM11*fQ11+fM12*fQ21+fM13*fQ31;
MgcReal fV1 = fM12*fQ11+fM22*fQ21+fM23*fQ31;
MgcReal fV2 = fM13*fQ11+fM23*fQ21+fM33*fQ31;
m_afDiag[1] = fQ11*fV0+fQ21*fV1+fQ31*fV2;
// build column Q3 = Q1x(S*Q1)
fQ13 = fQ21*fV2-fQ31*fV1;
fQ23 = fQ31*fV0-fQ11*fV2;
fQ33 = fQ11*fV1-fQ21*fV0;
fLength = MgcMath::Sqrt(fQ13*fQ13+fQ23*fQ23+fQ33*fQ33);
if ( fLength > 0.0 )
{
fInvLength = 1.0/fLength;
fQ13 *= fInvLength;
fQ23 *= fInvLength;
fQ33 *= fInvLength;
// build column Q2 = Q3xQ1
fQ12 = fQ23*fQ31-fQ33*fQ21;
fQ22 = fQ33*fQ11-fQ13*fQ31;
fQ32 = fQ13*fQ21-fQ23*fQ11;
fV0 = fQ12*fM11+fQ22*fM12+fQ32*fM13;
fV1 = fQ12*fM12+fQ22*fM22+fQ32*fM23;
fV2 = fQ12*fM13+fQ22*fM23+fQ32*fM33;
m_afSubd[1] = fQ11*fV0+fQ21*fV1+fQ31*fV2;
m_afDiag[2] = fQ12*fV0+fQ22*fV1+fQ32*fV2;
m_afSubd[2] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
fV0 = fQ13*fM11+fQ23*fM12+fQ33*fM13;
fV1 = fQ13*fM12+fQ23*fM22+fQ33*fM23;
fV2 = fQ13*fM13+fQ23*fM23+fQ33*fM33;
m_afDiag[3] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
}
else
{
// S*Q1 parallel to Q1, choose any valid Q2 and Q3
m_afSubd[1] = 0;
fLength = fQ21*fQ21+fQ31*fQ31;
if ( fLength > 0.0 )
{
fInvLength = 1.0/fLength;
MgcReal fTmp = fQ11-1.0;
fQ12 = -fQ21;
fQ22 = 1.0+fTmp*fQ21*fQ21*fInvLength;
fQ32 = fTmp*fQ21*fQ31*fInvLength;
fQ13 = -fQ31;
fQ23 = fQ32;
fQ33 = 1.0+fTmp*fQ31*fQ31*fInvLength;
fV0 = fQ12*fM11+fQ22*fM12+fQ32*fM13;
fV1 = fQ12*fM12+fQ22*fM22+fQ32*fM23;
fV2 = fQ12*fM13+fQ22*fM23+fQ32*fM33;
m_afDiag[2] = fQ12*fV0+fQ22*fV1+fQ32*fV2;
m_afSubd[2] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
fV0 = fQ13*fM11+fQ23*fM12+fQ33*fM13;
fV1 = fQ13*fM12+fQ23*fM22+fQ33*fM23;
fV2 = fQ13*fM13+fQ23*fM23+fQ33*fM33;
m_afDiag[3] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
}
else
{
// Q1 = (+-1,0,0)
fQ12 = 0.0; fQ22 = 1.0; fQ32 = 0.0;
fQ13 = 0.0; fQ23 = 0.0; fQ33 = 1.0;
m_afDiag[2] = fM22;
m_afDiag[3] = fM33;
m_afSubd[2] = fM23;
}
}
m_aafMat[1][1] = fQ11; m_aafMat[1][2] = fQ12; m_aafMat[1][3] = fQ13;
m_aafMat[2][1] = fQ21; m_aafMat[2][2] = fQ22; m_aafMat[2][3] = fQ23;
m_aafMat[3][1] = fQ31; m_aafMat[3][2] = fQ32; m_aafMat[3][3] = fQ33;
}
else
{
m_afDiag[1] = fM11;
m_afSubd[0] = fM01;
m_aafMat[1][1] = 1.0;
m_aafMat[2][1] = 0.0;
m_aafMat[3][1] = 0.0;
if ( fM13 != 0.0 )
{
fLength = MgcMath::Sqrt(fM12*fM12+fM13*fM13);
fInvLength = 1.0/fLength;
fM12 *= fInvLength;
fM13 *= fInvLength;
MgcReal fQ = 2.0*fM12*fM23+fM13*(fM33-fM22);
m_afDiag[2] = fM22+fM13*fQ;
m_afDiag[3] = fM33-fM13*fQ;
m_afSubd[1] = fLength;
m_afSubd[2] = fM23-fM12*fQ;
m_aafMat[1][2] = 0.0;
m_aafMat[1][3] = 0.0;
m_aafMat[2][2] = fM12;
m_aafMat[2][3] = fM13;
m_aafMat[3][2] = fM13;
m_aafMat[3][3] = -fM12;
}
else
{
m_afDiag[2] = fM22;
m_afDiag[3] = fM33;
m_afSubd[1] = fM12;
m_afSubd[2] = fM23;
m_aafMat[1][2] = 0.0;
m_aafMat[1][3] = 0.0;
m_aafMat[2][2] = 1.0;
m_aafMat[2][3] = 0.0;
m_aafMat[3][2] = 0.0;
m_aafMat[3][3] = 1.0;
}
}
}
//---------------------------------------------------------------------------
void MgcEigen::TridiagonalN (int iSize, MgcReal** m_aafMat,
MgcReal* m_afDiag, MgcReal* m_afSubd)
{
int i0, i1, i2, i3;
for (i0 = iSize-1, i3 = iSize-2; i0 >= 1; i0--, i3--)
{
MgcReal fH = 0.0, fScale = 0.0;
if ( i3 > 0 )
{
for (i2 = 0; i2 <= i3; i2++)
fScale += MgcMath::Abs(m_aafMat[i0][i2]);
if ( fScale == 0 )
{
m_afSubd[i0] = m_aafMat[i0][i3];
}
else
{
float fInvScale = 1.0/fScale;
for (i2 = 0; i2 <= i3; i2++)
{
m_aafMat[i0][i2] *= fInvScale;
fH += m_aafMat[i0][i2]*m_aafMat[i0][i2];
}
MgcReal fF = m_aafMat[i0][i3];
MgcReal fG = MgcMath::Sqrt(fH);
if ( fF > 0.0 )
fG = -fG;
m_afSubd[i0] = fScale*fG;
fH -= fF*fG;
m_aafMat[i0][i3] = fF-fG;
fF = 0.0;
float fInvH = 1.0/fH;
for (i1 = 0; i1 <= i3; i1++)
{
m_aafMat[i1][i0] = m_aafMat[i0][i1]*fInvH;
fG = 0.0;
for (i2 = 0; i2 <= i1; i2++)
fG += m_aafMat[i1][i2]*m_aafMat[i0][i2];
for (i2 = i1+1; i2 <= i3; i2++)
fG += m_aafMat[i2][i1]*m_aafMat[i0][i2];
m_afSubd[i1] = fG*fInvH;
fF += m_afSubd[i1]*m_aafMat[i0][i1];
}
MgcReal fHalfFdivH = 0.5*fF*fInvH;
for (i1 = 0; i1 <= i3; i1++)
{
fF = m_aafMat[i0][i1];
fG = m_afSubd[i1] - fHalfFdivH*fF;
m_afSubd[i1] = fG;
for (i2 = 0; i2 <= i1; i2++)
{
m_aafMat[i1][i2] -= fF*m_afSubd[i2] +
fG*m_aafMat[i0][i2];
}
}
}
}
else
{
m_afSubd[i0] = m_aafMat[i0][i3];
}
m_afDiag[i0] = fH;
}
m_afDiag[0] = m_afSubd[0] = 0;
for (i0 = 0, i3 = -1; i0 <= iSize-1; i0++, i3++)
{
if ( m_afDiag[i0] )
{
for (i1 = 0; i1 <= i3; i1++)
{
MgcReal fSum = 0;
for (i2 = 0; i2 <= i3; i2++)
fSum += m_aafMat[i0][i2]*m_aafMat[i2][i1];
for (i2 = 0; i2 <= i3; i2++)
m_aafMat[i2][i1] -= fSum*m_aafMat[i2][i0];
}
}
m_afDiag[i0] = m_aafMat[i0][i0];
m_aafMat[i0][i0] = 1;
for (i1 = 0; i1 <= i3; i1++)
m_aafMat[i1][i0] = m_aafMat[i0][i1] = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -