CGAL使用心得 转

77 篇文章 6 订阅
文章介绍了作者在使用CGAL图形算法库解决二维线段中寻找最小区域和最大外包问题的过程。作者探讨了CGAL的ARRANGEMENT模块,以及在精度和效率之间的权衡,提到了精度不足导致的问题,并分享了如何在构建弧线时处理精度问题的挑战。作者还讨论了如何在CGAL中附加信息并保持数据完整性,以及对CGAL核心组件的选择和预定义内核的建议。
摘要由CSDN通过智能技术生成

CGAL使用心得 转

作者:李浩

首先我说说我研究CGAL的背景,由于,早一阵子,有一个需求,需要求出在一堆二维线中(包括直线和弧线),找出所有的最小区域和最大外包。如下图所示。

在这里插入图片描述

在这里插入图片描述

在这两个图形中,要快速的找到每一个最小的封闭区域和一个由这些最小封闭区域组成的一个最大封装区域。这样的算法,有,像最常见的建构多边形TOPO,然后用雷达扫描法,可以求出来。但是,这么多的算法开源库,让我下了使用开源库来解决这个问题的决心,很快我就锁定了CGAL这个强大的图形算法库。

很快的我发现,CGAL里的ARRANGEMENT能够实现类似需求的功能,就这样,我开始慢慢的对ARRANGEMENT进行研究。但研究CGAL的应用,不可能不学习CGAL的基本结构。CGAL是一个基于C++模版的算法库(好像很多的C++开源算法库,都是基于模版的)。学习其基础对C++泛型编程的知识有一定的要求。如果你看过候捷的《STL源码剖析》一书,你会更容易的看懂CGAL的代码。

CGAL中的重要基本名词包括核心、域数据类型、TRAITS特性;

核心中的数据存储是用到了域数据类型,而核心中的数据与基本几何数据的提取是通过TRAITS来的。

ARRANGEMENT中定义了点、面、边的概念,每一个最小区域在它里面被描述成面,而组成最小区域的线被描述成边,所有线的交点被描述成点。这样,需求上的概念与ARRANGEMENT中的概念可以匹配上,就证明,可以用这个算法来实现需求。

在慢慢的学习过程中,我发现CGAL是一个对精度要求比效率要求更高的库(这一度让我想放弃CGAL,但后来,发现再差的效率,都比一般的算法求解出来的速度要快),而我们能够提供的数据,精度是达不到的。就拿MF_FLOAT域数据类型来说,它里面真正保存数据是一个std::vector,这样的精度是DOUBLE型不能比的。到现在,我还没有能够非常完美的解决这个问题。精度不够,特别表现在构建弧线时,CGAL preCondition就会通不过,报异常。这样让我很头大。发现是,我们提供的数据,在构建CGAL的弧时,弧的终点不在其支持圆上。想了很多的办法。最后网上有一位牛人告诉我,要重写CGAL的一个DCEL也许能够解决这个问题。DCEL是doubly-connected edge list data-structure,这种数据结构的最基本的观点是,将被共边的边,看作是一对方向互逆的边(注意,在这个数据结构中,每条边都是有方向,组成的一个环就是一个面)。我又开始学习CGAL中这一部分的内容 Arr_default_dcel,并且学习着,里面对顶点、面、边、孤点等几何对象的定义。发现,如果真正需要解决精度问题,不仅仅是重写DCEL能够解决的。对核心的部分内容也需要重写,这个工作量太大,代价也大。目前公司肯定是不允许的。更要命的是,公司的需求是,能够在传进去的线段上附加信息,出来后,其线段上的信息要不丢失。一开始,我想,有这个需求,不重写DCEL是不行了。于是,我开始跟踪CGAL构建ARRANGEMENT的过程,发现CGAL中,大部分的赋值操作,都是直接的内存拷贝。并且,不管怎么样,CGAL中真正处理的线类型只可能是X_monotone_curve_2,所以,就算你在开始构建的线段上能够附加上信息,当CGAL内部通过这个线段构建X_monotone_curve_2时,你的信息也会丢失。慢慢的,我发现,出来之后的线段也是X_monotone_curve_2,也就是说,只要你能在构建X_monotone_curve_2时能够将你的信息附加上去,你的信息,就有可能在计算出来之后的结果上,还存在。CGAL将核心中定义的CURVE转换成X_monotone_curve_2的过程是由make_x_objects完成的,所以,我在这里进行了改动,在转换过程中,将附加的值的信息给考虑上了。最终完成了这个需求。现在,又回到了,精度的问题了,把附加信息的问题解决了之后,重写这条路更加是不允许走了,通过CURVE构建的过程,我决定,将原来的构造方法改变,改成三点构造法。然后,在外边,对输入的数据的精度,进行更进一步的处理。最终应该是能完成这个功能。具体的,现在同事还在测试中。

