openmesh - src - trimesh delete and add elements

openmesh 版本 8.1

About

本文主要介绍openmesh的如下接口

  • add_vertex
  • add_face
  • delete_vertex
  • delete_edge
  • delete_face
  • delete_isolated_vertices

add_vertex

入口代码位于:\src\OpenMesh\Core\Mesh\PolyMeshT.hh。涉及到的源代码如下:

  1. template <class Kernel>
  2. class PolyMeshT : public Kernel
  3. {
  4. /// Alias for new_vertex(const Point&).
  5. inline SmartVertexHandle add_vertex(const Point& _p)
  6. { return new_vertex(_p); }
  7. /**
  8. * \brief Adds a new vertex initialized to a custom position.
  9. *
  10. * \sa new_vertex(), new_vertex_dirty()
  11. */
  12. inline SmartVertexHandle new_vertex(const Point& _p)
  13. {
  14. VertexHandle vh(Kernel::new_vertex());
  15. this->set_point(vh, _p);
  16. return make_smart(vh, this);
  17. }
  18. //..............
  19. }
  20. // kernel::new_vertex
  21. class OPENMESHDLLEXPORT ArrayKernel : public BaseKernel, public ArrayItems
  22. {
  23. inline VertexHandle new_vertex()
  24. {
  25. vertices_.push_back(Vertex());
  26. vprops_resize(n_vertices());//TODO:should it be push_back()?
  27. return handle(vertices_.back());
  28. }
  29. // --- handle -> item ---
  30. VertexHandle handle(const Vertex& _v) const
  31. {
  32. return VertexHandle( int( &_v - &vertices_.front()));
  33. }
  34. }
  35. // AttribKernelT
  36. // 顶点的位置,作为顶点的属性进行管理
  37. template <class MeshItems, class Connectivity>
  38. class AttribKernelT : public Connectivity
  39. {
  40. void set_point(VertexHandle _vh, const Point& _p)
  41. { this->property(points_, _vh) = _p; }
  42. }

从上面中的代码知,add_vertex的过程,就是创建了Vertex,然后创建关联的VertexHandle,并将顶点的位置记录到顶点property中。

add_face

入口代码位于:src\OpenMesh\Core\Mesh\TriConnectivity.cc

  1. SmartFaceHandle
  2. TriConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size)
  3. {
  4. // need at least 3 vertices
  5. if (_vhs_size < 3) return make_smart(InvalidFaceHandle, this);
  6. /// face is triangle -> ok
  7. if (_vhs_size == 3)
  8. return PolyConnectivity::add_face(_vertex_handles, _vhs_size);
  9. /// face is not a triangle -> triangulate
  10. else
  11. {
  12. //omlog() << "triangulating " << _vhs_size << "_gon\n";
  13. VertexHandle vhandles[3];
  14. vhandles[0] = _vertex_handles[0];
  15. FaceHandle fh;
  16. unsigned int i(1);
  17. --_vhs_size;
  18. while (i < _vhs_size)
  19. {
  20. vhandles[1] = _vertex_handles[i];
  21. vhandles[2] = _vertex_handles[++i];
  22. fh = PolyConnectivity::add_face(vhandles, 3);
  23. }
  24. return make_smart(fh, this);
  25. }
  26. }

从上面的代码可知,对于TriMesh,如果超过三个顶点,那么会进行三角化的过程,这个三角化的过程是,将第一个顶点作为所有三角形的公共点,接下来数组中的相邻两个点作为每个三角形的另外两个顶点。图示如下:

