qslim.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2016 Alec Jacobson <[email protected]>
  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 "qslim.h"
  9. #include "connect_boundary_to_infinity.h"
  10. #include "decimate.h"
  11. #include "edge_flaps.h"
  12. #include "find.h"
  13. #include "is_edge_manifold.h"
  14. #include "max_faces_stopping_condition.h"
  15. #include "per_vertex_point_to_plane_quadrics.h"
  16. #include "qslim_optimal_collapse_edge_callbacks.h"
  17. #include "placeholders.h"
  18. #include "quadric_binary_plus_operator.h"
  19. #include "remove_unreferenced.h"
  20. #include "intersection_blocking_collapse_edge_callbacks.h"
  21. #include "AABB.h"
  22. #include "PlainMatrix.h"
  23. IGL_INLINE bool igl::qslim(
  24. const Eigen::MatrixXd & V,
  25. const Eigen::MatrixXi & F,
  26. const int max_m,
  27. const bool block_intersections,
  28. Eigen::MatrixXd & U,
  29. Eigen::MatrixXi & G,
  30. Eigen::VectorXi & J,
  31. Eigen::VectorXi & I)
  32. {
  33. using namespace igl;
  34. igl::AABB<Eigen::MatrixXd, 3> * tree = nullptr;
  35. if(block_intersections)
  36. {
  37. tree = new igl::AABB<Eigen::MatrixXd, 3>();
  38. tree->init(V,F);
  39. }
  40. // Original number of faces
  41. const int orig_m = F.rows();
  42. // Tracking number of faces
  43. int m = F.rows();
  44. typedef Eigen::MatrixXd DerivedV;
  45. typedef Eigen::MatrixXi DerivedF;
  46. PlainMatrix<DerivedV,Eigen::Dynamic> VO;
  47. PlainMatrix<DerivedF,Eigen::Dynamic> FO;
  48. igl::connect_boundary_to_infinity(V,F,VO,FO);
  49. // decimate will not work correctly on non-edge-manifold meshes. By extension
  50. // this includes meshes with non-manifold vertices on the boundary since these
  51. // will create a non-manifold edge when connected to infinity.
  52. if(!is_edge_manifold(FO))
  53. {
  54. return false;
  55. }
  56. // These will unfortunately be immediately recomputed in decimate.
  57. Eigen::VectorXi EMAP;
  58. Eigen::MatrixXi E,EF,EI;
  59. edge_flaps(FO,E,EMAP,EF,EI);
  60. // Quadrics per vertex
  61. typedef std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> Quadric;
  62. std::vector<Quadric> quadrics;
  63. per_vertex_point_to_plane_quadrics(VO,FO,EMAP,EF,EI,quadrics);
  64. // State variables keeping track of edge we just collapsed
  65. int v1 = -1;
  66. int v2 = -1;
  67. // Callbacks for computing and updating metric
  68. decimate_cost_and_placement_callback cost_and_placement;
  69. decimate_pre_collapse_callback pre_collapse;
  70. decimate_post_collapse_callback post_collapse;
  71. qslim_optimal_collapse_edge_callbacks(
  72. E,quadrics,v1,v2, cost_and_placement, pre_collapse,post_collapse);
  73. if(block_intersections)
  74. {
  75. igl::intersection_blocking_collapse_edge_callbacks(
  76. pre_collapse, post_collapse, // These will get copied as needed
  77. tree,
  78. pre_collapse, post_collapse);
  79. }
  80. // Call to greedy decimator
  81. bool ret = decimate(
  82. VO, FO,
  83. cost_and_placement,
  84. max_faces_stopping_condition(m,orig_m,max_m),
  85. pre_collapse,
  86. post_collapse,
  87. U, G, J, I);
  88. // Remove phony boundary faces and clean up
  89. const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
  90. const auto keep_i = igl::find(keep);
  91. G = G(keep_i,igl::placeholders::all).eval();
  92. J = J(keep_i).eval();
  93. Eigen::VectorXi _1,I2;
  94. igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1,I2);
  95. I = I(I2).eval();
  96. assert(tree == nullptr || tree == tree->root());
  97. delete tree;
  98. return ret;
  99. }