decimate.cpp 3.9 KB

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