文章目录

  • 几何图元
  • 谓词
  • Kernel内核
    • double内核
    • 精确谓词、精确构造的内核
    • 精确谓词,但不精确构造的内核
  • Traits特征类

更多CGAL文章,请看CGAL知识库
计算几何技术交流群:604668232

几何图元

geometric primitives(几何图元)被定义在kernel(内核)中,使用几何图元之前要指定内核。此处先使用double内核,可以理解为使用double作为坐标的数值类型,内核将在后面介绍。

#include <CGAL/Simple_cartesian.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Segment_2 Segment_2;Point_2 p(1,1), q(10,10); //点
Segment_2 s(p,q);         //线段

谓词

Point_2 p(1,1), q(10,10), m(5, 9); //点
Segment_2 s(p,q);         //线段// 两点距离
CGAL::squared_distance(p,q);//点到线段距离的平方
CGAL::squared_distance(s,m);//计算中点
CGAL::midpoint(p,q);//三点的方向
switch (CGAL::orientation(p,q,m)){case CGAL::COLLINEAR: //共线std::cout << "are collinear\n";break;case CGAL::LEFT_TURN: //p->q, q->m时向左转std::cout << "make a left turn\n";break;case CGAL::RIGHT_TURN: //p->q, q->m时向右转std::cout << "make a right turn\n";break;
}

Kernel内核

计算几何的核心是计算精度问题,而Kernel正是代表这个程序如何去对待精度问题。它可以是

  1. double:使用double精度
  2. Exact_predicates_exact_constructions_kernel:精确谓词,且精确构造
  3. Exact_predicates_inexact_constructions_kernel:精确谓词、但不精确构造

double内核

要解释内核,就要先看一个计算几何中的一个大坑:精度问题。

「案例一」如果是自己写的几何算法,我们一般使用float或者double类型,这里以double为例,讨论精度问题。

#include <iostream>
#include <CGAL/Simple_cartesian.h>
typedef CGAL::Simple_cartesian<double> Kernel; //使用double作为坐标的类型
typedef Kernel::Point_2 Point_2; //定义一个double类型的二维点
int main()
{{Point_2 p(0, 0.3), q(1, 0.6), r(2, 0.9); //实例化三个点std::cout << (CGAL::collinear(p, q, r) ? "collinear\n" : "not collinear\n"); //三个点是否共线}{Point_2 p(0, 1.0 / 3.0), q(1, 2.0 / 3.0), r(2, 1);std::cout << (CGAL::collinear(p, q, r) ? "collinear\n" : "not collinear\n");}{Point_2 p(0, 0), q(1, 1), r(2, 2);std::cout << (CGAL::collinear(p, q, r) ? "collinear\n" : "not collinear\n");}return 0;
}

代码中的三个例子,手算都应该是共面,但输出的结果是这样的:

这是由于使用double所导致的(在计算的途中,由于精度的问题,可能会得到意想不到的结果)。如果要保证精度,可以使用内核Exact_predicates_exact_constructions_kernel

精确谓词、精确构造的内核

「案例二」使用内核Exact_predicates_exact_constructions_kernel,即精确谓词、精确构造的内核

#include <iostream>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <sstream>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; //精确谓词、精确构造的内核
typedef Kernel::Point_2 Point_2;
int main()
{Point_2 p(0, 0.3), q, r(2, 0.9);{q  = Point_2(1, 0.6);std::cout << (CGAL::collinear(p,q,r) ? "collinear\n" : "not collinear\n");}{std::istringstream input("0 0.3   1 0.6   2 0.9");input >> p >> q >> r;std::cout << (CGAL::collinear(p,q,r) ? "collinear\n" : "not collinear\n");}{q = CGAL::midpoint(p,r);std::cout << (CGAL::collinear(p,q,r) ? "collinear\n" : "not collinear\n");}return 0;
}

运行的结果如下:

是不是很奇怪,第一个例子还是出错了。
分析:

  1. 第一个代码块中,这三个点仍然不是共线的。是因为它用文本传入的坐标,传入后变成了浮点数,转换成了任意精度的有理数时,它们仅表示浮点数,而可能不会精确的表示原来数值。
  2. 第二个代码块中。是从文件中读取数字,然后直接从字符串构造任意精度的有理数,以便它们能够精确的表示原来的数值。
  3. 在第三块中,中点是通过计算得出的,正如内核定义的那样,使用的是精确谓词,精确构造出来的,所以计算所得的精度是可以靠得住的(这便是第二种内核,精确构造、精确谓词的意思)

在许多情况中,就浮点数而言,它们是“精确的”,即它们是由某些应用程序计算或从传感器中获得的,是全精度的浮点数。它们不是文本0.1或动态计算"1.0/10.0"所得的(如果是这种方式得到的结果,可能不是精确的)。

精确谓词,但不精确构造的内核

凸包算法仅仅比较坐标的数值和进行方向测试,故在凸包算法中(计算一个点集的凸包),输出的结果即是点集的子集,是原来的坐标值,而并不会重新构造出新的点。此类应用场景,即可使用精确谓词,但不精确构造的内核Exact_predicates_inexact_constructions_kernel

「案例三」2D凸包算法示例

#include <iostream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K; //精确谓词,但不精确构造的内核
typedef K::Point_2 Point_2;
int main()
{// 5个点Point_2 points[5] = { Point_2(0,0), Point_2(10,0), Point_2(10,10), Point_2(6,5), Point_2(4,1) };Point_2 result[5];// 计算2D凸包///参数:输入的起点、终点指针、凸包结果的指针数组///返回值:The function returns the pointer into the result array just behind the last convex hull point written,///so the pointer difference tells us how many points are on the convex hull.Point_2 *ptr = CGAL::convex_hull_2(points, points + 5, result);//凸包的个数=返回值-结果数组std::cout << ptr - result << " points on the convex hull:" << std::endl;for(int i = 0; i < ptr - result; i++){std::cout << result[i] << std::endl;}return 0;
}

「案例四」说到2D凸包算法,这里展示另一种写法,使用vector存点集,在vector中计算凸包

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_2.h>
#include <vector>typedef CGAL::Exact_predicates_inexact_constructions_kernel K; //精确谓词,但不精确构造的内核
typedef K::Point_2 Point_2;
typedef std::vector<Point_2> Points;int main()
{Points points, result;points.push_back(Point_2(0, 0));points.push_back(Point_2(10, 0));points.push_back(Point_2(10, 10));points.push_back(Point_2(6, 5));points.push_back(Point_2(4, 1));//2D凸包///第一二个参数:两个迭代器,表示输入的点集///第三个参数:计算结果所插入的位置CGAL::convex_hull_2(points.begin(), points.end(), std::back_inserter(result));std::cout << result.size() << " points on the convex hull" << std::endl;for(int i = 0, size = result.size(); i < size; ++i){std::cout << result.at(i) << std::endl;}return 0;
}

Traits特征类

「引言」convex_hull_2()函数有两种版本

  1. 一种即是上面所提到的,使用两个迭代器来规定输入点的范围,并使用一个输出迭代器来将凸包结果写入到结果容器中
template <class ForwardIterator, class OutputIterator>
inline
OutputIterator
convex_hull_2(ForwardIterator first, ForwardIterator last, OutputIterator  result )
  1. 第二个版本具有两个附加参数,一个是模板参数Traits此此类型的参数ch_traits
template <class InputIterator, class OutputIterator, class Traits>
inline
OutputIterator
convex_hull_2(InputIterator first, InputIterator last,OutputIterator  result, const Traits& ch_traits)

第二个版本即是CGAL泛型编程的体现,Traits中定义了用户所使用类型的一些特征,让convex_hull_2()函数支持任意点类型,也可支持多种凸包算法。

「举例」以经典的凸包算法Graham/Andrew Scan为例,该算法先从左到右对点进行排序,然后从排序结果中逐个拿点构造凸包
(1)Traits类型
因此,若要完成凸包计算,必须要知道三个内容:点的类型、这个点类型的排序方式、三点的方向计算。而为了避免参数太多、太长,则将这些参数都定义在一个特征类中,即Traits类型中(CGAL每个Kernel中都有定义好的Traits类型)

(2)验证上面的说法
convex_hull_2()函数中用到了一个核心函数ch_graham_andrew(),具体定义如下:

template <class InputIterator, class OutputIterator, class Point_2, class Less_xy_2, class Left_turn_2, class Equal_2>
OutputIterator
ch_graham_andrew( InputIterator  first,InputIterator  beyond,OutputIterator result);

可以看到,如果要完成convex_hull_2(),必须要提供以下嵌套类型:

  • Traits::Point_2:自定义类型
  • Traits::Less_xy_2:点排序
  • Traits::Left_turn_2:方向测试
  • Traits::Equal_2:相等判断

而对于CGAL的每个模型,都有定义好的Traits。我们举个例子,来实现convex_hull_2()算法:

#include <iostream>
#include <iterator>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Projection_traits_yz_3.h>
#include <CGAL/convex_hull_2.h>typedef CGAL::Exact_predicates_inexact_constructions_kernel K3; //精确谓词、不精确构造的Kernel
typedef CGAL::Projection_traits_yz_3<K3> K; //将3D投影到yz面的Traits
typedef K::Point_2 Point_2; //二维点int main()
{std::istream_iterator< Point_2 >  input_begin( std::cin );std::istream_iterator< Point_2 >  input_end;std::ostream_iterator< Point_2 >  output( std::cout, "\n" );CGAL::convex_hull_2( input_begin, input_end, output, K() );return 0;
}

[CGAL] CGAL的世界-Kernel内核、Traits特征类相关推荐

  1. linux内核centos6.9,CentOS6.9手动编译并更新Kernel内核版本

    Kernel是Linux操作系统的核心部分.它由操作系统中用于管理存储器.文件.外设和系统资源的那些部分组成.Kernel是操作系统的核心,掌控着所有硬件设备的控制权. 内核就是系统上面的一个文件,这 ...

  2. 小世界网络模型代码 c 语言,新的小世界网络模型实现文本特征的提取方法与流程...

    本发明涉及语义网络技术领域,具体涉及新的小世界网络模型实现文本特征的提取方法. 背景技术: 目前常用的文本特征提取方法,包括词频-反文档频率方法-TF-IDF.信息增益方法.互信息等方法:TF-IDF ...

  3. 基于Yocto构建嵌入式Linux系统U-boot、kernel内核、rootfs文件系统

    前言 Yocto 是一个很强大的构建工具,其功能不仅仅是用来获取BSP源码和简单地编译源码,开发者还可以使用Yocto对其 开发板添加各种第三方开发库,而不需要每次重新从零开始编译源码,解决第三方依赖 ...

  4. [linux kernel] 内核下ksz8081驱动调试

    系统版本:Ubuntu18.04-64 编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 - ...

  5. 【鸿蒙OS开发入门】06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 启动init进程

    [鸿蒙OS开发入门]06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 一.head.S 启动start_kernel() 1.1 start_kernel() ...

  6. Linux系统编程:验证kernel内核缓存区大小->4096字节

    Linux系统编程:验证kernel内核缓存区大小->4096字节 李四老师 于 2018-04-04 00:40:04 发布 2778 收藏 2 分类专栏: [Linux编程] [C/C++编 ...

  7. linux 编译cgal,CGAL - 计算几何算法库

    What is CGAL CGAL是一个强大的开源的计算几何算法库,全称是:Computational Geometry Algorithm Library. 提供了诸如:2D凸包,3D凸包,三角化等 ...

  8. linux内核特征,Linux内核的特征

    Linux内核的特征 Linux是个人计算机和工作站上的Unix类操作系统.但是,它绝不是简化的Unix.相反,Linux是强有力和具有创新意义的Unix类操作系统.它不仅继承了Unix的特征,而且在 ...

  9. Linux内核学习(七):linux kernel内核启动(一):概述篇

    Linux内核学习(七):linux kernel内核启动(一):概述篇 这一篇让我们来大致的了解一下Linux内核的启动过程 这篇文章不涉及源码,重在让你知道这个linux内核的启动过程,源码详细的 ...

  10. arm linux 内核配置,嵌入式 Linux开发Kernel移植(二)——kernel内核配置和编译

    嵌入式 Linux开发Kernel移植(二)--kernel内核配置和编译 本文选择linux 2.6.35.7版本kernel进行实践. 一.linux kernel源码目录分析 Kbuild,Ke ...

最新文章

  1. postgresql 集群_谁说postgresql 没有靠谱的高可用(2)
  2. 加班最狠的城市竟然不是北京!
  3. php导出大量excel表,php导出大量数据到excel时,有哪些比较好的处理方法?
  4. Angular添加class的正确方式
  5. piccolo2d android,如何在Piccolo2D中打洞?
  6. 源码编译wget问题解决
  7. SQL 2005 字段备注获取
  8. 现代控制理论——状态、状态空间、状态空间描述
  9. atv320说明书_ATV320U30N4B 施耐德 ATV320通用变频器 说明书
  10. 计算机主板上常用的接口,电脑主板上接口怎么接 主板所有接口插线功能作用识别图解...
  11. from表单的作用、组成和用法
  12. 树莓派监测CPU温度
  13. FastAdmin 目录权限设置
  14. Linux操作系统主机名(hostname)简介
  15. 基于51单片机及DS18B20温度传感器数码管显示程序
  16. 结婚戒指为什么要带在无名指上
  17. LG5200 「USACO2019JAN」Sleepy Cow Sorting 树状数组
  18. 【技术向】VOT中的EAO是如何计算的
  19. 方差、标准差和均方根误差的区别总结
  20. Ubuntu 16.04中安装OpenCV 2.4.11

热门文章

  1. html中的布局方式,网页设计常见的5种布局方式
  2. 新pop账户服务器信息,添加 POP 账户
  3. gitl clone 拉去代码失败?
  4. 设置eMMC和DDR的工作频率
  5. 社会工程学工具集之钓鱼网站的制作
  6. vbox win10 分辨率_win10如何更改分辨率?
  7. OUTLOOK 下邮件如何以人,文件夹来分类inbox
  8. html5自动换行,html5文字自动换行怎么设置
  9. 物联网安全硬件修改系列-硬改
  10. C# DataGridView 冻结列或行