多边形裁剪地Sutherland—Hodgman算法(计算机图形学)
sutherland-hodgman原理
sutherland-hodgman原理
Sutherland-Hodgman算法是一种计算多边形相交的算法。
该算
法是由伊文·苏瑟兰和阿尔伯特·霍奇曼在1974年首次提出的。
该算法的目的是确定一个多边形在给定一个“裁剪多边形”内部的部分,即得到裁剪后的多边形。
Sutherland-Hodgman算法的基本思想是,通过逐边计算两个多
边形之间的相交点,然后根据相交点的位置来保留或丢弃多边形的顶点。
具体步骤如下:
1. 首先,将待裁剪的多边形的顶点按逆时针的顺序排列。
2. 针对裁剪多边形的每条边,依次进行以下步骤:
a. 计算裁剪线与多边形顶点的相对位置关系。
有三种可能的
情况:内部、外部或边上。
b. 根据相对位置关系,确定多边形顶点是否需要保留。
c. 如果裁剪线与多边形的一条边相交,计算相交点并加入裁
剪后的多边形的顶点列表。
3. 重复步骤2,直到处理完所有的裁剪多边形的边。
4. 返回裁剪后的多边形。
该算法的主要优点是简单易懂、计算量相对较小,但也存在一
些问题。
首先,该算法只能处理凸多边形,对于凹多边形需要进行额外的处理。
其次,该算法无法正确处理相互重叠的多边形,这种情况下算法的结果可能是不正确的。
因此,在实际应用中,可能需要在算法的基础上进行一些改进或增加其他算法来解决这些问题。
多边形裁剪地Sutherland—Hodgman算法(计算机图形学)
多形裁剪的 Sutherland —Hodgman算法1>. Sutherland—Hodgman多形裁剪算法思想算法的根本思想是每次用窗口的一条界及其延来裁剪多形的各。
多形往常由它的点序列来表示,裁剪某条界裁剪后,果形成新的点序列,又留待下条界行裁剪,⋯,直到窗口的全部界都裁剪完,算法形成最后的点序列,才是果多形〔它可能组成一个或多个多形〕。
当多形一个点 Pi 相于窗口某条界及其延行剪裁,不外乎以下四种状况〔即裁剪〕:1、点 Pi 在内,前一点 Pi-1也在内,将 Pi 入新的点序列;2、点 Pi 在内,前一点 Pi-1在外,先求交点Q,再将 Q、Pi 挨次入新的点序列;3、点 Pi 在外,前一点 Pi-1在内,先求交点Q,再将 Q入新的点序列;4、点 Pi 与前一点 Pi-1 均在外,点序列中不增添新的点。
2>. Sutherland—Hodgman多形裁剪算法步考多形相于一条界及其延行裁剪的算法:1.从主函数获得待裁剪多形的点序列 P[][2] 、点序列数 n、窗口一条界参数 xl 〔假定矩形窗口的左界〕;2.初:将点序列中的最后一个点前一点S;置初始志 flag :if(S在界内)flag=0;else flag=1;新的点序列数j=0 ;3.多形各点行裁剪理,果放入新的多形点序列Q[][2]中:for( 第一个点直到最后一个点,逐个理〕{if(Pi 在界内 ){if(flag!=0){flag=0;求交点并放入新的多形点序列Qj 中;j++ ;}将目前点放入新的多形点序列 Qj 中: Qj=Pi ; j++ ;}else{if(flag==0){flag=1;求交点并放入新的多形点序列Qj 中;j++ ;}}将目前极点赋给S: S=Pi;}4.做返回准备:将新的多边形极点序列Q又逐个放回原多边形极点序列P 中: P=Q;将新的多边形极点数j 放回原多边形极点数n 中: n=j ;////////////////////////////////////////////////////////////////////////////////////////-----多边形裁剪的Sutherland—Hodgman算法---------///////////////////////////////////////////////////////////////////////////////////////void CMyClip_AView::ClipedgeL(CPoint polypoint[], CPoint clipwindow[],UINT polynum)/* 此中参数 polypoint[] 为多边形极点 ,clipwindow[] 为裁剪窗口极点 ,polynum 为多边形极点数量 */{//找出裁剪窗口界限long xl,xr,yt,yb;UINT i;xl=clipwindow[0].x;xr=clipwindow[0].x;yt=clipwindow[0].y;yb=clipwindow[0].y;for(i=1;i<=4;i++){if(xl>clipwindow[i].x)xl=clipwindow[i].x;if(xr<clipwindow[i].x)xr=clipwindow[i].x;if(yb>clipwindow[i].y)yb=clipwindow[i].y;if(yt<clipwindow[i].y)yt=clipwindow[i].y;}//CPoint B[Polygon_Num],C[Polygon_Num];UINT m_nA,m_nB;int x,y;long tem1,tem2;m_nA=polynum;/*记录原始多边形极点极点个数*/m_nB=0;/* 记录重生成多边形极点极点个数*/for(i=0;i<m_nA;i++){if(polypoint[i].x<xl&& polypoint[i+1].x<xl)/* 判断的多边形边两个端点都在外面,不做办理*/{continue;/*假如是这类状况,那么就对持续对下一条多边形边作判断,也就是说下边的判断不用做了*/}if(polypoint[i].x>=xl&& polypoint[i+1].x>=xl)/* 边两个端点都在内部,保留*//* 由于每个保留的点在数组中只出现一次,且下一次判断时第二个端点必定会要取到,所以只保留的两个点中的第一个*/{B[m_nB].x =polypoint[i].x ;B[m_nB].y =polypoint[i].y ;m_nB=m_nB+1;continue;}if(polypoint[i].x<xl&& polypoint[i+1].x>=xl)/*边两个端点起点在外面,终点在内部,求交点,而后交点,终点都应当送入暂时数组*/{/*保留交点*/x=xl;tem1=(xl-polypoint[i].x);//tem2=(xl-x1)*dy/dx+y1;//y/x=dy/dx---->y=x*dy/dxtem2=tem1*(polypoint[i+1].y-polypoint[i].y)/(polypoint[i+1].x-polypoint[i].x)+polypoint[i].y;y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB=m_nB+1;continue;}if(polypoint[i].x>=xl && polypoint[i+1].x<xl)/*起点在内部,终点在外,求交点,而后起点,交点送入暂时数组*/{/*保留内部点*/B[m_nB].x =polypoint[i].x ;B[m_nB].y =polypoint[i].y ;m_nB=m_nB+1;/* 保留交点 */x=xl;tem1=(xl-polypoint[i].x);tem2=tem1*(polypoint[i+1].y-polypoint[i].y)/(pol ypoint[i+1].x-polypoint[i].x)+polypoint[i].y;y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB=m_nB+1;continue;}}//把第一个点的数据拷贝到最后//形成裁剪后的多边形if(i==m_nA){B[m_nB]=B[0];}//下 ------------------m_nA=0;for(i=0;i<m_nB;i++){if(B[i].y<yb && B[i+1].y<yb)//两个点全在下方{continue;//下一条边}if(B[i].y>=yb && B[i+1].y>=yb)//p1,p2 都在 yb 上方{C[m_nA].x =B[i].x;C[m_nA].y =B[i].y;m_nA++;continue;}if(B[i].y<yb && B[i+1].y>=yb)//p1 在下, P2 在上 , 留交点,外->内{y=yb;tem1=yb-B[i].y;//tem2=x1+(yb-y1)*dx/dytem2=tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y)+ B[i].x;x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}if(B[i].y>=yb && B[i+1].y<yb)//p1在上方,P2 在下方,留P1 和交点, 内-外{//save p1C[m_nA].x=B[i].x;C[m_nA].y=B[i].y;m_nA++;//留交点y=yb;tem1=yb-B[i].y;//tem2=x1+(yb-y1)*dx/dytem2=tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y)+B[i].x;x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}}//形成第二次裁剪多边形if(i==m_nB){C[m_nA]=C[0];}//右 ------------------m_nB=0;for(i=0;i<m_nA;i++){if(C[i].x>xr && C[i+1].x>xr)//P1 , P2 都在右方 --go next{continue;}if(C[i].x<=xr && C[i+1].x<=xr)//P1 , P2 都在左方,留P1{B[m_nB].x =C[i].x;B[m_nB].y =C[i].y;m_nB++;continue;}if(C[i].x>xr && C[i+1].x<=xr)//P1在右方,P2在左方,留交点{x=xr;tem1=C[i].x-xr;tem2=C[i].y-tem1*(C[i+1].y-C[i].y)/(C[i+1].x-C[i ].x);y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB++;continue;}if(C[i].x<=xr && C[i+1].x>xr)//P1在内, P2 在外,留P1 和交点{//save p1B[m_nB].x =C[i].x;B[m_nB].y =C[i].y;m_nB++;//save交点x=xr;tem1=C[i].x-xr;tem2=C[i].y-tem1*(C[i+1].y-C[i].y)/(C[i+1].x-C[i ].x);y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB++;continue;}}//三次裁剪后的新多边形if(i==m_nA){B[m_nB]=B[0];多边形裁剪地Sutherland—Hodgman算法(计算机图形学)适用文档}//上 -------------------m_nA=0;for(i=0;i<m_nB;i++){if(B[i].y>yt && B[i+1].y>yt)//p1,p2 都在上方 ,next{continue;}if(B[i].y<=yt && B[i+1].y<=yt)//p1,p2 都在下方 , 留 P1{C[m_nA].x =B[i].x;C[m_nA].y =B[i].y;m_nA++;continue;}if(B[i].y>yt && B[i+1].y<=yt)//P1在上方,P2在下方外->内, 留交点{y=yt;tem1=B[i].y-yt;//tem2=x1+(yb-y1)*dx/dytem2=B[i].x-tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i ].y);x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}if(B[i].y<=yt && B[i+1].y>yt)//P1在下方,P2在上方,内->外,留P1 和交点{//save p1,,,C[m_nA].x =B[i].x;C[m_nA].y =B[i].y;m_nA++;//save交点y=yt;tem1=B[i].y-yt;多边形裁剪地Sutherland—Hodgman算法(计算机图形学)适用文档//tem2=x1+(yb-y1)*dx/dytem2=B[i].x-tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i ].y);x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}}//形成裁剪后的多边形if(i==m_nB){C[m_nA]=C[0];}CClientDC dc(this);CPen tempen;tempen.CreatePen(PS_SOLID,1,RGB(255,0,0));dc.SelectObject(tempen);dc.MoveTo(C[0]);for(i=1;i<=m_nA;i++){dc.LineTo(C[i]);}}//.....。
计算机图形学(简单多边形裁剪算法)
简单多边形裁剪算法摘要:多边形裁剪算法与线性裁剪算法具有更广泛的实用意义,因此它是目前裁剪研究的主要课题。
本文主要介绍了一种基于多边形顶点遍历的简单多边形裁剪算法,它有效降低了任意多边形裁剪复杂度。
通过记录交点及其前驱、后继信息,生成结果多边形,该算法简化了交点的数据结构,节省了存储空间,降低了算法的时间复杂度,具有简单、易于编程实现、运行效率高的特点。
关键词:多边形裁剪;交点;前驱;后继;矢量数组一、技术主题的基本原理简单多边形裁剪算法综合考虑现有多边形裁剪算法的优缺点,它是一种基于多边形顶点遍历来实现简单多边形裁剪工作的。
其主要的原理是遍历多边形并把多边形分解为边界的线段逐段进行裁剪,输出结果多边形。
二、发展研究现状近年来,随着遥感绘图、CAD辅助设计、图象识别处理技术的发展,图形裁剪算法从最初在二维平面上线和图形的裁剪扩展到三维空间里体和场的裁剪,国内外相继提出不少行之有效的算法,但越来越复杂的图形和计算也对算法的速度和适用性提出了越来越高的要求。
因此,不断简化算法的实现过程,完善细节处理,满足大量任意多边形的裁剪也就成了当今算法研究的焦点之一。
以往多边形裁剪算法不是要求剪裁多边形是矩形,就是必须判断多边形顶点的顺时针和逆时针性,即存在不实用或者是增加了多边形裁剪算法的难度。
为了解决现在的问题,我们研究现在的新多边形算法,其中,裁剪多边形和被裁剪多边形都可以是一般多边形,且不需要规定多边形输入方向。
它采用矢量数组结构,只需遍历剪裁多边形和被裁剪多边形顶点即完成多边形的裁剪,具有算法简单、运行效率高的特点。
三、新算法设计1、算法的思想本算法是为了尽量降低任意多边形裁剪算法复杂度而提出的,其主要思想是采用矢量数组结构来遍历裁剪多边形和被裁多边形顶点,记录裁剪多边形和被裁减多边形交点及其前驱、后继信息,并通过记录相邻交点的线段,然后通过射线法选择满足条件的线段,之后进行线段连接,输出对应的裁剪结果。
了解电脑显卡的多边形剪裁和裁剪
了解电脑显卡的多边形剪裁和裁剪随着计算机图形学的不断发展,电脑显卡在图像处理方面的性能也逐渐提升。
而多边形剪裁和裁剪则是电脑显卡中重要的技术之一。
本文将介绍多边形剪裁和裁剪的定义、作用以及相关的算法与技术。
一、多边形剪裁和裁剪的定义多边形剪裁是指根据视口和裁剪窗口的位置,将位于裁剪窗口外的多边形剪除,只保留位于窗口内的部分。
而裁剪是指将多边形按照裁剪窗口的形状进行修剪,以适应显示设备的输出。
二、多边形剪裁的作用多边形剪裁的作用主要有以下几个方面:1. 提高渲染效率:多边形剪裁可以剔除位于屏幕外的多边形,避免不必要的计算和绘制,从而提高渲染效率。
2. 减少像素填充:在3D渲染中,所有多边形都要经过像素填充来生成最终的图像。
通过剪裁掉屏幕外的多边形,可以减少不必要的像素填充操作,提高渲染速度。
3. 实现可视化效果:多边形剪裁可以确保只显示用户所需的图像内容,可以实现视点的选择、物体的隐藏和透视等视觉效果。
三、多边形剪裁的算法与技术在实际应用中,多边形剪裁通常使用的算法包括:1. 逐边裁剪算法(Cohen-Sutherland算法):该算法通过将裁剪窗口划分为9个区域,将多边形的每条边与裁剪窗口的边界相交,并根据交点位置来确定多边形是否可见以及如何修剪多边形。
2. 多边形切割算法(Sutherland-Hodgman算法):该算法通过对多边形的每条边进行切割,生成新的多边形。
这些新的多边形通过裁剪窗口切割并连接,最终得到位于裁剪窗口内的多边形。
四、裁剪的应用和技术裁剪不仅可以应用于多边形,还可以应用于曲线、曲面和体素等图形对象的裁剪。
裁剪的技术也不仅仅局限于多边形剪裁算法,还包括对二维和三维对象的参数化、位图和文本的裁剪处理等。
在实际应用中,常用的裁剪技术包括:1. 区域编码算法:区域编码算法通过给定的区域码来标识物体所在的位置,从而对物体进行裁剪。
常见的算法有四叉树编码和八叉树编码。
2. 软件裁剪和硬件裁剪:软件裁剪是指在计算机的主机CPU上通过算法进行裁剪操作;而硬件裁剪则是指使用专门的图形处理器(GPU)来完成裁剪操作,通过并行计算提高裁剪效率。
计算机图形学第四讲
11
1001 0001
xL
A
B
C
1000 0000 E 裁剪窗口 0100
xR
第4讲 图形裁剪算法
1010 D yT 0010
7
第4讲 图形裁剪算法
直线裁减的效率策略
首先,通过方法来快速判断完全在窗口内和完全 在窗口外的直线 若是部分在窗口内的情况,则设法减少直线的求 交次数和每次的求交计算量
8
第4讲 图形裁剪算法
直线裁剪算法
Cohen-Sutherland裁剪算法 中点分割算法 梁友栋-Barsky裁剪算法
9
第4讲 图形裁剪算法
Cohen-Sutherland裁剪算法(编码裁剪法)
基本思想:对于每条待裁剪的线段P1P2分三种情 况处理
若P1P2完全在窗口内,则显示该线段 若P1P2完全在窗口外,则丢弃该线段 若线段不满足上述条件,则求线段与窗口边界的交点, 在交点处把线段分为两段,其中一段完全在窗口外, 可舍弃之,然后对另一段重复上述处理
P1
P1
P1
A
Pm
A Pm A B B P2
B Pm
18
P2
P2
第4讲 图形裁剪算法
算法特点
对分辨率为2N×2N的显示器,上述二分过程至多 进行N次 主要过程只用到加法和除法运算,适合硬件实现, 它可以用左右移位来代替乘除法,这样就大大加 快了速度
19
第4讲 图形裁剪算法
梁友栋-Barsky裁剪算法
13
第4讲 图形裁剪算法
三维sutherland-hodgman算法
三维sutherland-hodgman算法Sutherland-Hodgman 算法是一种裁剪多边形的算法,用于从一个多边形中裁剪出另一个多边形。
三维Sutherland-Hodgman 算法在二维的基础上进行了扩展,适用于三维空间。
以下是三维Sutherland-Hodgman 算法的基本步骤:1. 定义裁剪平面:确定一个裁剪平面,该平面可以是XYZ 轴的任意组合。
例如,裁剪平面可以是XY 平面、XZ 平面或YZ 平面。
2. 对每个多边形顶点进行处理:-对于每个多边形顶点,检查其位置相对于裁剪平面的情况(在平面的哪一侧)。
3. 裁剪:-根据顶点在平面的位置,采取相应的裁剪操作。
-如果顶点在平面的一侧,将其添加到输出多边形中。
-如果顶点在平面的两侧,进行插值计算,找到交点并添加到输出多边形中。
4. 完成裁剪:-处理完所有顶点后,输出多边形即为裁剪后的结果。
以下是一个简化的Java 伪代码示例,假设裁剪平面是XY 平面:```java// 三维Sutherland-Hodgman 算法List<Vertex> clip3D(List<Vertex> inputPolygon) {List<Vertex> outputPolygon = new ArrayList<>();// 裁剪平面方程:z = 0for (int i = 0; i < inputPolygon.size(); i++) {Vertex currentVertex = inputPolygon.get(i);Vertex nextVertex = inputPolygon.get((i + 1) % inputPolygon.size());// 如果当前顶点在平面的一侧,添加到输出多边形if (currentVertex.z >= 0) {outputPolygon.add(currentVertex);}// 如果边与平面相交,计算交点并添加到输出多边形if ((currentVertex.z >= 0 && nextVertex.z < 0) || (currentVertex.z < 0 && nextVertex.z >= 0)) {double t = currentVertex.z / (currentVertex.z - nextVertex.z);double x = currentVertex.x + t * (nextVertex.x - currentVertex.x);double y = currentVertex.y + t * (nextVertex.y - currentVertex.y);outputPolygon.add(new Vertex(x, y, 0));}}return outputPolygon;}```这个示例中,裁剪平面被设定为XY 平面(z = 0)。
计算机图形学裁剪算法
一、实验目标1.了解Cohen-SutherLand线段裁剪算法、Liang-Barsky线段裁剪算法、SutherLand-Hodgeman多边形裁剪算法的基本思想;2.掌握Cohen-SutherLand线段裁剪算法、Liang-Barsky线段裁剪算法、SutherLand-Hodgeman多边形裁剪算法的算法实现;二、实验内容本次实验主要是实现Cohen-SutherLand线段裁剪算法、Liang-Barsky线段裁剪算法、SutherLand-Hodgeman多边形裁剪算法。
Cohen-sutherland线段裁剪算法思想:该算法也称为编码算法,首先对线段的两个端点按所在的区域进行分区编码,根据编码可以迅速地判明全部在窗口内的线段和全部在某边界外侧的线段。
只有不属于这两种情况的线段,才需要求出线段与窗口边界的交点,求出交点后,舍去窗外部分。
对剩余部分,把它作为新的线段看待,又从头开始考虑。
两遍循环之后,就能确定该线段是部分截留下来,还是全部舍弃。
Cohen-sutherland线段裁剪算法步骤:1、分区编码延长裁剪边框将二维平面分成九个区域,每个区域各用一个四位二进制代码标识。
各区代码值如图中所示。
四位二进制代码的编码规则是:(1)第一位置1:区域在左边界外侧(2)第二位置1:区域在右边界外侧(3)第三位置1:区域在下边界外侧(4)第四位置1:区域在上边界外侧裁剪窗口内(包括边界上)的区域,四位二进制代码均为0。
设线段的两个端点为P1(x1,y1)和P2(x2,y2),根据上述规则,可以求出P1和P2所在区域的分区代码C1和C2。
2、判别根据C1和C2的具体值,可以有三种情况:(1)C1=C2=0,表明两端点全在窗口内,因而整个线段也在窗内,应予保留。
(2)C1&C2≠0(两端点代码按位作逻辑乘不为0),即C1和C2至少有某一位同时为1,表明两端点必定处于某一边界的同一外侧,因而整个线段全在窗外,应予舍弃。
多边形裁剪——精选推荐
多边形裁剪错觉:直线段裁剪的组合?新的问题:边界不再封闭,需要⽤窗⼝边界的恰当部分来封闭它,如何确定其边界?⼀个凹多边形可能被裁剪成⼏个⼩的多边形,如何确定这些⼩多边形的边界?Sutherland-Hodgman算法Sutherland-Hodgman算法也叫逐边裁剪法,该算法是萨瑟兰德(I.E.Sutherland)和霍德曼(Hodgman)在1974年提出的。
这种算法采⽤了分割处理、逐边裁剪的⽅法。
1、算法介绍1. 分割处理策略:该算法的基本思想是将多边形边界作为⼀个整体,每次⽤窗⼝的⼀条边对要裁剪的多边形和中间结果多边形进⾏裁剪,体现⼀种分⽽治之的思想。
2. 流⽔线过程(左上右下):前边的结果是后边的输⼊2、算法思想基本思想是⼀次⽤窗⼝的⼀条边裁剪多边形。
考虑窗⼝的⼀条边以及延长线构成的裁剪线该线把平⾯分成两个部分:可见⼀侧和不可见⼀侧多边形的各条边的两端点S、P。
它们与裁剪线的位置关系只有四种情况(1):起点终点都在可见⼀侧,仅输出顶点P;如果都输出,会出现多边形的点重复情况(2):起点终点都不在可见⼀侧,输出0个顶点;情况(3):起点在可见⼀侧,终点在不可见⼀侧,输出线段SP与裁剪线的交点I;情况(4):起点在不可见⼀侧,终点在可见⼀侧,输出线段SP与裁剪线的交点I和终点P 3、算法框图上述算法仅⽤⼀条裁剪边对多边形进⾏裁剪,得到⼀个顶点序列,作为下⼀条裁剪边处理过程的输⼊。
对于每⼀条裁剪边,算法框图同上,只是判断点在窗⼝哪⼀侧以及求线段SP与裁剪边的交点算法应随之改变。
4、⼩结对凸多边形应⽤本算法可以得到正确的结果,但是对凹多边形的裁剪将如图所⽰显⽰出⼀条多余的直线。
这种情况在裁剪后的多边形有两个或者多个分离部分的时候出现。
因为只有⼀个输出顶点表,所以表中最后⼀个顶点总是连着第⼀个顶点。
解决这个问题有多种⽅法,⼀是把凹多边形分割成若⼲个凸多边形,然后分别处理各个凸多边形。
⼆是修改本算法,沿着任何⼀个裁剪窗⼝边检查顶点表,正确的连接顶点对。
多边形裁剪——精选推荐
多边形裁剪⼀、多边形的裁剪如果按线段的⽅法裁剪,得到的是⼀系列线段。
⽽实际上,应该得到的是下图所⽰的有边界的区域:多边形裁剪算法的输出应该是裁剪后的多边形边界的顶点序列!需要构造能产⽣⼀个或多个封闭区域的多边形裁剪算法⼆、Sutherland-Hodgeman多边形裁剪该算法的基本思想是将多边形边界作为⼀个整体,每次⽤窗⼝的⼀条边对要裁剪的多边形和中间结果多边形进⾏裁剪,体现⼀种分⽽治之的思想把平⾯分为两个区域:包含有窗⼝区域的⼀个域称为可见侧;不包含窗⼝区域的域为不可见侧裁剪得到的结果多边形的顶点有两部分组成:(1)落在可见⼀侧的原多边形顶点(2)多边形的边与裁剪窗⼝边界的交点根据多边形每⼀边与窗⼝边所形成的位置关系,沿着多边形依次处理顶点会遇到四种情况:(1)第⼀点S在不可见侧⾯,⽽第⼆点P在可见侧交点I与点 P均被加⼊到输出顶点表中。
(2)是S和P都在可见侧则P被加⼊到输出顶点表中(3)S在可见侧,⽽P在不可见侧则交点I被加⼊到输出顶点表中(4)如果S和P都在不可见侧输出顶点表中不增加任何顶点在窗⼝的⼀条裁剪边界处理完所有顶点后,其输出顶点表将⽤窗⼝的下⼀条边界继续裁剪while对于每⼀个窗⼝边或⾯ do begin if P1 在窗⼝边的可见⼀侧 then 输出P1 for i=1 to n do begin if P1 在窗⼝边的可见⼀侧 then if P1+1 在窗⼝边的可见⼀侧 then 输出 P1+1 else 计算交点并输出交点 else if Pi+1 在窗⼝可见⼀侧,then 计算交点 并输出交点,同时输出Pi+1 end endendSutherland-Hodgeman算法不⾜之处利⽤Sutherland-Hodgeman裁剪算法对凸多边形进⾏裁剪可以获得正确的裁剪结果,但是凹多边形不⾏。
计算机图形学Sutherland-Hodgman裁剪算法扩展三维裁剪
else
return true;
}
wcPt3D Intersect(wcPt3D p1,wcPt3D p2,Boundary b,wcPt3D wMin,wcPt3D wMax)
{
wcPt3D iPt;
float m1,m2,m3,m4,m5,m6;
if(p1.x !=p2.x)
{
Outcnt=edgeCliper(Boundary(b),wMin,wMax,pIn,cnt,pOut);
for(i=0;i<Outcnt;i++)
pIn[i]=pOut[i];
pIn[Outcnt]=pOut[0];
cnt=Outcnt;
}
glColor3f(1.0,0.0,0.0);
glBegin(GL_LINE_LOOP);
case Right:
iPt.x=wMax.x;
iPt.y=p1.y+(p2.y-p1.y)*m2;
iPt.z=p1.z+(p2.z-p1.z)*m2;
break;
case Bottom:
iPt.y=wMin.y;
iPt.x=p1.x+(p2.x-p1.x)*m3;
iPt.z=p1.z+(p2.z-p1.z)*m3;
{
wcPt3D s;
int i,Outcnt=0;
s=pIn[0];
for(i=1;i<=cnt;i++)
{
if(!Inside(s,b,wMin,wMax)&&Inside(pIn[i],b,wMin,wMax))
{
pOut[Outcnt]=Intersect(s,pIn[i],b,wMin,wMax);
VisualSudio下实现Sutherland-Hodgeman多边形裁剪算法
VisualSudio下实现Sutherland-Hodgeman多边形裁剪算法 学习计算机图形学的同学们肯定要写MFC程序,以及题⽬的S-H算法,不过这个代码的原理⽹络上很多博主都有对此讲解,这⾥就不说了,没搞懂原理的朋友们还是先把原理了解⼀下再来看下⾯的代码可能会更合适⼀点,写这个算法前,笔者也在⽹上查过,不过⽹上的代码让⼈看着真的毫⽆头绪(也许是笔者⽔平太低了,没看懂。
),所以看懂了原理后,决定还是⾃⼰写来的靠谱点,鉴于笔者编程⽔平有限,算法代码写的有点涝,代码的冗余度和执⾏效率都⽐不上编程⼤⽜写的那么好,如果介意代码的⽔平的朋友,额。
就不要往下看了,就此做罢吧,免得看到最后,⾃⼰也看得难受——这代码怎么写的那么烂。
如果不介意笔者代码之涝,那么就开始S-H算法的实现吧! ⾸先先来做下绘制多边形的⼯作,先画⼀个多边形,我这⾥绘制多边形是通过橡⽪绳的⽅法实现的,所以在类视图⾥要添加OnMouseMove和OnLButtonDown两个消息函数。
接下来在头⽂件加⼊以下内容CPoint start_point;//起始点CPoint end_point;//终⽌点CPoint first;//第⼀个点CPoint Point[100];int if_Press = 0;int Number = 0; //多边形的点数起始点和终⽌点表⽰画⼀条线的头和尾,创建first点的⽬的是,当画到最后⼀个点的时候,这个点是和最开始的第⼀个点连起来的,所以要事先把第⼀个点先存起来,不然之后调⽤strat_point和end_point是就没法把第⼀个点给记下来CPoint Point[100]建⽴⼀个点的数组,也就是把画多边形时点击过的点的坐标位置存起来。
把这段代码加到OnLButtonDown消息函数⾥⾯if (if_Press == 1 || Number == 0){if_Press = 1; //说明已经点过了⼀个点start_point = point;end_point = start_point;Point[Number] = start_point;//把这个点存⼊数组⾥if (Number == 0) //表⽰第⼀次左击的点为第⼀个点,first = start_point;//把第⼀个点保存下来Number++;//多边形的点数加⼀}这段代码加到onMouseMove消息函数⾥⾯CDC* pDC = this->GetWindowDC();if (if_Press){pDC->SetROP2(R2_NOT); //添加橡⽪绳(只要没左击,⿏标在桌⾯上移动,线条就会跟到哪去)pDC->MoveTo(start_point); //将点坐标移到上⼀个点击的点的位置pDC->LineTo(end_point); //没有画出线,此时的start_point = end_pointif ((point.x - first.x) < 0.1 && (point.y - first.y) < 0.1)//当⿏标指着的点离第⼀个点的距离⼩于⼀个值的时候,两点重合(这⾥两个点会⾃动重合,不⽤再次点击左键){point = first;if_Press = 0;}pDC->MoveTo(start_point); //画出直线pDC->LineTo(point);end_point = point;}CView::OnMouseMove(nFlags, point); 之后就只⽤在菜单页⾯添加⼀个事件处理函数,能调⽤OnLButtonDown⾥⾯的函数,这样就可以和onMouseMove⼀起作⽤画出⼀个多边形 做完准备⼯作,就可以开始写程序的核⼼——Sutherland-Hodgeman算法 ⾸先还是现在头⽂件⾥添加⼀下必要的结构体CPoint New_Point[100]; 这个数组和之前那个Point数组类型相同,之所以要重新建⽴⼀个数组,是为了S-H算法在边处理之后,点发⽣了改变,能有⼀个数组来存储这些新的点 接下来是画出⼀个矩形框,矩形框的作⽤是为了裁剪准备的,这⾥我直接把这个矩形框写死,在OnDraw函数添加这些代码,这样运⾏程序就能看到⼀个绿⾊的矩形框⼀直绘制在窗⼝上void CCGTestView::OnDraw(CDC* pDC){CCGTestDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;// TODO: 在此处为本机数据添加绘制代码CPen newpen(PS_SOLID, 3, RGB(0, 255, 0));CPen *old = pDC->SelectObject(&newpen);pDC->MoveTo(100, 100);pDC->LineTo(100, 200);pDC->MoveTo(100, 200);pDC->LineTo(300, 200);pDC->MoveTo(300, 200);pDC->LineTo(300, 100);pDC->MoveTo(300, 100);pDC->LineTo(100, 100);pDC->SelectObject(old);//ReleaseDC(pDC);}接下来的这段代码可以写在头⽂件⾥也可以写在S-H算法的前⾯,这⾥只是定义了矩形框的上下左右的坐标值int XL = 100, XR = 300, YB = 100, YT = 200;//分别是左边的x值,右边的x值,下边的y值,上边的y值 然后在菜单加⼀个事件处理程序添加S-H函数void CCGTestView::OnSutherHodegeman(){// TODO: 在此添加命令处理程序代码int temp_num; //这个临时的变量存储的就是多边形的点个数,也就是前⾯画多边形时的Numberint new_num = 0; //这个变量是⽤来存储通过算法裁剪后的点的个数CPoint temp_point; //定义⼀个临时点,在后⾯是⽤来求交点⽤的int i;int j;temp_num = Number; //先说明下,画线的时候是从起始点到终⽌点,在后⾯的解释中我会把起始点说成头点,终⽌点说成尾点,也就是从头到尾,还有⼀点,如果这个点在可视区外,在后⾯就直接简称为外了///////////////对矩形框上边处理for (i = 0; i < temp_num; i++)//temp_num 为多边形的边数,执⾏次数也就是边数{if (Point[i%temp_num].y > YT) //如果头点在上边之上,即头点在不可视区{ //这样要注意下Point数组选取元素是加的%号的含义,因为头号是i,尾号是i+1,可是到了最后⼀个点的时候,头号还是i,可是尾却不是i+1了,此时的头要和最初的第⼀个点相连,才能形成⼀个闭合的多边形,所以整除(点的个数),刚好 //本来%只是最后⼀个点才⽤得着,这⾥为了不乱掉,索性全加上,反正对前⾯的点也没什么影响。
sutherland算法表示方法
sutherland算法表示方法Sutherland算法:计算机图形学的里程碑引言计算机图形学是一门研究如何使用计算机生成和处理图像的学科。
在图形学的发展历史中,Sutherland算法是一个具有重要意义的里程碑。
本文将介绍Sutherland算法的基本原理、应用领域以及对计算机图形学的影响。
一、Sutherland算法的基本原理Sutherland算法,全称为Sutherland-Hodgman算法,是一种用于计算多边形裁剪的算法。
其基本原理是通过对多边形进行逐边裁剪,最终得到裁剪后的多边形。
这个过程可以简单地分为四个步骤:边界框检测、边界相交检测、多边形顶点分类以及多边形边界点的计算。
边界框检测是指通过与裁剪窗口的边界进行比较,确定多边形是否在裁剪窗口内部。
如果多边形完全位于裁剪窗口之外,则可以直接舍弃。
如果多边形与裁剪窗口有交集,则继续进行下一步操作。
接下来,边界相交检测是指确定多边形与裁剪窗口的边是否相交。
如果多边形的边与裁剪窗口的边没有相交,则舍弃该边。
如果有相交,则进行下一步操作。
然后,多边形顶点分类是指根据多边形的顶点与裁剪窗口的边界相对位置,将多边形的顶点分为内部点、外部点和交点。
内部点是指位于裁剪窗口内部的点,外部点是指位于裁剪窗口外部的点,交点是指位于裁剪窗口边界上的点。
根据多边形顶点的分类结果,计算出多边形的边界点。
这些边界点将组成裁剪后的多边形。
二、Sutherland算法的应用领域Sutherland算法在计算机图形学中有广泛的应用。
它可以用于多边形的裁剪,将多边形限制在指定的区域内,从而实现对图像的剪裁和切割。
这在计算机辅助设计(CAD)和计算机游戏中非常有用。
在CAD中,Sutherland算法可以用于对设计图形进行裁剪。
例如,在建筑设计中,可以使用Sutherland算法将建筑物的平面图限制在指定的区域内,以便更好地展示和分析。
在计算机游戏中,Sutherland算法可以用于实现视景裁剪。
sutherland-hodgman裁剪算法
Sutherland-Hodgman裁剪算法是一种用于裁剪凸多边形的算法。
该算法的基本思想是在多边形的每一条边上进行裁剪,逐步得到裁剪后的多边形。
以下是详细的Sutherland-Hodgman裁剪算法的步骤:
步骤:
1.确定裁剪窗口:定义一个裁剪窗口(clipping window),它是一个矩形,
用来指定裁剪区域。
2.初始化:对于输入多边形的每一条边,按顺序执行以下步骤:
–记录当前边的起点和终点。
–将裁剪窗口的一个边作为“裁剪边”。
–初始化一个空的输出多边形。
3.迭代裁剪:遍历每一条输入多边形的边,依次进行以下操作:
–对于当前边,判断其与裁剪边的相对位置关系(在窗口内、窗口外或跨越窗口边界)。
–根据相对位置关系,更新输出多边形:
•如果边完全在窗口内,则将边的终点添加到输出多边形中。
•如果边跨越窗口边界,则计算边与裁剪边的交点,并将交点添
加到输出多边形中。
•如果边完全在窗口外,则不添加任何点。
4.更新裁剪边:对于每一轮迭代,更新裁剪边为下一条窗口的边。
依次遍历
裁剪窗口的四个边。
5.重复直到完成:重复步骤3和步骤4,直到遍历完所有输入多边形的边。
6.输出结果:输出多边形即为裁剪后的结果。
示例代码:
以下是一个简单的示例代码,用C语言实现Sutherland-Hodgman裁剪算法:
请注意,这只是一个简单的示例,实际应用中可能需要更多的边界条件和错误处理。
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多边形裁剪算法可以用于各种需要裁剪二维多边形的场景,如计算机图形学中的视口裁剪、图像处理中的形状裁剪等。
图形学中的多边形裁剪与扫描线算法
图形学中的多边形裁剪与扫描线算法一、多边形裁剪与扫描线算法多边形裁剪和扫描算法是计算机图形学中常用的技术,用于处理在屏幕上显示的多边形的裁剪和填充。
裁剪是指将多边形中超出指定区域的部分去除,而扫描算法则是用来填充多边形的内部区域。
这两种算法通常结合使用,以实现对图形的精确裁剪和填充。
二、裁剪算法1. Cohen-Sutherland算法Cohen-Sutherland算法是一种常用的线段裁剪算法,它将平面分成九个部分,并用四位编码来表示线段的位置关系。
当线段与裁剪区域相交时,根据编码判断线段的起点和终点位置,然后将线段裁剪到裁剪区域内。
这样就可以快速有效地进行线段裁剪。
2. Sutherland-Hodgman算法Sutherland-Hodgman算法是用来对多边形进行裁剪的算法,它通过对多边形的每条边进行裁剪,最终得到裁剪后的多边形。
该算法的优势在于可以处理凸多边形和凹多边形,并且可以处理不规则的裁剪区域。
三、扫描线填充算法1.扫描线填充算法的原理扫描线填充算法是一种经典的多边形填充算法,其基本原理是从上到下逐行扫描屏幕,并根据扫描线与多边形边界的交点来确定每个像素点的颜色。
通过这种方法,可以有效地填充多边形的内部区域,并且可以处理复杂的多边形。
2.扫描线算法的实现步骤扫描线填充算法的实现步骤包括扫描线的生成、边界与扫描线的交点计算、交点排序、填充颜色等过程。
在每一行扫描时,通过计算扫描线与多边形的交点,然后对这些交点进行排序,最后通过填充算法来填充多边形的内部。
四、多边形裁剪与扫描算法的应用多边形裁剪与扫描算法在计算机图形学中有着广泛的应用。
例如,在计算机辅助设计(CAD)领域,这些算法被用于对图形进行裁剪和填充,以实现图形的精确显示和编辑。
另外,在计算机游戏开发中,多边形裁剪与扫描算法也被用于实现场景的渲染和光照效果。
五、总结多边形裁剪与扫描算法是计算机图形学中重要的技朧,通过裁剪算法可以实现对图形的剪切和编辑,而扫描算法则可以实现对图形的填充和显示。
多边形切分算法
多边形切分算法是一种处理多边形的方法,它可以将一个多边形切割成若干个更小的多边形。
这个过程可以通过多种算法实现,其中最常用的是Sutherland-Hodgman算法。
Sutherland-Hodgman算法的基本思想是,首先将多边形的每条边在两个方向上无限延伸,将整个空间一分为二。
其中,空间中有一侧是我们要保留的可见侧,还有一侧是我们不需要的。
如果待处理多边形的顶点位于多边形边上线的可见侧,则保留这些顶点,生成新的多边形。
对多边形的每条边重复这个过程,最终生成的顶点列表将定义一个完全可见的多边形。
在切分过程中,如果遇到新的交点,根据线段的状态来判断。
如果线段之前是处于多边形内部,那么当前交点个前一个交点的连线将原多边形分割得到了新的多边形,并且接下来线段的状态会发生变化,线段开始处于多边形外部。
如果线段之前处于多边形外部,那么从当前交点开始,线段开始处于多边形内部,当前交点和下一个交点将会分割元多边形,产生新的多边形。
以上是关于多边形切分算法的介绍,希望对你有所帮助。
图形学实验四_Sutherland-Hodgman多边形裁剪算法实验报告
《计算机图形学》实验报告《裁剪算法实验》姓名闫学森学号3013216087专业计算机班级3班天津大学计算机科学与技术学院2015年12 月1日一、实验目的实现Sutherland-Hodgman多边形裁剪算法二、实验内容自定义裁剪窗口和待裁剪直线段(或多边形),采用不同颜色突出显示裁剪结果三、实验结果四、实验分析和总结Sutherland-Hodgman多边形裁剪算法是将原多边形进行左右下上四次裁剪。
其中进行两次分解? 第一次分解:将多边形关于矩形窗口的裁剪分解为它关于窗口四条边所在直线的裁剪;? 第二次分解:将多边形关于一条直线的裁剪分解为多边形各边关于该直线的裁剪。
四次裁剪相似,只要修改部分变量即可。
但是第一次修改时没有完全改掉,出来的图像不正确。
通过这次试验使我了解到如何运用计算机程序对窗口进行剪裁,了解到编码剪裁算法直观方便,速度较快,中点分割剪裁算法不用进行乘除运算,剪裁效率高, Sutherland-Hodgman 直线裁剪算法更快。
五、源代码// PolygonClipDemo.cpp : Defines the class behaviors for the application.//#include "stdafx.h"#include "PolygonClipDemo.h"#include "MainFrm.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// CPolygonClipDemoAppBEGIN_MESSAGE_MAP(CPolygonClipDemoApp, CWinApp)ON_COMMAND(ID_APP_ABOUT, OnAppAbout)END_MESSAGE_MAP()// CPolygonClipDemoApp constructionCPolygonClipDemoApp::CPolygonClipDemoApp(){// TODO: add construction code here,// Place all significant initialization in InitInstance}// The one and only CPolygonClipDemoApp objectCPolygonClipDemoApp theApp;// CPolygonClipDemoApp initializationBOOL CPolygonClipDemoApp::InitInstance(){// InitCommonControls() is required on Windows XP if an application// manifest specifies use of ComCtl32.dll version 6 or later to enable// visual styles. Otherwise, any window creation will fail.InitCommonControls();CWinApp::InitInstance();// Standard initialization// If you are not using these features and wish to reduce the size// of your final executable, you should remove from the following// the specific initialization routines you do not need// Change the registry key under which our settings are stored// TODO: You should modify this string to be something appropriate// such as the name of your company or organizationSetRegistryKey(_T("Local AppWizard-Generated Applications"));// To create the main window, this code creates a new frame window// object and then sets it as the application's main window objectCMainFrame* pFrame = new CMainFrame;m_pMainWnd = pFrame;// create and load the frame with its resourcespFrame->LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,NULL);// The one and only window has been initialized, so show and update itpFrame->ShowWindow(SW_SHOW);pFrame->UpdateWindow();// call DragAcceptFiles only if there's a suffix// In an SDI app, this should occur after ProcessShellCommandreturn TRUE;}// CPolygonClipDemoApp message handlers// CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Dataenum { IDD = IDD_ABOUTBOX };protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support// Implementationprotected:DECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) {}void CAboutDlg::DoDataExchange(CDataExchange* pDX) {CDialog::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)END_MESSAGE_MAP()// App command to run the dialogvoid CPolygonClipDemoApp::OnAppAbout(){CAboutDlg aboutDlg;aboutDlg.DoModal();}// CPolygonClipDemoApp message handlers。
计算机图形学-实验五 直线和多边形的裁剪
大学实验报告学院:计算机科学与信息学院专业:软件工程班级: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 x = XL;y = y1 + (y2 - y1) * (XL - x1) / (x2 - x1);// 求直线与矩形窗口的左边界的交点} else if ((RIGHT & code) != 0) {// 直线的端点与矩形窗口的右边编码相与!=0x = XR;y = y1 + (y2 - y1) * (XR - x1) / (x2 - x1);// 求直线与矩形窗口的右边界的交点} else if ((BOTTOM & code) != 0) {// 直线的端点与矩形窗口的下边编码相与!=0y = YB;x = x1 + (x2 - x1) * (YB - y1) / (y2 - y1);// 求直线与矩形窗口的下边界的交点} else if ((TOP & code) != 0) {// 直线的端点与矩形窗口的上边编码相与!=0y = YT;x = x1 + (x2 - x1) * (YT - y1) / (y2 - y1);// 直线的端点与矩形窗口的上// 边编码相与!=0}if (code == code1) {x1 = x;y1 = y;code1 = encode(x, y);} else {x2 = x;y2 = y;code2 = encode(x, y);}}g.drawLine((int) (x1 + 0.5), (int) (y1 + 0.5), (int) (x2 + 0.5),(int) (y2 + 0.5));}二、多边形裁剪的核心代码为:通过点集画直线或者多边形:private void draw() {//通过点集画直线或者多边形for (int i = 1; i < points.size(); i++) {Point p1 = new Point();p1 = points.get(i);int x1 = (int) p1.getX();int y1 = (int) p1.getY();Point p2 = new Point();p2 = points.get(i - 1);int x2 = (int) p2.getX();int y2 = (int) p2.getY();g.drawLine(x1, y1, x2, 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;}} else if (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;}判断点是否在裁剪边的可见侧:private boolean inside(Point point, Point[] edge) {//判断点是否在裁剪边的可见侧// 裁剪边为窗口下边if ((edge[0].y == edge[1].y) && (edge[0].x < edge[1].x)) {if (point.y >= edge[0].y) {return true;}}// 裁剪边为窗口上边if ((edge[0].y == edge[1].y) && (edge[0].x > edge[1].x)) {if (point.y <= edge[0].y) {return true;}}// 裁剪边为窗口右边if ((edge[0].x == edge[1].x) && (edge[0].y < edge[1].y)) {if (point.x <= edge[0].x) {return true;}}// 裁剪边为窗口左边if ((edge[0].x == edge[1].x) && (edge[0].y > edge[1].y)) {if (point.x >= edge[0].x) {return true;}}return false;}直线段与窗口边界求交: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.x = s.x + (edge[0].y - s.y) * (p.x - s.x) / (p.y - s.y);} else if (edge[0].x == edge[1].x) {// 垂直裁剪边t.x = edge[0].x;t.y = s.y + (edge[0].x - s.x) * (p.y - s.y) / (p.x - s.x);}return t;}鼠标的监听类(部类):class MouseMonitor extends MouseAdapter {//通过鼠标的单击获取点,并画出直线或者多边形public void mouseClicked(MouseEvent e) {points.add(e.getPoint());if (points.size() > 1) {draw();}}}键盘的监听类(部类):class KeyMonitor extends KeyAdapter {// 键盘控制public void 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(XL, YB, XR - XL, YT - YB);//存放裁剪窗口的边top = new Point[2];// 存放裁剪窗口的上边top[0] = new Point(XL, YB);top[1] = new Point(XR, YB);right = new Point[2];//存放裁剪窗口的右边right[0] = new Point(XR, YB);right[1] = new Point(XR, YT);bottom = new Point[2];//存放裁剪窗口的下边bottom[0] = new Point(XR, YT);bottom[1] = new Point(XL, YT);left = new Point[2];//存放裁剪窗口的左边left[0] = new Point(XL, YT);left[1] = new Point(XL, YB);break;case KeyEvent.VK_A://对直线段进行裁剪g.setColor(Color.GREEN);Point p1 = points.get(0);Point p2 = points.get(1);lineCut(p1.getX(), p1.getY(), p2.getX(), 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);//得到多边形与裁剪窗口左边的交点第二种情况:线段在裁剪窗口的部,线段完全可见。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
多边形裁剪的Sutherland—Hodgman算法1>. Sutherland—Hodgman多边形裁剪算法思想该算法的基本思想是每次用窗口的一条边界及其延长线来裁剪多边形的各边。
多边形通常由它的顶点序列来表示,经过裁剪规则针对某条边界裁剪后,结果形成新的顶点序列,又留待下条边界进行裁剪,…,直到窗口的所有边界都裁剪完毕,算法形成最后的顶点序列,才是结果多边形(它可能构成一个或多个多边形)。
当多边形一个顶点Pi相对于窗口某条边界及其延长线进行剪裁时,不外乎下列四种情况(即裁剪规则):1、顶点Pi在内侧,前一顶点Pi-1也在内侧,则将Pi纳入新的顶点序列;2、顶点Pi在内侧,前一顶点Pi-1在外侧,则先求交点Q,再将Q、Pi依次纳入新的顶点序列;3、顶点Pi在外侧,前一顶点Pi-1在内侧,则先求交点Q,再将Q纳入新的顶点序列;4、顶点Pi与前一顶点Pi-1均在外侧,则顶点序列中不增加新的顶点。
2>. Sutherland—Hodgman多边形裁剪算法步骤考虑多边形相对于一条边界及其延长线进行裁剪的算法:1.从主函数得到待裁剪多边形的顶点序列P[][2]、顶点序列数n、窗口一条边界参数xl(假如为矩形窗口的左边界);2.赋初值:将顶点序列中的最后一个顶点赋给前一顶点S;设置初始标志flag:if(S在边界内侧)flag=0;else flag=1;设新的顶点序列数j=0;3.对多边形各顶点进行裁剪规则处理,结果放入新的多边形顶点序列Q[][2]中:for(对第一个顶点直到最后一个顶点,逐一处理){if(Pi在边界内侧){if(flag!=0){flag=0;求交点并放入新的多边形顶点序列Qj中;j++;}将当前顶点放入新的多边形顶点序列Qj中:Qj=Pi;j++;}else{if(flag==0){flag=1;求交点并放入新的多边形顶点序列Qj中;j++;}}将当前顶点赋给S:S=Pi;}4.做返回准备:将新的多边形顶点序列Q又逐一放回原多边形顶点序列P中:P=Q;将新的多边形顶点数j放回原多边形顶点数n中:n=j;///////////////////////////////////////////////////////////////////// ///////////////////-----多边形裁剪的Sutherland—Hodgman算法---------/////////////////////////////////////////////////////////////////////// ////////////////void CMyClip_AView::ClipedgeL(CPoint polypoint[], CPoint clipwindow[], UINT polynum)/*其中参数polypoint[]为多边形顶点,clipwindow[]为裁剪窗口顶点,polynum 为多边形顶点数目*/{//找出裁剪窗口边界long xl,xr,yt,yb;UINT i;xl=clipwindow[0].x;xr=clipwindow[0].x;yt=clipwindow[0].y;yb=clipwindow[0].y;for(i=1;i<=4;i++){if(xl>clipwindow[i].x)xl=clipwindow[i].x;if(xr<clipwindow[i].x)xr=clipwindow[i].x;if(yb>clipwindow[i].y)yb=clipwindow[i].y;if(yt<clipwindow[i].y)yt=clipwindow[i].y;}//CPoint B[Polygon_Num],C[Polygon_Num];UINT m_nA,m_nB;int x,y;long tem1,tem2;m_nA=polynum;/*记载原始多边形顶点顶点个数*/m_nB=0;/*记载新生成多边形顶点顶点个数*/for(i=0;i<m_nA;i++){if(polypoint[i].x<xl && polypoint[i+1].x<xl) /*判断的多边形边两个端点都在外部,不做处理*/{continue;/*如果是这种情况,那么就对继续对下一条多边形边作判断,也就是说下面的判断不用做了*/}if(polypoint[i].x>=xl && polypoint[i+1].x>=xl) /*边两个端点都在内部,保留*//*因为每个保留的点在数组中只出现一次,且下一次判断时第二个端点一定会要取到,因此只保留的两个点中的第一个*/{B[m_nB].x =polypoint[i].x ;B[m_nB].y =polypoint[i].y ;m_nB=m_nB+1;continue;}if(polypoint[i].x<xl && polypoint[i+1].x>=xl)/*边两个端点起点在外部,终点在内部,求交点,然后交点,终点都应该送入临时数组*/{/*保留交点*/x=xl;tem1=(xl-polypoint[i].x);//tem2=(xl-x1)*dy/dx+y1;//y/x=dy/dx---->y=x*dy/dxtem2=tem1*(polypoint[i+1].y-polypoint[i].y)/(polypoint[i+1].x-polypoint[i].x)+polypoi nt[i].y;y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB=m_nB+1;continue;}if(polypoint[i].x>=xl && polypoint[i+1].x<xl)/*起点在内部,终点在外,求交点,然后起点,交点送入临时数组*/{ /*保留内部点*/B[m_nB].x =polypoint[i].x ;B[m_nB].y =polypoint[i].y ;m_nB=m_nB+1;/*保留交点*/tem1=(xl-polypoint[i].x);tem2=tem1*(polypoint[i+1].y-polypoint[i].y)/(polypoint[i+1].x-polypoint[i].x)+polypoi nt[i].y;y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB=m_nB+1;continue;}}//把第一个点的数据拷贝到最后//形成裁剪后的多边形if(i==m_nA){B[m_nB]=B[0];}//下------------------m_nA=0;for(i=0;i<m_nB;i++){if(B[i].y<yb && B[i+1].y<yb)//两个点全在下方{continue;//下一条边}if(B[i].y>=yb && B[i+1].y>=yb)//p1,p2都在yb上方{C[m_nA].x =B[i].x;C[m_nA].y =B[i].y;m_nA++;continue;}if(B[i].y<yb && B[i+1].y>=yb)//p1在下,P2在上,留交点,外->内{y=yb;tem1=yb-B[i].y;//tem2=x1+(yb-y1)*dx/dytem2=tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y) + B[i].x;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}if(B[i].y>=yb && B[i+1].y<yb)//p1在上方,P2在下方,留P1和交点,内-外{//save p1C[m_nA].x=B[i].x;C[m_nA].y=B[i].y;m_nA++;//留交点y=yb;tem1=yb-B[i].y;//tem2=x1+(yb-y1)*dx/dytem2=tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y)+B[i].x;x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}}//形成第二次裁剪多边形if(i==m_nB){C[m_nA]=C[0];}//右------------------m_nB=0;for(i=0;i<m_nA;i++){if(C[i].x>xr && C[i+1].x>xr)//P1,P2都在右方--go next{continue;}if(C[i].x<=xr && C[i+1].x<=xr)//P1,P2都在左方,留P1{B[m_nB].x =C[i].x;B[m_nB].y =C[i].y;m_nB++;continue;}if(C[i].x>xr && C[i+1].x<=xr)//P1在右方,P2在左方,留交点{x=xr;tem1=C[i].x-xr;tem2=C[i].y-tem1*(C[i+1].y-C[i].y)/(C[i+1].x-C[i].x);y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB++;continue;}if(C[i].x<=xr && C[i+1].x>xr)//P1在内,P2在外,留P1和交点{//save p1B[m_nB].x =C[i].x;B[m_nB].y =C[i].y;m_nB++;//save 交点x=xr;tem1=C[i].x-xr;tem2=C[i].y-tem1*(C[i+1].y-C[i].y)/(C[i+1].x-C[i].x);y=tem2;B[m_nB].x =x;B[m_nB].y =y;m_nB++;continue;}}//三次裁剪后的新多边形if(i==m_nA){B[m_nB]=B[0];}//上-------------------m_nA=0;for(i=0;i<m_nB;i++){if(B[i].y>yt && B[i+1].y>yt)//p1,p2都在上方,next{continue;}if(B[i].y<=yt && B[i+1].y<=yt)//p1,p2都在下方,留P1{C[m_nA].x =B[i].x;C[m_nA].y =B[i].y;m_nA++;continue;}if(B[i].y>yt && B[i+1].y<=yt)//P1在上方,P2在下方外->内,留交点{y=yt;tem1=B[i].y-yt;//tem2=x1+(yb-y1)*dx/dytem2=B[i].x-tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y);x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}if(B[i].y<=yt && B[i+1].y>yt)//P1在下方,P2在上方,内->外,留P1和交点{//save p1,,,C[m_nA].x =B[i].x;C[m_nA].y =B[i].y;m_nA++;//save 交点y=yt;tem1=B[i].y-yt;//tem2=x1+(yb-y1)*dx/dytem2=B[i].x-tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y);x=tem2;C[m_nA].x =x;C[m_nA].y =y;m_nA++;continue;}}//形成裁剪后的多边形if(i==m_nB){C[m_nA]=C[0];}CClientDC dc(this);CPen tempen;tempen.CreatePen(PS_SOLID,1,RGB(255,0,0));dc.SelectObject(tempen);dc.MoveTo(C[0]);for(i=1;i<=m_nA;i++){dc.LineTo(C[i]);}}//.....。