scaf.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #include <test_common.h>
  2. #include <igl/cat.h>
  3. #include <igl/triangle/scaf.h>
  4. #include <igl/slice.h>
  5. #include <igl/harmonic.h>
  6. #include <igl/boundary_loop.h>
  7. #include <igl/map_vertices_to_circle.h>
  8. #include <igl/flip_avoiding_line_search.h>
  9. // Assert that building the SCAF equation system via scaf_system() and
  10. // solving it manually yields the same result as calling scaf_solve() directly.
  11. TEST_CASE("scaf_system: Test scaf_system() vs scaf_solve()", "[igl]")
  12. {
  13. // Read cube mesh
  14. Eigen::MatrixXd V;
  15. Eigen::MatrixXi F;
  16. igl::read_triangle_mesh(test_common::data_path("cube.obj"), V, F);
  17. // Cut to disk
  18. F = F.topRows(F.rows() - 1).eval();
  19. // Compute Tutte's embedding
  20. Eigen::MatrixXd uv_init;
  21. {
  22. Eigen::MatrixXd bnd_uv;
  23. std::vector<int> boundary;
  24. igl::boundary_loop(F, boundary);
  25. Eigen::VectorXi bnd = Eigen::Map<Eigen::VectorXi>(boundary.data(), boundary.size());
  26. igl::map_vertices_to_circle(V, bnd, bnd_uv);
  27. igl::harmonic(F, bnd, bnd_uv ,1, uv_init);
  28. uv_init.conservativeResize(V.rows(), 2);
  29. }
  30. // Init empty constraint vectors
  31. Eigen::VectorXi b;
  32. Eigen::MatrixXd bc;
  33. // Run one scaf iteration as reference
  34. igl::triangle::SCAFData s_ref;
  35. {
  36. igl::triangle::scaf_precompute(V, F, uv_init, igl::MappingEnergyType::SYMMETRIC_DIRICHLET, b, bc, 0, s_ref);
  37. igl::triangle::scaf_solve(1, s_ref);
  38. }
  39. // Obtain SCAF linear system perform iteration manually
  40. igl::triangle::SCAFData s_test;
  41. {
  42. // Set up system
  43. igl::triangle::scaf_precompute(V, F, uv_init, igl::MappingEnergyType::SYMMETRIC_DIRICHLET, b, bc, 0, s_test);
  44. Eigen::SparseMatrix<double> L;
  45. Eigen::VectorXd rhs;
  46. igl::triangle::scaf_system(s_test, L, rhs);
  47. // Solve
  48. Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
  49. auto x = solver.compute(L).solve(rhs);
  50. // Write result to uv_target
  51. Eigen::MatrixXd uv_target = s_test.w_uv;
  52. const int n_v_var = s_test.w_uv.rows() - s_test.frame_ids.size();
  53. for (int i = 0; i < n_v_var; ++i)
  54. {
  55. int row = i;
  56. if (i >= s_test.v_num)
  57. row += s_test.frame_ids.size();
  58. uv_target(row, 0) = x[i];
  59. uv_target(row, 1) = x[i + n_v_var];
  60. }
  61. // Line search
  62. std::function<double(Eigen::MatrixXd&)> E =
  63. [&s_test](Eigen::MatrixXd &uv) { return igl::triangle::scaf::compute_energy(s_test, uv, true); };
  64. Eigen::MatrixXi w_T;
  65. igl::cat(1, s_test.m_T, s_test.s_T, w_T);
  66. igl::flip_avoiding_line_search(w_T, s_test.w_uv, uv_target, E, -1);
  67. }
  68. // Compare both results
  69. REQUIRE(s_test.w_uv == s_ref.w_uv);
  70. }