decimate.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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 "decimate.h"
  9. #include "collapse_edge.h"
  10. #include "edge_flaps.h"
  11. #include "remove_unreferenced.h"
  12. #include <iostream>
  13. IGL_INLINE bool igl::decimate(
  14. const Eigen::MatrixXd & V,
  15. const Eigen::MatrixXi & F,
  16. const size_t max_m,
  17. Eigen::MatrixXd & U,
  18. Eigen::MatrixXi & G)
  19. {
  20. const auto & max_m_faces =
  21. [&max_m,&F](
  22. const Eigen::MatrixXd &,
  23. const Eigen::MatrixXi &,
  24. const Eigen::MatrixXi &,
  25. const Eigen::VectorXi &,
  26. const Eigen::MatrixXi &,
  27. const Eigen::MatrixXi &,
  28. const std::set<std::pair<double,int> > &,
  29. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  30. const Eigen::MatrixXd &,
  31. const int,
  32. const int,
  33. const int,
  34. const int,
  35. const int)->bool
  36. {
  37. using namespace std;
  38. static int m = F.rows();
  39. m-=2;
  40. return m<=(int)max_m;
  41. };
  42. const auto & shortest_edge_and_midpoint = [](
  43. const int e,
  44. const Eigen::MatrixXd & V,
  45. const Eigen::MatrixXi & /*F*/,
  46. const Eigen::MatrixXi & E,
  47. const Eigen::VectorXi & /*EMAP*/,
  48. const Eigen::MatrixXi & /*EF*/,
  49. const Eigen::MatrixXi & /*EI*/,
  50. double & cost,
  51. Eigen::RowVectorXd & p)
  52. {
  53. cost = (V.row(E(e,0))-V.row(E(e,1))).norm();
  54. p = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
  55. };
  56. return decimate(V,F,shortest_edge_and_midpoint,max_m_faces,U,G);
  57. }
  58. IGL_INLINE bool igl::decimate(
  59. const Eigen::MatrixXd & OV,
  60. const Eigen::MatrixXi & OF,
  61. const std::function<void(
  62. const int,
  63. const Eigen::MatrixXd &,
  64. const Eigen::MatrixXi &,
  65. const Eigen::MatrixXi &,
  66. const Eigen::VectorXi &,
  67. const Eigen::MatrixXi &,
  68. const Eigen::MatrixXi &,
  69. double &,
  70. Eigen::RowVectorXd &)> & cost_and_placement,
  71. const std::function<bool(
  72. const Eigen::MatrixXd &,
  73. const Eigen::MatrixXi &,
  74. const Eigen::MatrixXi &,
  75. const Eigen::VectorXi &,
  76. const Eigen::MatrixXi &,
  77. const Eigen::MatrixXi &,
  78. const std::set<std::pair<double,int> > &,
  79. const std::vector<std::set<std::pair<double,int> >::iterator > &,
  80. const Eigen::MatrixXd &,
  81. const int,
  82. const int,
  83. const int,
  84. const int,
  85. const int)> & stopping_condition,
  86. Eigen::MatrixXd & U,
  87. Eigen::MatrixXi & G)
  88. {
  89. using namespace Eigen;
  90. using namespace std;
  91. // Working copies
  92. Eigen::MatrixXd V = OV;
  93. Eigen::MatrixXi F = OF;
  94. VectorXi EMAP;
  95. MatrixXi E,EF,EI;
  96. typedef std::set<std::pair<double,int> > PriorityQueue;
  97. PriorityQueue Q;
  98. std::vector<PriorityQueue::iterator > Qit;
  99. edge_flaps(F,E,EMAP,EF,EI);
  100. Qit.resize(E.rows());
  101. // If an edge were collapsed, we'd collapse it to these points:
  102. MatrixXd C(E.rows(),V.cols());
  103. for(int e = 0;e<E.rows();e++)
  104. {
  105. double cost = e;
  106. RowVectorXd p(1,3);
  107. cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
  108. C.row(e) = p;
  109. Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
  110. }
  111. int prev_e = -1;
  112. bool clean_finish = false;
  113. while(true)
  114. {
  115. if(Q.empty())
  116. {
  117. break;
  118. }
  119. if(Q.begin()->first == std::numeric_limits<double>::infinity())
  120. {
  121. // min cost edge is infinite cost
  122. break;
  123. }
  124. int e,e1,e2,f1,f2;
  125. if(collapse_edge(cost_and_placement,V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  126. {
  127. if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
  128. {
  129. clean_finish = true;
  130. break;
  131. }
  132. }else
  133. {
  134. if(prev_e == e)
  135. {
  136. assert(false && "Edge collapse no progress... bad stopping condition?");
  137. break;
  138. }
  139. // Edge was not collapsed... must have been invalid. collapse_edge should
  140. // have updated its cost to inf... continue
  141. }
  142. prev_e = e;
  143. }
  144. // remove all IGL_COLLAPSE_EDGE_NULL faces
  145. MatrixXi F2(F.rows(),3);
  146. int m = 0;
  147. for(int f = 0;f<F.rows();f++)
  148. {
  149. if(
  150. F(f,0) != IGL_COLLAPSE_EDGE_NULL ||
  151. F(f,1) != IGL_COLLAPSE_EDGE_NULL ||
  152. F(f,2) != IGL_COLLAPSE_EDGE_NULL)
  153. {
  154. F2.row(m++) = F.row(f);
  155. }
  156. }
  157. F2.conservativeResize(m,F2.cols());
  158. VectorXi _1;
  159. remove_unreferenced(V,F2,U,G,_1);
  160. return clean_finish;
  161. }