CGAL5.4.1 边塌陷算法
目录
1、使用曲面网格的示例
2、使用默认多面体的示例
3、使用丰富多面体的示例
主要对1、使用曲面网格的示例 进行深度研究
CGAL编译与安装CGAL安装到验证到深入_cgal测试代码-CSDN博客
参考资料CGAL 5.4.5 - Triangulated Surface Mesh Simplification: User Manual
meshlab下载打开off文件MeshLab
1、使用曲面网格的示例
下面的例子说明了如何简化曲面网格。未指定的代价策略默认为 Lindstrom-Turk。
预览源文件 cube-meshed.off

stop_ratio 0.1代表只有之前10%的边量
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h>
#include <chrono>
#include <fstream>
#include <iostream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
namespace SMS = CGAL::Surface_mesh_simplification;
int main(int argc, char** argv)
{Surface_mesh surface_mesh;const std::string filename =CGAL::data_file_path(R"(C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\cube-meshed.off)");std::ifstream is(filename);if (!is || !(is >> surface_mesh)){std::cerr << "Failed to read input mesh: " << filename << std::endl;return EXIT_FAILURE;}if (!CGAL::is_triangle_mesh(surface_mesh)){std::cerr << "Input geometry is not triangulated." << std::endl;return EXIT_FAILURE;}std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();// In this example, the simplification stops when the number of undirected edges// drops below 10% of the initial countdouble stop_ratio = 0.1;SMS::Count_ratio_stop_predicate<Surface_mesh> stop(stop_ratio);int r = SMS::edge_collapse(surface_mesh, stop);std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now();std::cout << "\nFinished!\n" << r << " edges removed.\n" << surface_mesh.number_of_edges() << " final edges.\n";std::cout << "Time elapsed: " << std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count() << "ms" << std::endl;CGAL::IO::write_polygon_mesh(R"(C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\out.off)", surface_mesh, CGAL::parameters::stream_precision(17));return EXIT_SUCCESS;
}


2、使用默认多面体的示例
下面的示例展示了使用默认顶点、半边和面简化多面体_3 的过程。未指定的代价策略默认为 Lindstrom-Turk。
C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\small_cube.off 1000 C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\small_cube_out.off
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
// Simplification function
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
// Stop-condition policy
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef CGAL::Polyhedron_3<Kernel> Surface_mesh;
namespace SMS = CGAL::Surface_mesh_simplification;
int main(int argc, char** argv)
{Surface_mesh surface_mesh;const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/small_cube.off");std::ifstream is(filename);if (!is || !(is >> surface_mesh)){std::cerr << "Failed to read input mesh: " << filename << std::endl;return EXIT_FAILURE;}if (!CGAL::is_triangle_mesh(surface_mesh)){std::cerr << "Input geometry is not triangulated." << std::endl;return EXIT_FAILURE;}// This is a stop predicate (defines when the algorithm terminates).// In this example, the simplification stops when the number of undirected edges// left in the surface mesh drops below the specified number (1000)const std::size_t edge_count_treshold = (argc > 2) ? std::stoi(argv[2]) : 1000;SMS::Count_stop_predicate<Surface_mesh> stop(edge_count_treshold);// This the actual call to the simplification algorithm.// The surface mesh and stop conditions are mandatory arguments.// The index maps are needed because the vertices and edges// of this surface mesh lack an "id()" field.std::cout << "Collapsing edges of Polyhedron: " << filename << ", aiming for " << edge_count_treshold << " final edges..." << std::endl;int r = SMS::edge_collapse(surface_mesh, stop,CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)).halfedge_index_map(get(CGAL::halfedge_external_index, surface_mesh)));std::cout << "\nFinished!\n" << r << " edges removed.\n"<< (surface_mesh.size_of_halfedges() / 2) << " final edges.\n";std::ofstream os(argc > 3 ? argv[3] : "out.off");os.precision(17);os << surface_mesh;return EXIT_SUCCESS;
}

