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

📄 spine.cpp

📁 样条类的C++,该类包括三次样条的插值,拟合和B样条的插值,拟和等功能 。自己编写的简单适用的函数
💻 CPP
字号:
// Spine.cpp: implementation of the CSpine class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Spine.h"

#include"memory.h"
#include"math.h"
#include"Matrix.h"

#define MAX_PAR_NUM 150//三次样条或B样条拟合中最大参数上限,避免计算时间过大

#define ST_CLAMPED  1 //表明三次样条插值采用的是指定一阶导数条件
#define ST_NATURAL  2 //表明三次样条插值采用的是自然参数条件 
#define ST_EXTRA    3 //表明三次样条插值采用的是外插条件 
#define ST_CONSTANT 4 //表明三次样条插值采用的二阶倒数是常数
#define ST_TWO      5 //表明三次样条插值采用的是指定二阶导数条件

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//默认构造函数
//参数:无
//返回:无
//////////////////////////////////////////////////////////////////////
CSpine::CSpine()
{
	m_nNum=1;
	m_pTime=NULL;
	m_pData=NULL;
	m_p3SpineFit=NULL;
	m_p3SpineInsert=NULL;
	m_pBSpineFit=NULL;
	m_pBSpineInsert=NULL;
	BOOL bInit=Init(m_nNum);
	ASSERT(bInit);
}

//////////////////////////////////////////////////////////////////////
//构造函数,初附值
//参数:1 nNum------初始数据个数
//      2 Time------初始数据坐标点的值(注意是nNum+1维)
//      3 Data------初始数据坐标点的函数值(注意是nNum+1维)
//返回:无
//////////////////////////////////////////////////////////////////////
CSpine::CSpine(int nNum,double Time[],double Data[])
{
	m_nNum=nNum;

	m_pTime=NULL;
	m_pData=NULL;
	m_p3SpineFit=NULL;
	m_p3SpineInsert=NULL;
	m_pBSpineFit=NULL;
	m_pBSpineInsert=NULL;
	BOOL bInit=Init(m_nNum);
	ASSERT(bInit);
    SetTime(Time);
	SetData(Data);

}
///////////////////////////////////////////////////////////////////
// 拷贝构造函数
//////////////////////////////////////////////////////////////////
CSpine::CSpine(const CSpine& other)
{
	m_nNum=other.m_nNum;

	m_pTime=NULL;
	m_pData=NULL;
	m_p3SpineFit=NULL;
	m_p3SpineInsert=NULL;
	m_pBSpineFit=NULL;
	m_pBSpineInsert=NULL;	

	BOOL bInit=Init(m_nNum);
	ASSERT(bInit);
	memcpy(m_pTime,other.GetTime(),sizeof(double)*m_nNum);
	memcpy(m_pData,other.GetData(),sizeof(double)*m_nNum);
}
/////////////////////////////////////////////////////////////////////
//析构函数,释放内存
//参数:无
//返回:无
//////////////////////////////////////////////////////////////////////
CSpine::~CSpine()
{
	if(m_pTime)
		delete[] m_pTime;
	if(m_pData)
		delete[] m_pData;
	if(m_p3SpineFit)
		delete[] m_p3SpineFit;
	if(m_p3SpineInsert)
		delete[] m_p3SpineInsert;
	if(m_pBSpineFit)
		delete[] m_pBSpineFit;
	if(m_pBSpineInsert)
		delete[] m_pBSpineInsert;
}

////////////////////////////////////////////////////////////////
//初始函数,分配内存
//参数:1 nNum------初始数据个数
//返回:成功分配内存返回TRUE,否则FALSE
//////////////////////////////////////////////////////////////////
BOOL CSpine::Init(int nNum)
{
	
	m_nNum=nNum;
	//////////////////////////////////////////////////
	//释放内存
	if(m_pTime)
		delete[] m_pTime;
	if(m_pData)
		delete[] m_pData;
	if(m_p3SpineFit)
		delete[] m_p3SpineFit;
	if(m_p3SpineInsert)
		delete[] m_p3SpineInsert;
	if(m_pBSpineFit)
		delete[] m_pBSpineFit;
	if(m_pBSpineInsert)
		delete[] m_pBSpineInsert;
	//////////////////////////////////////////////////
	//分配内存
	m_pTime=new double[m_nNum];
	if(!m_pTime)
		return FALSE;
	m_pData=new double[m_nNum];
	if(!m_pData)
		return FALSE;
	

	/////////////////////////////////////////////////////////
	//初赋值
	memset(m_pTime,0,sizeof(double)*(m_nNum));
	memset(m_pData,0,sizeof(double)*(m_nNum));


	//////////////////////////////////////////////////////
	return TRUE;
}

////////////////////////////////////////////////////////////////
//设置初始坐标点的函数。注意时间是nNum+1维
//参数:1 Time------初始坐标点的数据集
//返回: 无
/////////////////////////////////////////////////////////////////
void CSpine::SetTime(double Time[])
{

	memset(m_pTime,0,sizeof(double)*(m_nNum));
	memcpy(m_pTime,Time,sizeof(double)*(m_nNum));
}

////////////////////////////////////////////////////////////////
//设置初始坐标点函数值的函数。注意是nNum+1维
//参数:1 Data------初始坐标点的函数值数据集
//返回: 无
/////////////////////////////////////////////////////////////////
void CSpine::SetData(double Data[])
{
	memset(m_pData,0,sizeof(double)*(m_nNum));
	memcpy(m_pData,Data,sizeof(double)*(m_nNum));
}

///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
double* CSpine::GetTime() const
{
	return m_pTime;
}

///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
double* CSpine::GetData() const
{
	return m_pData;
}


//////////////////////////////////////////////////////////////////
//B样条拟合函数
//参数:1 nInterval----用户要分的区间个数
//      2 nType--------用户指定的B样条阶数
//返回:残查
//////////////////////////////////////////////////////////////////
double CSpine::BSpineFit(int nParameter,int nType)
{
	if(nParameter<4)
	{
		AfxMessageBox("你输入的参数过小,请确认参数个数大于3!");
	}
	if(nParameter>MAX_PAR_NUM)
	{	AfxMessageBox("你输入的参数过大,将有可能造成数值上的困难!");
	}
	if(m_pBSpineFit)
		delete[] m_pBSpineFit;
	m_pBSpineFit=new double[nParameter];
	ASSERT(m_pBSpineFit);
	double *T=new double[nParameter];
	ASSERT(T);
	double a=m_pTime[0];
	double b=m_pTime[m_nNum-1];
	double h=(b-a)/(nParameter-3);
	for(int i=0;i<nParameter;i++)
		T[i]=a-h+i*h;
	/////////////////////////////////////////////////////////
	CMatrix mtxX(m_nNum,nParameter);
	CMatrix mtxY(m_nNum,1);
	for(i=0;i<m_nNum;i++)
		for(int j=0;j<nParameter;j++)
			mtxX.SetElement(i,j,ggBFuction((m_pTime[i]-T[j])/h,nType));
	mtxY.SetData(m_pData);
	CMatrix mtxL(nParameter);
	mtxL=mtxX.Transpose()*mtxX;

	mtxL.InvertGaussJordan();

	CMatrix mtxResult;
	mtxResult=mtxL*(mtxX.Transpose());
	mtxResult=mtxResult*mtxY;
	memcpy(m_pBSpineFit,mtxResult.GetData(),sizeof(double)*(nParameter));
	delete[] T;
	double er=0;
	for(i=0;i<m_nNum;i++)
		er+=(m_pData[i]-GetBSpineFitValue(m_pTime[i],nParameter,nType))*
		(m_pData[i]-GetBSpineFitValue(m_pTime[i],nParameter,nType));
	er=er/m_nNum;
	return sqrt(er);


}

///////////////////////////////////////////////////////////////////////////////
//求B样条拟合后给返回参数指针,注意:使用前务必先调用GetBSpineFit函数,切记
//参数:无
//返回:B样条拟合后给返回参数指针,个数为GetBSpineFit函数里面的nParameter参数 
//////////////////////////////////////////////////////////////////////////////
double* CSpine::GetBSpineFitPointer() const
{
	return m_pBSpineFit;
}

