decimate.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
  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. #include "decimate.h"
  9. #include "collapse_edge.h"
  10. #include "edge_flaps.h"
  11. #include "remove_unreferenced.h"
  12. #include "slice_mask.h"
  13. #include "slice.h"
  14. #include "connect_boundary_to_infinity.h"
  15. #include "max_faces_stopping_condition.h"
  16. #include "shortest_edge_and_midpoint.h"
  17. #include <iostream>
  18. IGL_INLINE bool igl::decimate(
  19. const Eigen::MatrixXd & V,
  20. const Eigen::MatrixXi & F,
  21. const size_t max_m,
  22. Eigen::MatrixXd & U,
  23. Eigen::MatrixXi & G,
  24. Eigen::VectorXi & J,
  25. Eigen::VectorXi & I)
  26. {
  27. // Original number of faces
  28. const int orig_m = F.rows();
  29. // Tracking number of faces
  30. int m = F.rows();
  31. typedef Eigen::MatrixXd DerivedV;
  32. typedef Eigen::MatrixXi DerivedF;
  33. DerivedV VO;
  34. DerivedF FO;
  35. igl::connect_boundary_to_infinity(V,F,VO,FO);
  36. const auto & always_try = [](const int e)->bool{return true;};
  37. const auto & never_care = [](const int e, const bool collapsed){};
  38. bool ret = decimate(
  39. VO,
  40. FO,
  41. shortest_edge_and_midpoint,
  42. max_faces_stopping_condition(m,orig_m,max_m),
  43. always_try,
  44. never_care,
  45. U,
  46. G,
  47. J,
  48. I);
  49. const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
  50. igl::slice_mask(Eigen::MatrixXi(G),keep,1,G);
  51. igl::slice_mask(Eigen::VectorXi(J),keep,1,J);
  52. Eigen::VectorXi _1,I2;
  53. igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1,I2);
  54. igl::slice(Eigen::VectorXi(I),I2,1,I);
  55. return ret;
  56. }
  57. IGL_INLINE bool igl::decimate(
  58. const Eigen::MatrixXd & V,
  59. const Eigen::MatrixXi & F,
  60. const size_t max_m,
  61. Eigen::MatrixXd & U,
  62. Eigen::MatrixXi & G,
  63. Eigen::VectorXi & J)
  64. {
  65. Eigen::VectorXi I;
  66. return igl::decimate(V,F,max_m,U,G,J,I);
  67. }
  68. IGL_INLINE bool igl::decimate(
  69. const Eigen::MatrixXd & OV,
  70. const Eigen::MatrixXi & OF,
  71. const std::function<void(
  72. const int,
  73. const Eigen::MatrixXd &,
  74. const Eigen::MatrixXi &,
  75. const Eigen::MatrixXi &,
  76. const Eigen::VectorXi &,
  77. const Eigen::MatrixXi &,
  78. const Eigen::MatrixXi &,
  79. double &,
  80. Eigen::RowVectorXd &)> & cost_and_placement,
  81. const std::function<bool(
  82. const Eigen::MatrixXd &,
  83. const Eigen::MatrixXi &,
  84. const Eigen::MatrixXi &,
  85. const Eigen::VectorXi &,
  86. const Eigen::MatrixXi &,
  87. const Eigen::MatrixXi &,
  88. const std::set<std::pair<double,int> > &,
  89. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  90. const Eigen::MatrixXd &,
  91. const int,
  92. const int,
  93. const int,
  94. const int,
  95. const int)> & stopping_condition,
  96. const std::function<bool(const int )> & pre_collapse,
  97. const std::function<void(const int , const bool)> & post_collapse,
  98. Eigen::MatrixXd & U,
  99. Eigen::MatrixXi & G,
  100. Eigen::VectorXi & J,
  101. Eigen::VectorXi & I
  102. )
  103. {
  104. using namespace Eigen;
  105. using namespace std;
  106. VectorXi EMAP;
  107. MatrixXi E,EF,EI;
  108. edge_flaps(OF,E,EMAP,EF,EI);
  109. return igl::decimate(
  110. OV,OF,
  111. cost_and_placement,stopping_condition,pre_collapse,post_collapse,
  112. E,EMAP,EF,EI,
  113. U,G,J,I);
  114. }
  115. IGL_INLINE bool igl::decimate(
  116. const Eigen::MatrixXd & OV,
  117. const Eigen::MatrixXi & OF,
  118. const std::function<void(
  119. const int,
  120. const Eigen::MatrixXd &,
  121. const Eigen::MatrixXi &,
  122. const Eigen::MatrixXi &,
  123. const Eigen::VectorXi &,
  124. const Eigen::MatrixXi &,
  125. const Eigen::MatrixXi &,
  126. double &,
  127. Eigen::RowVectorXd &)> & cost_and_placement,
  128. const std::function<bool(
  129. const Eigen::MatrixXd &,
  130. const Eigen::MatrixXi &,
  131. const Eigen::MatrixXi &,
  132. const Eigen::VectorXi &,
  133. const Eigen::MatrixXi &,
  134. const Eigen::MatrixXi &,
  135. const std::set<std::pair<double,int> > &,
  136. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  137. const Eigen::MatrixXd &,
  138. const int,
  139. const int,
  140. const int,
  141. const int,
  142. const int)> & stopping_condition,
  143. const std::function<bool(const int )> & pre_collapse,
  144. const std::function<void(const int , const bool)> & post_collapse,
  145. const Eigen::MatrixXi & OE,
  146. const Eigen::VectorXi & OEMAP,
  147. const Eigen::MatrixXi & OEF,
  148. const Eigen::MatrixXi & OEI,
  149. Eigen::MatrixXd & U,
  150. Eigen::MatrixXi & G,
  151. Eigen::VectorXi & J,
  152. Eigen::VectorXi & I
  153. )
  154. {
  155. using namespace Eigen;
  156. using namespace std;
  157. // Working copies
  158. Eigen::MatrixXd V = OV;
  159. Eigen::MatrixXi F = OF;
  160. Eigen::MatrixXi E = OE;
  161. Eigen::VectorXi EMAP = OEMAP;
  162. Eigen::MatrixXi EF = OEF;
  163. Eigen::MatrixXi EI = OEI;
  164. typedef std::set<std::pair<double,int> > PriorityQueue;
  165. PriorityQueue Q;
  166. std::vector<PriorityQueue::iterator > Qit;
  167. Qit.resize(E.rows());
  168. // If an edge were collapsed, we'd collapse it to these points:
  169. MatrixXd C(E.rows(),V.cols());
  170. for(int e = 0;e<E.rows();e++)
  171. {
  172. double cost = e;
  173. RowVectorXd p(1,3);
  174. cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
  175. C.row(e) = p;
  176. Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
  177. }
  178. int prev_e = -1;
  179. bool clean_finish = false;
  180. while(true)
  181. {
  182. if(Q.empty())
  183. {
  184. break;
  185. }
  186. if(Q.begin()->first == std::numeric_limits<double>::infinity())
  187. {
  188. // min cost edge is infinite cost
  189. break;
  190. }
  191. int e,e1,e2,f1,f2;
  192. if(collapse_edge(
  193. cost_and_placement, pre_collapse, post_collapse,
  194. V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  195. {
  196. if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  197. {
  198. clean_finish = true;
  199. break;
  200. }
  201. }else
  202. {
  203. if(prev_e == e)
  204. {
  205. assert(false && "Edge collapse no progress... bad stopping condition?");
  206. break;
  207. }
  208. // Edge was not collapsed... must have been invalid. collapse_edge should
  209. // have updated its cost to inf... continue
  210. }
  211. prev_e = e;
  212. }
  213. // remove all IGL_COLLAPSE_EDGE_NULL faces
  214. MatrixXi F2(F.rows(),3);
  215. J.resize(F.rows());
  216. int m = 0;
  217. for(int f = 0;f<F.rows();f++)
  218. {
  219. if(
  220. F(f,0) != IGL_COLLAPSE_EDGE_NULL ||
  221. F(f,1) != IGL_COLLAPSE_EDGE_NULL ||
  222. F(f,2) != IGL_COLLAPSE_EDGE_NULL)
  223. {
  224. F2.row(m) = F.row(f);
  225. J(m) = f;
  226. m++;
  227. }
  228. }
  229. F2.conservativeResize(m,F2.cols());
  230. J.conservativeResize(m);
  231. VectorXi _1;
  232. remove_unreferenced(V,F2,U,G,_1,I);
  233. return clean_finish;
  234. }