实验四 Hermite Bezier B样条三种曲线的绘制
1、实验目的
了解和学习Hermite、Bezier、B样条三种曲线算法
掌握基于 Win32、Visual C++环境MFC绘制图形配置过程制过程
编程实现Hermite、Bezier、B样条三种曲线的绘制
2、实验原理
✧ 三次参数曲线
1. 曲线段可以用端点、切向量和曲线段之间的连续性等约束条件来定义
2. 两个端点和两端点处的切向量定义Hermite曲线;
3. 两个端点和另外两个控制端点切向量的点定义的Bezier曲线;
4. 由四个控制顶点定义的样条曲线。
3、实验关键代码
void CDrawYTQXView::Hermite() //绘制Hermite三次插值样条
{
int a[4][4] ={{2,-2,1,1},{-3,3,-2,-1},{0,0,1,0},{1,0,0,0}};//Mh矩阵系数
int b[4][2];//边界点
for(int i=0;i<4;i++)
{
b[0][0]=p1[i][0];b[0][1]=p1[i][1];//起点的坐标
b[1][0]=p1[i+1][0];b[1][1]=p1[i+1][1];//终点的坐标
b[2][0]=p2[i][0];b[2][1]=p2[i][1];//起点的导数
b[3][0]=p2[i+1][0];b[3][1]=p2[i+1][1];//终点的导数
Caculate(a,b);
CClientDC dc(this);
CPen MyPen,*pOldPen;
MyPen.CreatePen(PS_SOLID,1,RGB(0,0,255));
pOldPen=dc.SelectObject(&MyPen);
dc.MoveTo(p1[i][0],p1[i][1]);
for(double t=0.0;t<=1;t+=1.0/400)
{
int x=ROUND(pow(t,3)*result[0][0]+pow(t,2)*result[1][0]
+ t*result[2][0]+result[3][0]);
int y=ROUND(pow(t,3)*result[0][1]+pow(t,2)*result[1][1]
+ t*result[2][1]+result[3][1]);
dc.LineTo(x,y);
}
dc.SelectObject(pOldPen);
MyPen.DeleteObject();
}
}
void CDrawYTQXView::Caculate(int a[4][4],int b[4][2])//矩阵相乘
{
int i,j,k;
for(i=0;i<4;i++)
for(j=0;j<2;j++)
result[i][j]=0; //矩阵清零
for(i=0;i<2;i++)
for(j=0;j<4;j++)
for(k=0;k<4;k++)
result[j][i]+=a[j][k]*b[k][i];
}
void CDrawYTQXView::DrawBezier()//绘制Bezier曲线
{
CClientDC dc(this);
double x,y;
int rate=400,n;
n=CtrlPoint-1;
for(double t=0;t<=1;t+=1.0/rate)
{
x=0;y=0;
for(int i=0;i<=n;i++)
{
x+=pt[i].x*Cnk(n,i)*pow(t,i)*pow(1-t,n-i);
y+=pt[i].y*Cnk(n,i)*pow(t,i)*pow(1-t,n-i);
}
dc.SetPixel(ROUND(x),ROUND(y),RGB(0,0,255)); //曲线颜色
}
}
double CDrawYTQXView::Cnk(const int &n, const int &i)//Bernstein第一项
{
return double(Factorial(n)/(Factorial(i)*Factorial(n-i)));
}
int CDrawYTQXView::Factorial(int m)//阶乘函数
{
int f=1;
for(int i=1;i<=m;i++)
f*=i;
return f;
}
void CDrawYTQXView::DrawB3_curves() //绘制B样条曲线
{
CClientDC dc(this);
int i,rate=10,m;
long lx,ly;
m=CtrlPoint-(3+1);
double F03,F13,F23,F33;
lx=ROUND((pt[0].x+4.0*pt[1].x+pt[2].x)/6.0); //t=0的起点x坐标
ly=ROUND((pt[0].y+4.0*pt[1].y+pt[2].y)/6.0);//t=0的起点y坐标
dc.MoveTo(lx,ly);
CPen MyPen2,*pOldPen2;
MyPen2.CreatePen(PS_SOLID,2,RGB(0,0,255)); //颜色设置
pOldPen2=dc.SelectObject(&MyPen2);
for(i=1;i
{
for(double t=0;t<=1;t+=1.0/rate)
{
F03=(-t*t*t+3*t*t-3*t+1)/6;//计算F0,3(t)
F13=(3*t*t*t-6*t*t+4)/6;//计算F1,3(t)
F23=(-3*t*t*t+3*t*t+3*t+1)/6;//计算F2,3(t)
F33=t*t*t/6;//计算B3,3(t)
lx=ROUND(pt[i-1].x*F03+pt[i].x*F13+pt[i+1].x*F23+pt[i+2].x*F33);
ly=ROUND(pt[i-1].y*F03+pt[i].y*F13+pt[i+1].y*F23+pt[i+2].y*F33);
dc.LineTo(lx,ly);
}
}
dc.SelectObject(pOldPen2);
MyPen2.DeleteObject();
}
void CDrawYTQXView::DrawCharPolygon()//绘制控制多边形
{
CClientDC dc(this);
CPen MyPen,*pOldPen;
MyPen.CreatePen(PS_SOLID,2,RGB(0,0,0)); //控制多边形
pOldPen=dc.SelectObject(&MyPen);
for(int i=0;i
{
if(i==0)
{
dc.MoveTo(pt[i]);
dc.Ellipse(pt[i].x-2,pt[i].y-2,pt[i].x+2,pt[i].y+2);
}
else
{
dc.LineTo(pt[i]);
dc.Ellipse(pt[i].x-2,pt[i].y-2,pt[i].x+2,pt[i].y+2);
}
}
dc.SelectObject(pOldPen);
MyPen.DeleteObject();
}
void CDrawYTQXView::OnLButtonDown(UINT nFlags, CPoint point)//获得屏幕控制点坐标
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
if(Flag)
{
pt[CtrlPoint].x=point.x;
pt[CtrlPoint].y=point.y;
if(CtrlPoint
CtrlPoint++;
else
Flag=false;
DrawCharPolygon();
}
else DrawCharPolygon1();
}
void CDrawYTQXView::OnRButtonDown(UINT nFlags, CPoint point)//调用绘制函数
{
// TODO: Add your message handler code here and/or call default
Flag=false;
if(Sign==0)Hermite();
if(Sign==1)DrawBezier();
if(Sign==2)DrawB3_curves();
CView::OnRButtonDown(nFlags, point);
}
4、实验结果
1、绘制Hermite曲线
2、绘制Bezier曲线
3. 绘制B样条曲线
5、心得体会
通过实验进一步学习和了解MFC的菜单的实现及其响应函数的实现,并设置鼠标的左键激活绘制多边形,右键激活绘制Hermite、Bezier、B样条三种曲线。
掌握了三个齐次坐标矩阵以及它们各自点的平移,旋转,缩放,错切变换的坐标矩阵。再做实验的同时又很好的复习了考试的内容,一举两得!
本文来源:https://www.2haoxitong.net/k/doc/623bf1d2b9f3f90f76c61b47.html
文档为doc格式