ramer_douglas_peucker.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #include "ramer_douglas_peucker.h"
  2. #include "find.h"
  3. #include "cumsum.h"
  4. #include "histc.h"
  5. #include "slice.h"
  6. #include "project_to_line.h"
  7. #include "EPS.h"
  8. #include "slice_mask.h"
  9. template <typename DerivedP, typename DerivedS, typename DerivedJ>
  10. IGL_INLINE void igl::ramer_douglas_peucker(
  11. const Eigen::MatrixBase<DerivedP> & P,
  12. const typename DerivedP::Scalar tol,
  13. Eigen::PlainObjectBase<DerivedS> & S,
  14. Eigen::PlainObjectBase<DerivedJ> & J)
  15. {
  16. typedef typename DerivedP::Scalar Scalar;
  17. // number of vertices
  18. const int n = P.rows();
  19. // Trivial base case
  20. if(n <= 1)
  21. {
  22. J = DerivedJ::Zero(n);
  23. S = P;
  24. return;
  25. }
  26. // number of dimensions
  27. const int m = P.cols();
  28. Eigen::Array<bool,Eigen::Dynamic,1> I =
  29. Eigen::Array<bool,Eigen::Dynamic,1>::Constant(n,1,true);
  30. const auto stol = tol*tol;
  31. std::function<void(const int,const int)> simplify;
  32. simplify = [&I,&P,&stol,&simplify](const int ixs, const int ixe)->void
  33. {
  34. assert(ixe>ixs);
  35. Scalar sdmax = 0;
  36. typename Eigen::Matrix<Scalar,Eigen::Dynamic,1>::Index ixc = -1;
  37. if((ixe-ixs)>1)
  38. {
  39. Scalar sdes = (P.row(ixe)-P.row(ixs)).squaredNorm();
  40. Eigen::Matrix<Scalar,Eigen::Dynamic,1> sD;
  41. const auto & Pblock = P.block(ixs+1,0,((ixe+1)-ixs)-2,P.cols());
  42. if(sdes<=EPS<Scalar>())
  43. {
  44. sD = (Pblock.rowwise()-P.row(ixs)).rowwise().squaredNorm();
  45. }else
  46. {
  47. Eigen::Matrix<Scalar,Eigen::Dynamic,1> T;
  48. project_to_line(Pblock,P.row(ixs).eval(),P.row(ixe).eval(),T,sD);
  49. }
  50. sdmax = sD.maxCoeff(&ixc);
  51. // Index full P
  52. ixc = ixc+(ixs+1);
  53. }
  54. if(sdmax <= stol)
  55. {
  56. if(ixs != ixe-1)
  57. {
  58. I.block(ixs+1,0,((ixe+1)-ixs)-2,1).setConstant(false);
  59. }
  60. }else
  61. {
  62. simplify(ixs,ixc);
  63. simplify(ixc,ixe);
  64. }
  65. };
  66. simplify(0,n-1);
  67. slice_mask(P,I,1,S);
  68. find(I,J);
  69. }
  70. template <
  71. typename DerivedP,
  72. typename DerivedS,
  73. typename DerivedJ,
  74. typename DerivedQ>
  75. IGL_INLINE void igl::ramer_douglas_peucker(
  76. const Eigen::MatrixBase<DerivedP> & P,
  77. const typename DerivedP::Scalar tol,
  78. Eigen::PlainObjectBase<DerivedS> & S,
  79. Eigen::PlainObjectBase<DerivedJ> & J,
  80. Eigen::PlainObjectBase<DerivedQ> & Q)
  81. {
  82. typedef typename DerivedP::Scalar Scalar;
  83. ramer_douglas_peucker(P,tol,S,J);
  84. const int n = P.rows();
  85. assert(n>=2 && "Curve should be at least 2 points");
  86. typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
  87. // distance traveled along high-res curve
  88. VectorXS L(n);
  89. L(0) = 0;
  90. L.block(1,0,n-1,1) = (P.bottomRows(n-1)-P.topRows(n-1)).rowwise().norm();
  91. // Give extra on end
  92. VectorXS T;
  93. cumsum(L,1,T);
  94. T.conservativeResize(T.size()+1);
  95. T(T.size()-1) = T(T.size()-2);
  96. // index of coarse point before each fine vertex
  97. Eigen::VectorXi B;
  98. {
  99. Eigen::VectorXi N;
  100. histc(Eigen::VectorXi::LinSpaced(n,0,n-1),J,N,B);
  101. }
  102. // Add extra point at end
  103. J.conservativeResize(J.size()+1);
  104. J(J.size()-1) = J(J.size()-2);
  105. Eigen::VectorXi s,d;
  106. // Find index in original list of "start" vertices
  107. slice(J,B,s);
  108. // Find index in original list of "destination" vertices
  109. slice(J,(B.array()+1).eval(),d);
  110. // Parameter between start and destination is linear in arc-length
  111. VectorXS Ts,Td;
  112. slice(T,s,Ts);
  113. slice(T,d,Td);
  114. T = ((T.head(T.size()-1)-Ts).array()/(Td-Ts).array()).eval();
  115. for(int t =0;t<T.size();t++)
  116. {
  117. if(!std::isfinite(T(t)) || T(t)!=T(t))
  118. {
  119. T(t) = 0;
  120. }
  121. }
  122. DerivedS SB;
  123. slice(S,B,1,SB);
  124. Eigen::VectorXi MB = B.array()+1;
  125. for(int b = 0;b<MB.size();b++)
  126. {
  127. if(MB(b) >= S.rows())
  128. {
  129. MB(b) = S.rows()-1;
  130. }
  131. }
  132. DerivedS SMB;
  133. slice(S,MB,1,SMB);
  134. Q = SB.array() + ((SMB.array()-SB.array()).colwise()*T.array());
  135. // Remove extra point at end
  136. J.conservativeResize(J.size()-1);
  137. }