多边形裁剪的Sutherland—Hodgman算法

合集下载

sutherland-hodgman原理

sutherland-hodgman原理

sutherland-hodgman原理
Sutherland-Hodgman算法是一种计算多边形相交的算法。

该算
法是由伊文·苏瑟兰和阿尔伯特·霍奇曼在1974年首次提出的。

该算法的目的是确定一个多边形在给定一个“裁剪多边形”内部的部分,即得到裁剪后的多边形。

Sutherland-Hodgman算法的基本思想是,通过逐边计算两个多
边形之间的相交点,然后根据相交点的位置来保留或丢弃多边形的顶点。

具体步骤如下:
1. 首先,将待裁剪的多边形的顶点按逆时针的顺序排列。

2. 针对裁剪多边形的每条边,依次进行以下步骤:
a. 计算裁剪线与多边形顶点的相对位置关系。

有三种可能的
情况:内部、外部或边上。

b. 根据相对位置关系,确定多边形顶点是否需要保留。

c. 如果裁剪线与多边形的一条边相交,计算相交点并加入裁
剪后的多边形的顶点列表。

3. 重复步骤2,直到处理完所有的裁剪多边形的边。

4. 返回裁剪后的多边形。

该算法的主要优点是简单易懂、计算量相对较小,但也存在一
些问题。

首先,该算法只能处理凸多边形,对于凹多边形需要进行额外的处理。

其次,该算法无法正确处理相互重叠的多边形,这种情况下算法的结果可能是不正确的。

因此,在实际应用中,可能需要在算法的基础上进行一些改进或增加其他算法来解决这些问题。

计算机图形学二维图形的裁剪

计算机图形学二维图形的裁剪
所示,对于其中任一边界向量,从向量起点A向终点B看过去: 如果被测试点P在该边界线右边(即内侧),AB×AP的方向与X-Y平面
垂直并指向屏幕里面,即右手坐标系中Z轴的负方向。 反过来,如果P在该边界线的左边(即外侧),这时AB×AP的方向与X-
Y平面垂直并指向屏幕外面,即右手坐标系中Z轴的正方向。 设:点P(x,y)、点A(xA,yA)、点B(xB,yB), 向量AB={(xB-xA),(yB-yA)}, 向量AP={(x-xA),(y-yA)}, 那么AB×AP的方向可由下式的符号来确定:
依次下去,相对于第三条、第四条边界线进行裁剪,最后输出的多边 形顶点序列即为所求的裁剪好了的多边形。如下图所示。
7.3.1 Sutherland-Hodgeman多边形裁剪
新的多边形顶点序列产生规则: 在用窗口一条边界及其延长线裁剪一个多边形时,该边界线把平面分
成两个部分:一部分称为边界内侧;另一部分称为边界外侧。 如下图所示,依序考虑多边形的各条边。假设当前处理的多边形的边为
V=(xB-xA)·(y-yA)-(x-xA)·(yB-yA)
(3-14)
因此,当V≤0时,P在边界线内侧; 而V>0时,P在边界线外侧。
练习
Sutherland-Hodgeman多边形裁剪中,常用向量叉积法来测试当前点P是 否在边界内侧。已知窗口边界A(30,100)、B(40,180),某点P(50, 300),请 问点P在边界内侧吗?
7.3 多边形的裁剪
多边形裁剪的常用算法 1.Sutherland-Hodgeman多边形裁剪 2.Weiler-Atherton任意多边形裁剪
7.3.1 Sutherland-Hodgeman多边形裁剪
Sutherland-Hodgman算法也叫逐边裁剪法,该算法是萨瑟兰德 (I.E.Sutherland)和霍德曼(Hodgman)在1974年提出的。这种算法采用了 分割处理、逐边裁剪的方法。 一、Sutherland-Hodgeman多边形裁剪算法思想:

一种有效的复杂多边形裁剪算法

一种有效的复杂多边形裁剪算法

