计算机图形学---多边形裁剪与填充-计算机图形学课程设计(共23页)_第1页
计算机图形学---多边形裁剪与填充-计算机图形学课程设计(共23页)_第2页
计算机图形学---多边形裁剪与填充-计算机图形学课程设计(共23页)_第3页
计算机图形学---多边形裁剪与填充-计算机图形学课程设计(共23页)_第4页
计算机图形学---多边形裁剪与填充-计算机图形学课程设计(共23页)_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、精选优质文档-倾情为你奉上课 程 设 计 报 告课程名称 计算机图形学 课题名称 多边形裁剪与填充 专 业 计算机科学与技术 班 级 计算机0902 学 号 姓 名 指导教师 刘长松 曹 燚 2012年 10 月 9 日湖南工程学院课 程 设 计 任 务 书课程名称 计算机图形学 课 题 多边形裁剪与填充 专业班级 计算机0902 学生姓名 学 号 指导老师 刘长松 曹 燚 审 批 任务书下达日期 2012年 9月 15 日任务完成日期 2012 年 10月 9 日一、设计内容与设计要求1设计内容:交互式地实现多边形的裁剪和填充。2设计要求:1)窗口功能设计。 2)实现鼠标画多边形与数据存储功

2、能。 3)实现鼠标剪裁窗口选择功能。4)实现多边形裁剪和填充功能。3.算法提示:多边形裁剪算法分析:基本思想是一次用窗口的一条边裁剪多边形,窗口的一条边以及延长线构成裁剪线,该线把平面分成两个部分:可见一侧,不可见一侧。用一条裁剪边对多边形进行裁剪,得到一个顶点序列,作为下一条裁剪边处理过程的输入点。对于每一条裁剪边,只是判断点在窗口的哪一测以及求线段与裁剪边的交点算法应随之改变。多边形填充算法分析:确定多边形所占有的最大扫描线数,得到多边形顶点的最小和最大y值(ymin和ymax),从y=ymin 到 y=ymax, 每次用一条扫描进行填充。对一条扫描线填充的过程可分为四个步骤: a.求交b

3、.排序c.交点配对d.区间填色。二、进度安排第 3 周 星期一 8:0012:00星期二 8:0012:00 星期三 8:0012:00 星期四 8:0012:00 星期五 8:0012:00第 4 周 星期一 8:0012:00附:课程设计报告装订顺序:封面、任务书、目录、正文、附件(A4大小的图纸及程序清单)、评分。 正文的格式:一级标题用3号黑体,二级标题用四号宋体加粗,正文用小四号宋体;行距为22。正文的内容:一、课题的主要功能;二、课题的功能模块的划分(要求画出模块图);三、主要功能的实现(至少要有一个主要模块的流程图);四、程序调试;五、总结;六、附件(所有程序的原代码,要求对程序

4、写出必要的注释)。正文总字数要求在5000字以上(不含程序原代码)。一、题目内容说明:1、交互式地实现多边形的裁剪和填充。2、功能要求:1) 窗口功能设计。 2)实现鼠标画多边形与数据存储功能。 4)实现鼠标剪裁窗口选择功能。5) 实现多边形裁剪和填充功能。二、总体设计:本程序使用MFC实现多边形的裁剪和填充绘图程序。多边形裁剪算法分析:基本思想是一次用窗口的一条边裁剪多边形,窗口的一条边以及延长线构成裁剪线,改线把平面分成两个部分:可见一侧,不可见一侧。用一条裁剪边多多边形进行裁剪,得到一个顶点序列,作为吓一条裁剪边处理过程的输入点。对于每一条裁剪边,只是判断点在窗口的哪一测以及求线段与裁剪

5、边的交点算法应随之改变。仅用一条裁剪边时,逐次多边形裁剪框图:在CGraphics类的CutRectangular(CRect)函数中实现对多边形的裁剪多边形填充算法分析:确定多边形所占有的最大扫描线数,得到多边形顶点的最小和最大y值(ymin和ymax),从y=ymin 到 y=ymax, 每次用一条扫描进行填充。对一条扫描线填充的过程可分为四个步骤: a.求交b.排序c.交点配对d.区间填色。在CGraphics类中的FillPlogon函数中实现多边形的填充算法。三、模块设计:各个程序函数的功能,参数,变量的说明:MFC应用程序框架中类的详细解析:1MainFrm:创建窗口及窗口里的菜单

