CGAL-3D 凸包算法

3D 凸包算法

  • 一、概述
  • 二、静态凸包构造
    • 1. Traits 特征类
    • 2. 极端点
    • 3. 半空间相交
    • 4. 凸性检验
  • 三、动态凸包构造
  • 四、性能

一、概述

在这里插入图片描述

一个点集 S∈R3 是凸的,如果对于任意两点 p 和 q 在集合中,具有端点的线段 p 和 q 包含在 S。集合的凸包 P 包含点集 S 的最小凸多边体。如果这个集合 S 的某些点是这个构成 P 凸多边体的顶点,则称其为(关于的)P的极值点。如果一个点集只包含极值点,就被称为强凸的

本章描述了CGAL中用于生成三维凸包的函数,以及用于检查点集是否为强凸的函数。在CGAL中,可以通过两种方式计算三维空间中点集的凸包:使用静态算法或使用三角剖分来获得完全动态的计算。

二、静态凸包构造

函数convex_hull_3()提供了quickhull算法[1]的一个实现。这个函数有两个版本,一个在已知输出是多面体(即超过三个点且不共线)时可用,另一个处理所有退化情况并返回一个对象,可能是一个点、一个线段、一个三角形或一个多面体。这两个版本都接受一个输入迭代器范围,该迭代器定义要计算凸包的点集,以及一个traits类,定义用于计算凸包的几何类型和谓词。

1. Traits 特征类

函数 convex_hull_3() 由一个traits类参数化,它指定了计算中使用的类型和几何基元。由于该函数从三个输入点构建3D平面,我们不能简单地将具有不精确结构的内核作为traits类的可选参数传递。

如果使用了来自具有精确谓词和非精确构造的内核的输入点,并且期望得到经过验证的结果,则应该使用类Convex_hull_traits_3 (R是输入内核)。如果内核的结构是精确的,那么该内核可以直接用作traits类。

注意,默认的traits类会考虑到这一点,即上述考虑只对自定义traits类重要。

下面的程序从输入文件中读取点,并计算它们的凸包。我们假设这些点并不都相同,也不都共线,因此我们直接使用多面体作为输出。在这个例子中,你可以看到凸包函数可以写在任何MutableFaceGraph概念的模型中。

例子1.

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/convex_hull_3.h>
#include <vector>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel  K;
typedef CGAL::Polyhedron_3<K>                     Polyhedron_3;
typedef K::Point_3                                Point_3;
typedef CGAL::Surface_mesh<Point_3>               Surface_mesh;
int main(int argc, char* argv[])
{std::ifstream in( (argc>1)? argv[1] : CGAL::data_file_path("points_3/cube.xyz"));std::vector<Point_3> points;Point_3 p;while(in >> p){points.push_back(p);}// define polyhedron to hold convex hullPolyhedron_3 poly;// compute convex hull of non-collinear pointsCGAL::convex_hull_3(points.begin(), points.end(), poly);std::cout << "The convex hull contains " << poly.size_of_vertices() << " vertices" << std::endl;Surface_mesh sm;CGAL::convex_hull_3(points.begin(), points.end(), sm);std::cout << "The convex hull contains " << num_vertices(sm) << " vertices" << std::endl;return 0;
}

例子2 :低维结果示例
下面的程序从输入文件中读取点,并计算它们的凸包。根据结果的尺寸,我们将得到一个点、一个线段、一个三角形或一个多面体曲面。注意,后者也可以是带边框的平面多边形。

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/convex_hull_3.h>
#include <vector>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel  K;
typedef CGAL::Polyhedron_3<K>                     Polyhedron_3;
typedef K::Point_3                                Point_3;
typedef K::Segment_3                              Segment_3;
typedef K::Triangle_3                             Triangle_3;
int main(int argc, char* argv[])
{std::ifstream in( (argc>1)? argv[1] : CGAL::data_file_path("points_3/cube.xyz"));std::vector<Point_3> points;Point_3 p;while(in >> p){points.push_back(p);}CGAL::Object obj;// compute convex hull of non-collinear pointsCGAL::convex_hull_3(points.begin(), points.end(), obj);if(const Point_3* p = CGAL::object_cast<Point_3>(&obj)){std::cout << "Point " << *p << std::endl;}else if(const Segment_3* s = CGAL::object_cast<Segment_3>(&obj)){std::cout << "Segment " << *s << std::endl;}else if(const Triangle_3* t = CGAL::object_cast<Triangle_3>(&obj)){std::cout << "Triangle " << *t << std::endl;}else  if(const Polyhedron_3* poly = CGAL::object_cast<Polyhedron_3>(&obj)){std::cout << "Polyhedron\n " << *poly << std::endl;std::cout << "The convex hull contains " << poly->size_of_vertices() << " vertices" << std::endl;}else {std::cout << "something else"<< std::endl;}return 0;
}