条件
目前主流的多边形裁剪算法有 Sutherland-Hodgeman算法 (简称S算法)、Liang-Barsky算法、Maillot算法(简称M算法) 等,它们均要求窗口多边形是矩形,而主多边形则是凸多边形, 具有极大的应用局限性。 本算法中主多边形和窗口多边形可以为任意形状的多边形!
基本概念
3
在各扫描带上建立“交梯形”的集合。
4
在“交梯形”集合的基础上通过边界追 踪等方法构建裁剪多边形并输出计算结
果。
关键过程 实现
一、计算两个图层的交点
两多边形图层间的交点也可借助扫描线思想获得, 思路为:
①分配一个坐标数组,记录主多边形与窗口多边形上 所有顶点的纵坐标值,并对该数组排序。
②以数组中每一个元素值作水平扫描线,分别将主多 边形和窗口多边形的边打断成小线段,得到两组线段 集合。
如图示
栅格法的缺陷:精度问题 克服方法:分解为不规则的几何单元
栅格图
多边形裁剪中的栅格法思想
算法原理
扫描线思想 多边形如何分解??
如果是单个多边形图层可以这样扫描分解:针对多边形的所有顶点,对 其纵坐标y值进行排序,然后根据y值的排序依次绘制水平扫描线,此时 多边形顶点均位于扫描线上。 图 示
(3)“分裂”运算的关键是判断“插入”梯形在参照链表中的位置。在算 法初期已完成多边形线段求交运算,待“插入”梯形与参照链表中梯形之间 不会出现斜边交叉的情况,梯形位置的判断十分容易。 具体判断方法为:计算梯形两条斜边中点的横坐标值x,参照链表中每个梯形两 斜边的x按照从左至右的方式构成一个有序坐标序列;通过折半查找求出待 “插入”梯形两斜边中点横坐标x在该坐标序列中的位置,从而推断出待“插 入”梯形两斜边位于参照链表中的位置,并找出该梯形与链表中哪些梯形相 交。

二维裁剪算法的研究

二维裁剪算法的研究

二维裁剪算法的研究一、概述二、常用算法1. Cohen-Sutherland算法Cohen-Sutherland算法是一种经典的线段裁剪算法,由Cohen和Sutherland于1967年提出。

该算法将显示区域划分为9个区域,每个区域用3位二进制编码表示,从而快速判断线段是否在显示区域内。

如果线段的两个端点处于同一区域内,则可以确认该线段不需要裁剪;否则,需要根据线段和显示区域的交点来计算裁剪后的线段。

2. Liang-Barsky算法Liang-Barsky算法是另一种常用的线段裁剪算法,由Liang和Barsky于1984年提出。

该算法通过参数化线段和显示区域的边界,得到线段与边界的交点,并判断交点的位置以确定裁剪后的线段。

与Cohen-Sutherland算法相比,Liang-Barsky算法可以更准确地计算交点,从而得到更精确的裁剪结果。

3. Sutherland-Hodgman算法Sutherland-Hodgman算法是一种多边形裁剪算法,由Sutherland和Hodgman于1974年提出。

该算法将多边形按顺时针方向遍历,同时与显示区域的边界进行求交操作,得到裁剪后的多边形。

该算法的关键在于如何确定求交点的位置,以及处理多边形与显示区域的边界相交和不相交的情况。

三、算法优化虽然上述算法在裁剪效果和计算性能上已经得到一定的改进,但仍然存在一些问题。

其中一个问题是算法在处理图形中大量的线段或多边形时,计算量较大,导致渲染效率较低。

为了提高算法的效率,可以通过以下几种方式进行优化。

1.边界框剔除在裁剪算法之前,可以先进行边界框剔除操作。

边界框(bounding box)是一个能包围图形的矩形框,通过判断边界框与显示区域的相交关系,可以快速确定哪些线段或多边形完全位于显示区域之外,从而减少不必要的计算。

2.分段裁剪如果待裁剪的线段或多边形较长,并且与显示区域的交点数量较多,可以考虑采用分段裁剪的方式。

三维sutherland-hodgman算法

三维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)。

多边形裁剪算法

多边形裁剪算法

则tu即为三者中离p0最近的 0
点的参数
– 若tu > tl,则可见线段区间 [tl , tu]
1
t3
梁友栋-Barsky算法
始边和终边的确定及交点计算:
令 QL= - △x
DL= x0-xLQR= △xDR= 来自R-x0QB= - △y
DB= y0-yB
QT= △y
DT= yT-y0
交点为
ti= Di / Qi
可弃之。然后对另一段重复上述处理。
1001
1000
1010
0001
0000
0010
0101
0100
0110

编码
P1 P3 P4
P2
线段裁剪
Cohen-Sutherland裁剪
如何判定应该与窗口的哪条边求交呢? 编码中对应位为1的边。
• 计算线段P1(x1,y1)P2(x2,y2)与窗口边界的交点 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);}
直接求交算法
直线与窗口边都 写成参数形式, 求参数值。
Cohen-Sutherland裁剪
• 基本思想:

多边形裁剪——精选推荐

多边形裁剪——精选推荐

