【CGAL系列】---Mesh修复

很高兴在雪易的CSDN遇见你 

VTK技术爱好者 QQ:870202403


前言

本文分享CGAL中关于Mesh修复问题,希望对各位小伙伴有所帮助!

感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!

你的点赞就是我的动力(^U^)ノ~YO


目录

前言

1. 多边形集合(Polygon Soup)修复

2. Stitch(拼接)

3. 多边形网格(Polygon Mesh)流形

4. 边界循环中的重复顶点

5. 几何修复

结论:


1. 多边形集合(Polygon Soup)修复

        多边形集合(Polygon Soup)是一个多边形网格(Polygon Mesh)中的所有面已知,但连接性未知的面集合。多边形集合(Polygon Soup)在执行任何算法之前必须确保多边形的方向一致(CGAL::Polygon_mesh_processing::orient_polygon_soup()实现)。

        多边形集合(Polygon Soup)和多边形网格(Polygon Mesh)之间的转化为:

        CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()

        CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup()

参考样例为:Polygon_mesh_processing_Examples中的repair_polygon_soup_example.

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>#include <algorithm>
#include <array>
#include <iostream>
#include <vector>typedef CGAL::Exact_predicates_inexact_constructions_kernel     K;
typedef K::FT                                                   FT;
typedef K::Point_3                                              Point_3;typedef CGAL::Surface_mesh<Point_3>                             Mesh;typedef std::array<FT, 3>                                       Custom_point;
typedef std::vector<std::size_t>                                CGAL_Polygon;namespace PMP = CGAL::Polygon_mesh_processing;struct Array_traits
{struct Equal_3{bool operator()(const Custom_point& p, const Custom_point& q) const {return (p == q);}};struct Less_xyz_3{bool operator()(const Custom_point& p, const Custom_point& q) const {return std::lexicographical_compare(p.begin(), p.end(), q.begin(), q.end());}};Equal_3 equal_3_object() const { return Equal_3(); }Less_xyz_3 less_xyz_3_object() const { return Less_xyz_3(); }
};int main(int, char**)
{// First, construct a polygon soup with some problemsstd::vector<std::array<FT, 3> > points;std::vector<CGAL_Polygon> polygons;points.push_back(CGAL::make_array<FT>(0,0,0));points.push_back(CGAL::make_array<FT>(1,0,0));points.push_back(CGAL::make_array<FT>(0,1,0));points.push_back(CGAL::make_array<FT>(-1,0,0));points.push_back(CGAL::make_array<FT>(0,-1,0));points.push_back(CGAL::make_array<FT>(0,1,0)); // duplicate pointpoints.push_back(CGAL::make_array<FT>(0,-2,0)); // unused pointCGAL_Polygon p;p.push_back(0); p.push_back(1); p.push_back(2);polygons.push_back(p);// degenerate facep.clear();p.push_back(0); p.push_back(0); p.push_back(0);polygons.push_back(p);p.clear();p.push_back(0); p.push_back(1); p.push_back(4);polygons.push_back(p);// duplicate face with different orientationp.clear();p.push_back(0); p.push_back(4); p.push_back(1);polygons.push_back(p);p.clear();p.push_back(0); p.push_back(3); p.push_back(5);polygons.push_back(p);// degenerate facep.clear();p.push_back(0); p.push_back(3); p.push_back(0);polygons.push_back(p);p.clear();p.push_back(0); p.push_back(3); p.push_back(4);polygons.push_back(p);// pinched and degenerate facep.clear();p.push_back(0); p.push_back(1); p.push_back(2); p.push_back(3);p.push_back(4); p.push_back(3); p.push_back(2); p.push_back(1);polygons.push_back(p);std::cout << "Before reparation, the soup has " << points.size() << " vertices and " << polygons.size() << " faces" << std::endl;PMP::repair_polygon_soup(points, polygons, CGAL::parameters::geom_traits(Array_traits()));std::cout << "After reparation, the soup has " << points.size() << " vertices and " << polygons.size() << " faces" << std::endl;Mesh mesh;PMP::orient_polygon_soup(points, polygons);PMP::polygon_soup_to_polygon_mesh(points, polygons, mesh);std::cout << "Mesh has " << num_vertices(mesh) << " vertices and " << num_faces(mesh) << " faces" << std::endl;assert(num_vertices(mesh) == 5);assert(num_faces(mesh) == 4);return 0;
}

 

