AGG第五十课 任意多边形的裁剪

简介:

摘自:http://davis.wpi.edu/~matt/courses/clipping/

 

Motivation 
Basic Concepts and Definitions 
Data Structures 
The Algorithm  ( Phase I, II and III) 
C/LIBSX Implementation 
Performance Results 
References 
Acknowledgments 
 

powerpoint slides  download presentation  code            _ back.gif


Motivation

Clipping is an essential part of image synthesis. Traditionally, polygon clipping has been used to clip out the portions of a polygon that lie outside the window of the output device to prevent undesirable effects. In the recent past polygon clipping is used to render 3D images through hidden surface removal and to produce high-quality surface details using techniques such as Beam tracing. Polygon clipping is also used in distributing the objects of a scene to appropriate processors in multiprocessor raytracing systems to improve rendering speeds.

Clipping an arbitrary polygon against an arbitrary polygon is a basic routine in computer graphics. In rendering complex images, it may be applied thousands of times. The efficiency of these routines is therefore extremely important. To achieve good results, most of the commercial products use simplified clipping algorithms that can only clip regular (e.g. convex) polygons. However, due to the development of new products that require complex modelling of the objects (e.g. CAD applications) the need of finding efficient methods for clipping more general polygons (e.g. concave or self-intersecting polygons) has become stringent. So far though, only two other algorithms have been proposed. In 1980, Weiler designed for the first time an algorithms which was able to clip arbitrary polygons. His approach was based on a graph representation of the polygons and was rather complicated. In order to generate the result polygon, a complete traversal of a tree structure was necessary. Only 12 year later, Vatti proposed a new algorithm. His method was able to perform some other boolean operations on the two input polygons and offered support to an eventual further filling process. However, the data structure they use was more complex that in the algorithm presented. Moreover, the intersection between the cross intersecting edges of a polygon has also to be computed. This leads to poorer results in comparison with the present algorithm.

top.gif


Basic Concepts

Definitions. A closed polygon is defined as an ordered list of nodes in which the first and the last one (and possible others too) are identical. Further, given two polygons - a clip (clipper) and a subject polygon (cleppee) - the clipped polygon is defines as the set of all points interior to the clip polygon that lie inside the subject polygon. This set will be either a single polygon or a set of new polygons.

But what does "interior" mean for a self-intersecting polygon? In order to define a containment criterion, the "winding number" has been introduced. Intuitively, the winding number of a point A shows how many times a ray originated in A winds around A when moving along a close curve w. Formally, the winding number is defined as an integral:

f11.gif

where the variable to be integrated in a positive angle obtained by moving the ray along the curve:

f12.gif

Now, we can define the interior of a curve w as the set of points for which the winding number is odd:

f3.gif

The winding numbers have some important properties, such as:

  • the winding number remains constant when the point (A) or the curve (w) change, as long as A keeps a positive distance to w;

  • the components of the subspace RxR - w have the same winding number; specifically, the winding numbers for the points situated in unbounded regions is zero.

  • by crossing the curve, the winding number changes by exactly 1 (+/-1).

These properties give an efficient way to compute the interior test. The testing method, based on a line scan of the polygon is presented in [2]. The idea is that, coming from infinity (where the winding number is zero) a ray changes is inside / outside status every time it 
intersects an edge.

top.gif


Data Structures

The algorithm computes the clipped polygon in three phases. In the first phase it determines (and marks) the intersection points. The points are then inserted in both lists, in their proper place by ordering them using the alpha values. If no intersection points are found in this phase we know that either the subject polygon lies entirely inside the clip polygon or vice versa, or that both polygons are disjoint. By performing a containment test for any of the vertexes we are able to determine which case we have. Then we either return the inner polygon or nothing at all.

In order to efficiently implement this, the algorithm uses two doubly linked lists to represent the polygons. One list is for the clip and one for the subject polygon. In each list, a node represents a distinct vertex. Obviously, the lists will contain the x and y coordinates of the vertexes as well as the necessary links to the previous and next node in the list. In addition to these however, the algorithm needs some more information:

