decimate.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 "connect_boundary_to_infinity.h"
  14. #include <iostream>
  15. IGL_INLINE bool igl::decimate(
  16. const Eigen::MatrixXd & V,
  17. const Eigen::MatrixXi & F,
  18. const size_t max_m,
  19. Eigen::MatrixXd & U,
  20. Eigen::MatrixXi & G,
  21. Eigen::VectorXi & J)
  22. {
  23. // Original number of faces
  24. const int orig_m = F.rows();
  25. // Tracking number of faces
  26. int m = F.rows();
  27. const auto & shortest_edge_and_midpoint = [](
  28. const int e,
  29. const Eigen::MatrixXd & V,
  30. const Eigen::MatrixXi & /*F*/,
  31. const Eigen::MatrixXi & E,
  32. const Eigen::VectorXi & /*EMAP*/,
  33. const Eigen::MatrixXi & /*EF*/,
  34. const Eigen::MatrixXi & /*EI*/,
  35. double & cost,
  36. Eigen::RowVectorXd & p)
  37. {
  38. cost = (V.row(E(e,0))-V.row(E(e,1))).norm();
  39. p = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
  40. };
  41. typedef Eigen::MatrixXd DerivedV;
  42. typedef Eigen::MatrixXi DerivedF;
  43. DerivedV VO;
  44. DerivedF FO;
  45. igl::connect_boundary_to_infinity(V,F,VO,FO);
  46. const auto & max_non_infinite_faces_stopping_condition =
  47. [max_m,orig_m,&m](
  48. const Eigen::MatrixXd &,
  49. const Eigen::MatrixXi &,
  50. const Eigen::MatrixXi &,
  51. const Eigen::VectorXi &,
  52. const Eigen::MatrixXi &,
  53. const Eigen::MatrixXi &,
  54. const std::set<std::pair<double,int> > &,
  55. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  56. const Eigen::MatrixXd &,
  57. const int,
  58. const int,
  59. const int,
  60. const int f1,
  61. const int f2) -> bool
  62. {
  63. // Only subtract if we're collapsing a real face
  64. if(f1 < orig_m) m-=1;
  65. if(f2 < orig_m) m-=1;
  66. return m<=(int)max_m;
  67. };
  68. bool ret = decimate(
  69. VO,
  70. FO,
  71. shortest_edge_and_midpoint,
  72. max_non_infinite_faces_stopping_condition,
  73. U,
  74. G,
  75. J);
  76. const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
  77. igl::slice_mask(Eigen::MatrixXi(G),keep,1,G);
  78. igl::slice_mask(Eigen::VectorXi(J),keep,1,J);
  79. Eigen::VectorXi _1;
  80. igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1);
  81. return ret;
  82. }
  83. IGL_INLINE bool igl::decimate(
  84. const Eigen::MatrixXd & OV,
  85. const Eigen::MatrixXi & OF,
  86. const std::function<void(
  87. const int,
  88. const Eigen::MatrixXd &,
  89. const Eigen::MatrixXi &,
  90. const Eigen::MatrixXi &,
  91. const Eigen::VectorXi &,
  92. const Eigen::MatrixXi &,
  93. const Eigen::MatrixXi &,
  94. double &,
  95. Eigen::RowVectorXd &)> & cost_and_placement,
  96. const std::function<bool(
  97. const Eigen::MatrixXd &,
  98. const Eigen::MatrixXi &,
  99. const Eigen::MatrixXi &,
  100. const Eigen::VectorXi &,
  101. const Eigen::MatrixXi &,
  102. const Eigen::MatrixXi &,
  103. const std::set<std::pair<double,int> > &,
  104. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  105. const Eigen::MatrixXd &,
  106. const int,
  107. const int,
  108. const int,
  109. const int,
  110. const int)> & stopping_condition,
  111. Eigen::MatrixXd & U,
  112. Eigen::MatrixXi & G,
  113. Eigen::VectorXi & J)
  114. {
  115. using namespace Eigen;
  116. using namespace std;
  117. // Working copies
  118. Eigen::MatrixXd V = OV;
  119. Eigen::MatrixXi F = OF;
  120. VectorXi EMAP;
  121. MatrixXi E,EF,EI;
  122. typedef std::set<std::pair<double,int> > PriorityQueue;
  123. PriorityQueue Q;
  124. std::vector<PriorityQueue::iterator > Qit;
  125. edge_flaps(F,E,EMAP,EF,EI);
  126. Qit.resize(E.rows());
  127. // If an edge were collapsed, we'd collapse it to these points:
  128. MatrixXd C(E.rows(),V.cols());
  129. for(int e = 0;e<E.rows();e++)
  130. {
  131. double cost = e;
  132. RowVectorXd p(1,3);
  133. cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
  134. C.row(e) = p;
  135. Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
  136. }
  137. int prev_e = -1;
  138. bool clean_finish = false;
  139. while(true)
  140. {
  141. if(Q.empty())
  142. {
  143. break;
  144. }
  145. if(Q.begin()->first == std::numeric_limits<double>::infinity())
  146. {
  147. // min cost edge is infinite cost
  148. break;
  149. }
  150. int e,e1,e2,f1,f2;
  151. if(collapse_edge(cost_and_placement,V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  152. {
  153. if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  154. {
  155. clean_finish = true;
  156. break;
  157. }
  158. }else
  159. {
  160. if(prev_e == e)
  161. {
  162. assert(false && "Edge collapse no progress... bad stopping condition?");
  163. break;
  164. }
  165. // Edge was not collapsed... must have been invalid. collapse_edge should
  166. // have updated its cost to inf... continue
  167. }
  168. prev_e = e;
  169. }
  170. // remove all IGL_COLLAPSE_EDGE_NULL faces
  171. MatrixXi F2(F.rows(),3);
  172. J.resize(F.rows());
  173. int m = 0;
  174. for(int f = 0;f<F.rows();f++)
  175. {
  176. if(
  177. F(f,0) != IGL_COLLAPSE_EDGE_NULL ||
  178. F(f,1) != IGL_COLLAPSE_EDGE_NULL ||
  179. F(f,2) != IGL_COLLAPSE_EDGE_NULL)
  180. {
  181. F2.row(m) = F.row(f);
  182. J(m) = f;
  183. m++;
  184. }
  185. }
  186. F2.conservativeResize(m,F2.cols());
  187. J.conservativeResize(m);
  188. VectorXi _1;
  189. remove_unreferenced(V,F2,U,G,_1);
  190. return clean_finish;
  191. }