ramer_douglas_peucker.cpp 4.9 KB

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