collapse_edge.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. using namespace igl;
  32. const int eflip = E(e,0)>E(e,1);
  33. // source and destination
  34. const int s = eflip?E(e,1):E(e,0);
  35. const int d = eflip?E(e,0):E(e,1);
  36. if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
  37. {
  38. return false;
  39. }
  40. // Important to grab neighbors of d before monkeying with edges
  41. const std::vector<int> nV2Fd = circulation(e,!eflip,F,E,EMAP,EF,EI);
  42. // The following implementation strongly relies on s<d
  43. assert(s<d && "s should be less than d");
  44. // move source and destination to midpoint
  45. V.row(s) = p;
  46. V.row(d) = p;
  47. // Helper function to replace edge and associate information with NULL
  48. const auto & kill_edge = [&E,&EI,&EF](const int e)
  49. {
  50. E(e,0) = IGL_COLLAPSE_EDGE_NULL;
  51. E(e,1) = IGL_COLLAPSE_EDGE_NULL;
  52. EF(e,0) = IGL_COLLAPSE_EDGE_NULL;
  53. EF(e,1) = IGL_COLLAPSE_EDGE_NULL;
  54. EI(e,0) = IGL_COLLAPSE_EDGE_NULL;
  55. EI(e,1) = IGL_COLLAPSE_EDGE_NULL;
  56. };
  57. // update edge info
  58. // for each flap
  59. const int m = F.rows();
  60. for(int side = 0;side<2;side++)
  61. {
  62. const int f = EF(e,side);
  63. const int v = EI(e,side);
  64. const int sign = (eflip==0?1:-1)*(1-2*side);
  65. // next edge emanating from d
  66. const int e1 = EMAP(f+m*((v+sign*1+3)%3));
  67. // prev edge pointing to s
  68. const int e2 = EMAP(f+m*((v+sign*2+3)%3));
  69. assert(E(e1,0) == d || E(e1,1) == d);
  70. assert(E(e2,0) == s || E(e2,1) == s);
  71. // face adjacent to f on e1, also incident on d
  72. const bool flip1 = EF(e1,1)==f;
  73. const int f1 = flip1 ? EF(e1,0) : EF(e1,1);
  74. assert(f1!=f);
  75. assert(F(f1,0)==d || F(f1,1)==d || F(f1,2) == d);
  76. // across from which vertex of f1 does e1 appear?
  77. const int v1 = flip1 ? EI(e1,0) : EI(e1,1);
  78. // Kill e1
  79. kill_edge(e1);
  80. // Kill f
  81. F(f,0) = IGL_COLLAPSE_EDGE_NULL;
  82. F(f,1) = IGL_COLLAPSE_EDGE_NULL;
  83. F(f,2) = IGL_COLLAPSE_EDGE_NULL;
  84. // map f1's edge on e1 to e2
  85. assert(EMAP(f1+m*v1) == e1);
  86. EMAP(f1+m*v1) = e2;
  87. // side opposite f2, the face adjacent to f on e2, also incident on s
  88. const int opp2 = (EF(e2,0)==f?0:1);
  89. assert(EF(e2,opp2) == f);
  90. EF(e2,opp2) = f1;
  91. EI(e2,opp2) = v1;
  92. // remap e2 from d to s
  93. E(e2,0) = E(e2,0)==d ? s : E(e2,0);
  94. E(e2,1) = E(e2,1)==d ? s : E(e2,1);
  95. if(side==0)
  96. {
  97. a_e1 = e1;
  98. a_f1 = f;
  99. }else
  100. {
  101. a_e2 = e1;
  102. a_f2 = f;
  103. }
  104. }
  105. // finally, reindex faces and edges incident on d. Do this last so asserts
  106. // make sense.
  107. //
  108. // Could actually skip first two, since those are always the two collpased
  109. // faces.
  110. for(auto f : nV2Fd)
  111. {
  112. for(int v = 0;v<3;v++)
  113. {
  114. if(F(f,v) == d)
  115. {
  116. const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
  117. const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
  118. assert(
  119. E(EMAP(f+m*((v+1)%3)),flip1) == d ||
  120. E(EMAP(f+m*((v+1)%3)),flip1) == s);
  121. E(EMAP(f+m*((v+1)%3)),flip1) = s;
  122. assert(
  123. E(EMAP(f+m*((v+2)%3)),flip2) == d ||
  124. E(EMAP(f+m*((v+2)%3)),flip2) == s);
  125. E(EMAP(f+m*((v+2)%3)),flip2) = s;
  126. F(f,v) = s;
  127. break;
  128. }
  129. }
  130. }
  131. // Finally, "remove" this edge and its information
  132. kill_edge(e);
  133. return true;
  134. }
  135. IGL_INLINE bool igl::collapse_edge(
  136. const int e,
  137. const Eigen::RowVectorXd & p,
  138. Eigen::MatrixXd & V,
  139. Eigen::MatrixXi & F,
  140. Eigen::MatrixXi & E,
  141. Eigen::VectorXi & EMAP,
  142. Eigen::MatrixXi & EF,
  143. Eigen::MatrixXi & EI)
  144. {
  145. int e1,e2,f1,f2;
  146. return collapse_edge(e,p,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
  147. }