/* Copyright 2008 Intel Corporation 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_POLYGON_90_SET_DATA_HPP #define BOOST_POLYGON_POLYGON_90_SET_DATA_HPP #include "isotropy.hpp" #include "point_concept.hpp" #include "point_3d_concept.hpp" #include "transform.hpp" #include "interval_concept.hpp" #include "rectangle_concept.hpp" #include "detail/iterator_points_to_compact.hpp" #include "detail/iterator_compact_to_points.hpp" #include "polygon_traits.hpp" //manhattan boolean algorithms #include "detail/boolean_op.hpp" #include "detail/polygon_formation.hpp" #include "detail/rectangle_formation.hpp" #include "detail/max_cover.hpp" #include "detail/property_merge.hpp" #include "detail/polygon_90_touch.hpp" #include "detail/iterator_geometry_to_set.hpp" namespace boost { namespace polygon{ template class polygon_90_set_view; template class polygon_90_set_data { public: typedef T coordinate_type; typedef std::vector > > value_type; typedef typename std::vector > >::const_iterator iterator_type; typedef polygon_90_set_data operator_arg_type; // default constructor inline polygon_90_set_data() : orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) {} // constructor inline polygon_90_set_data(orientation_2d orient) : orient_(orient), data_(), dirty_(false), unsorted_(false) {} // constructor from an iterator pair over vertex data template inline polygon_90_set_data(orientation_2d orient, iT input_begin, iT input_end) : orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) { dirty_ = true; unsorted_ = true; for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); } } // copy constructor inline polygon_90_set_data(const polygon_90_set_data& that) : orient_(that.orient_), data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_) {} template inline polygon_90_set_data(const polygon_90_set_view& that); // copy with orientation change constructor inline polygon_90_set_data(orientation_2d orient, const polygon_90_set_data& that) : orient_(orient), data_(), dirty_(false), unsorted_(false) { insert(that, false, that.orient_); } // destructor inline ~polygon_90_set_data() {} // assignement operator inline polygon_90_set_data& operator=(const polygon_90_set_data& that) { if(this == &that) return *this; orient_ = that.orient_; data_ = that.data_; dirty_ = that.dirty_; unsorted_ = that.unsorted_; return *this; } template inline polygon_90_set_data& operator=(const polygon_90_set_view& that); template inline polygon_90_set_data& operator=(const geometry_object& geometry) { data_.clear(); insert(geometry); return *this; } // insert iterator range inline void insert(iterator_type input_begin, iterator_type input_end, orientation_2d orient = HORIZONTAL) { if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; dirty_ = true; unsorted_ = true; if(orient == orient_) data_.insert(data_.end(), input_begin, input_end); else { for( ; input_begin != input_end; ++input_begin) { insert(*input_begin, false, orient); } } } // insert iterator range template inline void insert(iT input_begin, iT input_end, orientation_2d orient = HORIZONTAL) { if(input_begin == input_end) return; dirty_ = true; unsorted_ = true; for( ; input_begin != input_end; ++input_begin) { insert(*input_begin, false, orient); } } inline void insert(const polygon_90_set_data& polygon_set) { insert(polygon_set.begin(), polygon_set.end(), polygon_set.orient()); } inline void insert(const std::pair, point_data >, int>& edge, bool is_hole = false, orientation_2d orient = HORIZONTAL) { std::pair > vertex; vertex.first = edge.first.first.x(); vertex.second.first = edge.first.first.y(); vertex.second.second = edge.second * (is_hole ? -1 : 1); insert(vertex, false, VERTICAL); vertex.first = edge.first.second.x(); vertex.second.first = edge.first.second.y(); vertex.second.second *= -1; insert(vertex, false, VERTICAL); } template inline void insert(const geometry_type& geometry_object, bool is_hole = false, orientation_2d = HORIZONTAL) { iterator_geometry_to_set::type, geometry_type> begin_input(geometry_object, LOW, orient_, is_hole), end_input(geometry_object, HIGH, orient_, is_hole); insert(begin_input, end_input, orient_); } inline void insert(const std::pair >& vertex, bool is_hole = false, orientation_2d orient = HORIZONTAL) { data_.push_back(vertex); if(orient != orient_) std::swap(data_.back().first, data_.back().second.first); if(is_hole) data_.back().second.second *= -1; dirty_ = true; unsorted_ = true; } inline void insert(coordinate_type major_coordinate, const std::pair, int>& edge) { std::pair > vertex; vertex.first = major_coordinate; vertex.second.first = edge.first.get(LOW); vertex.second.second = edge.second; insert(vertex, false, orient_); vertex.second.first = edge.first.get(HIGH); vertex.second.second *= -1; insert(vertex, false, orient_); } template inline void get(output_container& output) const { get_dispatch(output, typename geometry_concept::type()); } template inline void get_polygons(output_container& output) const { get_dispatch(output, polygon_90_concept()); } template inline void get_rectangles(output_container& output) const { clean(); form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); } template inline void get_rectangles(output_container& output, orientation_2d slicing_orientation) const { if(slicing_orientation == orient_) { get_rectangles(output); } else { polygon_90_set_data ps(*this); ps.transform(axis_transformation(axis_transformation::SWAP_XY)); output_container result; ps.get_rectangles(result); for(typename output_container::iterator itr = result.begin(); itr != result.end(); ++itr) { ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); } output.insert(output.end(), result.begin(), result.end()); } } // equivalence operator inline bool operator==(const polygon_90_set_data& p) const { if(orient_ == p.orient()) { clean(); p.clean(); return data_ == p.data_; } else { return false; } } // inequivalence operator inline bool operator!=(const polygon_90_set_data& p) const { return !((*this) == p); } // get iterator to begin vertex data inline iterator_type begin() const { return data_.begin(); } // get iterator to end vertex data inline iterator_type end() const { return data_.end(); } const value_type& value() const { return data_; } // clear the contents of the polygon_90_set_data inline void clear() { data_.clear(); dirty_ = unsorted_ = false; } // find out if Polygon set is empty inline bool empty() const { clean(); return data_.empty(); } // get the Polygon set size in vertices inline std::size_t size() const { clean(); return data_.size(); } // get the current Polygon set capacity in vertices inline std::size_t capacity() const { return data_.capacity(); } // reserve size of polygon set in vertices inline void reserve(std::size_t size) { return data_.reserve(size); } // find out if Polygon set is sorted inline bool sorted() const { return !unsorted_; } // find out if Polygon set is clean inline bool dirty() const { return dirty_; } // get the scanline orientation of the polygon set inline orientation_2d orient() const { return orient_; } // Start BM // The problem: If we have two polygon sets with two different scanline orientations: // I tried changing the orientation of one to coincide with other (If not, resulting boolean operation // produces spurious results). // First I tried copying polygon data from one of the sets into another set with corrected orientation // using one of the copy constructor that takes in orientation (see somewhere above in this file) --> copy constructor throws error // Then I tried another approach:(see below). This approach also fails to produce the desired results when test case is run. // Here is the part that beats me: If I comment out the whole section, I can do all the operations (^=, -=, &= )these commented out // operations perform. So then why do we need them?. Hence, I commented out this whole section. // End BM // polygon_90_set_data& operator-=(const polygon_90_set_data& that) { // sort(); // that.sort(); // value_type data; // std::swap(data, data_); // applyBooleanBinaryOp(data.begin(), data.end(), // that.begin(), that.end(), boolean_op::BinaryCount()); // return *this; // } // polygon_90_set_data& operator^=(const polygon_90_set_data& that) { // sort(); // that.sort(); // value_type data; // std::swap(data, data_); // applyBooleanBinaryOp(data.begin(), data.end(), // that.begin(), that.end(), boolean_op::BinaryCount()); // return *this; // } // polygon_90_set_data& operator&=(const polygon_90_set_data& that) { // sort(); // that.sort(); // value_type data; // std::swap(data, data_); // applyBooleanBinaryOp(data.begin(), data.end(), // that.begin(), that.end(), boolean_op::BinaryCount()); // return *this; // } // polygon_90_set_data& operator|=(const polygon_90_set_data& that) { // insert(that); // return *this; // } void clean() const { sort(); if(dirty_) { boolean_op::default_arg_workaround::applyBooleanOr(data_); dirty_ = false; } } void sort() const{ if(unsorted_) { gtlsort(data_.begin(), data_.end()); unsorted_ = false; } } template void set(input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { data_.clear(); data_.insert(data_.end(), input_begin, input_end); orient_ = orient; dirty_ = true; unsorted_ = true; } void set(const value_type& value, orientation_2d orient) { data_ = value; orient_ = orient; dirty_ = true; unsorted_ = true; } //extents template bool extents(rectangle_type& extents_rectangle) const { clean(); if(data_.empty()) return false; if(orient_ == HORIZONTAL) set_points(extents_rectangle, point_data(data_[0].second.first, data_[0].first), point_data(data_[data_.size() - 1].second.first, data_[data_.size() - 1].first)); else set_points(extents_rectangle, point_data(data_[0].first, data_[0].second.first), point_data(data_[data_.size() - 1].first, data_[data_.size() - 1].second.first)); for(std::size_t i = 1; i < data_.size() - 1; ++i) { if(orient_ == HORIZONTAL) encompass(extents_rectangle, point_data(data_[i].second.first, data_[i].first)); else encompass(extents_rectangle, point_data(data_[i].first, data_[i].second.first)); } return true; } polygon_90_set_data& bloat2(typename coordinate_traits::unsigned_area_type west_bloating, typename coordinate_traits::unsigned_area_type east_bloating, typename coordinate_traits::unsigned_area_type south_bloating, typename coordinate_traits::unsigned_area_type north_bloating) { std::vector > rects; clean(); rects.reserve(data_.size() / 2); get(rects); rectangle_data convolutionRectangle(interval_data(-((coordinate_type)west_bloating), (coordinate_type)east_bloating), interval_data(-((coordinate_type)south_bloating), (coordinate_type)north_bloating)); for(typename std::vector >::iterator itr = rects.begin(); itr != rects.end(); ++itr) { convolve(*itr, convolutionRectangle); } clear(); insert(rects.begin(), rects.end()); return *this; } static void modify_pt(point_data& pt, const point_data& prev_pt, const point_data& current_pt, const point_data& next_pt, coordinate_type west_bloating, coordinate_type east_bloating, coordinate_type south_bloating, coordinate_type north_bloating) { bool pxl = prev_pt.x() < current_pt.x(); bool pyl = prev_pt.y() < current_pt.y(); bool nxl = next_pt.x() < current_pt.x(); bool nyl = next_pt.y() < current_pt.y(); bool pxg = prev_pt.x() > current_pt.x(); bool pyg = prev_pt.y() > current_pt.y(); bool nxg = next_pt.x() > current_pt.x(); bool nyg = next_pt.y() > current_pt.y(); //two of the four if statements will execute if(pxl) pt.y(current_pt.y() - south_bloating); if(pxg) pt.y(current_pt.y() + north_bloating); if(nxl) pt.y(current_pt.y() + north_bloating); if(nxg) pt.y(current_pt.y() - south_bloating); if(pyl) pt.x(current_pt.x() + east_bloating); if(pyg) pt.x(current_pt.x() - west_bloating); if(nyl) pt.x(current_pt.x() - west_bloating); if(nyg) pt.x(current_pt.x() + east_bloating); } static void resize_poly_up(std::vector >& poly, coordinate_type west_bloating, coordinate_type east_bloating, coordinate_type south_bloating, coordinate_type north_bloating) { point_data first_pt = poly[0]; point_data second_pt = poly[1]; point_data prev_pt = poly[0]; point_data current_pt = poly[1]; for(std::size_t i = 2; i < poly.size(); ++i) { point_data next_pt = poly[i]; modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); prev_pt = current_pt; current_pt = next_pt; } point_data next_pt = first_pt; modify_pt(poly.back(), prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); prev_pt = current_pt; current_pt = next_pt; next_pt = second_pt; modify_pt(poly[0], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); remove_colinear_pts(poly); } static bool resize_poly_down(std::vector >& poly, coordinate_type west_shrinking, coordinate_type east_shrinking, coordinate_type south_shrinking, coordinate_type north_shrinking) { rectangle_data extents_rectangle; set_points(extents_rectangle, poly[0], poly[0]); point_data first_pt = poly[0]; point_data second_pt = poly[1]; point_data prev_pt = poly[0]; point_data current_pt = poly[1]; encompass(extents_rectangle, current_pt); for(int i = 2; i < poly.size(); ++i) { point_data next_pt = poly[i]; encompass(extents_rectangle, next_pt); modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); prev_pt = current_pt; current_pt = next_pt; } if(delta(extents_rectangle, HORIZONTAL) < std::abs(west_shrinking + east_shrinking)) return false; if(delta(extents_rectangle, VERTICAL) < std::abs(north_shrinking + south_shrinking)) return false; point_data next_pt = first_pt; modify_pt(poly.back(), prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); prev_pt = current_pt; current_pt = next_pt; next_pt = second_pt; modify_pt(poly[0], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); return remove_colinear_pts(poly); } static bool remove_colinear_pts(std::vector >& poly) { bool found_colinear = true; while(found_colinear && poly.size() >= 4) { found_colinear = false; typename std::vector >::iterator itr = poly.begin(); itr += poly.size() - 1; //get last element position typename std::vector >::iterator itr2 = poly.begin(); typename std::vector >::iterator itr3 = itr2; ++itr3; std::size_t count = 0; for( ; itr3 < poly.end(); ++itr3) { if(((*itr).x() == (*itr2).x() && (*itr).x() == (*itr3).x()) || ((*itr).y() == (*itr2).y() && (*itr).y() == (*itr3).y()) ) { ++count; found_colinear = true; } else { itr = itr2; ++itr2; } *itr2 = *itr3; } itr3 = poly.begin(); if(((*itr).x() == (*itr2).x() && (*itr).x() == (*itr3).x()) || ((*itr).y() == (*itr2).y() && (*itr).y() == (*itr3).y()) ) { ++count; found_colinear = true; } poly.erase(poly.end() - count, poly.end()); } return poly.size() >= 4; } polygon_90_set_data& bloat(typename coordinate_traits::unsigned_area_type west_bloating, typename coordinate_traits::unsigned_area_type east_bloating, typename coordinate_traits::unsigned_area_type south_bloating, typename coordinate_traits::unsigned_area_type north_bloating) { std::list > polys; get(polys); clear(); for(typename std::list >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { //polygon_90_set_data psref; //psref.insert(view_as((*itr).self_)); //rectangle_data prerect; //psref.extents(prerect); resize_poly_up((*itr).self_.coords_, west_bloating, east_bloating, south_bloating, north_bloating); iterator_geometry_to_set > > begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), end_input(view_as((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); insert(begin_input, end_input, orient_); //polygon_90_set_data pstest; //pstest.insert(view_as((*itr).self_)); //psref.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); //if(!equivalence(psref, pstest)) { // std::cout << "test failed\n"; //} for(typename std::list >::iterator itrh = (*itr).holes_.begin(); itrh != (*itr).holes_.end(); ++itrh) { //rectangle_data rect; //psref.extents(rect); //polygon_90_set_data psrefhole; //psrefhole.insert(prerect); //psrefhole.insert(view_as(*itrh), true); //polygon_45_data testpoly(*itrh); if(resize_poly_down((*itrh).coords_, west_bloating, east_bloating, south_bloating, north_bloating)) { iterator_geometry_to_set > > begin_input2(view_as(*itrh), LOW, orient_, true, true), end_input2(view_as(*itrh), HIGH, orient_, true, true); insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > // begin_input2(view_as(*itrh), LOW, orient_, true, true); //pstesthole.insert(begin_input2, end_input, orient_); //psrefhole.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); //if(!equivalence(psrefhole, pstesthole)) { // std::cout << (winding(testpoly) == CLOCKWISE) << std::endl; // std::cout << (winding(*itrh) == CLOCKWISE) << std::endl; // polygon_90_set_data c(psrefhole); // c.clean(); // polygon_90_set_data a(pstesthole); // polygon_90_set_data b(pstesthole); // a.sort(); // b.clean(); // std::cout << "test hole failed\n"; // //std::cout << testpoly << std::endl; //} } } } return *this; } polygon_90_set_data& shrink(typename coordinate_traits::unsigned_area_type west_shrinking, typename coordinate_traits::unsigned_area_type east_shrinking, typename coordinate_traits::unsigned_area_type south_shrinking, typename coordinate_traits::unsigned_area_type north_shrinking) { std::list > polys; get(polys); clear(); for(typename std::list >::iterator itr = polys.begin(); itr != polys.end(); ++itr) { //polygon_90_set_data psref; //psref.insert(view_as((*itr).self_)); //rectangle_data prerect; //psref.extents(prerect); //polygon_45_data testpoly((*itr).self_); if(resize_poly_down((*itr).self_.coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking)) { iterator_geometry_to_set > > begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), end_input(view_as((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); insert(begin_input, end_input, orient_); //iterator_geometry_to_set > > // begin_input2(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE); //polygon_90_set_data pstest; //pstest.insert(begin_input2, end_input, orient_); //psref.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); //if(!equivalence(psref, pstest)) { // std::cout << "test failed\n"; //} for(typename std::list >::iterator itrh = (*itr).holes_.begin(); itrh != (*itr).holes_.end(); ++itrh) { //rectangle_data rect; //psref.extents(rect); //polygon_90_set_data psrefhole; //psrefhole.insert(prerect); //psrefhole.insert(view_as(*itrh), true); //polygon_45_data testpoly(*itrh); resize_poly_up((*itrh).coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking); iterator_geometry_to_set > > begin_input2(view_as(*itrh), LOW, orient_, true, true), end_input2(view_as(*itrh), HIGH, orient_, true, true); insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > // begin_input2(view_as(*itrh), LOW, orient_, true, true); //pstesthole.insert(begin_input2, end_input, orient_); //psrefhole.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); //if(!equivalence(psrefhole, pstesthole)) { // std::cout << (winding(testpoly) == CLOCKWISE) << std::endl; // std::cout << (winding(*itrh) == CLOCKWISE) << std::endl; // polygon_90_set_data c(psrefhole); // c.clean(); // polygon_90_set_data a(pstesthole); // polygon_90_set_data b(pstesthole); // a.sort(); // b.clean(); // std::cout << "test hole failed\n"; // //std::cout << testpoly << std::endl; //} } } } return *this; } polygon_90_set_data& shrink2(typename coordinate_traits::unsigned_area_type west_shrinking, typename coordinate_traits::unsigned_area_type east_shrinking, typename coordinate_traits::unsigned_area_type south_shrinking, typename coordinate_traits::unsigned_area_type north_shrinking) { rectangle_data externalBoundary; if(!extents(externalBoundary)) return *this; ::boost::polygon::bloat(externalBoundary, 10); //bloat by diferential ammount //insert a hole that encompasses the data insert(externalBoundary, true); //note that the set is in a dirty state now sort(); //does not apply implicit OR operation std::vector > rects; rects.reserve(data_.size() / 2); //begin does not apply implicit or operation, this is a dirty range form_rectangles(rects, data_.begin(), data_.end(), orient_, rectangle_concept()); clear(); rectangle_data convolutionRectangle(interval_data(-((coordinate_type)east_shrinking), (coordinate_type)west_shrinking), interval_data(-((coordinate_type)north_shrinking), (coordinate_type)south_shrinking)); for(typename std::vector >::iterator itr = rects.begin(); itr != rects.end(); ++itr) { rectangle_data& rect = *itr; convolve(rect, convolutionRectangle); //insert rectangle as a hole insert(rect, true); } convolve(externalBoundary, convolutionRectangle); //insert duplicate of external boundary as solid to cancel out the external hole boundaries insert(externalBoundary); clean(); //we have negative values in the set, so we need to apply an OR operation to make it valid input to a boolean return *this; } polygon_90_set_data& shrink(direction_2d dir, typename coordinate_traits::unsigned_area_type shrinking) { if(dir == WEST) return shrink(shrinking, 0, 0, 0); if(dir == EAST) return shrink(0, shrinking, 0, 0); if(dir == SOUTH) return shrink(0, 0, shrinking, 0); return shrink(0, 0, 0, shrinking); } polygon_90_set_data& bloat(direction_2d dir, typename coordinate_traits::unsigned_area_type shrinking) { if(dir == WEST) return bloat(shrinking, 0, 0, 0); if(dir == EAST) return bloat(0, shrinking, 0, 0); if(dir == SOUTH) return bloat(0, 0, shrinking, 0); return bloat(0, 0, 0, shrinking); } polygon_90_set_data& resize(coordinate_type west, coordinate_type east, coordinate_type south, coordinate_type north); polygon_90_set_data& move(coordinate_type x_delta, coordinate_type y_delta) { for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { (*itr).first += x_delta; (*itr).second.first += y_delta; } else { (*itr).second.first += x_delta; (*itr).first += y_delta; } } return *this; } // transform set template polygon_90_set_data& transform(const transformation_type& transformation) { direction_2d dir1, dir2; transformation.get_directions(dir1, dir2); int sign = dir1.get_sign() * dir2.get_sign(); for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { transformation.transform((*itr).first, (*itr).second.first); } else { transformation.transform((*itr).second.first, (*itr).first); } (*itr).second.second *= sign; } if(dir1 != EAST || dir2 != NORTH) unsorted_ = true; //some mirroring or rotation must have happened return *this; } // scale set polygon_90_set_data& scale_up(typename coordinate_traits::unsigned_area_type factor) { for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first *= (coordinate_type)factor; (*itr).second.first *= (coordinate_type)factor; } return *this; } polygon_90_set_data& scale_down(typename coordinate_traits::unsigned_area_type factor) { typedef typename coordinate_traits::coordinate_distance dt; for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first = scaling_policy::round((dt)((*itr).first) / (dt)factor); (*itr).second.first = scaling_policy::round((dt)((*itr).second.first) / (dt)factor); } unsorted_ = true; //scaling down can make coordinates equal that were not previously equal return *this; } template polygon_90_set_data& scale(const anisotropic_scale_factor& scaling) { for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { scaling.scale((*itr).first, (*itr).second.first); } else { scaling.scale((*itr).second.first, (*itr).first); } } unsorted_ = true; return *this; } template polygon_90_set_data& scale_with(const scaling_type& scaling) { for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { scaling.scale((*itr).first, (*itr).second.first); } else { scaling.scale((*itr).second.first, (*itr).first); } } unsorted_ = true; return *this; } polygon_90_set_data& scale(double factor) { typedef typename coordinate_traits::coordinate_distance dt; for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first = scaling_policy::round((dt)((*itr).first) * (dt)factor); (*itr).second.first = scaling_policy::round((dt)((*itr).second.first) * (dt)factor); } unsorted_ = true; //scaling make coordinates equal that were not previously equal return *this; } polygon_90_set_data& self_xor() { sort(); if(dirty_) { //if it is clean it is a no-op boolean_op::default_arg_workaround::applyBooleanOr(data_); dirty_ = false; } return *this; } polygon_90_set_data& self_intersect() { sort(); if(dirty_) { //if it is clean it is a no-op interval_data ivl((std::numeric_limits::min)(), (std::numeric_limits::max)()); rectangle_data rect(ivl, ivl); insert(rect, true); clean(); } return *this; } inline polygon_90_set_data& interact(const polygon_90_set_data& that) { typedef coordinate_type Unit; if(that.dirty_) that.clean(); typename touch_90_operation::TouchSetData tsd; touch_90_operation::populateTouchSetData(tsd, that.data_, 0); std::vector > polys; get(polys); std::vector > graph(polys.size()+1, std::set()); for(std::size_t i = 0; i < polys.size(); ++i){ polygon_90_set_data psTmp(that.orient_); psTmp.insert(polys[i]); psTmp.clean(); touch_90_operation::populateTouchSetData(tsd, psTmp.data_, i+1); } touch_90_operation::performTouch(graph, tsd); clear(); for(std::set::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ insert(polys[(*itr)-1]); } dirty_ = false; return *this; } template void applyBooleanBinaryOp(iterator_type_1 itr1, iterator_type_1 itr1_end, iterator_type_2 itr2, iterator_type_2 itr2_end, T2 defaultCount) { data_.clear(); boolean_op::applyBooleanBinaryOp(data_, itr1, itr1_end, itr2, itr2_end, defaultCount); } private: orientation_2d orient_; mutable value_type data_; mutable bool dirty_; mutable bool unsorted_; private: //functions template void get_dispatch(output_container& output, rectangle_concept ) const { clean(); form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); } template void get_dispatch(output_container& output, polygon_90_concept tag) const { get_fracture(output, true, tag); } template void get_dispatch(output_container& output, polygon_90_with_holes_concept tag) const { get_fracture(output, false, tag); } template void get_dispatch(output_container& output, polygon_45_concept tag) const { get_fracture(output, true, tag); } template void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { get_fracture(output, false, tag); } template void get_dispatch(output_container& output, polygon_concept tag) const { get_fracture(output, true, tag); } template void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { get_fracture(output, false, tag); } template void get_fracture(output_container& container, bool fracture_holes, concept_type tag) const { clean(); ::boost::polygon::get_polygons(container, data_.begin(), data_.end(), orient_, fracture_holes, tag); } }; template polygon_90_set_data& polygon_90_set_data::resize(coordinate_type west, coordinate_type east, coordinate_type south, coordinate_type north) { move(-west, -south); coordinate_type e_total = west + east; coordinate_type n_total = south + north; if((e_total < 0) ^ (n_total < 0)) { //different signs if(e_total < 0) { shrink(0, -e_total, 0, 0); if(n_total != 0) return bloat(0, 0, 0, n_total); else return (*this); } else { shrink(0, 0, 0, -n_total); //shrink first if(e_total != 0) return bloat(0, e_total, 0, 0); else return (*this); } } else { if(e_total < 0) { return shrink(0, -e_total, 0, -n_total); } return bloat(0, e_total, 0, n_total); } } template class property_merge_90 { private: std::vector, std::pair > > pmd_; public: inline property_merge_90() : pmd_() {} inline property_merge_90(const property_merge_90& that) : pmd_(that.pmd_) {} inline property_merge_90& operator=(const property_merge_90& that) { pmd_ = that.pmd_; return *this; } inline void insert(const polygon_90_set_data& ps, const property_type& property) { merge_scanline >:: populate_property_merge_data(pmd_, ps.begin(), ps.end(), property, ps.orient()); } template inline void insert(const GeoObjT& geoObj, const property_type& property) { polygon_90_set_data ps; ps.insert(geoObj); insert(ps, property); } //merge properties of input geometries and store the resulting geometries of regions //with unique sets of merged properties to polygons sets in a map keyed by sets of properties // T = std::map, polygon_90_set_data > or // T = std::map, polygon_90_set_data > template inline void merge(ResultType& result) { merge_scanline, typename ResultType::key_type> ms; ms.perform_merge(result, pmd_); } }; //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap template class connectivity_extraction_90 { private: typedef typename touch_90_operation::TouchSetData tsd; tsd tsd_; unsigned int nodeCount_; public: inline connectivity_extraction_90() : tsd_(), nodeCount_(0) {} inline connectivity_extraction_90(const connectivity_extraction_90& that) : tsd_(that.tsd_), nodeCount_(that.nodeCount_) {} inline connectivity_extraction_90& operator=(const connectivity_extraction_90& that) { tsd_ = that.tsd_; nodeCount_ = that.nodeCount_; {} return *this; } //insert a polygon set graph node, the value returned is the id of the graph node inline unsigned int insert(const polygon_90_set_data& ps) { ps.clean(); touch_90_operation::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); return nodeCount_++; } template inline unsigned int insert(const GeoObjT& geoObj) { polygon_90_set_data ps; ps.insert(geoObj); return insert(ps); } //extract connectivity and store the edges in the graph //graph must be indexable by graph node id and the indexed value must be a std::set of //graph node id template inline void extract(GraphT& graph) { touch_90_operation::performTouch(graph, tsd_); } }; } } #endif