ear_clipping.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2019 Hanxiao Shen <[email protected]>
  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 <igl/slice.h>
  9. #include "ear_clipping.h"
  10. #include "point_inside_convex_polygon.h"
  11. #include "predicates.h"
  12. template <typename DerivedP, typename DerivedRT,
  13. typename DerivedF, typename DerivedI>
  14. IGL_INLINE void igl::predicates::ear_clipping(
  15. const Eigen::MatrixBase<DerivedP>& P,
  16. const Eigen::MatrixBase<DerivedRT>& RT,
  17. Eigen::PlainObjectBase<DerivedI>& I,
  18. Eigen::PlainObjectBase<DerivedF>& eF,
  19. Eigen::PlainObjectBase<DerivedP>& nP
  20. ){
  21. typedef typename DerivedF::Scalar Index;
  22. typedef typename DerivedP::Scalar Scalar;
  23. static_assert(std::is_same<typename DerivedI::Scalar,
  24. typename DerivedF::Scalar>::value,
  25. "index type should be consistent");
  26. // check whether vertex i is an ear
  27. auto is_ear = [](
  28. const Eigen::MatrixBase<DerivedP>& P,
  29. const Eigen::MatrixBase<DerivedRT>& RT,
  30. const Eigen::Matrix<Index,-1,1>& L,
  31. const Eigen::Matrix<Index,-1,1>& R,
  32. const Index i
  33. ){
  34. Index a = L(i), b = R(i);
  35. if(RT(i) != 0 || RT(a) != 0 || RT(b) != 0) return false;
  36. Eigen::Matrix<Scalar,1,2> pa = P.row(a);
  37. Eigen::Matrix<Scalar,1,2> pb = P.row(b);
  38. Eigen::Matrix<Scalar,1,2> pi = P.row(i);
  39. auto r = igl::predicates::orient2d(pa,pi,pb);
  40. if(r == igl::predicates::Orientation::NEGATIVE ||
  41. r == igl::predicates::Orientation::COLLINEAR) return false;
  42. // check if any vertex is lying inside triangle (a,b,i);
  43. int k=R(b);
  44. while(k!=a){
  45. Eigen::Matrix<Scalar,-1,2> T(3,2);
  46. T<<P.row(a),P.row(i),P.row(b);
  47. Eigen::Matrix<Scalar,1,2> q=P.row(k);
  48. if(igl::predicates::point_inside_convex_polygon(T,q))
  49. return false;
  50. k=R(k);
  51. }
  52. return true;
  53. };
  54. Eigen::Matrix<Index,-1,1> L(P.rows());
  55. Eigen::Matrix<Index,-1,1> R(P.rows());
  56. for(int i=0;i<P.rows();i++){
  57. L(i) = Index((i-1+P.rows())%P.rows());
  58. R(i) = Index((i+1)%P.rows());
  59. }
  60. Eigen::VectorXi ears; // mark ears
  61. Eigen::VectorXi X; // clipped vertices
  62. ears.setZero(P.rows());
  63. X.setZero(P.rows());
  64. // initialize ears
  65. for(int i=0;i<P.rows();i++){
  66. ears(i) = is_ear(P,RT,L,R,i);
  67. }
  68. // clip ears until none left
  69. while(ears.maxCoeff()==1){
  70. // find the first ear
  71. Index e = 0;
  72. while(e<ears.rows()&&ears(e)!=1) e++;
  73. // find valid neighbors
  74. Index a = L(e), b = R(e);
  75. if(a == b) break;
  76. // clip ear and store face
  77. eF.conservativeResize(eF.rows()+1,3);
  78. eF.bottomRows(1)<<a,e,b;
  79. L(b) = a;
  80. L(e) = -1;
  81. R(a) = b;
  82. R(e) = -1;
  83. ears(e) = 0; // mark vertex e as non-ear
  84. // update neighbor's ear status
  85. ears(a) = is_ear(P,RT,L,R,a);
  86. ears(b) = is_ear(P,RT,L,R,b);
  87. X(e) = 1;
  88. // when only one edge left
  89. // mark the endpoints as clipped
  90. if(L(a)==b && R(b)==a){
  91. X(a) = 1;
  92. X(b) = 1;
  93. }
  94. }
  95. // collect remaining vertices if theres any
  96. for(int i=0;i<X.rows();i++)
  97. X(i) = 1-X(i);
  98. I.resize(X.sum());
  99. Index j=0;
  100. for(Index i=0;i<X.rows();i++)
  101. if(X(i)==1){
  102. I(j++) = i;
  103. }
  104. igl::slice(P,I,1,nP);
  105. }
  106. #ifdef IGL_STATIC_LIBRARY
  107. template void igl::predicates::ear_clipping<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  108. #endif