进入CGAL的世界

2023-11-03

进入CGAL的世界由四个小的主题组成:定义点和线段,以及对他们的简单操作,(这里要有一个重要的认识,就是计算机中的浮点数的使用会导致精度问题,这个也是计算机图形学的一个重要的问题);第二部分使用一个典型的CGAL函数,计算二维的凸包;第三部分介绍了一个特征(traits)类;第四部分定义了concept以及model的概念。

1.顶点和线段

#include <iostream>
#include <CGAL/Simple_cartesian.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
//定义二维的顶点
typedef Kernel::Segment_2 Segment_2;
//定义二维的线段
int main()
{
  Point_2 p(1,1), q(10,10);
  std::cout << "p = " << p << std::endl;
  std::cout << "q = " << q.x() << " " << q.y() << std::endl;
  //这里展示了访问顶点以及定点中的数据的方式
  std::cout << "sqdist(p,q) = "
            << CGAL::squared_distance(p,q) << std::endl;
            //计算两个顶点的距离
  Segment_2 s(p,q);
  Point_2 m(5, 9);
  std::cout << "m = " << m << std::endl;
  std::cout << "sqdist(Segment_2(p,q), m) = "
            << CGAL::squared_distance(s,m) << std::endl;
  //实际的结果显示这里是把s当成了一个顶点在处理
  std::cout << "p, q, and m ";
  switch (CGAL::orientation(p,q,m)){
  case CGAL::COLLINEAR:
    std::cout << "are collinear\n";
    break;
  case CGAL::LEFT_TURN:
    std::cout << "make a left turn\n";
    break;
  case CGAL::RIGHT_TURN:
    std::cout << "make a right turn\n";
    break;
  }
  //没错,这段代码就是在计算三个点是左旋,共线,还是右旋的,估计是计算向量叉乘的方式来实现的
  std::cout << " midpoint(p,q) = " << CGAL::midpoint(p,q) << std::endl;
  //计算两个顶点的中点
  return 0;
}

需要注意的地方:

  • CGAL使用的命名空间为CGAL,如果代码中无using namespace CGAL的话,需要使用前缀CGAL::来调用CGAL中的成员和函数。
  • CGAL中的类(例如Kernel)首字母大写,函数(例如sqdist())小写,常数(例如CGAL::COLLINEAR)全部大写,对象的维度(例如Point_2二维顶点)以后缀的方式体现。

接下来的两段代码显示了浮点数的使用造成的有悖于常识(精确的数学计算)的结果:

#include <iostream>
#include <CGAL/Simple_cartesian.h>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
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");
  }
  //结果是not collinear
  {
    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");
  }
  //结果是not collinear
  {
    Point_2 p(0,0), q(1, 1), r(2, 2);
    std::cout << (CGAL::collinear(p,q,r) ? "collinear\n" : "not collinear\n");
  }
  //结果是collinear
  return 0;
}
#include <iostream>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <sstream>
typedef CGAL::Exact_predicates_exact_constructions_kernel 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");
  }
  //结果是not collinear
  {
    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");
  }
  //结果是collinear
  {
    q = CGAL::midpoint(p,r);
    std::cout << (CGAL::collinear(p,q,r) ? "collinear\n" : "not collinear\n");
  }
  //结果是collinear
  return 0;
}

以上的两段代码就揭示了计算机几何处理中的一个重要的问题:就是浮点数的使用所导致的精度问题。在第一段代码中,由于舍入(rounding)误差的存在,分数没有在计算机中表示成完整精度的double,这样一来,在判定线性性是,行列式的计算会趋于零担不会是零,从而判定为非线性。为了解决这个问题,cgal设计了另一个精确计算的核(kernel) Exact_predicates_exact_constructions_kernel。
再看第二段代码的第一块内容,这个示例仍然被判定为非线性,这是因为在这个过程中,计算机是存在着一个转换的。点的位置在代码中表示为一个text,被计算机读入时会转换为float的形式,在计算时又会被转换为任意精度的有理数,这个有理数在浮点精度上是精确的,之后的位数是不精确的,就会导致这样的结果。而第二块代码是直接从输入流(文件)中读取的数据,这个数据是以string的格式读取的,会被精确的表达为text的数据。第三块中的中点是计算机计算所得,同样也是精确的。
通过上面的两个示例,基本上可以理解计算机几何中的精度问题了。精确计算,通常是最符合直觉的计算,但是,对于计算机而言,进行精确的计算并不像想象中的那样简单。此外,它会给计算机带来额外的内存以及算力上的消耗,所以并不一定要在所有的应用中进行精确的计算!

