第五章曲线和曲面.docx
《第五章曲线和曲面.docx》由会员分享,可在线阅读,更多相关《第五章曲线和曲面.docx(71页珍藏版)》请在冰豆网上搜索。
第五章曲线和曲面
曲线和曲面
第一节Hermite多项式
1.1三次Hermite多项式
Hermite多项式是非常有用的曲线形式。
三次Hermite多项式就是一类常用的曲线,因为它们提供了对形状的局部控制,并且提供了C1连续性。
若给定参数方程f(t)在起点和终点的位置
、
和一阶导数
、
,则可以利用下式构造一个三次Hermite多项式:
式中式
(t)就是对于函数f(t)的Hermite插值多项式,矩阵H称为Hermite矩阵
绘制三次Hermite曲线,用户必须指定位置和导数。
一种方式是通过用户通过鼠标确定曲线的起点和终点的位置,并给出起点和终点的导数,可给出三次Hermite多项式所需的插值信息。
1.2Hermite曲线绘制的程序设计
根据给出的三次Hermite多项式,利用逐点绘制的方法即可实现三次Hermite多项式的绘制。
程序“Hermite”的设计步骤如下:
(1)创建工程名称为“Hermite”单文档应用程序框架。
(2)添加消息处理函数。
利用ClassWizard(类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName栏中选择CHermiteView,根据表1建立如下的消息映射函数,ClassWizard会自动完成有关的函数声明。
表1菜单项的消息处理函数
标示符ID
消息
消息处理函数
CHermiteView
WM_LBUTTONDOWN
OnLButtonDown(UINTnFlags,CPointpoint);
CHermiteView
WM_LBUTTONUP
OnLButtonUp(UINTnFlags,CPointpoint);
CHermiteView
WM_MOUSEMOVE
OnMouseMove(UINTnFlags,CPointpoint);
(3)添加函数。
在工程中添加应用函数的方法,这里先在HermiteView.h中声明需要使用的函数名称,然后再在HermiteView.cpp中定义此函数。
//HermiteView.h:
interfaceoftheCHermiteViewclass
//
/////////////////////////////////////////////////////////////////////////////
constintN=3;//N次Hermite曲线
constintnpoints=50;//由npoints+1个点构成的折线逼近Hermite曲线
classPoint//二维平面点Point类
{
public:
doublex,y;//二维平面中的点坐标为双精度浮点小数
Point(){x=0;y=0;};//构造函数
Point(double_x,double_y){x=_x;y=_y;};//构造函数
Point(CPointp){x=p.x;y=p.y;};//构造函数
inlinePointoperator=(Pointp){x=p.x;y=p.y;return(*this);};//Point对象的赋值运算
inlinePointoperator=(CPointp){x=p.x;y=p.y;return(*this);};//CPoint对象的赋值运算
inlinePointoperator+=(Pointp){x+=p.x;y+=p.y;return(*this);};//重载+=运算
inlinePointoperator+=(CPointp){x+=p.x;y+=p.y;return(*this);};//重载+=运算
inlinePointoperator-=(Pointp){x-=p.x;y-=p.y;return(*this);};//重载-=运算
inlinePointoperator-=(CPointp){x-=p.x;y-=p.y;return(*this);};//重载-=运算
inlinePointoperator*=(doubles){x*=s;y*=s;return(*this);};//重载*=运算
inlinePointoperator/=(doubles){x/=s;y/=s;return(*this);};//重载/=运算
inlinePointoperator+(Pointp){Pointt;t.x=x+p.x;t.y=y+p.y;return(t);};//重载+运算
inlinePointoperator+(CPointp){Pointt;t.x=x+p.x;t.y=y+p.y;return(t);};//重载+运算
inlinePointoperator-(Pointp){Pointt;t.x=x-p.x;t.y=y-p.y;return(t);};//重载-运算
inlinePointoperator-(CPointp){Pointt;t.x=x-p.x;t.y=y-p.y;return(t);};//重载-运算
inlinePointoperator*(doubles){Pointt;t.x=x*s;t.y=y*s;return(t);};//重载*运算
inlinePointoperator/(doubles){Pointt;t.x=x/s;t.y=y/s;return(t);};//重载/运算
inlineoperatorCPoint(){returnCPoint((int)x,(int)y);};//类型强制转换运算
};
classCHermiteView:
publicCView
{
......
public:
intm_nCount;//记录鼠标左键按下的次数
CPointm_Newpoint;//记录鼠标移动时的位置坐标
PointptControlPts[N+1];//曲线控制点坐标
PointptPts[npoints+1];//逼近曲线的折线点坐标
public:
voidhermite_to_points(PointCP[],Pointpts[],intnpoints);//计算Hermite曲线上各点的坐标值
Pointhermite(PointV[],doubleu);//计算Hermite曲线在参数为u的坐标值
......
//Generatedmessagemapfunctions
protected:
//{{AFX_MSG(CHermiteView)
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);
afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);
afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//HermiteView.cpp:
implementationoftheCHermiteViewclass
//
CHermiteView:
:
CHermiteView()
{
m_nCount=0;//鼠标左键按下的次数初始化为0
}
voidCHermiteView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
ptControlPts[m_nCount]=point;//保存鼠标左键按下的当前位置
m_Newpoint=point;//存放画线的起始位置
m_nCount=(++m_nCount)%(N+1);//记录鼠标左键按下的次数,次数>=N+1时,归零
CView:
:
OnLButtonDown(nFlags,point);
}
voidCHermiteView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
inti;
if(m_nCount==0)//m_nCount为0时,说明鼠标左键按下的次数为N+1的整数倍,绘制曲线
{
CClientDCdc(this);
CPenpen,*oldpen;
pen.CreatePen(PS_SOLID,1,RGB(255,0,0));//创建红色实线画笔,线宽为1
oldpen=dc.SelectObject(&pen);//选择新画笔
hermite_to_points(ptControlPts,ptPts,npoints);//当控制点的个数满足要求时,计算Hermite曲线上各点位置
dc.MoveTo(ptPts[0]);//将Hermite曲线上各点位置相连,绘制Hermite曲线
for(i=1;idc.LineTo(ptPts[i]);
dc.SelectObject(oldpen);//恢复老画笔
}
CView:
:
OnLButtonUp(nFlags,point);
}
voidCHermiteView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
if(m_nCount>0&&m_nCount<=N&&m_nCount%2==1)//绘制曲线起点和终点的切向量
{
CClientDCdc(this);
dc.SetROP2(R2_NOT);//设置绘图模式,以屏幕颜色的相反色绘图
//以重绘的方式擦除前一个OnMouseMove绘制的直线
dc.MoveTo((CPoint)ptControlPts[m_nCount-1]);//擦除前面刚绘制的一条直线
dc.LineTo(m_Newpoint);
dc.MoveTo((CPoint)ptControlPts[m_nCount-1]);//从起始位置到当前位置绘制一条新的直线
dc.LineTo(point);
m_Newpoint=point;//存放当前鼠标位置
}
CView:
:
OnLButtonUp(nFlags,point);
}
//输入参数CP为控制点坐标
//控制点CP的个数为N+1
//输出参数为Hermite曲线上的离散点序列pts
//离散点pts的个数为npoints+1
voidCHermiteView:
:
hermite_to_points(PointCP[],Pointpts[],intnpoints)
{
doubleu,delt;
PointP[N+1],V[N+1];
delt=1/(double)(npoints);//将参数u变化区间进行npoints等分
u=0;
//Hermite矩阵与控制点坐标相乘,得到V
P[0]=CP[0];
P[1]=CP[2];
P[2]=CP[1]-CP[0];
P[3]=CP[3]-CP[2];
V[0]=P[0]*2-P[1]*2+P[2]+P[3];
V[1]=P[0]*(-3)+P[1]*3-