多边形裁剪的Sutherland―Hodgman算法(计算机图形学)
计算机图形学二维图形的裁剪
垂直并指向屏幕里面,即右手坐标系中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多边形裁剪算法思想:
二维裁剪算法的研究
二维裁剪算法的研究一、概述二、常用算法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 算法的基本步骤: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)。
复杂多边形窗口的多边形裁剪的改进算法
复杂多边形窗口的多边形裁剪的改进算法复杂多边形窗口的多边形裁剪是计算机图形学领域中的一个重要问题。
这个问题涉及到了两个多边形的相交,求取相交部分的算法。
这个问题在游戏开发、工程制图、计算机辅助设计等领域都有广泛应用。
然而,复杂多边形窗口的多边形裁剪问题不易解决,深入研究之后,发现现行的算法在实际运用中存在一些问题,需要改进。
一、现行的多边形裁剪算法现行的多边形裁剪算法主要有两种,分别是Sutherland-Hodgman算法和Weiler-Atherton算法。
这两种算法在实现方面相对简单,适用面广,被广泛运用。
1. Sutherland-Hodgman算法Sutherland-Hodgman算法是一种逐边裁剪的算法。
该算法将待裁剪多边形沿着裁剪窗口的四个边分别进行裁剪,从而得到最终结果。
该算法基于的思想是将多边形沿着裁剪边拆分成多个三角形,然后对每个三角形进行分类,得到最终的结果。
但是该算法存在一定的问题,比如会向四个方向输出不必要的顶点信息。
2. Weiler-Atherton算法Weiler-Atherton算法是一种基于点和交点的算法。
该算法首先查找所有的交点,并寻找他们之间的连接线段。
这些交点和线段形成了一个新的多边形,然后将这个新多边形剔除窗口外的部分,得到最终结果。
这个算法的主要问题是,当多边形的顶点数量很大时,会产生大量的交点,造成计算时间上的消耗。
二、改进的多边形裁剪算法考虑到现行的两种多边形裁剪算法存在一定的问题,我们提出了一种改进的多边形裁剪算法。
该算法基于分段的概念,分别对多边形和裁剪窗口的各条边进行分段,以减少计算量。
具体而言,我们将多边形和窗口的边按照其坐标值的大小,分为若干个段。
然后,我们逐段进行裁剪。
这个方法最初提出于1984年,但在当时的计算机技术条件下,没有得到推广应用。
如今,我们可以用现代的算力来完成这个算法的运算。
改进算法的主要步骤如下: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-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算法可以用于实现视景裁剪。
(完整版)计算机图形学题库及答案
注意:答案仅供参考第一章 一、名词解释图形;图像;点阵表示法;参数表示法; 二、选择题:F 面哪个不是国际标准化组织(ISO )批准的图形标准。
(D )A. GKS三、判断题:计算机图形学和图像处理是两个近似互逆的学科。
计算机图形学处理的最基本的图元是线段。
(F ) 四、简答题:图形包括哪两方面的要素,在计算机中如何表示它们?阐述计算机图形学、数字图像处理和计算机视觉学科间的关系。
图形学作为一个学科得以确立的标志性事件是什么?试列举出几种图形学的软件标准?工业界事实上的标准有那些? 举例说明计算机图形学有哪些应用范围,解决的问题是什么? 第二章 一、选择题:1. 触摸屏是一种(C )A. 输入设备;B. 输出设备;C. 既是输入设备,又是输出设备;2. 3. 4. B. P HIGS C. CGM D. DXF下面哪一项不属于计算机图形学的应用范围?(A. 计算机动画;B. 从遥感图像中识别道路等线划数据;C. QuickTime 技术;D. 影视三维动画制作关于计算机图形标准化的论述,哪个是正确的(A. CGM 和CGI 是面向图形设备的接口标准B. GKS IGES STEP 匀是 ISO 标准;C. IGES 和STEP 是数据模型和文件格式的标准;D. P HIGS 具有模块化的功能结构; 与计算机图形学相关的学科有A. 图像处理B. 测量技术C. 模式识别D. 计算几何E. 生命科学F. 分子生物学A 、C 、D OB )1. (F )2.空间球最多能提供(D )个自由度;A.一个;B.三个;C.五个;D.六个;3.等离子显示器属于(C)A.随机显示器;B.光栅扫描显示器;C.平板显示器;D.液晶显示器;4.对于一个1024 X 1024存储分辨率的设备来说,当有8个位平面时,显示一帧图像所需要的内存为(A、D)A.1M字节;B.8M字节;C.1M比特;D.8M比特;5.分辨率为1024*1024的显示器,其位平面数为24,则帧缓存的字节数应为(A)A.3MB ;B.2MB;C.1MB;D.512KB;6.下面对光栅扫描图形显示器描述正确的是:(A)A.荧光粉涂层均匀离散分布:B.是一种点画设备;C.电子束从顶到底扫描;D.通过控制电子束的强弱实现色彩的强弱;7.一个逻辑输入设备可以对应(C)物理输入设备。
计算机图形学5.5裁剪算法
如何判定线段应该与窗口的哪条边求交呢?
编码中对应位为1的窗口边。
计算线段P1(x1,y1)P2(x2,y2)与窗口边界的交点 Code代表线段某个端点的编码。 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);}
P4 (1010)
上下右左 □□□□
P1 (1001)
Y=YT
P3: 0110 P4:& 1010
0010
X=XL
P1: 1001 P2:& 0010
0000
P2 (0010)
X=XR
Y=YB P3 (0110)
对于三维裁剪,需要6位编码。
一旦给定所有的线段端点的区域码,就可以快速 判断哪条直线完全在剪取窗口内,哪条直线完全在 窗口外。所以得到一个规律:
4.求交:假定直线的端点坐标为(x1, y1)和(x2, y2) (1)左、右边界交点的计算:y=y1+k(x-x1); (2)上、下边界交点的计算:x=x1+(y-y1)/k。
Cohen-Sutherland端点编码算法
优点:简单,易于实现。 特点:用编码方法可快速判断线段的完全可见和 显然不可见。
计算机图形学习题参考答案(完整版)
计算机图形学习题参考答案第1章绪论1、第一届ACM SIGGRAPH会议是哪一年在哪里召开的?解:1974年,在Colorado大学召开了第一届SIGGRAPH年会。
2、计算机图形学之父是谁?解:Sutherland3、列举一些计算机图形学的应用领域(至少5个)。
解:计算机辅助设计、图示图形学、计算机艺术、娱乐、教学与培训、可视化、图像处理、图形用户界面等。
4、简要介绍计算机图形学的研究内容。
解:(1)图形的输入。
如何开发和利用图形输入设备及相关软件把图形输入到计算机中,以便进行各种处理。
(2)图形的处理。
包括对图形进行变换(如几何变换、投影变换)和运算(如图形的并、交、差运算)等处理。
(3)图形的生成和输出。
如何将图形的特定表示形式转换成图形输出系统便于接受的表示形式,并将图形在显示器或打印机等输出设备上输出。
5、简要说明计算机图形学与相关学科的关系。
解:与计算机图形学密切相关的学科主要有图像处理、计算几何、计算机视觉和模式识别等。
计算机图形学着重讨论怎样将数据模型变成数字图像。
图像处理着重研究图像的压缩存储和去除噪音等问题。
模式识别重点讨论如何从图像中提取数据和模型。
计算几何着重研究数据模型的建立、存储和管理。
随着技术的发展和应用的深入,这些学科的界限变得模糊起来,各学科相互渗透、融合。
一个较完善的应用系统通常综合利用了各个学科的技术。
6、简要介绍几种计算机图形学的相关开发技术。
解:(1)OpenGL。
OpenGL是一套三维图形处理库,也是该领域事实上的工业标准。
OpenGL独立于硬件、操作系统和窗口系统,能运行于不同操作系统的各种计算机,并能在网络环境下以客户/服务器模式工作,是专业图形处理、科学计算等高端应用领域的标准图形库。
以OpenGL为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL与C/C++紧密接合,便于实现图形的相关算法,并可保证算法的正确性和可靠性;OpenGL使用简便,效率高。
多边形裁剪的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裁剪算法的步骤:
步骤:
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);//得到多边形与裁剪窗口左边的交点第二种情况:线段在裁剪窗口的部,线段完全可见。
sutherland-hodgman matlab代码
下面是使用Matlab编写的Sutherland-Hodgman算法的示例代码。
该算法用于计算多边形的裁剪,通过指定裁剪窗口(多边形)和待裁剪多边形,可以得到裁剪后的多边形。
```matlabfunction result = sutherlandHodgman(clipper, subject)% 计算Sutherland-Hodgman算法% 输入参数: clipper - 裁剪窗口多边形% subject - 待裁剪多边形% 输出结果: 裁剪后的多边形% 初始化结果列表result = subject;% 获取裁剪窗口的顶点数n = numel(clipper);% 遍历裁剪窗口的边for e = 1:nedge = [clipper(e,:), clipper(mod(e,n)+1,:)];% 初始化裁剪结果列表output = [];% 获取待裁剪多边形的顶点数m = numel(result);% 遍历待裁剪多边形的边for i = 1:mcurrVertex = result(i,:);nextVertex = result(mod(i,m)+1,:);% 判断待裁剪多边形边与裁剪窗口边的相交情况if insideEdge(currVertex, edge)if insideEdge(nextVertex, edge)% 待裁剪多边形的下一顶点在裁剪窗口内,将其添加到裁剪结果列表output = [output; nextVertex];else% 待裁剪多边形的下一顶点在裁剪窗口外,计算相交点并添加到裁剪结果列表intersection = computeIntersection(currVertex, nextVertex, edge);output = [output; intersection];endelseif insideEdge(nextVertex, edge)% 待裁剪多边形的下一顶点在裁剪窗口内,计算相交点并添加到裁剪结果列表intersection = computeIntersection(currVertex, nextVertex, edge);output = [output; intersection; nextVertex];endend% 更新裁剪结果列表result = output;endendfunction inside = insideEdge(vertex, edge)% 判断顶点是否在边的内侧a = [edge(1)-vertex(1), edge(2)-vertex(2)];b = [edge(3)-vertex(1), edge(4)-vertex(2)];% 计算叉乘crossProduct = a(1)*b(2) - a(2)*b(1);% 判断顶点是否在边的内侧inside = crossProduct > 0;endfunction intersection = computeIntersection(a, b, clip)% 计算边ab与边clip的交点dx = b(1) - a(1);dy = b(2) - a(2);if dx ~= 0m = dy / dx;n = a(2) - m*a(1);if clip(1) ~= clip(3)mClip = (clip(4) - clip(2)) / (clip(3) - clip(1));nClip = clip(2) - mClip * clip(1);x = (nClip - n) / (m - mClip);y = m * x + n;elsex = clip(1);y = m * x + n;endelsex = a(1);if clip(2) ~= clip(4)mClip = (clip(4) - clip(2)) / (clip(3) - clip(1));nClip = clip(2) - mClip * clip(1);y = mClip * x + nClip;elsey = a(2);endend% 返回交点intersection = [x, y];end```。
- 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;求交点并放入新的多边形顶点序列Qjxx;j++;}将当前顶点放入新的多边形顶点序列Qj中:Qj=Pi;j++;}else{if(flag==0){flag=1;求交点并放入新的多边形顶点序列Qjxx;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)/(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(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];}//上-------------------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]);}}//.....。