线段裁剪算法
- 格式:doc
- 大小:75.50 KB
- 文档页数:5
描述cohen sutherland裁剪算法
Cohen-Sutherland裁剪算法是一种用于裁剪线段的算法,由S.G.Cohen和D.P.Sutherland在1969年提出。
它的基本思想是使用一个2D窗口矩形对要裁剪的线段进行测试,根据结果将线段分成四个不同的类别(左端点的左边,右端点的右边,上端点的上边,下端点的下边),这样就可以把线段按照它们在窗口中的相对位置编码。
下面具体讲解Cohen-Sutherland裁剪算法的步骤:
1.首先,确定要裁剪的线段端点的坐标,以及窗口的左上角和右下角的坐标。
2.然后,根据左上角的坐标和右下角的坐标,利用一个4位的二进制整数对线段端点进行编码,每一位的0或1表示端点是否在窗口的4个边界外面。
3.对比端点的编码,如果两个编码都为0,表示线段完全位于窗口内,不需进行裁剪。
如果两个编码不同,则表示至少有一个端点位于窗口边界外,此时需要进行裁剪。
4.根据不同的编码情况,对线段进行裁剪:
(1)如果两个编码都不为0,则表明线段两个端点都在窗口边界外,此时线段不可见,可以将线段丢弃。
(2)如果两个编码中只有一个不为0,则表明线段上有一个端点在窗口边界外,此时只需要将外部端点移动到窗口边界上,即可得到一个可见的线段。
5.此外,还需要对线段两个端点进行重新编码,根据编码重复步
骤3和步骤4,直至线段完全位于窗口内,或者线段完全被丢弃。
至此,Cohen-Sutherland裁剪算法就完成了。
它既可以用于直线的裁剪,也可以用于曲线的裁剪。
liang-barsky算法的基本原理
liangbarsky算法是一种用于裁剪线段的算法,其基本原理是利用参数化表示,将线段与剪裁窗口边界进行比较,确定线段是否需要进行裁剪,并计算出裁剪后的线段端点坐标。
具体来说,liangbarsky算法将线段表示为参数化形式:
x = x1 + t * (x2 - x1)
y = y1 + t * (y2 - y1)
其中,t是参数,表示线段上的点。
根据线段的起点和终点坐标(x1,y1)、(x2,y2),可以计算出线段在参数范围[0,1]内的参数化表示。
然后,将参数化表示代入剪裁窗口边界的方程中,求解参数t的范围,即线段与边界的交点,以确定裁剪后的线段端点坐标。
具体的求解过程如下:
首先,根据线段的方向向量(dx,dy)和窗口边界的方向向量(dx',dy'),计算出4个参数p1、p2、p3、p4:
p1 = -dx
p2 = dx
p3 = -dy
p4 = dy
然后,利用线段的起点坐标(x1,y1)与窗口边界的4个顶点坐标(xi,yi),计算出参数q1、q2、q3、q4:
q1 = x1 - xi
q2 = xi + w - x1
q3 = y1 - yi
q4 = yi + h - y1
其中,w和h分别是窗口的宽度和高度。
最后,通过以下公式计算出参数u1、u2:
u1 = max(0, max(p1 * q1, p3 * q3))
u2 = min(1, min(p2 * q2, p4 * q4))
如果u1>u2,则线段完全在剪裁窗口外部,可以忽略直接将线段裁剪掉;否则,根据参数化表示计算出裁剪后的线段端点坐标。
中间区段法裁剪
中间区段法裁剪(Middle Segment Clipping)是计算机图形学
中一种常用的二维裁剪算法,主要用于裁剪直线和多边形等图形。
中间区段法裁剪的基本思想是:首先确定裁剪窗口的边界,并将其等分为上、下、左、右四个方向的区段。
接着,根据裁剪窗口与图形在平面上的相对位置关系,决定各个区段是否需要进行裁剪。
最终,根据裁剪结果进行图形的显示或丢弃。
具体裁剪过程如下:
1. 确定裁剪窗口的边界:左边界(Xmin)、右边界(Xmax)、上边界(Ymin)和下边界(Ymax)。
2. 以直线为例,对于每一条线段,根据起点(P1)和终点
(P2)的位置关系,判断其是否需要进行裁剪。
3. 首先根据P1和P2的水平位置关系判断是否在裁剪窗口的
左右区段内。
若在同一区段内,则根据垂直位置关系进一步判断是否在裁剪窗口的上下区段内。
若在裁剪窗口内,则直接保留该线段。
若跨越区段边界,则根据裁剪窗口与线段的交点计算新的起点和终点,并进行裁剪。
4. 根据裁剪结果进行线段的显示或丢弃。
中间区段法裁剪的优点是相对简单、高效,适用于直线和多边形等较简单的图形。
缺点是无法处理曲线和复杂图形的裁剪。
在实际应用中,可以与其他裁剪算法结合使用,以实现更复杂的图形裁剪效果。
裁剪算法——cohen-sutherland算法实验环境:VC6.0算法思想: 延长窗⼝的边,将⼆维平⾯分成9个区域,每个区域赋予4位编码C t C b C r C l,裁剪⼀条线段P1P2时,先求出所在的区号code1,code2。
若code1=0,且code2=0,则线段P1P2在窗⼝内,应取之。
若按位与运算code1&code2,则说明两个端点同时在窗⼝的上⽅、下⽅、左⽅或右⽅,则可判断线段完全在窗⼝外,可弃之;否则,按第三种情况处理,求出线段与窗⼝某边的交点,在交点处把线段⼀分为⼆,其中必有⼀段在窗⼝外,可弃之,再对另⼀段重复上述处理。
100110001010000100000010010********* 多边形裁剪编码程序实现:#include "stdafx.h"#include<stdio.h>#include<conio.h>#include<graphics.h>#define LEFT 1#define RIGHT 2#define BOTTOM 4#define TOP 8void midpointLine(int x0,int y0,int x1,int y1,int color)//中点画线算法{int a,b,d1,d2,d,x,y;a=y0-y1;b=x1-x0;d=2*a+b;d1=2*a;d2=2*(a+b);x=x0;y=y0;putpixel(x,y,color);while(x<x1){if(d<0){x++;y++;d+=d2;}else{x++;d+=d1;}putpixel(x,y,color);}}int encode(int x,int y,int XL,int XR,int YB,int YT)//编码{int c=0;if(x<XL) c|=LEFT;if(x>XR) c|=RIGHT;if(y<YB) c|=BOTTOM;if(y>YT) c|=TOP;return c;}void C_SLineClip(int x1,int y1,int x2,int y2,int XL,int XR,int YB,int YT){int code1,code2,code,x,y;code1=encode(x1,y1,XL,XR,YB,YT);code2=encode(x2,y2,XL,XR,YB,YT);while((code1 != 0) || (code2 != 0)){if((code1 & code2) != 0){midpointLine(x1,y1,x2,y2,RGB(0, 255, 0));//如果直线在裁剪窗⼝外就⽤绿⾊画出printf("线段在窗⼝外!");return;}if(code1 != 0) code=code1;else code=code2;if((LEFT & code) != 0){x=XL;y=y1+(y2-y1)*(XL-x1)/(x2-x1);}else if((RIGHT & code) != 0){x=XR;y=y1+(y2-y1)*(XR-x1)/(x2-x1);}else if((BOTTOM & code) != 0){y=YB;x=x1+(x2-x1)*(YB-y1)/(y2-y1);}else if((TOP & code) != 0){y=YT;x=x1+(x2-x1)*(YT-y1)/(y2-y1);}if(code == code1){x1=x; y1=y; code1=encode(x,y,XL,XR,YB,YT);}else{x2=x; y2=y; code2=encode(x,y,XL,XR,YB,YT);}}midpointLine(x1,y1,x2,y2,RGB(255,0,0));//将裁减的直线⽤红⾊标注return;}int main(int argc, char* argv[]){int gdriver=DETECT,gmode;int x1=20,y1=30,x2=250,y2=300,XL=10,XR=200,YT=400,YB=30;initgraph(&gdriver,&gmode,"c:\\tc");//setbkcolor(WHITE);cleardevice();midpointLine(x1,y1,x2,y2,RGB(0,255,0));//将被裁剪直线⽤绿⾊画出rectangle(10,400,200,30);//rectangle(int left,int top,int right,int bottom);//裁剪窗⼝ C_SLineClip(x1,y1,x2,y2,XL,XR,YB,YT);// cohen sutherland算法getch();closegraph();return0;}显⽰效果:将在窗⼝内的线段设为红⾊,窗⼝外的线段设为绿⾊。
Cohen-Sutherland裁剪算法例题Cohen-Sutherland裁剪算法是一种用于线段裁剪的算法,用于确定线段是否完全位于视窗内部,或者是否与视窗有部分或完全重合。
以下是一个例题来说明Cohen-Sutherland算法的使用:假设有一个视窗,左上角坐标为(20, 20),右下角坐标为(60, 60)。
现有一条线段,起点坐标为(10, 40),终点坐标为(70, 30)。
使用Cohen-Sutherland算法对该线段进行裁剪。
步骤1: 定义裁剪区域的编码使用二进制编码来定义裁剪区域,对于视窗的四个边界线段,可以使用以下编码:●左侧编码: 0001●右侧编码: 0010●下方编码: 0100●上方编码: 1000步骤2: 计算线段的编码对于线段的起点和终点坐标,根据其相对于视窗的位置,计算其编码。
假设线段起点的编码为C1,终点的编码为C2。
起点(10, 40)编码计算:●位于视窗左侧,所以C1 = 0001终点(70, 30)编码计算:●位于视窗右侧,所以C2 = 0010步骤3: 判断是否完全落在视窗内部如果起点和终点的编码C1和C2都为0,则表示线段完全位于视窗内部,无需裁剪。
在这个例子中,C1 = 0001,C2 = 0010,都不等于0,因此线段不完全位于视窗内部,需要进行裁剪。
步骤4: 判断是否完全在视窗之外如果起点和终点的编码C1和C2的逻辑与操作(AND)结果为非零,表示线段完全在视窗之外,可以完全丢弃不进行裁剪。
在这个例子中,C1 = 0001,C2 = 0010,它们的逻辑与操作结果为0,因此线段不完全在视窗之外,需要进行裁剪。
步骤5: 通过裁剪区域裁剪线段通过逐步调整线段的起点和终点坐标,根据它们的编码,使得线段落在视窗内部或与视窗边界相交。
在这个例子中,我们将线段向视窗内进行裁剪:●根据起点编码C1 = 0001,在视窗左边界裁剪:将起点的x坐标调整为视窗左边界的x坐标,即20,计算新的起点编码C1 =0000。
实验报告Experimentation Report of Taiyuan teachers College系部计算机系年级三年级课程图形学姓名同组者日期项目直线段的裁剪算法一、实验目的:1.熟悉图形裁剪的基本知识2.掌握Cohen-Sutherland 直线裁剪算法二、实验内容:在矩形窗口的裁剪算法中,考虑到构成图形的基本元素就是线段,曲线可看成是有很多小线段逼近而成的,因此,讨论线段的裁剪算法更为实用,即Cohen-Sutherland裁剪算法。
Cohen-Sutherland裁剪算法具体思路如下。
任意平面线段和矩形窗口的位置关系只会有如下3种:(1)完全落在窗口内。
(2)完全落在窗口外。
(3)部分落在窗口内,部分落在窗口外。
要想判断线段和窗口的位置关系,只要找到线段的两端点相对于矩形窗口的位置即可,线段的两端点相对于矩形窗口的位置可能会有如下几种情况:(1)线段的两个端点均在窗口内,这时线段全部落在窗口内,完全可见,应予以保留。
(2)线段的两个端点均在窗口边界线外同侧,这时线段全部落在窗口外,完全不可见,应予以舍弃。
(3)线段的一个端点在窗口内,另一个端点在窗口外,这时线段部分可见,应求出线段与窗口边界线的交点,从而得到线段在窗口内的可见部分。
(4)线段的两个端点均不在窗口内,但不处于窗口边界线外同侧,这时有可能线段是部分可见的,也可能是完全不可见的。
Cohen-Sutherland裁剪算法就是按照上述思路来对线段进行裁剪的,只是在线段的两端点相对于矩形窗口的位置上,巧妙地运用了编码的思想。
首先,延长窗口的四条边界线,将平面划分成9个区域,然后,用四位二进制数C3C2C1C0对这9个区域进行编码,编码规则如下:第0位C0:当线段的端点在窗口的左边界之左时,该位编码为1,否则,该位编码为0。
第1位C1:当线段的端点在窗口的右边界之右时,该位编码为1,否则,该位编码为0。
第2位C2:当线段的端点在窗口的下边界之下时,该位编码为1,否则,该位编码为0。
一、实验目的:直线段的裁剪:编码裁剪算法,中点分割裁剪算法。
二、实验内容://BasicGraph.cpp//请将下列裁剪程序补充完整,并用注释说明是何种裁剪算法void Encode (int x,int y,int *code,int XL,int XR,int YB,int YT) {//请将此程序补充完整int c=0;if(x<XL) c=c|LEFT;else if(x>XR) c=c|RIGHT;if(y<YB) c=c|BOTTOM;else if(y>YT) c=c|TOP;(*code)=c;}//编码裁剪算法:void C_S_Line(POINT &p1,POINT &p2,int XL,int XR,int YB,int YT) {//请将此程序补充完整int x1,x2,y1,y2,x,y,code1,code2,code;x1=p1.x; x2=p2.x; y1=p1.y; y2=p2.y;Encode(x1,y1,&code1,XL,XR,YB,YT);Encode(x2,y2,&code2,XL,XR,YB,YT);while(code1!=0||code2!=0){if((code1&code2)!=0) return;code=code1;if(code1==0) code=code2;if((LEFT&code)!=0){x=XL;y=y1+(y2-y1)*(XL-x1)/(x2-x1);}else if((RIGHT&code)!=0){x=XR;y=y1+(y2-y1)*(XR-x1)/(x2-x1);}if((BOTTOM&code)!=0){y=YB;x=x1+(x2-x1)*(YB-y1)/(y2-y1);}else if((TOP&code)!=0){y=YT;x=x1+(x2-x1)*(YT-y1)/(y2-y1);}if(code==code1){x1=x;y1=y;Encode(x,y,&code1,XL,XR,YB,YT);}else{x2=x;y2=y;Encode(x,y,&code2,XL,XR,YB,YT);}}p1.x=x1;p1.y=y1;p2.x=x2;p2.y=y2;}int IsInArea(POINT point,int XL,int XR,int YB,int YT){//请将此程序补充完整if(point.x>=XL && point.x<=XR && point.y>YB && point.y<YT) return 1;else return 0;}int NotIntersect(POINT begin,POINT end,int XL,int XR,int YB,int YT) {//请将此程序补充完整int maxx,maxy,minx,miny;maxx=(begin.x>end.x)?begin.x:end.x;minx=(begin.x<end.x)?begin.x:end.x;maxy=(begin.y>end.y)?begin.y:end.y;miny=(begin.y<end.y)?begin.y:end.y;if(maxx<XL|| minx>XR||maxy<YB||miny>YT) return 1;else return 0;}//中点裁剪算法:POINT ClipMid(POINT begin,POINT end,int XL,int XR,int YB,int YT){//请将此程序补充完整POINT mid,temp;if(IsInArea(begin,XL,XR,YB,YT)) temp=begin;else if(NotIntersect(begin,end,XL,XR,YB,YT)) temp=begin;else{mid.x=(begin.x+end.x)/2;mid.y=(begin.y+end.y)/2;if(abs(mid.x-end.x)<=1&& abs(mid.y-end.y)<=1) temp=mid;else{if(NotIntersect(begin,mid,XL,XR,YB,YT))temp=ClipMid(mid,end,XL,XR,YB,YT);elsetemp=ClipMid(begin,mid,XL,XR,YB,YT);}}return temp;}//Liang-Barsky直线裁剪算法:void ClipParameter(POINT &p1,POINT &p2,int XL,int XR,int YB,int YT) {float u1=0.0,u2=1.0;float dx=p2.x-p1.x,dy=p2.y-p1.y;if(clipTest(-dx,p1.x-XL,&u1,&u2))if(clipTest(dx,XR-p1.x,&u1,&u2))if(clipTest(-dy,p1.y-YB,&u1,&u2))if(clipTest(dy,YT-p1.y,&u1,&u2)){if(u2<1.0){p2.x=p1.x+u2*dx;p2.y=p1.y+u2*dy;}if(u1>0.0){p1.x=p1.x+u1*dx;p1.y=p1.y+u1*dy;}}}int clipTest(float p,float q,float *u1,float *u2){float r;int remainFlag=1;if(p<0.0){r=q/p;if(r>*u2) remainFlag=0;else if(r>*u1) *u1=r;}else if(p>0.0){r=q/p;if(r<*u1) remainFlag=0;else if(r<*u2) *u2=r;}else //*p=0if(q<0.0) remainFlag=0;return remainFlag;}//逐边裁剪算法://typedef struct tRes { int yes,isIn; POINT pout;} Res;Res TestIntersect(int edge,int type,POINT p1,POINT p2){//判断p2是否在所裁剪的窗边edge的内侧,是否与p1点分别在窗边edge的异侧float dx,dy,m;Res res;int isIn=0,yes=0;POINT pout;dy=p2.y-p1.y;dx=p2.x-p1.x;m=dy/dx;switch(type){case 1: /*right*/if(p2.x<=edge){isIn=1;if(p1.x>edge)yes=1;}else if(p1.x<=edge)yes=1;break;case 2: /*bottom*/if(p2.y>=edge){isIn=1;if(p1.y<edge)yes=1;}else if(p1.y>=edge)yes=1;break;case 3: /*left*/if(p2.x>=edge){isIn=1;if(p1.x<edge)yes=1;}else if(p1.x>=edge)yes=1;break;case 4: /*top*/if(p2.y<=edge){isIn=1;if(p1.y>edge)yes=1;}else if(p1.y<=edge)yes=1;default: break;}if(yes){if((type==1) || (type==3)){ pout.x=edge;pout.y=p1.y+m*(pout.x-p1.x);}if((type==2) || (type==4)){ pout.y=edge;pout.x=p1.x+(pout.y-p1.y)/m;}}res.isIn=isIn;res.yes=yes;res.pout=pout;return res;}int clipSingleEdge(int edge,int type,int nin,POINT pin[50],POINT pout[50])/*对多边形pin与窗边edge进行裁剪,返回裁剪后的多边形pout及点数*/ {int i,k=0;POINT p;Res res;p.x=pin[nin-1].x;p.y=pin[nin-1].y;for(i=0;i<nin;i++){res=TestIntersect(edge,type,p,pin[i]);if(res.yes){ pout[k].x=res.pout.x;pout[k].y=res.pout.y;k++;} if(res.isIn){ pout[k].x=pin[i].x;pout[k].y=pin[i].y;k++;}p.x=pin[i].x;p.y=pin[i].y;}return k;}void ClipEdgePolygon(POINT ps[50],int &n,int XL,int XR,int YB,int YT) { /*对多边形ps进行逐边裁剪*/int n1=0,n2=0;POINT pt[50];n1=clipSingleEdge(XR,1,n,ps,pt);n2=clipSingleEdge(YB,2,n1,pt,ps);n1=clipSingleEdge(XL,3,n2,ps,pt);n2=clipSingleEdge(YT,4,n1,pt,ps);n=n2;}//多边形编码裁剪算法:void ClipEncodePolygon(POINT ps[50],int &n,int XL,int XR,int YB,int YT) {POINT tp[50];int k=0,m;int code1,code2,code;int x,y;for(int i=0;i<n-1;i++){Encode(ps[i].x,ps[i].y,&code1,XL,XR,YB,YT);Encode(ps[i+1].x,ps[i+1].y,&code2,XL,XR,YB,YT);code=code1;m=i;for(int j=0;j<2;j++){if((code1 & code2)!=0) //线段两端都在窗口外的同一侧{switch(code){case 1:x=XL;y=ps[m].y;break;case 2:x=XR;y=ps[m].y;break;case 4:x=ps[m].x;y=YB;break;case 5:x=XL;y=YB;break;case 6:x=XR;y=YB;break;case 8:x=ps[m].x;y=YT;break;case 9:x=XL;y=YT;break;case 10:x=XR;y=YT;break;}tp[k].x=x;tp[k].y=y;k++;}else if((code1 & code2)==0) //线段两端不在窗口的同一侧{if(code==0){tp[k]=ps[m];k++;}else if ((LEFT & code) !=0) //线段与左边界相交 {x=XL;y=ps[i].y+(ps[i+1].y-ps[i].y)*(XL-ps[i].x)/(ps[i+1].x-ps[i].x);if(y>YB && y<YT){tp[k].x=x;tp[k].y=y;k++;}}else if((TOP & code)!=0) //线段与上边界相交{y=YT;x=ps[i].x+(ps[i+1].x-ps[i].x)*(YT-ps[i].y)/(ps[i+1].y-ps[i].y);if(x>XL && x<XR){tp[k].x=x;tp[k].y=y;k++;}}else if((RIGHT & code)!=0) //线段与右边界相交 {x=XR;y=ps[i].y+(ps[i+1].y-ps[i].y)*(XR-ps[i].x)/(ps[i+1].x-ps[i].x);if(y>YB && y<YT){tp[k].x=x;tp[k].y=y;k++;}}else if((BOTTOM & code) != 0) //线段与下边界相交 {y=YB;x=ps[i].x+(ps[i+1].x-ps[i].x)*(YB-ps[i].y)/(ps[i+1].y-ps[i].y);if(x>XL && x<XR){tp[k].x=x;tp[k].y=y;k++;}}}code=code2;m++;}//for(j)}//for(i)for(i=0;i<k;i++)ps[i]=tp[i];n=k;}//函数的调用,裁剪窗口的调整//DrawView.cpp文件//裁剪窗口的调整CDrawView::CDrawView(){/************请在此函数中将裁剪窗口大小调整为长度100单位像素,宽度50单位像素的矩形********/// TODO: add construction code here//m_pWidth=1;m_pStyle=PEN_STYLE_SOLID;m_pColor=RGB(0,0,0);m_FFlag=0;m_FColor=RGB(0,0,0);m_HFlag=0;CurrentDraw=DRAW_VCLINE;m_Num=0;m_Drag=0;m_HCursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS);//DrawType=0;ClipFlag=0;ClipType=-1;XL=200;XR=300;YB=150;YT=200;//XL=200;XR=500;YB=150;YT=400;ClipWindowColor=RGB(192,192,50);}void CDrawView::OnDraw(CDC* pDC){CDrawDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereif(ClipFlag){CPen NewPen,*pOldPen;NewPen.CreatePen(PS_DASH,1,ClipWindowColor);pOldPen=pDC->SelectObject(&NewPen);pDC->MoveTo(XL,YB);pDC->LineTo(XR,YB);pDC->LineTo(XR,YT);pDC->LineTo(XL,YT);pDC->LineTo(XL,YB);}int index;index=pDoc->GetShapeNumber();for(int i=0;i<index;i++)pDoc->GetShape(i)->Drawing(pDC);}void CDrawView::OnInitialUpdate(){CSize sizeTotal;sizeTotal.cx = 640; sizeTotal.cy = 480;SetScrollSizes(MM_TEXT, sizeTotal);// TODO: Add your specialized code here and/or call the base class }void CDrawView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultCClientDC dc(this);OnPrepareDC(&dc);dc.DPtoLP(&point);m_pPrev=point;m_pOrigin=point; //点击鼠标左键作为拖动绘图的第一点m_Drag=1;SetCapture();RECT rect;GetClientRect(&rect);ClientToScreen(&rect);ClipCursor(&rect);CScrollView::OnLButtonDown(nFlags, point);}//函数调用处void CDrawView::OnLButtonUp(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultif(m_Drag){m_Drag=0;ReleaseCapture();ClipCursor(NULL);CDrawDoc *pDoc=GetDocument();CShape *pShape;POINT p1,p2;if(CurrentDraw==DRAW_VCLINE || CurrentDraw==DRAW_DDALINE ||CurrentDraw==DRAW_MIDLINE || CurrentDraw==DRAW_BSHLINE){if(ClipFlag){switch(ClipType){/****************编码裁剪函数调用处*************/case CLIP_ENCODE:C_S_Line(m_pOrigin,m_pPrev,XL,XR,YB,YT); break; /****************中点分割裁剪函数调用处************/case CLIP_MIDPOINT: ClipMid(m_pPrev,m_pOrigin,XL,XR,YB,YT);p1=ClipMid(m_pPrev,m_pOrigin,XL,XR,YB,YT);p2=ClipMid(m_pOrigin,m_pPrev,XL,XR,YB,YT);m_pOrigin=p1;m_pPrev=p2;break;case CLIP_PARAMETER:ClipParameter(m_pOrigin,m_pPrev,XL,XR,YB,YT);break;}}pShape=newCLine(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,DrawType);pDoc->AddShape(pShape);}if(CurrentDraw==DRAW_RECTANGLE){if(ClipType==CLIP_WINDOW){XL=m_pOrigin.x;XR=m_pPrev.x;YB=m_pOrigin.y;YT=m_pPrev.y;}else{pShape=newCRectangle(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,m_FFlag,m_FColor,m_HFlag,m_Hatch);pDoc->AddShape(pShape);}}if( CurrentDraw==DRAW_VCCIRCLE || CurrentDraw==DRAW_MIDCIRCLE || CurrentDraw==DRAW_BSHCIRCLE){pShape=newCCircle(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,m_FFlag,m_FColor,m_HFlag,m_Hatch,DrawType);pDoc->AddShape(pShape);}if(CurrentDraw==DRAW_VCELLIPSE || CurrentDraw==DRAW_MIDELLIPSE) {pShape=newCEllipse(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,m_FFlag,m_FColor,m_HFlag,m_Hatch,DrawType);pDoc->AddShape(pShape);}pDoc->UpdateAllViews(NULL);}CScrollView::OnLButtonUp(nFlags, point);}三实验结果:四、实验总结通过这次试验使我了解到如何运用计算机程序对窗口进行剪裁,了解到编码剪裁算法直观方便,速度较快,中点分割剪裁算法不用进行乘除运算,剪裁效率高,Liang-Barsky直线裁剪算法更快。
计算机图形学
实验报告
实验(四)
实验题目:线段裁剪算法
指导老师:吴颖斌
专业:数字媒体技术
班级: 1306班
姓名: xx(20131006xx)
2014年 11月19日
一、实验类型
验证性。
二、实验目的和要求
目的:编写线段裁剪算法程序,验证算法的正确性。
要求:编写Cohen-Sutherland直线剪裁算法程序,编译、调试,查看运行结果。
三、实验中用到的硬件设备及软件环境
Microsoft Visual C++ 6.0和PC机
四、实验主要程序代码
Cohen-Sutherland直线剪裁算法
(1)主要步骤和代码:
步骤1:创建Code_Clip工程文件;
步骤2:在主程序的程序头部定义符号常量(鼠标双击“CCode_ClipView”,添
加至
“class CCode_ClipView : public …………”之前)
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
步骤3:定义成员变量和成员函数(鼠标双击“CCode_ClipView”,添加至“class CCode_ClipView : public …………”之内))
int WT;
int WB;
int WR;
int WL;
步骤4:在构造函数中为窗口边界变量赋初值
CCode_ClipView::CCode_ClipView()
{
// TODO: add construction code here
WL=100;WR=400;WB=100;WT=300;
}
步骤5:编写成员函数程序(在“CCode_ClipView”单击鼠标右键-->Add member function……)
void CCode_ClipView::encode(int x, int y, int *code)
{
int c=0;
if (x<WL) c=c|LEFT;
else if (x>WR) c=c|RIGHT;
if (y<WB) c=c|BOTTOM;
else if (y>WT) c=c|TOP;
*code=c;
}
int CCode_ClipView::C_S_Line(CDC* pDC,int x1, int y1, int x2, int y2) {
// CDC *pDC=GetDC();
int code1,code2,code,x,y;
encode(x1,y1,&code1); //(x1,y1)处的编码
encode(x2,y2,&code2); //(x2,y2)处的编码
while (code1!=0||code2!=0) //当code1不等于0或code2不等于0
{
if ((code1&code2)!=0) return 0; //当code1与 code2不等于0,在同侧;
code=code1;
if (code1==0) code=code2;
if ((LEFT&code)!=0) //求交点
{
x=WL;
y=y1+(y2-y1)*(WL-x1)/(x2-x1);
}
else if ((RIGHT&code)!=0)
{
x=WR;
y=y1+(y2-y1)*(WR-x1)/(x2-x1);
}
else if ((BOTTOM&code)!=0)
{
y=WB;
x=x1+(x2-x1)*(WB-y1)/(y2-y1);
}
else if ((TOP&code)!=0)
{
y=WT;
x=x1+(x2-x1)*(WT-y1)/(y2-y1);
}
if (code==code1)
{
x1=x;y1=y;
encode(x,y,&code1);
}
else
{
x2=x;y2=y;
encode(x,y,&code2);
}
}
//end while,表示code1,code2都为0,其中的线段为可视部分 pDC->MoveTo(x1,y1);
pDC->LineTo(x2,y2);
}
步骤6:编写OnDraw()程序
void CCode_ClipView::OnDraw(CDC* pDC)
{
CCode_ClipDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//定义三条直线的坐标
int x11,y11,x21,y21,x12,y12,x22,y22,x13,y13,x23,y23; x11=50;y11=150;x21=450;y21=250;
x12=150;y12=150;x22=350;y22=240;
x13=50;y13=400;x23=500;y23=350;
//定义画笔
CPen PenRed(PS_SOLID,1,RGB(255,0,0));//定义红色笔
CPen PenBlue(PS_SOLID,1,RGB(0,0,255));//定义蓝色笔
//先画出窗口,用蓝色
pDC->SelectObject(&PenBlue);
pDC->Rectangle(WL,WB,WR,WT);
//先画出三条直线,用红线
pDC->TextOut(x11,y11,"line1:");
pDC->MoveTo(x11,y11);pDC->LineTo(x21,y21);
pDC->TextOut(x12,y12,"line2:");
pDC->MoveTo(x12,y12);pDC->LineTo(x22,y22);
pDC->TextOut(x13,y13,"line3:");
pDC->MoveTo(x13,y13);pDC->LineTo(x23,y23);
//用蓝线,画出裁剪三条线
pDC->SelectObject(&PenBlue);
C_S_Line(pDC,x11,y11,x21,y21);
C_S_Line(pDC,x12,y12,x22,y22);
C_S_Line(pDC,x13,y13,x23,y23);
}
步骤7:编译、调试,查看运行结果。
(2)运行结果如图1所示。
五、程序运行结果或数据记录
图1 Cohen-Sutherland直线剪裁算法
六、实验总结与体会
通过本次实验,让我了解到了Cohen-Sutherland直线剪裁算法剪裁直线实现的具体过程,并且对剪裁直线的过程和特点也有个更进一步的学习和掌握。
由于用的是MFC实现的,所以通过此次实验,对MFC的使用也得到了强化。