6、、工具栏、状态栏等实现交互的按钮。1)函数int CMainFrame:OnCreate(LPCREATESTRUCT lpCreateStruct)创建菜单、工具栏、状栏。2)BOOL CMainFrame:PreCreateWindow(CREATESTRUCT& cs)设置窗口的大小和初始位置。2图像裁剪View:视图,负责内存数据与用户的交互,包括数据的显示、菜单的选取,鼠标的响应。1. void CMyView:OnLButtonDown(UINT nFlags, CPoint point)对鼠标按下左键的响应,如果是自定义裁剪的区域操作就捕获鼠标按下的点,画裁剪区域,如果是

7、自定义点坐标的操作就捕获鼠标的点画多边形。2. void CMyView:OnMouseMove(UINT nFlags, CPoint point)对 鼠标 移动的响应。用捕获的点画出相应的矩形裁剪边框。画边框的时候,先用白色擦出原先的矩形边框,再用虚线画出新的举行边框3. void CMyView:OnRButtonUp(UINT nFlags, CPoint point)对鼠标放开左键的相应。如果是自定义点的坐标,就获取新的初始裁减矩形范围。4. void CMyView:OnLButtonUp(UINT nFlags, CPoint point)对鼠标放开左键的响应5. void CM

8、yView:OnInitialUpdate()初始化裁剪区域和在窗口中画一个矩形和一个五角星。6. void CMyView:OnDraw(CDC* pDC)重画窗口,用voidCMyView:OnInitialUpdate来启动它,通过消息映射表处理菜单、工具条、快捷键和其他用户消息。定义裁剪矩形区域,并赋值。当自定义多边形坐标时,在各个点坐标处画一个小圆,以显示点的位置。画出多边形。3图像裁剪DOC:文档,负责内存数据与磁盘的交互。1、 void CMyDoc:OnFillployon()2、 void CMyDoc:OnUpdateFillployon(CCmdUI* pCmdUI)3、