typedef struct _node 
{ 
  int x, y; 
  struct _node *next; 
  struct _node *prev; 
  struct _node *nextPoly;   /* pointer to the next polygon */ 
  struct _node *neighbor;   /* the corresponding intersection point */ 
  int intersect;            /* 1 if an intersection point, 0 otherwise */ 
  int entry;                /* 1 if an entry point, 0 otherwise */ 
  int visited;              /* 1 if the node has been visited, 0 otherwise */ 
  float alpha;              /* intersection point placemet */ 
} node;

NextPoly is a pointer to a new polygon, once the current one has been closed. Indeed, in the most general case, the result of the algorithm is a set of polygons rather than a single one, so that the lists that represent the polygons have to be linked together in order for polygons to be accessed from one to another.

Intersect is a boolean value that is set to true if the current node is an intersection point and to false otherwise. Similarly, entry is flag that records whether the intersecting point is an entry or an exit point to the other polygon's interior.

Neighbor is a link to the identical vertex in the "neighbor" list. An intersection node belongs, obviously, to both polygons and therefore has to be present in both lists of vertexes. However, in Phase III, when we generate the polygons from the list of resulting edges we want to be able to jump from one polygon to another (switch the current polygon). To enable that, the neighbor pointers keep track of the 
identical vertexes. In the same phase of building the polygons by navigating through the list of nodes, the visited flag is used to mark the nodes already inserted in the result (it is important to notice here that every intersection point belongs to the resulting polygon (since by definition it belongs to both interiors).

The alpha value is a floating point number from 0 to 1 that indicates the position of an intersection point reported to two consecutive 
non-intersection vertexes from the initial list of vertexes.

top.gif

The Algorithm

Phase one. The first phase is basically an iteration through the both lists (the complexity is at least m*n, where m and n are the number of vertexes for the two polygons). The intersection points between all the edges are determined. An important thing to remark is that here, unlike in the Vatti's algorithm, only the intersection points between edges from different polygons are considered.

Once a new intersection point is determined, it is inserted in both the two lists. A link between these nodes is maintain through the "neighbor" value. These links will further be used in the navigation process describe in phase three. While computing an intersection point, the algorithm determines also its alpha value. The alpha value shows basically the placement of the intersection point between the two polygon vertexes. If the length of the new formed segment is and the length of the edge it belongs to is b, then the alpha value is defined as a/b (the value is obviously between 0 and 1). Alpha is used when inserting the new intersection points. They basically define an ordering relation on the number of intersection points between the two vertexes of the same edge.

This phase of the algorithm is the most time consuming one. Determining the intersection requires floating points operations and floating points operation are computationally expensive. Moreover, we can have many degeneration cases which unfortunately increase the computation time. These problems have been solved by perturbing the "problem nodes" a method that is usually faster than addressing all the exception rules. The two perturbation choices (methods) for the two major cases of degenerating are shown below:

f15.gif

Phase two. Phase two is a simple process of marking the intersection points as entries or exits. Practically, the intersection points are labeled as entry/exit alternatively when traversing the polygon lists, since we cannot have two entry/exit points in a row. The process starts by first determining the inside/outside value for one vertex of each of the polygons. If, for example, it is outside the other 
polygon, then the next intersection point that come across will be marked as entry. What it is interesting here is that, by changing the order in which one starts marking the nodes, other boolean operations on the set of polygons (specifically union and difference) can also be performed.

Consequently, the only problem in this phase is finding a "containment test" that, given a point and a polygon, determines whether the point lies inside that polygon or not. However, based on the observations in Section 1 (the properties of the winding numbers), a quick method can be found ([2]).

Phase three. The goal of phase three is to generate the clipped polygon (set of polygons). The generation process is a back and forth navigation through the two lists, guided by the entry/exit values and the neighbor pointers. The generation of a single polygon starts at 
an intersection point. If the point is an entry then go forward till the next intersection point is reached (otherwise go backward). From this point switch the list by using the neighbor link. Further go forward or backward depending on whether the "neighbor" vertex is an entry or an exit. This process iterates until the starting point is reached, when we complete the generation of the polygon. In case that there still are unvisited nodes (every node is marked as visited or not) then the result is composed by multiple polygons and a new iteration begins.

The execution of the algorithm for a small example is illustrated below: 
 

f101.gif f103.gif
f102.gif


top.gif

C/LIBSX Implementation

I have implemented the algorithm in C, using as a front-end tool the graphical package libsx. The user can define arbitrary polygons by simply clicking with the mouse in the drawing area and then can specify the desired functionality (intersection, union, difference) by selecting an option in the drill-down menu (the default setting is intersection). A complete version of the implementation can be found here. Below, there are some screen previews illustrating the execution window for the three typical cases. First we have the intersection of the subject (blue) polygon and the clip (green) polygon, then the difference and finally the union. Notice that union can lead to interesting results when applied to self-intersecting polygons. 
 

x1.gif
x11.gif


  
 

y1.gif
y11.gif


 

z1.gif
z11.gif
top.gif

Performance Results

The algorithm presented here as well as the Vatti's one [3] have been implemented and compared. The tests have been performed on a SGI Indigo work station.

The method they used assumed that both the clip and the subject polygons had the same number of nodes n. For that number, one thousand polygons were randomly generated. The computation time was then averaged. The test results are presented below:

f16.gif

The improvement over the previous approach is obvious. The authors explain this by the fact that Vetti's algorithm needs also to compute the intersection points for the self-intersecting polygons. The number of such self-intersections could be quadratic in the worst case.

top.gif


References

[1]    Greiner, G.; Hormann, K.: "Efficient Clipping of Arbitrary Polygons", ACM Trans on Graphics, 1998
[2]    Foley, J.D.; Van Dame, A.; Feiner, S.K., Hughes, J.F.: "Computer Graphics, Principle and Practice", Addison-Wrasley, 1990

[3]    Vatti, B.R.: "A generic solution to polygon clipping", ACM Commun., 1992

top.gif

Acknowledgments

Some of the figures used in this presentation have been obtained from [1]. The title photography has been provided by photo.net.

top.gif






     本文转自fengyuzaitu 51CTO博客,原文链接:http://blog.51cto.com/fengyuzaitu/1972935,如需转载请自行联系原作者


相关文章
|
小程序 前端开发 程序员
不得不说,这19个程序员兼职平台让我1年收入60w
关于程序员接私活,社会各界说法不一。
2243 1
|
机器学习/深度学习 人工智能 自然语言处理
从前端智能化看“低代码/无代码”
什么是低代码/无代码开发?业界对于低代码/无代码开发是否存在其他不同的理解?低代码开发和无代码开发之间的区别是什么?
从前端智能化看“低代码/无代码”
|
3月前
|
机器学习/深度学习 人工智能 vr&ar
H4H:面向AR/VR应用的NPU-CIM异构系统混合卷积-Transformer架构搜索——论文阅读
H4H是一种面向AR/VR应用的混合卷积-Transformer架构,基于NPU-CIM异构系统,通过神经架构搜索实现高效模型设计。该架构结合卷积神经网络(CNN)的局部特征提取与视觉Transformer(ViT)的全局信息处理能力,提升模型性能与效率。通过两阶段增量训练策略,缓解混合模型训练中的梯度冲突问题,并利用异构计算资源优化推理延迟与能耗。实验表明,H4H在相同准确率下显著降低延迟和功耗,为AR/VR设备上的边缘AI推理提供了高效解决方案。
503 0
|
存储 Java 大数据
0036Java程序设计-基于Java的敬老院管理系统的设计和实现毕业设计论文1
0036Java程序设计-基于Java的敬老院管理系统的设计和实现毕业设计论文
203 0
|
机器学习/深度学习 自然语言处理 搜索推荐
探索深度学习中的注意力机制
探索深度学习中的注意力机制
426 72
|
负载均衡 监控 算法
在Linux中,如何配置和管理LVS集群?
在Linux中,如何配置和管理LVS集群?
|
并行计算 算法 安全
Bulletproof范围证明之优化
【11月更文挑战第9天】Bulletproof 是一种高效的零知识证明技术,广泛应用于加密货币等领域,用于证明交易金额在合法范围内而不泄露具体数值。本文介绍了 Bulletproof 的基本概念及其在算法、计算资源利用和协议交互等方面的优化方向,探讨了不同应用场景下的优化需求及面临的安全性和兼容性挑战。
276 4
|
固态存储 芯片 内存技术
固态硬盘E2E数据保护机制
为什么采用E2E端对端数据保护机制很有必要呢?
|
机器学习/深度学习
双向RNN与堆叠的双向RNN
双向RNN(Bidirectional RNN)的结构如下图所示。
649 0
双向RNN与堆叠的双向RNN

热门文章

最新文章