进一步查看PolyConnectivity::add_face(_vertex_handles, _vhs_size);,完整的代码如下(TODO详细剖析下面的代码):

  1. SmartFaceHandle
  2. PolyConnectivity::add_face(const VertexHandle* _vertex_handles, size_t _vhs_size)
  3. {
  4. VertexHandle vh;
  5. size_t i, ii, n(_vhs_size);
  6. HalfedgeHandle inner_next, inner_prev,
  7. outer_next, outer_prev,
  8. boundary_next, boundary_prev,
  9. patch_start, patch_end;
  10. // Check sufficient working storage available
  11. if (edgeData_.size() < n)
  12. {
  13. edgeData_.resize(n); // 数据类型为:std::vector<AddFaceEdgeInfo>;
  14. // struct AddFaceEdgeInfo { HalfedgeHandle halfedge_handle; bool is_new; bool needs_adjust; }
  15. next_cache_.resize(6*n); //数据类型为:std::vector<std::pair<HalfedgeHandle, HalfedgeHandle> >
  16. // for set_next_halfedge and vertex' set_halfedge
  17. }
  18. size_t next_cache_count = 0;
  19. // don't allow degenerated faces
  20. assert (n > 2);
  21. // test for topological errors
  22. for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
  23. {
  24. // 需要添加三角形的顶点必须是位于当前拓扑结构的边界
  25. if ( !is_boundary(_vertex_handles[i]) )
  26. {
  27. omerr() << "PolyMeshT::add_face: complex vertex\n";
  28. return make_smart(InvalidFaceHandle, this);
  29. }
  30. // Initialise edge attributes
  31. // 查找是否存在点i和点ii构成的半边
  32. edgeData_[i].halfedge_handle = find_halfedge(_vertex_handles[i],
  33. _vertex_handles[ii]);
  34. edgeData_[i].is_new = !edgeData_[i].halfedge_handle.is_valid();
  35. edgeData_[i].needs_adjust = false;
  36. // 如果存在这个半边,并且该半边不是边界,那么添加的为重复半边,直接return
  37. if (!edgeData_[i].is_new && !is_boundary(edgeData_[i].halfedge_handle))
  38. {
  39. omerr() << "PolyMeshT::add_face: complex edge\n";
  40. return make_smart(InvalidFaceHandle, this);
  41. }
  42. }
  43. // re-link patches if necessary
  44. for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
  45. {
  46. // 如果存在点i点ii构成的半边i-to-ii,和点ii和点ii+1构建的半边,ii-to-ii+1
  47. if (!edgeData_[i].is_new && !edgeData_[ii].is_new)
  48. {
  49. inner_prev = edgeData_[i].halfedge_handle;
  50. inner_next = edgeData_[ii].halfedge_handle;
  51. // 如果i-to-ii的下一个半边不是ii-to-ii+1,那么需要修正拓扑结构关系
  52. // TODO:需要了解下出现此种情况的具体场景是什么
  53. if (next_halfedge_handle(inner_prev) != inner_next)
  54. {
  55. // here comes the ugly part... we have to relink a whole patch
  56. // search a free gap
  57. // free gap will be between boundary_prev and boundary_next
  58. outer_prev = opposite_halfedge_handle(inner_next);
  59. outer_next = opposite_halfedge_handle(inner_prev);
  60. boundary_prev = outer_prev;
  61. do
  62. boundary_prev =
  63. opposite_halfedge_handle(next_halfedge_handle(boundary_prev));
  64. while (!is_boundary(boundary_prev));
  65. boundary_next = next_halfedge_handle(boundary_prev);
  66. // ok ?
  67. if (boundary_prev == inner_prev)
  68. {
  69. omerr() << "PolyMeshT::add_face: patch re-linking failed\n";
  70. return make_smart(InvalidFaceHandle, this);
  71. }
  72. assert(is_boundary(boundary_prev));
  73. assert(is_boundary(boundary_next));
  74. // other halfedges' handles
  75. patch_start = next_halfedge_handle(inner_prev);
  76. patch_end = prev_halfedge_handle(inner_next);
  77. assert(boundary_prev.is_valid());
  78. assert(patch_start.is_valid());
  79. assert(patch_end.is_valid());
  80. assert(boundary_next.is_valid());
  81. assert(inner_prev.is_valid());
  82. assert(inner_next.is_valid());
  83. // relink
  84. next_cache_[next_cache_count++] = std::make_pair(boundary_prev, patch_start);
  85. next_cache_[next_cache_count++] = std::make_pair(patch_end, boundary_next);
  86. next_cache_[next_cache_count++] = std::make_pair(inner_prev, inner_next);
  87. }
  88. }
  89. }
  90. // create missing edges
  91. for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
  92. if (edgeData_[i].is_new)
  93. edgeData_[i].halfedge_handle = new_edge(_vertex_handles[i], _vertex_handles[ii]);
  94. // create the face
  95. FaceHandle fh(new_face());
  96. set_halfedge_handle(fh, edgeData_[n-1].halfedge_handle);
  97. // setup halfedges
  98. for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
  99. {
  100. vh = _vertex_handles[ii];
  101. inner_prev = edgeData_[i].halfedge_handle;
  102. inner_next = edgeData_[ii].halfedge_handle;
  103. assert(inner_prev.is_valid());
  104. assert(inner_next.is_valid());
  105. size_t id = 0;
  106. if (edgeData_[i].is_new) id |= 1;
  107. if (edgeData_[ii].is_new) id |= 2;
  108. if (id)
  109. {
  110. outer_prev = opposite_halfedge_handle(inner_next);
  111. outer_next = opposite_halfedge_handle(inner_prev);
  112. assert(outer_prev.is_valid());
  113. assert(outer_next.is_valid());
  114. // set outer links
  115. switch (id)
  116. {
  117. case 1: // prev is new, next is old
  118. boundary_prev = prev_halfedge_handle(inner_next);
  119. assert(boundary_prev.is_valid());
  120. next_cache_[next_cache_count++] = std::make_pair(boundary_prev, outer_next);
  121. set_halfedge_handle(vh, outer_next);
  122. break;
  123. case 2: // next is new, prev is old
  124. boundary_next = next_halfedge_handle(inner_prev);
  125. assert(boundary_next.is_valid());
  126. next_cache_[next_cache_count++] = std::make_pair(outer_prev, boundary_next);
  127. set_halfedge_handle(vh, boundary_next);
  128. break;
  129. case 3: // both are new
  130. if (!halfedge_handle(vh).is_valid())
  131. {
  132. set_halfedge_handle(vh, outer_next);
  133. next_cache_[next_cache_count++] = std::make_pair(outer_prev, outer_next);
  134. }
  135. else
  136. {
  137. boundary_next = halfedge_handle(vh);
  138. boundary_prev = prev_halfedge_handle(boundary_next);
  139. assert(boundary_prev.is_valid());
  140. assert(boundary_next.is_valid());
  141. next_cache_[next_cache_count++] = std::make_pair(boundary_prev, outer_next);
  142. next_cache_[next_cache_count++] = std::make_pair(outer_prev, boundary_next);
  143. }
  144. break;
  145. }
  146. // set inner link
  147. next_cache_[next_cache_count++] = std::make_pair(inner_prev, inner_next);
  148. }
  149. else edgeData_[ii].needs_adjust = (halfedge_handle(vh) == inner_next);
  150. // set face handle
  151. set_face_handle(edgeData_[i].halfedge_handle, fh);
  152. }
  153. // process next halfedge cache
  154. for (i = 0; i < next_cache_count; ++i)
  155. set_next_halfedge_handle(next_cache_[i].first, next_cache_[i].second);
  156. // adjust vertices' halfedge handle
  157. for (i=0; i<n; ++i)
  158. if (edgeData_[i].needs_adjust)
  159. adjust_outgoing_halfedge(_vertex_handles[i]);
  160. return make_smart(fh, this);
  161. }

