【CGAL系列】---Mesh修复

news2024/11/18 9:27:47

很高兴在雪易的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 problems
  std::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 point
  points.push_back(CGAL::make_array<FT>(0,-2,0)); // unused point

  CGAL_Polygon p;
  p.push_back(0); p.push_back(1); p.push_back(2);
  polygons.push_back(p);

  // degenerate face
  p.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 orientation
  p.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 face
  p.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 face
  p.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 vertex

  remove_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 vertices
  vertex_descriptor v0 = *(vertices(mesh).begin());
  vertex_descriptor v1 = *(--(vertices(mesh).end()));
  merge_vertices(v0, v1, mesh);

  // Count non manifold vertices
  int 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 vertices
  std::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.coloradmin.cn/o/1386238.html

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

相关文章

Java中单体应用锁的局限性分布式锁

互联网系统架构的演进 在互联网系统发展之初&#xff0c;系统比较简单&#xff0c;消耗资源小&#xff0c;用户访问量也比较少&#xff0c;我们只部署一个Tomcat应用就可以满足需求。系统架构图如下: 一个Tomcat可以看作是一个JVM进程&#xff0c;当大量的请求并发到达系统时&…

使用php代码调用jar包里面的类方法的实战操作

#php调用jar包# 需求说明 接到一个需求&#xff0c;网站是使用php开发的帝国cms&#xff0c;现接到需求是需要对接一个系统 &#xff0c;但系统里面有一个数据加密字段&#xff0c;需要使用jar包进行加解密。 技术解决方案&#xff0c;资源包解决一切。下载就行了&#xff0…

Springboot整合Redission分布式锁使用实例

Springboot整合Redission分布式锁 引言&#xff1a;实际项目中&#xff0c;我们经常会遇到一些需要考虑使用分布式锁的场景&#xff0c;以防止页面重复请求或者多系统之间相互重复调用的产生业务偏差的问题&#xff1b; 例如&#xff1a; 1.并发的场景下&#xff0c;生成订单需…

LeetCode刷题---基本计算器

解题思路&#xff1a; 根据题意&#xff0c;字符串中包含的运算符只有和- 使用辅助栈的方法来解决该问题 定义结果集res和符号位sign(用于判断对下一数的加减操作),接着对字符串进行遍历。 如果当前字符为数字字符&#xff0c;判断当前字符的下一个字符是否也是数字字符&#x…

(2023版)斯坦福CS231n学习笔记:DL与CV教程 (2) | 图像分类与损失函数

前言 &#x1f4da; 笔记专栏&#xff1a;斯坦福CS231N&#xff1a;面向视觉识别的卷积神经网络&#xff08;23&#xff09;&#x1f517; 课程链接&#xff1a;https://www.bilibili.com/video/BV1xV411R7i5&#x1f4bb; CS231n: 深度学习计算机视觉&#xff08;2017&#xf…

深度学习 Day25——J4 ResNet与DenseNet结合探索(DPN)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 文章目录 前言1 我的环境2 pytorch实现DPN算法2.1 前期准备2.1.1 引入库2.1.2 设置GP…

如何构建高质量,低成本的移动机器人(AGV/AMR)?

中国移动机器人行业规模的不断扩大&#xff0c;低成本无人化是现市场需求突出的特点之一。然而研发一套完整的移动机器人导航方案不仅需要耗费大量的人力成本&#xff0c;还要经过漫长的市场验证&#xff0c;这将滞后整个产业的发展&#xff0c;并有可能错失市场的抢占先机。 如…

数据绑定,defineProperty,v-on,事件处理

目录​​​​​​​ v-bind单向数据绑定 defineProperty 是v-on的简写 事件处理 v-bind单向数据绑定 从name绑定到v-bind到value单向数据绑定&#xff1a; <input type"text" :value"name"> <input type "text" v-model"na…

API可视化编排如何实现

企业随着前后端分离架构、微服务架构、中台战略、产业互联互通的实施必将产生大量的各种协议的API服务&#xff0c;API将成为企业的数字化资产且API会越来越多&#xff0c; API服务之间的相互调用和依赖情况也随之越来越多和复杂。业务系统与业务系统之间、关联企业之间的API都…

