计算机辅助与图形学作业(三)——绘制三次样条曲线

如需转载本文,请注明出处。

接着前面的两个系列,继续,这次要绘制的是三次样条曲线。

上来先看一下效果:

接下来上源码:

首先是一个函数,可以根据所给的初值,求出三次样条曲线的参数。

/*
	本程序借助EasyX图像库,绘制三次样条曲线
*/
#include<iostream>
#include<graphics.h>
#include<math.h>
using namespace std;
#define  MAXNUM  50   //定义样条数据区间个数最多为50个
typedef struct SPLINE    //定义样条结构体,用于存储一条样条的所有信息
{ //初始化数据输入
	float x[MAXNUM + 1];    //存储样条上的点的x坐标,最多51个点
	float y[MAXNUM + 1];    //存储样条上的点的y坐标,最多51个点
	unsigned int point_num;   //存储样条上的实际的 点 的个数
	float begin_k1;     //开始点的一阶导数信息
	float end_k1;     //终止点的一阶导数信息
					  //float begin_k2;    //开始点的二阶导数信息
					  //float end_k2;     //终止点的二阶导数信息
					  //计算所得的样条函数S(x)
	float k1[MAXNUM + 1];    //所有点的一阶导数信息
	float k2[MAXNUM + 1];    //所有点的二阶导数信息
							 //51个点之间有50个段,func[]存储每段的函数系数
	float a3[MAXNUM], a1[MAXNUM];
	float b3[MAXNUM], b1[MAXNUM];
	//分段函数的形式为 Si(x) = a3[i] * {x(i+1) - x}^3  + a1[i] * {x(i+1) - x} +
	//        b3[i] * {x - x(i)}^3 + b1[i] * {x - x(i)}
	//xi为x[i]的值,xi_1为x[i+1]的值      
}SPLINE, *pSPLINE;
typedef int RESULT;      //返回函数执行的结果状态,下面为具体的返回选项
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE -1
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef ERR
#define ERR  -2
#endif
						 //
						 /*===============================================================================
						 *** 函数名称: Spline3()
						 *** 功能说明: 完成三次样条差值,其中使用追赶法求解M矩阵
						 *** 入口参数: (pSPLINE)pLine  样条结构体指针pLine中的x[],y[],num,begin_k1,end_k1
						 *** 出口参数: (pSPLINE)pLine  样条结构体指针pLine中的函数参数
						 *** 返回参数: 返回程序执行结果的状态TRUE or FALSE
						 ================================================================================*/
