decimate.cpp 13 KB

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