massmatrix.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #include <test_common.h>
  2. #include <igl/massmatrix.h>
  3. #include <igl/doublearea.h>
  4. #include <igl/edges.h>
  5. #include <igl/vertex_triangle_adjacency.h>
  6. TEST_CASE("massmatrix: full", "[igl]" )
  7. {
  8. const auto test_case = [](const std::string &param)
  9. {
  10. const double epsilon = 1e-15;
  11. Eigen::MatrixXd V;
  12. Eigen::MatrixXi F;
  13. // Load example mesh: GetParam() will be name of mesh file
  14. igl::read_triangle_mesh(test_common::data_path(param), V, F);
  15. Eigen::SparseMatrix<double> M;
  16. igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_FULL,M);
  17. REQUIRE(M.rows() == V.rows());
  18. REQUIRE(M.cols() == V.rows());
  19. Eigen::MatrixXd dblA;
  20. igl::doublearea(V,F,dblA);
  21. REQUIRE(M.sum() == Approx(dblA.sum()/2.).margin(epsilon));
  22. };
  23. test_common::run_test_cases(test_common::all_meshes(), test_case);
  24. }
  25. TEST_CASE("massmatrix: barycentric", "[igl]" )
  26. {
  27. const auto test_case = [](const std::string &param)
  28. {
  29. const double epsilon = 1e-15;
  30. Eigen::MatrixXd V;
  31. Eigen::MatrixXi F;
  32. // Load example mesh: GetParam() will be name of mesh file
  33. igl::read_triangle_mesh(test_common::data_path(param), V, F);
  34. Eigen::SparseMatrix<double> M;
  35. igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_BARYCENTRIC,M);
  36. REQUIRE(M.rows() == V.rows());
  37. REQUIRE(M.cols() == V.rows());
  38. Eigen::MatrixXd dblA;
  39. igl::doublearea(V,F,dblA);
  40. REQUIRE(M.sum() == Approx(dblA.sum()/2.).margin(epsilon));
  41. };
  42. test_common::run_test_cases(test_common::all_meshes(), test_case);
  43. }
  44. TEST_CASE("massmatrix: cube_barycentric", "[igl]")
  45. {
  46. //The allowed error for this test
  47. const double epsilon = 1e-15;
  48. Eigen::MatrixXd V;
  49. Eigen::MatrixXi F;
  50. //This is a cube of dimensions 1.0x1.0x1.0
  51. igl::read_triangle_mesh(test_common::data_path("cube.obj"), V, F);
  52. Eigen::SparseMatrix<double> M;
  53. //Check the mass matrix of the cube
  54. igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_BARYCENTRIC,M);
  55. REQUIRE(M.rows() == V.rows());
  56. REQUIRE(M.cols() == V.rows());
  57. //All triangles' areas are 0.5
  58. //barycentric area for a vertex is {number of adj triangles} * 0.5 / 3
  59. Eigen::VectorXi adj(8);
  60. adj << 6,4,4,4,4,4,6,4;
  61. for(int f = 0;f<M.rows();f++)
  62. {
  63. REQUIRE(M.coeff(f,f) == Approx(0.5/3*adj(f)).margin(epsilon));
  64. }
  65. }
  66. TEST_CASE("massmatrix: cube_full", "[igl]")
  67. {
  68. //The allowed error for this test
  69. const double epsilon = 1e-15;
  70. Eigen::MatrixXd V;
  71. Eigen::MatrixXi F;
  72. //Check the mass matrix of the cube
  73. igl::read_triangle_mesh(test_common::data_path("cube.obj"), V, F);
  74. Eigen::SparseMatrix<double> M;
  75. //Check the regular tetrahedron of side sqrt(2)
  76. igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_FULL,M);
  77. REQUIRE(M.rows() == V.rows());
  78. REQUIRE(M.cols() == V.rows());
  79. Eigen::VectorXi adj(8);
  80. adj << 6,4,4,4,4,4,6,4;
  81. //All triangles' areas are 0.5
  82. //full mass matrix on diagnol is {number of adj triangles} * 0.5 / 6
  83. for(int f=0;f<M.rows();++f)
  84. {
  85. REQUIRE(M.coeff(f,f) == Approx(0.5/6*adj(f)).margin(epsilon));
  86. }
  87. for (int i=0;i<F.rows();++i)
  88. {
  89. for (int j=0;j<3;++j)
  90. {
  91. REQUIRE(M.coeff(F(i,j),F(i,(j+1)%3)) == Approx(0.5/6).margin(epsilon));
  92. REQUIRE(M.coeff(F(i,(j+1)%3),F(i,j)) == Approx(0.5/6).margin(epsilon));
  93. }
  94. }
  95. }