delete_vertex

入口代码位置见:src\OpenMesh\Core\Mesh\PolyConnectivity.cc

  1. void PolyConnectivity::delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices)
  2. {
  3. // store incident faces
  4. // 先找到顶点周围的所有面
  5. std::vector<FaceHandle> face_handles;
  6. face_handles.reserve(8);
  7. for (VFIter vf_it(vf_iter(_vh)); vf_it.is_valid(); ++vf_it)
  8. face_handles.push_back(*vf_it);
  9. // delete collected faces
  10. // 删除所有关联的面
  11. std::vector<FaceHandle>::iterator fh_it(face_handles.begin()),
  12. fh_end(face_handles.end());
  13. for (; fh_it!=fh_end; ++fh_it)
  14. delete_face(*fh_it, _delete_isolated_vertices);
  15. // 然后将该顶点标记为已删除
  16. status(_vh).set_deleted(true);
  17. }

上述代码实现中的重点部分是delete_face,那么接下来先来看一下delete_face的代码实现。

delete_face

入口代码位置见:src\OpenMesh\Core\Mesh\PolyConnectivity.cc

  1. void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices)
  2. {
  3. assert(_fh.is_valid() && !status(_fh).deleted());
  4. // mark face deleted,将该facehandle标记为已经删除
  5. status(_fh).set_deleted(true);
  6. // this vector will hold all boundary edges of face _fh
  7. // these edges will be deleted
  8. // 用来存储面的所有边界边,这些边将会被删除
  9. std::vector<EdgeHandle> deleted_edges;
  10. deleted_edges.reserve(3);
  11. // this vector will hold all vertices of face _fh
  12. // for updating their outgoing halfedge
  13. // 用来存储面的所有顶点,用来更新这些顶点的outgoing 半边;
  14. std::vector<VertexHandle> vhandles;
  15. vhandles.reserve(3);
  16. // for all halfedges of face _fh do:
  17. // 1) invalidate face handle.
  18. // 2) collect all boundary halfedges, set them deleted
  19. // 3) store vertex handles
  20. HalfedgeHandle hh;
  21. for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it.is_valid(); ++fh_it)
  22. {
  23. hh = *fh_it;
  24. set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle);
  25. // 如果边界半边opposite半边也是边界,那么这个边需要被删除
  26. if (is_boundary(opposite_halfedge_handle(hh)))
  27. deleted_edges.push_back(edge_handle(hh));
  28. vhandles.push_back(to_vertex_handle(hh));
  29. }
  30. // delete all collected (half)edges
  31. // these edges were all boundary
  32. // delete isolated vertices (if _delete_isolated_vertices is true)
  33. // 此处的逻辑可以见代码后的图示。
  34. if (!deleted_edges.empty())
  35. {
  36. std::vector<EdgeHandle>::iterator del_it(deleted_edges.begin()),
  37. del_end(deleted_edges.end());
  38. HalfedgeHandle h0, h1, next0, next1, prev0, prev1;
  39. VertexHandle v0, v1;
  40. for (; del_it!=del_end; ++del_it)
  41. {
  42. h0 = halfedge_handle(*del_it, 0);
  43. v0 = to_vertex_handle(h0);
  44. next0 = next_halfedge_handle(h0);
  45. prev0 = prev_halfedge_handle(h0);
  46. h1 = halfedge_handle(*del_it, 1);
  47. v1 = to_vertex_handle(h1);
  48. next1 = next_halfedge_handle(h1);
  49. prev1 = prev_halfedge_handle(h1);
  50. // adjust next and prev handles
  51. set_next_halfedge_handle(prev0, next1);
  52. set_next_halfedge_handle(prev1, next0);
  53. // mark edge deleted if the mesh has a edge status
  54. if ( has_edge_status() )
  55. status(*del_it).set_deleted(true);
  56. // mark corresponding halfedges as deleted
  57. // As the deleted edge is boundary,
  58. // all corresponding halfedges will also be deleted.
  59. if ( has_halfedge_status() ) {
  60. status(h0).set_deleted(true);
  61. status(h1).set_deleted(true);
  62. }
  63. // update v0
  64. if (halfedge_handle(v0) == h1)
  65. {
  66. // isolated ?
  67. if (next0 == h1)
  68. {
  69. if (_delete_isolated_vertices)
  70. status(v0).set_deleted(true);
  71. set_isolated(v0);
  72. }
  73. else set_halfedge_handle(v0, next0);
  74. }
  75. // update v1
  76. if (halfedge_handle(v1) == h0)
  77. {
  78. // isolated ?
  79. if (next1 == h0)
  80. {
  81. if (_delete_isolated_vertices)
  82. status(v1).set_deleted(true);
  83. set_isolated(v1);
  84. }
  85. else set_halfedge_handle(v1, next1);
  86. }
  87. }
  88. }
  89. // update outgoing halfedge handles of remaining vertices
  90. // 边界的顶点对应的半边必须是边界的。
  91. std::vector<VertexHandle>::iterator v_it(vhandles.begin()),
  92. v_end(vhandles.end());
  93. for (; v_it!=v_end; ++v_it)
  94. adjust_outgoing_halfedge(*v_it);
  95. }

