collapse_edge.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 Alec Jacobson <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #ifndef IGL_COLLAPSE_EDGE_H
  9. #define IGL_COLLAPSE_EDGE_H
  10. #include "igl_inline.h"
  11. #include "min_heap.h"
  12. #include "decimate_callback_types.h"
  13. #include <Eigen/Core>
  14. #include <vector>
  15. #include <set>
  16. namespace igl
  17. {
  18. #ifndef IGL_COLLAPSE_EDGE_NULL
  19. /// Special value for indicating a null vertex index as the result of a
  20. /// collapsed edge.
  21. #define IGL_COLLAPSE_EDGE_NULL 0
  22. #endif
  23. /// Attempt to collapse a given edge of a mesh. Assumes (V,F) is a closed
  24. /// manifold mesh (except for previously collapsed faces which should be set
  25. /// to: [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL
  26. /// IGL_COLLAPSE_EDGE_NULL]. Collapses exactly two faces and exactly 3 edges
  27. /// from E (e and one side of each face gets collapsed to the other). This is
  28. /// implemented in a way that it can be repeatedly called until satisfaction
  29. /// and then the garbage in F can be collected by removing NULL faces.
  30. ///
  31. /// @param[in] e index into E of edge to try to collapse. E(e,:) = [s d] or [d s] so
  32. /// that s<d, then d is collapsed to s.
  33. /// @param[in] p dim list of vertex position where to place merged vertex
  34. /// [mesh inputs]
  35. /// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
  36. /// to midpoint of edge.
  37. /// @param[in,out] F #F by 3 list of face indices into V.
  38. /// @param[in,out] E #E by 2 list of edge indices into V.
  39. /// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
  40. /// unique edge in E
  41. /// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
  42. /// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1) "
  43. /// e=(j->i)
  44. /// @param[in,out] EI #E by 2 list of edge flap corners (see above).
  45. /// [mesh inputs]
  46. /// @param[out] e1 index into E of edge collpased on left
  47. /// @param[out] e2 index into E of edge collpased on right
  48. /// @param[out] f1 index into F of face collpased on left
  49. /// @param[out] f2 index into F of face collpased on right
  50. /// @return true if edge was collapsed
  51. ///
  52. ///
  53. /// Define [s,d] = sort(E(e,:)) so that s<d, then d is "detached" from
  54. /// connectivity meaning all faces/edges incident on d will now be incident on
  55. /// s. (This reduces fragmentation by preferring to collapse toward the start
  56. /// of V)¹. If E(e,1)==s then we say the edge is "flipped" (`eflip` true in
  57. /// the implementation).
  58. ///
  59. /// f1 is set to EF(e,0) and f2 is set to EF(e,1). Let v1 be EI(e,0) the
  60. /// corner of F(f1,:) opposite e. _If_ (s<d) then e1 will be the edge after e
  61. /// within f1:
  62. ///
  63. /// s<d
  64. /// ✅s----e-----d☠️
  65. /// \ ← /
  66. /// \ ↘f₁↗ /
  67. /// e₁ /
  68. /// \ /
  69. /// \/
  70. ///
  71. /// _If_ (s>d) then e1 will be the edge after e within f1:
  72. ///
  73. /// s>d
  74. /// ✅s----e-----d☠️
  75. /// \ ← /
  76. /// \ ↘f₁↗ /
  77. /// \ e₁
  78. /// \ /
  79. /// \/
  80. ///
  81. ///
  82. /// ¹Or at least it would if we templated these functions to allow using
  83. /// RowMajor V.
  84. ///
  85. /// It really seems that this callback should provide a meaningful edge on the
  86. /// _new_ mesh. Meanwhile – Oof – You can use this gross mechanism to find the faces incident on the
  87. /// collapsed vertex:
  88. ///
  89. /// ```cpp
  90. /// const auto survivors =
  91. /// [&F,&e,&EMAP](const int f1, const int e1, int & d1)
  92. /// {
  93. /// for(int c=0;c<3;c++)
  94. /// {
  95. /// d1 = EMAP(f1+c*F.rows());
  96. /// if((d1 != e) && (d1 != e1)) { break; }
  97. /// }
  98. /// };
  99. /// int d1,d2;
  100. /// survivors(f1,e1,d1);
  101. /// survivors(f2,e2,d2);
  102. /// // Will circulating by continuing in the CCW direction of E(d1,:)
  103. /// // encircle the common edge? That is, is E(d1,1) the common vertex?
  104. /// const bool ccw = E(d1,1) == E(d2,0) || E(d1,1) == E(d2,1);
  105. /// std::vector<int> Nf;
  106. /// {
  107. /// std::vector<int> Nv;
  108. /// igl::circulation(d1,ccw,F,EMAP,EF,EI,Nv,Nf);
  109. /// }
  110. /// ```
  111. template <
  112. typename Derivedp,
  113. typename DerivedV,
  114. typename DerivedF,
  115. typename DerivedE,
  116. typename DerivedEMAP,
  117. typename DerivedEF,
  118. typename DerivedEI>
  119. IGL_INLINE bool collapse_edge(
  120. const int e,
  121. const Eigen::MatrixBase<Derivedp> & p,
  122. Eigen::MatrixBase<DerivedV> & V,
  123. Eigen::MatrixBase<DerivedF> & F,
  124. Eigen::MatrixBase<DerivedE> & E,
  125. Eigen::MatrixBase<DerivedEMAP> & EMAP,
  126. Eigen::MatrixBase<DerivedEF> & EF,
  127. Eigen::MatrixBase<DerivedEI> & EI,
  128. int & e1,
  129. int & e2,
  130. int & f1,
  131. int & f2);
  132. /// \overload
  133. ///
  134. /// @param[in] Nsv #Nsv vertex circulation around s (see circulation)
  135. /// @param[in] Nsf #Nsf face circulation around s
  136. /// @param[in] Ndv #Ndv vertex circulation around d
  137. /// @param[in] Ndf #Ndf face circulation around d
  138. template
  139. <
  140. typename Derivedp,
  141. typename DerivedV,
  142. typename DerivedF,
  143. typename DerivedE,
  144. typename DerivedEMAP,
  145. typename DerivedEF,
  146. typename DerivedEI>
  147. IGL_INLINE bool collapse_edge(
  148. const int e,
  149. const Eigen::MatrixBase<Derivedp> & p,
  150. /*const*/ std::vector<int> & Nsv,
  151. const std::vector<int> & Nsf,
  152. /*const*/ std::vector<int> & Ndv,
  153. const std::vector<int> & Ndf,
  154. Eigen::MatrixBase<DerivedV> & V,
  155. Eigen::MatrixBase<DerivedF> & F,
  156. Eigen::MatrixBase<DerivedE> & E,
  157. Eigen::MatrixBase<DerivedEMAP> & EMAP,
  158. Eigen::MatrixBase<DerivedEF> & EF,
  159. Eigen::MatrixBase<DerivedEI> & EI,
  160. int & a_e1,
  161. int & a_e2,
  162. int & a_f1,
  163. int & a_f2);
  164. /// Collapse least-cost edge from a priority queue and update queue
  165. ///
  166. /// See decimate.h for more details.
  167. ///
  168. /// @param[in] cost_and_placement function computing cost of collapsing an edge and 3d
  169. /// position where it should be placed:
  170. /// cost_and_placement(V,F,E,EMAP,EF,EI,cost,placement);
  171. /// **If the edges is collapsed** then this function will be called on all
  172. /// edges of all faces previously incident on the endpoints of the
  173. /// collapsed edge.
  174. /// @param[in] pre_collapse callback called with index of edge whose collapse is about
  175. /// to be attempted. This function should return whether to **proceed**
  176. /// with the collapse: returning true means "yes, try to collapse",
  177. /// returning false means "No, consider this edge 'uncollapsable', behave
  178. /// as if collapse_edge(e) returned false.
  179. /// @param[in] post_collapse callback called with index of edge whose collapse was
  180. /// just attempted and a flag revealing whether this was successful.
  181. /// @param[in,out] V #V by dim list of vertex positions, lesser index of E(e,:) will be set
  182. /// to midpoint of edge.
  183. /// @param[in,out] F #F by 3 list of face indices into V.
  184. /// @param[in,out] E #E by 2 list of edge indices into V.
  185. /// @param[in,out] EMAP #F*3 list of indices into E, mapping each directed edge to unique
  186. /// unique edge in E
  187. /// @param[in,out] EF #E by 2 list of edge flaps, EF(e,0)=f means e=(i-->j) is the edge of
  188. /// F(f,:) opposite the vth corner, where EI(e,0)=v. Similarly EF(e,1)
  189. /// e=(j->i)
  190. /// @param[in,out] EI #E by 2 list of edge flap corners (see above).
  191. /// @param[in] Q queue containing pairs of costs and edge indices and insertion "time"
  192. /// @param[in] EQ #E list of "time" of last time pushed into Q
  193. /// @param[in] C #E by dim list of stored placements
  194. /// @param[out] e index into E of attempted collapsed edge. Set to -1 if Q is empty or
  195. /// contains only infinite cost edges.
  196. /// @param[out] e1 index into E of edge collpased on left.
  197. /// @param[out] e2 index into E of edge collpased on right.
  198. /// @param[out] f1 index into F of face collpased on left.
  199. /// @param[out] f2 index into F of face collpased on right.
  200. template <
  201. typename CPFunc,
  202. typename PreFunc,
  203. typename PostFunc,
  204. typename DerivedV,
  205. typename DerivedF,
  206. typename DerivedE,
  207. typename DerivedEMAP,
  208. typename DerivedEF,
  209. typename DerivedEI,
  210. typename DerivedEQ,
  211. typename DerivedC>
  212. IGL_INLINE bool collapse_edge(
  213. const CPFunc & cost_and_placement,
  214. const PreFunc & pre_collapse,
  215. const PostFunc & post_collapse,
  216. Eigen::MatrixBase<DerivedV> & V,
  217. Eigen::MatrixBase<DerivedF> & F,
  218. Eigen::MatrixBase<DerivedE> & E,
  219. Eigen::MatrixBase<DerivedEMAP> & EMAP,
  220. Eigen::MatrixBase<DerivedEF> & EF,
  221. Eigen::MatrixBase<DerivedEI> & EI,
  222. igl::min_heap< std::tuple<double,int,int> > & Q,
  223. Eigen::MatrixBase<DerivedEQ> & EQ,
  224. Eigen::MatrixBase<DerivedC> & C,
  225. int & e,
  226. int & e1,
  227. int & e2,
  228. int & f1,
  229. int & f2);
  230. }
  231. #ifndef IGL_STATIC_LIBRARY
  232. # include "collapse_edge.cpp"
  233. #endif
  234. #endif