计算机图形学实验报告 实验 1 使用画线算法绘制直线段 学号 1008140925 姓名 杜艾莲 系别班级 地信 101 实验日期 2011.10.10 指导教师 实验成绩 一 实验目的及要求 1掌握图形学中常用的三种画线算法数值微分法、中点画线法和 Bresenham 画线算法。 2掌握绘制直线的程序设计方法。 3掌握使用文件来保存直线段的方法。 4掌握从文本文件中恢复出直线的方法。 二 实验内容 使用 VC++ 6.0 开发环境分别实现中点画线算法和 Bresenham 画线算法绘制直线注意不能使用 VC 中已有的绘制直线的函数 并以文本文件的形式保存绘制的结果可以从文本文件中恢复出以前绘制过的直线。 三 算法设计与分析 Bresenham 算法绘制直线的程序仅包含整数运算 。 void MidBresenhamLine(int x0,int y0,int x1,int y1,int color) { int dx,dy,d,UpIncre,DownIncre,x,y; if(x0>x1){ x=x1;x1=x0;x0=x; 输入 P0(X0,Y0) 和 P1X1Y1 计算初始值△x△y d=△x-2△y,x=X0,y=Y0 (x,y) x+1,y+1,d 更新为d+2△x-2△y 更新为 更新为 d-2△y (x,y)更新为 x+1,y ,d结束 y=y1;y1=y0;y0=y; } x=x0;y=y0; dx=x1-x0;dy=y1-y0; d=dx-2*dy; UpIncre=2*dx-2*dy;DownIncre=-2*dy; while(x<=x1){ putpixel(x,y,color); X++; if(d<0){ y++; d+=UpIncre; } else d+=DownIncre; } } 四 程序调试及运行结果的自我分析与自我评价 // testView.cpp : implementation of the CTestView class #include "stdafx.h" #include "test.h" #include "testDoc.h" #include "testView.h" #include #include #include #include "DlgInput.h" //CDlgInput 类的头文件 using #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // CTestView IMPLEMENT_DYNCREATE(CTestView, CView) BEGIN_MESSAGE_MAP(CTestView, CView) // ifstream、ofstream 等位于其中 // string 类型需要 namespace std; //{{AFX_MSG_MAP(CTestView) ON_COMMAND(ID_MENUITEM32771, OnMenuitem32771) ON_COMMAND(ID_MENUBRESENHAMLINE, OnMenubresenhamline) ON_COMMAND(ID_MENUCLEARVIEW, OnMenuclearview) ON_COMMAND(ID_FILE_OPEN, OnFileOpen) ON_COMMAND(ID_FILE_SAVE, OnFileSave) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) END_MESSAGE_MAP() // CTestView construction/destruction CTestView::CTestView() { } CTestView::~CTestView() { } BOOL CTestView::PreCreateWindow(CREATESTRUCT& cs) { } // CTestView drawing void CTestView::OnDraw(CDC* pDC) { // CTestView printing BOOL CTestView::OnPreparePrinting(CPrintInfo* pInfo) { } void CTestView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } void CTestView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) // TODO: add construction code here m_nFlag = -1; // 不是任何绘图类型 // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); CTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here if(1==m_nFlag) { } else if(2==m_nFlag) { } } // 中点画线 MidPointLine(m_X0, m_Y0, m_X1, m_Y1, RGB(255,0,0) ); // Bresenham 画线 BresenhamLine(m_X0, m_Y0, m_X1, m_Y1, RGB(0,255,0) ); // default preparation return DoPreparePrinting(pInfo); // TODO: add extra initialization before printing // TODO: add cleanup after printing } // CTestView diagnostics #ifdef _DEBUG void CTestView::AssertValid() const { } void CTestView::Dump(CDumpContext& dc) const { } CTestDoc* CTestView::GetDocument() // non-debug version is inline { } #endif //_DEBUG // CTestView message handlers void CTestView::OnMenuitem32771() { } void CTestView::OnMenubresenhamline() { CView::AssertValid(); CView::Dump(dc); ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestDoc))); return (CTestDoc*)m_pDocument; // TODO: Add your command handler code here m_nFlag = 1; // 中点画线 CDlgInput if(IDOK==dlg.DoModal()) { dlg; m_X0=dlg.m_nX0; m_Y0=dlg.m_nY0; m_X1=dlg.m_nX1; m_Y1=dlg.m_nY1; } RedrawWindow(); //重绘窗口 // TODO: Add your command handler code here m_nFlag = 2; // CDlgInput if(IDOK==dlg.DoModal()) { Bresenham 画线 dlg; m_X0=dlg.m_nX0; m_Y0=dlg.m_nY0; m_X1=dlg.m_nX1; m_Y1=dlg.m_nY1; RedrawWindow(); //重绘窗口 } // 算法: 中点画线 // 输入: 起点(x0,y0),终点(x1,y1); // void CTestView::MidPointLine( int x0, int y0, int x1, int y1, int color ) { // // 浮点数比较方法 b 的比较之前的设置已经保证 b 为正数 } 输入要求 x0<=x1; CDC * pDC=GetDC(); int a,b,d0,d1,d2,d3,d4,d5,d,x,y; b=x1-x0; d=2*a+b; d0=2*a-b; d1=2*a; d2=2*(a+b); d3=2*b; d4=2*(a-b); d5=a-2*b; y=y0; pDC->SetPixel(x,y,color); if(x==x1) { a=y0-y1; // 之前的设置已经保证始终有 x1>=x0 x=x0; // 斜率 k 为无穷大 if(y<=y1) { while(y<=y1) { pDC->SetPixel(x,y,color); } else { y++; } while(y>=y1) { pDC->SetPixel(x,y,color); }// if 斜率 k 为无穷大 else { } y--; } // 斜率 k 为有限值 double k=-a/b; if( k+1>1e-6 && k-1<1e-6 || fabs(k-1)<1e-6 || fabs(k+1)<1e-6) // |k|<=1(即-1<= k <=1)与 1e-6 比较是 if( -b<=-a && -a<=b ) // 用浮点数比较在|k|=1.0f 时容易出问题所以直接用整数比较将斜率 k 转换为 a 与 { if(y<=y1) pDC->SetPixel(x,y,color); pDC->SetPixel(x,y,color); { while(x1 if(y<=y1) { while(xSetPixel(x,y,color); while(x1 ) } } pDC->SetPixel(x,y,color); } // 算法: Bresenham 画线 // 输入: 起点(x0,y0),终点(x1,y1); // void CTestView::BresenhamLine( int x0, int y0, int x1, int y1, int color ) { dx=x1-x0; dy=y1-y0; e=-dx; x=x0;y=y0; while(x<=x1) { x++; e=e+2*dy; if(e>0) } } void CTestView::OnMenuclearview() { // 打开过去保存的文件该文件包含直线的端点坐标 void CTestView::OnFileOpen() { }// else 斜率 k 为有限值 ReleaseDC(pDC); 输入要求 x0<=x1; CDC * pDC=GetDC(); int x,y,dx,dy,e; pDC->SetPixel(x,y,color); {y++; e=e-2*dx; } // TODO: Add your command handler code here m_X0=0; m_Y0=0; m_X1=0; m_Y1=0; RedrawWindow();//重绘窗口 } // TODO: 在此添加命令处理程序代码 if( m_nFlag!=1 && m_nFlag!=2 ) { } CFileDialog if( IDOK == dlgFile.DoModal()) { MessageBox("请先在菜单中选择绘制直线的方法!","提示",MB_ICONWARNING); return; dlgFile (TRUE, _T("txt"), _T(""), OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, _T("线段端点坐标文件(*.txt)|*.txt||"), this); } // 保存当前视图上绘制的所有直线的端点坐标 void CTestView::OnFileSave() { (*.txt)|*.txt||"), this); CString ifstream rFile; rFile.open(fileName,ios::in); if ( ! rFile.is_open() ) { } fileName = dlgFile.GetFileName(); MessageBox("文件打开失败!","提示",MB_ICONWARNING); return; CString strLine0; string int strLine; nX,nY; // 起点、终点两个坐标 rFile>>strLine; strLine0 = strLine.c_str(); nX = atoi( strLine0.Left( strLine0.Find(",") ) ); nY = atoi( strLine0.Mid( strLine0.Find(",")+1 ) ); m_X0 = nX; m_Y0 = nY; // 解析文件如“220,221”表示一个点的 x、y 坐标 rFile>>strLine; strLine0 = strLine.c_str(); nX = atoi( strLine0.Left( strLine0.Find(",") ) ); nY = atoi( strLine0.Mid( strLine0.Find(",")+1 ) ); m_X1 = nX; m_Y1 = nY; RedrawWindow(); } rFile.close(); // TODO: 在此添加命令处理程序代码 CFileDialog dlgFile(FALSE, _T("txt"), _T(""), OFN_OVERWRITEPROMPT, _T(" 线 段 端 点 坐 标 文 件if( IDOK == dlgFile.DoModal()) // 保存文件 { CString strFileName = dlgFile.GetFileName(); // 包含完整路径的文件名称 ofstream wFile; wFile.open(strFileName,ios::out|ios::ate|ios::app); 五 实验心得及建议 实验心得Bresenham 算法是一种很方便很实用很简单的算法它对任意斜率的直线段具有通用性。对于斜率为正且大于 1 的直线段只需交换 x 和 y 之间的规则。对于负斜率除了一个坐标递减而另一个坐标递增外其余的程序是类似的。另外水平、垂直和斜率的绝对值为 1 的直线可以直接装入帧缓冲储存器而无须进行画线算法处理。 建议这个程序还不是最简单的还有改进的空间希望能把程序变得更简洁些。 if ( ! wFile.is_open() ) { } wFile<