deleted_edges相关的逻辑示意图如下:

delete_edge

  1. void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices)
  2. {
  3. FaceHandle fh0(face_handle(halfedge_handle(_eh, 0)));
  4. FaceHandle fh1(face_handle(halfedge_handle(_eh, 1)));
  5. if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices);
  6. if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices);
  7. // If there is no face, we delete the edge
  8. // here
  9. if ( ! fh0.is_valid() && !fh1.is_valid()) {
  10. // mark edge deleted if the mesh has a edge status
  11. if ( has_edge_status() )
  12. status(_eh).set_deleted(true);
  13. // mark corresponding halfedges as deleted
  14. // As the deleted edge is boundary,
  15. // all corresponding halfedges will also be deleted.
  16. if ( has_halfedge_status() ) {
  17. status(halfedge_handle(_eh, 0)).set_deleted(true);
  18. status(halfedge_handle(_eh, 1)).set_deleted(true);
  19. }
  20. }
  21. }

delete_edge的实现是将边关联的face删除,然后将edge和关联的half_edge的状态设置为删除。

delete_isolated_vertices

  1. unsigned int ArrayKernel::delete_isolated_vertices()
  2. {
  3. assert(has_vertex_status());//this function requires vertex status property
  4. unsigned int n_isolated = 0;
  5. for (KernelVertexIter v_it = vertices_begin(); v_it != vertices_end(); ++v_it)
  6. {
  7. if (is_isolated(handle(*v_it)))
  8. {
  9. status(handle(*v_it)).set_deleted(true);
  10. n_isolated++;
  11. }
  12. }
  13. return n_isolated;
  14. }

