用C实现数学函数图形绘制.docx
《用C实现数学函数图形绘制.docx》由会员分享,可在线阅读,更多相关《用C实现数学函数图形绘制.docx(25页珍藏版)》请在冰豆网上搜索。
![用C实现数学函数图形绘制.docx](https://file1.bdocx.com/fileroot1/2023-5/29/318758d3-f58f-49af-86de-469a49733855/318758d3-f58f-49af-86de-469a497338551.gif)
用C实现数学函数图形绘制
用VC++实现数学函数图形绘制
UsetheVC++torealizedrawingfiguresofmathematicfunctions
指导教师:
付勇
制作人:
刘海,卢文娟
Tutor:
Fuyong
Producer:
Liuhai、Luwenjuan
摘要
VisualC++(以下简称VC++)是面向对象与可视化软件开发工具中比较成熟的一类。
MFC是VC++中直接由Microsoft提供的类库,它集成了大量已概念好的类,咱们可以按照需要,挪用相应类,或按照需要自概念类。
正是基于MFC的这种特性,咱们试图设计出具有封装性、独立性的功能模块------函数数据生成模块,函数曲线输出模块,模块之间的桥梁是由模板类CArray派生的CPoint类数组充当的。
函数数据生成模块用来实现对函数的设置并取得采样点,数组取得采样点数据并将其传递到输出模块中。
从整体来看,实现了各程序模块的独立性,使得在函数模块中可任意添加、删除函数,可利用不同的DC和GDI,可实现不同的输出方式,整个工程在函数画图功能上是无穷扩展的。
通过反复的调试和查验,咱们实现了预期目标。
咱们的主要目的是尝试VC++在数学函数画图方面的功能和应用。
这是对VC++的探索,也是对数学函数画图多样化的尝试。
关键字
数学函数图形绘制模板数组三次样条
【Abstract】
VisualC++isoneoftheobjectorientedandvisualsoftwaredeveloper,whichismorematurethanothers.MFCisaclasswarehousewhichissuppliedbyMicrosoft,anditcontainsagreatdealofdefinedclasses.wecantransferthecorrespondedclassifnecessary,orgiveafreshdefinitionaccordingourneeds.ExactlybasedonMFCthiskindofcharacter,wetrytodesignoutthefunctionmoldwhichhavethefunctiontopacktheclassandbeindependent------MoldforcreatingFunctiondata,Moldforoutputtingthefunctioncurve,moldpieceofbornmoldpiecebesentbyCpointArrayraredbytemplatefirstmoldistomakeoutsetsforthefunctionandgetdataweneedwhichwillbesenttothedefinedarray,sonowthearrayhavethedatathatistobegotbythesecondwholeproject,wecanseetheindependenceofeachmold,andexactlywemayincreaseanddecreasefunctionsifnecessary,weevencanusedifferentDCandGDItorealizethecustomedexportationmethodbywhichwecanhaveanewviewofthefunctioncurve.So,thefunctionoftheprojectcanbeextendedrepeatedlydebuggingandexamining,weachieveourmostimportantthingwearetryingistofindawaytoconnecttheVC++andthefiguresofmathmeticisnotonlyaexplorationtoVC++,butalsoaattemptforrealizingdiversifingthemathmeticfunctions.
【Keywords】
Mathematicfunctionsdrawingfigurestemplatearraytripline
一、引言
从事科技研究的人员常常需要解决一些复杂的数学问题,而这些数学问题的解答往往可以从它的函数图形上很直观、明了的表现出来,这时快捷方便的绘制出该数学函数的图形就显得尤其重要。
用Matlab等数学软件就可以够做到这一点,可是当咱们需要在咱们自己的软件产品中快速简练的绘制出众多自概念的数学函数图形时,用Matlab等数学软件就有些麻烦。
所以咱们选择了用VC++来实现数学函数图形的绘制。
随着软件工程技术的不断发展,应用面向对象的编程技术已经成为现今软件开发的重要手腕之一,尤其是VC++的出现,大大推动了面向对象与可视化编程技术的应用与发展。
VC++主要利用了两种方式:
1.用Windows提供的WindowsAPI函数。
2.直接利用Microsoft提供的MFC类库。
咱们选用的是MFCAppwizard(exe)工程。
MFC类库是VC++中直接由Microsoft提供的一种编程资源,是对程序设计的高度抽象,它集成了大量已概念好的类,咱们可以按照需要,挪用相应类,或按照需要自概念有关类,使得程序员的主要精力不用放在程序设计的细节实现上,而放在程序的功能拓展上。
它允许在编程进程中自概念和扩展运用程序中的类,同时还允许对WindowsAPI函数进行存取,从而使运用程序能以最小的规模实现最丰硕的功能,而且能提供高效率的运行代码。
更重要的是,MFC可以封装不同的类,将类封装后,形成一个功能模块。
也就是说,允许为实现功能模块而将不同的类封装。
咱们选择了用VisualC++来实现数学函数图形的绘制。
还有以下几种考虑:
1、VC++的良好特性促使咱们去了解,熟悉和开发;
2、四年来计算数学的学习让咱们产生了对一些数学算法进行深一步的实践探索;
3、用VC++来实现函数的画图功能是很有优势的。
VC++的画图进程直接引用Windows系统本身资源,画图速度很快,不同的映像模式还可以确保图形的准确;其可视化的界面设置简单明了;
4、对图形的绘制和算法的研究是无止境的,很多时候需要更具体、更详尽和易懂的算法设计,这需要选取一种好的语言自己编写。
VC++基于C++语言,易懂且容易掌握。
MFC类库的特性无穷扩展了VC++的功能,用它来实现复杂多变的数学算法无疑是一个好的选择。
VC++运用对象、类、消息传递、封装等概念来构造系统,要实现各类各样图形的绘制,咱们可以将函数看做对象,将各类函数封装起来,形成不同的类,组成函数模块。
将处置数据和输出图形概念在不同的模块中,而模块之间的接口则是通过用VC++的类数组模块概念的CPoint类数组实现的。
二、设计思路
整体结构的设计
正是以上了解使咱们得出了这样一条编程思路:
函数数据生成模块,函数曲线输出模块,中间媒介由CPoint类数组组成。
函数数据生成模块是实现对函数的设置:
包括参数设置,自变量设置,数据输入,并从算法中取得采样点,再将采样点传给CPoint类数组。
函数曲线输出模块则要从CPoint类数组中取得采样点,在已概念好的输出环境中以描点连线的方式绘制图形。
(如图)
(图)
这样的设计既表现了模块间的独立性,也表现了数组在两个模块间的桥梁关系。
由于对函数的设置也是独立的,选择不同的函数会出现与之相适应的设置,绘出相应的函数图形,所以各函数间也是彼此独立的,对整个工程的其他部份是没有影响的。
咱们以sin,cos作为开始的尝试,主要为熟悉VC++的开发环境,构造出良好的画图环境,再以三次样条函数为重点实现对算法的分析,充分利用MFC的优势,达到目的。
大体结构的设计
1.将所要表达的对象封装。
对函数的属性主如果参数设置-----一般用对话框来实现;对函数的服务即函数算法用具体函数来表达,再将具体的函数一个个的封装到为他们创建的函数模块中,使它们完全独立开来;
2.咱们用函数数据生成模块取得了数据-----采样点,为实现合理的函数画图形式,对采样点要做必要的处置后,放入到类数组中;
3.函数曲线输出模块专门负责营造输出气氛:
用画笔仍是画刷,用多文档输出仍是单文档,用那一种映像模式,界面看起来是不是美观。
固然,最终是取得数组中的数据,将它们放到适合的坐标轴上,随即连线成图。
看似独立的三个部份实际上是彼此牵制和彼此照顾的,采样点受到模板数组的影响,通常不同函数取得采样点在放入模板数组前所作的处置也不同。
面临的问题
咱们面临的问题有技术方面的和对每一个函数的具体设置,有如下几个方面:
1.函数参数设置,自变量的范围,函数的具体算法;
2.输出设置:
画图方式,坐标的成立、设置,图形的缩放;
3.对数组模板类的引用;
4.对误差的控制。
解决问题的方式
1、函数数据生成模块方面,咱们利用对话框来完成对自变量范围、各类参数的设置,这使得对函数特性控制更明了和简单。
(如图)
(图)函数参数设置对话框
所要关注的是采样点。
采样点通过算法取得后,需要符合类数组对数据的要求,考虑到屏幕坐标是整型值,因此,所概念的类中的分量类型也应是整型,而采样点的数据类型是多样的,所以输入前,需要对它们进行必要的处置,而又由于受输出模块中映像模式的影响,输出时也有必要对从数组中取得的数据进行处置。
二、CPoint类数组的利用是一个重点。
它是由模数组概念的一个新的类数组类型。
利用模板化,就可使这段程序能够处置某个类型范围内的各类类型的对象。
模板具有两种形式:
函数模板和类模板。
n)
则称
为三次样条插值函数。
边界条件
三次样条插值函数的边界条件:
(j=1,2,……)
函数表达式
知足条件及加上边界条件,的三次样条函数
的表达式,可得
其中
是由分段三次Hermite插值所得的基函数,
;将
,
代入取得
在
上的表达式:
()
所要求的是
按照
和边界条件,得矩阵方程:
如下:
算法
算法步骤:
步1输入初始数据xj,yj(j=0,1,2,……,n)及
和n;
步2j从0到n-1计算hj=xj+1-xj及
[xj,xj+1];
步3j从1到n-1由公式,及计算λj,μj,gj;
步4用追赶法解方程求出;
步5计算的系数或计算在若干点上的值,取得采样点,绘出图形。
程序实现
◆函数关系图
函数数据生成模块函数曲线输出模块
◆三次样条算法实现函数
voidCLLLView:
:
OnCreateYang()
{
Invalidate(TRUE);
InputYang();//挪用InputYang();实现输入初始数据
(j=0,1,2,……,n)及边界条件
和原始数据个数
Zuigan();//挪用Zuigan();实现追赶法求
for(k=xi[0];k{
kx=k;
for(i=0;i;
{
if(kx>=xi[i]&&kx<=xi[i+1])
{
ky=(kx-xi[i+1])*(kx-xi[i+1])*(h[i]+2*(kx-xi[i]))*yi[i]/(h[i]*h[i]*h[i])+
(kx-xi[i])*(kx-xi[i])*(h[i]+2*(xi[i+1]-kx))*yi[i+1]/(h[i]*h[i]*h[i])+
(kx-xi[i+1])*(kx-xi[i+1])*(kx-xi[i])*m[i]/(h[i]*h[i])+
(kx-xi[i])*(kx-xi[i])*(kx-xi[i+1])*m[i+1]/(h[i]*h[i]);
}
}
CPointSegPoint;//概念临时点
=(int)(100*kx);//将采样点值赋给临时点;
=(int)(100*ky);//临时点值存入CPoint类数组m_PntArray;
(SegPoint);
}
Compare();//挪用Compare()函数实现坐标变换;
("Yong()");
("%d",m_Num);
("%d",(int)xi[0]);
("%d",(int)xi[n-1]);
Invalidate(TRUE);//刷新屏幕,挪用OnDraw()函数进行画图;
}
其他功能函数代码见附录。
效果
Ø程序整体效果
函数参数设置对话框
程序整体效果图
Ø三次样条实例
xi
yi
三次样条插值函数的边界条件:
实例图
Ø三次样条函数绘出的sin
sin()参数设置
三次样条参数设置:
xi
0
yi
三次样条插值函数的边界条件:
三次样条函数画图与sin()的比较
从比较画图来看,三次样条函数绘制的图形与原函数图形比较吻合,说明咱们的三次样条函数算法可行,误差控制良好。
四、结论
通过利用VC++的MFC类实现了sin,cos及三样条函数的图形绘制,咱们对VC++的开发环境和运行方式有了更深的熟悉,对数学函数的算法以对函数本身的了解有了新的高度,尤其是将二者结合起来的尝试让咱们对开发软件进程中所碰到的困难有了切身的体会,同时又对寻觅解决问题的前途充满了兴趣,大体实现了咱们要求的预期效果。
但问题是存在的:
●由于自身能力和实践的有限,咱们没能实现过更成心义的函数,进行更深层次的探讨和开发;
●工程本身也有不完善的地方,咱们只是实现了算法,但没能对图的准确性、精度、误差做出精准估量和判断,也没有对算法作进一步的研究,以期取得更简便的算法;
●坐标轴对自变量的范围有必然限制;当自变量范围很大时,函数图形显示的会不完整,影响函数图形的整体效果。
但咱们仍然庆幸自己做了这么个尝试:
若是碰到数学方面一些具体而又需要自己编程时,VC++不失为一个好工具,它的面向对象和可视化的设计,它的编程语言的易于编写和易于理解,它的画图速度,尤其是它的自概念类功能和程序的模块化,都证明它是一个好的开发工具。
在此论文设计进程中,刘海同窗主要负责软件方面的工作,做了许多有创新意义的工作,包括程序模块化的实现、输出方式的概念、坐标轴的肯定和对模板类CArray派生的CPoint类数组的引用等。
卢文娟同窗主要分担了数学函数方面的设计工作;实现了函数数据生成模块,特别是三次样条函数算法的确立。
最后完成了论文的写作。
参考文献
一、VisualC++程序设计教程机械工业出版社黄维通,姚瑞霞
二、用C++语言编写数学常常利用算法人民邮电出版社陈必红
3、C++语言程序设计电子工业出版社吕凤翥
4、C程序设计清华大学出版社谭浩强
五、VisualC++实践与提高--图形图像篇中国铁道出版社李于剑
六、数值分析华中科技大学出版社李庆扬,王能超,易大义
致谢
衷心的感激咱们的指导教师付勇老师,他从一开始的程序整体设计,到程序的具体实施和论文的最后成形,为咱们解决了许多疑难问题,提出了许多意见,尤其是在引用模板类CArray派生的CPoint类数组时,帮咱们解决最主要的难题,是整个工程顺利完成的关键。
付老师细致、认真的指导态度一直鼓励着咱们,促使咱们在做毕业论文进程中以严谨的态度对待每一个问题。
咱们还要感激热心的同窗,他们为咱们找来了资料,提出了很多好的观点,最后咱们彼此感激对方,虽然合作期间有时意见相左,但通过咱们的不断的交流、探讨,最后在整个工程的每一个细节都达到了一致,咱们一直合作愉快!
卢文娟刘海
2003/6/10
附录
◆参数输入函数程序代码:
(输入初始数据xj,yj(j=0,1,2,……,n)及f′0,f′n,f"n,f"n和原始数据个数n)
voidCLLLView:
:
InputYang()//三样条参数输入
{
();//数组赋空;
flag=0;
CInput1Input1;//实例化对话框类CInput1,接收要输入数据的个数和段数;
=m_Num;
=n;
if()==IDOK)
{
flag=4;
m_Num=;
n=;
CInput2Input2;//实例化对话框类CInput2,输入边界条件;
=f1;//将默许的边界条件赋给Input2的成员变量;
=f2;
=f3;
=f4;
if()==IDOK)//将Input2成员变量取得的值赋给内存变量;
{
f1=;
f2=;
f3=;
f4=;
for(i=0;i{
CInput3Input3;//实例化对话框类CInput3,输入原始数据;
=i+1;
if()==IDOK)
{
xi[i]=;
yi[i]=;
}
else
break;
}
}
}
}
◆追赶法实现函数程序代码:
(求
)
voidCLLLView:
:
Zuigan()
{
for(i=0;i{
h[i]=(xi[i+1]-xi[i]);
f[i]=(yi[i+1]-yi[i])/h[i];
}
for(i=1;i{
r[i]=h[i]/(h[i-1]+h[i]);
u[i]=h[i]/(h[i]+h[i]);
g[i]=3*(r[i]*f[i-1]+u[i]*f[i]);
}
g[0]=3*f[0]-h[0]*f3/2;
g[n-1]=3*f[n-2]-h[n-2]*f4/2;
b[0]=1/2;
for(i=1;i<=n-2;i++)//追赶法的实现,求解
{
b[i]=u[i]/(2-r[i]*b[i-1]);
}
ni[0]=g[0]/2;
for(i=1;ini[i]=(f[i]-r[i]*ni[i-1])/(2-r[i]*b[i-1]);
m[n-1]=f2;
for(i=n-2;i>0;i--)
m[i]=ni[i]-m[i+1]*b[i];//解出
m[0]=f1;
}
◆绘制坐标轴函数程序代码:
voidCLLLView:
:
DrawCrood(CDC*pDC)//绘制坐标轴;
{
CRectrc;//取得屏幕窗口矩形区域,并赋给rc;
GetClientRect(&rc);//获适当前客户取得矩形区域
m_Dis=0;//在挪用Compare()函数前,此参数为0;
if(sig==1)//按照Compare(),若采样点横坐标值全大于0,则X轴0点左移,使画图的有效区域增加;
m_Dis=+2*m_Riu;
m_Ds=0;
if(sg==1)
m_Ds=+2*m_Riu;
pDC->MoveTo,m_Ds);//移点至屏幕坐标左侧界点;
pDC->LineTo,m_Ds);//划线至屏幕右边界点,成X轴;
pDC->TextOut+60,m_Ds-20,"X");//输出字母X;
pDC->MoveTo(m_Dis,);//移点至屏幕坐标下边界点;
pDC->LineTo(m_Dis,);//划线至屏幕上边界点,成Y轴;
pDC->TextOut(m_Dis-50,+50,"Y");//输出字母Y;
pDC->TextOut(m_Dis-25,m_Ds-15,"0");//输出窗口坐标的原点”0”;
pDC->MoveTo,m_Ds);//画箭头,标出X轴的方向;
pDC->LineTo,m_Ds+7);
pDC->MoveTo,m_Ds);
pDC->LineTo,m_Ds-7);
pDC->MoveTo(m_Dis,;//画箭头,标出Y轴的方向;
pDC->LineTo(7+m_Dis,;
pDC->MoveTo(m_Dis,;
pDC->LineTo(-7+m_Dis,;
pDC->SetTextColor(RGB(0,0,255));//设置输出文本颜色
//X轴刻度
for(i=-m_Riu;i>=;i-=m_Riu)//因为0点已经肯定,以0点为中心向正、负方向标刻度点;
{
j=i/100;
("%d",j);
pDC->TextOut(i+m_Dis-10,m_Ds-20,st);//标出刻度值;
pDC->SetPixel(i+m_Dis,m_Ds-1,(COLORREF)0X00FFFFFF);//描出刻度点;
}
for(i=m_Riu;i<;i+=m_Riu)//因为0点已经肯定,以0点为中心向正、//负方向标刻度点;
{
j=i/100;
("%d",j);
pDC->TextOut(i+m_Dis-10,m_Ds-20,st);//标出刻度值;
pDC->SetPixel(i+m_Dis,m_Ds-1,(COLORREF)0X00FFFFFF);//描出刻度点;
}
//Y轴刻度
for(i=-m_Riu;i>=;i-=m_Riu)
{
j=i/100;
("%d",j);
pDC->TextOut(-40+m_Dis,m_Ds+i+20,st);
pDC->SetPixel(-1+m_Dis,m_Ds+i,(COLORREF)0X00FFFFFF);
}
for(i=m_Riu;i<;i+=m_Riu)
{
j=i/100;
("%d",j);
pDC->Text