2. 极端点

除了 convex_hull_3() 函数外,还提供了函数 extreme_points_3(),用于只需要凸包上的点(不需要连通性信息)的情况。此外,还提供了traits类适配器CGAL::Extreme_points_traits_adapter_3,以获取索引或更一般地说,与凸包上的3D点相关联的任何给定实体。

下面的程序从一个OFF文件中读取一组点,并输出这些点在凸包上的索引。

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/convex_hull_3.h>
#include <CGAL/Extreme_points_traits_adapter_3.h>
#include <CGAL/IO/read_points.h>
#include <boost/iterator/counting_iterator.hpp>
#include <vector>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel      K;
typedef K::Point_3                                               Point_3;
int main(int argc, char* argv[])
{const std::string filename = (argc>1) ? argv[1] : CGAL::data_file_path("meshes/star.off");std::vector<Point_3> points;if(!CGAL::IO::read_points(filename, std::back_inserter(points))){std::cerr<< "Cannot open input file." <<std::endl;return 1;}//This will contain the extreme verticesstd::vector<std::size_t> extreme_point_indices;//call the function with the traits adapter for verticesCGAL::extreme_points_3(CGAL::make_range(boost::counting_iterator<std::size_t>(0),boost::counting_iterator<std::size_t>(points.size())),std::back_inserter(extreme_point_indices),CGAL::make_extreme_points_traits_adapter(CGAL::make_property_map(points)));//print the number of extreme verticesstd::cout << "Indices of points on the convex hull are:\n";std::copy(extreme_point_indices.begin(), extreme_point_indices.end(), std::ostream_iterator<std::size_t>(std::cout, " "));std::cout << "\n";return 0;
}

下面的程序从一个OFF文件中读取并构建一个网格,然后收集网格凸包上的顶点。

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Extreme_points_traits_adapter_3.h>
#include <CGAL/convex_hull_3.h>
#include <vector>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel      K;
typedef K::Point_3                                               Point_3;
typedef CGAL::Surface_mesh<Point_3>                              Mesh;
int main(int argc, char* argv[])
{const std::string filename = (argc>1) ? argv[1] : CGAL::data_file_path("meshes/star.off");Mesh sm;if(!CGAL::IO::read_polygon_mesh(filename, sm)){std::cerr<< "Cannot open input file." <<std::endl;return 1;}//This will contain the extreme verticesstd::vector<Mesh::Vertex_index> extreme_vertices;//call the function with the traits adapter for verticesCGAL::extreme_points_3(vertices(sm), std::back_inserter(extreme_vertices),CGAL::make_extreme_points_traits_adapter(sm.points()));//print the number of extreme verticesstd::cout << "There are  " << extreme_vertices.size() << " extreme vertices in this mesh." << std::endl;return 0;
}

3. 半空间相交

函数halfspace_intersection_3()和halfspace_intersection_with_constructions_3()使用凸包算法和对偶性来计算半空间列表的交集。第一个版本没有显式地计算对偶点:traits类会处理这个问题。第二种方法构造了这些点,因此鲁棒性较差,但计算速度较快。

为了计算交点,需要一个内点。它可以由用户给出,也可以用线性规划计算出来。请注意,由于线性规划的分辨率,第二种方法比较慢。