2.计算序列点的凸包

接下来的代码是计算一个点序列的凸包,原始的输入为一个点数组,输出为凸包的一个点数组

#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()
{
  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];
  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;
}

计算凸包的函数的第一个参数为点序列的起始点的位置,第二个参数为点序列的终止点的位置,第三个为存储输出的数组的起始位置,这个函数返回值指向最后写入的顶点的数组位置,所以ptr - result的值为凸包中的顶点个数。

#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;
//使用stl中的vector进行存储
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));
  CGAL::convex_hull_2( points.begin(), points.end(), std::back_inserter(result) );
  std::cout << result.size() << " points on the convex hull" << std::endl;
  return 0;
}

这段代码的基本上和上一段代码的意思是差不多的,只不过,使用了stl中的vevtor来存储输入和输出。需要注意的是第三个参数,这里不能直接用result.begin(),而是使用了一个由辅助函数std::back_inserter()产生的输出迭代器。这个是stl库关于算法与容器解耦思想的一个体现。

3.关于核以及特质类

#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;
typedef CGAL::Projection_traits_yz_3<K3> K;
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;
}

这段代码示意了如何去定义一个特质(traits)类,其中k()就是一个特质类,这个特性是专门为了模板编程而设计的。由于笔者对模板编程的理解尚浅,只能提一些简单的理解。
注意,这段代码的输入是键入顶点的形式,输出为打印的形式,函数计算的是三维的点投影到二维yz平面上的凸包的计算。输入的结尾应以ctrl+Z结束。例如可以键入:

0 0 0
0 10 0
0 10 10
0 6 5
0 4 1

ctrl+z,再enter即可输入计算。
回到对特质(traits)类的解读,展示convex_hull_2()的函数原型,这个原型可以通过查看函数定义的方式查看

template<class InputIterator , class OutputIterator , class Traits >
OutputIterator
convex_hull_2(InputIterator first,
              InputIterator beyond,
              OutputIterator result,
              const Traits & ch_traits)

要了解特质类是如何起作用的,那么首先要了解计算凸包的算法。考虑其中的一种可能是最为高效的简单算法,即“Graham/Andrew Scan”。该算法首先从左到右对点进行排序,然后通过从排序列表中一个接一个地添加一个点来逐步构建凸包。要做到这一点,它至少必须知道某种点类型,它应该知道如何对这些点进行排序,并且它必须能够评估三元组点的方向。那么对于,这个算法而言,它所提供的特质应当包括

  • Traits::Point_2
  • Traits::Less_xy_2
  • Traits::Left_turn_2
  • Triats::Equal_2

其中Point_2指的是算法处理的数据的形式,Less_xy_2和Equal_2是对顶点进行排序的依据,Left_turn_2是确定三个顶点方向的方法。
那么这里产生了两个问题:什么可以作为这个模板参数的参数?为什么要使用这个模板参数?
对于第一个问题,那就是需要了解这个模板参数都需要对哪些参数和方法进行定义,完整的定义了这些需要的参数即可成为该模板参数的参数。
对于第二个问题,最开始的那段代码就给出了原因,可以最大程度的复用代码。例如要在三维点的yz平面上计算凸包,只需要对traits进行修改即可实现。

4.概念和模型

概念是指对某种类型的的一组要求,它要有怎样的数据组织形式,有哪些成员函数等,模型是指具现了这些要求的一种类
例如

template <typename T>
T
duplicate(T t)
{
  return t;
}

这里的T就是一个概念,对于任何一个定义了拷贝函数的类,都是它的一个模型,又如

template <typename T>
T& std::min(const T& a, const T& b)
{
  return (a<b)?a:b;
}

这里的T也是一个概念,对于一个定义了(重载了)运算符<的类,都是它的一个模型。
这里的概念和模型实际上是对模板编程的一个解释,也是为了更好的理解CGAL中的函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

