decimate.cpp 4.0 KB

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