资源描述
试验零 Visual C++ 绘图系统
地点: 土木楼B401机房 时间: 星期三下午 节次: 第三大节
一、 试验目标:
1. 了解Visual C++ 绘图基础概念
2. 了解Visual C++ 绘图环境
3. 掌握用Visual C++ 设计绘图项目标基础步骤
4. 掌握用Visual C++ 绘图基础命令
二、 试验内容:
试验内容1:创建绘图应用程序主框架
试验内容2:应用程序编译运行
试验内容3:设置菜单项并生成消息响应函数
试验内容4:SetPixel绘图
三、 试验步骤:
试验内容1:创建绘图应用程序主框架
步骤:
1.创建一个工作目录D:\MyProject
2.开启 Visual Studio
3.单击“文件”->“新建”->“项目”,项目类型对话框中选择“其它语言”->“VC++” ->“MFC”,模版选择“MFC应用程序”。在工作目录D:\MyProject 下创建一个新应用项目: Sample,以下图所表示。
4.单击“确定”按钮。
5.单击“下一步”按钮。
6.在“应用程序类型中”,选择“单文档”类型。
7.单击“完成”,创建了一项空工程-绘图应用程序主框架。
试验内容2:应用程序编译运行
运行版本有两类:Debug、Release, 生成Debug处理方案步骤以下:
1.生成处理方案
点击“生成-〉生成处理方案”, 生成了Debug版可运行程序。
2.调试运行程序
点击菜单“调试——〉开始实施(不调试)”, 实施Debug版可运行程序。
结果以下:
生成Release处理方案步骤以下:
1.生成处理方案
点击“生成-〉批生成”。
2.勾选“Release”,单击“生成”,生成能够独立于Visual C++ 外运行.exe程序。
3.查看目录,sample.exe是Release版,单击即能够运行。
运行结果:
试验内容3:设置菜单项并生成消息响应函数
1.弹出菜单设计器
单击“处理方案管理器”窗口中资源文件Sample.rc,弹出资源视图,
2.插入一项菜单
双击“资源视图”中“Menu”展开文件夹,双击“IDR_MAINFRAME”,弹出菜单设计器。右健单击菜单设计器“帮助”,选择“新插入”,插入一项菜单。
在新插入菜单项“Caption” 中输入“绘图”。
3.输入ID
输入“打开”菜单项,输入“直线”菜单项,在“直线”菜单项下输入“DDA”菜单,“DDA”菜单ID为ID_LINE_DDA。
ID
Caption
功效
ID_LINE_DDA
DDA
用DDA发绘制直线
4.调出类视图窗口
单击菜单“视图-〉类视图”,
在“处理方案管理器”窗口中出现“类视图”窗口。
4.生成菜单消息响应函数
在类视图窗口,单击Csample0View类,单击事件按钮,
5.选择ID_LINE_DDACOMMAND,添加OnLineDDA事件。
6.进入代码编辑器
在void Csample0View::OnLineDda()中 // TODO: 在此添加命令处理程序代码处输入自己代码:
AfxMessageBox("Hello World",MB_OK,NULL);
7.修改项目字符集属性
选择“项目”菜单->属性->,弹出“属性”对话框,选择“配置属性 ->常规->字符集”,改为“未设置”。
8.运行结果
重新生成处理方案,运行结果以下。
试验内容4:SetPixel绘图
在void Csample0View::OnLineDda()中 // TODO: 在此添加命令处理程序代码处输入代码:
// TODO: Add your command handler code here
CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_DOT,1,RGB(255,0,0));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
int x,y;
y=100;
for(x=100;x<=300;x+=3){
y++;
pdc->SetPixelV(x,y,RGB(255,0,0));
}
pdc->DeleteDC();
}
运行结果以下。
四、 试验结果:
试验内容1:创建绘图应用程序主框架结果
试验内容2:应用程序编译运行结果
试验内容3:设置菜单项并生成消息响应函数
试验内容4:SetPixel绘图
五、 回复以下问题:
解释以下每条命令含义
CClientDC *pdc=new CClientDC(this);//定义一个指针类型CClientDC对象,用户区设备上下文用于客//户区输出,和特定窗口关联
CPen pen;//定义一个画笔对象
pen.CreatePen(PS_DOT,1,RGB(255,0,0));//给予pen对象以风格
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);//
pdc->SetPixelV(x,y,RGB(255,0,0));//画出像素坐标为(x,y),风格为红色一点
六、 其它试验内容:
答:工具条按钮添加
七、 试验中发觉问题及你处理方法:
答:发觉问题:调试过程中出现以下错误
处理方法:重新生成处理方案,如还出现则多生成几次。
试验一 直线生成算法
地点: 土木楼B401机房 时间: 星期三下午 节次: 第三大节
一、 试验目标:
1.了解DDA算法
2.了解中点Bresenham算法
3.了解改善Bresenham算法
4.了解DDA和Bresenham算法区分,和生成图形差异原因
二、试验内容:
试验内容1:设计DDA算法程序
试验内容2:设计中点Bresenham算法程序
试验内容3:改善Bresenham算法
三、 试验步骤:
试验内容1:设计DDA算法程序
添加函数:void DDALine(int Xa, int Ya, int Xb, int Yb)
//DDA算法
void CSampleView::DDALine(int Xa, int Ya, int Xb, int Yb)
{
CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_DOT,1,RGB(255,0,0));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
float delta_x,delta_y;int x,y;
int dx,dy,steps,k;
dx=Xb-Xa;
dy=Yb-Ya;
if(abs(dx)>abs(dy))
steps=abs(dx);
else steps=abs(dy);
delta_x=(float)dx/(float)steps;
delta_y=(float)dy/(float)steps;
x=Xa;
y=Ya;
pdc->SetPixelV(x,y,RGB(255,0,0));
for(k=1;k<=steps;k++)
{
x+=(int)delta_x;
y+=(int)delta_y;
pdc->SetPixelV(x,y,RGB(255,0,0));
}
pdc->DeleteDC();
}
添加事件响应函数:
// 消息响应函数DDA算法程序设计画直线
void CSampleView::OnDdaLine()
{
DDALine(100,100,300,300);
}
试验内容2:设计中点Bresenham算法程序
添加函数:void LineBresenhams(int Xa,int Ya,int Xb,int Yb)
//Bresenhams算法程序设计画直线实现
void CSampleView::LineBresenhams(int Xa,int Ya,int Xb,int Yb)
{ CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_DOT,1,RGB(255,0,0));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
int dx=abs(Xa-Xb);
int dy=abs(Ya-Yb);
int p=2*dy-dx;
int twody=2*dy;
int twodydx = 2*(dy-dx);
int x,y,xend;
if(Xa>Xb)
{ x=Xb; y=Yb;
xend=Xa;
}
else
{
x=Xa;y=Ya;
xend=Xb;
}
pdc->SetPixelV(x,y,RGB(255,0,0));;
while(x<xend)
{ x++;
if(p<0)
p+=twody;
else
{
y++;
p+=twodydx; }
pdc->SetPixelV(x,y,RGB(255,0,0));;
}
}添加事件响应函数:
void CSampleView::OnBresenhamline()
{
// TODO: 在此添加命令处理程序代码
LineBresenhams(100,200,300,300);
}
试验内容3:改善Bresenham算法
添加函数:void ImproveBresenhams(int Xa, int Ya, int Xb, int Yb)
//Bresenham算法改善算法实现
void CSampleView::ImproveBresenhams(int Xa, int Ya, int Xb, int Yb)
{ CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_DOT,1,RGB(255,0,0));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
int dx,dy,e,x,y;
dx=Xb-Xa;
dy=Yb-Ya;
e=-dx;
x=Xa;
y=Ya;
while(x<=Xb){
pdc->SetPixelV(x,y,RGB(255,0,0));;
x++;
e+=2*dy;
if(e>0){
y++;
e-=2*dx;
}
}
}
添加事件响应函数:
//菜单响应函数生成直线ImproveBresenhams算法
void CSampleView::OnImprove()
{
// TODO: 在此添加命令处理程序代码
ImproveBresenhams(200,100,300,300);
}
四、 试验结果:
试验内容1:设计DDA算法程序
试验内容2:设计中点Bresenham算法程序
试验内容3:改善Bresenham算法
五、 回复以下问题:
DDA算法缺点是什么?
答:DDA算法缺点是:它y和斜率k必需用浮点数表示,而且每一步全部必需对y进行舍入取整,这不利于用硬件实现。
六、 其它试验内容:
答:添加工具栏按钮DDA,Bresenham,Bresenham改善画直线
在SampleView.cpp中添加代码:
ON_COMMAND(ID_BUTTONDDALine,OnDda)
ON_COMMAND(ID_BUTTONBresenham,OnBresenham)
ON_COMMAND(ID_BUTTONImprovedBresenham,OnImprovedbresenham)
调试点击工具栏按钮查看效果。
七、 试验中发觉问题及你处理方法:
发觉问题:在生成Release文件时出现错误,但调试时没有错误。
处理方法:查了资料,现在还没有处理。
试验二:圆和椭圆生成算法
地点: B401机房 时间: 星期四 节次: 第一大节
一、 试验目标:
1、了解Bresenham法生成圆和椭圆方法
2、掌握Bresenham生成圆和椭圆算法基础思想、推导和算法
二、试验内容:
试验内容1:Bresenham法生成圆
试验内容2:Bresenham法生成椭圆
三、 试验步骤:
试验内容1:Bresenham法生成圆
步骤1:添加菜单“试验二”,子菜单以下:圆 ID_Circle
步骤2:在SampleView类中添加函数bool CircleLine(x1,y1,r)
实现代码:
bool CSampleView::CircleLine(int x1, int y1, int r)
{
CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_DOT,1,RGB(255,0,0));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
int x,y,d;
x = 0; y = r; d = 3 - 2 * r;
while(x < y) {
pdc->SetPixelV(x+x1,y+y1,RGB(255,0,0));
pdc->SetPixelV(y+x1,x+y1,RGB(255,0,0));
pdc->SetPixelV(-y+x1,x+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1,-y+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1,y+y1,RGB(255,0,0));
pdc->SetPixelV(-y+x1,-x+y1,RGB(255,0,0));
pdc->SetPixelV(y+x1,-x+y1,RGB(255,0,0));
pdc->SetPixelV(x+x1,-y+y1,RGB(255,0,0));
if(d < 0) d += 4 * x + 6;
else {
d += 4 * (x - y) + 10;
y --;
}
x ++;
}
if(x == y) {
pdc->SetPixelV(x+x1,y+y1,RGB(255,0,0));
pdc->SetPixelV(y+x1,x+y1,RGB(255,0,0));
pdc->SetPixelV(-y+x1,x+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1,-y+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1,y+y1,RGB(255,0,0));
pdc->SetPixelV(-y+x1,-x+y1,RGB(255,0,0));
pdc->SetPixelV(y+x1,-x+y1,RGB(255,0,0));
pdc->SetPixelV(x+x1,-y+y1,RGB(255,0,0));
}
return true;
}
步骤3;添加画圆菜单响应函数:
void CSampleView::OnCircle()
{
// TODO: 在此添加命令处理程序代码
CircleLine(200,200,100);
}
步骤四:调试运行。
试验内容2:Bresenham法生成椭圆
步骤1:添加菜单“试验二”,子菜单以下:椭圆:ID_Ellipse
步骤2:在SampleView类中添加函数void Ellipse(int x1,int y1,int a, int b)
实现代码:
// 画椭圆函数
void CSampleView::Ellipse(int x1,int y1,int a, int b)
{
CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_DOT,1,RGB(255,0,0));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
float d1,d2;
int x,y;
x=0;
y=b;
d1=b*b+a*a*(-b+0.25);
pdc->SetPixelV(x+x1 ,y+y1 ,RGB(255,0,0));
pdc->SetPixelV(-x+x1 ,-y+y1 ,RGB(255,0,0));
pdc->SetPixelV(x+x1 ,-y+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1 ,y+y1,RGB(255,0,0));
while(b*b*(x+1)<a*a*(y-0.5))
{
if(d1<=0)
{
d1+=b*b*(2*x+3);
x++;
}
else
{
d1+=b*b*(2*x+3)+a*a*(-2*y+2);
x++;
y--;
pdc->SetPixelV(x+x1 ,y+y1 ,RGB(255,0,0));
pdc->SetPixelV(-x+x1 ,-y+y1 ,RGB(255,0,0));
pdc->SetPixelV(x+x1 ,-y+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1 ,y+y1,RGB(255,0,0));
}
}
d2=b*b*(x+0.5)*(x+0.5)+a*a*(y-1)*(y-1)-a*a*b*b;
while(y>0)
{
if(d2<=0)
{
d2+=b*b*(2*x+2)+a*a*(-2*y+3);
x++;
y--;
}
else
{
d2+a*a*(-2*y+3);
y--;
}
pdc->SetPixelV(x+x1 ,y+y1 ,RGB(255,0,0));
pdc->SetPixelV(-x+x1 ,-y+y1 ,RGB(255,0,0));
pdc->SetPixelV(x+x1 ,-y+y1,RGB(255,0,0));
pdc->SetPixelV(-x+x1 ,y+y1,RGB(255,0,0));
}
}
步骤3;添加画圆菜单响应函数:
void CSampleView::OnEllipse()
{
// TODO: 在此添加命令处理程序代码
Ellipse(100,100,20,10);
}
步骤四:调试运行。
四、 试验结果:
1.程序:程序在试验步骤中已经有
2.图形:
五、 回复以下问题:
1、屏幕上显示圆几部分?为何?
答:8部分,因为我们采取画圆方法是八分法画圆,在屏幕上画出是圆8部分。
2、屏幕上显示椭圆几部分?为何?
答:8部分,因为我们在画圆时候在第一象限内画出有两部分:上半部分和下半部分;所以在四个象限内画出是8部分。
六、 其它试验内容:
答:用动态画圆和椭圆方法来画圆:
七、 试验中发觉问题及你处理方法:
答:发觉问题:在调用函数时候用传参方法传输CClientDC *pdc不能运行;
处理方法:舍弃传参,每次画图形时重新申明CClientDC指针对象。
试验三:二维图形基础几何变换
地点: B401机房 时间: 星期四 节次: 第四大节
一、 试验目标:
1、掌握二维图形基础几何变换原理及变换矩阵
2、掌握矩阵运算程序设计
二、试验内容:
1、平移
2、旋转
三、试验步骤:
1、平移
步骤1:初始化函数,画出图形平移前状态。实现在
void CSampleView::OnDraw(CDC* pDC)
{ CSampleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//初始化画出图形平移旋转前状态
static double x1[]={0.0,10.0,100.0,110.0,0.0};
static double y1[]={0.0,50.0,50.0,0.0,0.0};
static double x2[5];
static double y2[5];
int i;
double r;
pDC->MoveTo(scx(0),scy(-ymax/2));
pDC->LineTo(scx(0),scy(ymax/2));
pDC->MoveTo(scx(-xmax/2),scy(0.0));
pDC->LineTo(scx(xmax/2),scy(0.0));
for(int x=0;x<=1;x=x+20)
{
parallel(x,x/2);
for (i=0;i<=4;i++){
x2[i]=affinex(x1[i],y1[i],1.0);
y2[i]=affiney(x1[i],y1[i],1.0);
}
for (i=0;i<=3;i++){
pDC->MoveTo(scx(x2[i]),scy(y2[i]));
pDC->LineTo(scx(x2[i+1]),scy(y2[i+1]));
}
}
}
步骤2:
⑴旋转函数添加,在CSampleView类里添加旋转函数void Rotate();// 旋转
⑵再依次添加辅助函数及变量
public:
int scx(double xj);
int scy(double yj);
public:
double affinex(double x,double y,double d);
double affiney(double x,double y,double d);
public:
void parallel(double dx,double dy);
public:
double f[3][3];
//组员变量
double xmax;
double ymax;
void rotate(double theta);
⑶在SampleView.cpp中依次实现她们,函数以下:
//平移函数
void CSampleView::Pan()
{
// TODO: Add your command handler code here
static double x1[]={0.0,10.0,100.0,110.0,0.0};
static double y1[]={0.0,50.0,50.0,-10.0,0.0};
static double x2[5];
static double y2[5];
int i;
double x;
CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_SOLID,1,RGB(0,0xff,0x1f));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
pdc->MoveTo(scx(0),scy(-ymax/2));
pdc->LineTo(scx(0),scy(ymax/2));
pdc->MoveTo(scx(-xmax/2),scy(0.0));
pdc->LineTo(scx(xmax/2),scy(0.0));
for(x=-300;x<=200;x=x+20){
parallel(x,x/2);
for (i=0;i<=4;i++){
x2[i]=affinex(x1[i],y1[i],1.0);
y2[i]=affiney(x1[i],y1[i],1.0);
}
for (i=0;i<=3;i++){
pdc->MoveTo(scx(x2[i]),scy(y2[i]));
pdc->LineTo(scx(x2[i+1]),scy(y2[i+1]));
}
}
pdc->DeleteDC();
}
int CSampleView::scx(double xj)
{
int x;
x=(int)(xj+xmax/2);
return(x);
}
int CSampleView:: scy(double yj)
{
int y;
y=(int)ymax-(int)(yj+(ymax/2));
return(y);
}
void CSampleView:: parallel(double dx,double dy)
{
f[0][0]=1.0;f[0][1]=0.0;f[0][2]=0.0;
f[1][0]=0.0;f[1][1]=1.0;f[1][2]=0.0;
f[2][0]=dx;f[2][1]=dy;f[2][2]=1.0;
}
double CSampleView::affinex(double x,double y,double d)
{
double xx;
xx=x*f[0][0]+y*f[1][0]+d*f[2][0];
return(xx);
}
double CSampleView::affiney(double x,double y,double d)
{
double yy;
yy=x*f[0][1]+y*f[1][1]+d*f[2][1];
return(yy);
}
⑷添加事件响应函数调用平移函数
void CSampleView::OnPan()
{
// TODO: 在此添加命令处理程序代码
Pan();
}
平移完成。
2、旋转
步骤一:在平移完成基础上添加旋转函数void Rotate()和辅助函数void rotate();
实现函数以下:
void CSampleView::rotate(double theta)
{
double th;
th=theta/180*3.1415927;
f[0][0]=cos(th);f[0][1]=sin(th);f[0][2]=0.0;
f[1][0]=-sin(th);f[1][1]=cos(th);f[1][2]=0.0;
f[2][0]=0.0;f[2][1]=0.0;f[2][2]=1.0;
}
实现代码以下:
//旋转函数
void CSampleView::Rotate()
{
static double x1[]={0.0,10.0,100.0,110.0,0.0};
static double y1[]={0.0,50.0,50.0,0.0,0.0};
static double x2[5];
static double y2[5];
int i;
double r;
CClientDC *pdc=new CClientDC(this);
CPen pen;
pen.CreatePen(PS_SOLID,1,RGB(0,0xff,0x1f));
CPen *oldpen=(CPen*)pdc->SelectObject(&pen);
pdc->MoveTo(scx(0),scy(-ymax/2));
pdc->LineTo(scx(0),scy(ymax/2));
pdc->MoveTo(scx(-xmax/2),scy(0.0));
pdc->LineTo(scx(xmax/2),scy(0.0));
for(r=0;r<360;r=r+10){
rotate(r);
for (i=0;i<=4;i++){
x2[i]=affinex(x1[i],y1[i],1.0);
y2[i]=affiney(x1[i],y1[i],1.0);
}
for (i=0;i<=3;i++){
pdc->MoveTo(scx(x2[i]),scy(y2[i]));
pdc->LineTo(scx(x2[i+1]),scy(y2[i+1]));
}
}
pdc->DeleteDC();
}
添加事件响应函数调用旋转函数:
void CSampleView::Onrotate()
{
// TODO: 在此添加命令处理程序代码
Rotate();
}
旋转完成。
四、试验结果:
1.程序
试验步骤中已包含完整程序代码。
2.图形
程序打开时图:
平移N次后:
旋转n次后:
五、 其它试验内容:
其它内容:用工具栏按钮实现平移和旋转。
六、 试验中发觉问题及你处理方法:
发觉问题:老师给参考程序上有些函数没有定义,需自己编。
处理方法:自己在网上找图形学资料,找到该函数后在程序中自己定义。
展开阅读全文