下面的例子计算切平面定义的半空间与球面的交点。

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Convex_hull_3/dual/halfspace_intersection_3.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Surface_mesh.h>
#include <list>
typedef CGAL::Exact_predicates_inexact_constructions_kernel   K;
typedef K::Plane_3                                            Plane;
typedef K::Point_3                                            Point;
typedef CGAL::Surface_mesh<Point>                             Surface_mesh;
// compute the tangent plane of a point
template <typename K>
typename K::Plane_3 tangent_plane (typename K::Point_3 const& p) {typename K::Vector_3 v(p.x(), p.y(), p.z());v = v / sqrt(v.squared_length());typename K::Plane_3 plane(v.x(), v.y(), v.z(), -(p - CGAL::ORIGIN) * v);return plane;
}
int main (void) {// number of generated planesint N = 200;// generates random planes on a spherestd::list<Plane> planes;CGAL::Random_points_on_sphere_3<Point> g;for (int i = 0; i < N; i++) {planes.push_back(tangent_plane<K>(*g++));}// define polyhedron to hold the intersectionSurface_mesh chull;// compute the intersection// if no point inside the intersection is provided, one// will be automatically found using linear programmingCGAL::halfspace_intersection_3(planes.begin(),planes.end(),chull );std::cout << "The convex hull contains " << num_vertices(chull) << " vertices" << std::endl;return 0;
}

4. 凸性检验

函数 is_strongly_convex_3() 实现了 Mehlhorn等人[2]的算法,用于判断给定多胞体的顶点是否构成强凸点集。该函数用于对 convex_hull_3() 进行后置条件测试。

三、动态凸包构造

Delaunay_triangulation_3 类可实现凸包的全动态维护。这个类支持插入和删除点(即三角剖分的顶点),凸包边只是无限面的有限边。下面的例子演示了凸包的动态构造。首先从一定半径的球面上随机生成点并插入到三角剖分中;然后通过统计与无限顶点相关的三角剖分顶点数得到凸包的点数;去掉一些点,然后确定船体上剩余的点的数量。请注意,与三角剖分的无限顶点相关的顶点都在凸包上,但可能不是所有的顶点都是凸包的顶点。

下面的例子展示了如何用三角剖分计算凸包。与无限大顶点相关的顶点在凸包上。

函数convex_hull_3_to_face_graph()可用于获得一个多面体曲面,它是MutableFaceGraph概念的模型,例如Polyhedron_3和Surface_mesh。

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/algorithm.h>
#include <CGAL/convex_hull_3_to_face_graph.h>
#include <list>
typedef CGAL::Exact_predicates_inexact_constructions_kernel     K;
typedef K::Point_3                                              Point_3;
typedef CGAL::Delaunay_triangulation_3<K>                       Delaunay;
typedef Delaunay::Vertex_handle                                 Vertex_handle;
typedef CGAL::Surface_mesh<Point_3>                             Surface_mesh;
int main()
{CGAL::Random_points_in_sphere_3<Point_3> gen(100.0);std::list<Point_3> points;// generate 250 points randomly in a sphere of radius 100.0// and insert them into the triangulationstd::copy_n(gen, 250, std::back_inserter(points));Delaunay T;T.insert(points.begin(), points.end());std::list<Vertex_handle>  vertices;T.incident_vertices(T.infinite_vertex(), std::back_inserter(vertices));std::cout << "This convex hull of the 250 points has "<< vertices.size() << " points on it." << std::endl;// remove 25 of the input pointsstd::list<Vertex_handle>::iterator v_set_it = vertices.begin();for (int i = 0; i < 25; i++){T.remove(*v_set_it);v_set_it++;}//copy the convex hull of points into a polyhedron and use it//to get the number of points on the convex hullSurface_mesh chull;CGAL::convex_hull_3_to_face_graph(T, chull);std::cout << "After removal of 25 points, there are "<< num_vertices(chull) << " points on the convex hull." << std::endl;return 0;
}

四、性能

下面,我们比较两种方法计算3D凸包的运行时间。对于静态版本(使用convex_hull_3())和动态版本(使用Delaunay_triangulation_3和convex_hull_3_to_face_graph()),使用的内核是Exact_predicates_inexact_constructions_kernel。

