decimate.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. IGL_INLINE bool igl::decimate(
  18. const Eigen::MatrixXd & V,
  19. const Eigen::MatrixXi & F,
  20. const size_t max_m,
  21. Eigen::MatrixXd & U,
  22. Eigen::MatrixXi & G,
  23. Eigen::VectorXi & J,
  24. Eigen::VectorXi & I)
  25. {
  26. // Original number of faces
  27. const int orig_m = F.rows();
  28. // Tracking number of faces
  29. int m = F.rows();
  30. typedef Eigen::MatrixXd DerivedV;
  31. typedef Eigen::MatrixXi DerivedF;
  32. DerivedV VO;
  33. DerivedF FO;
  34. igl::connect_boundary_to_infinity(V,F,VO,FO);
  35. bool ret = decimate(
  36. VO,
  37. FO,
  38. shortest_edge_and_midpoint,
  39. max_faces_stopping_condition(m,orig_m,max_m),
  40. U,
  41. G,
  42. J,
  43. I);
  44. const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
  45. igl::slice_mask(Eigen::MatrixXi(G),keep,1,G);
  46. igl::slice_mask(Eigen::VectorXi(J),keep,1,J);
  47. Eigen::VectorXi _1,I2;
  48. igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1,I2);
  49. igl::slice(Eigen::VectorXi(I),I2,1,I);
  50. return ret;
  51. }
  52. IGL_INLINE bool igl::decimate(
  53. const Eigen::MatrixXd & V,
  54. const Eigen::MatrixXi & F,
  55. const size_t max_m,
  56. Eigen::MatrixXd & U,
  57. Eigen::MatrixXi & G,
  58. Eigen::VectorXi & J)
  59. {
  60. Eigen::VectorXi I;
  61. return igl::decimate(V,F,max_m,U,G,J,I);
  62. }
  63. IGL_INLINE bool igl::decimate(
  64. const Eigen::MatrixXd & OV,
  65. const Eigen::MatrixXi & OF,
  66. const std::function<void(
  67. const int,
  68. const Eigen::MatrixXd &,
  69. const Eigen::MatrixXi &,
  70. const Eigen::MatrixXi &,
  71. const Eigen::VectorXi &,
  72. const Eigen::MatrixXi &,
  73. const Eigen::MatrixXi &,
  74. double &,
  75. Eigen::RowVectorXd &)> & cost_and_placement,
  76. const std::function<bool(
  77. const Eigen::MatrixXd &,
  78. const Eigen::MatrixXi &,
  79. const Eigen::MatrixXi &,
  80. const Eigen::VectorXi &,
  81. const Eigen::MatrixXi &,
  82. const Eigen::MatrixXi &,
  83. const std::set<std::pair<double,int> > &,
  84. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  85. const Eigen::MatrixXd &,
  86. const int,
  87. const int,
  88. const int,
  89. const int,
  90. const int)> & stopping_condition,
  91. Eigen::MatrixXd & U,
  92. Eigen::MatrixXi & G,
  93. Eigen::VectorXi & J,
  94. Eigen::VectorXi & I
  95. )
  96. {
  97. const auto always_try = [](
  98. const Eigen::MatrixXd & ,/*V*/
  99. const Eigen::MatrixXi & ,/*F*/
  100. const Eigen::MatrixXi & ,/*E*/
  101. const Eigen::VectorXi & ,/*EMAP*/
  102. const Eigen::MatrixXi & ,/*EF*/
  103. const Eigen::MatrixXi & ,/*EI*/
  104. const std::set<std::pair<double,int> > & ,/*Q*/
  105. const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
  106. const Eigen::MatrixXd & ,/*C*/
  107. const int /*e*/
  108. ) -> bool { return true;};
  109. const auto never_care = [](
  110. const Eigen::MatrixXd & , /*V*/
  111. const Eigen::MatrixXi & , /*F*/
  112. const Eigen::MatrixXi & , /*E*/
  113. const Eigen::VectorXi & ,/*EMAP*/
  114. const Eigen::MatrixXi & , /*EF*/
  115. const Eigen::MatrixXi & , /*EI*/
  116. const std::set<std::pair<double,int> > & , /*Q*/
  117. const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
  118. const Eigen::MatrixXd & , /*C*/
  119. const int , /*e*/
  120. const int , /*e1*/
  121. const int , /*e2*/
  122. const int , /*f1*/
  123. const int , /*f2*/
  124. const bool /*collapsed*/
  125. )-> void { };
  126. return igl::decimate(
  127. OV,OF,cost_and_placement,stopping_condition,always_try,never_care,U,G,J,I);
  128. }
  129. IGL_INLINE bool igl::decimate(
  130. const Eigen::MatrixXd & OV,
  131. const Eigen::MatrixXi & OF,
  132. const std::function<void(
  133. const int,
  134. const Eigen::MatrixXd &,
  135. const Eigen::MatrixXi &,
  136. const Eigen::MatrixXi &,
  137. const Eigen::VectorXi &,
  138. const Eigen::MatrixXi &,
  139. const Eigen::MatrixXi &,
  140. double &,
  141. Eigen::RowVectorXd &)> & cost_and_placement,
  142. const std::function<bool(
  143. const Eigen::MatrixXd &,
  144. const Eigen::MatrixXi &,
  145. const Eigen::MatrixXi &,
  146. const Eigen::VectorXi &,
  147. const Eigen::MatrixXi &,
  148. const Eigen::MatrixXi &,
  149. const std::set<std::pair<double,int> > &,
  150. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  151. const Eigen::MatrixXd &,
  152. const int,
  153. const int,
  154. const int,
  155. const int,
  156. const int)> & stopping_condition,
  157. const std::function<bool(
  158. const Eigen::MatrixXd & ,/*V*/
  159. const Eigen::MatrixXi & ,/*F*/
  160. const Eigen::MatrixXi & ,/*E*/
  161. const Eigen::VectorXi & ,/*EMAP*/
  162. const Eigen::MatrixXi & ,/*EF*/
  163. const Eigen::MatrixXi & ,/*EI*/
  164. const std::set<std::pair<double,int> > & ,/*Q*/
  165. const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
  166. const Eigen::MatrixXd & ,/*C*/
  167. const int /*e*/
  168. )> & pre_collapse,
  169. const std::function<void(
  170. const Eigen::MatrixXd & , /*V*/
  171. const Eigen::MatrixXi & , /*F*/
  172. const Eigen::MatrixXi & , /*E*/
  173. const Eigen::VectorXi & ,/*EMAP*/
  174. const Eigen::MatrixXi & , /*EF*/
  175. const Eigen::MatrixXi & , /*EI*/
  176. const std::set<std::pair<double,int> > & , /*Q*/
  177. const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
  178. const Eigen::MatrixXd & , /*C*/
  179. const int , /*e*/
  180. const int , /*e1*/
  181. const int , /*e2*/
  182. const int , /*f1*/
  183. const int , /*f2*/
  184. const bool /*collapsed*/
  185. )> & post_collapse,
  186. Eigen::MatrixXd & U,
  187. Eigen::MatrixXi & G,
  188. Eigen::VectorXi & J,
  189. Eigen::VectorXi & I
  190. )
  191. {
  192. using namespace Eigen;
  193. using namespace std;
  194. VectorXi EMAP;
  195. MatrixXi E,EF,EI;
  196. edge_flaps(OF,E,EMAP,EF,EI);
  197. return igl::decimate(
  198. OV,OF,
  199. cost_and_placement,stopping_condition,pre_collapse,post_collapse,
  200. E,EMAP,EF,EI,
  201. U,G,J,I);
  202. }
  203. IGL_INLINE bool igl::decimate(
  204. const Eigen::MatrixXd & OV,
  205. const Eigen::MatrixXi & OF,
  206. const std::function<void(
  207. const int,
  208. const Eigen::MatrixXd &,
  209. const Eigen::MatrixXi &,
  210. const Eigen::MatrixXi &,
  211. const Eigen::VectorXi &,
  212. const Eigen::MatrixXi &,
  213. const Eigen::MatrixXi &,
  214. double &,
  215. Eigen::RowVectorXd &)> & cost_and_placement,
  216. const std::function<bool(
  217. const Eigen::MatrixXd &,
  218. const Eigen::MatrixXi &,
  219. const Eigen::MatrixXi &,
  220. const Eigen::VectorXi &,
  221. const Eigen::MatrixXi &,
  222. const Eigen::MatrixXi &,
  223. const std::set<std::pair<double,int> > &,
  224. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  225. const Eigen::MatrixXd &,
  226. const int,
  227. const int,
  228. const int,
  229. const int,
  230. const int)> & stopping_condition,
  231. const std::function<bool(
  232. const Eigen::MatrixXd & ,/*V*/
  233. const Eigen::MatrixXi & ,/*F*/
  234. const Eigen::MatrixXi & ,/*E*/
  235. const Eigen::VectorXi & ,/*EMAP*/
  236. const Eigen::MatrixXi & ,/*EF*/
  237. const Eigen::MatrixXi & ,/*EI*/
  238. const std::set<std::pair<double,int> > & ,/*Q*/
  239. const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
  240. const Eigen::MatrixXd & ,/*C*/
  241. const int /*e*/
  242. )> & pre_collapse,
  243. const std::function<void(
  244. const Eigen::MatrixXd & , /*V*/
  245. const Eigen::MatrixXi & , /*F*/
  246. const Eigen::MatrixXi & , /*E*/
  247. const Eigen::VectorXi & ,/*EMAP*/
  248. const Eigen::MatrixXi & , /*EF*/
  249. const Eigen::MatrixXi & , /*EI*/
  250. const std::set<std::pair<double,int> > & , /*Q*/
  251. const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
  252. const Eigen::MatrixXd & , /*C*/
  253. const int , /*e*/
  254. const int , /*e1*/
  255. const int , /*e2*/
  256. const int , /*f1*/
  257. const int , /*f2*/
  258. const bool /*collapsed*/
  259. )> & post_collapse,
  260. const Eigen::MatrixXi & OE,
  261. const Eigen::VectorXi & OEMAP,
  262. const Eigen::MatrixXi & OEF,
  263. const Eigen::MatrixXi & OEI,
  264. Eigen::MatrixXd & U,
  265. Eigen::MatrixXi & G,
  266. Eigen::VectorXi & J,
  267. Eigen::VectorXi & I
  268. )
  269. {
  270. // Decimate 1
  271. using namespace Eigen;
  272. using namespace std;
  273. // Working copies
  274. Eigen::MatrixXd V = OV;
  275. Eigen::MatrixXi F = OF;
  276. Eigen::MatrixXi E = OE;
  277. Eigen::VectorXi EMAP = OEMAP;
  278. Eigen::MatrixXi EF = OEF;
  279. Eigen::MatrixXi EI = OEI;
  280. typedef std::set<std::pair<double,int> > PriorityQueue;
  281. PriorityQueue Q;
  282. std::vector<PriorityQueue::iterator > Qit;
  283. Qit.resize(E.rows());
  284. // If an edge were collapsed, we'd collapse it to these points:
  285. MatrixXd C(E.rows(),V.cols());
  286. for(int e = 0;e<E.rows();e++)
  287. {
  288. double cost = e;
  289. RowVectorXd p(1,3);
  290. cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
  291. C.row(e) = p;
  292. Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
  293. }
  294. int prev_e = -1;
  295. bool clean_finish = false;
  296. while(true)
  297. {
  298. if(Q.empty())
  299. {
  300. break;
  301. }
  302. if(Q.begin()->first == std::numeric_limits<double>::infinity())
  303. {
  304. // min cost edge is infinite cost
  305. break;
  306. }
  307. int e,e1,e2,f1,f2;
  308. if(collapse_edge(
  309. cost_and_placement, pre_collapse, post_collapse,
  310. V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  311. {
  312. if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  313. {
  314. clean_finish = true;
  315. break;
  316. }
  317. }else
  318. {
  319. if(prev_e == e)
  320. {
  321. assert(false && "Edge collapse no progress... bad stopping condition?");
  322. break;
  323. }
  324. // Edge was not collapsed... must have been invalid. collapse_edge should
  325. // have updated its cost to inf... continue
  326. }
  327. prev_e = e;
  328. }
  329. // remove all IGL_COLLAPSE_EDGE_NULL faces
  330. MatrixXi F2(F.rows(),3);
  331. J.resize(F.rows());
  332. int m = 0;
  333. for(int f = 0;f<F.rows();f++)
  334. {
  335. if(
  336. F(f,0) != IGL_COLLAPSE_EDGE_NULL ||
  337. F(f,1) != IGL_COLLAPSE_EDGE_NULL ||
  338. F(f,2) != IGL_COLLAPSE_EDGE_NULL)
  339. {
  340. F2.row(m) = F.row(f);
  341. J(m) = f;
  342. m++;
  343. }
  344. }
  345. F2.conservativeResize(m,F2.cols());
  346. J.conservativeResize(m);
  347. VectorXi _1;
  348. remove_unreferenced(V,F2,U,G,_1,I);
  349. return clean_finish;
  350. }