【原创】CGAL中,2D Arrangements学习笔记
2D Arrangement类型简介:
给定一组平面曲线,2D Arrangement能够将这组曲线所组成的图形细分成顶点、边和面这些最基本的几何单位。其中给定的曲线能够相互相交,甚至能自相交。其组成的图形在2D Arrangemen 中描述成双边连接数据结构(doubly-connected edge list data-structure (D CEL for short))即把一条边变成两条半边来描述,其中,这个数据结构包含了对顶点、边、面的描述。
如上图,通过线段构造的2D Arrangements表现成了顶点(vn)、边(un)、面(fn)的形式。 其中f0是一个没有被包装的面(un_bound),其余都是被包装的面,其中f2为普通的面,f1中包含两个洞f3和f4。至于顶点和边,在这里就不多说了,很简单。需要说明的是对于f0面来说,所有里面的(即f1+f2)组成的为其一个洞。
一个面的边界由一系列的边和点组成,我们称其为a connected component of the boundary(or CCB for short)。这个CCB我们是可以迭代的访问其组成的边和顶点的。
2D Arrangement类型基本使用方法:
1、构造组成
经过研究,2D Arrangement主要由内核、DCEL描述和数据类型组成,其中CGAL提供N种内核来构造一个ARRANGMENT,而我们要用到的基本上就是二维空间中ARRANGMENT的应用,即ARRANGMENT_2,所以下面所说明和讨论的都是基于ARRANGMENT_2的;
在所有的内核之中,据文档介绍Arr_segment_traits_2是一种效率高的内核,所以我也主要以其为研究对象。DCEL一般的就是用默认的DCEL足够了,数据类型则用CGAL::MP_Float。
2、迭代访问
我们可以通过给定的迭代器来访问2D Arrangement。如下代码
template<class Arrangement>
void print_arrangement (const Arrangement& arr)
{
CGAL_precondition (arr.is_valid());
// Print the arrangement vertices.
typename Arrangement::Vertex_const_iterator vit;
std::cout << arr.number_of_vertices() << " vertices:" << std::endl;
for (vit = arr.vertices_begin(); vit != arr.vertices_end(); ++vit)
{
std::cout << "(" << vit->point() << ")";
if (vit->is_isolated())
std::cout << " - Isolated." << std::endl;
else
std::cout << " - degree " << vit->degree() << std::endl;
}
// Print the arrangement edges.
typename Arrangement::Edge_const_iterator eit;
std::cout << arr.number_of_edges() << " edges:" << std::endl;
for (eit = arr.edges_begin(); eit != arr.edges_end(); ++eit)
std::cout << "[" << eit->curve() << "]" << std::endl;
// Print the arrangement faces.
typename Arrangement::Face_const_iterator fit;
std::cout << arr.number_of_faces() << " faces:" << std::endl;
for (fit = arr.faces_begin(); fit != arr.faces_end(); ++fit)
print_face<Arrangement> (fit);
return;
}
注:arrangement操作方法比较简单,总有来说就是把一组线段插入到一个arrangement对象中,arrangement会自然的构造DCEL结构来描述线段所能组成的图形(不同的图形复杂度,构造需要的时间也不同),然后就可以迭代的访问其中的几何对象了。
经过研究,arrangement对于相交线段与非相交线段的处理方法,可以是不同的(不同的插入处理),见其例子。
经过以上分析,就需要针对我们软件中的例子,进行抽象建模。我们的需求是,给定一组线,找出最小区域和最大外包。仔细一分析,CGAL中的arrangement类完全可以满足我们的需求。对于arrangement也是通过一组线段,就能求出其对应的面(这里可以对应我们的最小区域和最大外包),但在arrangement中只有面的概念,那么怎么样区分最小区域和最大外包呢,上文中提到过,所谓最大外包就是对应的最外面一个面,这个面是un_bound的,其余的面,也是就最小区域是被bound的,所以,针对我们的问题,这个标记应该就能够解决的。
现在的问题就是,我们采用哪一种方法来处理一组线段,是我们在外面自己离散? 还是输入最基本的数据,让arrangement自己去离散? 这就在于,是自己的离散算法效率高,还是arrangement的效率高。不管怎么样,我们首先还是用一组数据和结果来说明(以下数据采自己CGAL的两个例子。
其中,图A是没有离散的数据,图B是离散了的数据。运行结果如下:
A
B
其中构造图A的arrangement花了11秒多,而构造图B的arrangement只花了半秒多。当然,这两份数据不是描述一个图,所以也只仅做参考和学习之用,但这说明了,arrangement对线段离散的时间和线段的复杂性是成正比的。
下面,我将自己构造的数据来说明两者的差据。(数据为横、竖各一百条线组成的简单轴网):
首先是离散了的数据的运行结果:
然后是没有离散的数据运行结果
从这份数据来看,对于简单的线段复杂度,离散与非离散数据表现出来的差异并不是很大。
但我相信,也不能完全根据这份数据盲目的判断,我将加入一些曲线,来判断运行的时间,关于结果,下次再贴。