对于计算单位球中一百万个随机点的凸包,静态方法需要1.63s,而动态方法需要9.50s。要计算图13.1中192135个点的模型的凸包,静态方法需要0.18s,而动态方法需要1.90s。

在Linux (Debian发行版)下,使用GNU c++编译器4.3.5版本的CGAL 3.9执行测量,编译选项为-O3 -DCGAL_NDEBUG。使用的计算机配备了64位英特尔Xeon 2.27GHz处理器和12GB RAM。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GADM 4.1 全球国家行政区划下载

扫描文末二维码&#xff0c;关注微信公众号&#xff1a;ThsPool 后台回复g004&#xff0c;领取最新 GADM 4.1 全球国家行政区划 GADM概述 GADM&#xff0c;全称 Database of Global Administrative Areas&#xff0c;是一个开放获取的全球行政区划数据库&#xff0c;包含各国、…

APIfox编排自动化测试场景(一)

测试场景用于将多个接口请求与实际可能发生的一些特殊情况&#xff08;如条件判断、循环&#xff09;有序的组合在一起&#xff0c;来模拟一个真实业务流程&#xff0c;组成自动化测试单元。 新建目录 / 测试场景​ 打开 Apifox 后点击左侧菜单栏中的“自动化测试”&#xff…

基于Vue的移动端UI框架整理

一、Vant 官方地址&#xff1a;https://youzan.github.io/vant/#/zh-CN/ 简介&#xff1a;有赞公司开发。 特性&#xff1a;60 高质量组件、90% 单元测试覆盖率、完善的中英文文档和示例、支持按需引入、支持主题定制、支持国际化、支持 TS、支持 SSR。 特别说明&#xff1…

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)

1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据&#xff08;例如训练样本&#xff09;对感兴趣的未知变量&#xff08;例如类别标 记&#xff09;进行估计和推测。概率模型&#xff08;probabilistic model&#xff09;提供了一种描述框架&#xff0c;将描述任…

R语言阈值效应函数cut.tab2.0版发布(支持线性回归、逻辑回归、cox回归,自定义拐点)

阈值效应和饱和效应是剂量-反应关系中常见的两种现象。阈值效应是指当某种物质的剂量达到一定高度时&#xff0c;才会对生物体产生影响&#xff0c;而低于这个剂量则不会产生影响。饱和效应是指当某种物质的剂量达到一定高度后&#xff0c;其影响不再随剂量的增加而增加&#x…

编译DuiLib库遇到的变量定义位置问题

C89 规定&#xff0c;所有局部变量都必须定义在函数开头&#xff0c;在定义好变量之前不能有其他的执行语句&#xff1b; C99 标准取消这这条限制&#xff0c;但是 VC/VS 对 C99 的支持不是很积极&#xff1b; C99 是 C89 的升级版&#xff1b; 如图是修改之后的代码&#xff1…

AI专题:海外科技巨头指引,AI主线逻辑依旧坚挺

今天分享的是AI 系列深度研究报告&#xff1a;《AI专题&#xff1a;海外科技巨头指引&#xff0c;AI主线逻辑依旧坚挺》。 &#xff08;报告出品方&#xff1a;华西证券&#xff09; 报告共计&#xff1a;54页 本周热点:海外科技巨头指引&#xff0c;AI主线逻辑依旧坚挺 硬件…

介绍docker

一&#xff1a;介绍docker&#xff1a; Docker 并没有单独的图形界面&#xff0c;它主要通过命令行来进行管理和操作 1、 docker ps&#xff1a;显示正在运行的容器。 docker images&#xff1a;显示本地的镜像。 docker run&#xff1a;创建并启动一个新容器。 docker stop&a…

高速接口PCB布局指南(二)通用高速信号布线

高速接口PCB布局指南&#xff08;二&#xff09;通用高速信号布线 1.PCB材料编织2.高速信号布线长度3.高速信号布线长度匹配4.高速信号参考平面 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 1.PCB材料编织 在常见的 PCB 材料上为差分信号布线时&#xff0c;…

Java笔记 --- 六、IO流