点和面一样
3、 使用丰富多面体的示例
下面的示例等同于上一个示例,但使用的是丰富多面体,其半边支持 id 字段,用于存储算法所需的边索引。
C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\small_cube.off 0.1 C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\small_cube_out.off
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
// Extended polyhedron items which include an id() field
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
// Setup an enriched polyhedron type which stores an id() field in the items
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Surface_mesh;
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Surface_mesh>::halfedge_descriptor halfedge_descriptor;
namespace SMS = CGAL::Surface_mesh_simplification;
int main(int argc, char** argv)
{Surface_mesh surface_mesh;const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/small_cube.off");std::ifstream is(filename);if (!is || !(is >> surface_mesh)){std::cerr << "Failed to read input mesh: " << filename << std::endl;return EXIT_FAILURE;}if (!CGAL::is_triangle_mesh(surface_mesh)){std::cerr << "Input geometry is not triangulated." << std::endl;return EXIT_FAILURE;}// The items in this polyhedron have an "id()" field// which the default index maps used in the algorithm// need to get the index of a vertex/edge.// However, the Polyhedron_3 class doesn't assign any value to// this id(), so we must do it here:int index = 0;for (halfedge_descriptor hd : halfedges(surface_mesh))hd->id() = index++;index = 0;for (vertex_descriptor vd : vertices(surface_mesh))vd->id() = index++;// In this example, the simplification stops when the number of undirected edges// drops below xx% of the initial countconst double ratio = (argc > 2) ? std::stod(argv[2]) : 0.1;SMS::Count_ratio_stop_predicate<Surface_mesh> stop(ratio);// The index maps are not explicitelty passed as in the previous// example because the surface mesh items have a proper id() field.// On the other hand, we pass here explicit cost and placement// function which differ from the default policies, ommited in// the previous example.std::cout << "Collapsing edges of mesh: " << filename << ", aiming for " << 100 * ratio << "% of the input edges..." << std::endl;int r = SMS::edge_collapse(surface_mesh, stop);std::cout << "\nFinished!\n" << r << " edges removed.\n"<< (surface_mesh.size_of_halfedges() / 2) << " final edges.\n";std::ofstream os((argc > 3) ? argv[3] : "out.off");os.precision(17);os << surface_mesh;return EXIT_SUCCESS;
}

