⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mgcnaturalspline3.cpp

📁 《3D游戏引擎设计》的源码
💻 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 "MgcLinearSystem.h"
#include "MgcNaturalSpline3.h"
#include "MgcPolynomial.h"
#include "MgcRTLib.h"

//---------------------------------------------------------------------------
MgcNaturalSpline3::MgcNaturalSpline3 (BoundaryType eType, int iSegments,
    MgcReal* afTime, MgcVector3* akPoint)
    :
    MgcMultipleCurve3(iSegments,afTime)
{
    m_akA = akPoint;

    switch ( eType )
    {
        case BT_FREE:
        {
            CreateFreeSpline();
            break;
        }
        case BT_CLAMPED:
        {
            CreateClampedSpline();
            break;
        }
        case BT_CLOSED:
        {
            CreateClosedSpline();
            break;
        }
    }
}
//---------------------------------------------------------------------------
MgcNaturalSpline3::~MgcNaturalSpline3 ()
{
    delete[] m_akA;
    delete[] m_akB;
    delete[] m_akC;
    delete[] m_akD;
}
//---------------------------------------------------------------------------
void MgcNaturalSpline3::CreateFreeSpline ()
{
    MgcReal* afDt = new MgcReal[m_iSegments];
    int i;
    for (i = 0; i < m_iSegments; i++)
        afDt[i] = m_afTime[i+1] - m_afTime[i];

    MgcReal* afD2t = new MgcReal[m_iSegments];
    for (i = 1; i < m_iSegments; i++)
        afD2t[i] = m_afTime[i+1] - m_afTime[i-1];

    MgcVector3* akAlpha = new MgcVector3[m_iSegments];
    for (i = 1; i < m_iSegments; i++)
    {
        MgcVector3 kNumer = 3.0*(afDt[i-1]*m_akA[i+1] - afD2t[i]*m_akA[i] +
            afDt[i]*m_akA[i-1]);
        MgcReal fInvDenom = 1.0/(afDt[i-1]*afDt[i]);
        akAlpha[i] = fInvDenom*kNumer;
    }

    MgcReal* afEll = new MgcReal[m_iSegments+1];
    MgcReal* afMu = new MgcReal[m_iSegments];
    MgcVector3* akZ = new MgcVector3[m_iSegments+1];
    MgcReal fInv;

    afEll[0] = 1.0;
    afMu[0] = 0.0;
    akZ[0] = MgcVector3::ZERO;
    for (i = 1; i < m_iSegments; i++)
    {
        afEll[i] = 2.0*afD2t[i] - afDt[i-1]*afMu[i-1];
        fInv = 1.0/afEll[i];
        afMu[i] = fInv*afDt[i];
        akZ[i] = fInv*(akAlpha[i] - afDt[i-1]*akZ[i-1]);
    }
    afEll[m_iSegments] = 1.0;
    akZ[m_iSegments] = MgcVector3::ZERO;

    m_akB = new MgcVector3[m_iSegments];
    m_akC = new MgcVector3[m_iSegments+1];
    m_akD = new MgcVector3[m_iSegments];

    m_akC[m_iSegments] = MgcVector3::ZERO;

    for (i = m_iSegments-1; i >= 0; i--)
    {
        const MgcReal fOneThird = 1.0/3.0;
        m_akC[i] = akZ[i] - afMu[i]*m_akC[i+1];
        fInv = 1.0/afDt[i];
        m_akB[i] = fInv*(m_akA[i+1] - m_akA[i]) - fOneThird*afDt[i]*(
            m_akC[i+1] + 2.0*m_akC[i]);
        m_akD[i] = fOneThird*fInv*(m_akC[i+1] - m_akC[i]);
    }

    delete[] afDt;
    delete[] afD2t;
    delete[] akAlpha;
    delete[] afEll;
    delete[] afMu;
    delete[] akZ;
}
//-----------------------------------------------------------------------------
void MgcNaturalSpline3::CreateClampedSpline ()
{
    MgcReal* afDt = new MgcReal[m_iSegments];
    int i;
    for (i = 0; i < m_iSegments; i++)
        afDt[i] = m_afTime[i+1] - m_afTime[i];

    MgcReal* afD2t = new MgcReal[m_iSegments];
    for (i = 1; i < m_iSegments; i++)
        afD2t[i] = m_afTime[i+1] - m_afTime[i-1];

    MgcVector3* akAlpha = new MgcVector3[m_iSegments+1];
    MgcReal fInv = 1.0/afDt[0];
    MgcVector3 kDiff = m_akA[1] - m_akA[0];
    akAlpha[0] = 3.0*(fInv - 1.0)*(m_akA[1] - m_akA[0]);
    fInv = 1.0/afDt[m_iSegments-1];
    akAlpha[m_iSegments] = 3.0*(1.0 - fInv)*(m_akA[m_iSegments] -
        m_akA[m_iSegments-1]);
    for (i = 1; i < m_iSegments; i++)
    {
        MgcVector3 kNumer = 3.0*(afDt[i-1]*m_akA[i+1] - afD2t[i]*m_akA[i] +
            afDt[i]*m_akA[i-1]);
        MgcReal fInvDenom = 1.0/(afDt[i-1]*afDt[i]);
        akAlpha[i] = fInvDenom*kNumer;
    }

    MgcReal* afEll = new MgcReal[m_iSegments+1];
    MgcReal* afMu = new MgcReal[m_iSegments];
    MgcVector3* akZ = new MgcVector3[m_iSegments+1];

    afEll[0] = 2.0*afDt[0];
    afMu[0] = 0.5;
    fInv = 1.0/afEll[0];
    akZ[0] = fInv*akAlpha[0];

    for (i = 1; i < m_iSegments; i++)
    {
        afEll[i] = 2.0*afD2t[i] - afDt[i-1]*afMu[i-1];
        fInv = 1.0/afEll[i];
        afMu[i] = fInv*afDt[i];
        akZ[i] = fInv*(akAlpha[i] - afDt[i-1]*akZ[i-1]);
    }
    afEll[m_iSegments] = afDt[m_iSegments-1]*(2.0 - afMu[m_iSegments-1]);
    fInv = 1.0/afEll[m_iSegments];
    akZ[m_iSegments] = fInv*(akAlpha[m_iSegments] - afDt[m_iSegments-1]*
        akZ[m_iSegments-1]);

    m_akB = new MgcVector3[m_iSegments];
    m_akC = new MgcVector3[m_iSegments+1];
    m_akD = new MgcVector3[m_iSegments];

    m_akC[m_iSegments] = akZ[m_iSegments];

    for (i = m_iSegments-1; i >= 0; i--)
    {
        MgcReal fOneThird = 1.0/3.0;
        m_akC[i] = akZ[i] - afMu[i]*m_akC[i+1];
        fInv = 1.0/afDt[i];
        m_akB[i] = fInv*(m_akA[i+1] - m_akA[i]) - fOneThird*afDt[i]*(
            m_akC[i+1] + 2.0*m_akC[i]);
        m_akD[i] = fOneThird*fInv*(m_akC[i+1] - m_akC[i]);
    }

    delete[] afDt;
    delete[] afD2t;
    delete[] akAlpha;
    delete[] afEll;
    delete[] afMu;
    delete[] akZ;
}
//-----------------------------------------------------------------------------
void MgcNaturalSpline3::CreateClosedSpline ()
{
    MgcReal* afDt = new MgcReal[m_iSegments];
    int i;
    for (i = 0; i < m_iSegments; i++)
        afDt[i] = m_afTime[i+1] - m_afTime[i];

    // TO DO.  Add ability to solve AX = B for B nxm (not just m=1) and
    // remove resetting of aafMat that occurs for each component of m_afC.
    MgcLinearSystem kSys;

    // construct matrix of system
    MgcReal** aafMat = kSys.NewMatrix(m_iSegments+1);
    aafMat[0][0] = 1.0;
    aafMat[0][m_iSegments] = -1.0;
    for (i = 1; i <= m_iSegments-1; i++)
    {
        aafMat[i][i-1] = afDt[i-1];
        aafMat[i][i  ] = 2.0*(afDt[i-1] + afDt[i]);
        aafMat[i][i+1] = afDt[i];
    }
    aafMat[m_iSegments][m_iSegments-1] = afDt[m_iSegments-1];
    aafMat[m_iSegments][0] = 2.0*(afDt[m_iSegments-1] + afDt[0]);
    aafMat[m_iSegments][1] = afDt[0];

    // construct right-hand side of system
    m_akC = new MgcVector3[m_iSegments+1];
    m_akC[0] = MgcVector3::ZERO;
    MgcReal fInv0, fInv1;
    for (i = 1; i <= m_iSegments-1; i++)
    {
        fInv0 = 1.0/afDt[i];
        fInv1 = 1.0/afDt[i-1];
        m_akC[i] = 3.0*(fInv0*(m_akA[i+1] - m_akA[i]) - fInv1*(m_akA[i] -
            m_akA[i-1]));
    }
    fInv0 = 1.0/afDt[0];
    fInv1 = 1.0/afDt[m_iSegments-1];
    m_akC[m_iSegments] = 3.0*(fInv0*(m_akA[1] - m_akA[0]) - fInv1*(m_akA[0] -
        m_akA[m_iSegments-1]));

    MgcReal* afCx = kSys.NewVector(m_iSegments+1);
    MgcReal* afCy = kSys.NewVector(m_iSegments+1);
    MgcReal* afCz = kSys.NewVector(m_iSegments+1);
    for (i = 0; i <= m_iSegments; i++)
    {
        afCx[i] = m_akC[i].x;
        afCy[i] = m_akC[i].y;
        afCz[i] = m_akC[i].z;
    }
    kSys.Solve(m_iSegments+1,aafMat,afCx);

    // reset matrix for next system
    aafMat[0][0] = 1.0;
    aafMat[0][m_iSegments] = -1.0;
    for (i = 1; i <= m_iSegments-1; i++)
    {
        aafMat[i][i-1] = afDt[i-1];
        aafMat[i][i  ] = 2.0*(afDt[i-1] + afDt[i]);
        aafMat[i][i+1] = afDt[i];
    }
    aafMat[m_iSegments][m_iSegments-1] = afDt[m_iSegments-1];
    aafMat[m_iSegments][0] = 2.0*(afDt[m_iSegments-1] + afDt[0]);
    aafMat[m_iSegments][1] = afDt[0];

    kSys.Solve(m_iSegments+1,aafMat,afCy);

    // reset matrix for next system
    aafMat[0][0] = 1.0;
    aafMat[0][m_iSegments] = -1.0;
    for (i = 1; i <= m_iSegments-1; i++)
    {
        aafMat[i][i-1] = afDt[i-1];
        aafMat[i][i  ] = 2.0*(afDt[i-1] + afDt[i]);
        aafMat[i][i+1] = afDt[i];
    }
    aafMat[m_iSegments][m_iSegments-1] = afDt[m_iSegments-1];
    aafMat[m_iSegments][0] = 2.0*(afDt[m_iSegments-1] + afDt[0]);
    aafMat[m_iSegments][1] = afDt[0];

    kSys.Solve(m_iSegments+1,aafMat,afCz);

    for (i = 0; i <= m_iSegments; i++)
    {
        m_akC[i].x = afCx[i];
        m_akC[i].y = afCy[i];
        m_akC[i].z = afCz[i];
    }

    const MgcReal fOneThird = 1.0/3.0;
    m_akB = new MgcVector3[m_iSegments];
    m_akD = new MgcVector3[m_iSegments];
    for (i = 0; i < m_iSegments; i++)
    {
        fInv0 = 1.0/afDt[i];
        m_akB[i] = fInv0*(m_akA[i+1] - m_akA[i]) - fOneThird*(m_akC[i+1] +
            2.0*m_akC[i])*afDt[i];
        m_akD[i] = fOneThird*fInv0*(m_akC[i+1] - m_akC[i]);
    }

    kSys.DeleteMatrix(m_iSegments+1,aafMat);
    delete[] afDt;
    delete[] afCx;
    delete[] afCy;
    delete[] afCz;
}
//-----------------------------------------------------------------------------
MgcVector3 MgcNaturalSpline3::GetPosition (MgcReal fTime) const
{
    int iKey;
    MgcReal fDt;
    GetKeyInfo(fTime,iKey,fDt);

    MgcVector3 kResult = m_akA[iKey] + fDt*(m_akB[iKey] + fDt*(
        m_akC[iKey] + fDt*m_akD[iKey]));

    return kResult;
}
//---------------------------------------------------------------------------
MgcVector3 MgcNaturalSpline3::GetFirstDerivative (MgcReal fTime) const
{
    int iKey;
    MgcReal fDt;
    GetKeyInfo(fTime,iKey,fDt);

    MgcVector3 kResult = m_akB[iKey] + fDt*(2.0*m_akC[iKey] + 3.0*fDt*
        m_akD[iKey]);

    return kResult;
}
//---------------------------------------------------------------------------
MgcVector3 MgcNaturalSpline3::GetSecondDerivative (MgcReal fTime) const
{
    int iKey;
    MgcReal fDt;
    GetKeyInfo(fTime,iKey,fDt);

    MgcVector3 kResult = 2.0*m_akC[iKey] + 6.0*fDt*m_akD[iKey];

    return kResult;
}
//---------------------------------------------------------------------------
MgcVector3 MgcNaturalSpline3::GetThirdDerivative (MgcReal fTime) const
{
    int iKey;
    MgcReal fDt;
    GetKeyInfo(fTime,iKey,fDt);

    MgcVector3 kResult = 6.0*m_akD[iKey];

    return kResult;
}
//---------------------------------------------------------------------------
MgcReal MgcNaturalSpline3::GetSpeed (int iKey, MgcReal fTime) const
{
    MgcVector3 kVelocity = m_akB[iKey] + fTime*(2.0*m_akC[iKey] +
        3.0*fTime*m_akD[iKey]);
    return kVelocity.Length();
}
//-----------------------------------------------------------------------------
MgcReal MgcNaturalSpline3::GetLength (int iKey, MgcReal fT0, MgcReal fT1) const
{
    class ThisPlusKey
    {
    public:
        ThisPlusKey (const MgcNaturalSpline3* pkThis, int iKey)
            : m_pkThis(pkThis), m_iKey(iKey) { /**/ }

        const MgcNaturalSpline3* m_pkThis;
        int m_iKey;
    };

    ThisPlusKey kData(this,iKey);

    return MgcIntegrate::RombergIntegral(fT0,fT1,GetSpeedWithData,
        (void*)&kData);
}
//-----------------------------------------------------------------------------
MgcReal MgcNaturalSpline3::GetVariation (int iKey, MgcReal fT0,
    MgcReal fT1, const MgcVector3& rkA, const MgcVector3& rkB) const
{
    MgcPolynomial kXPoly(3);
    kXPoly[0] = m_akA[iKey].x;
    kXPoly[1] = m_akB[iKey].x;
    kXPoly[2] = m_akC[iKey].x;
    kXPoly[3] = m_akD[iKey].x;

    MgcPolynomial kYPoly(3);
    kYPoly[0] = m_akA[iKey].y;
    kYPoly[1] = m_akB[iKey].y;
    kYPoly[2] = m_akC[iKey].y;
    kYPoly[3] = m_akD[iKey].y;

    MgcPolynomial kZPoly(3);
    kZPoly[0] = m_akA[iKey].z;
    kZPoly[1] = m_akB[iKey].z;
    kZPoly[2] = m_akC[iKey].z;
    kZPoly[3] = m_akD[iKey].z;

    // construct line segment A + t*B
    MgcPolynomial kLx(1), kLy(1), kLz(1);
    kLx[0] = rkA.x;
    kLx[1] = rkB.x;
    kLy[0] = rkA.y;
    kLy[1] = rkB.y;
    kLz[0] = rkA.z;
    kLz[1] = rkB.z;

    // compute |X(t) - L(t)|^2
    MgcPolynomial kDx = kXPoly - kLx;
    MgcPolynomial kDy = kYPoly - kLy;
    MgcPolynomial kDz = kZPoly - kLz;
    MgcPolynomial kNormSqr = kDx*kDx + kDy*kDy + kDz*kDz;

    // compute indefinite integral of |X(t)-L(t)|^2
    MgcPolynomial kIntegral(kNormSqr.GetDegree()+1);
    kIntegral[0] = 0.0;
    for (int i = 1; i <= kIntegral.GetDegree(); i++)
        kIntegral[i] = kNormSqr[i-1]/i;

    // compute definite Integral(t0,t1,|X(t)-L(t)|^2)
    MgcReal fResult = kIntegral(fT1) - kIntegral(fT0);
    return fResult;
}
//---------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -