欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3次样条曲线差值函数c++实现

程序员文章站 2022-05-17 21:39:48
...
/*
	mousePoint		为输入的拟合点
	linePoint		为计算后拟合曲线上的点,只要以这些点来画线就可以绘制出曲线
	controlPoint	为计算后得到的理论控制点数组
*/

void B3Line(vector<Point>& mousePoint, vector<Point>& linePoint, vector<Point>& controlPoint)
{

	const int nPointCount = 5;				//	在每一段曲线上要拟合出的点数
	const int nMaxmousePtCount = 300;			//	能够处理的鼠标点数为这个变理值减1
	const int nMaxSiShu = nMaxmousePtCount + 5;

	double d[nMaxSiShu] = { 0 };
	double sishu[nMaxSiShu][nMaxSiShu] = { 0 };	//	用来保存方和程系数和对应行的右值

	double x[nMaxSiShu] = { 0 };			//	用来保存鼠标点的x坐标
	double y[nMaxSiShu] = { 0 };			//	用来保存鼠标点的y坐标

	double q0x = 0.0, q0y = 0.0, qnx = 0.0, qny = 0.0;


	int nCtrlPtCount = mousePoint.size();	    //	实际控制点数
	if (nCtrlPtCount == 0)
	{
		return;
	}

	nCtrlPtCount++;

	q0x = mousePoint[0].x;
	q0y = mousePoint[0].y;
	qnx = mousePoint.back().x;
	qny = mousePoint.back().y;

	int nPt = nCtrlPtCount + 2;					//	理论控制点数

	if (nCtrlPtCount > nMaxmousePtCount) return;
	if (nCtrlPtCount < 3) return;				//	只在已有两个鼠标点的情况下才进行计算



	Point pt = mousePoint[0];
	x[0] = pt.x;
	y[0] = pt.y;
	for (int k = 1; k < nCtrlPtCount; k++)
	{
		Point pt = mousePoint[k - 1];
		x[k] = pt.x;
		y[k] = pt.y;

	}


	//	初始化矩阵
	sishu[0][0] = -0.5; sishu[0][1] = 0.0;		sishu[0][2] = 3.0 / 2;
	sishu[1][0] = 0.0;	sishu[1][1] = 4.0 / 6;	sishu[1][2] = 4.0 / 6;

	for (int i = 2; i <= nPt - 1 - 2; i++)
	{

		sishu[i][i - 1] = 1.0 / 6;
		sishu[i][i] = 4.0 / 6;
		sishu[i][i + 1] = 1.0 / 6;
	}

	sishu[nPt - 2][nPt - 2 - 1] = 2.0 / 9;
	sishu[nPt - 2][nPt - 2] = 4.0 / 6;
	sishu[nPt - 2][nPt - 2 + 1] = 0;
	sishu[nPt - 1][nPt - 2 - 1] = -0.5;
	sishu[nPt - 1][nPt - 2] = 0.0;
	sishu[nPt - 1][nPt - 2 + 1] = 3.0 / 2;

	sishu[0][nPt] = q0x;					sishu[0][nPt + 1] = q0y;
	sishu[1][nPt] = x[0] + 1.0 / 3 * q0x;	sishu[1][nPt + 1] = y[0] + 1.0 / 3 * q0y;

	for (int i = 2; i <= nPt - 1 - 2; i++)
	{
		sishu[i][nPt] = x[i - 1];
		sishu[i][nPt + 1] = y[i - 1];
	}


	sishu[nPt - 2][nPt] = x[nPt - 3] - 1.0 / 9 * qnx;  sishu[nPt - 2][nPt + 1] = y[nPt - 3] - 1.0 / 9 * qny;
	sishu[nPt - 1][nPt] = qnx;						  sishu[nPt - 1][nPt + 1] = qny;
	//	完成矩阵的初始化

	//	进行方程组求解
	for (int i = 0; i < nPt; i++)
	{
		//	找出列主元
		int k = i;
		double max = fabs(sishu[i][k]);
		for (int j = i; j < nPt; j++)
		{
			if (max < fabs(sishu[j][i]))
			{
				k = j;
			}
		}

		if (k != i)
		{
			//	进行含主元行的交换, 第k行和第i行交换
			for (int n = 0; n <= nPt + 1; n++)
			{
				double t = sishu[i][n];
				sishu[i][n] = sishu[k][n];
				sishu[k][n] = t;
			}

		}

		//	将主元化为1

		double temp = sishu[i][i];

		for (k = i; k <= nPt + 1; k++)
		{
			sishu[i][k] = sishu[i][k] / temp;
		}

		for (int nn = 0; nn < nPt; nn++)
		{
			if (nn != i)
			{
				double tt = -1.0 * sishu[nn][i];
				for (int mm = 0; mm <= nPt + 1; mm++)
				{
					sishu[nn][mm] += sishu[i][mm] * tt;
				}
			}
		}

	}
	//	完成方程组的求解

	//	取出解得的值, 理论控制点
	controlPoint.clear();
	for (int i = 0; i < nPt; i++)
	{
		x[i] = sishu[i][nPt];
		y[i] = sishu[i][nPt + 1];
		Point pt;
		pt.x = x[i];
		pt.y = y[i];
		controlPoint.push_back(pt);
	}


	//	跟据计算出来的理论控制点,进行三次B样条计算
	linePoint.clear();
	for (int i = 2; i <= nPt - 3; i++)
	{
		for (int j = 0; j <= nPointCount; j++)
		{
			double t = 1.0 * j / nPointCount;
			double t2 = t * t;
			double t3 = t * t * t;

			double xPt = 1.0 / 6 * (1 - 3 * t + 3 * t2 - t3) * x[i - 1] + 1.0 / 6 * (4 - 6 * t2 + 3 * t3) * x[i] + 1.0 / 6 * (1 + 3 * t + 3 * t2 - 3 * t3) * x[i + 1] + 1.0 / 6 * t3 * x[i + 2];
			double yPt = 1.0 / 6 * (1 - 3 * t + 3 * t2 - t3) * y[i - 1] + 1.0 / 6 * (4 - 6 * t2 + 3 * t3) * y[i] + 1.0 / 6 * (1 + 3 * t + 3 * t2 - 3 * t3) * y[i + 1] + 1.0 / 6 * t3 * y[i + 2];

			Point pt;
			pt.x = xPt;
			pt.y = yPt;
			linePoint.push_back(pt);
		}
	}
}

相关标签: 样条曲线 插值