9、 void CMyDoc:OnCutRect()4、 void CMyDoc:OnUpdateCutRect(CCmdUI* pCmdUI)4.CGraphics:实现多边形的填充和裁剪。1、 构造函数CGraphics():PointCount(10),Point(NULL)初始化五角星的顶点坐标。2、 析构函数CGraphics()删除动态生成的Point指针。3、 bool DrawPloyon(CDC*);在指定设备中画多边形。4、 bool FillPloyon(CDC*);填充多边形。5、 bool InterCross(CPoint,CPoint,CPoint,CPoint,CP

10、oint&);判断两条线段是否相交。6、 bool CutRect(CRect);对多边形进行裁剪。7、 bool IsInSquareRgn(CRect,CPoint,int);对多边形裁剪时,判断线段断点是否在可视一侧。8、 bool SortArray(int*,int);冒泡排序。四、详细设计:1、创建窗口、菜单、工具栏、状栏的函数。int CMainFrame:OnCreate(LPCREATESTRUCT lpCreateStruct)if (CFrameWnd:OnCreate(lpCreateStruct) = -1)return -1;if (!m_wndToolBa

11、r.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) |!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)TRACE0("Failed to create toolbarn");return -1; / fail to createif (!m_wndStatusBar.Create(this) |!m_wndStatusBar.SetIndic

12、ators(indicators, sizeof(indicators)/sizeof(UINT)TRACE0("Failed to create status barn");return -1; / fail to create/ TODO: Delete these three lines if you don't want the toolbar to/ be dockablem_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&

13、m_wndToolBar);return 0; 2、鼠标按下左键的响应函数void CMyView:OnLButtonDown(UINT nFlags, CPoint point) /对鼠标按下左键的相应CScrollView:OnLButtonDown(nFlags, point);if(m_bDefineRect) /如果是自定义裁减的区域的操作SetCapture();/捕获鼠标m_bCaptured = TRUE;CDC *dc=GetDC();CRect rect(TopLeft,BottomRight);dc->SelectStockObject(WHITE_PEN);dc-

14、>Rectangle(rect);InvalidateRect(rect,false);TopLeft = point;:SetCursor(:LoadCursor(NULL, IDC_CROSS);/设置鼠标样子为十字形的if(m_bDefinePointV)/如果是自定义点坐标的操作PointArray.Add(point);CRect ellipseRect;ellipseRect.top = point.y - 5;ellipseRect.bottom = point.y + 5;ellipseRect.left = point.x - 5;ellipseRect.right =

15、 point.x + 5;InvalidateRect(ellipseRect,true);3、鼠标移动时的响应函数void CMyView:OnMouseMove(UINT nFlags, CPoint point) CScrollView:OnMouseMove(nFlags, point);/对鼠标移动时的相应if (m_bCaptured) /画出相应的矩形裁减边框CDC *dc=GetDC();CRect rect(TopLeft,BottomRight);dc->SelectStockObject(WHITE_PEN);dc->Rectangle(rect);/用白色擦

16、除原先的矩形边框InvalidateRect(rect,false);BottomRight=point;CRect newrect(TopLeft,BottomRight);CPen pen;pen.CreatePen(PS_DOT,1,RGB(0,0,0);dc->SelectObject(pen);dc->Rectangle(newrect);/用虚线画出新的矩形边框 void CMyView:OnLButtonUp(UINT nFlags, CPoint point) CScrollView:OnLButtonUp(nFlags, point);/对鼠标放开左键的响应 if

17、 (m_bCaptured) :ReleaseCapture(); m_bCaptured = false;m_bDefineRect = false;void CMyView:OnViewDefineRect() /设置是否自定义裁减区域m_bDefineRect = true;void CMyView:OnEditDefinePoint() /设置是否自定义点的坐标m_bDefinePointV = true;4、放开鼠标右键的响应void CMyView:OnRButtonUp(UINT nFlags, CPoint point) /对鼠标放开右键的相应CScrollView:OnRBu

18、ttonUp(nFlags, point);if(m_bDefinePointV)CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);pDoc->m_grahics.PointCount=PointArray.GetSize();if(pDoc->m_grahics.Point)delete pDoc->m_grahics.Point;pDoc->m_grahics.Point = new CPointpDoc->m_grahics.PointCount;for(int i=0;i<pDoc->m_grahi

19、cs.PointCount;i+)pDoc->m_grahics.Pointi=PointArray.GetAt(i);/对Point点坐标重新赋值PointArray.RemoveAll();m_bDefinePointV=false;CRect rect;this->GetClientRect(rect);InvalidateRect(rect);/获取新的初始裁减矩形范围int minX = pDoc->m_grahics.Point0.x , minY = pDoc->m_grahics.Point0.y;int maxX = pDoc->m_grahic

20、s.Point0.x , maxY = pDoc->m_grahics.Point0.y;for(i=1;i<pDoc->m_grahics.PointCount;i+)if(minX > pDoc->m_grahics.Pointi.x)minX = pDoc->m_grahics.Pointi.x;if(minY > pDoc->m_grahics.Pointi.y)minY = pDoc->m_grahics.Pointi.y;if(maxX < pDoc->m_grahics.Pointi.x)maxX = pDoc-&

21、gt;m_grahics.Pointi.x;if(maxY < pDoc->m_grahics.Pointi.y)maxY = pDoc->m_grahics.Pointi.y;TopLeft = CPoint(minX,minY);BottomRight = CPoint(maxX,maxY);5、初始化函数void CMyView:OnInitialUpdate()CScrollView:OnInitialUpdate();CSize sizeTotal;sizeTotal.cx = sizeTotal.cy = 100;SetScrollSizes(MM_TEXT, s

22、izeTotal);CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/设置初始的裁减区域int minX = pDoc->m_grahics.Point0.x , minY = pDoc->m_grahics.Point0.y;int maxX = pDoc->m_grahics.Point0.x , maxY = pDoc->m_grahics.Point0.y;for(int i=1;i<pDoc->m_grahics.PointCount;i+)if(minX > pDoc->m_grahic

23、s.Pointi.x)minX = pDoc->m_grahics.Pointi.x;if(minY > pDoc->m_grahics.Pointi.y)minY = pDoc->m_grahics.Pointi.y;if(maxX < pDoc->m_grahics.Pointi.x)maxX = pDoc->m_grahics.Pointi.x;if(maxY < pDoc->m_grahics.Pointi.y)maxY = pDoc->m_grahics.Pointi.y;TopLeft = CPoint(minX,minY

24、);BottomRight = CPoint(maxX,maxY);6、重画窗口的函数,是MFC自动生成的,我们可以在里面添加自己的代码,用来实现消息映射表处理菜单、工具条、快捷键和其他用户消息。void CMyView:OnDraw(CDC* pDC)CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ TODO: add draw code for native data hereint left,top,right,buttom;left=min(TopLeft.x,BottomRight.x);right=max(TopLeft.x,Bot

25、tomRight.x);top=min(TopLeft.y,BottomRight.y);buttom=max(TopLeft.y,BottomRight.y);CRect rect(left,top,right,buttom);/定义裁减矩形区域,并赋值CPen penDot,penSolid;penDot.CreatePen(PS_DOT,1,RGB(0,0,0);pDC->SelectObject(penDot);pDC->Rectangle(rect);/用虚线画出裁减矩形区域penSolid.CreatePen(PS_SOLID,1,RGB(0,0,0);pDC->

26、SelectObject(penSolid);if(PointArray.GetSize()/当自定义多边形点坐标时,在各个点坐标处画一个小圆,以显示点的位置int i;for(i=0;i<PointArray.GetSize();i+)pDC->MoveTo(PointArray.GetAt(i);CRect ellipseRect;ellipseRect.top = PointArray.GetAt(i).y - 5;ellipseRect.bottom = PointArray.GetAt(i).y + 5;ellipseRect.left = PointArray.GetA

27、t(i).x - 5;ellipseRect.right = PointArray.GetAt(i).x + 5;pDC->Ellipse(ellipseRect);if(pDoc->bCutRect) /判断是否裁减,若是,则根据裁减区域进行裁减pDoc->m_grahics.CutRect(rect);pDoc->bCutRect=false;pDoc->m_grahics.DrawPloyon(pDC);/画出多边形if(pDoc->bFillPloyon)/判断是否填充,根据需要进行相应的操作pDoc->m_grahics.FillPloyon

28、(pDC);pDoc->bFillPloyon=false;7、在指定的pDC设备中,画多边形bool CGraphics:DrawPloyon(CDC* pDC)if(PointCount < 3)return false;/若多边形小于三个点则返回pDC->MoveTo(Point0);for(int i=1;i<PointCount;i+)pDC->LineTo(Pointi);pDC->LineTo(Point0);/在pDC中画出多边形return true;8、填充多边形函数,重量级的函数/在指定的pDC设备中,填充多边形bool CGraphi

29、cs:FillPloyon(CDC* pDC)if(PointCount < 3)return false;/若多边形小于三个点则返回int minX = Point0.x , minY = Point0.y;int maxX = Point0.x , maxY = Point0.y;for(int i=1;i<PointCount;i+)if(minX > Pointi.x)minX = Pointi.x;if(minY > Pointi.y)minY = Pointi.y;if(maxX < Pointi.x)maxX = Pointi.x;if(maxY &

30、lt; Pointi.y)maxY = Pointi.y;/获取多边形中所有坐标点的最大值和最小值,作为扫描线循环的范围CUIntArray myArray;int x,y;for(y=minY;y<maxY;y+)/扫描线从minY开始到maxYfor(i=0;i<PointCount;i+)/对每条边进行循环CPoint PointCross;int beforeI=BeforeIndex(i),afterI=AfterIndex(i);/判断是否跟线段相交if(InterCross(PointbeforeI,Pointi,CPoint(minX,y),CPoint(maxX,

31、y),PointCross)/若是存在交点,则进行相应的判断,即判断x的坐标取两次、一次还是不取if(PointCross=Pointi)if(PointbeforeI.y > PointCross.y) && (PointafterI.y > PointCross.y)myArray.Add(PointCross.x);myArray.Add(PointCross.x);/边顶点的y值大于交点的y值,x坐标取两次elseif(PointbeforeI.y - PointCross.y) * (PointafterI.y - PointCross.y) < 0

32、)myArray.Add(PointCross.x);/边顶点的y值在交点的y值之间,即一个顶点的y值大于交点的y值,而另一个小于,相应的x坐标取一次elseif(PointCross.y=PointafterI.y)myArray.Add(PointCross.x); else if(PointCross=PointbeforeI)continue;elsemyArray.Add(PointCross.x);/当交点不在线段的顶点时,x坐标只取一次int *scanLineX,num=myArray.GetSize();scanLineX = new intnum;for(i=0;i<

33、num;i+)scanLineXi=myArray.GetAt(i);/获取扫描线x值,以构成填充区间myArray.RemoveAll();SortArray(scanLineX,num);/对scanLine(扫描线x坐标进行排序)for(i=0;i<num;i=i+2)if(i+1>=num)break;for(x=scanLineXi;x<scanLineXi+1;x+)/x值配对填充pDC->SetPixelV(CPoint(x,y),RGB(255,0,0);/将填充区间相应点的颜色设置成红色 Sleep(1);/CPU暂停1ms,以体现出多边形是以扫描线的

34、方式,一条一条的填充的delete scanLineX;return true;9、裁剪多边形的函数,重量级的函数bool CGraphics:CutRect(CRect rect)CPoint rectPoint4;rectPoint0.x = rect.left;rectPoint0.y = rect.top;rectPoint1.x = rect.right;rectPoint1.y = rect.top;rectPoint3.x = rect.left;rectPoint3.y = rect.bottom;rectPoint2.x = rect.right;rectPoint2.y =

35、 rect.bottom;/获取裁减矩形的四个点的坐标,第一个点为左上,第二个点为右上,第三个点为右下,第四个点为左下int i;CArray<CPoint,CPoint&> myArray;/裁减后,保存的多边形的依次各点的坐标for(int rectNum=0;rectNum<4;rectNum+)/对裁减矩形的四条边进行循环for(i=0;i<PointCount;i+)/对每条边进行循环CPoint PointCross;int beforeI=BeforeIndex(i),afterI=AfterIndex(i);int afterrectNum =

36、(rectNum = 3)?0:rectNum+1);/判断是否跟线段相交if(InterCross(PointbeforeI,Pointi,rectPointrectNum,rectPointafterrectNum,PointCross)if(PointCross=Pointi)myArray.Add(Pointi);/交点在线段上,直接添加点坐标在保存多边形的数组中else if(PointCross=PointbeforeI)if(IsInSquareRgn(rect,Pointi,rectNum)myArray.Add(Pointi);/判断是否可视,若是,则添加点坐标elsemyA

37、rray.Add(PointCross);/跟线段相交,但交点不在顶点上,添加交点坐标if(IsInSquareRgn(rect,Pointi,rectNum)myArray.Add(Pointi);/判断是否可视,若是,则添加点坐标elseif(IsInSquareRgn(rect,Pointi,rectNum)myArray.Add(Pointi);/线段不相交,但需判断是否可视,若是,则添加点坐标PointCount=myArray.GetSize();if(Point)delete Point;Point = new CPointPointCount;for(i=0;i<Poin

38、tCount;i+)Pointi=myArray.GetAt(i);/重新赋予点坐标的值myArray.RemoveAll();return true;10、判断判断两条线段是否相交的函数bool CGraphics:InterCross(CPoint objectP1,CPoint objectP2,CPoint scanP1,CPoint scanP2,CPoint& coordinate)/objectP1、objectP2是一条线段的顶点坐标,而scanP1、scanP2是另一条线段的顶点坐标if(objectP1 = objectP2)return false;/若objec

39、tP1、objectP2相等,则构不成线段,退出if(scanP1 = scanP2)return false;/若scanP1、scanP2等,则构不成线段,退出if( ( objectP1.y - objectP2.y ) * ( scanP1.x - scanP2.x )= ( scanP1.y - scanP2.y ) * ( objectP1.x - objectP2.x)/对斜率相等的情况下的处理if(objectP1.y-objectP2.y)*(scanP1.x-objectP1.x)=(objectP1.x-objectP2.x)*(scanP1.y-objectP1.y)/

40、判断两条线段是不是同一条线段coordinate=objectP2;return true;elsereturn false;if(objectP1.x = objectP2.x)/当第一条线段斜率不存在是的,处理办法double x,y;x = objectP1.x;y = (scanP1.y-scanP2.y)*1.0/(scanP1.x-scanP2.x)*(objectP1.x-scanP1.x)+scanP1.y;y = (float)(int)(y+0.5);if(objectP1.y-y)*(y-objectP2.y)>=0) && (objectP1.x-

41、x)*(x-objectP2.x)>=0)/判断交点是不是在该两条线段上coordinate.x = objectP1.x;coordinate.y = (int)(y+0.5);return true;return false;elseif(scanP1.x = scanP2.x)/当第二条线段斜率不存在是的,处理办法double x,y;x = scanP1.x;y = (objectP1.y-objectP2.y)*1.0/(objectP1.x-objectP2.x)*(scanP1.x-objectP1.x)+objectP1.y;y = (float)(int)(y+0.5)

42、;if(objectP1.y-y)*(y-objectP2.y)>=0) && (objectP1.x-x)*(x-objectP2.x)>=0)/判断交点是不是在该两条线段上coordinate.x = scanP1.x;coordinate.y = (int)(y+0.5);return true;return false;else/两条线段斜率都存在时的处理办法double k1,k2;k1 = ( objectP1.y - objectP2.y ) * 1.0 / ( objectP1.x - objectP2.x);k2 = ( scanP1.y - scanP2.y ) * 1.0 / ( scanP1.x - scanP2.x );/k1,k2为计算的两线段的斜率double x,y;x = (scanP1.y-objectP1.y-k2*scanP1.x+k1*objectP1.x)/(k1-k2);y = (k1*k2*scanP1.x-k1*k2*objectP1.x+k2*objectP1.y-k1*scanP1.y)/(k2-k1);x=(float)(int)(x+0.5);y = (float)(int)(y+0.5);

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论