pseudonormal_test.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
  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 "pseudonormal_test.h"
  9. #include "AABB.h"
  10. #include "project_to_line_segment.h"
  11. #include <cassert>
  12. IGL_INLINE void igl::pseudonormal_test(
  13. const Eigen::MatrixXd & V,
  14. const Eigen::MatrixXi & F,
  15. const Eigen::MatrixXd & FN,
  16. const Eigen::MatrixXd & VN,
  17. const Eigen::MatrixXd & EN,
  18. const Eigen::VectorXi & EMAP,
  19. const Eigen::RowVector3d & q,
  20. const int f,
  21. const Eigen::RowVector3d & c,
  22. double & s,
  23. Eigen::RowVector3d & n)
  24. {
  25. using namespace Eigen;
  26. const auto & qc = q-c;
  27. RowVector3d b;
  28. // Using barycentric coorindates to determine whether close to a vertex/edge
  29. // seems prone to error when dealing with nearly degenerate triangles: Even
  30. // the barycenter (1/3,1/3,1/3) can be made arbitrarily close to an
  31. // edge/vertex
  32. //
  33. const RowVector3d A = V.row(F(f,0));
  34. const RowVector3d B = V.row(F(f,1));
  35. const RowVector3d C = V.row(F(f,2));
  36. const double area = [&A,&B,&C]()
  37. {
  38. Matrix<double,1,1> area;
  39. doublearea(A,B,C,area);
  40. return area(0);
  41. }();
  42. // These were chosen arbitrarily. In a floating point scenario, I'm not sure
  43. // the best way to determine if c is on a vertex/edge or in the middle of the
  44. // face: specifically, I'm worrying about degenerate triangles where
  45. // barycentric coordinates are error-prone.
  46. const double MIN_DOUBLE_AREA = 1e-4;
  47. const double epsilon = 1e-12;
  48. if(area>MIN_DOUBLE_AREA)
  49. {
  50. AABB<Eigen::MatrixXd,3>::barycentric_coordinates( c,A,B,C,b);
  51. // Determine which normal to use
  52. const int type = (b.array()<=epsilon).cast<int>().sum();
  53. switch(type)
  54. {
  55. case 2:
  56. // Find vertex
  57. for(int x = 0;x<3;x++)
  58. {
  59. if(b(x)>epsilon)
  60. {
  61. n = VN.row(F(f,x));
  62. break;
  63. }
  64. }
  65. break;
  66. case 1:
  67. // Find edge
  68. for(int x = 0;x<3;x++)
  69. {
  70. if(b(x)<=epsilon)
  71. {
  72. n = EN.row(EMAP(F.rows()*x+f));
  73. break;
  74. }
  75. }
  76. break;
  77. default:
  78. assert(false && "all barycentric coords zero.");
  79. case 0:
  80. n = FN.row(f);
  81. break;
  82. }
  83. }else
  84. {
  85. // Check each vertex
  86. bool found = false;
  87. for(int v = 0;v<3 && !found;v++)
  88. {
  89. if( (c-V.row(F(f,v))).norm() < epsilon)
  90. {
  91. found = true;
  92. n = VN.row(F(f,v));
  93. }
  94. }
  95. // Check each edge
  96. for(int e = 0;e<3 && !found;e++)
  97. {
  98. const RowVector3d s = V.row(F(f,(e+1)%3));
  99. const RowVector3d d = V.row(F(f,(e+2)%3));
  100. Matrix<double,1,1> sqr_d_j_x(1,1);
  101. Matrix<double,1,1> t(1,1);
  102. project_to_line_segment(c,s,d,t,sqr_d_j_x);
  103. if(sqrt(sqr_d_j_x(0)) < epsilon)
  104. {
  105. n = EN.row(EMAP(F.rows()*e+f));
  106. found = true;
  107. }
  108. }
  109. // Finally just use face
  110. if(!found)
  111. {
  112. n = FN.row(f);
  113. }
  114. }
  115. s = (qc.dot(n) >= 0 ? 1. : -1.);
  116. }
  117. IGL_INLINE void igl::pseudonormal_test(
  118. const Eigen::MatrixXd & V,
  119. const Eigen::MatrixXi & E,
  120. const Eigen::MatrixXd & EN,
  121. const Eigen::MatrixXd & VN,
  122. const Eigen::RowVector2d & q,
  123. const int e,
  124. const Eigen::RowVector2d & c,
  125. double & s,
  126. Eigen::RowVector2d & n)
  127. {
  128. using namespace Eigen;
  129. const auto & qc = q-c;
  130. const double len = (V.row(E(e,1))-V.row(E(e,0))).norm();
  131. // barycentric coordinates
  132. RowVector2d b((c-V.row(E(e,1))).norm()/len,(c-V.row(E(e,0))).norm()/len);
  133. // Determine which normal to use
  134. const double epsilon = 1e-12;
  135. const int type = (b.array()<=epsilon).cast<int>().sum();
  136. switch(type)
  137. {
  138. case 1:
  139. // Find vertex
  140. for(int x = 0;x<2;x++)
  141. {
  142. if(b(x)>epsilon)
  143. {
  144. n = VN.row(E(e,x));
  145. break;
  146. }
  147. }
  148. break;
  149. default:
  150. assert(false && "all barycentric coords zero.");
  151. case 0:
  152. n = EN.row(e);
  153. break;
  154. }
  155. s = (qc.dot(n) >= 0 ? 1. : -1.);
  156. }