多边形裁剪错觉:直线段裁剪的组合?新的问题:边界不再封闭,需要⽤窗⼝边界的恰当部分来封闭它,如何确定其边界?⼀个凹多边形可能被裁剪成⼏个⼩的多边形,如何确定这些⼩多边形的边界?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裁剪算法扩展三维裁剪

计算机图形学Sutherland-Hodgman裁剪算法扩展三维裁剪
return (false);
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多边形裁剪算法

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算法,全称为Sutherland-Hodgman算法,是一种用于计算多边形裁剪的算法。

其基本原理是通过对多边形进行逐边裁剪,最终得到裁剪后的多边形。

这个过程可以简单地分为四个步骤:边界框检测、边界相交检测、多边形顶点分类以及多边形边界点的计算。

边界框检测是指通过与裁剪窗口的边界进行比较,确定多边形是否在裁剪窗口内部。

如果多边形完全位于裁剪窗口之外,则可以直接舍弃。

如果多边形与裁剪窗口有交集,则继续进行下一步操作。

接下来,边界相交检测是指确定多边形与裁剪窗口的边是否相交。

如果多边形的边与裁剪窗口的边没有相交,则舍弃该边。

如果有相交,则进行下一步操作。

然后,多边形顶点分类是指根据多边形的顶点与裁剪窗口的边界相对位置,将多边形的顶点分为内部点、外部点和交点。

内部点是指位于裁剪窗口内部的点,外部点是指位于裁剪窗口外部的点,交点是指位于裁剪窗口边界上的点。

根据多边形顶点的分类结果,计算出多边形的边界点。

这些边界点将组成裁剪后的多边形。

二、Sutherland算法的应用领域Sutherland算法在计算机图形学中有广泛的应用。

它可以用于多边形的裁剪,将多边形限制在指定的区域内,从而实现对图像的剪裁和切割。

这在计算机辅助设计(CAD)和计算机游戏中非常有用。

在CAD中,Sutherland算法可以用于对设计图形进行裁剪。

例如,在建筑设计中,可以使用Sutherland算法将建筑物的平面图限制在指定的区域内,以便更好地展示和分析。

在计算机游戏中,Sutherland算法可以用于实现视景裁剪。

多边形裁剪的Sutherland—Hodgman算法(计算机图形学)

多边形裁剪的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)+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]);}}//.....。

sutherland-hodgman裁剪算法

sutherland-hodgman裁剪算法

Sutherland-Hodgman裁剪算法是一种用于裁剪凸多边形的算法。

该算法的基本思想是在多边形的每一条边上进行裁剪,逐步得到裁剪后的多边形。

以下是详细的Sutherland-Hodgman裁剪算法的步骤:
步骤:
1.确定裁剪窗口:定义一个裁剪窗口(clipping window),它是一个矩形,
用来指定裁剪区域。

2.初始化:对于输入多边形的每一条边,按顺序执行以下步骤:
–记录当前边的起点和终点。

–将裁剪窗口的一个边作为“裁剪边”。

–初始化一个空的输出多边形。

3.迭代裁剪:遍历每一条输入多边形的边,依次进行以下操作:
–对于当前边,判断其与裁剪边的相对位置关系(在窗口内、窗口外或跨越窗口边界)。

–根据相对位置关系,更新输出多边形:
•如果边完全在窗口内,则将边的终点添加到输出多边形中。

•如果边跨越窗口边界,则计算边与裁剪边的交点,并将交点添
加到输出多边形中。

•如果边完全在窗口外,则不添加任何点。

4.更新裁剪边:对于每一轮迭代,更新裁剪边为下一条窗口的边。

依次遍历
裁剪窗口的四个边。

5.重复直到完成:重复步骤3和步骤4,直到遍历完所有输入多边形的边。

6.输出结果:输出多边形即为裁剪后的结果。

示例代码:
以下是一个简单的示例代码,用C语言实现Sutherland-Hodgman裁剪算法:
请注意,这只是一个简单的示例,实际应用中可能需要更多的边界条件和错误处理。

SutherlandHodgman多边形裁剪算法

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)领域,这些算法被用于对图形进行裁剪和填充,以实现图形的精确显示和编辑。

另外,在计算机游戏开发中,多边形裁剪与扫描算法也被用于实现场景的渲染和光照效果。

五、总结多边形裁剪与扫描算法是计算机图形学中重要的技朧,通过裁剪算法可以实现对图形的剪切和编辑,而扫描算法则可以实现对图形的填充和显示。

mfc直线和多边形矩形窗口裁剪算法

mfc直线和多边形矩形窗口裁剪算法

