ear_clipping.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 "ear_clipping.h"
  9. #include "predicates.h"
  10. #include "orient2d.h"
  11. #include "segment_segment_intersect.h"
  12. #include "../turning_number.h"
  13. template <
  14. typename DerivedP,
  15. typename DerivedRT,
  16. typename DerivedF,
  17. typename DerivedI>
  18. IGL_INLINE void igl::predicates::ear_clipping(
  19. const Eigen::MatrixBase<DerivedP>& P,
  20. const Eigen::MatrixBase<DerivedRT>& RT,
  21. Eigen::PlainObjectBase<DerivedF>& eF,
  22. Eigen::PlainObjectBase<DerivedI>& I)
  23. {
  24. typedef typename DerivedF::Scalar Index;
  25. typedef typename DerivedP::Scalar Scalar;
  26. static_assert(std::is_same<typename DerivedI::Scalar,
  27. typename DerivedF::Scalar>::value,
  28. "index type should be consistent");
  29. // check whether vertex i is an ear
  30. auto is_ear = [](
  31. const Eigen::MatrixBase<DerivedP>& P,
  32. const Eigen::MatrixBase<DerivedRT>& RT,
  33. const Eigen::Matrix<Index,Eigen::Dynamic,1>& L,
  34. const Eigen::Matrix<Index,Eigen::Dynamic,1>& R,
  35. const Index i
  36. ){
  37. // check if any edge in the leftover polygon intersects triangle (a,b,i)
  38. Index a = L(i), b = R(i);
  39. if(RT(i) != 0 || RT(a) != 0 || RT(b) != 0) return false;
  40. Eigen::Matrix<Scalar,1,2> pa = P.row(a);
  41. Eigen::Matrix<Scalar,1,2> pb = P.row(b);
  42. Eigen::Matrix<Scalar,1,2> pi = P.row(i);
  43. auto r = igl::predicates::orient2d(pa, pi, pb);
  44. if(r == igl::predicates::Orientation::NEGATIVE ||
  45. r == igl::predicates::Orientation::COLLINEAR) return false;
  46. // check edge (b, R(b))
  47. Index k = b;
  48. Index l = R(b);
  49. Eigen::Matrix<Scalar, 1, 2> pk = P.row(k);
  50. Eigen::Matrix<Scalar, 1, 2> pl = P.row(l);
  51. auto r1 = igl::predicates::orient2d(pb, pl, pa);
  52. auto r2 = igl::predicates::orient2d(pi, pl, pb);
  53. if (l == a) return true; // single triangle
  54. if (r1 != igl::predicates::Orientation::POSITIVE &&
  55. r2 != igl::predicates::Orientation::POSITIVE) {
  56. return false;
  57. }
  58. // iterate through all edges do not have common endpoints with a, b
  59. k = l;
  60. l = R(k);
  61. while (l != a) {
  62. pk = P.row(k);
  63. pl = P.row(l);
  64. if (igl::predicates::segment_segment_intersect(pa, pb, pk, pl) ||
  65. igl::predicates::segment_segment_intersect(pa, pi, pk, pl) ||
  66. igl::predicates::segment_segment_intersect(pi, pb, pk, pl)
  67. ){
  68. return false;
  69. }
  70. k = l;
  71. l = R(k);
  72. }
  73. // check edge (L(a), a)
  74. pk = P.row(k);
  75. pl = P.row(l);
  76. r1 = igl::predicates::orient2d(pb, pk, pl);
  77. r2 = igl::predicates::orient2d(pi, pa, pk);
  78. if (r1 != igl::predicates::Orientation::POSITIVE &&
  79. r2 != igl::predicates::Orientation::POSITIVE
  80. ){
  81. return false;
  82. }
  83. return true;
  84. };
  85. Eigen::Matrix<Index,Eigen::Dynamic,1> L(P.rows());
  86. Eigen::Matrix<Index,Eigen::Dynamic,1> R(P.rows());
  87. for(int i = 0;i < P.rows(); i++){
  88. L(i) = Index((i - 1 + P.rows()) % P.rows());
  89. R(i) = Index((i + 1) % P.rows());
  90. }
  91. Eigen::Matrix<Index, Eigen::Dynamic, 1> ears; // mark ears
  92. Eigen::Matrix<Index, Eigen::Dynamic, 1> X; // clipped vertices
  93. ears.setZero(P.rows());
  94. X.setZero(P.rows());
  95. // initialize ears
  96. for(int i = 0; i < P.rows(); i++){
  97. ears(i) = is_ear(P, RT, L, R, i);
  98. }
  99. // clip ears until none left
  100. while(ears.maxCoeff()==1){
  101. // find the first ear
  102. Index e = 0;
  103. while(e < ears.rows() && ears(e) != 1) e++;
  104. // find valid neighbors
  105. Index a = L(e), b = R(e);
  106. if(a == b) break;
  107. // clip ear and store face
  108. eF.conservativeResize(eF.rows()+1,3);
  109. eF.bottomRows(1)<<a, e, b;
  110. L(b) = a;
  111. L(e) = -1;
  112. R(a) = b;
  113. R(e) = -1;
  114. ears(e) = 0; // mark vertex e as non-ear
  115. // update neighbor's ear status
  116. ears(a) = is_ear(P, RT, L, R, a);
  117. ears(b) = is_ear(P, RT, L, R, b);
  118. X(e) = 1;
  119. // when only one edge left
  120. // mark the endpoints as clipped
  121. if(L(a) == b && R(b) == a){
  122. X(a) = 1;
  123. X(b) = 1;
  124. }
  125. }
  126. // collect remaining vertices if theres any
  127. for(int i = 0;i < X.rows(); i++)
  128. {
  129. X(i) = 1 - X(i);
  130. }
  131. I.resize(X.sum());
  132. Index j=0;
  133. for(Index i = 0;i < X.rows(); i++)
  134. {
  135. if(X(i) == 1)
  136. {
  137. I(j++) = i;
  138. }
  139. }
  140. }
  141. template <typename DerivedP,
  142. typename DerivedF>
  143. IGL_INLINE bool igl::predicates::ear_clipping(
  144. const Eigen::MatrixBase<DerivedP>& P,
  145. Eigen::PlainObjectBase<DerivedF>& eF)
  146. {
  147. if(turning_number(P) < 0)
  148. {
  149. // reverse input
  150. const auto rP = P.colwise().reverse().eval();
  151. const bool ret = igl::predicates::ear_clipping(rP, eF);
  152. // flip output
  153. eF = eF.rowwise().reverse();
  154. return ret;
  155. }
  156. const Eigen::Matrix<typename DerivedP::Scalar, Eigen::Dynamic, 1> RT =
  157. Eigen::Matrix<typename DerivedP::Scalar, Eigen::Dynamic, 1>::Zero(P.rows());
  158. Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 1> I;
  159. igl::predicates::ear_clipping(P, RT, eF, I);
  160. return I.size() == 0;
  161. }
  162. #ifdef IGL_STATIC_LIBRARY
  163. template bool igl::predicates::ear_clipping<Eigen::Matrix<double, -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::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>>&);
  164. 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>>&);
  165. #endif