collapse_edge.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 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 "collapse_edge.h"
  9. #include "circulation.h"
  10. #include "edge_collapse_is_valid.h"
  11. #include <vector>
  12. IGL_INLINE bool igl::collapse_edge(
  13. const int e,
  14. const Eigen::RowVectorXd & p,
  15. Eigen::MatrixXd & V,
  16. Eigen::MatrixXi & F,
  17. Eigen::MatrixXi & E,
  18. Eigen::VectorXi & EMAP,
  19. Eigen::MatrixXi & EF,
  20. Eigen::MatrixXi & EI,
  21. int & a_e1,
  22. int & a_e2,
  23. int & a_f1,
  24. int & a_f2)
  25. {
  26. // Assign this to 0 rather than, say, -1 so that deleted elements will get
  27. // draw as degenerate elements at vertex 0 (which should always exist and
  28. // never get collapsed to anything else since it is the smallest index)
  29. using namespace Eigen;
  30. using namespace std;
  31. const int eflip = E(e,0)>E(e,1);
  32. // source and destination
  33. const int s = eflip?E(e,1):E(e,0);
  34. const int d = eflip?E(e,0):E(e,1);
  35. if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
  36. {
  37. return false;
  38. }
  39. // Important to grab neighbors of d before monkeying with edges
  40. const std::vector<int> nV2Fd = circulation(e,!eflip,EMAP,EF,EI);
  41. // The following implementation strongly relies on s<d
  42. assert(s<d && "s should be less than d");
  43. // move source and destination to midpoint
  44. V.row(s) = p;
  45. V.row(d) = p;
  46. // Helper function to replace edge and associate information with NULL
  47. const auto & kill_edge = [&E,&EI,&EF](const int e)
  48. {
  49. E(e,0) = IGL_COLLAPSE_EDGE_NULL;
  50. E(e,1) = IGL_COLLAPSE_EDGE_NULL;
  51. EF(e,0) = IGL_COLLAPSE_EDGE_NULL;
  52. EF(e,1) = IGL_COLLAPSE_EDGE_NULL;
  53. EI(e,0) = IGL_COLLAPSE_EDGE_NULL;
  54. EI(e,1) = IGL_COLLAPSE_EDGE_NULL;
  55. };
  56. // update edge info
  57. // for each flap
  58. const int m = F.rows();
  59. for(int side = 0;side<2;side++)
  60. {
  61. const int f = EF(e,side);
  62. const int v = EI(e,side);
  63. const int sign = (eflip==0?1:-1)*(1-2*side);
  64. // next edge emanating from d
  65. const int e1 = EMAP(f+m*((v+sign*1+3)%3));
  66. // prev edge pointing to s
  67. const int e2 = EMAP(f+m*((v+sign*2+3)%3));
  68. assert(E(e1,0) == d || E(e1,1) == d);
  69. assert(E(e2,0) == s || E(e2,1) == s);
  70. // face adjacent to f on e1, also incident on d
  71. const bool flip1 = EF(e1,1)==f;
  72. const int f1 = flip1 ? EF(e1,0) : EF(e1,1);
  73. assert(f1!=f);
  74. assert(F(f1,0)==d || F(f1,1)==d || F(f1,2) == d);
  75. // across from which vertex of f1 does e1 appear?
  76. const int v1 = flip1 ? EI(e1,0) : EI(e1,1);
  77. // Kill e1
  78. kill_edge(e1);
  79. // Kill f
  80. F(f,0) = IGL_COLLAPSE_EDGE_NULL;
  81. F(f,1) = IGL_COLLAPSE_EDGE_NULL;
  82. F(f,2) = IGL_COLLAPSE_EDGE_NULL;
  83. // map f1's edge on e1 to e2
  84. assert(EMAP(f1+m*v1) == e1);
  85. EMAP(f1+m*v1) = e2;
  86. // side opposite f2, the face adjacent to f on e2, also incident on s
  87. const int opp2 = (EF(e2,0)==f?0:1);
  88. assert(EF(e2,opp2) == f);
  89. EF(e2,opp2) = f1;
  90. EI(e2,opp2) = v1;
  91. // remap e2 from d to s
  92. E(e2,0) = E(e2,0)==d ? s : E(e2,0);
  93. E(e2,1) = E(e2,1)==d ? s : E(e2,1);
  94. if(side==0)
  95. {
  96. a_e1 = e1;
  97. a_f1 = f;
  98. }else
  99. {
  100. a_e2 = e1;
  101. a_f2 = f;
  102. }
  103. }
  104. // finally, reindex faces and edges incident on d. Do this last so asserts
  105. // make sense.
  106. //
  107. // Could actually skip first and last, since those are always the two
  108. // collpased faces.
  109. for(auto f : nV2Fd)
  110. {
  111. for(int v = 0;v<3;v++)
  112. {
  113. if(F(f,v) == d)
  114. {
  115. const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
  116. const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
  117. assert(
  118. E(EMAP(f+m*((v+1)%3)),flip1) == d ||
  119. E(EMAP(f+m*((v+1)%3)),flip1) == s);
  120. E(EMAP(f+m*((v+1)%3)),flip1) = s;
  121. assert(
  122. E(EMAP(f+m*((v+2)%3)),flip2) == d ||
  123. E(EMAP(f+m*((v+2)%3)),flip2) == s);
  124. E(EMAP(f+m*((v+2)%3)),flip2) = s;
  125. F(f,v) = s;
  126. break;
  127. }
  128. }
  129. }
  130. // Finally, "remove" this edge and its information
  131. kill_edge(e);
  132. return true;
  133. }
  134. IGL_INLINE bool igl::collapse_edge(
  135. const int e,
  136. const Eigen::RowVectorXd & p,
  137. Eigen::MatrixXd & V,
  138. Eigen::MatrixXi & F,
  139. Eigen::MatrixXi & E,
  140. Eigen::VectorXi & EMAP,
  141. Eigen::MatrixXi & EF,
  142. Eigen::MatrixXi & EI)
  143. {
  144. int e1,e2,f1,f2;
  145. return collapse_edge(e,p,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
  146. }
  147. IGL_INLINE bool igl::collapse_edge(
  148. const std::function<void(
  149. const int,
  150. const Eigen::MatrixXd &,
  151. const Eigen::MatrixXi &,
  152. const Eigen::MatrixXi &,
  153. const Eigen::VectorXi &,
  154. const Eigen::MatrixXi &,
  155. const Eigen::MatrixXi &,
  156. double &,
  157. Eigen::RowVectorXd &)> & cost_and_placement,
  158. Eigen::MatrixXd & V,
  159. Eigen::MatrixXi & F,
  160. Eigen::MatrixXi & E,
  161. Eigen::VectorXi & EMAP,
  162. Eigen::MatrixXi & EF,
  163. Eigen::MatrixXi & EI,
  164. std::set<std::pair<double,int> > & Q,
  165. std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
  166. Eigen::MatrixXd & C)
  167. {
  168. int e,e1,e2,f1,f2;
  169. const auto always_try = [](
  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. ) -> bool { return true;};
  181. const auto never_care = [](
  182. const Eigen::MatrixXd & , /*V*/
  183. const Eigen::MatrixXi & , /*F*/
  184. const Eigen::MatrixXi & , /*E*/
  185. const Eigen::VectorXi & ,/*EMAP*/
  186. const Eigen::MatrixXi & , /*EF*/
  187. const Eigen::MatrixXi & , /*EI*/
  188. const std::set<std::pair<double,int> > & , /*Q*/
  189. const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
  190. const Eigen::MatrixXd & , /*C*/
  191. const int , /*e*/
  192. const int , /*e1*/
  193. const int , /*e2*/
  194. const int , /*f1*/
  195. const int , /*f2*/
  196. const bool /*collapsed*/
  197. )-> void { };
  198. return
  199. collapse_edge(
  200. cost_and_placement,always_try,never_care,
  201. V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
  202. }
  203. IGL_INLINE bool igl::collapse_edge(
  204. const std::function<void(
  205. const int,
  206. const Eigen::MatrixXd &,
  207. const Eigen::MatrixXi &,
  208. const Eigen::MatrixXi &,
  209. const Eigen::VectorXi &,
  210. const Eigen::MatrixXi &,
  211. const Eigen::MatrixXi &,
  212. double &,
  213. Eigen::RowVectorXd &)> & cost_and_placement,
  214. const std::function<bool(
  215. const Eigen::MatrixXd & ,/*V*/
  216. const Eigen::MatrixXi & ,/*F*/
  217. const Eigen::MatrixXi & ,/*E*/
  218. const Eigen::VectorXi & ,/*EMAP*/
  219. const Eigen::MatrixXi & ,/*EF*/
  220. const Eigen::MatrixXi & ,/*EI*/
  221. const std::set<std::pair<double,int> > & ,/*Q*/
  222. const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
  223. const Eigen::MatrixXd & ,/*C*/
  224. const int /*e*/
  225. )> & pre_collapse,
  226. const std::function<void(
  227. const Eigen::MatrixXd & , /*V*/
  228. const Eigen::MatrixXi & , /*F*/
  229. const Eigen::MatrixXi & , /*E*/
  230. const Eigen::VectorXi & ,/*EMAP*/
  231. const Eigen::MatrixXi & , /*EF*/
  232. const Eigen::MatrixXi & , /*EI*/
  233. const std::set<std::pair<double,int> > & , /*Q*/
  234. const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
  235. const Eigen::MatrixXd & , /*C*/
  236. const int , /*e*/
  237. const int , /*e1*/
  238. const int , /*e2*/
  239. const int , /*f1*/
  240. const int , /*f2*/
  241. const bool /*collapsed*/
  242. )> & post_collapse,
  243. Eigen::MatrixXd & V,
  244. Eigen::MatrixXi & F,
  245. Eigen::MatrixXi & E,
  246. Eigen::VectorXi & EMAP,
  247. Eigen::MatrixXi & EF,
  248. Eigen::MatrixXi & EI,
  249. std::set<std::pair<double,int> > & Q,
  250. std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
  251. Eigen::MatrixXd & C)
  252. {
  253. int e,e1,e2,f1,f2;
  254. return
  255. collapse_edge(
  256. cost_and_placement,pre_collapse,post_collapse,
  257. V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
  258. }
  259. IGL_INLINE bool igl::collapse_edge(
  260. const std::function<void(
  261. const int,
  262. const Eigen::MatrixXd &,
  263. const Eigen::MatrixXi &,
  264. const Eigen::MatrixXi &,
  265. const Eigen::VectorXi &,
  266. const Eigen::MatrixXi &,
  267. const Eigen::MatrixXi &,
  268. double &,
  269. Eigen::RowVectorXd &)> & cost_and_placement,
  270. const std::function<bool(
  271. const Eigen::MatrixXd & ,/*V*/
  272. const Eigen::MatrixXi & ,/*F*/
  273. const Eigen::MatrixXi & ,/*E*/
  274. const Eigen::VectorXi & ,/*EMAP*/
  275. const Eigen::MatrixXi & ,/*EF*/
  276. const Eigen::MatrixXi & ,/*EI*/
  277. const std::set<std::pair<double,int> > & ,/*Q*/
  278. const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
  279. const Eigen::MatrixXd & ,/*C*/
  280. const int /*e*/
  281. )> & pre_collapse,
  282. const std::function<void(
  283. const Eigen::MatrixXd & , /*V*/
  284. const Eigen::MatrixXi & , /*F*/
  285. const Eigen::MatrixXi & , /*E*/
  286. const Eigen::VectorXi & ,/*EMAP*/
  287. const Eigen::MatrixXi & , /*EF*/
  288. const Eigen::MatrixXi & , /*EI*/
  289. const std::set<std::pair<double,int> > & , /*Q*/
  290. const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
  291. const Eigen::MatrixXd & , /*C*/
  292. const int , /*e*/
  293. const int , /*e1*/
  294. const int , /*e2*/
  295. const int , /*f1*/
  296. const int , /*f2*/
  297. const bool /*collapsed*/
  298. )> & post_collapse,
  299. Eigen::MatrixXd & V,
  300. Eigen::MatrixXi & F,
  301. Eigen::MatrixXi & E,
  302. Eigen::VectorXi & EMAP,
  303. Eigen::MatrixXi & EF,
  304. Eigen::MatrixXi & EI,
  305. std::set<std::pair<double,int> > & Q,
  306. std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
  307. Eigen::MatrixXd & C,
  308. int & e,
  309. int & e1,
  310. int & e2,
  311. int & f1,
  312. int & f2)
  313. {
  314. using namespace Eigen;
  315. if(Q.empty())
  316. {
  317. // no edges to collapse
  318. return false;
  319. }
  320. std::pair<double,int> p = *(Q.begin());
  321. if(p.first == std::numeric_limits<double>::infinity())
  322. {
  323. // min cost edge is infinite cost
  324. return false;
  325. }
  326. Q.erase(Q.begin());
  327. e = p.second;
  328. Qit[e] = Q.end();
  329. std::vector<int> N = circulation(e, true,EMAP,EF,EI);
  330. std::vector<int> Nd = circulation(e,false,EMAP,EF,EI);
  331. N.insert(N.begin(),Nd.begin(),Nd.end());
  332. bool collapsed = true;
  333. if(pre_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e))
  334. {
  335. collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
  336. }else
  337. {
  338. // Aborted by pre collapse callback
  339. collapsed = false;
  340. }
  341. post_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2,collapsed);
  342. if(collapsed)
  343. {
  344. // Erase the two, other collapsed edges
  345. Q.erase(Qit[e1]);
  346. Qit[e1] = Q.end();
  347. Q.erase(Qit[e2]);
  348. Qit[e2] = Q.end();
  349. // update local neighbors
  350. // loop over original face neighbors
  351. for(auto n : N)
  352. {
  353. if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
  354. F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
  355. F(n,2) != IGL_COLLAPSE_EDGE_NULL)
  356. {
  357. for(int v = 0;v<3;v++)
  358. {
  359. // get edge id
  360. const int ei = EMAP(v*F.rows()+n);
  361. // erase old entry
  362. Q.erase(Qit[ei]);
  363. // compute cost and potential placement
  364. double cost;
  365. RowVectorXd place;
  366. cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
  367. // Replace in queue
  368. Qit[ei] = Q.insert(std::pair<double,int>(cost,ei)).first;
  369. C.row(ei) = place;
  370. }
  371. }
  372. }
  373. }else
  374. {
  375. // reinsert with infinite weight (the provided cost function must **not**
  376. // have given this un-collapsable edge inf cost already)
  377. p.first = std::numeric_limits<double>::infinity();
  378. Qit[e] = Q.insert(p).first;
  379. }
  380. return collapsed;
  381. }