mfc直线和多边形矩形窗口裁剪算法MFC直线和多边形矩形窗口裁剪算法是一种在MFC框架下用于裁剪直线和多边形的算法。

该算法可以确保在绘制图形时,图形的边界不会超出指定的矩形窗口范围。

这种裁剪算法是为了确保图形的可视性和美观性,以及提高程序的性能。

在MFC框架中,绘制图形一般是通过在窗口的OnPaint函数中完成的。

在OnPaint函数中,我们可以获取绘图设备上下文(device context,简称DC),并在DC上进行绘图操作。

为了实现裁剪效果,我们需要在绘图之前对要绘制的图形进行裁剪,确保图形不会超出指定的窗口范围。

对于直线的裁剪,我们可以使用Cohen-Sutherland裁剪算法。

该算法是一种基于线段的区域编码(region encoding)算法,用于裁剪位于矩形窗口外部的线段。

算法的基本思路是判断直线的两个端点是否在窗口的内部,如果都在内部,则直接绘制该直线;如果都在外部,则直接丢弃该直线;如果一个在内部,一个在外部,则通过计算交点并选择正确的端点来裁剪直线。

对于多边形的裁剪,我们可以使用Sutherland-Hodgman裁剪算法。

该算法是一种基于点的裁剪算法,用于裁剪位于矩形窗口外部的多边形。

算法的基本思路是将多边形分割为若干条边和端点,然后根据边与窗口的关系进行裁剪。

具体步骤包括:将多边形的各个顶点与窗口的边界进行比较,并根据顶点在内部和外部的情况确定裁剪结果;根据边界与窗口的关系确定新的裁剪结果,并将结果作为下一次裁剪的输入。

在MFC中实现直线和多边形的裁剪算法,可以按照以下步骤进行:1.获取绘图设备上下文(DC)。

2.设置裁剪区域为窗口矩形范围。

3.使用Cohen-Sutherland算法进行直线裁剪,对于每条需要绘制的直线,判断其裁剪结果并进行绘制。

4.使用Sutherland-Hodgman算法进行多边形裁剪,对于每个需要绘制的多边形,判断其裁剪结果并进行绘制。

5.释放绘图设备上下文。

多边形切分算法

多边形切分算法

多边形切分算法是一种处理多边形的方法,它可以将一个多边形切割成若干个更小的多边形。

