123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- // Copyright 2011, Andrew Ross
- //
- // Use, modification and distribution are subject to the Boost Software License,
- // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt).
- #ifndef BOOST_POLYGON_DETAIL_SIMPLIFY_HPP
- #define BOOST_POLYGON_DETAIL_SIMPLIFY_HPP
- #include <vector>
- namespace boost { namespace polygon { namespace detail { namespace simplify_detail {
- // Does a simplification/optimization pass on the polygon. If a given
- // vertex lies within "len" of the line segment joining its neighbor
- // vertices, it is removed.
- template <typename T> //T is a model of point concept
- std::size_t simplify(std::vector<T>& dst, const std::vector<T>& src,
- typename coordinate_traits<
- typename point_traits<T>::coordinate_type
- >::coordinate_distance len)
- {
- using namespace boost::polygon;
- typedef typename point_traits<T>::coordinate_type coordinate_type;
- typedef typename coordinate_traits<coordinate_type>::area_type ftype;
- typedef typename std::vector<T>::const_iterator iter;
- std::vector<T> out;
- out.reserve(src.size());
- dst = src;
- std::size_t final_result = 0;
- std::size_t orig_size = src.size();
- //I can't use == if T doesn't provide it, so use generic point concept compare
- bool closed = equivalence(src.front(), src.back());
- //we need to keep smoothing until we don't find points to remove
- //because removing points in the first iteration through the
- //polygon may leave it in a state where more removal is possible
- bool not_done = true;
- while(not_done) {
- if(dst.size() < 3) {
- dst.clear();
- return orig_size;
- }
- // Start with the second, test for the last point
- // explicitly, and exit after looping back around to the first.
- ftype len2 = ftype(len) * ftype(len);
- for(iter prev=dst.begin(), i=prev+1, next; /**/; i = next) {
- next = i+1;
- if(next == dst.end())
- next = dst.begin();
- // points A, B, C
- ftype ax = x(*prev), ay = y(*prev);
- ftype bx = x(*i), by = y(*i);
- ftype cx = x(*next), cy = y(*next);
- // vectors AB, BC and AC:
- ftype abx = bx-ax, aby = by-ay;
- ftype bcx = cx-bx, bcy = cy-by;
- ftype acx = cx-ax, acy = cy-ay;
- // dot products
- ftype ab_ab = abx*abx + aby*aby;
- ftype bc_bc = bcx*bcx + bcy*bcy;
- ftype ac_ac = acx*acx + acy*acy;
- ftype ab_ac = abx*acx + aby*acy;
- // projection of AB along AC
- ftype projf = ab_ac / ac_ac;
- ftype projx = acx * projf, projy = acy * projf;
- // perpendicular vector from the line AC to point B (i.e. AB - proj)
- ftype perpx = abx - projx, perpy = aby - projy;
- // Squared fractional distance of projection. FIXME: can
- // remove this division, the decisions below can be made with
- // just the sign of the quotient and a check to see if
- // abs(numerator) is greater than abs(divisor).
- ftype f2 = (projx*acx + projy*acx) / ac_ac;
- // Square of the relevant distance from point B:
- ftype dist2;
- if (f2 < 0) dist2 = ab_ab;
- else if(f2 > 1) dist2 = bc_bc;
- else dist2 = perpx*perpx + perpy*perpy;
- if(dist2 > len2) {
- prev = i; // bump prev, we didn't remove the segment
- out.push_back(*i);
- }
- if(i == dst.begin())
- break;
- }
- std::size_t result = dst.size() - out.size();
- if(result == 0) {
- not_done = false;
- } else {
- final_result += result;
- dst = out;
- out.clear();
- }
- } //end of while loop
- if(closed) {
- //if the input was closed we want the output to be closed
- --final_result;
- dst.push_back(dst.front());
- }
- return final_result;
- }
- }}}}
- #endif
|