collapse_edge.cpp 10 KB

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