pseudonormal_test.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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 "barycentric_coordinates.h"
  10. #include "doublearea.h"
  11. #include "project_to_line_segment.h"
  12. #include <cassert>
  13. template <
  14. typename DerivedV,
  15. typename DerivedF,
  16. typename DerivedFN,
  17. typename DerivedVN,
  18. typename DerivedEN,
  19. typename DerivedEMAP,
  20. typename Derivedq,
  21. typename Derivedc,
  22. typename Scalar,
  23. typename Derivedn>
  24. IGL_INLINE void igl::pseudonormal_test(
  25. const Eigen::MatrixBase<DerivedV> & V,
  26. const Eigen::MatrixBase<DerivedF> & F,
  27. const Eigen::MatrixBase<DerivedFN> & FN,
  28. const Eigen::MatrixBase<DerivedVN> & VN,
  29. const Eigen::MatrixBase<DerivedEN> & EN,
  30. const Eigen::MatrixBase<DerivedEMAP> & EMAP,
  31. const Eigen::MatrixBase<Derivedq> & q,
  32. const int f,
  33. Eigen::PlainObjectBase<Derivedc> & c,
  34. Scalar & s,
  35. Eigen::PlainObjectBase<Derivedn> & n)
  36. {
  37. using namespace Eigen;
  38. const auto & qc = q-c;
  39. typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
  40. RowVector3S b;
  41. // Using barycentric coorindates to determine whether close to a vertex/edge
  42. // seems prone to error when dealing with nearly degenerate triangles: Even
  43. // the barycenter (1/3,1/3,1/3) can be made arbitrarily close to an
  44. // edge/vertex
  45. //
  46. const RowVector3S A = V.row(F(f,0));
  47. const RowVector3S B = V.row(F(f,1));
  48. const RowVector3S C = V.row(F(f,2));
  49. const double area = [&A,&B,&C]()
  50. {
  51. Matrix<double,1,1> area;
  52. doublearea(A,B,C,area);
  53. return area(0);
  54. }();
  55. // These were chosen arbitrarily. In a floating point scenario, I'm not sure
  56. // the best way to determine if c is on a vertex/edge or in the middle of the
  57. // face: specifically, I'm worrying about degenerate triangles where
  58. // barycentric coordinates are error-prone.
  59. const double MIN_DOUBLE_AREA = 1e-4;
  60. const double epsilon = 1e-12;
  61. if(area>MIN_DOUBLE_AREA)
  62. {
  63. barycentric_coordinates( c,A,B,C,b);
  64. // Determine which normal to use
  65. const int type = (b.array()<=epsilon).template cast<int>().sum();
  66. switch(type)
  67. {
  68. case 2:
  69. // Find vertex
  70. for(int x = 0;x<3;x++)
  71. {
  72. if(b(x)>epsilon)
  73. {
  74. n = VN.row(F(f,x));
  75. break;
  76. }
  77. }
  78. break;
  79. case 1:
  80. // Find edge
  81. for(int x = 0;x<3;x++)
  82. {
  83. if(b(x)<=epsilon)
  84. {
  85. n = EN.row(EMAP(F.rows()*x+f));
  86. break;
  87. }
  88. }
  89. break;
  90. default:
  91. assert(false && "all barycentric coords zero.");
  92. case 0:
  93. n = FN.row(f);
  94. break;
  95. }
  96. }else
  97. {
  98. // Check each vertex
  99. bool found = false;
  100. for(int v = 0;v<3 && !found;v++)
  101. {
  102. if( (c-V.row(F(f,v))).norm() < epsilon)
  103. {
  104. found = true;
  105. n = VN.row(F(f,v));
  106. }
  107. }
  108. // Check each edge
  109. for(int e = 0;e<3 && !found;e++)
  110. {
  111. const RowVector3S s = V.row(F(f,(e+1)%3));
  112. const RowVector3S d = V.row(F(f,(e+2)%3));
  113. Matrix<double,1,1> sqr_d_j_x(1,1);
  114. Matrix<double,1,1> t(1,1);
  115. project_to_line_segment(c,s,d,t,sqr_d_j_x);
  116. if(sqrt(sqr_d_j_x(0)) < epsilon)
  117. {
  118. n = EN.row(EMAP(F.rows()*e+f));
  119. found = true;
  120. }
  121. }
  122. // Finally just use face
  123. if(!found)
  124. {
  125. n = FN.row(f);
  126. }
  127. }
  128. s = (qc.dot(n) >= 0 ? 1. : -1.);
  129. }
  130. template <
  131. typename DerivedV,
  132. typename DerivedF,
  133. typename DerivedEN,
  134. typename DerivedVN,
  135. typename Derivedq,
  136. typename Derivedc,
  137. typename Scalar,
  138. typename Derivedn>
  139. IGL_INLINE void igl::pseudonormal_test(
  140. const Eigen::MatrixBase<DerivedV> & V,
  141. const Eigen::MatrixBase<DerivedF> & E,
  142. const Eigen::MatrixBase<DerivedEN> & EN,
  143. const Eigen::MatrixBase<DerivedVN> & VN,
  144. const Eigen::MatrixBase<Derivedq> & q,
  145. const int e,
  146. Eigen::PlainObjectBase<Derivedc> & c,
  147. Scalar & s,
  148. Eigen::PlainObjectBase<Derivedn> & n)
  149. {
  150. using namespace Eigen;
  151. const auto & qc = q-c;
  152. const double len = (V.row(E(e,1))-V.row(E(e,0))).norm();
  153. // barycentric coordinates
  154. Eigen::Matrix<Scalar,1,2>
  155. b((c-V.row(E(e,1))).norm()/len,(c-V.row(E(e,0))).norm()/len);
  156. // Determine which normal to use
  157. const double epsilon = 1e-12;
  158. const int type = (b.array()<=epsilon).template cast<int>().sum();
  159. switch(type)
  160. {
  161. case 1:
  162. // Find vertex
  163. for(int x = 0;x<2;x++)
  164. {
  165. if(b(x)>epsilon)
  166. {
  167. n = VN.row(E(e,x)).head(2);
  168. break;
  169. }
  170. }
  171. break;
  172. default:
  173. assert(false && "all barycentric coords zero.");
  174. case 0:
  175. n = EN.row(e).head(2);
  176. break;
  177. }
  178. s = (qc.dot(n) >= 0 ? 1. : -1.);
  179. }
  180. #ifdef IGL_STATIC_LIBRARY
  181. // Explicit template instantiation
  182. // generated by autoexplicit.sh
  183. template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
  184. // generated by autoexplicit.sh
  185. template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
  186. // generated by autoexplicit.sh
  187. template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
  188. #endif