RESULT Spline3(pSPLINE pLine)
{
	float H[MAXNUM] = { 0 };     //小区间的步长
	float Fi[MAXNUM] = { 0 };     //中间量
	float U[MAXNUM + 1] = { 0 };    //中间量
	float A[MAXNUM + 1] = { 0 };    //中间量
	float D[MAXNUM + 1] = { 0 };    //中间量
	float M[MAXNUM + 1] = { 0 };    //M矩阵
	float B[MAXNUM + 1] = { 0 };    //追赶法中间量
	float Y[MAXNUM + 1] = { 0 };    //追赶法中间变量
	int i = 0;
	计算中间参数
	if ((pLine->point_num < 3) || (pLine->point_num > MAXNUM + 1))
	{
		return ERR;       //输入数据点个数太少或太多
	}
	for (i = 0; i <= pLine->point_num - 2; i++)
	{          //求H[i]
		H[i] = pLine->x[i + 1] - pLine->x[i];
		Fi[i] = (pLine->y[i + 1] - pLine->y[i]) / H[i]; //求F[x(i),x(i+1)]
	}
	for (i = 1; i <= pLine->point_num - 2; i++)
	{          //求U[i]和A[i]和D[i]
		U[i] = H[i - 1] / (H[i - 1] + H[i]);
		A[i] = H[i] / (H[i - 1] + H[i]);
		D[i] = 6 * (Fi[i] - Fi[i - 1]) / (H[i - 1] + H[i]);
	}
	//若边界条件为1号条件,则
	U[i] = 1;
	A[0] = 1;
	D[0] = 6 * (Fi[0] - pLine->begin_k1) / H[0];
	D[i] = 6 * (pLine->end_k1 - Fi[i - 1]) / H[i - 1];
	//若边界条件为2号条件,则
	//U[i] = 0;
	//A[0] = 0;
	//D[0] = 2 * begin_k2;
	//D[i] = 2 * end_k2;
	/追赶法求解M矩阵
	B[0] = A[0] / 2;
	for (i = 1; i <= pLine->point_num - 2; i++)
	{
		B[i] = A[i] / (2 - U[i] * B[i - 1]);
	}
	Y[0] = D[0] / 2;
	for (i = 1; i <= pLine->point_num - 1; i++)
	{
		Y[i] = (D[i] - U[i] * Y[i - 1]) / (2 - U[i] * B[i - 1]);
	}
	M[pLine->point_num - 1] = Y[pLine->point_num - 1];
	for (i = pLine->point_num - 1; i > 0; i--)
	{
		M[i - 1] = Y[i - 1] - B[i - 1] * M[i];
	}
	//计算方程组最终结果
	for (i = 0; i <= pLine->point_num - 2; i++)
	{
		pLine->a3[i] = M[i] / (6 * H[i]);
		pLine->a1[i] = (pLine->y[i] - M[i] * H[i] * H[i] / 6) / H[i];
		pLine->b3[i] = M[i + 1] / (6 * H[i]);
		pLine->b1[i] = (pLine->y[i + 1] - M[i + 1] * H[i] * H[i] / 6) / H[i];
	}
	return TRUE;
}

然后是一个坐标转换函数。由于计算的结果所得到的图形比较小,为了显示的方便,将图形放大了,进行了坐标系的变换。默认的坐标系原点在窗口左上方,向下为Y轴正方向,向右为X轴正方向。

void CoordinateTransform(double &x, double &y)
{//坐标转换函数,X轴从27-31,Y轴从2.5到4.5
	x = x*160 - 4320;
	y = -240 * y + 1080;
}

接着是绘制三次样条的函数,x坐标每次按1/2000的值进行递增,并得到对应的y坐标的值,然后将对应点的像素点亮,这样画出的线更加细密。

void DrawCubicSpline(pSPLINE line)
{//绘制三次样条的函数,取离散点对,并将相应的像素点打亮
	int num = line->point_num;
	double y,z;
	int rate = 2000;
	for (int i = 0; i < num - 1; i++)
	{
		for (double  j= line->x[i];j < line->x[i + 1];j += 1.0 / rate)
		{
			//打入三次样条的分段解析式,得到函数值
			y = line->a3[i] * pow((line->x[i + 1] - j), 3) + line->a1[i] * (line->x[i + 1] - j) + line->b3[i] * pow((j - line->x[i]), 3) + line->b1[i] * (j - line->x[i]);
			z = j;
			CoordinateTransform(z, y);
			putpixel(z, y,GREEN);
		}
	}
}

最后主函数中输入初始参数,求出三次样条曲线的参数,并绘制图形即可。

SPLINE line1;								//定义全局变量
pSPLINE pLine1 = &line1;

int main()
{
	line1.x[0] = 27.7;				//对构造样条的参数进行初始化
	line1.x[1] = 28;
	line1.x[2] = 29;
	line1.x[3] = 30;
	line1.y[0] = 4.1;
	line1.y[1] = 4.3;
	line1.y[2] = 4.1;
	line1.y[3] = 3.0;
	line1.point_num = 4;
	line1.begin_k1 = 3.0;			//开始点出的一阶导数
	line1.end_k1 = -4.0;				//结尾点的一阶导数
	Spline3(pLine1);					//求出三次样条的参数方程
	initgraph(640, 480);				//初始化绘图界面
	DrawCubicSpline(pLine1);	//绘制三次样条曲线
	system("pause");
	return 0;
}

所有源码链接:https://github.com/xsgaaaa/Computer-Graphics-Homeworks

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值