通过对CGAL这一段时间的学习,我发觉,CGAL确实是一个很强大的图形算法库,对数据精度要求相当高,所以处理出来的数据正确率也是相当高的,对于那种对算法处理速度要求特别高的,不推荐用CGAL,但可以用CGAL中的算法的思想。

目前CGAL也有商业化的产品GeometryFactory,客户还是挺多的,像国产CAD的龙头产品(吼得最大,动作最大的产品,哈)ZWCAD,也是其客户。

哈哈,就稍微总结在这里,对CGAL的学习,借用一句广告词——永不止步。

附加说明:

  1.   CGAL整体概述
    

CGAL是一个用C++描述的,包含三个主要部分的计算几何算法库.
第一部分是核心组件(Kernel),它包括基本的几何对象以及做用在这些对象上的各种操作.这些对象被实现成使用表现类参数化的独立的类,这样使得核心更具有灵活性和适应性.
第二部分是一系列的基础几何数据结构和算法.它们被特征类参数化.而特征类定义了数据结构或者算法和它们使用的原生类型(primitives)的接口.在很多情况下CGAL中的核心类可以作为这些数据结构或算法的特征类使用.
第三部分是由一些支持设施比如为方便调试设计的迭代器,随即数源,I/O支持以及一些可视化工具等等.这个部分主要介绍核心部分.核心由一些基础对象组成,比如点,向量,方向,直线,射线,线段,三角形,ISO型长方形和四面体.每个部分都有一些对这些对象进行操作的函数.一般有访问函数(比如一个点的坐标),测试点和这个对象的位置关系,得到对象的包围盒子的函数,长度,面积等等.核心中还包含一些基本超作,比如仿射变幻,相交的检测与计算,距离计算.

2. CGAL核心说明
我们学习的对象是d维欧几里德仿射空间.这里我们主要考虑2维和3维得情况.空间中的对象是有点集组成.表示点的一般方法是使用笛卡儿坐标.它假定了一个参照框架(一个原点和d个正交轴).这个框架中一个点是由一个d维的向量表示的(c0,c1,…,cd-1),相应的线性空间中的向量也是如此.每个点都有唯一的笛卡儿坐标与之对应.另一种表示点的方法是齐次坐标.在这个框架中一个点是有一个d+1(h0,h1…,hd)维向量表示的.根据公式ci=hi/hd,对应的点的笛卡儿坐)标(c0,c1,…,cd-1)可以计算出来.注意齐次坐标的点的表示是不唯一的.当λ≠0时,向量(h0,h1,…hd)和向量(λh0, λh1 …, λhd)表示同一个点.如果一个点的笛卡儿坐标是(c0,c1,…,cd-1),它可以表示成(c0,c1,…,cd-1,1)这个齐次坐标.齐次坐标系可实际上可以在一个更一般的空间的中表示对象.这个空间叫射影空间.在CGAL中我们不会进行射影几何的计算.我们使用齐次坐标是为了避免除法运算,而增加的这个坐标是作为公共分母.

2.1 通过参数化实现泛型
几乎所有的核心对象(已经对应的函数)都是由模板来实现的.而模板参数是用用户来选择从而决定核心对象的表现形式.

2.2 笛卡儿坐标系核心
通过Cartesian你可以给笛卡儿坐标系选择表现形式.当你选择了坐标系的表现形式以后,你必须同时指定坐标的数据类型.这种数据类型必须具有域的性质.前面提到int不是一种域类型.但是在笛卡儿坐标系中不包括除法运算,所以环类型在这种情况下是可以使用的.当指定了Cartesian以后Cartesian::FT和Cartesian::RT都被映射成域类型.
Cartesian的内部使用了引用计数来节省拷贝的开支.CGAL同时也提供了不使用引用计数的Simple_cartesian.调试的时候使用Simple_cartesian 会比较方便,这是因为坐标被保存在类的内部,因此可以直接访问坐标.在使用的不同算法的时候,这两种实现方式将有不同的效率.

2.3 齐次坐标系核心(由于ARRANGMENT的例子都是基于笛卡儿坐标系核心的,所以没有做过多的研究)
齐次坐标系中可以避免除法运算,因为引入的补充坐标可以坐标为公共分母.避免了除法运算对几何计算的精确性相当有利.通过Homogeneous可以指定齐次坐标的表现形式.而在笛卡儿坐标系中我们还必须指定坐标的数值类型.因为齐次坐标系不使用除法,作为齐次坐标表现的数值类型必须被建立成为相对较弱的环数据类型.然而齐次核心提供的一些操作中使用到了除法,例如计算笛卡儿坐标系下的平方距离.为了不改变齐次坐标的弱类型参数,我们使用Quotient来解决需要除法计算的情况.这种类型可以认为是一种把环类型转换成为域类型的配接器.它保存数为分子和分母的形式.使用Homegeneous 后,Homogeneous::FT和Quotient等价,同时Homogeneous::RT和RingNumberType等价.
Homogeneous使用引用计数.CGAL同样也提供了没有引用计数技术的Simple_homogeneous.