直接判断出是否为孤立点,然后标记为删除。

openmesh - src - trimesh delete and add elements的更多相关文章

  1. How do I add elements to a Scala List?

    Scala List FAQ: How do I add elements to a Scala List? This is actually a trick question, because yo ...

  2. How to add elements to a List in Scala

    Scala List FAQ: How do I add elements to a Scala List? This is actually a trick question, because yo ...

  3. select 下拉菜单Option对象使用add(elements,index)方法动态添加

    原生js 的add函数为下拉菜单增加选项 1.object.add(oElement [, iIndex]) index 可选参数:指定元素放置所在的索引号,整形值.如果没有指定值,将添加到集合的最后 ...

  4. openmesh - impl - Remove Duplicated Vertices

    openmesh - impl - Remove Duplicated Vertices 关于openmesh元素删除实现的介绍参见:openmesh - src - trimesh delete a ...

  5. 【OpenMesh】创建一个正方体

    原文出处: http://openmesh.org/Documentation/OpenMesh-Doc-Latest/tutorial.html 这个例程演示了: 如何声明MyMesh 如何添加顶点 ...

  6. 调用 webapi的put和delete 报"Method Not Allowed" 405 错误。

    修改引用到webapi的Dll文件对应的项目的web.config 选择生成读写方法webapi会生成四个读写的方法(CRUD),两个获取数据的.一个更新.一个删除,默认情况下更新和删除是不对外开外的 ...

  7. Mongodb 语法,update,insert,delete,find

    ---恢复内容开始--- db.Users.update({OrganizationCode:"Global"},{$set:{OrganizationCode:"Fre ...

  8. C++ 重载new和delete操作符

    原因: C++标准库提供的new和delete操作符,是一个通用实现,未针对具体对象做具体分析 存在分配器速度慢.小型对象空间浪费严重等问题,不适用于对效率和内存有限制的应用场景   好处: 灵活的内 ...

  9. Import the Add Email and Post Configuration to the SiteMap managed solution -Dynamices CRM

    We have prepared a managed solution named Add Email and Post Configuration to SiteMap that you can i ...

随机推荐

  1. 【编程思想】【设计模式】【创建模式creational】建造者模式builder

    Python版 https://github.com/faif/python-patterns/blob/master/creational/builder.py #!/usr/bin/python ...

  2. Appium获取toast消息(二)

    刚接触appium进行移动端设备的UI自动化,在遇到toast消息的时候很是苦恼了一阵,最后通过强大的搜索引擎找到了个相对解决方法,废话不多说,直接贴代码↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ ...

  3. Nginx+ uWSGI +django进行部署

    一:uWSGI的安装 sudo pip install uwsgi 如果安装报错: conda install -c conda-forge uwsgi conda install -c conda- ...

  4. 【Jenkins系列】-备份机制

    Jenkins是主从模式,从节点可以做集群.负载,从而实现从节点的高可用,但是主节点是单节点,一旦主节点宕机,会导致Jenkins服务不可用.Jenkins主节点本身是不支持集群的,需要通过其他变通方 ...

  5. windows下更换MySql数据库数据文件夹位置

    详细解决地址 ,感谢博主  :https://blog.csdn.net/u010953266/article/details/56499361 概述 由于更换硬盘,系统重新安装了一遍,原来的mysq ...

  6. 解析Redis操作五大数据类型常用命令

    摘要:分享经常用到一些命令和使用场景总结,以及对Redis中五大数据类型如何使用cmd命令行的形式进行操作的方法. 本文分享自华为云社区<Redis操作五大数据类型常用命令解析>,作者:灰 ...

  7. odoo views中html的奇怪问题

    在我创建了字段类型为 fields.Html 以后,确出现了两种不同的情况 下图中,content是此类型的,可以正常显示不需要加widget(小部件)="html" <fo ...

  8. CF139A Petr and Book 题解

    Content 小 P 有一本 \(n\) 页的书,现给出他一周七天每天的阅读页数,求它在星期几读完这本书. 数据范围:\(1\leqslant n\leqslant 1000\). Solution ...

  9. MimeTypes数值表

    我们常常需要再前端附件进行上传的时候,就设定只能选择固定的后缀的上传文件,这时就需要用到我们MimeTypes表 MimeTypes表 mimes = [("ez", " ...

  10. PC chrome开启自带的dark mode

    地址 复制下面的地址到chrome地址栏打开,再设置为 Enable 就可以开启了. chrome://flags/#enable-force-dark