进入CGAL的世界 的相关文章

  • 如何在 C++ 中的文件末尾添加数据?

    我已按照网上的说明进行操作 此代码应该将输入添加到文件 数据库 的末尾 但当我检查时 数据会覆盖现有数据 请帮忙 这是我的代码 int main string name string address string handphone cou
  • 在 C# 中创建具有单独列的分隔文本

    我一直在尝试在 C 中创建一个制表符限制的文本文件 以便数据正确显示在单独的列中 Firstname Lastname Age John Smith 17 James Sawyer 31 我尝试过 t 字符 但我得到的只是 Firstnam
  • 如何使用MemoryCache代替Timer来触发一个方法?

    以下方法通过等待已运行操作的结果来处理并发请求 对数据的请求可能会使用相同 不同的凭据同时出现 对于每组唯一的凭据 最多可以有一个GetCurrentInternal呼叫正在进行中 当准备就绪时 该呼叫的结果将返回给所有排队的服务员 pri
  • 为 Visual Studio 2013 编译 Tesseract

    我正在尝试使用tesseract在 Visual Studio 2013 中 我在链接器 gt 输入 不是 libtesseract302 static lib 中使用 libtesseract302 lib 一切都正常 并且已编译并运行
  • 向 Nhibernate 发出 SQL 查询

    如何将此 SQL 查询发送给 Nhibernate SELECT Customer name FROM Company INNER JOIN Customer ON Company CompanyId Customer CompanyId
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • 如何访问另一个窗体上的ListView控件

    当单击与 ListView 所在表单不同的表单中的按钮时 我试图填充 ListView 我在 Form1 中创建了一个方法以在 Form2 中使用 并将参数传递给 Form1 中的方法 然后填充 ListView 当我调试时 我得到了传递的
  • C# Dns.GetHostEntry 不返回连接到 WiFi 的移动设备的名称

    我有一个 C 中的 Windows 窗体应用程序 我试图获取列表中所有客户端的主机名 下面给出的是 ra00l 来自此链接的代码示例 GetHostEntry 非常慢 https stackoverflow com questions 99
  • 使用 C 语言使用 strftime() 获取缩写时区

    我看过this https stackoverflow com questions 34408909 how to get abbreviated timezone and this https stackoverflow com ques
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • 如何使用 Mongodb C# 驱动程序连接多个集合

    我需要将 3 个集合与多个集合合并在一起 lookup我在 C 驱动程序中尝试过 它允许我 lookup用户采集但无法执行秒 lookup用于设置集合 有人可以帮忙吗 db Transactions aggregate lookup fro
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • Process.Start() 方法在什么情况下返回 false?

    From MSDN https msdn microsoft com en us library e8zac0ca v vs 110 aspx 返回值 true 表示有新的进程资源 开始了 如果由 FileName 成员指定的进程资源 St
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • 使用 GhostScript.NET 打印 PDF DPI 打印问题

    我在用GhostScript NET http ghostscriptnet codeplex com打印 PDF 当我以 96DPI 打印时 PDF 打印效果很好 但有点模糊 如果我尝试以 600DPI 打印文档 打印的页面会被极大地放大

