decimate.cpp 4.3 KB

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