1、计算机图形学实验报告实验二 直线裁剪一、实验目的与要求:1理解裁剪的实质和裁剪操作的基本任务;2通过实验,进一步理解和掌握 Cohen-Sutherland 裁剪算法;3掌握用 Cohen-Sutherland 裁剪算法裁减直线段的基本过程;4通过编程,在 TC 环境下用 Cohen-Sutherland 算法编程实现矩形窗口对直线段的裁剪。二、实验原理直线和窗口的关系如图 1-23 所示,可以分为如下 3 类:(1)整条直线在窗口内。此时,不需剪裁,显示整条直线。(2)整条直线在窗口外,此时,不需剪裁,不显示整条直线。(3)部分直线在窗口内,部分直线在窗口外。此时,需要求出直线与窗框的交点,
2、并将窗口外的直线部分剪裁掉,显示窗口内的直线部分。直线剪裁算法有两个主要步骤。首先将不需剪裁 的 直 线 挑 出 , 即 删 去 在 窗 外 的 直 线 。 然 后 , 对 其 余 直 线 , 逐 条 与 窗 框 求 交 点 , 并 将 窗口 外 的 部 分 删 去 。以区域编码为基础,将窗口及其周围的 8 个方向以 4 bit 的二进制数进行编码。如图 1-24 所示的编码方法将窗口及其邻域分为 5 个区域。(1)内域:区域(0000) 。(2)上域:区域(1001,1000,1010) 。(3)下域:区域(0101, 0100, 0110)。(4)左域:区域(1001, 0001, 010
3、1)。直线与窗口的关系窗口及其邻域的 5 个区域及与直线的关系三、算法设计与分析区域(1010, 0010, 0110)。当线段的两个端点的编码的逻辑“与”非零时,线段显然为不可见的。对某线段的两各端点的区号进行位与运算,可知这两个端点是否同在视区的上、下、左、右。算法的主要思想是,对每条直线,如 P1P2 利用以下步骤进行判断: 对直线两端点 P1、P 2 编码分别记为 C1(P1)=a1, b1, c1, d1,C 2(P2)=a2, b2, c2, d2其中,a i、b i、c i、 di取值范围为 1, 0,i 1, 2。 如果 ai=bi=ci=di=0,则显示整条直线,取出下一条直
4、线,返回步骤;否则,进入步骤。 如果| a 1a2 |=1,则求直线与窗上边( y=ywmax)的交点,并删去交点以上部分。如果| b1b2 |=1,| c1c2 |1,| d1d2 |=1,进行类似处理。 返回步骤判断下一条直线。设计下图所示的菜单项。在工作区的 ResourceView 标签中,单击 Menu 项左边“+” ,然后双击其子项 IDR_MAINFRAME,并根据下图的定义编辑菜单资源。菜单标题 菜单项标题 标示符 ID裁剪 线段裁剪 ID_CLIPLINE添加消息处理函数。利用 ClassWizard(建立类向导)为应用程序添加与菜单项相关的消息处理函数,ClassName
5、栏中选择 CMyView,下表建立如下的消息映射函数, ClassWizard 会自动完成有关的函数声明。菜单项 ID 消 息 消息处理函数ID_CLIPLINE CONMMAN OnIDTRANSLATION利用 ClassWizard(建立类向导)为应用程序添加鼠标响应函数 OnLButtonDblClk,以实现双击鼠标左键弹出所要进行裁剪的直线,在这里应用了 mylineView.h 中定义的类CPoint 的一个对象数组,来存放所要画直线的一些点。四、关键程序代码 在“图形裁剪 View.h”文档中的适当位置添加定义存储线段端点的数组。#include N 9public:CPoint
6、 ptsetN;在“mylineView.cpp”适当位置添加以下代码。#define LEFT 1#define RIGHT 2#define BOTTOM 4#define TOP 8#define XL 100#define XR 300#define YT 100#define YB 250在OnDraw中添加下列代码:以下的数据为所要生成直线的起点与终点CPen newpen(PS_SOLID,1,RGB(255,0,0);CPen *old=pDC-SelectObject(pDC-Rectangle(CRect(XL,YT,XR,YB);/剪切窗口ptset0=CPoint(12
7、0,150);ptset1=CPoint(170,110);ptset2=CPoint(400,0);ptset3=CPoint(350,150);ptset4=CPoint(0,250);ptset5=CPoint(150,230);ptset6=CPoint(200,50);ptset7=CPoint(130,200);pDC-TextOut(0,0,“双击鼠标左键出现要裁剪的直线“);在添加的鼠标响应函数OnLButtonDblClk里加入下列代码用来在双击鼠标左键时生成要裁剪的直线CDC* pDC=GetDC();CPen newpen(PS_SOLID,1,RGB(255,0,0);
8、CPen *old=pDC-SelectObject(for(int i=0;iMoveTo(ptseti);pDC-LineTo(ptseti+1);i+;pDC-SelectObject(old);在 实 现 裁 剪 的 函 数 OnIDTRANSLATION里添加下列代码,实现对上面的鼠标响应函数画出直线的裁剪CDC* pDC=GetDC();CPen newpen(PS_SOLID,1,RGB(255,0,0);CPen *old=pDC-SelectObject(float x,y;int i;int code1,code2;RedrawWindow();/ 求 两 端 点 所 在
9、区 号 codefor(i=0;iXR)c=c|RIGHT;if(ptseti.yYB) c=c|BOTTOM;else if(ptseti.yXR) c=c|RIGHT;if(ptseti+1.yYB) c=c|BOTTOM;else if(ptseti+1.yMoveTo(ptseti.x,ptseti.y);pDC-LineTo(ptseti+1.x,ptseti+1.y);if(code1=0pDC-LineTo(ptseti+1.x,ptseti+1.y);if(code1=0if(LEFT y=(float)ptseti.y+(ptseti+1.y-ptseti.y)*(XL-pt
10、seti.x)/(ptseti+1.x-ptseti.x);else if(RIGHT y=(float)ptseti.y+(ptseti+1.y-ptseti.y)*(XR-ptseti.x)/(ptseti+1.x-ptseti.x);else if(BOTTOM x=(float)ptseti.x+(ptseti+1.x-ptseti.x)*(YB-ptseti.y)/(ptseti+1.y-ptseti+1.y);else if(TOP x=(float)ptseti.x+(ptseti+1.x-ptseti.x)*(YT-ptseti.y)/(ptseti+1.y-ptseti.y)
11、;ptseti+1.x=(long)x;ptseti+1.y=(long)y;pDC-LineTo(ptseti+1.x,ptseti+1.y);if(code1!=0if(LEFT y=(float)ptseti.y+(ptseti+1.y-ptseti.y)*(XL-ptseti.x)/(ptseti+1.x-ptseti.x);else if(RIGHT y=(float)ptseti.y+(ptseti+1.y-ptseti.y)*(XR-ptseti.x)/(ptseti+1.x-ptseti.x);else if(BOTTOM x=(float)ptseti.x+(ptseti+1
12、.x-ptseti.x)*(YB-ptseti.y)/(ptseti+1.y-ptseti+1.y);else if(TOP x=(float)ptseti.x+(ptseti+1.x-ptseti.x)*(YT-ptseti.y)/(ptseti+1.y-ptseti.y);ptseti.x=(long)x;ptseti.y=(long)y;pDC-LineTo(ptseti.x,ptseti.y);五、程序运行结果分析(操作和功能说明)运行函数,弹出程序窗口,在窗口里会有一个画好的矩形窗口,首先在窗口双击鼠标左键,会发现弹出四条线段,位置各异,有在窗口里的,有部分在窗口里的,还有与窗口不相交的,然后选择菜单里的裁剪命令,选择下属菜单线段裁剪,单击后会发现,程序运行结果,在窗口外的直线都被裁剪掉,只剩窗口里的,原来四条线段变成了三条,在外面没于窗口相交的被裁剪掉。