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 count
    double 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 count
    const 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 path
    std::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 file
    if (!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 simplification
    double stop_ratio = 0.5; // Adjust this ratio as needed
    SMS::Count_ratio_stop_predicate<Surface_Mesh> stop(stop_ratio);
    SMS::edge_collapse(surface_mesh, stop);

    // Write the simplified mesh to OBJ file
    if (!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;
}

至于实现纹理贴图自动更新,需要自己额外实现塌陷策略、停止的标准。目前代码是已经有一部分了,还需要完善,后续会更新。

  1. 在简化前记录纹理坐标:在开始网格简化之前,记录下每个顶点的纹理坐标。

  2. 自定义边缘坍塌操作:实现一个自定义的边缘坍塌策略,在边缘坍塌的同时更新相关顶点的纹理坐标。这可能涉及计算坍塌操作中涉及的顶点的新纹理坐标。

  3. 简化网格:使用自定义策略来简化网格。

  4. 输出简化后的网格和纹理坐标:在简化过程完成后,输出简化后的网格和更新后的纹理坐标到 OBJ 文件。

参考文章:网格简化 QEM 方法详解 - 知乎 (zhihu.com) 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

卡片式 UI 设计的 8 个秘诀,让你轻松打造高颜值界面

做卡片设计最重要的是什么&#xff1f;我将在这篇文章中分享 8 最关键的细节。在此之前&#xff0c;让我们一起来对付一下。 UI 梳理卡片设计的基础&#xff0c;总结哪些场景适合卡片设计。 卡片是 UI 其中一个组件元素可以创建一个清晰的视觉单元&#xff0c;使信息更具逻辑性…

expect 语言 Here Document 多行重定向

一、expect是什么 1.1 expect定义 是建立在tcl&#xff08;tool command language&#xff09;语言基础上的一个工具&#xff0c;常被用于进行自动化控制和测试&#xff0c;解决shell脚本中交互的相关问题 1.2 怎么安装expect yum install -y expect 进行安装 二、怎么使用e…

力扣hot100 电话号码的字母组合 回溯

Problem: 17. 电话号码的字母组合 文章目录 思路复杂度&#x1f49d; Code 思路 &#x1f468;‍&#x1f3eb; 参考题解 复杂度 时间复杂度: O ( 3 8 ) O(3^8) O(38) 空间复杂度: O ( 3 8 ) O(3^8) O(38) &#x1f49d; Code class Solution {String[] map { "…

实战项目(二)汽车保养管家系统

一、实现技术 前端技术&#xff1a;html、javascript(jquery、ajax、json)、css、layui 后端技术&#xff1a;java、mysql、servlet 开发工具&#xff1a;eclipse、vscode 二、项目描述 基于web的汽车保养管家系统的设计与实现 一、功能需求 1&#xff0e;用户功能 1.1…

《Pandas 简易速速上手小册》第1章:Pandas入门(2024 最新版)

文章目录 1.1 Pandas 简介1.1.1 基础知识1.1.2 案例&#xff1a;气候变化数据分析1.1.3 拓展案例一&#xff1a;金融市场分析1.1.4 拓展案例二&#xff1a;社交媒体情感分析 1.2 安装和配置 Pandas1.2.1 基础知识1.2.2 案例&#xff1a;个人财务管理1.2.3 拓展案例一&#xff1…

力扣 55.跳跃游戏

思路&#xff1a; 从后往前遍历&#xff0c;遇到元素为0时&#xff0c;记录对应的下标位置&#xff0c;再向前遍历元素&#xff0c;看最大的跳跃步数能否跳过0的位置&#xff0c;不能则继续往前遍历 代码&#xff1a; class Solution { public:bool canJump(vector<int>…

ip https证书多少钱

IP https证书是一种数字证书&#xff0c;用于在网络传输中保护数据的机密性和完整性。它通过使用SSL&#xff08;安全套接层&#xff09;协议&#xff0c;在客户端和服务器之间建立一条加密通道&#xff0c;确保数据在传输过程中不会被窃取或篡改。而IP https证书的价格和它的品…

基于springboot的视频点播系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

5G智慧钢铁厂数字孪生三维可视化,推进钢铁新型工业化数字化转型

5G智慧钢铁厂数字孪生三维可视化&#xff0c;推进钢铁新型工业化数字化转型。随着科技的不断发展&#xff0c;数字化转型已经成为钢铁企业转型升级的必经之路。而5G技术的广泛应用&#xff0c;为钢铁企业数字化转型提供了新的机遇。其中&#xff0c;5G智慧钢铁厂数字孪生三维可…

SpringCloud_学习笔记_1

SpringCloud01 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.0.学习目标 了解微服务架构的优缺点 1.1.单体架构 单体架构&#xff…

Android Studio 安装配置教程 - Windows版

Android Studio下载 安装&#xff1a; 下载&#xff1a; Android Studio Hedgehog | 2023.1.1 | Android Developers (google.cn) 安装&#xff1a; 基本不需要思考跟着走 默认下一步 默认下一步 自定义修改路径&#xff0c;下一步 默认下一步&#xff0c;不勾选 默认下一…

GEE移除landsat collection 1数据集

简介 大家好&#xff0c;我是锐多宝&#xff0c;今天刷twitter时&#xff0c;看到了这样一篇文章&#xff1a; Google earth engine宣布从 2024 年7月1日开始&#xff0c;将完全移除 Landsat Collection 1数据集&#xff0c;并推荐大家将使用Collection 1的代码改为使用Colle…

centOS+nodejs+mysql阿里云部署前后端个人网站

centOSnodejsmysql阿里云部署前后端个人网站 参考&#xff1a; 部署NodeExpressMySQL项目到阿里云轻量应用服务器 阿里云轻量应用服务器部署Node.jsReactMongoDB前后端分离项目 参考&#xff1a;在阿里云上部署nodejs服务 https 部署的原理就是你在本地测试的时候在地址栏&am…

使用Mysql实现Postgresql中窗口函数row_number的功能

1. 描述 需要根据用户id&#xff0c;查询每个人得分第二高的科目信息 2. 表结构及数据 2.1 表结构 CREATE TABLE t_score (id bigint(20) NOT NULL AUTO_INCREMENT,user_id bigint(20) NOT NULL,score double NOT NULL,subject varchar(100) NOT NULL,PRIMARY KEY (id) ) E…

知识库建设这些工具来帮忙,企业工作效率翻倍

在当今深度信息化的年代&#xff0c;知识库成了企业不可或缺的一部分&#xff0c;它的建设与管理显得格外重要。然而&#xff0c;想要建设又好又高效的知识库并非易事。好消息是&#xff0c;有很多优秀的工具可以让这个过程变得更加轻松&#xff0c;今天我们就重点来探讨其中的…

Vulnhub靶场DC-2

本机IP&#xff1a;192.168.223.128 目标IP&#xff1a;192.168.223.131 目标搜索&#xff1a;nmap -sP 192.168.223.1/24 端口搜索&#xff1a;nmap -sV -A -p- 192.168.223.131 开放了80 7744端口 访问一下web 发现进不去 目标ip被重定向到www.dc-2.com 修改一下本地DNS l…

【极数系列】Flink集成DataSource读取Socket请求数据(09)

文章目录 01 引言02 简介概述03 基于socket套接字读取数据3.1 从套接字读取。元素可以由分隔符分隔。3.2 windows安装netcat工具&#xff08;1&#xff09;下载netcat工具&#xff08;2&#xff09;安装部署&#xff08;3&#xff09;启动socket端口监听 04 源码实战demo4.1 po…

[网络安全]IIS---FTP服务器 、serverU详解

一 . FTP服务器(File Transfor Protocol) : 协议:文件传输协议 端口号:TCP: 20(数据) / 21(控制) 二 . FTP工作方式: 1.主动模式 : (FTP服务器21端口与FTP客户端产生的随机端口先建立连接 建立连接后,再使用FTP服务器21端口与FTP客户端创建的一个新的随机端口进行发送…

【lesson29】MySQL事务不同隔离级别之间的区别演示

文章目录 读未提交读提交可重复读串行化总结 读未提交 我们看到这时的隔离级别是读提交&#xff0c;那么我们就要把隔离级别改为&#xff0c;读未提交。 我们可以看到两个终端的mysql隔离级别已经都被改成了读未提交。 开始演示读未提交&#xff1a; 开启2个事务 事务2读…

【C++】STL之空间配置器(了解)

一、什么是空间配置器 空间配置器 &#xff0c;顾名思义就是为各个容器高效的管理空间&#xff08;空间的申请与回收&#xff09;的&#xff0c;在默默地工作。虽然在常规使用 STL 时&#xff0c;可能用不到它&#xff0c;但站在学习研究的角度&#xff0c;学习它的实现原理对…