1、课 程 设 计 报 告课程名称 计算机图形学 课题名称 多边形裁剪与填充 专 业 计算机科学与技术 班 级 学 号 姓 名 指导教师 刘长松 曹 燚 年 月 日湖南工程学院课 程 设 计 任 务 书课程名称 计算机图形学 课 题 多边形裁剪与填充 专业班级 学生姓名 学 号 指导老师 刘长松 曹 燚 审 批 任务书下达日期 年 月 日任 务 完 成 日 期 年 月 日一 、 设 计 内 容 与 设 计 要 求1设计内容:交互式地实现多边形的裁剪和填充。 。2设计要求:1)窗口功能设计。2)实现鼠标画多边形与数据存储功能。3)实现鼠标剪裁窗口选择功能。4)实现多边形裁剪和填充功能。3.算法提示:
2、多边形裁剪算法分析:基本思想是一次用窗口的一条边裁剪多边形,窗口的一条边以及延长线构成裁剪线,该线把平面分成两个部分:可见一侧,不可见一侧。用一条裁剪边对多边形进行裁剪,得到一个顶点序列,作为下一条裁剪边处理过程的输入点。对于每一条裁剪边,只是判断点在窗口的哪一测以及求线段与裁剪边的交点算法应随之改变。多边形填充算法分析:确定多边形所占有的最大扫描线数,得到多边形顶点的最小和最大 y 值(ymin和 ymax) ,从 y=ymin 到 y=ymax, 每次用一条扫描进行填充。对一条扫描线填充的过程可分为四个步骤: a.求交 b.排序 c.交点配对 d.区间填色。二、进 度 安 排第 3 周 星
3、期一 8:0012:00星期二 8:0012:00 星期三 8:0012:00星期四 8:0012:00 星期五 8:0012:00第 4 周 星期一 8:0012:00附:课程设计报告装订顺序:封面、任务书、目录、正文、附件(A4 大小的图纸及程序清单) 、评分。 正文的格式:一级标题用 3 号黑体,二级标题用四号宋体加粗,正文用小四号宋体;行距为 22。正文的内容:一、课题的主要功能;二、课题的功能模块的划分(要求画出模块图) ;三、主要功能的实现(至少要有一个主要模块的流程图) ;四、程序调试;五、总结;六、附件(所有程序的原代码,要求对程序写出必要的注释) 。正文总字数要求在 5000
4、 字以上(不含程序原代码) 。一、题目内容说明: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在指定设备中画多边形。4、 bool FillPloyon(CDC*);填充多边形。5、 bool InterCross(CPoint,CPoint,CPoint,CPoint,CPoint判断两条线段是否相交。6、 bool CutRect(CRect);对多边形进行裁剪。7、 bool IsInSquareRgn(CRect,CPoi
7、nt,int);对多边形裁剪时,判断线段断点是否在可视一侧。8、 bool SortArray(int*,int);冒泡排序。四、详细设计:1、创建窗口、菜单、工具栏、状栏的函数。int CMainFrame:OnCreate(LPCREATESTRUCT lpCreateStruct)if (CFrameWnd:OnCreate(lpCreateStruct) = -1)return -1;if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP| CBRS_GRIPPER | CBRS_T
8、OOLTIPS | 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.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)TRACE0(“Failed to create status barn“);return -1
9、; / fail to create/ TODO: Delete these three lines if you dont want the toolbar to/ be dockablem_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(return 0; 2、鼠标按下左键的响应函数void CMyView:OnLButtonDown(UINT nFlags, CPoint point) /对鼠标按下左键的相应CScrollView:OnLButtonDown(nFl
10、ags, point);if(m_bDefineRect)/如果是自定义裁减的区域的操作SetCapture();/捕获鼠标m_bCaptured = TRUE;CDC *dc=GetDC();CRect rect(TopLeft,BottomRight);dc-SelectStockObject(WHITE_PEN);dc-Rectangle(rect);InvalidateRect(rect,false);TopLeft = point;:SetCursor(:LoadCursor(NULL, IDC_CROSS);/设置鼠标样子为十字形的if(m_bDefinePointV)/如果是自定
11、义点坐标的操作PointArray.Add(point);CRect ellipseRect;ellipseRect.top = point.y - 5;ellipseRect.bottom = point.y + 5;ellipseRect.left = point.x - 5;ellipseRect.right = point.x + 5;InvalidateRect(ellipseRect,true);3、 鼠标移动时的响应函数void CMyView:OnMouseMove(UINT nFlags, CPoint point) CScrollView:OnMouseMove(nFlag
12、s, point);/对鼠标移动时的相应if (m_bCaptured) /画出相应的矩形裁减边框CDC *dc=GetDC();CRect rect(TopLeft,BottomRight);dc-SelectStockObject(WHITE_PEN);dc-Rectangle(rect);/用白色擦除原先的矩形边框InvalidateRect(rect,false);BottomRight=point;CRect newrect(TopLeft,BottomRight);CPen pen;pen.CreatePen(PS_DOT,1,RGB(0,0,0);dc-SelectObject(
13、pen);dc-Rectangle(newrect);/用虚线画出新的矩形边框void CMyView:OnLButtonUp(UINT nFlags, CPoint point) CScrollView:OnLButtonUp(nFlags, point);/对鼠标放开左键的响应if (m_bCaptured) :ReleaseCapture();m_bCaptured = false;m_bDefineRect = false;void CMyView:OnViewDefineRect() /设置是否自定义裁减区域m_bDefineRect = true;void CMyView:OnEd
14、itDefinePoint() /设置是否自定义点的坐标m_bDefinePointV = true;4、放开鼠标右键的响应void CMyView:OnRButtonUp(UINT nFlags, CPoint point) /对鼠标放开右键的相应CScrollView:OnRButtonUp(nFlags, point);if(m_bDefinePointV)CMyDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);pDoc-m_grahics.PointCount=PointArray.GetSize();if(pDoc-m_grahics.Poin
15、t)delete pDoc-m_grahics.Point;pDoc-m_grahics.Point = new CPointpDoc-m_grahics.PointCount;for(int i=0;im_grahics.PointCount;i+)pDoc-m_grahics.Pointi=PointArray.GetAt(i);/对 Point 点坐标重新赋值PointArray.RemoveAll();m_bDefinePointV=false;CRect rect;this-GetClientRect(rect);InvalidateRect(rect);/获取新的初始裁减矩形范围i
16、nt 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(i=1;im_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(max
17、X m_grahics.Pointi.x)maxX = pDoc-m_grahics.Pointi.x;if(maxY 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;SetScrollSize
18、s(MM_TEXT, sizeTotal);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;im_grahics.PointCount;i+)if(minX pDoc-m_grahics.Pointi.x)minX = pDoc-m_g
19、rahics.Pointi.x;if(minY pDoc-m_grahics.Pointi.y)minY = pDoc-m_grahics.Pointi.y;if(maxX m_grahics.Pointi.x)maxX = pDoc-m_grahics.Pointi.x;if(maxY m_grahics.Pointi.y)maxY = pDoc-m_grahics.Pointi.y;TopLeft = CPoint(minX,minY);BottomRight = CPoint(maxX,maxY);6、重画窗口的函数,是 MFC 自动生成的,我们可以在里面添加自己的代码,用来实现消息映射
20、表处理菜单、工具条、快捷键和其他用户消息。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,BottomRight.x);top=min(TopLeft.y,BottomRight.y);buttom=max(TopLeft.y,BottomRight
21、.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-SelectObject(penSolid);if(PointArray.GetSize()/当自定义多边形点坐标时,在各个点坐标处画一个小圆,以显示点的位置int i;for(
22、i=0;iMoveTo(PointArray.GetAt(i);CRect ellipseRect;ellipseRect.top = PointArray.GetAt(i).y - 5;ellipseRect.bottom = PointArray.GetAt(i).y + 5;ellipseRect.left = PointArray.GetAt(i).x - 5;ellipseRect.right = PointArray.GetAt(i).x + 5;pDC-Ellipse(ellipseRect);if(pDoc-bCutRect) /判断是否裁减,若是,则根据裁减区域进行裁减pDo
23、c-m_grahics.CutRect(rect);pDoc-bCutRect=false;pDoc-m_grahics.DrawPloyon(pDC);/画出多边形if(pDoc-bFillPloyon)/判断是否填充,根据需要进行相应的操作pDoc-m_grahics.FillPloyon(pDC);pDoc-bFillPloyon=false;7、在指定的 pDC 设备中,画多边形bool CGraphics:DrawPloyon(CDC* pDC)if(PointCount MoveTo(Point0);for(int i=1;iLineTo(Pointi);pDC-LineTo(Po
24、int0);/在 pDC 中画出多边形return true;8、填充多边形函数,重量级的函数/在指定的 pDC 设备中,填充多边形bool CGraphics:FillPloyon(CDC* pDC)if(PointCount Pointi.x)minX = Pointi.x;if(minY Pointi.y)minY = Pointi.y;if(maxX PointCross.y) myArray.Add(PointCross.x);/边顶点的 y 值大于交点的 y 值,x 坐标取两次elseif(PointbeforeI.y - PointCross.y) * (PointafterI.
25、y - PointCross.y) =num)break;for(x=scanLineXi;xSetPixelV(CPoint(x,y),RGB(255,0,0);/将填充区间相应点的颜色设置成红色Sleep(1);/CPU 暂停 1ms,以体现出多边形是以扫描线的方式,一条一条的填充的delete scanLineX;return true;9、裁剪多边形的函数,重量级的函数bool CGraphics:CutRect(CRect rect)CPoint rectPoint4;rectPoint0.x = rect.left;rectPoint0.y = rect.top;rectPoint
26、1.x = rect.right;rectPoint1.y = rect.top;rectPoint3.x = rect.left;rectPoint3.y = rect.bottom;rectPoint2.x = rect.right;rectPoint2.y = rect.bottom;/获取裁减矩形的四个点的坐标,第一个点为左上,第二个点为右上,第三个点为右下,第四个点为左下int i;CArray myArray;/裁减后,保存的多边形的依次各点的坐标for(int rectNum=0;rectNum=0) coordinate.y = (int)(y+0.5);return true
27、;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);if(objectP1.y-y)*(y-objectP2.y)=0) coordinate.y = (int)(y+0.5);return true;return false;else/两条线段斜率都存在时
28、的处理办法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)/(
29、k2-k1);x=(float)(int)(x+0.5);y = (float)(int)(y+0.5);if(objectP1.y-y)*(y-objectP2.y)=0) coordinate.y = (int)(y+0.5);return true;return false;return true;11、冒泡排序函数bool CGraphics:SortArray(int* iArray,int iLength)/冒泡排序int i,j,iTemp;bool bFlag;for(i=0;i iArrayj+1)iTemp=iArrayj;iArrayj=iArrayj+1;iArrayj
30、+1=iTemp;bFlag=false;if(bFlag)break;return true;12、对多边形裁减时,判断线段端点是否在可视一侧,判断就是直接判断点坐标的关系bool CGraphics:IsInSquareRgn(CRect rect,CPoint Point,int flag)switch(flag) case 0:if(Point.y rect.top)return true;else return false;break;case 1:if(Point.x rect.left)return true;else return false;break;default:break;return true;四、完成的成果截图:初始化过后:自定义多边形点坐标和自定义裁剪区域:填充:五、体会通过这次课设,我学会了怎么和如何灵活有效的运用图形学的知识来解决问题。同时也感谢老师和朋友的帮忙。计算机与通信学院课程设计评分表课题名称: 多边形裁剪与填充 项 目 评 价设计方案的合理性与创造性设计与调试结果设计说明书的质量答辩陈述与回答问题情况课程设计周表现情况综合成绩教师签名: 日 期: