[CGAL] CGAL的世界-Kernel内核、Traits特征类
文章目录
- 几何图元
- 谓词
- 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正是代表这个程序如何去对待精度问题。它可以是
double
:使用double精度Exact_predicates_exact_constructions_kernel
:精确谓词,且精确构造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;
}
运行的结果如下:
是不是很奇怪,第一个例子还是出错了。
分析:
- 第一个代码块中,这三个点仍然不是共线的。是因为它用文本传入的坐标,传入后变成了浮点数,转换成了任意精度的有理数时,它们仅表示浮点数,而可能不会精确的表示原来数值。
- 第二个代码块中。是从文件中读取数字,然后直接从字符串构造任意精度的有理数,以便它们能够精确的表示原来的数值。
- 在第三块中,中点是通过计算得出的,正如内核定义的那样,使用的是精确谓词,精确构造出来的,所以计算所得的精度是可以靠得住的(这便是第二种内核,精确构造、精确谓词的意思)
在许多情况中,就浮点数而言,它们是“精确的”,即它们是由某些应用程序计算或从传感器中获得的,是全精度的浮点数。它们不是文本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()函数有两种版本
- 一种即是上面所提到的,使用两个迭代器来规定输入点的范围,并使用一个输出迭代器来将凸包结果写入到结果容器中
template <class ForwardIterator, class OutputIterator>
inline
OutputIterator
convex_hull_2(ForwardIterator first, ForwardIterator last, OutputIterator result )
- 第二个版本具有两个附加参数,一个是模板参数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特征类相关推荐
- linux内核centos6.9,CentOS6.9手动编译并更新Kernel内核版本
Kernel是Linux操作系统的核心部分.它由操作系统中用于管理存储器.文件.外设和系统资源的那些部分组成.Kernel是操作系统的核心,掌控着所有硬件设备的控制权. 内核就是系统上面的一个文件,这 ...
- 小世界网络模型代码 c 语言,新的小世界网络模型实现文本特征的提取方法与流程...
本发明涉及语义网络技术领域,具体涉及新的小世界网络模型实现文本特征的提取方法. 背景技术: 目前常用的文本特征提取方法,包括词频-反文档频率方法-TF-IDF.信息增益方法.互信息等方法:TF-IDF ...
- 基于Yocto构建嵌入式Linux系统U-boot、kernel内核、rootfs文件系统
前言 Yocto 是一个很强大的构建工具,其功能不仅仅是用来获取BSP源码和简单地编译源码,开发者还可以使用Yocto对其 开发板添加各种第三方开发库,而不需要每次重新从零开始编译源码,解决第三方依赖 ...
- [linux kernel] 内核下ksz8081驱动调试
系统版本:Ubuntu18.04-64 编译器版本:gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot版本:2018.07 - ...
- 【鸿蒙OS开发入门】06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 启动init进程
[鸿蒙OS开发入门]06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 一.head.S 启动start_kernel() 1.1 start_kernel() ...
- Linux系统编程:验证kernel内核缓存区大小->4096字节
Linux系统编程:验证kernel内核缓存区大小->4096字节 李四老师 于 2018-04-04 00:40:04 发布 2778 收藏 2 分类专栏: [Linux编程] [C/C++编 ...
- linux 编译cgal,CGAL - 计算几何算法库
What is CGAL CGAL是一个强大的开源的计算几何算法库,全称是:Computational Geometry Algorithm Library. 提供了诸如:2D凸包,3D凸包,三角化等 ...
- linux内核特征,Linux内核的特征
Linux内核的特征 Linux是个人计算机和工作站上的Unix类操作系统.但是,它绝不是简化的Unix.相反,Linux是强有力和具有创新意义的Unix类操作系统.它不仅继承了Unix的特征,而且在 ...
- Linux内核学习(七):linux kernel内核启动(一):概述篇
Linux内核学习(七):linux kernel内核启动(一):概述篇 这一篇让我们来大致的了解一下Linux内核的启动过程 这篇文章不涉及源码,重在让你知道这个linux内核的启动过程,源码详细的 ...
- arm linux 内核配置,嵌入式 Linux开发Kernel移植(二)——kernel内核配置和编译
嵌入式 Linux开发Kernel移植(二)--kernel内核配置和编译 本文选择linux 2.6.35.7版本kernel进行实践. 一.linux kernel源码目录分析 Kbuild,Ke ...
最新文章
- postgresql 集群_谁说postgresql 没有靠谱的高可用(2)
- 加班最狠的城市竟然不是北京!
- php导出大量excel表,php导出大量数据到excel时,有哪些比较好的处理方法?
- Angular添加class的正确方式
- piccolo2d android,如何在Piccolo2D中打洞?
- 源码编译wget问题解决
- SQL 2005 字段备注获取
- 现代控制理论——状态、状态空间、状态空间描述
- atv320说明书_ATV320U30N4B 施耐德 ATV320通用变频器 说明书
- 计算机主板上常用的接口,电脑主板上接口怎么接 主板所有接口插线功能作用识别图解...
- from表单的作用、组成和用法
- 树莓派监测CPU温度
- FastAdmin 目录权限设置
- Linux操作系统主机名(hostname)简介
- 基于51单片机及DS18B20温度传感器数码管显示程序
- 结婚戒指为什么要带在无名指上
- LG5200 「USACO2019JAN」Sleepy Cow Sorting 树状数组
- 【技术向】VOT中的EAO是如何计算的
- 方差、标准差和均方根误差的区别总结
- Ubuntu 16.04中安装OpenCV 2.4.11