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