2.4 命名约定
使用核心类不仅可以避免出问题,而且使得CGAL类具有一致性.

  1. 以大写字母开头的名字表示几何对象,像Point,Segment,Triangle.
  2. 下划线加上对象的维度,_2,_3或者_d
  3. 核心类型加上参数类型比如Cartesian,Homogeneous<leda_integer>.

2.5 作为特征类的核心组件
CGAL基本库中的算法与数据结构是由一些特征类来参数化的.这些特征类包含了一类对象和上面算法或数据结构的操作和函数的行为一致.基础库中的大部分的算法与数据结构都可以由核心组件作为特征类.一些算法可以根据传入的几何对象的类型进行自动的推导,从而不需要直接指定.有些类还需要更多的参数.有些则不能使用核心组件.

2.6 选择一种核心组件和预定义核心组件

如果你使用整形的笛卡儿坐标,大部分的几何计算将只使用整形数值.特别是在只使用断言计算的时候.例如点集三角化和凸包计算.这些情况下笛卡儿坐标系是第一选择,即使是使用RingNumberType.你可以使用精度受限的int和long,使用double来表示整形,或者任意精度的整形例如GMP整形的包装类GMPZ,lead_integer,或者MP_Float.要注意,除非使用任意精度的环类型,溢出将会产生错误.

如果出现新建点的情况,比如求两条直线的交点,笛卡儿坐标中的计算经常出现除法.因此使用笛卡儿坐标的时候需要FieldNumberType.相对的,转换到齐次坐标的时候也一样.double是一个不精确的FieldNumberType.你可以把任何RingNumberType传给Quotient配接器来得到一个FieldNumberType从而可以在笛卡儿坐标系中进行运算.一般来说使用RingNumberType进行齐次坐标运算是比较合适的.其他一些FieldNumberType有leda_rational和leda_real…

如果可靠性对你来说非常重要,使用经过认定的精确计算的数据类型是比较好的选择.Filtered_kernel提供了一种过滤机制使得核心具有既精确又有效率的断言.仍然还有许多人喜欢使用double,因为他们需要速度,而且可以接受近似的结果,甚至可以忍受时不时由于舍入误差而崩溃的算法.

预定义核心组件
为了使用方便,CGAL预定义3个类型
它们都是笛卡儿坐标系核心
它们都支持从double型来建立笛卡儿坐标系里的点
它们用不同的方式处理建立几何对象的问题

—Exact_predicates_exact_constructions:精确的生成几何对象,提供精确的几何断言
—Exact_predicates_exact_construtions_kernel_with_sqrt:和上面一样,但数值类型提供了精确的开方运算
—Exact_predictates_inexact_constructions_kernel:提供精确断言,但是生成几何对象可能存在舍入误差.这对于大部分的CGAL算法来说已经足够了.而且比前面两种情况要快很多.
这三种预定义核心组件都是基于笛卡儿坐标系核心的,只是其构造的域参数类型不同。
我个人建议,内核用基本的笛卡儿坐标系核心,域参数类型用MF_FLOAT或者DOUBLE类型,因为,这样的效率会比其它,对精度对准确度有要求的域参数类型和内核封装类型(其实也是从笛卡儿坐标系核心派生出来的)快。效率最高的Exact_predictates_inexact_constructions_kernel就是Filtered_kernel<Simple_cartesian >

Qt是一款流行的跨平台应用程序开发框架,而CGAL是计算几何算法库的简称。在Qt中使用CGAL可以帮助我们进行各种计算几何相关的操作。 首先,我们需要将CGAL的库文件添加到Qt项目中。这可以通过在项目文件中添加CGAL的链接库和头文件路径来实现。然后,在代码中使用#include指令包含相应的CGAL头文件即可开始使用CGAL提供的功能。 CGAL提供了丰富的计算几何算法和数据结构,例如几何体的构造、凸包计算、点、线和面的相交判断等。我们可以使用这些功能来解决各种几何问题,例如计算两个几何体之间的距离、判断一个点是否在多边形内部等。 除了基本几何计算外,CGAL还提供了一些高级算法,例如三角剖分、形状重建、网格生成等。这些算法可以在图形学、计算机辅助设计等领域中得到广泛应用。 在Qt中使用CGAL的过程与在其他C++项目中使用CGAL基本相同。我们可以通过调用CGAL提供的函数和对象来完成特定的计算几何任务。同时,Qt的图形界面和事件处理机制也可以很好地与CGAL的功能结合起来,实现更复杂的交互操作。 综上所述,通过在Qt中使用CGAL,我们可以方便地进行各种计算几何操作,从而实现高效、精确的几何计算和图形处理。无论是开发桌面应用程序还是移动应用程序,都可以借助Qt和CGAL来实现丰富的几何功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lst0426

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值