实验二实验三 基本图形.docx
《实验二实验三 基本图形.docx》由会员分享,可在线阅读,更多相关《实验二实验三 基本图形.docx(16页珍藏版)》请在冰豆网上搜索。
![实验二实验三 基本图形.docx](https://file1.bdocx.com/fileroot1/2022-11/25/7e86fdf4-d476-4912-b415-3aaba9b25182/7e86fdf4-d476-4912-b415-3aaba9b251821.gif)
实验二实验三基本图形
实验二基本图形(元)生成技术
(一)
直线生成算法
一、实验目的
在一个图形系统中,基本图形(也称为图元、图素等)的生成技术是最基本的,任何复杂的图形都是由基本图形组成的,基本图形生成的质量直接影响该图形系统绘图的质量。
所以,需要设计出精确的基本图形生成算法,以确保图形系统绘图的精确性。
本次实验的目的就是验证直线生成的三种扫描算法,并要求对基本算法进行扩充和改进,包括:
利用VisualC++实现三种直线生成算法,验证算法的正确性;
二、实验任务
1.理解三种直线生成算法思想,写出实现程序;
2.添加鼠标功能,实现交互式画直线程序;
3.将10个像素作为步距单位,编出Bresenham算法的示例。
三、基本知识和实验步骤
任务一:
实现DDA画线程序
实验步骤:
1.建立一个DDALine的工程文件;
2.添加ddaline()成员函数
方法:
在工作区中选择CLASSVIEW类窗口,右击CDDAlineView类,选择“addmemberfunction…”,定义如下的成员函数:
voidddaline(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor);
3.编写自定义的成员函数ddaline()程序
voidCDDALineView:
:
ddaline(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor)
{
intlength,i;
floatx,y,dx,dy;
length=abs(x1-x0);
if(abs(y1-y0)>length)
length=abs(y1-y0);
dx=(x1-x0)/length;
dy=(y1-y0)/length;
x=x0+0.5;y=y0+0.5;
for(i=1;i<=length;i++)
{
pDC->SetPixel((int)x,(int)y,color);
x=x+dx;y=y+dy;
}
}
4.编写OnDraw()函数
voidCDDALineView:
:
OnDraw(CDC*pDC)
{
CDDALineDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
ddaline(pDC,100,100,400,100,RGB(255,0,0));
ddaline(pDC,400,100,400,400,RGB(0,255,0));
ddaline(pDC,400,400,100,400,RGB(0,0,255));
ddaline(pDC,100,400,100,100,RGB(255,255,0));
ddaline(pDC,100,100,400,400,RGB(255,0,255));
ddaline(pDC,100,400,400,100,RGB(0,255,255));}
}
5.编译、调试和运行程序,查看程序结果。
任务二、放大10倍后,算法演示程序
先画出(100,100)到(600,400)大小为10的网格,然后从(100,100)以10为单位,计算出直线上各个像素位置。
步骤:
1.建立DDA2Line工程;
2.在OnDraw()函数中画出网格,并调用DDA2Line()函数
voidCDDA2LineView:
:
OnDraw(CDC*pDC)
{
CDDA2LineDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
//画网格
intgi,gj;
//画横线
pDC->TextOut(90,90,"(100,100)");
pDC->MoveTo(100,100);
for(gj=100;gj<=400;gj=gj+10)
{
pDC->MoveTo(100,gj);
pDC->LineTo(600,gj);
}
//画竖线
pDC->MoveTo(100,100);
for(gi=100;gi<=600;gi=gi+10)
{
pDC->MoveTo(gi,100);
pDC->LineTo(gi,400);
}
pDC->TextOut(590,410,"(600,400)");
//画出像素点
DDA2line(pDC,100,100,600,400,RGB(255,0,0));
}
3.添加DDA2Line()成员函数
方法:
在工作区中选择CLASSVIEW类窗口,右击CDDAlineView类,选择“addmemberfunction…”,定义如下的成员函数:
voidDDA2Line(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor);
4.编写DDA2Line()函数
voidCDDA2LineView:
:
DDA2line(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor)
{
intlength,i,tx,ty;
floatx,y,dx,dy;
length=abs(x1-x0);
if(abs(y1-y0)>length)
length=abs(y1-y0);
dx=(float)(x1-x0)/length;
dy=(float)(y1-y0)/length;
//chartbuf[20];
//sprintf(tbuf,"dx,dy=%f,%f",dx,dy);
//AfxMessageBox(tbuf);
x=x0;y=y0;
for(i=0;i<=length;i=i+10)
{
tx=(int)((x+5)/10)*10;
ty=(int)((y+5)/10)*10;
pDC->SetPixel(tx,ty,color);
pDC->Ellipse(tx-5,ty-5,tx+5,ty+5);
x=x+dx*10;y=y+dy*10;
}
}
5.调试、运行程序
任务三、加入鼠标功能,实现交互式画直线
第一步:
建立DDAMouseLine工程文件;
第二步:
向视图类中添加自定义的成员变量
用鼠标右键单击视图类,选择“AddMemberVariable…”,添加下面三个成员变量。
proctected:
CPointm_p1;//起点
CPointm_p2;//终点
intm_ist;//区别,m_ist=0,表示直线起点,
//m_ist=1,表示直线终点
第三步:
向视图类中添加自定义的成员函数原型:
public:
voidDDAMouseLine(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor);
第四步:
在视图类CPP文件的构造函数中初始化成员变量。
视图类的构造函数名与该视图类的名字相同。
在视图类中选择构造函数,如:
CDDAMouseLineView(),用鼠标左键双击,输入下面程序代码:
CDDAMouseLineView:
:
CDDAMouseLineView()
{
//TODO:
addconstructioncodehere
m_p1.x=0;m_p1.y=0;//起点
m_p2.x=0;m_p2.y=0;//终点
m_ist=0;//0,第1点;1,第2点;
}
第五步:
在视图类的OnDraw()函数中加入下列代码,实现视图绘图。
voidCMouseSpringView:
:
OnDraw(CDC*pDC)
{
CMouseSpringDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
pDC->SelectStockObject(NULL_BRUSH);
DDAMouseLine(pDC,m_p1.x,m_p1.y,m_p2.x,m_p2.y,RGB(255,0,0));
//调用自定义的成员函数,用鼠标画直线
}
第六步:
向视图类中添加鼠标OnLButtonDown()函数消息响应函数,并输入鼠标处理程序代码。
voidCMouseSpringView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CDC*pDC=GetDC();
pDC->SelectStockObject(NULL_BRUSH);
if(!
m_ist)//是起点
{
m_p1=m_p2=point;//纪录第一次单击鼠标位置,定起点
m_ist++;
}
else
{
m_p2=point;//记录第二次单击鼠标的位置,定终点的点
m_ist--;//为新绘图作准备
DDAMouseLine(pDC,m_p1.x,m_p1.y,m_p2.x,m_p2.y,RGB(255,0,0));//绘制新直线
}
ReleaseDC(pDC);//释放设备环境
CView:
:
OnLButtonDown(nFlags,point);
}
第七步:
添加成员函数的程序代码。
voidCDDAMouseLineView:
:
DDAMouseLine(CDC*pDC,intx0,inty0,intx1,inty1,COLORREFcolor)
{
intlength,i;
floatx,y,dx,dy;
length=abs(x1-x0);
if(abs(y1-y0)>length)
length=abs(y1-y0);
dx=(float)(x1-x0)/length;
dy=(float)(y1-y0)/length;
x=x0+0.5;y=y0+0.5;
for(i=1;i<=length;i++)
{
pDC->SetPixel((int)x,(int)y,color);
x=x+dx;y=y+dy;
}
//pDC->MoveTo(x0,y0);
//pDC->LineTo(x1,y1);
}
第八步:
编译运行程序,验证运行结果。
程序改进,添加橡皮筋绘图技术,实现交互式画直线。
向视图类中添加鼠标OnMouseMove()函数消息响应函数,并输入鼠标处理程序代码。
voidCDDAMouseLineView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CDC*pDC=GetDC();
intnDrawmode=pDC->SetROP2(R2_NOT);//设置异或绘图模式,并保存原来绘图模式
pDC->SelectStockObject(NULL_BRUSH);
if(m_ist==1)
{
CPointprePnt,curPnt;
prePnt=m_p2;//获得鼠标所在的前一位置
curPnt=point;
//绘制橡皮筋线
DDAMouseLine(pDC,m_p1.x,m_p1.y,prePnt.x,prePnt.y,RGB(255,0,0));
//DrawCircle(pDC,m_bO,prePnt);//用异或模式重复画圆,擦出所画的圆
DDAMouseLine(pDC,m_p1.x,m_p1.y,curPnt.x,curPnt.y,RGB(255,0,0));
//DrawCircle(pDC,m_bO,curPnt);//用当前位置作为圆周上的点画圆
m_p2=point;
}
pDC->SetROP2(nDrawmode);//恢复原绘图模式
ReleaseDC(pDC);//释放设备环境
CView:
:
OnMouseMove(nFlags,point);
}
四、实验结果和分析
1.查看实验结果,验证算法的正确性;
2.对程序进行分析和比较,你还能提出哪些改进和扩充?
例如:
(1)线刷子绘制直线和圆;
(2)方形刷子绘制直线和圆;
(3)虚线和点划线的绘制;
五、实验总结
总结从本次实验中学到了那些知识点或者有哪些感受?
实验三基本图形(元)生成技术
(二)
圆、椭圆生成算法
一、实验目的
编写圆和椭圆的扫描转换算法程序,验证算法的正确性。
二、实验任务
1.编写中点画圆法的扫描转换程序,考虑原点在(x0,y0)处程序的改动;
2.添加鼠标程序,实现交互式画圆;
3.编写中点画椭圆法的扫描转换程序;
4.添加鼠标程序,实现交互式画椭圆;
三、实验内容
任务一:
中点画圆法的扫描转换算法
编写中点画圆法的扫描转换程序,考虑原点在(x0,y0)处程序的改动;
分析:
考虑圆心不再原点,设圆心坐标为(x0,y0)。
通过平移坐标原点到圆心,则第二个8分圆上一点p(x,y),其原始坐标为
x’=x+x0
y’=y+y0
即p’1(x0+x,y+y0)
其它7个对称点分别是:
p’2(x0+y,y+x0),p’3(x0+y,y0-x),p’4(x0+x,y0-y),p’5(x0-x,y0-y),p’6(x0-y,y0-x),p’7(x0-y,y0+x),p’8(x0-x,y0+y)
程序实现步骤:
(1)建立MidPointCircle工程文件;
(2)右击CMidPointCircleView类,建立成员函数
voidMidpointCircle(CDC*pDC,intx0,inty0,intr,COLORREFcolor)
intCirPot(CDC*pDC,intx0,inty0,intx,inty,COLORREFcolor)
(3)编写成员函数代码,程序如下:
voidCMidPointCircleView:
:
MidpointCircle(CDC*pDC,intx0,inty0,intr,COLORREFcolor)
{
//自己补充
}
(4)编写OnDraw(CDC*pDC)函数,程序如下:
voidCMidPointCircleView:
:
OnDraw(CDC*pDC)
{
CMidPointCircleDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
MidpointCircle(pDC,100,100,10,RGB(255,0,0));
MidpointCircle(pDC,500,300,60,RGB(255,255,0));
}
(6)编译、运行程序,查看结果。
任务二:
添加鼠标程序,实现交互式画圆
在任务1的基础上,完成下列步骤:
(1)向视图类中添加自定义的成员变量
用鼠标右键单击视图类,选择“AddMemberVariable…”,添加下面三个成员变量。
proctected:
intm_r;//半径
CPointm_bO;//圆心
CPointm_bR;//圆上的点
intm_ist;//圆心与圆周上点的区别,m_ist=0,表示鼠标左击点为圆心,
//m_ist=1,表示鼠标左击点为圆周上的点
(2)在视图类CPP文件的构造函数中初始化成员变量
CMidPointCircleMouseView:
:
CMidPointCircleMouseView()
{
//TODO:
addconstructioncodehere
m_bO.x=0;m_bO.y=0;//圆心
m_bR.x=0;m_bR.y=0;//圆上的点
m_ist=0;//圆心与圆上的点区别
m_r=0;//圆的半径
}
(3)向视图类中添加自定义的成员函数原型:
public:
intComputeRadius(CPointcenp,CPointardp);
添加成员函数的程序代码:
intCMouseSpringView:
:
ComputeRadius(CPointcenp,CPointardp)
{
intdx=cenp.x-ardp.x;
intdy=cenp.y-ardp.y;
//sqrt()函数的调用,在头文件中加入#include"math.h"
return(int)sqrt(dx*dx+dy*dy);
}
(4)向视图类中添加两个鼠标消息响应函数,并输入鼠标处理程序代码。
具体操作方法与鼠标示例1方法相同。
一个是OnLButtonDown()函数,另一个是OnMouseMove()函数。
程序如下:
voidCMidPointCircleMouseView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CDC*pDC=GetDC();
pDC->SelectStockObject(NULL_BRUSH);
if(!
m_ist)//绘制圆
{
m_bO=m_bR=point;//纪录第一次单击鼠标位置,定圆心
m_ist++;
}
else
{
m_bR=point;//记录第二次单击鼠标的位置,定圆周上的点
m_ist--;//为新绘图作准备
m_r=ComputeRadius(m_bO,m_bR);
MidpointCircle(pDC,m_bO.x,m_bO.y,m_r,RGB(255,0,0));
}
ReleaseDC(pDC);//释放设备环境
CView:
:
OnLButtonDown(nFlags,point);
}
voidCMidPointCircleMouseView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CDC*pDC=GetDC();
intnDrawmode=pDC->SetROP2(R2_NOT);//设置异或绘图模式,并保存原来绘图模式
pDC->SelectStockObject(NULL_BRUSH);
if(m_ist==1)
{
CPointprePnt,curPnt;
prePnt=m_bR;//获得鼠标所在的前一位置
curPnt=point;
//绘制橡皮筋线
m_r=ComputeRadius(m_bO,prePnt);
MidpointCircle(pDC,m_bO.x,m_bO.y,m_r,RGB(255,0,0));//用异或模式重复画圆,擦出所画的圆
//DrawCircle(pDC,m_bO,prePnt);
m_r=ComputeRadius(m_bO,curPnt);
MidpointCircle(pDC,m_bO.x,m_bO.y,m_r,RGB(255,0,0));//用当前位置作为圆周上的点画圆
m_bR=point;
}
pDC->SetROP2(nDrawmode);//恢复原绘图模式
ReleaseDC(pDC);//释放设备环境
CView:
:
OnMouseMove(nFlags,point);
}
任务三:
编写中点画椭圆法的扫描转换程序
程序实现步骤:
(1)建立MidPointEllise工程文件;
(2)右击CMidPointElliseView类,建立成员函数
voidMidpointEllise(CDC*pDC,intx0,inty0,inta,intb,COLORREFcolor)
(3)编写成员函数代码,程序如下:
voidCMidPointEllipseView:
:
MidpointEllise(CDC*pDC,intx0,inty0,inta,intb,COLORREFcolor)
{
//自己补充
}
(4)编写OnDraw()函数
voidCMidPointEllipseView:
:
OnDraw(CDC*pDC)
{
CMidPointEllipseDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
MidpointEllise(pDC,300,200,50,20,RGB(255,0,0));
}
(5)编译、运行程序。
任务四:
添加鼠标程序,实现交互式画椭圆
程序实现步骤:
(1)~(3)同上,建立MidPointElliseMouse工程文件。
(4)添加成员变量
protected:
intb;
inta;
intm_ist;
CPointCenterPoint;
CPointRightBottom;
CPointLeftTop;
(5)在构造函数中赋初值
CMidPointElliseMouseView:
:
CMidPointElliseMouseView()
{
//TODO:
addconstructioncodehere
LeftTop.x=0;LeftTop.y=0;//左上角坐标初值
RightBottom.x=0;RightBottom.y=0;//右下角坐标初值
CenterPoint.x=0;CenterPoint.y=0;//中心点坐标初值
a=0;b=0;//长轴和短轴长度
m_ist=0;//0:
表示第一点,1:
表示第二点
}
(6)添加OnLButtonDown()函数
voidCMidPointElliseMouseView:
:
OnLButton