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…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...

Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...