主要对1、使用曲面网格的示例 进行深度研究
曲面网格简化是指在尽可能保留整体形状、体积和边界的前提下,减少曲面网格中使用的面的数量。它与细分相反。
本文介绍的算法可以使用一种称为 "边缘折叠 "的方法,简化任何具有任意数量连接组件、有或无边界(边界或孔)和手柄(任意种属)的定向 2-manifold曲面。粗略地说,这种方法包括用一个顶点迭代替换一条边,每次折叠删除 2 个三角形。
边的折叠优先级由用户提供的成本函数决定,替换顶点的坐标由另一个用户提供的放置函数决定。当满足用户提供的停止谓词(如达到所需的边数)时,算法终止。
这里实现的算法是通用的,因为它不要求曲面网格是特定类型的,而要求它是可变曲面图(MutableFaceGraph)和半边列表图(HalfedgeListGraph)概念的模型。我们给出了 Surface_mesh、Polyhedron_3 和 OpenMesh 的示例。
计算折叠成本和顶点位置的具体方法称为成本策略。用户可以选择不同的策略,以策略和相关参数的形式传递给算法。
当前版本的软件包提供了一组实现三种策略的策略:默认的 Lindstrom-Turk 策略、Garland-Heckbert 策略,以及由边长成本和可选的中点放置(速度更快,但精度较低)组成的策略。
文献[4]、[5]中介绍的策略的主要特点是,简化后的曲面网格在每一步都不会与原始曲面网格(或前一步的曲面网格)进行比较,因此无需保留额外的信息,如原始曲面网格或局部变化的历史记录。因此被称为无记忆简化。
与 Lindstrom-Turk 策略一样,[2] 中提出的 Garland-Heckbert 策略不将生成的网格与原始网格进行比较,也不依赖于局部变化的历史。相反,它通过为每个顶点分配四元矩阵来编码与原始网格的近似距离。
关键函数
/*
surface_mesh : 要简化的曲面网格
stop_predicate : 表示何时必须完成简化的策略
vertex_index_map(vimap):赋予每个顶点唯一整数索引的属性映射
edge_index_map(eimap):赋予每条边唯一整数索引的属性图
edge_is_constrained_map(ebmap):指定一条边是否为受约束边的属性图
get_cost(cf):计算折叠成本的函数对象
get_placement(pf):计算剩余顶点位置的函数对象
filter(filter):用于拒绝下一条折叠边的候选对象的函数对象
visitor(vis) : 跟踪简化过程的函数对象
*/
int r = edge_collapse(surface_mesh, stop_predicate、
CGAL::parameters::vertex_index_map(vimap)
.edge_index_map(eimap)
.edge_is_border_map(ebmap)
.get_cost(cf)
.get_placement(pf)
.filter(filter
.visitor(vis));

这里读取的数据是off文件,如果需要读取其他文件例如ply,obj则需要转换位Surface_mesh格式,先解析一下这个格式
Surface_mesh surface_mesh;const std::string filename = CGAL::data_file_path(R"(C:\chenqi\ThridParty\CGAL-5.4.3\data\meshes\bear.off)");std::ifstream is(filename);if (!is || !(is >> surface_mesh)){std::cerr << "Failed to read input mesh: " << filename << std::endl;return EXIT_FAILURE;}
- 下载的obj网站:Borderlands角色扮演 | 免费3D模型 | 专业3D扫描方案 (artec3d.cn)
读取obj进行网格简化,已经测试,这份代码只可以处理网格,不可以处理带纹理的
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/IO/OBJ.h>
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h>
#include <fstream>typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Surface_Mesh;
namespace SMS = CGAL::Surface_mesh_simplification;int main() {Surface_Mesh surface_mesh;std::string input_filename = R"(C:\Users\Administrator\Desktop\OBJ\borderlands_cosplay-obj\out.obj)"; // Replace with your input OBJ file pathstd::string output_filename = R"(C:\Users\Administrator\Desktop\OBJ\borderlands_cosplay-obj\out2.obj)"; // Replace with your desired output OBJ file path// Read the mesh from OBJ fileif (!CGAL::IO::read_polygon_mesh(input_filename, surface_mesh)) {std::cerr << "Failed to read input mesh: " << input_filename << std::endl;return EXIT_FAILURE;}// Perform edge collapse simplificationdouble stop_ratio = 0.5; // Adjust this ratio as neededSMS::Count_ratio_stop_predicate<Surface_Mesh> stop(stop_ratio);SMS::edge_collapse(surface_mesh, stop);// Write the simplified mesh to OBJ fileif (!CGAL::IO::write_polygon_mesh(output_filename, surface_mesh)) {std::cerr << "Failed to write output mesh: " << output_filename << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

至于实现纹理贴图自动更新,需要自己额外实现塌陷策略、停止的标准。目前代码是已经有一部分了,还需要完善,后续会更新。
在简化前记录纹理坐标:在开始网格简化之前,记录下每个顶点的纹理坐标。
自定义边缘坍塌操作:实现一个自定义的边缘坍塌策略,在边缘坍塌的同时更新相关顶点的纹理坐标。这可能涉及计算坍塌操作中涉及的顶点的新纹理坐标。
简化网格:使用自定义策略来简化网格。
输出简化后的网格和纹理坐标:在简化过程完成后,输出简化后的网格和更新后的纹理坐标到 OBJ 文件。
参考文章:网格简化 QEM 方法详解 - 知乎 (zhihu.com)
相关文章:
CGAL5.4.1 边塌陷算法
目录 1、使用曲面网格的示例 2、使用默认多面体的示例 3、使用丰富多面体的示例 主要对1、使用曲面网格的示例 进行深度研究 CGAL编译与安装CGAL安装到验证到深入_cgal测试代码-CSDN博客 参考资料CGAL 5.4.5 - Triangulated Surface Mesh Simplification: User Manual …...
网络安全知识和华为防火墙
网络安全 网络空间安全 ---Cyberspace 2003年美国提出的网络空间概念 ---一个由信息基础设施组成的互相依赖的网络。 我国官方文件定义:网络空间为继海、陆、空、天以外的第五大人类互动领域。 通信保密阶段 --- 计算机安全阶段 --- 信息系统安全 --- 网络空间安…...
Docker 搭建MySQL主从复制-读写分离
一. 介绍 MySQL主从复制是一种常用的数据库高可用性解决方案,通过在主数据库上记录的数据变更,同步到一个或多个从数据库,实现数据的冗余备份和读写分离。在Docker环境下搭建MySQL主从复制和读写分离,不仅方便管理,还…...
[linux] which和find有什么区别?
which 和 find 都是 Unix/Linux 系统中的命令,但它们的用途和工作方式有很大的不同。 which 命令:which 命令是用来查找并显示用户可以在当前环境下执行的命令的完整路径。这些命令通常位于 PATH 环境变量中指定的目录中。例如,which python …...
使用Neo4j做技术血缘管理
目录 一、neo4j介绍 二、windows安装启动neo4j 2.1下载neo4j 2.2 解压文件 2.3 启动neo4j 三、neo4j基础操作 3.1 创建结点和关系 3.2 查询 3.3 更改 3.4 删除 四、技术血缘Demo实现 4.1 构建节点对象 4.2 构建存储对象 4.3 创建有属性关联关系 4.4 最后是图结果…...
Unity-WebGL
问题:提示gzip压缩报错解决:关闭打包的地方压缩,如下图问题:窗口未全屏解决:使用百分比画布替换固定尺寸画布 参考:新版Unity打包Webgl端进行屏幕自适应_unity webgl分辨率自适应-CSDN博客问题:…...
腾讯云部署vue+node项目
文章目录 一、安装宝塔二、vue项目部署三、node项目部署 前言: 关于项目部署,一开始也是找了很多资料,费了点时间,所以记录一下。希望能对各位有所帮助。 一、安装宝塔 1.首先在控制台,进入云服务器的终端界面 2.输入命令和密码获取权限,并且安装宝塔界面 yum install -y w…...
HBase表结构
HBase是非关系型数据库,是高可靠性、高性能、面向列、可伸缩、实时读写的分布式数据库。 HBase使用场景 大规模数据存储:如日志记录、数据库备份等。实时数据访问:如实时搜索、实时分析等。高性能读写:如高并发、低延迟的读写操…...
本人面试积累面试题更新中
本人面试积累面试题 1.事务的隔离级别 答:2024年1月30日 1.读已提交-----读取其他事务已经提交的数据 2.读未提交-----读取其他事务还未提交的数据–可能出现脏读 3.可重复读-----同一个事务多次读取同一个数据,尽可能的保证数据的一致性但是可能出现幻读 4.串行读------确保每…...
[经典面试题]169. 多数元素
题目描述 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入:nums [3,2,3] 输出:3…...
Wireshark网络协议分析 - TCP协议
在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的TCP服务器与客户端2.2. Wireshark抓包分析2.3. 限制数据包的大小——MSS与MTU2.4. 保证TCP的有序传输——Seq,Len与Ack2.5. TCP头标志位——URG,ACK,PSH,RST&…...
3 款最好的电脑硬盘数据迁移软件
您将从本页了解 3 款最好的 SSD硬盘数据迁移软件,磁盘供应商提供的软件和可靠的第三方软件。仔细阅读本文并做出您的选择。 什么是数据迁移? 数据迁移是将数据移动到其他计算机或存储设备的过程。在日常工作活动中,常见的数据迁移有三种&…...
【Java之HTML】
HTML 概念 互联网的产生:w3c的成立, 互联网最开始设计的目的:看论文 ---->浏览器,HTML 网络三要素:HTML HTTP URL HTML描述论文的格式 HTTP标记这个论文在网络上怎么传输 URL:指示这个论文在互联网的哪…...
支付宝支付功能解析,从零到掌握,轻松享受便捷支付
目录 一、支付宝支付功能简介 1.1 支付宝支付的概念 1.2 支付宝支付的优势 1.3 支付宝支付的适用场景 二、支付宝支付的准备工作 三、支付宝支付的接入流程 四、支付宝支付的安全性 5.1 支付宝支付的安全机制 5.2 防范支付风险的措施 5.3 支付宝支付的安全技术保障 …...
MacOS安装反编译工具JD-GUI以及解决无法打开的问题
目录 一.下载地址 二.安装 三.问题 四.解决办法 1.显示包内容 2.找到Contents/MacOS/universalJavaApplicationStub.sh 3.修改sh文件 4.保存后再次打开即可 一.下载地址 Java Decompiler 二.安装 将下载下来的 jd-gui-osx-1.6.6.tar 解压,然后将 JD-GUI.a…...
SpringBoot将第三方的jar中的bean对象自动注入到ioc容器中
新建一个模块,做自动配置 config:需要准备两个类,一个自动配置类,一个配置类 CommonAutoConfig:此类用于做自动配置类它会去读取resoutces下的META-INF.spring下的org.springframework.boot.autoconfigure.AutoConfig…...
5.变量的解构赋值 - JS
什么是解构赋值 通过类似(或相同)的构型,将已知数据的元素/属性解构并提取出来,再赋值到相应变量,可以是新建的变量,也可以是已存在的变量/属性等;最常见的是数组和对象的解构赋值,…...
tableau添加形状
目录 1.效果:1.自带的形状:2.添加形状:小结: 1.效果: 1.自带的形状: 2.添加形状: 找到tableau的安装目录,点入 默认->形状 的文件夹: 新建一个文件夹: …...
(2)(2.10) LTM telemetry
文章目录 前言 1 协议概述 2 配置 3 带FPV视频发射器的使用示例 4 使用TCM3105的FSK调制解调器示例 前言 轻量级 TeleMetry 协议 (LTM) 是一种单向通信协议(从飞行器下行的数据链路),可让你以低带宽/低波特率(通常为 2400 波…...
工具推荐系列-极客编辑器(实时在线编写md文件同步GitHub)
工具项目地址:https://github.com/geekeditor/geekeditor-desktop-releases/tree/main 工具基础配置方法:https://www.geekeditor.com/workspace1.x.html 详细同步代码仓的方法可以用下面: 如何创建GitHub仓库 及生成获取AccessToken…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