2. Stitch(拼接)

        在处理多边形网格(Polygon Mesh)时,网格可能会出现多个重复的边和顶点的情况。对于这些边和顶点,网格的连通性是不完整的。可以通过Stitch(拼接)多边形网格的边界来修复一些重复数据。主要包括两个主要步骤:首先检测并配对几何上相同但重复的边界边缘。然后将它们“拼接”在一起,以便从网格中删除重复的边和顶点,并且这些剩余的边中每一个都恰好入射到两个面上。

        注:输入网格应该是流形的,否则不能保证拼接成功。

参考样例为:Polygon_mesh_processing_Examples中的stitch_borders_example。

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>#include <iostream>
#include <string>typedef CGAL::Exact_predicates_inexact_constructions_kernel   K;
typedef CGAL::Polyhedron_3<K>                                 Polyhedron;namespace PMP = CGAL::Polygon_mesh_processing;int main(int argc, char* argv[])
{const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/quads_to_stitch.off");Polyhedron mesh;if(!PMP::IO::read_polygon_mesh(filename, mesh)){std::cerr << "Invalid input." << std::endl;return 1;}std::cout << "Before stitching : " << std::endl;std::cout << "\t Number of vertices  :\t" << mesh.size_of_vertices() << std::endl;std::cout << "\t Number of halfedges :\t" << mesh.size_of_halfedges() << std::endl;std::cout << "\t Number of facets    :\t" << mesh.size_of_facets() << std::endl;PMP::stitch_borders(mesh);std::cout << "Stitching done : " << std::endl;std::cout << "\t Number of vertices  :\t" << mesh.size_of_vertices() << std::endl;std::cout << "\t Number of halfedges :\t" << mesh.size_of_halfedges() << std::endl;std::cout << "\t Number of facets    :\t" << mesh.size_of_facets() << std::endl;CGAL::IO::write_polygon_mesh("mesh_stitched.off", mesh, CGAL::parameters::stream_precision(17));return 0;
}

3. 多边形网格(Polygon Mesh)流形

        可以使用函数 检测非流形顶点。该函数可用于尝试通过将任何非流形顶点拆分为与此几何位置处的流形片数量相同的顶点来创建组合流形曲面网格。但请注意,从几何角度来看,网格仍然不是流形的,因为在非流形顶点处引入的新顶点的位置与输入的非流形顶点相同。CGAL::Polygon_mesh_processing::is_non_manifold_vertex()CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()

        参考样例为:Polygon_mesh_processing_Examples中的manifoldness_repair_example。

 

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>#include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>#include <CGAL/boost/graph/iterator.h>#include <iostream>
#include <iterator>
#include <string>
#include <vector>namespace PMP = CGAL::Polygon_mesh_processing;
namespace NP = CGAL::parameters;typedef CGAL::Exact_predicates_inexact_constructions_kernel          K;
typedef CGAL::Surface_mesh<K::Point_3>                               Mesh;typedef boost::graph_traits<Mesh>::vertex_descriptor                 vertex_descriptor;
typedef boost::graph_traits<Mesh>::halfedge_descriptor               halfedge_descriptor;void merge_vertices(vertex_descriptor v_keep, vertex_descriptor v_rm, Mesh& mesh)
{std::cout << "merging vertices " << v_keep << " and " << v_rm << std::endl;for(halfedge_descriptor h : CGAL::halfedges_around_target(v_rm, mesh))set_target(h, v_keep, mesh); // to ensure that no halfedge points at the deleted vertexremove_vertex(v_rm, mesh);
}int main(int argc, char* argv[])
{const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/blobby.off");Mesh mesh;if(!PMP::IO::read_polygon_mesh(filename, mesh) || CGAL::is_empty(mesh)){std::cerr << "Invalid input." << std::endl;return 1;}// Artificially create non-manifoldness for the sake of the example by merging some verticesvertex_descriptor v0 = *(vertices(mesh).begin());vertex_descriptor v1 = *(--(vertices(mesh).end()));merge_vertices(v0, v1, mesh);// Count non manifold verticesint counter = 0;for(vertex_descriptor v : vertices(mesh)){if(PMP::is_non_manifold_vertex(v, mesh)){std::cout << "vertex " << v << " is non-manifold" << std::endl;++counter;}}std::cout << counter << " non-manifold occurrence(s)" << std::endl;// Fix manifoldness by splitting non-manifold verticesstd::vector<std::vector<vertex_descriptor> > duplicated_vertices;std::size_t new_vertices_nb = PMP::duplicate_non_manifold_vertices(mesh,NP::output_iterator(std::back_inserter(duplicated_vertices)));std::cout << new_vertices_nb << " vertices have been added to fix mesh manifoldness" << std::endl;for(std::size_t i=0; i<duplicated_vertices.size(); ++i){std::cout << "Non-manifold vertex " << duplicated_vertices[i].front() << " was fixed by creating";for(std::size_t j=1; j<duplicated_vertices[i].size(); ++j)std::cout << " " << duplicated_vertices[i][j];std::cout << std::endl;}return EXIT_SUCCESS;
}

