第3章 5 裁剪算法
2016新编Weiler-Atherton任意多边形裁剪算法
Weiler-Atherton任意多边形裁剪Sutherland-Hodgeman算法解决了裁剪窗口为凸多边形窗口的问题,但一些应用需要涉及任意多边形窗口(含凹多边形窗口)的裁剪。
Weiler-Atherton多边形裁剪算法正是满足这种要求的算法。
一、Weiler-Atherton任意多边形裁剪算法描述:在算法中,裁剪窗口、被裁剪多边形可以是任意多边形:凸的、凹的(内角大于180o)、甚至是带有内环的(子区),见下图。
裁剪窗口和被裁剪多边形处于完全对等的地位,这里我们称:1、被裁剪多边形为主多边形,记为A;2、裁剪窗口为裁剪多边形,记为B。
主多边形A和裁剪多边形B的边界将整个二维平面分成了四个区域:1、A∩B(交:属于A且属于B);2、A-B(差:属于A不属于B);3、B-A(差:属于B不属于A);4、A∪B(并:属于A或属于B,取反;即:不属于A且不属于B)。
内裁剪即通常意义上的裁剪,取图元位于窗口之内的部分,结果为A∩B。
外裁剪取图元位于窗口之外的部分,结果为A-B。
观察右图不难发现裁剪结果区域的边界由被裁剪多边形的部分边界和裁剪窗口的部分边界两部分构成,并且在交点处边界发生交替,即由被裁剪多边形的边界转至裁剪窗口的边界,或者反之。
由于多边形构成一个封闭的区域,所以,如果被裁剪多边形和裁剪窗口有交点,则交点成对出现。
这些交点分成两类:一类称“入”点,即被裁剪多边形由此点进入裁剪窗口,如图中a、c、e;一类称“出”点,即被裁剪多边形由此点离开裁剪窗口,如图中b、d、f。
二、Weiler-Atherton任意多边形裁剪算法思想:假设被裁剪多边形和裁剪窗口的顶点序列都按顺时针方向排列。
当两个多边形相交时,交点必然成对出现,其中一个是从被裁剪多边形进入裁剪窗口的交点,称为“入点”,另一个是从被裁剪多边形离开裁剪窗口的交点,称为“出点”。
算法从被裁剪多边形的一个入点开始,碰到入点,沿着被裁剪多边形按顺时针方向搜集顶点序列;而当遇到出点时,则沿着裁剪窗口按顺时针方向搜集顶点序列。
简单多边形裁剪算法
摘 要 :为 了尽量 降低任意 多边形裁剪复杂度,提 出了一种基 于多边形顶点遍历 的简单 多边形裁 剪算 法。该 算法将 多边形
交 点插 入 到裁 剪 多边 形 和 被 裁 减 多边 形 顶 点 矢 量数 组 中 ,通 过 记 录 交 点及 其 前 驱 、 后 继 信 息 ,可 快 速 生 成 结 果 多边 形 。其
2 .C h i n a C e n t r e f o r R e s o u r c e s S a t e l l i t e Da t a a n d Ap p l i c a t i o n , B e i j i n g 1 0 0 0 9 4 , C h i n a ;3 .C h i n a C o a l Te c h n o l o g i e s G r o u p or C p o r a t i o n ,B e i j i n g 1 0 0 0 1 3 , C h i n a ; 4 .B e i j i n g I n s t i t u t e o f A p p l i e d Me t e o r o l o g y , B e i j i n g 1 0 0 0 2 9 , C h i n a )
中,时间复杂度 为 ( ) ( ( m+k ) ×k ) ,m 是两 多边形 中顶点数较 大者 ,k是 两 多边形的 交点数 。该算 法简化 了交点的数据 结 构 ,节省 了存储 空间,降低 了算法的时间复杂度 ,具有 简单 、易于编程 实现 、运行效 率高的特点 。
关 键 词 : 多边 形 裁 剪 ; 交点 ;前 驱 ;后 继 ;矢 量数 组 中图 法 分 类 号 :TP 3 9 1 文 献 标 识 号 :A 文章 编 号 :1 0 0 0 — 7 0 2 4( 2 0 1 4 )0 1 - 0 1 9 2 - 0 6
计算机图形学(简单多边形裁剪算法)
简单多边形裁剪算法摘要:多边形裁剪算法与线性裁剪算法具有更广泛的实用意义,因此它是目前裁剪研究的主要课题。
本文主要介绍了一种基于多边形顶点遍历的简单多边形裁剪算法,它有效降低了任意多边形裁剪复杂度。
通过记录交点及其前驱、后继信息,生成结果多边形,该算法简化了交点的数据结构,节省了存储空间,降低了算法的时间复杂度,具有简单、易于编程实现、运行效率高的特点。
关键词:多边形裁剪;交点;前驱;后继;矢量数组一、技术主题的基本原理简单多边形裁剪算法综合考虑现有多边形裁剪算法的优缺点,它是一种基于多边形顶点遍历来实现简单多边形裁剪工作的。
其主要的原理是遍历多边形并把多边形分解为边界的线段逐段进行裁剪,输出结果多边形。
二、发展研究现状近年来,随着遥感绘图、CAD辅助设计、图象识别处理技术的发展,图形裁剪算法从最初在二维平面上线和图形的裁剪扩展到三维空间里体和场的裁剪,国内外相继提出不少行之有效的算法,但越来越复杂的图形和计算也对算法的速度和适用性提出了越来越高的要求。
因此,不断简化算法的实现过程,完善细节处理,满足大量任意多边形的裁剪也就成了当今算法研究的焦点之一。
以往多边形裁剪算法不是要求剪裁多边形是矩形,就是必须判断多边形顶点的顺时针和逆时针性,即存在不实用或者是增加了多边形裁剪算法的难度。
为了解决现在的问题,我们研究现在的新多边形算法,其中,裁剪多边形和被裁剪多边形都可以是一般多边形,且不需要规定多边形输入方向。
它采用矢量数组结构,只需遍历剪裁多边形和被裁剪多边形顶点即完成多边形的裁剪,具有算法简单、运行效率高的特点。
三、新算法设计1、算法的思想本算法是为了尽量降低任意多边形裁剪算法复杂度而提出的,其主要思想是采用矢量数组结构来遍历裁剪多边形和被裁多边形顶点,记录裁剪多边形和被裁减多边形交点及其前驱、后继信息,并通过记录相邻交点的线段,然后通过射线法选择满足条件的线段,之后进行线段连接,输出对应的裁剪结果。
裁剪算法——cohen-sutherland算法
裁剪算法——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;}显⽰效果:将在窗⼝内的线段设为红⾊,窗⼝外的线段设为绿⾊。
计算机图形学 第三章 二维图形的裁剪概述
3.2.3 梁友栋-Barsky裁剪算法
式中,Δx=x2-x1,Δy=y2-y1,参数u在0~1 之间取值,P(x,y)代表了该线段上的一个 点,其值由参数u确定,由公式可知,当u=0 时,该点为P1(x1,y1),当u=1时,该点 为P2(x2,y2)。如果点P(x,y)位于由 坐标(xwmin,ywmin)和(xwmax,ywmax)所 确定的窗口内,那么下式成立: xwmin≤x1+ u· Δx≤xwmax ywmin≤y1+ u· Δy≤ywmax(3-10)
3.2.1 Cohen-Sutherland算法
► Code(int ►{
x,int y,int *c)
*c=0; if(y>ymax) /*(xmin,ymin)和(xmax,ymax) 为窗口左下角、右上角坐标。*/ *c=*c|0x08; else if(y<ymin) *c=*c|0x04; if(x>xmax) *c=*c|0x02; else if(x<xmin) *c=*c|0x01; }
► 根据直线两点式方程:
►
2)
(3-
3.2 线段的裁剪
► 整理后得通用交点公式: ►
(3-3)
► ►
1、与上边界的求交公式: (3-4)
3.2 线段的裁剪
► ►
2、与下边界的求交公式:
(3-5)
►
► ►
3、与右边界的求交公式:
(3-6) 4、与左边界的求交公式:
►
(3-7)
3.2.1 Cohen-Sutherla2、判别 根据C1和C2的具体值,可以有三种情况: (1)C1=C2=0,表明两端点全在窗口内,因而 整个线段也在窗内,应予保留。 (2)C1&C2≠0(两端点代码按位作逻辑乘不为 0),即C1和C2至少有某一位同时为1,表明两端点 必定处于某一边界的同一外侧,因而整个线段全在 窗外,应予舍弃。 (3)不属于上面两种情况,均需要求交点。
计算机图形学的裁剪算法
计算机图形学的裁剪算法
计算机图形学的裁剪算法是图形学的一种重要算法,它的基本思想是将一个完整的几何图形(如线段、多边形、圆圈等)按照指定的裁剪窗口(矩形)进行裁剪,只保留在窗口内的部分,而把窗口外的部分抛弃掉。
由于裁剪算法的应用非常广泛,像图形显示系统、图形设备接口(GDI)和图形处理器(GPU)等都广泛使用裁剪算法。
计算机图形学的裁剪算法可以分为两种:2D裁剪算法和
3D裁剪算法。
2D裁剪算法是基于二维空间的,它将一个几何
图形投影到一个平面上,然后按照指定的窗口裁剪;而3D裁
剪算法是基于三维空间的,它将一个几何图形投影到一个三维空间,然后按照指定的窗口裁剪。
2D裁剪算法的基本步骤如下:首先,将要裁剪的几何图
形投影到平面上;其次,计算出投影后的几何图形以及裁剪窗口之间的交点;最后,将裁剪窗口内的部分保留,而把窗口外的部分抛弃掉。
3D裁剪算法的基本步骤如下:首先,将要裁剪的几何图
形投影到三维空间;其次,计算出投影后的几何图形以及裁剪窗口之间的交点;最后,将裁剪窗口内的部分保留,而把窗口外的部分抛弃掉。
计算机图形学的裁剪算法在图形处理中有着重要的作用,它不仅能够有效减少图形处理时间,而且还可以节约存储空间。
此外,它还可以有效提高图形处理效率,提高图形显示效果。
但是,它也存在着一定的局限性,比如,当几何图形的运动变得复杂时,它就会变得费时费力,这就对性能产生了一定的影响。
总之,计算机图形学的裁剪算法是图形学的重要算法,它的应用非常广泛,在图形处理中有着重要的作用。
虽然它也存在着一定的局限性,但是它仍然是一种有效的图形处理算法。
第3章 5 裁剪算法
80年代初提出了著名的Liang-Barsky裁剪算法,通过 线段的参数化表示,实现快速裁剪,至今仍是计算机 图形学中最经典的算法之一; 80年代末到90年代,梁友栋先生致力于几何连续性的 研究,提出了一系列几何连续性方面的理论和方法,成 为国际上几何连续性研究的重要力量; 1991年梁友栋先生为首完成的成果“计算机图形生 成与几何造型研究”获国家自然科学三等奖;
1
2 3 4
Sutherlan-Cohen算法 中点分割算法
梁友栋-Barsky算法 Sutherlan-Hodgman逐边裁剪算法
裁剪的意义 为了描述图形对象,我们必须存储它的全部信息,但有时 为了达到分区描述或重点描述某一部分的目的,往往将 要描述的部分置于一个窗口内,而将窗口外的部分“剪 掉”,这个处理过程叫做裁剪,裁剪在计算机图形处理中 具有十分重要的意义。 裁剪就是将指定窗口作为图形边界,将窗口内的图形保 留,而窗口外的图形则被舍弃。 裁剪处理过程 1、图元在窗口内外的判别; 2、图形元素与窗口的求交。
直线裁剪方法
◦ Cohen-Sutherland裁剪算法
◦ 中点分割算法 ◦ 梁友栋-barskey算法
多边形裁剪方法
◦ Sutherland-Hodgman逐次多边形裁剪算法 ◦ Weiler-Atherton多边形裁剪算法
对于线段的裁剪基本思想是:
线段是否全不在窗口里,若是,转5 ② 线段是否全在窗口,若是,转4 ③ 计算该线段与窗口边界的交点,以此将线段分为两部分, 丢弃不可见的部分,剩余线段转2 ④ 保留并显示该线段 ⑤ 算法结束 可以看到算法的核心有两个:
区域编码
◦ 由窗口四条边所在直线把二维平面分成9个区域,每个区域 赋予一个四位编码,CtCbCrCl,上下右左
计算机图形学实验报告实验2裁剪算法实验
一、实验目的:直线段的裁剪:编码裁剪算法,中点分割裁剪算法。
二、实验内容://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直线裁剪算法更快。
裁剪算法设计实验报告(3篇)
第1篇一、实验目的本次实验旨在深入理解并掌握裁剪算法的基本原理,通过编程实现Cohen-Sutherland算法和Liang-Barsky算法,对图形进行窗口裁剪,从而提高图形处理效率,优化显示效果。
二、实验环境1. 开发环境:Visual Studio 20192. 编程语言:C++3. 图形库:OpenGL三、实验内容1. 理解裁剪算法的基本原理;2. 实现Cohen-Sutherland算法;3. 实现Liang-Barsky算法;4. 对图形进行窗口裁剪,并展示裁剪效果。
四、实验过程1. 理解裁剪算法的基本原理裁剪算法是计算机图形学中的一个重要技术,用于将一个图形或图像中不需要的部分去除,只保留需要的部分。
常见的裁剪算法有Cohen-Sutherland算法、Liang-Barsky算法等。
Cohen-Sutherland算法是一种编码线段裁剪算法,通过将线段端点相对于窗口的位置进行编码,判断线段是否与窗口相交,从而实现裁剪。
Liang-Barsky算法是一种参数化线段裁剪算法,通过计算线段参数,判断线段是否与窗口相交,从而实现裁剪。
2. 实现Cohen-Sutherland算法(1)定义窗口边界首先,定义窗口边界,包括左边界、右边界、上边界和下边界。
(2)编码线段端点将线段端点相对于窗口的位置进行编码,编码规则如下:- 如果端点在窗口内,则编码为0;- 如果端点在窗口左侧,则编码为1;- 如果端点在窗口右侧,则编码为2;- 如果端点在窗口上方,则编码为4;- 如果端点在窗口下方,则编码为8。
(3)判断线段是否与窗口相交将线段两端点的编码进行异或运算,如果结果为0,则线段与窗口相交;否则,线段与窗口不相交。
(4)裁剪线段如果线段与窗口相交,则根据端点编码,将线段分为两部分,分别进行裁剪。
3. 实现Liang-Barsky算法(1)定义窗口边界首先,定义窗口边界,包括左边界、右边界、上边界和下边界。
计算机图形学-第三章-变换及裁剪
(x,y)点对应的齐次坐标为三维空间的一条 直线
xh hx
yh
hy
zh h
7
齐次坐标的作用
1. 将各种变换用阶数统一的矩阵来表示。提供了用矩阵 运算把二维、三维甚至高维空间上的一个点从一个坐 标系变换到另一坐标系的有效方法。
2. 便于表示无穷远点。
例如:(x h, y h, h),令h等于0
25
3 规格化设备坐标系 用于用户的图形是定义在用户坐标系里,
而图形的输出定义在设备坐标系里,它依赖于 基体的图形设备。由于不同的图形设备有不同 的设备坐标系,且不同设备间坐标范围也不尽 相同, 例如:分辨率为1024*768的显示器其屏幕坐标的 范围:x方向为0~1023,y方向为0~767,分辨 率为640*480的显示器,其屏幕坐标范围为:x 方向0~639,y方向0~479
y 1),则
1 0 0
P'x' y' 1 x y 1 0 1 0 x
Tx1
Ty1
1
y 1Tt1
经第二次平移变换后的坐标为P*(x* y* 1)
P * x *
y * 1 x'
y'
1
1 0
0 0 1 0
Tx
2
Ty 2
1
1 0 0 1 0 0
x y 1 0 1 0 0 1 0 x y 1 Tt1Tt2
44
关于透视投影
一点透视投影
两点透视投影
三点透视投影
45
内容
二维变换 三维变换 裁剪
二维线裁剪 二维多边形裁剪 文本裁剪 三维裁剪 关于三维变换与裁剪
46
三维变换流程图
图形裁剪算法
图形裁剪算法研究本文由天空乐园郑州大学生兼职网整理分享摘要在用户坐标系中定义的图形往往是大而复杂的,而输出设备如显示屏幕的尺寸及其分辨率却是有限的,为了能够清晰地观察某一部分或对其进行某些绘图操作,就需要将所关心的这一局部区域的图形从整个图形中区分出来,这个区分指定区域内和区域外的图形过程称为裁剪,所指定的区域称为裁剪窗口。
裁剪通常是对用户坐标系中窗口边界进行裁剪,然后把窗口内的部分映射到视区中,也可以首先将用户坐标系的图形映射到设备坐标系或规范化设备坐标系中,然后用视区边界裁剪。
关键词:矢量裁剪多边形裁剪圆裁剪双边裁剪法线段裁剪字符裁剪引言在人机交互编辑时,作业员往往要把某一区域放大到整个屏幕显示区,这要靠开窗裁剪来实现。
另外,地图的输出往往是分幅输出的,这也要靠开窗裁剪来实现。
裁剪是用于描述某一图形要素(如直线、圆等)是否与一多边形窗口(如矩形窗口)相交的过程,其主要用途是确定某些图形要素是否全部位于窗口之内,若只有部分在窗口内又如何裁剪去窗口外的图形,从而只显示窗口内的内容。
对于一个完整的图形要素,开窗口时可能使得其一部分在窗口之内,一部分位于窗口外,为了显示窗口内的内容,就需要用裁剪的方法对图形要素进行剪取处理。
裁剪时开取的窗口可以为任意多边形,但在实践工作中大多是开一个矩形窗口。
1窗口区和视图区1.1坐标系1.用户坐标系(World Coordinates)又称为世界坐标系、完全坐标系等,它可以是用户用来定义设计对象的各种标准坐标系,例直角坐标、极坐标、球坐标、对数坐标等。
用户坐标系所拥有的区域范围从理论上说是连续的、无限的。
2.观察坐标系(Viewing Coordinates)在用户坐标中设置观察坐标系,在观察坐标系中定义一个观察窗口。
观察坐标系用来任意设置矩形窗口的方向。
一旦建立了观察参考系,就可以将用户坐标系下的描述变换到观察坐标系下。
由于窗口和视图是在不同坐标系中定义的,因此,在把窗口中图形信息转换到视图区之前,必须进行坐标变换,即把用户坐标系的坐标值转化为设备坐标系的坐标值。
计算机图形学第3章
第3章 基本图形生成算法
3.1 生成直线的常用算法
均假定所画直线的斜率k∈[0,1]。
3.1.1 DDA画线算法
DDA(Digital Differential Analyzer)画线 算法也称数值微分法,是一种增量算法。它的算 法实质是用数值方法解微分方程,通过同时对x和 y各增加一个小增量,计算下一步的x、y值。
边界表示的四连通区域种子填充算法 内点表示的四连通区域种子填充算法 边界表示的八连通区域种子填充算法 内点表示的八连通区域种子填充算法
第3章 基本图形生成算法
1.边界表示的四连通区域种子填充算法
基本思想:从多边形内部任一点(像素)出发,依“左 上右下”顺序判断相邻像素,若其不是边界像素且没有被填 充过,对其填充,并重复上述过程,直到所有像素填充完毕。 可以使用栈结构来实现该算法,算法的执行步骤如下: 种子像素入栈,当栈非空时,重复执行如下三步操作: (1)栈顶像素出栈; (2)将出栈像素置成多边形填充的颜色; (3)按左、上、右、下的顺序检查与出栈像素相邻的 四个像素,若其中某个像素不在边界上且未置成多边形色, 则把该像素入栈。
过各行各列像素中心构造一组虚拟网格线,按直 线从起点到终点的顺序计算直线与各垂直网格线的交 点,然后确定该列像素中与此交点最近的像素。 由图3-5不难看出:若s<t, 则Si比较靠近理想直线,应 选Si;若s≥t,则Ti比较靠近 理想直线,应选Ti。
第3章 基本图形生成算法
令dx=x2-x1,dy=y2-y1 递推公式 :di 1 di 2dy 2dx( yi yi 1 ) di的初值: d1 2dy dx 当di≥0时,选Ti,
第3章 基本图形生成算法
裁剪算法——中点分割算法Liang-Barsky算法
裁剪算法——中点分割算法Liang-Barsky算法三、中点分割法⾸先对直线段的端点进⾏编码。
【核⼼思想:通过⼆分逼近来确定直线段与窗⼝的交点。
】具体⽅法:1、若中点不在窗⼝内,则把【中点】和离窗⼝边界【最远点】构成的线段丢掉,以线段上的另⼀点和该中点再构成线段求其中点。
2、如果中点在窗⼝内,则⼜以中点和最远点构成线段,并求其中点,直到中点与窗⼝边界的坐标值在规定的误差范围内想等。
【问题】中点分割算法会不会⽆限循环⼆分下去?由于屏幕像素是有限的⽽且会规定误差范围,⼀般计算次数不会太多。
四、Liang-Barsky裁剪算法——>【基本出发点:直线的参数⽅程】Liang-Barsky算法是写进国内外主流《计算机图形学》教科书⾥唯⼀⼀个亿中国⼈命名的算法。
【主要思想】(1)⽤参数⽅程表⽰⼀条直线;(2)把被裁剪的红⾊直线段看成是⼀条【有⽅向】的【线段】,把窗⼝的四条边分成两类:⼊边和出边;裁剪线段的起点是直线和两条⼊边的交点以及始端点三个点⾥最前⾯的⼀个点,即参数u【最⼤】的那个点;裁剪线段的终点是直线和两条出边的交点以及端点最后⾯的⼀个点,即参数u【最⼩】的那个点;【梁先⽣的重⼤发现】如果⽤u1,u2分别表⽰线段(u1<=u2)可见部分的开始和结束——>由直线的参数⽅程可知:线段和窗⼝边界⼀共有四个交点,根据Pk的符号,可以知道那两个是⼊交点,那两个是出交点。
:【Liang-Barsky裁剪算法步骤】(1)输⼊直线段的两端点坐标(x1,y1)、(x2,y2),以及窗⼝的四条边界坐标:wxl,wxr,wyb,wyt;(2)若Δx=0,则p1=p2=0,此时进⼀步判断是否满⾜q1<0或q2<0,若满⾜,则直线段不在窗⼝内,算法转(7)结束,否则,进⼀步计算Umax=max(0,Uk|pk<0)和Umin=min(Uk|pk>0,1),其中,Uk=qk/pk;(pk≠0,k=3,4)算法转(5);(3)若Δy=0,则p3=p4=0,此时进⼀步判断是否满⾜q3<0或q4<0,若满⾜,则直线段不在窗⼝内,算法转(7),否则,进⼀步计算Umax=max(0,Uk|pk<0)和Umin=min(Uk|pk>0,1),其中,Uk=qk/pk;(pk≠0,k=3,4)算法转(5);(4)若上述两个条件均不满⾜,则有pk≠0(k=1,2,3,4),此时计算Umax=max(0,Uk|pk<0,Uk|pk<0)和Umin=min(Uk|pk>0,Uk|pk>0,1)其中,Uk=qk/pk;(pk≠0,k=1,2,3,4);(5)求得Umax和Umin后,进⾏判断:若Umax>Umin,则直线段在窗⼝外,算法转(7)若Umax≤Umin,带⼊直线段参数⽅程;(6)利⽤直线的扫描转换算法绘制在窗⼝内的直线段;(7)算法结束。
计算机图形学裁剪算法详解
计算机图形学裁剪算法详解裁剪算法详解在使⽤计算机处理图形信息时,计算机内部存储的图形往往⽐较⼤,⽽屏幕显⽰的只是图的⼀部分。
因此需要确定图形中哪些部分落在显⽰区之内,哪些落在显⽰区之外,以便只显⽰落在显⽰区内的那部分图形。
这个选择过程称为裁剪。
最简单的裁剪⽅法是把各种图形扫描转换为点之后,再判断各点是否在窗内。
但那样太费时,⼀般不可取。
这是因为有些图形组成部分全部在窗⼝外,可以完全排除,不必进⾏扫描转换。
所以⼀般采⽤先裁剪再扫描转换的⽅法。
(a)裁剪前 (b) 裁剪后图1.1 多边形裁剪1直线段裁剪直线段裁剪算法⽐较简单,但⾮常重要,是复杂图元裁剪的基础。
因为复杂的曲线可以通过折线段来近似,从⽽裁剪问题也可以化为直线段的裁剪问题。
常⽤的线段裁剪⽅法有三种:Cohen-Sutherland,中点分割算法和梁友栋-barskey 算法。
1.1 Cohen-Sutherland裁剪该算法的思想是:对于每条线段P1P2分为三种情况处理。
(1)若P1P2完全在窗⼝内,则显⽰该线段P1P2简称“取”之。
(2)若P1P2明显在窗⼝外,则丢弃该线段,简称“弃”之。
(3)若线段既不满⾜“取”的条件,也不满⾜“弃”的条件,则在交点处把线段分为两段。
其中⼀段完全在窗⼝外,可弃之。
然后对另⼀段重复上述处理。
为使计算机能够快速判断⼀条直线段与窗⼝属何种关系,采⽤如下编码⽅法。
延长窗⼝的边,将⼆维平⾯分成九个区域。
每个区域赋予4位编码CtCbCrCl.其中各位编码的定义如下:图1.2 多边形裁剪区域编码图5.3线段裁剪裁剪⼀条线段时,先求出P1P2所在的区号code1,code2。
若code1=0,且code2=0,则线段P1P2在窗⼝内,应取之。
若按位与运算code1&code2≠0,则说明两个端点同在窗⼝的上⽅、下⽅、左⽅或右⽅。
可判断线段完全在窗⼝外,可弃之。
否则,按第三种情况处理。
求出线段与窗⼝某边的交点,在交点处把线段⼀分为⼆,其中必有⼀段在窗⼝外,可弃之。
SutherlandHodgman多边形裁剪算法
SutherlandHodgman多边形裁剪算法Sutherland-Hodgman多边形裁剪算法是一种用于裁剪二维多边形的算法,它是由伊恩·萨瑟兰(Ian Sutherland)和威廉·霍德曼(William E. Hodgman)在1962年提出的。
这种算法基于线段裁剪的思想,通过迭代过程逐步减少多边形的顶点数量,直到多边形完全被裁剪为止。
一、算法步骤1.初始化:将待裁剪的多边形P和裁剪多边形Q的边界表示为一系列的顶点。
设P的顶点集合为{p0, p1, , pn},Q的顶点集合为{q0, q1, , qm}。
2.排序:将P的所有顶点按照逆时针(或顺时针)的顺序排列,将Q的所有顶点也按照逆时针(或顺时针)的顺序排列。
3.初始化裁剪结果:将裁剪结果设为一个空的多边形R。
4.迭代过程:从i=0开始,依次进行以下步骤,直到i=n或j=m:a. 确定P的第i个顶点pi是否在Q的边界内部(即判断pi是否在Q的凸壳上)。
如果pi不在Q的边界内部,则直接将pi添加到裁剪结果R中。
b. 如果pi在Q的边界内部,则找到Q边界上与pi最近的两个点,记为qi1和qi2。
根据这两个点的位置,将P的第i个顶点pi分割成两个部分,分别位于qi1和qi2之间的线段以及线段外的部分。
将这两个部分分别添加到R中。
c. 将i增加1,如果i<n,跳转到步骤4.4开始下一轮迭代;否则结束迭代。
5.返回结果:将R作为裁剪结果输出。
二、算法复杂度Sutherland-Hodgman多边形裁剪算法的时间复杂度为O(n+m),其中n和m分别为待裁剪多边形P和裁剪多边形Q的顶点数量。
这是因为每次迭代过程中,我们最多只处理n个P的顶点和m个Q的顶点。
空间复杂度为O(n+m),因为我们需要存储P和Q的顶点以及裁剪结果R的多边形表示。
三、算法应用Sutherland-Hodgman多边形裁剪算法可以用于各种需要裁剪二维多边形的场景,如计算机图形学中的视口裁剪、图像处理中的形状裁剪等。
计算机图形学-实验五直线和多边形的裁剪
大学实验报告学院:计算机科学与信息学院专业:软件工程班级:102班** 实验组实验时间指导教师成绩实验工程名称实验五直线和多边形的裁剪实验目的掌握直线段的裁剪算法以及多边形的裁剪算法实验要求熟练掌握直线段的裁剪算法以及多边形的裁剪算法的根本原理,并编写测试代码进展实验。
实验原理Cohen-Sutherland直线剪裁算法以区域编码为根底,将窗口及其周围的,8个方向以4 bit的二进制数进展编码。
右图所示的编码方法将窗口及其邻域分为5个区域:⑴域:区域(0000)。
⑵上域:区域(1001, 1000, 1010)。
⑶下域:区域(0101, 0100, 0110)。
⑷左域:区域(1001, 0001, 0101)。
⑸右域:区域(1010, 0010, 0110)。
当线段的两个端点的编码的逻辑"与〞非零时,线段为显然不可见的,对*线段的两个端点的区号进展位与运算,可知这两个端点是否同在视区的上、下、左、右;Cohen-Sutherland直线剪裁算法的算法思想是:对于每条线段P1P2分为三种情况处理。
〔1〕假设P1P2完全在窗口,则显示该线段P1P2简称"取〞之。
〔2〕假设P1P2明显在窗口外,则丢弃该线段,简称"弃〞之。
〔3〕假设线段既不满足"取〞的条件,也不满足"弃〞的条件,则在交点处把线段分为两段。
其while (code1 != 0 || code2 != 0) {if ((code1 & code2) != 0) {// 两端点的编码相与不为0,表示直线在窗口外return;}if (code1 != 0) {code = code1;} else {code = code2;}if ((LEFT & code) != 0) {// 直线的端点与矩形窗口的左边编码相与!=0* = *L;y = y1 + (y2 - y1) * (*L - *1) / (*2 - *1);// 求直线与矩形窗口的左边界的交点} elseif ((RIGHT & code) != 0) {// 直线的端点与矩形窗口的右边编码相与!=0* = *R;y = y1 + (y2 - y1) * (*R - *1) / (*2 - *1);// 求直线与矩形窗口的右边界的交点} elseif ((BOTTOM & code) != 0) {// 直线的端点与矩形窗口的下边编码相与!=0y = YB;* = *1 + (*2 - *1) * (YB - y1) / (y2 - y1);// 求直线与矩形窗口的下边界的交点} elseif ((TOP & code) != 0) {// 直线的端点与矩形窗口的上边编码相与!=0y = YT;* = *1 + (*2 - *1) * (YT - y1) / (y2 - y1);// 直线的端点与矩形窗口的上// 边编码相与!=0}if (code == code1) {*1 = *;y1 = y;code1 = encode(*, y);} else {*2 = *;y2 = y;code2 = encode(*, y);}}g.drawLine((int) (*1 + 0.5), (int) (y1 + 0.5), (int) (*2 + 0.5),(int) (y2 +0.5));}二、多边形裁剪的核心代码为:通过点集画直线或者多边形:privatevoid draw() {//通过点集画直线或者多边形for (int i = 1; i < points.size(); i++) {Point p1 = new Point();p1 = points.get(i);int *1 = (int) p1.get*();int y1 = (int) p1.getY();Point p2 = new Point();p2 = points.get(i - 1);int *2 = (int) p2.get*();int y2 = (int) p2.getY();g.drawLine(*1, y1, *2, y2);}}多边形的裁剪函数:private Point[] cutPicture(Point[] point, Point[] edge) {// 剪裁函数,参数为〔点集,边〕Point[] intersectPoint = new Point[20];//存放交点的集合for (int j = 0; j < 20; j++) {intersectPoint[j] = new Point();}Point s = new Point();Point p = new Point();Point t = new Point();int i = 0;int length = point.length;s = point[length - 1];for (int j = 0; j < length; j++) {p = point[j];if (inside(p, edge)) {// sp在窗口,情况1if (inside(s, edge)) {intersectPoint[i] = p;i += 1;} else {// s在窗口外,情况4t = intersect(s, p, edge);intersectPoint[i] = t;i += 1;intersectPoint[i] = p;i += 1;}} elseif (inside(s, edge)) {// s在窗口,p在窗口外,情况3t = intersect(s, p, edge);intersectPoint[i] = t;i += 1;}// 情况2没有输出s = p;}List<Point> tempList = new ArrayList<Point>();for (int k = 0; k < i; k++) {if (intersectPoint[k] != null) {Point pt = intersectPoint[k];tempList.add(pt);}}Point[] temp = new Point[tempList.size()];for (int j = 0; j < tempList.size(); j++) {temp[j] = new Point();temp[j] = tempList.get(j);}intersectPoint = temp;return intersectPoint;}判断点是否在裁剪边的可见侧:privateboolean inside(Point point, Point[] edge) {//判断点是否在裁剪边的可见侧// 裁剪边为窗口下边if ((edge[0].y == edge[1].y) && (edge[0].* < edge[1].*)) {if (point.y >= edge[0].y) {returntrue;}}// 裁剪边为窗口上边if ((edge[0].y == edge[1].y) && (edge[0].* > edge[1].*)) {if (point.y <= edge[0].y) {returntrue;}}// 裁剪边为窗口右边if ((edge[0].* == edge[1].*) && (edge[0].y < edge[1].y)) {if (point.* <= edge[0].*) {returntrue;}}// 裁剪边为窗口左边if ((edge[0].* == edge[1].*) && (edge[0].y > edge[1].y)) {if (point.* >= edge[0].*) {returntrue;}}returnfalse;}直线段与窗口边界求交:private Point intersect(Point s, Point p, Point[] edge) {//直线段与窗口边界求交,并返回交点Point t = new Point();if (edge[0].y == edge[1].y) {// 水平裁剪边t.y = edge[0].y;t.* = s.* + (edge[0].y - s.y) * (p.* - s.*) / (p.y - s.y);} elseif (edge[0].* == edge[1].*) {// 垂直裁剪边t.* = edge[0].*;t.y = s.y + (edge[0].* - s.*) * (p.y - s.y) / (p.* - s.*);}return t;}鼠标的监听类〔部类〕:class MouseMonitor e*tends MouseAdapter {//通过鼠标的单击获取点,并画出直线或者多边形publicvoid mouseClicked(MouseEvent e) {points.add(e.getPoint());if (points.size() > 1) {draw();}}}键盘的监听类〔部类〕:class KeyMonitor e*tends KeyAdapter {// 键盘控制publicvoid keyPressed(KeyEvent e) {switch (e.getKeyCode()) {case KeyEvent.VK_R:// 清空画布和点集panel.repaint();points.removeAll(points);break;case KeyEvent.VK_W://对裁剪窗口的处理g.setColor(Color.RED);g.drawRect(*L, YB, *R - *L, YT - YB);//存放裁剪窗口的边top = new Point[2];// 存放裁剪窗口的上边top[0] = new Point(*L, YB);top[1] = new Point(*R, YB);right = new Point[2];//存放裁剪窗口的右边right[0] = new Point(*R, YB);right[1] = new Point(*R, YT);bottom = new Point[2];//存放裁剪窗口的下边bottom[0] = new Point(*R, YT);bottom[1] = new Point(*L, YT);left = new Point[2];//存放裁剪窗口的左边left[0] = new Point(*L, YT);left[1] = new Point(*L, YB);break;case KeyEvent.VK_A://对直线段进展裁剪g.setColor(Color.GREEN);Point p1 = points.get(0);Point p2 = points.get(1);lineCut(p1.get*(), p1.getY(), p2.get*(), p2.getY()); break;case KeyEvent.VK_B://对多边形进展裁剪source = new Point[points.size()];//得到多边形的点for (int i = 0; i < points.size(); i++) {source[i] = points.get(i);}g.setColor(Color.GREEN);wT = cutPicture(source, top);//得到多边形与裁剪窗口上边的交点wR = cutPicture(wT, right);//得到多边形与裁剪窗口右边的交点wB = cutPicture(wR, bottom);//得到多边形与裁剪窗口下边的交点wL = cutPicture(wB, left);//得到多边形与裁剪窗口左边的交点第二种情况:线段在裁剪窗口的部,线段完全可见。
线段裁剪算法
线段裁剪算法裁剪:确定图形中哪些部分落在显⽰区之内,哪些落在显⽰区之外,以便只显⽰落在显⽰区内的那部分图形。
这个选择过程称为裁剪。
图形裁剪算法,直接影响图形系统的效率。
Cohen-SutherLand直线裁剪算法1、基本思想对于每条线段P1P2分为三种情况处理:1. 若P1P2完全在窗⼝内,则显⽰该线段P1P2。
2. 若P1P2明显在窗⼝外,则丢弃该线段。
3. 若线段不满⾜(1)或(2)的条件,则在交点处把线段分为两段。
其中⼀段完全在窗⼝外,可弃之。
然后对另⼀段重复上述处理。
2、编码⽅法为了使计算机能够快速的判断⼀条线段与窗⼝属于何种关系,采⽤如下编码⽅法:把窗⼝的边界延长成直线,窗⼝平台就分成9个分区,每个区设定⼀个4位的编码与之对应。
平⾯上每⼀条直线的端点根据其所在的区域都可定义出两个编码。
编码(以⼆进制形式⾃右向左给出)的意义如下:1. 第0位:如果端点在窗⼝左边界左侧,则为1,否则为0;2. 第1位:如果端点在窗⼝右边界右侧,则为1,否则为0;3. 第2位:如果端点在窗⼝下边界下侧,则为1,否则为0;4. 第3位:如果端点在窗⼝上边界上侧,则为1,否则为0。
3、线段裁剪裁剪⼀条线段时,先求出端点p1和p2的编码code1和code2:1. 如果code1和code2均为0,则说明P1和P2均在窗⼝内,那么线段全部位于窗⼝内部,应取之。
(c)2. 如果code1和code2经过按位与运算后的结果code1&code2不等于0,说明P1和P2同时在窗⼝的上⽅、下⽅、左⽅或右⽅,那么线段全部位于窗⼝的外部,应弃之。
(e,d)3. 如果上述两种条件均不成⽴,则可按如下⽅法处理:求出线段与窗⼝边界的交点,在交点处把线段⼀分为⼆,其中必有⼀段完全在窗⼝外,可以弃之。
再对另⼀段重复进⾏上述处理,直到该线段完全被舍弃或者找到位于窗⼝内的⼀段线段为⽌。
(a,b,d’)4、检查顺序编码中对应位为1的边。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Cohen-Sutherland算法的实现
算法优点: 1) 简单将不需剪裁的直线舍弃。法则是:若是 一条直线的两头在同一地区,则该直线不需裁剪, 不然,该直线为也许剪裁直线。 2) 对也许剪裁的直线缩小了与之求交的边框范 畴。法则是:若是直线的一个端点在上(下、左、 右)域,则此直线与上边框求交,然后移除上边框 以上的局部。该法则对直线的另一端点也实用。这 样,一条直线至多只需与两条边框求交。
p1
梁友栋-Barsky算法(Liang-Barsky算法)
写入图形学教科书的唯一中国人的算 法
梁有栋教授的贡献
Liang-Barsky算法 几何连续理论 从几何学与纤维缠绕理论到基因工程
梁友栋先生出生于1935年7月,福建福州人. 19561960年于复旦大学作为研究生,师从苏步青先生学 习几何理论,1960年研究生毕业后任教于浙江大学 数学系,1984-1990年任数学系主任. 一直致力于计算机辅助几何设计与计算机图形学方 面的研究.
如:CD C:0000 D:1000 Dt位等于1,与上边相交
9
8
10
1 2
AB:与窗口左边相交,求交点H, AH和BH显然不可见
EF:与窗口上边交点I,弃EI 与窗口下边交点K,弃KF 与窗口右边交点J,弃KJ 保留IJ
0
5 4 6
E
I
L M J
C
CD:与窗口上边交点L, 弃CL DO G 与窗口下边交点O, 弃OD H 与窗口右边交点M, 弃LM 与窗口左边交点N, 弃NO 保留MN 求交次数最多 可达?
区域编码
◦ 由窗口四条边所在直线把二维平面分成9个区域,每个区域 赋予一个四位编码,CtCbCrCl,上下右左
1 Ct 0 1 Cb 0 1 Cr 0 1 Cl 0 当y y max else 当y y min else 当x x max else 当x x min else
第三章
裁剪是抽取数据的一部分,或者识别一个指定区域 内部或外部的画面或图片的成分的过程。 按照被裁剪的图形可以分为:二维裁剪算法和三维 裁剪算法 按照裁剪区域的形状可以分为:规则区域和不规则 区域 本章二维裁剪算法只考虑举行和多边形,裁剪的对 象只考虑点、线段、多边形、字符等。 三维裁剪算法只考虑正方体和平截头正四棱锥两种 裁剪盒,裁剪对象只考虑线段。
y yT yB P0 xL A B
P1 C
D
设要裁剪的线段是P0P1。 P0P1和
窗口边界交于A,B,C,D四点.
算法的基本思想是从A,B和P0三点
xB
x
中找出最靠近P1的点,图中要找 的点是B; 从C,D和P1中找出最靠 近P0的点。图中要找的点是C点。 那么BC就是P0P1线段上的可见部 分。
1.
p2 示例: b
对于A线段, p1 c P1(0000).p2(0000),显示出来 对于线段B p1 p2 a p1 P1(1000),p2(1000),非零,丢弃 p2 d 对于线段C P1(1000),p2(0010),“与”为零,不可判断,对P1 开始,pa=p1,pb=p2,求得pm1(1000),pb与pm1 p2 “与”为零,不可判断, pa=pm1,求得pm2(0010),Pb与pm2 “与”非零,丢弃,pb变为pm2。直到线段长度小于一个给定的值,计算该 点的 编码。对于p2做同样处理,最后得出线段C不可见。 对于选段D: P1(0001),p2(0100), “与”为零,不可判断。 从p1开始, pa=p1,pb=p2,pm1(0100),pbpm1丢弃,pm1代替pb,求 得pm2(0000),pm2与pb“与”,为零 ,pa=pm2,计算pm3(0000), 最后汇聚成一点。计算该点的编码。对 p2进行同样处理。
区域编码
◦ 由窗口四条边所在直线把二维平面分成9个区域,每个区域 赋予一个四位编码,CtCbCrCl,上下右左
1 当y y max 例如:给出直线 AB的 Ct 端点编码。 0 else 1 当y y min A : 1001 问题 2: 给定一条线段 Cb 0 else B:0010 端点的区域码 ,该如何 1 当x x max 判断属于哪一种情况? Cr 0 1 Cl 0 else 当x x min else
A
N B
K F
最多求交次数 为4
Cohen—SutherLand直线裁剪算法 直线和窗口的关系可以分为如下三类: 1) 整条直线在窗口之内,此时,不需裁剪,显 现整条直线。 2) 整条直线在窗口之外,此时,不需裁剪,不 显现整条直线。 3) 局部直线在窗口之内,局部直线在窗口之外, 此时,必要求出直线与窗框之交点,并将窗口外的 直线局部剪裁掉,显现窗口内的局部。
直线裁剪方法
◦ Cohen-Sutherland裁剪算法
◦ 中点分割算法 ◦ 梁友栋-barskey算法
多边形裁剪方法
◦ Sutherland-Hodgman逐次多边形裁剪算法 ◦ Weiler-Atherton多边形裁剪算法
对于线段的裁剪基本思想是:
线段是否全不在窗口里,若是,转5 ② 线段是否全在窗口,若是,转4 ③ 计算该线段与窗口边界的交点,以此将线段分为两部分, 丢弃不可见的部分,剩余线段转2 ④ 保留并显示该线段 ⑤ 算法结束 可以看到算法的核心有两个:
中心思想: 1. 算法采用了裁剪算法相同的编码和检查办法 2. 先判断完全可见和显然不可见的线段 3. 不能判断的线段使用中点分割方法。 4. 算法从线段的两个端点出发,分别求出离本端点 最远的可见点。 5. 两个可见点之间的线段就是所求的可见线段
算法的思想:
①
② ③ ④
对线段p1p2进行编码,如果p1p2可以直接保留或者舍弃, 算法结束,否则进入步骤2. 从p1出发寻找离p1最远的可见点B; 从p2出发寻找离p2最远的可见点A; AB之间的线段就是可见的线段。
A
B
若P1P2完全在窗口内, code1=0,且code2=0,则“取”; 若P1P2明显在窗口外code1&code2≠0,则“弃” ; 若P1P2明显在窗口外code1&code2=0,则不确定 ; 在交点处把线段分为两段。其中一段完全在窗口外,可弃
之。然后对另一段重复上述处理。
算法的缺点?
第一,当code1&code2≠0,能判断出直 线段显然在窗口之外. 然而这个条件 并没有包含所有的在窗口之外的直线段,比如: code1=0001,code2=0100,如图 中直线段P3P4,此时, code1&code2=0,但直线段也是完全在窗口之外.这就意 味着这类型的直线必须计算与窗口的边线求交,其实是 一种无意义操作;
线段p1(x1,y1)p2(x2,y2)的参数方程可以表示为:
x=x1+t△x y=y1+t△y 其中,△x=x2-x1, △y=y2-y1,0<=t<=1
P(x,y)代表了该线段上的一个点,其值由参数t确定。 由公式可知,当t=0时,该点为P1(x1,y1),当t=1时,该 点为P2(x2,y2)。 如果点P(x,y)位于由坐标(xmin,ymin)和(xmax,ymax) 所确定的矩形窗口内,那么下式成立:
如何改进?
第二,对于p1p2,当code 码中同时有两位不等于0 时,求 交运算的次数多达四次. 如图2中直线P1P2 与窗口的四 条边的交点分别为A、B、C、D。而实际上,直线只与窗 口的两条边相交,另外两个交点发生在边的延长线上。
பைடு நூலகம்
编码裁剪算法需要求线段与边界的交点 如果使用将线段一分为二,那么求交点的过程可以 用二分法逐渐逼近来得到 中点分割算法比较适合硬件实现 如果用软件来实现,中点分割算法的运行速度反而 比编码裁剪算法慢
九十年代后期,六十多岁的他积极开展纤维缠绕几何 设计的研究,为我国几何设计与计算机图形学的研究 做出了杰出贡献. 鉴于梁友栋先生的杰出贡献和成就,中国工业与应用 数学学会几何设计与计算专委会授予梁友栋先生第 二届“中国几何设计与计算贡献奖”。 梁友栋和Barsky独立地提出了更快的参数化线段裁 剪算法
①
① 判断线段与窗口的关系。 ② 获取线段与窗口的交点。
基本思想: 对于每条线段算法分成三 种情况处理:
第一种:若线段完全在窗口内,则显示该线段称 “完全可见”,需要“取”之; 第二种:若明显在窗口外,称“完全不可见”.则 丢弃该线段。 第三种:若线段不满足“取”或 “弃”的条件,则 在交点处把线段分为两段. 其中一段完全在窗口 外,可弃之. 然后对另一段重复上述处理。 问题1:用什么方法解决该问题?
80年代初提出了著名的Liang-Barsky裁剪算法,通过 线段的参数化表示,实现快速裁剪,至今仍是计算机 图形学中最经典的算法之一; 80年代末到90年代,梁友栋先生致力于几何连续性的 研究,提出了一系列几何连续性方面的理论和方法,成 为国际上几何连续性研究的重要力量; 1991年梁友栋先生为首完成的成果“计算机图形生 成与几何造型研究”获国家自然科学三等奖;
xmin≤x0+ t· Δx≤xmax ymin≤y0+ t· Δy≤ymax
t· Dk ≤Mk , k=1,2,3,4 其中: ① D1=-Δx, M1=x0-xmin ② D2= Δx, M2=xmax-x0 ③ D3=-Δy, M3=y0-ymin ④ D4= Δy, M4=ymax-y0 进行公式验证: 公式1表示为: t*- Δx<=x0-xmin-xmin<=x0+t Δx 公式2表示为:t Δx<=xmax-x0- x0+t Δx<=xmax 公式3表示为:t*- Δy<=y0-ymin ymin<=y0+t Δy 公式4表示为: t Δy<=ymax-y0 y0+t Δy<=ymax