这个过程可以通过多种算法实现,其中最常用的是Sutherland-Hodgman算法。

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. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
4、顶点Pi与前一顶点Pi-1均在外侧,则顶点序列中不增加新的顶点。
2>. Sutherland—Hodgman多边形裁剪算法步骤
考虑多边形相对于一条边界及其延长线进行裁剪的算法:
1.从主函数得到待裁剪多边形的顶点序列P[][2]、顶点序列数n、窗口一条边界参数xl(假如为矩形窗口的左边界);
if(yt<clipwindow[i].y)
yt=clipwindow[i].y;
}
//
CPoint B[Polygon_Num],C[Polygon_Num];
UINT m_nA,m_nB;
}
if(polypoint[i].x>=xl && polypoint[i+1].x>=xl) /*边两个端点都在内部,保留*/
/*因为每个保留的点在数组中只出现一次,且下一次判断时第二个端点一定会要取到,因此只保留的两个点中的第一个*/
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)/*起点在内部,终点在外,求交点,然后起点,交点送入临时数组*/
//p1在上方,P2在下方,留P1和交点,内-外
{
//save p1
C[m_nA].x=B[i].x;
C[m_nA].y=B[i].y;
m_nA++;
பைடு நூலகம்
//-----多边形裁剪的Sutherland—Hodgman算法---------//
/////////////////////////////////////////////////////////////////////////////////////
void CMyClip_AView::ClipedgeL(CPoint polypoint[], CPoint clipwindow[], UINT polynum)
m_nA++;
continue;
}
if(B[i].y<yb && B[i+1].y>=yb)
//p1在下,P2在上,留交点,外->内
{
}
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;
}
}
将当前顶点赋给S:S=Pi;
}
4.做返回准备:
将新的多边形顶点序列Q又逐一放回原多边形顶点序列P中:P=Q;
将新的多边形顶点数j放回原多边形顶点数n中:n=j;
//////////////////////////////////////////////////////////////////////////////////////
if(polypoint[i].x<xl && polypoint[i+1].x>=xl)/*边两个端点起点在外部,终点在内部,求交点,然后交点,终点都应该送入临时数组*/
{
/*保留交点*/
x=xl;
多边形裁剪的Sutherland—Hodgman算法
1>. Sutherland—Hodgman多边形裁剪算法思想
该算法的基本思想是每次用窗口的一条边界及其延长线来裁剪多边形的各边。多边形通常由它的顶点序列来表示,经过裁剪规则针对某条边界裁剪后,结果形成新的顶点序列,又留待下条边界进行裁剪,…,直到窗口的所有边界都裁剪完毕,算法形成最后的顶点序列,才是结果多边形(它可能构成一个或多个多边形)。
xr=clipwindow[0].x;
yt=clipwindow[0].y;
yb=clipwindow[0].y;
for(i=1;i<=4;i++)
{
if(xl>clipwindow[i].x)
//留交点
y=yb;
tem1=yb-B[i].y;
//tem2=x1+(yb-y1)*dx/dy
tem2=tem1*(B[i+1].x-B[i].x)/(B[i+1].y-B[i].y)+B[i].x;
y=tem2;
B[m_nB].x =x;
B[m_nB].y =y;
m_nB=m_nB+1;
continue;
}
}
{ /*保留内部点*/
B[m_nB].x =polypoint[i].x ;
B[m_nB].y =polypoint[i].y ;
m_nB=m_nB+1;
/*保留交点*/
当多边形一个顶点Pi相对于窗口某条边界及其延长线进行剪裁时,不外乎下列四种情况(即裁剪规则):
1、顶点Pi在内侧,前一顶点Pi-1也在内侧,则将Pi纳入新的顶点序列;
2、顶点Pi在内侧,前一顶点Pi-1在外侧,则先求交点Q,再将Q、Pi依次纳入新的顶点序列;
3、顶点Pi在外侧,前一顶点Pi-1在内侧,则先求交点Q,再将Q纳入新的顶点序列;
tem1=(xl-polypoint[i].x);
//tem2=(xl-x1)*dy/dx+y1;
//y/x=dy/dx---->y=x*dy/dx
tem2=tem1*(polypoint[i+1].y-polypoint[i].y)/(polypoint[i+1].x-polypoint[i].x)+polypoint[i].y;
xl=clipwindow[i].x;
if(xr<clipwindow[i].x)
xr=clipwindow[i].x;
if(yb>clipwindow[i].y)
yb=clipwindow[i].y;
if(Pi在边界内侧)
{
if(flag!=0)
{
flag=0;
求交点并放入新的多边形顶点序列Qj中;
j++;
}
将当前顶点放入新的多边形顶点序列Qj中:Qj=Pi;
j++;
}
else
{
if(flag==0)
{
flag=1;
求交点并放入新的多边形顶点序列Qj中;
j++;
{
B[m_nB].x =polypoint[i].x ;
B[m_nB].y =polypoint[i].y ;
m_nB=m_nB+1;
continue;
}
int x,y;
long tem1,tem2;
m_nA=polynum;/*记载原始多边形顶点顶点个数*/
m_nB=0;/*记载新生成多边形顶点顶点个数*/
for(i=0;i<m_nA;i++)
{
/*其中参数polypoint[]为多边形顶点,clipwindow[]为裁剪窗口顶点,polynum为多边形顶点数目*/
{
//找出裁剪窗口边界
long xl,xr,yt,yb;
UINT i;
xl=clipwindow[0].x;
for(i=0;i<m_nB;i++)
{
if(B[i].y<yb && B[i+1].y<yb)
//两个点全在下方
{
continue;//下一条边
x=xl;
tem1=(xl-polypoint[i].x);
tem2=tem1*(polypoint[i+1].y-polypoint[i].y)/(polypoint[i+1].x-polypoint[i].x)+polypoint[i].y;
//把第一个点的数据拷贝到最后
//形成裁剪后的多边形
if(i==m_nA)
{
B[m_nB]=B[0];
}
//下------------------
m_nA=0;
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)
2.赋初值:将顶点序列中的最后一个顶点赋给前一顶点S;
设置初始标志flag:
if(S在边界内侧)flag=0;
else flag=1;
设新的顶点序列数j=0;
3.对多边形各顶点进行裁剪规则处理,结果放入新的多边形顶点序列Q[][2]中:
for(对第一个顶点直到最后一个顶点,逐一处理)
{
if(polypoint[i].x<xl && polypoint[i+1].x<xl) /*判断的多边形边两个端点都在外部,不做处理*/
{
continue;/*如果是这种情况,那么就对继续对下一条多边形边作判断,也就是说下面的判断不用做了*/
y=yb;
tem1=yb-B[i].y;
相关文档
最新文档