4. 边界循环中的重复顶点

         多边形网格(Polygon Mesh)中可能存在的另一个问题是出现“捏”孔,即当从边界半边开始并沿该边界的半边行走时,几何位置在再次到达初始边界半边之前出现不止一次(尽管具有不同的顶点)。合并相同位置顶点的函数 和 可用于修复此配置。CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()

5. 几何修复

        由几乎共线点组成的网格的三角形面是形状不好的元素,在网格中可能不希望有。该函数允许删除此类元素,并使用用户定义的参数来限定几乎意味着什么 ( 和 )。由于一些形状不好的元素是不可避免的(例如,在顶部和底部圆上只有顶点的长圆柱体的三角测量),因此可以传递额外的参数来防止删除此类元素 ( 和 )。CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()cap_thresholdneedle_thresholdcollapse_length_thresholdflip_triangle_height_threshold

 

结论:

感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步!

你的赞赏是我的最最最最大的动力(^U^)ノ~YO

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

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

相关文章

Elasticsearch--Master选举

角色 主节点&#xff08;active master&#xff09;&#xff1a;一般指的是活跃的主节点&#xff0c;避免负载任务&#xff0c;主节点主要用来管理集群&#xff0c;专用master节点仍将充当协调节点 候选节点&#xff08;master-eligible nodes&#xff09;&#xff1a;默认具备…

图形化编程:以Scratch引领少儿编程思维启蒙之旅

在21世纪科技飞速发展的今天&#xff0c;编程教育已经成为培养未来人才的重要途径。而“少儿编程”这一概念的提出&#xff0c;正是为了让孩子们从小接触并理解计算机逻辑&#xff0c;锻炼他们的创新思维与问题解决能力。其中&#xff0c;图形化编程以其直观易懂、趣味性强的特…

ElasticSearch分布式搜索引擎(两万字详解)

文章目录 ElasticSearch分布式搜索引擎1.了解ESELK技术栈elasticsearch和lucene为什么不是其他搜索技术&#xff1f;总结倒排索引正向索引倒排索引正向和倒排 es的一些概念文档和字段索引和映射mysql与elasticsearch 2.安装elasticsearch1.部署单点es1.1.创建网络1.2.拉取镜像1…

【C语言基础】01环境安装 Windows下的CLion开发环境的安装

资源:放在评论区中 下载编译器mingw64 把压缩包拖拽到C盘根目录,一键解压压缩包,得到文件夹mingw64 安装CLion开发环境 点击CLion.exe,运行安装程序路径为默认安装,如需更改,注意路径中不要带有中文. Installation Options 全部勾选选择<我想要之后重启电脑>点击CLion…

自动生成批量验证码用于RPA组件测试的方法

许多人工智能和RPA公司致力于开发能够识别验证码的组件&#xff0c;以便在自动化操作中处理通过网页和App弹出的验证码验证&#xff0c;从而完成后续的自动化流程。作为从事人工智能行业的专业人士&#xff0c;在测试过程中通常需要搜集大量验证码素材&#xff0c;以评估验证码…

Linux学习记录——삼십팔 网络层IP协议

文章目录 1、了解IP协议2、IP协议报文1、8位服务类型2、16位总长度&#xff08;字节数&#xff09;3、8位生存时间&#xff08;TTL&#xff09; 3、网段划分1、网段划分和CIDR方案2、子网划分简单方法3、IP地址问题的解决方案 4、公网内网1、内网分配2、运营商管理方法 5、路由…

C++力扣题目669--修剪二叉搜索树

给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&#xff0c;原有的父代子代关系都应当保留)。…

Uncaught ReferenceError: videojs is not defined

项目场景&#xff1a; 项目背景&#xff1a; 开发 vue 项目时&#xff0c;调试时浏览器前端控制台 出现红色 报错信息&#xff1a; Uncaught ReferenceError: videojs is not defined 问题描述 遇到的问题&#xff1a; 开发 vue 项目时&#xff0c; 浏览器控制台出现如下所…

【Linux】shell 脚本入门详解