////////////////////////////////////////////////////////////////////////////////
//给定一个点,求B样条拟合后给定一个点求值,注意,求值前必须调用GetBSpineFit函数
//参数:1 x------------指定一个坐标
//      2 nInterval----用户要分的区间个数
//      3 nType--------用户指定的B样条阶数
//返回:该点拟合后的函数值
/////////////////////////////////////////////////////////////////////////////
double CSpine::GetBSpineFitValue(double x,int nParameter,int nType) 
{
	
	double *T=new double[nParameter];
	ASSERT(T);
	double a=m_pTime[0];
	double b=m_pTime[m_nNum-1];
	double h=(b-a)/(nParameter-3);
	for(int i=0;i<nParameter;i++)
		T[i]=a-h+i*h;
	double result=0;
	for(i=0;i<nParameter;i++)
		result+=m_pBSpineFit[i]*ggBFuction((x-T[i])/h,nType);
	delete[] T;
	return result;
	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//内部函数,计算nType-1次B样条的值,暂时可取取 1 ,2 ,3, 4
//参数: 1 x-------指定一个坐标点
//      2 nType---指定B样条函数基的阶数
//返回:函数值
//////////////////////////////////////////////////////////////////////////////////////////////
double CSpine::ggBFuction(double x,int nType)
{
	switch(nType)
	{
	case 1:
		if(fabs(x)==0.5)
			return 0.5;
		else if(fabs(x)<0.5)
			return 1;
		else
			return 0;
		break;
	case 2:
		if(fabs(x)>1)
			return 0;
		else
			return 1-fabs(x);
		break;
	case 3:
		if(fabs(x)>=1.5)
			return 0;
		else if(fabs(x)<0.5)
			return 0.75-x*x;
		else
			return x*x/2.0-1.5*fabs(x)+9/8.0;
		break;
	case 4:
		if(fabs(x)>=2)
			return 0;
		else if(fabs(x)<1)
			return x*x*fabs(x)/2.0-x*x+2/3.0;
		else 
			return x*x-2*fabs(x)+4/3.0-x*x*fabs(x)/6.0;
		break;
	}
	return -1;

}

//////////////////////////////////////////////////////////////////////////
//三次样条插值函数,可以指定5种不同边界类型,返回参数指针(核心函数,必须调用)
double *CSpine::ThreeSpineInsert(UINT nType,double Border[2])
{
	if(m_p3SpineInsert)
		delete[] m_p3SpineInsert;
	m_p3SpineInsert=new double[4*m_nNum-4];
	ASSERT(m_p3SpineInsert);
	//////////////////////////////////////////////////////////////////////////
	//------------------------------------------------------------------------
	//以下调用了作者以前在做计算方法作业时编的代码
	double *H=new double[m_nNum-1];//步长,
	double *m=new double[m_nNum];//二阶导数
	double *d=new double[m_nNum-1];//差分d[0].....d[N-1]
	double *V=new double[m_nNum-1];//求解二阶导数线性方程组的右端向量V[1]...V[N-1]
	double *a=new double[m_nNum-1];//向量a,b,c,表示三对角方程组的系数
	double *b=new double[m_nNum-1];
	double *c=new double[m_nNum-1];
  //double S[MAX][4]; //存储每一个插值区间多项式的系数       
 
  d[0]=(m_pData[1]-m_pData[0])/H[0];
  for(int k=1;k<m_nNum-1;k++)
  {   H[k]=m_pTime[k+1]-m_pTime[k];
      d[k]=(m_pData[k+1]-m_pData[k])/H[k];//相关初赋值
	  a[k]=H[k];
	  b[k]=2*(H[k-1]+H[k]);
	  c[k]=H[k];
	  V[k]=6*(d[k]-d[k-1]);
  }
 double t;
 
  switch(nType)
  {  
      case ST_CLAMPED:
		  {
		   
		   b[1]=b[1]-H[0]/2;
		   t=d[0]-Border[0];
		   V[1]=V[1]-3*t;
	  	   b[m_nNum-2]=b[m_nNum-2]-H[m_nNum-2]/2;
	       t=Border[1]-d[m_nNum-2];
		   V[m_nNum-2]=V[m_nNum-2]-3*t;
		   break;
		  }
	  case 2:
		  {m[0]=0;
		   m[m_nNum-1]=0;
		   break;
		  }
      case 3:
		  {b[1]=b[1]+H[0]*H[0]/H[1];
		   c[1]=c[1]-H[0]*H[0]/H[1];
		   t=H[m_nNum-2]*H[m_nNum-2]/H[m_nNum-3];
		   b[m_nNum-2]=b[m_nNum-2]+H[m_nNum-2]+t;
		   a[m_nNum-3]=a[m_nNum-3]+t;
		   break;
		  }
      case 4:
		  {b[1]=b[1]+H[0];
		   b[m_nNum-2]=b[m_nNum-2]+H[m_nNum-2];
		   break;
		  }
      case 5:
		  {
           V[1]=V[1]-H[0]*Border[0];
		   V[m_nNum-2]=V[m_nNum-2]-H[m_nNum-2]*Border[1];
		   break;
		  }
  }
  for(k=2;k<=m_nNum-2;k++)//该循环是利用高斯主元法求解三对角方程
  {   t=a[k-1]/b[k-1];
      b[k]=b[k]-t*c[k-1];
	  V[k]=V[k]-t*V[k-1];
  }
  m[m_nNum-2]=V[m_nNum-2]/b[m_nNum-2];
  for(k=m_nNum-3;k>=1;k--)
	  m[k]=(V[k]-c[k]*m[k+1])/b[k];//求出每一点的二阶导数,不包括端点
  switch(nType)
  {       //这个switch语句用来求不同情况下端点的二阶导数
      case 1:
		  {t=(d[0]-Border[0])/H[0];
		   m[0]=3*t-m[1]/2;
		   t=(Border[1]-d[m_nNum-2])/H[m_nNum-2];
		   m[m_nNum-1]=3*t-m[m_nNum-3]/2;
		   break;
		  }
      case 2:
		  {m[0]=m[m_nNum-1]=0;
		  break;
		  }
      case 3:
		  {t=(m[2]-m[1])/H[1];
		   m[0]=m[1]-H[0]*t;
		   double ss=(m[m_nNum-1]-m[m_nNum-3])/H[m_nNum-3];
		   m[m_nNum-1]=m[m_nNum-2]+H[m_nNum-2]*ss;
		   break;
		  }
      case 4:
		  {m[0]=m[1];
		   m[m_nNum-1]=m[m_nNum-2];
		   break;
		  }
      case 5:
		  {m[0]=Border[0];
		   m[m_nNum-1]=Border[1];
		   break;
		  }
  }
  for(k=0;k<=m_nNum-2;k++)//回代求各个区间的三次多项式的系数
  {   m_p3SpineInsert[k*4+0]=m_pData[k];
      t=(2*m[k]+m[k+1])/6;
	 m_p3SpineInsert[k*4+1]=d[k]-H[k]*t;
	  m_p3SpineInsert[k*4+2]=m[k]/2;
	m_p3SpineInsert[k*4+3]=(m[k+1]-m[k])/(6*H[k]);
  }
  
  delete[] H;
  delete[] m;
  delete[] d;
  delete[] V;
  delete[] a;
  delete[] b;
  delete[] c;
  return m_p3SpineInsert;
}

double CSpine::GetThreeSpineInsertValue(double x) const
{
	ASSERT(x>=m_pTime[0]&&x<=m_pTime[m_nNum-1]);
	double z;
	int k;
	double t;
	for(int j=1;j<=m_nNum-1;j++)
	  if((m_pTime[j-1]<=x)&&(m_pTime[j]>=x))
	  {   k=j-1;j=m_nNum-1;
		  double w=x-m_pTime[k];
	      t=m_p3SpineInsert[k*4+3]*w+m_p3SpineInsert[k*4+2];
		  z=(t*w+m_p3SpineInsert[k*4+1])*w+m_p3SpineInsert[k*4+0];
	  }
  
       return z;                  
}

⌨️ 快捷键说明

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