cotmatrix_entries.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include <test_common.h>
  2. #include <igl/cotmatrix_entries.h>
  3. #include <igl/edge_lengths.h>
  4. #include <igl/EPS.h>
  5. TEST_CASE("cotmatrix_entries: simple", "[igl]")
  6. {
  7. //The allowed error for this test
  8. const double epsilon = 1e-15;
  9. Eigen::MatrixXd V;
  10. Eigen::MatrixXi F;
  11. //This is a cube of dimensions 1.0x1.0x1.0
  12. test_common::load_mesh("cube.obj", V, F);
  13. //Prepare another mesh with triangles along side diagonals of the cube
  14. //These triangles are form a regular tetrahedron of side sqrt(2)
  15. Eigen::MatrixXi F_tet(4,3);
  16. F_tet << 4,6,1,
  17. 6,4,3,
  18. 4,1,3,
  19. 1,6,3;
  20. //1. Check cotmatrix_entries
  21. Eigen::MatrixXd C1;
  22. igl::cotmatrix_entries(V,F,C1);
  23. REQUIRE (C1.rows() == F.rows());
  24. REQUIRE (C1.cols() == 3);
  25. //All angles in unit cube measure 45 or 90 degrees
  26. //Their (half)cotangent must value 0.5 or 0.0
  27. for(int f = 0;f<C1.rows();f++)
  28. {
  29. #ifdef IGL_EDGE_LENGTHS_SQUARED_H
  30. //Hard assert if we have edge_length_squared
  31. for(int v = 0;v<3;v++)
  32. if (C1(f,v) > 0.1)
  33. REQUIRE (C1(f,v) == 0.5);
  34. else
  35. REQUIRE (C1(f,v) == 0.0);
  36. //All cotangents sum 1.0 for those triangles
  37. REQUIRE (C1.row(f).sum() == 1.0);
  38. #else
  39. //Soft assert if we have not edge_length_squared
  40. for(int v = 0;v<3;v++)
  41. if (C1(f,v) > 0.1)
  42. REQUIRE (C1(f,v) == Approx (0.5).margin( epsilon));
  43. else
  44. REQUIRE (C1(f,v) == Approx (0.0).margin( epsilon));
  45. //All cotangents sum 1.0 for those triangles
  46. REQUIRE (C1.row(f).sum() == Approx (1.0).margin( epsilon));
  47. #endif
  48. }
  49. //Check the regular tetrahedron
  50. Eigen::MatrixXd C2;
  51. igl::cotmatrix_entries(V,F_tet,C2);
  52. REQUIRE (C2.rows() == F_tet.rows());
  53. REQUIRE (C2.cols() == 3);
  54. for(int f = 0;f<C2.rows();f++)
  55. {
  56. //Their (half)cotangent must value 0.5 / tan(M_PI / 3.0)
  57. for(int v = 0;v<3;v++)
  58. REQUIRE (C2(f,v) == Approx (0.5 / tan(M_PI / 3.0)).margin( epsilon));
  59. }
  60. //Scale the cube to have huge sides
  61. Eigen::MatrixXd V_huge = V * 1.0e8;
  62. igl::cotmatrix_entries(V_huge,F,C1);
  63. REQUIRE (C1.rows() == F.rows());
  64. REQUIRE (C1.cols() == 3);
  65. //All angles still measure 45 or 90 degrees
  66. //Their (half)cotangent must value 0.5 or 0.0
  67. for(int f = 0;f<C1.rows();f++)
  68. {
  69. #ifdef IGL_EDGE_LENGTHS_SQUARED_H
  70. //Hard assert if we have edge_length_squared
  71. for(int v = 0;v<3;v++)
  72. if (C1(f,v) > 0.1)
  73. REQUIRE (C1(f,v) == 0.5);
  74. else
  75. REQUIRE (C1(f,v) == 0.0);
  76. //All cotangents sum 1.0 for those triangles
  77. REQUIRE (C1.row(f).sum() == 1.0);
  78. #else
  79. //Soft assert if we have not edge_length_squared
  80. for(int v = 0;v<3;v++)
  81. if (C1(f,v) > 0.1)
  82. REQUIRE (C1(f,v) == Approx (0.5).margin( epsilon));
  83. else
  84. REQUIRE (C1(f,v) == Approx (0.0).margin( epsilon));
  85. //All cotangents sum 1.0 for those triangles
  86. REQUIRE (C1.row(f).sum() == Approx (1.0).margin( epsilon));
  87. #endif
  88. }
  89. //Check the huge regular tetrahedron
  90. igl::cotmatrix_entries(V_huge,F_tet,C2);
  91. REQUIRE (C2.rows() == F_tet.rows());
  92. REQUIRE (C2.cols() == 3);
  93. for(int f = 0;f<C2.rows();f++)
  94. {
  95. //Their (half)cotangent must value 0.5 / tan(M_PI / 3.0)
  96. for(int v = 0;v<3;v++)
  97. REQUIRE (C2(f,v) == Approx (0.5 / tan(M_PI / 3.0)).margin( epsilon));
  98. }
  99. //Scale the cube to have tiny sides
  100. Eigen::MatrixXd V_tiny = V * 1.0e-8;
  101. igl::cotmatrix_entries(V_tiny,F,C1);
  102. REQUIRE (C1.rows() == F.rows());
  103. REQUIRE (C1.cols() == 3);
  104. //All angles still measure 45 or 90 degrees
  105. //Their (half)cotangent must value 0.5 or 0.0
  106. for(int f = 0;f<C1.rows();f++)
  107. {
  108. for(int v = 0;v<3;v++)
  109. if (C1(f,v) > 0.1)
  110. REQUIRE (C1(f,v) == Approx (0.5).margin( epsilon));
  111. else
  112. REQUIRE (C1(f,v) == Approx (0.0).margin( epsilon));
  113. //All cotangents sum 1.0 for those triangles
  114. REQUIRE (C1.row(f).sum() == Approx (1.0).margin( epsilon));
  115. }
  116. //Check the tiny regular tetrahedron
  117. igl::cotmatrix_entries(V_tiny,F_tet,C2);
  118. REQUIRE (C2.rows() == F_tet.rows());
  119. REQUIRE (C2.cols() == 3);
  120. for(int f = 0;f<C2.rows();f++)
  121. {
  122. //Their (half)cotangent must value 0.5 / tan(M_PI / 3.0)
  123. for(int v = 0;v<3;v++)
  124. REQUIRE (C2(f,v) == Approx (0.5 / tan(M_PI / 3.0)).margin( epsilon));
  125. }
  126. }// TEST_CASE("cotmatrix_entries: simple", "[igl]")
  127. TEST_CASE("cotmatrix_entries: intrinsic", "[igl]")
  128. {
  129. Eigen::MatrixXd V;
  130. Eigen::MatrixXi F;
  131. //This is a cube of dimensions 1.0x1.0x1.0
  132. test_common::load_mesh("cube.obj", V, F);
  133. Eigen::MatrixXd Cext,Cint;
  134. // compute C extrinsically
  135. igl::cotmatrix_entries(V,F,Cext);
  136. // compute C intrinsically
  137. Eigen::MatrixXd l;
  138. igl::edge_lengths(V,F,l);
  139. igl::cotmatrix_entries(l,Cint);
  140. test_common::assert_near(Cext,Cint,igl::EPS<double>());
  141. }