随机推荐

  • 汽车行业数据备份有必要吗?

    随着电气化 智能化 网联化和数字化的突破性发展 汽车产业供应链进一步重新构筑 更多科技型企业 汽车供应商以不同形式加入到整车领域 促使中国汽车产业发展进入崭新阶段 在疫情挑战下逐步实现恢复和增长 在数字化时代的大趋势下 数据安全成为全球企业
  • 什么是过拟合和欠拟合,怎么解决?

    过拟合和欠拟合的解释 欠拟合是指模型在训练集 验证集和测试集上均表现不佳的情况 过拟合是指模型在训练集上表现很好 到了验证和测试阶段就很差 即模型的泛化能力很差 过拟合和欠拟合产生的原因 欠拟合 underfitting 模型复杂度过低 特
  • 青藤放飞“猎鹰”,主动防御又多一张牌

    点击上方关注我们 研习ATT CK 模拟安全攻防大战 这一切只要在牌桌上就能完成 在10月30日举行的青藤新品 全国巡展 北京站 现场 就进行了一场别开生面的青藤 首届ATT CK卡牌争霸赛 将专业的安全知识融入卡牌游戏 这个创意棒棒的 让
  • enumerate的用法

    for i data in enumerate trainloader 0 data里面包含图像数据 inputs tensor类型的 和标签 labels tensor类型 inputs labels data enumerate 用于可
  • L2TP and PPTP共存一键安装

    一 L2TP IPSec vpn一键安装脚本 运行下面的命令 wget no check certificate https raw githubusercontent com teddysun across master l2tp sh
  • 批量执行python程序文件

    如果想执行n个文件 不必一个一个点run 可以把要执行的文件放在同一个文件夹里 然后在一个文件里输入以下脚本即可 import os lst os listdir os getcwd 获取当前目录下所有的文件名 for c in lst i
  • BT656跟BT1120和BT709有什么区别

    如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额1元起步 多少随意 锋影 email 174176320 qq com 601是SDTV的数据结构 656是SDTV的interface709是HDTV的数据结构
  • 【OpenGL】笔记五、纹理

    1 流程 1 1 单个纹理 纹理是一个2D图片 甚至也有1D和3D的纹理 它可以用来添加物体的细节 为了能够使用纹理图片 我们需要一个叫做stb image h的头文件库来加载不同格式的图片作为纹理 全部文件 得到该头文件后 加入项目 并且
  • java使用2种方法操作liberoffice把word转pdf,pdf加水印,java远程调用Linux执行命令

    文章目录 libreoffice下载地址 安装 第一种 java调用 第二种 推荐 java调用Linux命令转pdf java远程连接Linux执行命令 少数情况 linux安装windows中文字体解决pdf乱码 pdf加水印 libr
  • Unity基础笔记(2)—— Unity2D及输入系统

    Unity2D及输入系统 Unity2D 部分 一 Unity 2D 介绍 1 游戏中 2D 3D 以及 UI 的概念 先笼统地将整个游戏分为两部分 UI 和游戏内容 UI 即 User Interface 人机交互 操作界面 游戏中一般指
  • 目标检测学习--FPN(特征金字塔网络)-解决多尺度检测问题

    论文地址 Feature Pyramid Networks for Object Detection 深度神经网络学习到的特征中 浅层特征学到的是物理信息 比如物体的角点 边缘的细节信息 而深层特征学到的是语义信息 更加高维与抽象 目标检测
  • vim编辑器显示行号 :set num

    set num
  • python自动化测试写日志self.logname = os.path.join(log_path, '{0}.log'.format(time.strftime('%Y-%m-%d')))

    coding utf 8 import logging import time import os from config import globaVar log path globaVar log path class Log def i
  • IntelliJ IDEA:多开窗口

    参考 https blog csdn net chehec2010 article details 84942967
  • Kubernetes集群——(k8s)service(一)+外部主机访问容器的多种方法+【flannel(vxlan)+calico+host-gw】跨主机通信网络插件

    一 service的简介 1 1Service可以看作是一组提供相同服务的Pod对外的访问接口 借助Service 应 用可以方便地实现服务发现和负载均衡 service默认只支持4层负载均衡能力 没有7层功能 可以通过Ingress实现
  • QT美化使用字体图标

    QT美化使用字体图标 准备字体图标资源 建立QT工程 工程增加字体图标资源文件 创建一个按钮控件 运行效果 准备字体图标资源 fontawesome下载地址 解压得到文件如下 建立QT工程 使用qtcreator创建mainwindow工程
  • 大模型论文周报丨清华大学、CMU、华盛顿大学、莱斯大学、亚马逊等机构前沿科研动态

    大模型又可以称为Foundation Model模型 模型通过亿级的语料或者图像进行知识抽取 学习进而生产了亿级参数的大模型 大模型的出现迎来了AI研究的新时代 其所带来的结果提升十分显著 超越了很多领域中针对研究问题设计特定算法实现的提升
  • Windows和CentOs下载ZLMediaKit

    Windows和CentOs下载ZLMediaKit 一 Window下载ZLMediaKit 首先前提是你在windows下载了git bash 一个windows下的终端 类似Linux 1 在git bash下输入以下命令 git c
  • 蓝桥算法题:拿金币

    问题描述 有一个N x N的方格 每一个格子都有一些金币 只要站在格子里就能拿到里面的金币 你站在最左上角的格子里 每次可以从一个格子走到它右边或下边的格子里 请问如何走才能拿到最多的金币 例 输入 3 1 3 3 2 2 2 3 1 2
  • 进入CGAL的世界

    进入CGAL的世界由四个小的主题组成 定义点和线段 以及对他们的简单操作 这里要有一个重要的认识 就是计算机中的浮点数的使用会导致精度问题 这个也是计算机图形学的一个重要的问题 第二部分使用一个典型的CGAL函数 计算二维的凸包 第三部分介