【极光系列】Windows安装Mysql8.0版本

【极光系列】Windows安装Mysql8.0版本 一.mysql服务端 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 二.解压二进制包 解压到 E:\mysql-8.0.35-winx64目录下&#xff0c;记住你解压后的目录&#xff0c;后续要使用三.创建my.ini文件 tips&#xff1a;mys…

深圳三维扫描分析/偏差检测模具型腔三维尺寸及形位偏差测量公司

CASAIM中科广电三维扫描模具型腔深圳案例&#xff1a; 模具型腔的三维扫描分析/偏差检测是一项重要的质量控制过程&#xff0c;旨在确保模具制造过程中的精确度和一致性。 CASAIM中科广电通过使用高精度的三维扫描设备&#xff0c;可以获取模具型腔的实际形状和尺寸数据&…

解决com.alibaba.fastjson.JSONException: default constructor not found的问题

1.问题描述 在进行JSON和对象互转时&#xff0c;发现有个报错&#xff1a; com.alibaba.fastjson.JSONException: default constructor not found. class com.hellobike.ph.match.service.taxi.model.message.DelayAddSkuMsg 2.原因和解决方案 通过其提示可以看出在利用fastJ…

基于 IDEA 进行 Maven 工程构建

一、构建概念和构建过程 项目构建是指将源代码、依赖库和资源文件等转换成可执行或可部署的应用程序的过程&#xff0c;在这个过程中包括编译源代码、链接依赖库、打包和部署等多个步骤。 项目构建是软件开发过程中至关重要的一部分&#xff0c;它能够大大提高软件开发效率&…

【TypeScript】tsconfig.json文件到底是干啥的?作用是什么?

参考学习博文&#xff1a; 掌握tsconfig.json 一、tsconfig.json简介 1、tsconfig.json是什么&#xff1f; TypeScript 使用 tsconfig.json 文件作为其配置文件&#xff0c;当一个目录中存在 tsconfig.json 文件&#xff0c;则认为该目录为 TypeScript 项目的根目录。 通常…

西贝柳斯音乐记谱软件Avid Sibelius Ultimate 2023中文激活版

Avid Sibelius(西贝柳斯终极解锁版) 是一款记谱软件&#xff0c;从有抱负的作曲家和词曲作者到教师和学生&#xff0c;任何人都可以快速轻松地开始创作和分享音乐。对于那些还不熟悉使用符号软件的人来说&#xff0c;直观的界面将引导您完成整个过程。磁性布局可防止对象相互碰…

vue中el-radio无法默认选中

页面上不生效&#xff0c;默认什么都不选中 <el-radio-group v-model"queryParams.videoUrlType"><el-radio :label"1">本地上传</el-radio><el-radio :label"2">外部链接</el-radio> </el-radio-group>da…

MS5350高精度时间测量电路

描述 MS5350 是一款高精度时间测量电路&#xff0c;它具有高精度&#xff0c;高 稳定性&#xff0c;高效率的特点&#xff1b;它的测量精度高达 15PS &#xff0c;测量范围 在 4MHZ 时从 500NS 到 16MS &#xff0c;在第一波模式情况下&#xff0c;内部比 较器的 o…

sqli-labs关卡22(基于cookie被base64编码的报错盲注)

文章目录 前言一、回顾上一关知识点二、靶场第二十二关通关思路1、判断注入点2、爆数据库名3、爆数据库表4、爆数据库列5、爆数据库关键信息 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;不能随意去…

图片里面的水印怎么去除

我们经常会在网络上看到各种带有水印的图片。那么在摄图网下载的图片都带有水印&#xff0c;我们该怎么去除让我们让图片更完美无瑕呢然而&#xff0c;这时候心中就有一个疑问了如何去除图片上的水印呢?接下来&#xff0c;我将为您介绍一种常见的方法。 那就是我们的水印云了…

如何使用LightPicture+cpolar搭建个人云图床随时随地公网访问

文章目录 1.前言2. Lightpicture网站搭建2.1. Lightpicture下载和安装2.2. Lightpicture网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 现在的手机越来越先进&#xff0c;功能也越来越多&#xff0c;而手机…