intersection_blocking_collapse_edge_callbacks.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include "intersection_blocking_collapse_edge_callbacks.h"
  2. #include "AABB.h"
  3. #include "circulation.h"
  4. #include "decimate_trivial_callbacks.h"
  5. #include "collapse_edge_would_create_intersections.h"
  6. // If debugging, it's a good idea to run this once in release mode to collect
  7. // the edge id then adjust below.
  8. //#define IGL_INTERSECTION_BLOCKING_COLLAPSE_EDGE_CALLBACKS_DEBUG
  9. #ifdef IGL_INTERSECTION_BLOCKING_COLLAPSE_EDGE_CALLBACKS_DEBUG
  10. #include "copyleft/cgal/is_self_intersecting.h"
  11. #include "writePLY.h"
  12. #endif
  13. void igl::intersection_blocking_collapse_edge_callbacks(
  14. const igl::decimate_pre_collapse_callback & orig_pre_collapse,
  15. const igl::decimate_post_collapse_callback & orig_post_collapse,
  16. const std::vector<igl::AABB<Eigen::MatrixXd,3> *> & leaves,
  17. igl::AABB<Eigen::MatrixXd,3> * & tree,
  18. igl::decimate_pre_collapse_callback & pre_collapse,
  19. igl::decimate_post_collapse_callback & post_collapse
  20. )
  21. {
  22. // Not clear padding would help much but could try it.
  23. const double pad = 0;
  24. const int leaves_size = (int)leaves.size();
  25. // Capture the original callbacks by value so that caller can destory their
  26. // copy.
  27. pre_collapse =
  28. [orig_pre_collapse,leaves_size,&tree](
  29. const Eigen::MatrixXd & V,
  30. const Eigen::MatrixXi & F,
  31. const Eigen::MatrixXi & E,
  32. const Eigen::VectorXi & EMAP,
  33. const Eigen::MatrixXi & EF,
  34. const Eigen::MatrixXi & EI,
  35. const igl::min_heap< std::tuple<double,int,int> > & Q,
  36. const Eigen::VectorXi & EQ,
  37. const Eigen::MatrixXd & C,
  38. const int e)->bool
  39. {
  40. if(!orig_pre_collapse(V,F,E,EMAP,EF,EI,Q,EQ,C,e))
  41. {
  42. return false;
  43. }
  44. // Check if there would be (new) intersections
  45. return
  46. !igl::collapse_edge_would_create_intersections(
  47. e,C.row(e).eval(),V,F,E,EMAP,EF,EI,*tree,leaves_size);
  48. };
  49. // leaves could also be captured by value
  50. post_collapse =
  51. [orig_post_collapse,leaves,pad,leaves_size,&tree](
  52. const Eigen::MatrixXd & V,
  53. const Eigen::MatrixXi & F,
  54. const Eigen::MatrixXi & E,
  55. const Eigen::VectorXi & EMAP,
  56. const Eigen::MatrixXi & EF,
  57. const Eigen::MatrixXi & EI,
  58. const igl::min_heap< std::tuple<double,int,int> > & Q,
  59. const Eigen::VectorXi & EQ,
  60. const Eigen::MatrixXd & C,
  61. const int e,
  62. const int e1,
  63. const int e2,
  64. const int f1,
  65. const int f2,
  66. const bool collapsed)
  67. {
  68. if(collapsed)
  69. {
  70. // detach leaves of deleted faces
  71. for(int f : {f1,f2})
  72. {
  73. // Skip faces that aren't in leaves (e.g., infinite faces)
  74. if(f >= leaves_size) { continue; }
  75. auto * sibling = leaves[f]->detach();
  76. sibling->refit_lineage();
  77. tree = sibling->root();
  78. delete leaves[f];
  79. }
  80. // If finding `Nf` becomes a bottleneck we could remember it via
  81. // `pre_collapse` the same way that
  82. // `qslim_optimal_collapse_edge_callbacks` remembers `v1` and `v2`
  83. const int m = F.rows();
  84. const auto survivors =
  85. [&m,&e,&EF,&EI,&EMAP](const int f1, const int e1, int & d1)
  86. {
  87. int c;
  88. for(c=0;c<3;c++)
  89. {
  90. d1 = EMAP(f1+c*m);
  91. if((d1 != e) && (d1 != e1)) { break; }
  92. }
  93. assert(c<3);
  94. };
  95. int d1,d2;
  96. survivors(f1,e1,d1);
  97. survivors(f2,e2,d2);
  98. // Will circulating by continuing in the CCW direction of E(d1,:)
  99. // encircle the common edge? That is, is E(d1,1) the common vertex?
  100. const bool ccw = E(d1,1) == E(d2,0) || E(d1,1) == E(d2,1);
  101. #ifndef NDEBUG
  102. // Common vertex.
  103. const int s = E(d1,ccw?1:0);
  104. assert(s == E(d2,0) || s == E(d2,1));
  105. #endif
  106. std::vector<int> Nf;
  107. {
  108. std::vector<int> Nv;
  109. igl::circulation(d1,ccw,F,EMAP,EF,EI,Nv,Nf);
  110. }
  111. for(const int & f : Nf)
  112. {
  113. // Skip faces that aren't in leaves (e.g., infinite faces)
  114. if(f >= leaves_size) { continue; }
  115. Eigen::AlignedBox<double,3> box;
  116. box
  117. .extend(V.row(F(f,0)).transpose())
  118. .extend(V.row(F(f,1)).transpose())
  119. .extend(V.row(F(f,2)).transpose());
  120. // Always grab root (returns self if no update)
  121. tree = leaves[f]->update(box,pad)->root();
  122. assert(tree == tree->root());
  123. }
  124. assert(tree == tree->root());
  125. }
  126. #ifdef IGL_INTERSECTION_BLOCKING_COLLAPSE_EDGE_CALLBACKS_DEBUG
  127. #warning "🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌🐌 Slow intersection checking..."
  128. constexpr bool stinker = false;
  129. //const bool stinker = e==2581;
  130. if(stinker && igl::copyleft::cgal::is_self_intersecting(V,F))
  131. {
  132. igl::writePLY("after.ply",V,F);
  133. printf("💩🛌@e=%d \n",e);
  134. exit(1);
  135. }
  136. #endif
  137. // Finally. Run callback.
  138. return orig_post_collapse(
  139. V,F,E,EMAP,EF,EI,Q,EQ,C,e,e1,e2,f1,f2,collapsed);
  140. };
  141. }
  142. IGL_INLINE void igl::intersection_blocking_collapse_edge_callbacks(
  143. const igl::decimate_pre_collapse_callback & orig_pre_collapse,
  144. const igl::decimate_post_collapse_callback & orig_post_collapse,
  145. igl::AABB<Eigen::MatrixXd,3> * & tree,
  146. igl::decimate_pre_collapse_callback & pre_collapse,
  147. igl::decimate_post_collapse_callback & post_collapse)
  148. {
  149. return intersection_blocking_collapse_edge_callbacks(
  150. orig_pre_collapse,
  151. orig_post_collapse,
  152. tree->gather_leaves(),
  153. tree,
  154. pre_collapse,
  155. post_collapse);
  156. }
  157. IGL_INLINE void igl::intersection_blocking_collapse_edge_callbacks(
  158. igl::AABB<Eigen::MatrixXd,3> * & tree,
  159. igl::decimate_pre_collapse_callback & pre_collapse,
  160. igl::decimate_post_collapse_callback & post_collapse)
  161. {
  162. igl::decimate_pre_collapse_callback always_try;
  163. igl::decimate_post_collapse_callback never_care;
  164. igl::decimate_trivial_callbacks(always_try,never_care);
  165. intersection_blocking_collapse_edge_callbacks(
  166. always_try,
  167. never_care,
  168. tree,
  169. pre_collapse,
  170. post_collapse);
  171. }