六、IO流 概述 分类 纯文本文件&#xff1a;Windows自带的记事本打开能读懂的 eg&#xff1a;txt文件&#xff0c;md文件&#xff0c;xml文件&#xff0c;lrc文件 IO流体系 字节流 FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写到本地文件中…

如何进行游戏服务器的负载均衡和扩展性设计?

​在进行游戏服务器的负载均衡和扩展性设计时&#xff0c;需要考虑多个方面&#xff0c;以确保服务器的稳定性和可扩展性。以下是一些关键的步骤和考虑因素&#xff1a; 负载均衡的需求分析 在进行负载均衡设计之前&#xff0c;需要深入了解游戏服务器的负载特性和需求。这包括…

2024.2.5 vscode连不上虚拟机,始终waiting for server log

昨天还好好的&#xff0c;吃着火锅&#xff0c;做着毕设&#xff0c;突然就被vscode给劫了。 起初&#xff0c;哥们跟着网上教程有模有样地删除了安装包缓存&#xff0c;还删除了.vscode-server&#xff0c;发现没卵用&#xff0c;之前都是搜那个弹窗报错。 后来发现原来是vsco…

mac检查CPU温度和风扇速度软件:Macs Fan Control Pro 1.5.17中文版

Macs Fan Control Pro for Mac是一款专业的电脑风扇控制工具&#xff0c;旨在帮助Mac用户有效控制电脑的风扇速度&#xff0c;提高电脑的运行效率和稳定性。 软件下载&#xff1a;Macs Fan Control Pro 1.5.17中文版 该软件支持多种风扇控制模式和预设方案&#xff0c;用户可以…

三层交换组网实验(思科)

华为设备参考&#xff1a;三层交换组网实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 三层交换技术的出现&#xff0c;解决子网必须依赖路由器进行管理的问题&#xff0c;解决传统路由器低速、复杂所造成的网络瓶颈问题。一个具有三层交换功能的设备可简单理解为…

Zephyr NRF7002 实现AppleJuice

BLE的基础知识 ble的信道和BR/EDR的信道是完全不一样的。但是范围是相同的&#xff0c;差不多也都是2.4Ghz的频道。可以简单理解为空中有40个信道0~39信道。两个设备在相同的信道里面可以进行相互通信。 而这些信道SIG又重新编号&#xff1a; 这个编号就是把37 38 39。 3个信道…

杨中科 配置系统

1、配置系统入门 说明 1、传统Web.config配置的缺点&#xff0c;之前DI讲到过 2、为了兼容&#xff0c;仍然可以使用Web.config和ConfigurationManager类&#xff0c;但不推荐。 3、.NET 中的配置系统支持丰富的配置源&#xff0c;包括文件(json、xml、ini等)、注册表、环境变…

OpenCV/C++:点线面相关计算(二)

接续&#xff0c;继续更新 OpenCV/C:点线面相关计算_线面相交的点 代码计算-CSDN博客文章浏览阅读1.6k次&#xff0c;点赞2次&#xff0c;收藏12次。OpenCV处理点线面的常用操作_线面相交的点 代码计算https://blog.csdn.net/cd_yourheart/article/details/125626239 目录 1、…

Unity_修改天空球

Unity_修改天空球 Unity循序渐进的深入会发现可以改变的其实很多&#xff0c;剖开代码逻辑&#xff0c;可视化的表现对于吸引客户的眼球是很重要的。尤其对于知之甚少的客户&#xff0c;代码一般很难说服客户&#xff0c;然表现确很容易。 非代码色彩通才&#xff0c;持续学习…

STM32F1 引脚重映射功能

STM32 端口引脚重映射 文章目录 STM32 端口引脚重映射前言1、查阅芯片数据手册1.1 串口引脚重映射描述 2、代码部分2.1 核心代码部分 3、实验现象4、总结 前言 在写程序时遇到想要的端口功能&#xff0c;而这个引脚又被其它的功能占用了无法删除掉或直接使用&#xff0c;这种情…

蓝桥杯----凑算式

这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。 比如: 68/3952/714 就是一种解法, 53/1972/486 是另一种解法. 这个算式一共有多少种解法? 注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。