collapse_edge_would_create_intersections.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #include "collapse_edge_would_create_intersections.h"
  2. #include "AABB.h"
  3. #include "circulation.h"
  4. #include "writePLY.h"
  5. #include "triangle_triangle_intersect.h"
  6. #include <Eigen/Geometry>
  7. #include <vector>
  8. #include <iostream>
  9. #include <algorithm>
  10. #include <cassert>
  11. IGL_INLINE bool igl::collapse_edge_would_create_intersections(
  12. const int e,
  13. const Eigen::RowVectorXd & p,
  14. const Eigen::MatrixXd & V,
  15. const Eigen::MatrixXi & F,
  16. const Eigen::MatrixXi & E,
  17. const Eigen::VectorXi & EMAP,
  18. const Eigen::MatrixXi & EF,
  19. const Eigen::MatrixXi & EI,
  20. const igl::AABB<Eigen::MatrixXd,3> & tree,
  21. const int inf_face_id)
  22. {
  23. // Merge two lists of integers
  24. const auto merge = [&](
  25. const std::vector<int> & A, const std::vector<int> & B)->
  26. std::vector<int>
  27. {
  28. std::vector<int> C;
  29. C.reserve( A.size() + B.size() ); // preallocate memory
  30. C.insert( C.end(), A.begin(), A.end() );
  31. C.insert( C.end(), B.begin(), B.end() );
  32. // https://stackoverflow.com/a/1041939/148668
  33. std::sort( C.begin(), C.end() );
  34. C.erase( std::unique( C.begin(), C.end() ), C.end() );
  35. return C;
  36. };
  37. std::vector<int> old_one_ring;
  38. {
  39. std::vector<int> Nsv,Nsf,Ndv,Ndf;
  40. igl::circulation(e, true,F,EMAP,EF,EI,Nsv,Nsf);
  41. igl::circulation(e,false,F,EMAP,EF,EI,Ndv,Ndf);
  42. old_one_ring = merge(Nsf,Ndf);
  43. }
  44. int f1 = EF(e,0);
  45. int f2 = EF(e,1);
  46. std::vector<int> new_one_ring = old_one_ring;
  47. // erase if ==f1 or ==f2
  48. new_one_ring.erase(
  49. std::remove(new_one_ring.begin(), new_one_ring.end(), f1),
  50. new_one_ring.end());
  51. new_one_ring.erase(
  52. std::remove(new_one_ring.begin(), new_one_ring.end(), f2),
  53. new_one_ring.end());
  54. // big box containing new_one_ring
  55. Eigen::AlignedBox<double,3> big_box;
  56. // Extend box by placement point
  57. big_box.extend(p.transpose());
  58. // Extend box by all other corners (skipping old edge vertices)
  59. for(const auto f : new_one_ring)
  60. {
  61. Eigen::RowVector3d corners[3];
  62. for(int c = 0;c<3;c++)
  63. {
  64. if(F(f,c) == E(e,0) || F(f,c) == E(e,1))
  65. {
  66. corners[c] = p;
  67. }else
  68. {
  69. corners[c] = V.row(F(f,c));
  70. big_box.extend(V.row(F(f,c)).transpose());
  71. }
  72. }
  73. // Degenerate triangles are considered intersections
  74. if((corners[0]-corners[1]).cross(corners[0]-corners[2]).squaredNorm() < 1e-16)
  75. {
  76. return true;
  77. }
  78. }
  79. std::vector<const igl::AABB<Eigen::MatrixXd,3>*> candidates;
  80. tree.append_intersecting_leaves(big_box,candidates);
  81. // Exclude any candidates that are in old_one_ring.
  82. // consider using unordered_set above so that this is O(n+m) rather than O(nm)
  83. candidates.erase(
  84. std::remove_if(candidates.begin(), candidates.end(),
  85. [&](const igl::AABB<Eigen::MatrixXd,3>* candidate) {
  86. return std::find(old_one_ring.begin(), old_one_ring.end(), candidate->m_primitive) != old_one_ring.end();
  87. }),
  88. candidates.end());
  89. // print candidates
  90. //const bool stinker = e==2581;
  91. constexpr bool stinker = false;
  92. if(stinker)
  93. {
  94. igl::writePLY("before.ply",V,F);
  95. std::cout<<"Ee = ["<<E(e,0)<<" "<<E(e,1)<<"]+1;"<<std::endl;
  96. std::cout<<"p = ["<<p<<"];"<<std::endl;
  97. // print new_one_ring as matlab vector of indices
  98. std::cout<<"new_one_ring = [";
  99. for(const auto f : new_one_ring)
  100. {
  101. std::cout<<f<<" ";
  102. }
  103. std::cout<<"]+1;"<<std::endl;
  104. // print candidates as matlab vector of indices
  105. std::cout<<"candidates = [";
  106. for(const auto * candidate : candidates)
  107. {
  108. std::cout<<candidate->m_primitive<<" ";
  109. }
  110. std::cout<<"]+1;"<<std::endl;
  111. }
  112. // For each pair of candidate and new_one_ring, check if they intersect
  113. bool found_intersection = false;
  114. for(const int & f : new_one_ring)
  115. {
  116. if(inf_face_id >= 0 && f >= inf_face_id) { continue; }
  117. Eigen::AlignedBox<double,3> small_box;
  118. small_box.extend(p.transpose());
  119. for(int c = 0;c<3;c++)
  120. {
  121. if(F(f,c) != E(e,0) && F(f,c) != E(e,1))
  122. {
  123. small_box.extend(V.row(F(f,c)).transpose());
  124. }
  125. }
  126. for(const auto * candidate : candidates)
  127. {
  128. const int g = candidate->m_primitive;
  129. //constexpr bool inner_stinker = false;
  130. const bool inner_stinker = stinker && (f==1492 && g==1554);
  131. if(inner_stinker){ printf(" f: %d g: %d\n",f,g); }
  132. if(!small_box.intersects(candidate->m_box))
  133. {
  134. if(inner_stinker){ printf(" ✅ boxes don't overlap\n"); }
  135. continue;
  136. }
  137. // Corner replaced by p
  138. int c;
  139. for(c = 0;c<3;c++)
  140. {
  141. if(F(f,c) == E(e,0) || F(f,c) == E(e,1))
  142. {
  143. break;
  144. }
  145. }
  146. assert(c<3);
  147. found_intersection = triangle_triangle_intersect(V,F,E,EMAP,EF,f,c,p,g);
  148. if(found_intersection) { break; }
  149. }
  150. if(found_intersection) { break; }
  151. }
  152. return found_intersection;
  153. }