一、shell入门简介 1.1什么是shell # 什么是shell网上有很多shell的概念介绍&#xff0c;其实都很官方化&#xff0c;如果你对linux命令很熟悉&#xff0c;那么编写shell就不是一个难事&#xff0c;shell本质上是linux命令&#xff0c;一条一条命令组合在一起&#xff0c;实现…

如何通过内网穿透实现公网访问Portainer管理监控Docker容器

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风…

Win10专业版系统搭建DNS解析服务

Win10专业版 纯新手&#xff0c;也没弄过Linux的。不喜勿喷&#xff0c;有问题请指出 第一天一头雾水整了几个小时没结果&#xff0c;第二天豁然开朗&#xff0c;10分钟明白了第一天的问题所在。 Win10 安卓&#xff1a; iOS&#xff1a; 搭建DNS服务器的意义&#xff1a; 屏蔽…

MyBatis-Plus 入门指南:安装与配置、代码生成、综合案例、主键生成策略、自动填充

目录 1.MyBatis-Plus介绍 1.1.简介 1.2.特性 1.3.结构 1.4.支持数据库 2.快速开始 3.安装与配置 4.代码生成 5.综合案例 5.1.主键生成策略 5.2.自动填充 1.MyBatis-Plus介绍 1.1.简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&…

写点东西《 Kickstart:搭建 JS 项目的最快方式!》

写点东西《&#x1f680; Kickstart&#xff1a;搭建 JS 项目的最快方式&#xff01;》 如何使用它&#xff1f; 想象一下&#xff1a;你刚刚有一个新的项目创意&#xff0c;你对创意充满热情&#xff0c;并准备好编码。 但是&#xff0c;在实际编写代码之前&#xff0c;您必须…

解决jmeter响应乱码的问题

HTTP请求响应乱码 方法一&#xff1a;添加后置处理器BeanShell PostProcessor&#xff0c;写入【prev.setDataEncoding("utf-8")】 方法二&#xff1a;修改bin目录下的配置文件jmeter.properties&#xff0c;将配置修改为【sampleresult.default.encodingUTF-8】 J…

2024年如何成为技术创作KOL?| 分享抽龙年公仔

引言 2024 年已经到来&#xff0c;你年初的 Flag 立好了吗&#xff1f;今年要创作多少篇文章&#xff1f;要如何获得更大的影响力&#xff1f;如何通过创作来改变自己的职业轨道&#xff1f;你有没有想过&#xff0c;其实成为技术创作领域的一位 KOL&#xff0c;离你并不遥远&a…

2023年全国职业院校技能大赛软件测试赛题—单元测试卷⑤

单元测试 一、任务要求 题目1&#xff1a;根据下列流程图编写程序实现相应处理&#xff0c;执行j10*x-y返回文字“j1&#xff1a;”和计算值&#xff0c;执行j(x-y)*(10⁵%7)返回文字“j2&#xff1a;”和计算值&#xff0c;执行jy*log(x10)返回文字“j3&#xff1a;”和计算值…

通义千问AI挑战赛赛后反思

个人理解&#xff1a; 初赛阶段主要聚焦在如何通过 SFT 提升基础模型的代码能力&#xff0c;需要选手基于最新开源的 Qwen 1.8 模型作为基础模型&#xff0c;上分的关键主要通过收集高质量的代码数据提升模型的在Python, JavaScript, Java, Go, C, Rust六种编程语言的代码生成…

若依框架实现排序【升序或降序】很简单

前端实现 1. 在表格上加监听函数sort-change。如下红框所示&#xff1a; 2. 在表行上加排序字:sort-orders&#xff0c;可排序字sortable。如下红框所示&#xff1a; 3. 添加监听函数实现。代码如下&#xff1a; handleSortChange(column) {this.queryParams.orderByColumn …

使用emu8086实现——循环结构程序设计

一、实验目的 1.掌握循环结构程序设计的方法&#xff1b; 2.掌握数据块传送程序设计的方法&#xff1b; 3.掌握串传送指令的应用。 二、实验内容 1、计算S12*33*4...N*(N1)&#xff0c;直到N*(N1)项大于200为止。编写程序&#xff0c;计算上式的结果。 代码及注释&#…

考研经验总结——目录

文章目录 一、写作顺序二、个人情况说明三、读评论四、一些小牢骚五、一些注意事项&#xff08;持续更新&#xff09; 一、写作顺序 我将准备从三个阶段开始介绍吧 考研前考研中考研后&#xff08;也就是现在我的这种情况&#xff09; 考研前我会分为&#xff1a;数学、专业…