qslim.cpp 3.2 KB

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