polygon_simplify.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2011, Andrew Ross
  2. //
  3. // Use, modification and distribution are subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt).
  6. #ifndef BOOST_POLYGON_DETAIL_SIMPLIFY_HPP
  7. #define BOOST_POLYGON_DETAIL_SIMPLIFY_HPP
  8. #include <vector>
  9. namespace boost { namespace polygon { namespace detail { namespace simplify_detail {
  10. // Does a simplification/optimization pass on the polygon. If a given
  11. // vertex lies within "len" of the line segment joining its neighbor
  12. // vertices, it is removed.
  13. template <typename T> //T is a model of point concept
  14. std::size_t simplify(std::vector<T>& dst, const std::vector<T>& src,
  15. typename coordinate_traits<
  16. typename point_traits<T>::coordinate_type
  17. >::coordinate_distance len)
  18. {
  19. using namespace boost::polygon;
  20. typedef typename point_traits<T>::coordinate_type coordinate_type;
  21. typedef typename coordinate_traits<coordinate_type>::area_type ftype;
  22. typedef typename std::vector<T>::const_iterator iter;
  23. std::vector<T> out;
  24. out.reserve(src.size());
  25. dst = src;
  26. std::size_t final_result = 0;
  27. std::size_t orig_size = src.size();
  28. //I can't use == if T doesn't provide it, so use generic point concept compare
  29. bool closed = equivalence(src.front(), src.back());
  30. //we need to keep smoothing until we don't find points to remove
  31. //because removing points in the first iteration through the
  32. //polygon may leave it in a state where more removal is possible
  33. bool not_done = true;
  34. while(not_done) {
  35. if(dst.size() < 3) {
  36. dst.clear();
  37. return orig_size;
  38. }
  39. // Start with the second, test for the last point
  40. // explicitly, and exit after looping back around to the first.
  41. ftype len2 = ftype(len) * ftype(len);
  42. for(iter prev=dst.begin(), i=prev+1, next; /**/; i = next) {
  43. next = i+1;
  44. if(next == dst.end())
  45. next = dst.begin();
  46. // points A, B, C
  47. ftype ax = x(*prev), ay = y(*prev);
  48. ftype bx = x(*i), by = y(*i);
  49. ftype cx = x(*next), cy = y(*next);
  50. // vectors AB, BC and AC:
  51. ftype abx = bx-ax, aby = by-ay;
  52. ftype bcx = cx-bx, bcy = cy-by;
  53. ftype acx = cx-ax, acy = cy-ay;
  54. // dot products
  55. ftype ab_ab = abx*abx + aby*aby;
  56. ftype bc_bc = bcx*bcx + bcy*bcy;
  57. ftype ac_ac = acx*acx + acy*acy;
  58. ftype ab_ac = abx*acx + aby*acy;
  59. // projection of AB along AC
  60. ftype projf = ab_ac / ac_ac;
  61. ftype projx = acx * projf, projy = acy * projf;
  62. // perpendicular vector from the line AC to point B (i.e. AB - proj)
  63. ftype perpx = abx - projx, perpy = aby - projy;
  64. // Squared fractional distance of projection. FIXME: can
  65. // remove this division, the decisions below can be made with
  66. // just the sign of the quotient and a check to see if
  67. // abs(numerator) is greater than abs(divisor).
  68. ftype f2 = (projx*acx + projy*acx) / ac_ac;
  69. // Square of the relevant distance from point B:
  70. ftype dist2;
  71. if (f2 < 0) dist2 = ab_ab;
  72. else if(f2 > 1) dist2 = bc_bc;
  73. else dist2 = perpx*perpx + perpy*perpy;
  74. if(dist2 > len2) {
  75. prev = i; // bump prev, we didn't remove the segment
  76. out.push_back(*i);
  77. }
  78. if(i == dst.begin())
  79. break;
  80. }
  81. std::size_t result = dst.size() - out.size();
  82. if(result == 0) {
  83. not_done = false;
  84. } else {
  85. final_result += result;
  86. dst = out;
  87. out.clear();
  88. }
  89. } //end of while loop
  90. if(closed) {
  91. //if the input was closed we want the output to be closed
  92. --final_result;
  93. dst.push_back(dst.front());
  94. }
  95. return final_result;
  96. }
  97. }}}}
  98. #endif