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